]> source.dussan.org Git - tigervnc.git/commitdiff
Refresh MonitorArrangement on configuration change 1295/head
authorHugo Lundin <hugo@lundin.dev>
Fri, 16 Jul 2021 14:31:16 +0000 (16:31 +0200)
committerHugo Lundin <hugo@lundin.dev>
Fri, 16 Jul 2021 14:31:16 +0000 (16:31 +0200)
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
vncviewer/MonitorArrangement.h

index 83a53d3890cc58bc9f478f1db12dea43c82725a8..2a7bfad69905ef012b78a7706612dc27b23a9398 100644 (file)
@@ -52,6 +52,7 @@
 #include "i18n.h"
 #include "MonitorArrangement.h"
 
+static std::set<MonitorArrangement *> 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<int> 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<int> 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<MonitorArrangement *>::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;
index ca1c4896d63c8afee7227ae59621fbdb6ebc8125..f1ba108d2882dac523a6d6bab6000daab1db65bf 100644 (file)
@@ -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);