]> source.dussan.org Git - tigervnc.git/commitdiff
Handle mirrored monitors on X11
authorPierre Ossman <ossman@cendio.se>
Thu, 9 Sep 2021 09:01:47 +0000 (11:01 +0200)
committerPierre Ossman <ossman@cendio.se>
Thu, 9 Sep 2021 11:20:13 +0000 (13:20 +0200)
macOS and Windows present mirrored monitors as a single virtual monitor,
but X11 exposes this scenario as two distinct monitors with identical
coordinates. This messes up our logic, and is likely confusing for the
user. So instead we'll ignore any monitors that have identical
coordinates to any already seen monitors.

(cherry picked from commit fb561eb321b36dcf13932c903047ce08e55d67d5)

vncviewer/MonitorArrangement.cxx
vncviewer/MonitorArrangement.h
vncviewer/MonitorIndicesParameter.cxx

index b1d30128e54992690067a1464e8928784fd11521..735177ba299f7e77888c371686bfe221cbd15e9a 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright 2021 Hugo Lundin <huglu@cendio.se> for Cendio AB.
+ * Copyright 2021 Pierre Ossman for Cendio AB
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -60,8 +61,7 @@ MonitorArrangement::MonitorArrangement(
    int x, int y, int w, int h)
 :  Fl_Group(x, y, w, h),
    SELECTION_COLOR(fl_lighter(FL_BLUE)),
