From 11ca86b9432bfb1e7d2ba586b4dc6da60329bf92 Mon Sep 17 00:00:00 2001 From: Hugo Lundin Date: Fri, 16 Jul 2021 16:31:16 +0200 Subject: [PATCH] Refresh MonitorArrangement on configuration change MonitorArrangement (in the options dialog) never changes when the system monitor configuration changes. Therefore, the user can get into a state where the reality doesn't match what is shown (when a monitor is added/removed, resolution or position changed etc). All these changes triggers an event in FLTK (FL_SCREEN_CONFIGURATION_CHANGED). This commit adds an event handler in MonitorArrangement and refreshes the widget whenever that event occurs. Because Fl_Handler does not have a void*-argument (and we must be able to access the widget from our handler callback) a static set of instances have been added, which all will receive the events. --- vncviewer/MonitorArrangement.cxx | 45 ++++++++++++++++++++++++++++++++ vncviewer/MonitorArrangement.h | 4 +++ 2 files changed, 49 insertions(+) diff --git a/vncviewer/MonitorArrangement.cxx b/vncviewer/MonitorArrangement.cxx index 83a53d38..2a7bfad6 100644 --- a/vncviewer/MonitorArrangement.cxx +++ b/vncviewer/MonitorArrangement.cxx @@ -52,6 +52,7 @@ #include "i18n.h" #include "MonitorArrangement.h" +static std::set instances; static rfb::LogWriter vlog("MonitorArrangement"); static const Fl_Boxtype FL_CHECKERED_BOX = FL_FREE_BOXTYPE; @@ -65,6 +66,10 @@ MonitorArrangement::MonitorArrangement( // Used for required monitors. Fl::set_boxtype(FL_CHECKERED_BOX, checkered_pattern_draw, 0, 0, 0, 0); + if (instances.size() == 0) + Fl::add_handler(fltk_event_handler); + instances.insert(this); + box(FL_DOWN_BOX); color(fl_lighter(FL_BACKGROUND_COLOR)); layout(); @@ -73,7 +78,10 @@ MonitorArrangement::MonitorArrangement( MonitorArrangement::~MonitorArrangement() { + instances.erase(this); + if (instances.size() == 0) + Fl::remove_handler(fltk_event_handler); } std::set MonitorArrangement::get() @@ -142,6 +150,25 @@ void MonitorArrangement::layout() m_monitors[i]->copy_tooltip(description(i).c_str()); } +void MonitorArrangement::refresh() +{ + // The selection state is only saved persistently when "OK" is + // pressed. We need to manually restore the current selection + // when the widget is refreshed. + std::set indices = get(); + m_monitors.clear(); + + // FLTK recursively deletes all children for us. + clear(); + begin(); + layout(); + end(); + + // Restore the current selection state. + set(indices); + redraw(); +} + bool MonitorArrangement::is_required(int m) { // A selected monitor is never required. @@ -419,6 +446,24 @@ int MonitorArrangement::get_monitor_name(int m, char name[], size_t name_len) #endif } +int MonitorArrangement::fltk_event_handler(int event) +{ + MonitorArrangement *self; + std::set::iterator it; + + for (it = instances.begin(); it != instances.end(); it++) { + self = *it; + + switch (event) { + case FL_SCREEN_CONFIGURATION_CHANGED: + self->refresh(); + break; + } + } + + return 0; +} + void MonitorArrangement::monitor_pressed(Fl_Widget *widget, void *user_data) { MonitorArrangement *self = (MonitorArrangement *) user_data; diff --git a/vncviewer/MonitorArrangement.h b/vncviewer/MonitorArrangement.h index ca1c4896..f1ba108d 100644 --- a/vncviewer/MonitorArrangement.h +++ b/vncviewer/MonitorArrangement.h @@ -46,6 +46,9 @@ private: // Layout the monitor arrangement. void layout(); + // Refresh the monitor arrangement. + void refresh(); + // Return true if the given monitor is required to be part of the configuration // for it to be valid. A configuration is only valid if the framebuffer created // from is rectangular. @@ -68,6 +71,7 @@ private: std::string description(int m); int get_monitor_name(int m, char name[], size_t name_len); + static int fltk_event_handler(int event); static void monitor_pressed(Fl_Widget *widget, void *user_data); static void checkered_pattern_draw( int x, int y, int width, int height, Fl_Color color); -- 2.39.5