From 2b78d5bd5da07716c0f81facbd581d95415f8d7d Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 25 Aug 2009 15:23:53 -0400 Subject: [PATCH] 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 c5a0a2ad1..ec23fdabc 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 8bfd660b2..6c1e943db 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 f48d38b44..110404432 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 f3f402dd7..4d5b37cbb 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 4ffeb0f9f..473375bb7 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 727957046..3d05c68ec 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 998fef236..ca389ced1 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__ */