[gnome-shell] Improve support for multihead setups



commit 2b78d5bd5da07716c0f81facbd581d95415f8d7d
Author: Dan Winship <danw gnome org>
Date:   Tue Aug 25 15:23:53 2009 -0400

    Improve support for multihead setups
    
    Fix panel, app switcher, and looking glass to limit themselves to the
    primary monitor, and run dialog to limit itself to the monitor
    containing the currently-focused window.
    
    The overview is also limited to the primary monitor now (with the
    other monitors being blacked out), although the workspaces within the
    overview are shaped like the full "screen" (the bounding box of all
    monitors). To be fixed later.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=593060

 js/ui/altTab.js       |    6 ++-
 js/ui/lookingGlass.js |   13 ++++---
 js/ui/main.js         |    4 ++-
 js/ui/overview.js     |   36 ++++++++++---------
 js/ui/runDialog.js    |   30 ++++++++++------
 src/shell-global.c    |   96 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-global.h    |    4 ++
 7 files changed, 152 insertions(+), 37 deletions(-)
---
diff --git a/js/ui/altTab.js b/js/ui/altTab.js
index c5a0a2a..ec23fda 100644
--- a/js/ui/altTab.js
+++ b/js/ui/altTab.js
@@ -105,8 +105,10 @@ AltTabPopup.prototype = {
                                                global.screen_height);
 
         this.actor.show_all();
-        this.actor.x = Math.floor((global.screen_width - this.actor.width) / 2);
-        this.actor.y = Math.floor((global.screen_height - this.actor.height) / 2);
+
+        let primary = global.get_primary_monitor();
+        this.actor.x = primary.x + Math.floor((primary.width - this.actor.width) / 2);
+        this.actor.y = primary.y + Math.floor((primary.height - this.actor.height) / 2);
 
         this._updateSelection(initialSelection);
 
diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js
index 8bfd660..6c1e943 100644
--- a/js/ui/lookingGlass.js
+++ b/js/ui/lookingGlass.js
@@ -249,15 +249,16 @@ function Inspector() {
 Inspector.prototype = {
     _init: function() {
         let width = 150;
+        let primary = global.get_primary_monitor();
         let eventHandler = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
                                          border: 1,
                                          border_color: LG_BORDER_COLOR,
                                          corner_radius: 4,
-                                         y: global.stage.height/2,
+                                         y: primary.y + Math.floor(primary.height / 2),
                                          reactive: true
                                       });
         eventHandler.connect('notify::allocation', Lang.bind(this, function () {
-            eventHandler.x = Math.floor((global.stage.width)/2 - (eventHandler.width)/2);
+            eventHandler.x = primary.x + Math.floor((primary.width - eventHandler.width) / 2);
         }));
         global.stage.add_actor(eventHandler);
         let displayText = new Clutter.Text({ color: MATRIX_GREEN,
@@ -518,11 +519,11 @@ LookingGlass.prototype = {
     },
 
     _resizeTo: function(actor) {
-        let stage = global.stage;
-        let myWidth = stage.width * 0.7;
-        let myHeight = stage.height * 0.7;
+        let primary = global.get_primary_monitor();
+        let myWidth = primary.width * 0.7;
+        let myHeight = primary.height * 0.7;
         let [srcX, srcY] = actor.get_transformed_position();
-        this.actor.x = srcX + (stage.width-myWidth)/2;
+        this.actor.x = srcX + (primary.width - myWidth) / 2;
         this._hiddenY = srcY + actor.height - myHeight - 4; // -4 to hide the top corners
         this._targetY = this._hiddenY + myHeight;
         this.actor.y = this._hiddenY;
diff --git a/js/ui/main.js b/js/ui/main.js
index f48d38b..1104044 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -121,7 +121,9 @@ function start() {
 }
 
 function _relayout() {
-    panel.actor.set_size(global.screen_width, Panel.PANEL_HEIGHT);
+    let primary = global.get_primary_monitor();
+    panel.actor.set_position(primary.x, primary.y);
+    panel.actor.set_size(primary.width, Panel.PANEL_HEIGHT);
     overview.relayout();
 }
 
diff --git a/js/ui/overview.js b/js/ui/overview.js
index f3f402d..4d5b37c 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -142,42 +142,44 @@ Overview.prototype = {
     },
 
     _recalculateGridSizes: function () {
-        wideScreen = (global.screen_width/global.screen_height > WIDE_SCREEN_CUT_OFF_RATIO) &&
-                     (global.screen_height >= WIDE_SCREEN_MINIMUM_HEIGHT);
+        let primary = global.get_primary_monitor();
+        wideScreen = (primary.width/primary.height > WIDE_SCREEN_CUT_OFF_RATIO) &&
+                     (primary.height >= WIDE_SCREEN_MINIMUM_HEIGHT);
 
         // We divide the screen into an imaginary grid which helps us determine the layout of
         // different visual components.
         if (wideScreen) {
-            displayGridColumnWidth = global.screen_width / COLUMNS_WIDE_SCREEN;
-            displayGridRowHeight = global.screen_height / ROWS_WIDE_SCREEN;
+            displayGridColumnWidth = primary.width / COLUMNS_WIDE_SCREEN;
+            displayGridRowHeight = primary.height / ROWS_WIDE_SCREEN;
         } else {
-            displayGridColumnWidth = global.screen_width / COLUMNS_REGULAR_SCREEN;
-            displayGridRowHeight = global.screen_height / ROWS_REGULAR_SCREEN;
+            displayGridColumnWidth = primary.width / COLUMNS_REGULAR_SCREEN;
+            displayGridRowHeight = primary.height / ROWS_REGULAR_SCREEN;
         }
     },
 
     relayout: function () {
-        let screenHeight = global.screen_height;
-        let screenWidth = global.screen_width;
+        let primary = global.get_primary_monitor();
+
+        this._group.set_position(primary.x, primary.y);
 
         let contentY = Panel.PANEL_HEIGHT;
-        let contentHeight = screenHeight - contentY;
+        let contentHeight = primary.height - contentY;
 
         this._coverPane.set_position(0, contentY);
-        this._coverPane.set_size(screenWidth, contentHeight);
+        this._coverPane.set_size(primary.width, contentHeight);
 
         let workspaceColumnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN;
         let workspaceRowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
 
         this._workspacesWidth = displayGridColumnWidth * workspaceColumnsUsed
                                   - WORKSPACE_GRID_PADDING * 2;
-        // We scale the vertical padding by (screenHeight / screenWidth)
+        // We scale the vertical padding by (primary.height / primary.width)
         // so that the workspace preserves its aspect ratio.
         this._workspacesHeight = displayGridRowHeight * workspaceRowsUsed
-                                   - WORKSPACE_GRID_PADDING * (screenHeight / screenWidth) * 2;
+                                   - WORKSPACE_GRID_PADDING * (primary.height / primary.width) * 2;
 
         this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
-        this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth);
+        this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (primary.height / primary.width);
 
         this._dash.actor.set_position(0, contentY);
         this._dash.actor.set_size(displayGridColumnWidth, contentHeight);
@@ -187,10 +189,10 @@ Overview.prototype = {
         // place the 'Add Workspace' button in the bottom row of the grid
         addRemoveButtonSize = Math.floor(displayGridRowHeight * 3/5);
         this._addButtonX = this._workspacesX + this._workspacesWidth - addRemoveButtonSize;
-        this._addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
+        this._addButtonY = primary.height - Math.floor(displayGridRowHeight * 4/5);
 
-        this._backOver.set_position(0, contentY);
-        this._backOver.set_size(global.screen_width, contentHeight);
+        this._backOver.set_position(0, 0);
+        this._backOver.set_size(global.screen_width, global.screen_height);
 
         this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
                                          contentY);
@@ -198,7 +200,7 @@ Overview.prototype = {
         this._paneContainer.height = contentHeight;
 
         this._transparentBackground.set_position(this._paneContainer.x, this._paneContainer.y);
-        this._transparentBackground.set_size(global.screen_width - this._paneContainer.x,
+        this._transparentBackground.set_size(primary.width - this._paneContainer.x,
                                              this._paneContainer.height);
 
         if (this._activeDisplayPane != null)
diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js
index 4ffeb0f..473375b 100644
--- a/js/ui/runDialog.js
+++ b/js/ui/runDialog.js
@@ -60,24 +60,26 @@ RunDialog.prototype = {
 
         // All actors are inside _group. We create it initially
         // hidden then show it in show()
-        this._group = new Clutter.Group({ visible: false });
+        this._group = new Clutter.Group({ visible: false,
+                                          x: 0,
+                                          y: 0,
+                                          width: global.screen_width,
+                                          height: global.screen_height });
         global.stage.add_actor(this._group);
 
-        this._lightbox = new Lightbox.Lightbox(this._group);
+        let lightbox = new Lightbox.Lightbox(this._group);
 
-        let boxH = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
-                                 x_align: Big.BoxAlignment.CENTER,
-                                 y_align: Big.BoxAlignment.CENTER,
-                                 width: global.screen_width,
-                                 height: global.screen_height });
+        this._boxH = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+                                   x_align: Big.BoxAlignment.CENTER,
+                                   y_align: Big.BoxAlignment.CENTER });
 
-        this._group.add_actor(boxH);
-        this._lightbox.highlight(boxH);
+        this._group.add_actor(this._boxH);
+        lightbox.highlight(this._boxH);
 
         let boxV = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
                                  y_align: Big.BoxAlignment.CENTER });
 
-        boxH.append(boxV, Big.BoxPackFlags.NONE);
+        this._boxH.append(boxV, Big.BoxPackFlags.NONE);
 
 
         let dialogBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
@@ -87,7 +89,7 @@ RunDialog.prototype = {
                                       padding: DIALOG_PADDING,
                                       width: DIALOG_WIDTH });
 
