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
This commit is contained in:
Dan Winship 2009-08-25 15:23:53 -04:00
parent c9d9846759
commit 2b78d5bd5d
7 changed files with 152 additions and 37 deletions

View File

@ -105,8 +105,10 @@ AltTabPopup.prototype = {
global.screen_height); global.screen_height);
this.actor.show_all(); 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); this._updateSelection(initialSelection);

View File

@ -249,15 +249,16 @@ function Inspector() {
Inspector.prototype = { Inspector.prototype = {
_init: function() { _init: function() {
let width = 150; let width = 150;
let primary = global.get_primary_monitor();
let eventHandler = new Big.Box({ background_color: LG_BACKGROUND_COLOR, let eventHandler = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
border: 1, border: 1,
border_color: LG_BORDER_COLOR, border_color: LG_BORDER_COLOR,
corner_radius: 4, corner_radius: 4,
y: global.stage.height/2, y: primary.y + Math.floor(primary.height / 2),
reactive: true reactive: true
}); });
eventHandler.connect('notify::allocation', Lang.bind(this, function () { 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); global.stage.add_actor(eventHandler);
let displayText = new Clutter.Text({ color: MATRIX_GREEN, let displayText = new Clutter.Text({ color: MATRIX_GREEN,
@ -518,11 +519,11 @@ LookingGlass.prototype = {
}, },
_resizeTo: function(actor) { _resizeTo: function(actor) {
let stage = global.stage; let primary = global.get_primary_monitor();
let myWidth = stage.width * 0.7; let myWidth = primary.width * 0.7;
let myHeight = stage.height * 0.7; let myHeight = primary.height * 0.7;
let [srcX, srcY] = actor.get_transformed_position(); 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._hiddenY = srcY + actor.height - myHeight - 4; // -4 to hide the top corners
this._targetY = this._hiddenY + myHeight; this._targetY = this._hiddenY + myHeight;
this.actor.y = this._hiddenY; this.actor.y = this._hiddenY;

View File

@ -121,7 +121,9 @@ function start() {
} }
function _relayout() { 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(); overview.relayout();
} }

View File

@ -142,42 +142,44 @@ Overview.prototype = {
}, },
_recalculateGridSizes: function () { _recalculateGridSizes: function () {
wideScreen = (global.screen_width/global.screen_height > WIDE_SCREEN_CUT_OFF_RATIO) && let primary = global.get_primary_monitor();
(global.screen_height >= WIDE_SCREEN_MINIMUM_HEIGHT); 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 // We divide the screen into an imaginary grid which helps us determine the layout of
// different visual components. // different visual components.
if (wideScreen) { if (wideScreen) {
displayGridColumnWidth = global.screen_width / COLUMNS_WIDE_SCREEN; displayGridColumnWidth = primary.width / COLUMNS_WIDE_SCREEN;
displayGridRowHeight = global.screen_height / ROWS_WIDE_SCREEN; displayGridRowHeight = primary.height / ROWS_WIDE_SCREEN;
} else { } else {
displayGridColumnWidth = global.screen_width / COLUMNS_REGULAR_SCREEN; displayGridColumnWidth = primary.width / COLUMNS_REGULAR_SCREEN;
displayGridRowHeight = global.screen_height / ROWS_REGULAR_SCREEN; displayGridRowHeight = primary.height / ROWS_REGULAR_SCREEN;
} }
}, },
relayout: function () { relayout: function () {
let screenHeight = global.screen_height; let primary = global.get_primary_monitor();
let screenWidth = global.screen_width;
this._group.set_position(primary.x, primary.y);
let contentY = Panel.PANEL_HEIGHT; let contentY = Panel.PANEL_HEIGHT;
let contentHeight = screenHeight - contentY; let contentHeight = primary.height - contentY;
this._coverPane.set_position(0, 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 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; let workspaceRowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
this._workspacesWidth = displayGridColumnWidth * workspaceColumnsUsed this._workspacesWidth = displayGridColumnWidth * workspaceColumnsUsed
- WORKSPACE_GRID_PADDING * 2; - 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. // so that the workspace preserves its aspect ratio.
this._workspacesHeight = displayGridRowHeight * workspaceRowsUsed 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._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_position(0, contentY);
this._dash.actor.set_size(displayGridColumnWidth, contentHeight); 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 // place the 'Add Workspace' button in the bottom row of the grid
addRemoveButtonSize = Math.floor(displayGridRowHeight * 3/5); addRemoveButtonSize = Math.floor(displayGridRowHeight * 3/5);
this._addButtonX = this._workspacesX + this._workspacesWidth - addRemoveButtonSize; 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_position(0, 0);
this._backOver.set_size(global.screen_width, contentHeight); this._backOver.set_size(global.screen_width, global.screen_height);
this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING, this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
contentY); contentY);
@ -198,7 +200,7 @@ Overview.prototype = {
this._paneContainer.height = contentHeight; this._paneContainer.height = contentHeight;
this._transparentBackground.set_position(this._paneContainer.x, this._paneContainer.y); 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); this._paneContainer.height);
if (this._activeDisplayPane != null) if (this._activeDisplayPane != null)

View File

@ -60,24 +60,26 @@ RunDialog.prototype = {
// All actors are inside _group. We create it initially // All actors are inside _group. We create it initially
// hidden then show it in show() // 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); 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, this._boxH = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
x_align: Big.BoxAlignment.CENTER, x_align: Big.BoxAlignment.CENTER,
y_align: Big.BoxAlignment.CENTER, y_align: Big.BoxAlignment.CENTER });
width: global.screen_width,
height: global.screen_height });
this._group.add_actor(boxH); this._group.add_actor(this._boxH);
this._lightbox.highlight(boxH); lightbox.highlight(this._boxH);
let boxV = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, let boxV = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
y_align: Big.BoxAlignment.CENTER }); 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, let dialogBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
@ -87,7 +89,7 @@ RunDialog.prototype = {
padding: DIALOG_PADDING, padding: DIALOG_PADDING,
width: DIALOG_WIDTH }); 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, let label = new Clutter.Text({ color: BOX_TEXT_COLOR,
font_name: '18px Sans', font_name: '18px Sans',
@ -182,6 +184,12 @@ RunDialog.prototype = {
if (!Main.pushModal(this._group)) if (!Main.pushModal(this._group))
return; 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._isOpen = true;
this._group.show(); this._group.show();

View File

@ -869,3 +869,99 @@ shell_global_create_root_pixmap_actor (ShellGlobal *global)
return clutter_clone_new (global->root_pixmap); 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);
}

View File

@ -73,6 +73,10 @@ void shell_global_format_time_relative_pretty (ShellGlobal *global, guint delta,
ClutterActor *shell_global_create_root_pixmap_actor (ShellGlobal *global); 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 G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */ #endif /* __SHELL_GLOBAL_H__ */