--- a/src/displays.cpp +++ b/src/displays.cpp @@ -98,6 +98,7 @@ pack_start(heading, false, false); pack_start(description, false, false); toolbar.pack_start(refresh_button, false, false); toolbar.pack_start(identify_button, false, false); pack_start(toolbar, false, false); + diagram.set_no_show_all(); diagram.set_size_request(560, 165); diagram.signal_draw().connect(sigc::mem_fun(*this, &DisplaysPage::draw)); pack_start(diagram, false, false); left.set_border_width(12); right.set_border_width(12); @@ -126,7 +127,10 @@ body.pack_start(settings_tabs, true, true); settings_scroll.add(body); settings_scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); settings_scroll.set_min_content_height(120); - pack_start(settings_scroll, true, true); + unavailable.set_line_wrap(); unavailable.set_max_width_chars(65); + settings_state.add(unavailable, "unavailable"); settings_state.add(settings_scroll, "settings"); + settings_state.set_visible_child("unavailable"); + pack_start(settings_state, true, true); left.pack_start(combined, false, false); general_grid.set_row_spacing(10); general_grid.set_column_spacing(12); field(general_grid, 0, "Default desktop output", default_output); @@ -151,14 +155,18 @@ role.append("desktop", "Desktop monitor"); role.append("masked", "Audio only — keep signal active"); role.append("off", "Disabled — signal off"); field(monitor_grid, 0, "Use", role); field(monitor_grid, 1, "Mode / refresh", mode); position.set_placeholder_text("auto or x,y"); field(monitor_grid, 2, "Desktop position", position); - scale.set_range(.25, 8); scale.set_increments(.25, 1); scale.set_digits(2); field(monitor_grid, 3, "Scale", scale); + scale.set_range(.25, 8); scale.set_increments(.25, 1); scale.set_digits(2); scale.set_value(1.0); + scale.get_accessible()->set_name("Physical monitor scale"); field(monitor_grid, 3, "Scale", scale); for (auto text : {"normal", "90", "180", "270", "flipped", "flipped-90", "flipped-180", "flipped-270"}) rotation.append(text, text); field(monitor_grid, 4, "Rotation", rotation); local_gap.set_range(-1, 1000); local_gap.set_increments(1, 5); local_gap.get_accessible()->set_name("Physical monitor zone gap"); local_gap.set_tooltip_text("-1 inherits the shared monitor-zone gap; 0 removes the gap for this physical monitor."); field(monitor_grid, 5, "Zone gap (−1 = inherit)", local_gap); - right.pack_start(monitor_grid, false, false); right.pack_start(include, false, false); + right.pack_start(monitor_grid, false, false); + scale_note.set_text("Scale 1.00 = 100%. Monitors combined into VIRTUAL-1 currently require 1.00."); + scale_note.set_line_wrap(); scale_note.set_max_width_chars(55); scale_note.set_halign(Gtk::ALIGN_START); + right.pack_start(scale_note, false, false); right.pack_start(include, false, false); order_buttons.pack_start(left_button, true, true); order_buttons.pack_start(right_button, true, true); right.pack_start(order_buttons, false, false); status.set_line_wrap(); status.set_max_width_chars(65); status.set_halign(Gtk::ALIGN_START); status.set_selectable(true); pack_start(status, false, false); @@ -230,13 +238,16 @@ throw std::runtime_error("WCM is editing a different configuration from the running compositor. Open its session configuration: " + data["config_file"].as_string()); if (data["pending"].as_bool() && transaction.empty()) { - body.set_sensitive(false); apply_button.set_sensitive(false); + body.set_sensitive(false); apply_button.set_sensitive(false); identify_button.set_sensitive(false); status.set_text("A display preview is awaiting confirmation in another window."); return; } + bool recovering = !available; if (discard || revision != data["revision"].as_string()) load(data); - else update_controls(); + available = true; update_controls(); + if (recovering && !dirty) status.set_text("Changes are previewed for 20 seconds. Keep Changes saves them; closing WCM lets the preview revert."); } catch (const std::exception& e) { + loading = false; available = false; update_controls(); error(std::string(e.what()) + "\nDisplays needs the output-control and ipc plugins from the matching Wayfire package."); apply_button.set_sensitive(false); } @@ -244,7 +255,7 @@ void DisplaysPage::load(const wf::json_t& data) { - loading = true; state = data; revision = data["revision"].as_string(); + loading = true; revision.clear(); state = data; original.clear(); draft.clear(); heads.clear(); order.clear(); monitors.remove_all(); wf::json_t opts = data["options"]; for (auto& key : opts.get_member_names()) original[key] = opts[key].as_string(); @@ -307,7 +318,8 @@ update_defaults(); if (!heads.count(selected)) selected = heads.empty() ? "" : heads.begin()->first; monitors.set_active_id(selected); - loading = false; select_monitor(); dirty = false; update_controls(); diagram.queue_draw(); + loading = false; select_monitor(); dirty = false; revision = data["revision"].as_string(); + update_controls(); diagram.queue_draw(); status.set_text("Changes are previewed for 20 seconds. Keep Changes saves them; closing WCM lets the preview revert."); } @@ -385,8 +397,11 @@ void DisplaysPage::update_controls() { bool preview = !transaction.empty(); - body.set_sensitive(!preview); refresh_button.set_sensitive(!preview); identify_button.set_sensitive(!heads.empty() && !preview); - keep_button.set_visible(preview); revert_button.set_visible(preview); apply_button.set_visible(!preview); apply_button.set_sensitive(dirty && !preview); + settings_state.set_visible_child(available ? "settings" : "unavailable"); + diagram.set_visible(available); + body.set_sensitive(available && !preview); refresh_button.set_sensitive(!preview); + identify_button.set_sensitive(available && !heads.empty() && !preview); + keep_button.set_visible(preview); revert_button.set_visible(preview); apply_button.set_visible(!preview); apply_button.set_sensitive(available && dirty && !preview); bool desktop = role.get_active_id() == "desktop"; include.set_sensitive(desktop); local_gap.set_sensitive(desktop && include.get_active()); --- a/src/displays.hpp +++ b/src/displays.hpp @@ -19,6 +19,8 @@ Gtk::Box left{Gtk::ORIENTATION_VERTICAL, 8}, right{Gtk::ORIENTATION_VERTICAL, 8}; Gtk::Notebook settings_tabs; Gtk::ScrolledWindow settings_scroll; + Gtk::Stack settings_state; + Gtk::Label unavailable{"Display settings are unavailable. Check the message below, then Refresh."}, scale_note; Gtk::Box actions{Gtk::ORIENTATION_HORIZONTAL, 8}, order_buttons{Gtk::ORIENTATION_HORIZONTAL, 8}; Gtk::Button refresh_button{"Refresh"}, identify_button{"Identify"}, apply_button{"Apply"}; Gtk::Button keep_button{"Keep Changes"}, revert_button{"Revert"}, left_button{"Move Left"}, right_button{"Move Right"}; @@ -45,7 +47,7 @@ std::map original, draft; wf::json_t state; std::string revision, transaction, selected, config_file; - bool loading = false, dirty = false; + bool loading = false, dirty = false, available = false; int countdown = 0; sigc::connection timer, identify_timer; std::vector> identifiers;