-        boxH.append(dialogBox, Big.BoxPackFlags.NONE);
+        this._boxH.append(dialogBox, Big.BoxPackFlags.NONE);
 
         let label = new Clutter.Text({ color: BOX_TEXT_COLOR,
                                        font_name: '18px Sans',
@@ -182,6 +184,12 @@ RunDialog.prototype = {
         if (!Main.pushModal(this._group))
             return;
 
+        // Position the dialog on the current monitor
+        let monitor = global.get_focus_monitor();
+
+        this._boxH.set_position(monitor.x, monitor.y);
+        this._boxH.set_size(monitor.width, monitor.height);
+
         this._isOpen = true;
         this._group.show();
 
diff --git a/src/shell-global.c b/src/shell-global.c
index 7279570..3d05c68 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -869,3 +869,99 @@ shell_global_create_root_pixmap_actor (ShellGlobal *global)
 
   return clutter_clone_new (global->root_pixmap);
 }
+
+/**
+ * shell_global_get_monitors:
+ * @global: the #ShellGlobal
+ *
+ * Gets a list of the bounding boxes of the active screen's monitors.
+ *
+ * Return value: (transfer full) (element-type GdkRectangle): a list
+ * of monitor bounding boxes.
+ */
+GSList *
+shell_global_get_monitors (ShellGlobal *global)
+{
+  MetaScreen *screen = shell_global_get_screen (global);
+  GSList *monitors = NULL;
+  MetaRectangle rect;
+  int i;
+
+  g_assert (sizeof (MetaRectangle) == sizeof (GdkRectangle) &&
+            G_STRUCT_OFFSET (MetaRectangle, x) == G_STRUCT_OFFSET (GdkRectangle, x) &&
+            G_STRUCT_OFFSET (MetaRectangle, y) == G_STRUCT_OFFSET (GdkRectangle, y) &&
+            G_STRUCT_OFFSET (MetaRectangle, width) == G_STRUCT_OFFSET (GdkRectangle, width) &&
+            G_STRUCT_OFFSET (MetaRectangle, height) == G_STRUCT_OFFSET (GdkRectangle, height));
+
+  for (i = meta_screen_get_n_monitors (screen) - 1; i >= 0; i--)
+    {
+      meta_screen_get_monitor_geometry (screen, i, &rect);
+      monitors = g_slist_prepend (monitors,
+                                  g_boxed_copy (GDK_TYPE_RECTANGLE, &rect));
+    }
+  return monitors;
+}
+
+/**
+ * shell_global_get_primary_monitor:
+ * @global: the #ShellGlobal
+ *
+ * Gets the bounding box of the primary monitor (the one that the
+ * panel is on).
+ *
+ * Return value: the bounding box of the primary monitor
+ */
+GdkRectangle *
+shell_global_get_primary_monitor (ShellGlobal  *global)
+{
+  MetaScreen *screen = shell_global_get_screen (global);
+  MetaRectangle rect;
+
+  g_assert (sizeof (MetaRectangle) == sizeof (GdkRectangle) &&
+            G_STRUCT_OFFSET (MetaRectangle, x) == G_STRUCT_OFFSET (GdkRectangle, x) &&
+            G_STRUCT_OFFSET (MetaRectangle, y) == G_STRUCT_OFFSET (GdkRectangle, y) &&
+            G_STRUCT_OFFSET (MetaRectangle, width) == G_STRUCT_OFFSET (GdkRectangle, width) &&
+            G_STRUCT_OFFSET (MetaRectangle, height) == G_STRUCT_OFFSET (GdkRectangle, height));
+
+  meta_screen_get_monitor_geometry (screen, 0, &rect);
+  return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
+}
+
+/**
+ * shell_global_get_focus_monitor:
+ * @global: the #ShellGlobal
+ *
+ * Gets the bounding box of the monitor containing the window that
+ * currently contains the keyboard focus.
+ *
+ * Return value: the bounding box of the focus monitor
+ */
+GdkRectangle *
+shell_global_get_focus_monitor (ShellGlobal  *global)
+{
+  MetaScreen *screen = shell_global_get_screen (global);
+  MetaDisplay *display = meta_screen_get_display (screen);
+  MetaWindow *focus = meta_display_get_focus_window (display);
+  MetaRectangle rect, wrect;
+  int nmonitors, i;
+
+  if (focus)
+    {
+      meta_window_get_outer_rect (focus, &wrect);
+      nmonitors = meta_screen_get_n_monitors (screen);
+
+      /* Find the monitor that the top-left corner of @focus is on. */
+      for (i = 0; i < nmonitors; i++)
+        {
+          meta_screen_get_monitor_geometry (screen, i, &rect);
+
+          if (rect.x < wrect.x && rect.y < wrect.y &&
+              rect.x + rect.width > wrect.x &&
+              rect.y + rect.height > wrect.y)
+            return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
+        }
+    }
+
+  meta_screen_get_monitor_geometry (screen, 0, &rect);
+  return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
+}
diff --git a/src/shell-global.h b/src/shell-global.h
index 998fef2..ca389ce 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -73,6 +73,10 @@ void shell_global_format_time_relative_pretty (ShellGlobal *global, guint delta,
 
 ClutterActor *shell_global_create_root_pixmap_actor (ShellGlobal *global);
 
+GSList       *shell_global_get_monitors        (ShellGlobal  *global);
+GdkRectangle *shell_global_get_primary_monitor (ShellGlobal  *global);
+GdkRectangle *shell_global_get_focus_monitor   (ShellGlobal  *global);
+
 G_END_DECLS
 
 #endif /* __SHELL_GLOBAL_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]