]> source.dussan.org Git - tigervnc.git/commitdiff
Implement client side multi-head support. Requires a FLTK patched to support
authorPierre Ossman <ossman@cendio.se>
Fri, 13 Jul 2012 11:22:55 +0000 (11:22 +0000)
committerPierre Ossman <ossman@cendio.se>
Fri, 13 Jul 2012 11:22:55 +0000 (11:22 +0000)
fullscreen over multiple monitors. Will properly report screen configuration
to the server, provided the server supports it.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4935 3789f03b-4d11-0410-bbf8-ca57d06f2519

CMakeLists.txt
config.h.in
vncviewer/DesktopWindow.cxx
vncviewer/DesktopWindow.h
vncviewer/OptionsDialog.cxx
vncviewer/OptionsDialog.h
vncviewer/Viewport.cxx
vncviewer/parameters.cxx
vncviewer/parameters.h

index 9cf3dd3227ee97f88330827b08f1fdde5b7f1ef4..c375314a3ab99fa13ef196c61b06f30022565361 100644 (file)
@@ -289,6 +289,9 @@ if(FLTK_FOUND)
   # FLTK STR #2816
   check_cxx_source_compiles("#include <FL/Fl_Window.H>\nint main(int c, char** v) { Fl_Window::default_icons(0, 0); return 0; }" HAVE_FLTK_ICONS)
 
+  # FLTK STR #2860
+  check_cxx_source_compiles("#include <FL/Fl_Window.H>\nint main(int c, char** v) { void (Fl_Window::*foo)(int,int,int,int) = &Fl_Window::fullscreen_screens; return 0; }" HAVE_FLTK_FULLSCREEN_SCREENS)
+
   set(CMAKE_REQUIRED_INCLUDES)
   set(CMAKE_REQUIRED_LIBRARIES)
 endif()
index a11ec10b489591ad9bdebfb49e292b520ad129c8..55cd652dfad7cdd6499ff7768dabb55401c61a76 100644 (file)
@@ -19,6 +19,7 @@
 #cmakedefine HAVE_FLTK_CLIPBOARD
 #cmakedefine HAVE_FLTK_MEDIAKEYS
 #cmakedefine HAVE_FLTK_FULLSCREEN
+#cmakedefine HAVE_FLTK_FULLSCREEN_SCREENS
 #cmakedefine HAVE_FLTK_CURSOR
 #cmakedefine HAVE_FLTK_ICONS
 #cmakedefine HAVE_ACTIVE_DESKTOP_H
index 290539161ef47f4101e91b7f8460add6072817fe..78a94b6078fc5ac6a1dbc6cd3d55e8e2480b8e03 100644 (file)
@@ -76,7 +76,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
 
 #ifdef HAVE_FLTK_FULLSCREEN
   if (fullScreen)
-    fullscreen();
+    fullscreen_on();
   else
 #endif
   {
@@ -295,6 +295,54 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
 }
 
 