-   AVAILABLE_COLOR(fl_lighter(fl_lighter(fl_lighter(FL_BACKGROUND_COLOR)))),
-   monitors()
+   AVAILABLE_COLOR(fl_lighter(fl_lighter(fl_lighter(FL_BACKGROUND_COLOR))))
 {
   // Used for required monitors.
   Fl::set_boxtype(FL_CHECKERED_BOX, checkered_pattern_draw, 0, 0, 0, 0);
@@ -87,10 +87,11 @@ MonitorArrangement::~MonitorArrangement()
 std::set<int> MonitorArrangement::get()
 {
   std::set<int> indices;
+  MonitorMap::const_iterator iter;
 
-  for (int i = 0; i < (int) monitors.size(); i++) {
-    if (monitors[i]->value() == 1)
-      indices.insert(i);
+  for (iter = monitors.begin(); iter != monitors.end(); ++iter) {
+    if (iter->second->value() == 1)
+      indices.insert(iter->first);
   }
 
   return indices;
@@ -98,18 +99,23 @@ std::set<int> MonitorArrangement::get()
 
 void MonitorArrangement::set(std::set<int> indices)
 {
-  for (int i = 0; i < (int) monitors.size(); i++) {
-    bool selected = std::find(indices.begin(), indices.end(), i) != indices.end();
-    monitors[i]->value(selected ? 1 : 0);
+  MonitorMap::const_iterator iter;
+
+  for (iter = monitors.begin(); iter != monitors.end(); ++iter) {
+    bool selected = std::find(indices.begin(), indices.end(),
+                              iter->first) != indices.end();
+    iter->second->value(selected ? 1 : 0);
   }
 }
 
 void MonitorArrangement::draw()
 {
-  for (int i = 0; i < (int) monitors.size(); i++) {
-    Fl_Button * monitor = monitors[i];
+  MonitorMap::const_iterator iter;
+
+  for (iter = monitors.begin(); iter != monitors.end(); ++iter) {
+    Fl_Button * monitor = iter->second;
 
-    if (is_required(i)) {
+    if (is_required(iter->first)) {
       monitor->box(FL_CHECKERED_BOX);
       monitor->color(SELECTION_COLOR);
     } else {
@@ -130,8 +136,26 @@ void MonitorArrangement::layout()
   std::pair<int, int> offset = this->offset();
 
   for (int i = 0; i < Fl::screen_count(); i++) {
+    bool match;
+
     Fl::screen_xywh(x, y, w, h, i);
 
+    // Only keep a single entry for mirrored screens
+    match = false;
+    for (int j = 0; j < i; j++) {
+        int x2, y2, w2, h2;
+
+        Fl::screen_xywh(x2, y2, w2, h2, j);
+
+        if ((x != x2) || (y != y2) || (w != w2) || (h != h2))
+            continue;
+
+        match = true;
+        break;
+    }
+    if (match)
+        continue;
+
     Fl_Button *monitor = new Fl_Button(
       /* x = */ this->x() + offset.first + x*scale + (1 - MARGIN_SCALE_FACTOR)*x*scale,
       /* y = */ this->y() + offset.second +  y*scale + (1 - MARGIN_SCALE_FACTOR)*y*scale,
@@ -143,11 +167,9 @@ void MonitorArrangement::layout()
     monitor->callback(monitor_pressed, this);
     monitor->type(FL_TOGGLE_BUTTON);
     monitor->when(FL_WHEN_CHANGED);
-    monitors.push_back(monitor);
+    monitor->copy_tooltip(description(i).c_str());
+    monitors[i] = monitor;
   }
-
-  for (int i = 0; i < (int) monitors.size(); i++)
-    monitors[i]->copy_tooltip(description(i).c_str());
 }
 
 void MonitorArrangement::refresh()
@@ -308,7 +330,7 @@ std::pair<int, int> MonitorArrangement::origin()
 
 std::string MonitorArrangement::description(int m)
 {
-  assert(m < (int) monitors.size());
+  assert(m < Fl::screen_count());
   const size_t name_len = 1024;
   char name[name_len] = {};
   int bytes_written = get_monitor_name(m, name, name_len);
index 3a71e5b04948fb891ffd9dd0941117b9413d8edd..e69198b672ad064999191d824e27ba096cbe45b3 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright 2021 Hugo Lundin <huglu@cendio.se> for Cendio AB.
+ * Copyright 2021 Pierre Ossman for Cendio AB
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,6 +21,8 @@
 #define __MONITOR_ARRANGEMENT_H__
 
 #include <string>
+#include <map>
+#include <set>
 
 class Fl_Group;
 class Fl_Button;
@@ -41,7 +44,8 @@ protected:
 private:
   const Fl_Color SELECTION_COLOR;
   const Fl_Color AVAILABLE_COLOR;
-  std::vector<Fl_Button *> monitors;
+  typedef std::map<int, Fl_Button *> MonitorMap;
+  MonitorMap monitors;
 
   // Layout the monitor arrangement.
   void layout();
index 827687dce478271ace0000901cb742b78ad957a4..ad791504bd06fe561deb8e6157afa4d7683c6c6c 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright 2021 Hugo Lundin <huglu@cendio.se> for Cendio AB.
+ * Copyright 2021 Pierre Ossman for Cendio AB
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -196,6 +197,7 @@ std::vector<MonitorIndicesParameter::Monitor> MonitorIndicesParameter::fetchMoni
     // Start by creating a struct for every monitor.
     for (int i = 0; i < Fl::screen_count(); i++) {
         Monitor monitor = {0};
+        bool match;
 
         // Get the properties of the monitor at the current index;
         Fl::screen_xywh(
@@ -206,6 +208,24 @@ std::vector<MonitorIndicesParameter::Monitor> MonitorIndicesParameter::fetchMoni
             i
         );
 
+        // Only keep a single entry for mirrored screens
+        match = false;
+        for (int j = 0; j < ((int) monitors.size()); j++) {
+            if (monitors[i].x != monitor.x)
+                continue;
+            if (monitors[i].y != monitor.y)
+                continue;
+            if (monitors[i].w != monitor.w)
+                continue;
+            if (monitors[i].h != monitor.h)
+                continue;
+
+            match = true;
+            break;
+        }
+        if (match)
+            continue;
+
         monitor.fltkIndex = i;
         monitors.push_back(monitor);
     }