+void DesktopWindow::fullscreen_on()
+{
+#ifdef HAVE_FLTK_FULLSCREEN
+#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
+  if (not fullScreenAllMonitors)
+    fullscreen_screens(-1, -1, -1, -1);
+  else {
+    int top, bottom, left, right;
+    int top_y, bottom_y, left_x, right_x;
+
+    int sx, sy, sw, sh;
+
+    top = bottom = left = right = 0;
+
+    Fl::screen_xywh(sx, sy, sw, sh, 0);
+    top_y = sy;
+    bottom_y = sy + sh;
+    left_x = sx;
+    right_x = sx + sw;
+
+    for (int i = 1;i < Fl::screen_count();i++) {
+      Fl::screen_xywh(sx, sy, sw, sh, i);
+      if (sy < top_y) {
+        top = i;
+        top_y = sy;
+      }
+      if ((sy + sh) > bottom_y) {
+        bottom = i;
+        bottom_y = sy + sh;
+      }
+      if (sx < left_x) {
+        left = i;
+        left_x = sx;
+      }
+      if ((sx + sw) > right_x) {
+        right = i;
+        right_x = sx + sw;
+      }
+    }
+
+    fullscreen_screens(top, bottom, left, right);
+  }
+#endif // HAVE_FLTK_FULLSCREEN_SCREENS
+
+  fullscreen();
+#endif // HAVE_FLTK_FULLSCREEN
+}
+
 void DesktopWindow::grabKeyboard()
 {
   // Grabbing the keyboard is fairly safe as FLTK reroutes events to the
@@ -394,6 +442,7 @@ void DesktopWindow::remoteResize()
 {
   int width, height;
   ScreenSet layout;
+  ScreenSet::iterator iter;
 
   if (firstUpdate) {
     if (sscanf(desktopSize.getValueStr(), "%dx%d", &width, &height) != 2)
@@ -403,28 +452,88 @@ void DesktopWindow::remoteResize()
     height = h();
   }
 
-  layout = cc->cp.screenLayout;
+#ifdef HAVE_FLTK_FULLSCREEN
+  if (!fullscreen_active()) {
+#endif
+    // In windowed mode we just report a single virtual screen that
+    // covers the entire framebuffer.
+
+    layout = cc->cp.screenLayout;
 
-  if (layout.num_screens() == 0)
-    layout.add_screen(rfb::Screen());
-  else if (layout.num_screens() != 1) {
-    ScreenSet::iterator iter;
+    // Not sure why we have no screens, but adding a new one should be
+    // safe as there is nothing to conflict with...
+    if (layout.num_screens() == 0)
+      layout.add_screen(rfb::Screen());
+    else if (layout.num_screens() != 1) {
+      // More than one screen. Remove all but the first (which we
+      // assume is the "primary").
 
-    while (true) {
-      iter = layout.begin();
-      ++iter;
+      while (true) {
+        iter = layout.begin();
+        ++iter;
 
-      if (iter == layout.end())
-        break;
+        if (iter == layout.end())
+          break;
 
-      layout.remove_screen(iter->id);
+        layout.remove_screen(iter->id);
+      }
     }
-  }
 
-  layout.begin()->dimensions.tl.x = 0;
-  layout.begin()->dimensions.tl.y = 0;
-  layout.begin()->dimensions.br.x = width;
-  layout.begin()->dimensions.br.y = height;
+    // Resize the remaining single screen to the complete framebuffer
+    layout.begin()->dimensions.tl.x = 0;
+    layout.begin()->dimensions.tl.y = 0;
+    layout.begin()->dimensions.br.x = width;
+    layout.begin()->dimensions.br.y = height;
+#ifdef HAVE_FLTK_FULLSCREEN
+  } else {
+    int i;
+    rdr::U32 id;
+    int sx, sy, sw, sh;
+
+    // In full screen we report all screens that are fully covered.
+
+    // If we can find a matching screen in the existing set, we use
+    // that, otherwise we create a brand new screen.
+    //
+    // FIXME: We should really track screens better so we can handle
+    //        a resized one.
+    //
+    for (i = 0;i < Fl::screen_count();i++) {
+      Fl::screen_xywh(sx, sy, sw, sh, i);
+
+      // Look for perfectly matching existing screen...
+      for (iter = cc->cp.screenLayout.begin();
+           iter != cc->cp.screenLayout.end(); ++iter) {
+        if ((iter->dimensions.tl.x == sx) &&
+            (iter->dimensions.tl.y == sy) &&
+            (iter->dimensions.width() == sw) &&
+            (iter->dimensions.height() == sh))
+          break;
+      }
+
+      // Found it?
+      if (iter != cc->cp.screenLayout.end()) {
+        layout.add_screen(*iter);
+        continue;
+      }
+
+      // Need to add a new one, which means we need to find an unused id
+      while (true) {
+        id = rand();
+        for (iter = cc->cp.screenLayout.begin();
+             iter != cc->cp.screenLayout.end(); ++iter) {
+          if (iter->id == id)
+            break;
+        }
+
+        if (iter == cc->cp.screenLayout.end())
+          break;
+      }
+
+      layout.add_screen(rfb::Screen(id, sx, sy, sw, sh, 0));
+    }
+  }
+#endif
 
   // Do we actually change anything?
   if ((width == cc->cp.width) &&
@@ -432,8 +541,14 @@ void DesktopWindow::remoteResize()
       (layout == cc->cp.screenLayout))
     return;
 
-  vlog.debug("Requesting framebuffer resize from %dx%d to %dx%d",
-             cc->cp.width, cc->cp.height, width, height);
+  vlog.debug("Requesting framebuffer resize from %dx%d to %dx%d (%d screens)",
+             cc->cp.width, cc->cp.height, width, height, layout.num_screens());
+
+  if (!layout.validate(width, height)) {
+    vlog.error("Invalid screen layout computed for resize request!");
+    layout.debug_print();
+    return;
+  }
 
   cc->writer()->writeSetDesktopSize(width, height, layout);
 }
@@ -499,7 +614,7 @@ void DesktopWindow::handleOptions(void *data)
     self->ungrabKeyboard();
 
   if (fullScreen && !self->fullscreen_active())
-    self->fullscreen();
+    self->fullscreen_on();
   else if (!fullScreen && self->fullscreen_active())
     self->fullscreen_off();
 #endif
index 3fe9c866b07f239b8e74e19d4a01530f57eb2b4b..2a4613c779bc9d3f8839f50cd601d0b557479b7f 100644 (file)
@@ -78,6 +78,8 @@ public:
 
   int handle(int event);
 
+  void fullscreen_on();
+
 private:
   static int fltkHandle(int event, Fl_Window *win);
 
index c82079f57165f611eca2b014f1f27968dbd9d923..df9f3554ccafe3e7f4b756f31cc47a4418680282 100644 (file)
@@ -288,6 +288,9 @@ void OptionsDialog::loadOptions(void)
   remoteResizeCheckbox->value(remoteResize);
 #ifdef HAVE_FLTK_FULLSCREEN
   fullScreenCheckbox->value(fullScreen);
+#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
+  fullScreenAllMonitorsCheckbox->value(fullScreenAllMonitors);
+#endif // HAVE_FLTK_FULLSCREEN_SCREENS
 #endif // HAVE_FLTK_FULLSCREEN
 
   handleDesktopSize(desktopSizeCheckbox, this);
@@ -393,6 +396,9 @@ void OptionsDialog::storeOptions(void)
   remoteResize.setParam(remoteResizeCheckbox->value());
 #ifdef HAVE_FLTK_FULLSCREEN
   fullScreen.setParam(fullScreenCheckbox->value());
+#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
+  fullScreenAllMonitors.setParam(fullScreenAllMonitorsCheckbox->value());
+#endif // HAVE_FLTK_FULLSCREEN_SCREENS
 #endif // HAVE_FLTK_FULLSCREEN
 
   /* Misc. */
@@ -760,6 +766,16 @@ void OptionsDialog::createScreenPage(int tx, int ty, int tw, int th)
                                                   _("Full-screen mode")));
   ty += CHECK_HEIGHT + TIGHT_MARGIN;
 
+#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
+
+  fullScreenAllMonitorsCheckbox = new Fl_Check_Button(LBLRIGHT(tx + INDENT, ty,
+                                                      CHECK_MIN_WIDTH,
+                                                      CHECK_HEIGHT,
+                                                      _("Enable full-screen mode over all monitors")));
+  ty += CHECK_HEIGHT + TIGHT_MARGIN;
+
+#endif // HAVE_FLTK_FULLSCREEN_SCREENS
+
 #endif // HAVE_FLTK_FULLSCREEN
 
   group->end();
index c26c0c91346a4d3bace4b1574f6dda819e1e31a9..b3ac015635543835bcc8ede0d45b858ce3ea45d3 100644 (file)
@@ -114,6 +114,7 @@ protected:
   Fl_Int_Input *desktopHeightInput;
   Fl_Check_Button *remoteResizeCheckbox;
   Fl_Check_Button *fullScreenCheckbox;
+  Fl_Check_Button *fullScreenAllMonitorsCheckbox;
 
   /* Misc. */
   Fl_Check_Button *sharedCheckbox;
index a80b8efe06aad71d4b9d333558b9e7138f368fc5..43b39d4f29ee88ebd90576d439943f27910e0048 100644 (file)
@@ -920,7 +920,7 @@ void Viewport::popupContextMenu()
     if (window()->fullscreen_active())
       window()->fullscreen_off();
     else
-      window()->fullscreen();
+      ((DesktopWindow*)window())->fullscreen_on();
     break;
 #endif
   case ID_RESIZE:
index 4407bd95c8db374eedaffec26f9bf6c04a16702f..22fa1ac532d3c7f98644815c8ccaf578a8c679a7 100644 (file)
@@ -66,6 +66,11 @@ IntParameter qualityLevel("QualityLevel",
 
 #ifdef HAVE_FLTK_FULLSCREEN
 BoolParameter fullScreen("FullScreen", "Full screen mode", false);
+#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
+BoolParameter fullScreenAllMonitors("FullScreenAllMonitors",
+                                    "Enable full screen over all monitors",
+                                    true);
+#endif // HAVE_FLTK_FULLSCREEN_SCREENS
 #endif // HAVE_FLTK_FULLSCREEN
 StringParameter desktopSize("DesktopSize",
                             "Reconfigure desktop size on the server on "
index a935ea0ea1c07d197bcfc88e4dcb0a638026ec65..59909d112cda6a69faeb7b9beda4cca7a4d7ae11 100644 (file)
@@ -39,6 +39,9 @@ extern rfb::IntParameter qualityLevel;
 
 #ifdef HAVE_FLTK_FULLSCREEN
 extern rfb::BoolParameter fullScreen;
+#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
+extern rfb::BoolParameter fullScreenAllMonitors;
+#endif // HAVE_FLTK_FULLSCREEN_SCREENS
 #endif // HAVE_FLTK_FULLSCREEN
 extern rfb::StringParameter desktopSize;
 extern rfb::BoolParameter remoteResize;