summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2003-02-23 17:09:46 +0000
committerHavoc Pennington <hp@src.gnome.org>2003-02-23 17:09:46 +0000
commitc27d89218ce16d99a2045241dbb1c411141217a5 (patch)
tree32e1bebbc12ef895c5ec2f9b91d526f924bfc0eb
parent15c5ddbec4c6be9032fe8c77f815e4122190377b (diff)
downloadmetacity-c27d89218ce16d99a2045241dbb1c411141217a5.tar.gz
Patch from Rob Adams addresses #95014 (placement issues), makes first fit
2003-02-23 Havoc Pennington <hp@pobox.com> Patch from Rob Adams addresses #95014 (placement issues), makes first fit algorithm "center tile", adds most code for per-xinerama workspaces (#86682) but disables it for now. * src/workspace.c (meta_workspace_get_work_area_for_xinerama) (meta_workspace_get_work_area_all_xineramas): new xinerama functions, maintain workspace->work_areas with a different work area for each xinerama. However for now all the work areas are the same, because haven't quite figured out how _NET_WM_STRUT is supposed to work * src/window.c: adapt to new meta_window_* xinerama APIs (meta_window_get_work_area_current_xinerama): new xinerama API (meta_window_get_work_area_for_xinerama): new xinerama API (constrain_position): be a bit more clever about which xinerama's work area we choose to use. * src/stack.c: adapt to new Xinerama API * src/screen.c (reload_xinerama_infos): invalidate all work areas (meta_screen_get_xinerama_for_rect): new function (meta_screen_window_intersects_xinerama): new function * src/place.c (find_first_fit): change to use "center tiling" (center a screen full of tiled windows, rather than aligning them top left). Adapt to new xinerama functions.
-rw-r--r--ChangeLog31
-rw-r--r--src/place.c137
-rw-r--r--src/screen.c70
-rw-r--r--src/screen.h14
-rw-r--r--src/stack.c8
-rw-r--r--src/window.c149
-rw-r--r--src/window.h10
-rw-r--r--src/workspace.c221
-rw-r--r--src/workspace.h18
9 files changed, 480 insertions, 178 deletions
diff --git a/ChangeLog b/ChangeLog
index 159599e7..9e516a58 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2003-02-23 Havoc Pennington <hp@pobox.com>
+
+ Patch from Rob Adams addresses #95014 (placement issues),
+ makes first fit algorithm "center tile", adds most code
+ for per-xinerama workspaces (#86682) but disables it for now.
+
+ * src/workspace.c (meta_workspace_get_work_area_for_xinerama)
+ (meta_workspace_get_work_area_all_xineramas): new xinerama
+ functions, maintain workspace->work_areas with a different
+ work area for each xinerama. However for now all the work
+ areas are the same, because haven't quite figured out how
+ _NET_WM_STRUT is supposed to work
+
+ * src/window.c: adapt to new meta_window_* xinerama APIs
+ (meta_window_get_work_area_current_xinerama): new xinerama
+ API
+ (meta_window_get_work_area_for_xinerama): new xinerama API
+ (constrain_position): be a bit more clever about which xinerama's
+ work area we choose to use.
+
+ * src/stack.c: adapt to new Xinerama API
+
+ * src/screen.c (reload_xinerama_infos): invalidate all work areas
+ (meta_screen_get_xinerama_for_rect): new function
+ (meta_screen_window_intersects_xinerama): new function
+
+ * src/place.c (find_first_fit): change to use
+ "center tiling" (center a screen full of tiled windows,
+ rather than aligning them top left). Adapt to new
+ xinerama functions.
+
2003-02-22 Rob Adams <robadams@ucla.edu>
* src/metacity.schemas.in: change toggle_maximized to
diff --git a/src/place.c b/src/place.c
index 7e03faa3..68b62b6b 100644
--- a/src/place.c
+++ b/src/place.c
@@ -2,6 +2,8 @@
/*
* Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
+ * Copyright (C) 2003 Rob Adams
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -120,13 +122,13 @@ find_next_cascade (MetaWindow *window,
* cascade_x, cascade_y are the target position
* of NW corner of window frame.
*/
-
- /* FIXME this is bogus because we get the current xinerama
- * for the window based on its position, but we haven't
- * placed it yet.
+
+ /* FIXME should use xinerama with mouse pointer
+ * (or better, xinerama where window was launched
+ * determined via startup notification)
*/
- meta_window_get_work_area (window, TRUE, &work_area);
-
+ meta_window_get_work_area_for_xinerama (window, 0, &work_area);
+
cascade_x = MAX (0, work_area.x);
cascade_y = MAX (0, work_area.y);
@@ -363,14 +365,36 @@ topmost_cmp (gconstpointer a, gconstpointer b)
return 0;
}
+static void
+center_tile_rect_in_area (MetaRectangle *rect,
+ MetaRectangle *work_area)
+{
+ int fluff;
+
+ /* The point here is to tile a window such that "extra"
+ * space is equal on either side (i.e. so a full screen
+ * of windows tiled this way would center the windows
+ * as a group)
+ */
+
+ fluff = (work_area->width % rect->width) / 2;
+ rect->x = work_area->x + fluff;
+ fluff = (work_area->height % rect->height) / 3;
+ rect->y = work_area->y + fluff;
+}
+
static gboolean
-fit_rect_in_xinerama (MetaScreen *screen,
+fit_rect_in_xinerama (MetaWindow *window,
MetaRectangle *rect)
{
int i;
int best_index;
int best_overlap;
+ MetaScreen *screen;
+ MetaRectangle work_area;
const MetaXineramaScreenInfo *xsi;
+
+ screen = window->screen;
/* Find xinerama with best fit, then
* shift rect to be entirely within it.
@@ -409,17 +433,17 @@ fit_rect_in_xinerama (MetaScreen *screen,
/* some overlap had to be better than -1 */
g_assert (best_index >= 0);
- xsi = &screen->xinerama_infos[best_index];
+ meta_window_get_work_area_for_xinerama (window, best_index, &work_area);
- if (rect->x < xsi->x_origin)
- rect->x = xsi->x_origin;
- if (rect->y < xsi->y_origin)
- rect->y = xsi->y_origin;
-
- /* Now return whether we are entirely within the xinerama screen */
- return
- ((rect->x + rect->width) < (xsi->x_origin + xsi->width)) &&
- ((rect->y + rect->height) < (xsi->y_origin + xsi->height));
+ if ((rect->x < work_area.x) || (rect->y < work_area.y) ||
+ (rect->x >= work_area.x + work_area.width) ||
+ (rect->y >= work_area.y + work_area.height))
+ center_tile_rect_in_area (rect, &work_area);
+
+ /* Now return whether we are entirely within the work area */
+ return
+ ((rect->x + rect->width) < (work_area.x + work_area.width)) &&
+ ((rect->y + rect->height) < (work_area.y + work_area.height));
}
/* Find the leftmost, then topmost, empty area on the workspace
@@ -446,12 +470,12 @@ find_first_fit (MetaWindow *window,
* the bottom of each existing window, and then to the right
* of each existing window, aligned with the left/top of the
* existing window in each of those cases.
- */
-
+ */
int retval;
GList *sorted;
GList *tmp;
MetaRectangle rect;
+ MetaRectangle work_area;
int i;
retval = FALSE;
@@ -466,11 +490,16 @@ find_first_fit (MetaWindow *window,
rect.height += fgeom->top_height + fgeom->bottom_height;
}
- /* Try origin of first Xinerama */
- rect.x = window->screen->xinerama_infos[0].x_origin;
- rect.y = window->screen->xinerama_infos[0].y_origin;
+ /* Try center-tiling on first xinerama */
+ /* FIXME should use xinerama with mouse pointer
+ * (or better, xinerama where window was launched
+ * determined via startup notification)
+ */
+ meta_window_get_work_area_for_xinerama (window, 0, &work_area);
- if (fit_rect_in_xinerama (window->screen, &rect) &&
+ center_tile_rect_in_area (&rect, &work_area);
+
+ if (fit_rect_in_xinerama (window, &rect) &&
!rectangle_overlaps_some_window (&rect, windows))
{
*new_x = rect.x;
@@ -497,13 +526,13 @@ find_first_fit (MetaWindow *window,
{
MetaWindow *w = tmp->data;
MetaRectangle outer_rect;
-
- meta_window_get_outer_rect (w, &outer_rect);
+ meta_window_get_outer_rect (w, &outer_rect);
+
rect.x = outer_rect.x;
rect.y = outer_rect.y + outer_rect.height;
- if (fit_rect_in_xinerama (window->screen, &rect) &&
+ if (fit_rect_in_xinerama (window, &rect) &&
!rectangle_overlaps_some_window (&rect, sorted))
{
*new_x = rect.x;
@@ -513,12 +542,12 @@ find_first_fit (MetaWindow *window,
*new_x += fgeom->left_width;
*new_y += fgeom->top_height;
}
-
+
retval = TRUE;
-
+
goto out;
}
-
+
tmp = tmp->next;
}
@@ -531,13 +560,13 @@ find_first_fit (MetaWindow *window,
{
MetaWindow *w = tmp->data;
MetaRectangle outer_rect;
-
+
meta_window_get_outer_rect (w, &outer_rect);
-
+
rect.x = outer_rect.x + outer_rect.width;
rect.y = outer_rect.y;
-
- if (fit_rect_in_xinerama (window->screen, &rect) &&
+
+ if (fit_rect_in_xinerama (window, &rect) &&
!rectangle_overlaps_some_window (&rect, sorted))
{
*new_x = rect.x;
@@ -547,23 +576,24 @@ find_first_fit (MetaWindow *window,
*new_x += fgeom->left_width;
*new_y += fgeom->top_height;
}
-
+
retval = TRUE;
-
+
goto out;
- }
-
+ }
+
tmp = tmp->next;
- }
+ }
- /* Origin of each Xinerama screen which isn't the first */
+ /* Try center-tile on each Xinerama screen which isn't the first */
i = 1;
while (i < window->screen->n_xinerama_infos)
{
- rect.x = window->screen->xinerama_infos[i].x_origin;
- rect.y = window->screen->xinerama_infos[i].y_origin;
-
- if (fit_rect_in_xinerama (window->screen, &rect) &&
+ meta_window_get_work_area_for_xinerama (window, i, &work_area);
+
+ center_tile_rect_in_area (&rect, &work_area);
+
+ if (fit_rect_in_xinerama (window, &rect) &&
!rectangle_overlaps_some_window (&rect, windows))
{
*new_x = rect.x;
@@ -578,6 +608,7 @@ find_first_fit (MetaWindow *window,
goto out;
}
+
++i;
}
@@ -602,17 +633,18 @@ constrain_placement (MetaWindow *window,
int nw_x, nw_y;
int offscreen_w, offscreen_h;
MetaRectangle outer_rect;
-
+
meta_window_get_outer_rect (window, &outer_rect);
-
+
/* FIXME this is bogus because we get the current xinerama
* for the window based on its position, but we haven't
* placed it yet.
*/
- meta_window_get_work_area (window, TRUE, &work_area);
+ meta_window_get_work_area_current_xinerama (window, &work_area);
nw_x = work_area.x;
nw_y = work_area.y;
+
if (window->frame)
{
nw_x += fgeom->left_width;
@@ -849,6 +881,7 @@ meta_window_place (MetaWindow *window,
constrain_placement (window, fgeom, x, y, &x, &y);
done_no_constraints:
+
*new_x = x;
*new_y = y;
}
@@ -946,13 +979,11 @@ get_vertical_edges (MetaWindow *window,
edges = g_new (int, n_edges);
/* workspace/screen edges */
- meta_window_get_work_area (window, FALSE, &work_area);
+ meta_window_get_work_area_current_xinerama (window, &work_area);
edges[i] = work_area.x;
++i;
- edges[i] =
- work_area.x +
- work_area.width;
+ edges[i] = work_area.x + work_area.width;
++i;
edges[i] = 0;
++i;
@@ -1019,13 +1050,11 @@ get_horizontal_edges (MetaWindow *window,
edges = g_new (int, n_edges);
/* workspace/screen edges */
- meta_window_get_work_area (window, FALSE, &work_area);
+ meta_window_get_work_area_current_xinerama (window, &work_area);
edges[i] = work_area.y;
++i;
- edges[i] =
- work_area.y +
- work_area.height;
+ edges[i] = work_area.y + work_area.height;
++i;
edges[i] = 0;
++i;
diff --git a/src/screen.c b/src/screen.c
index 25fc8313..f02e947f 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -5,6 +5,7 @@
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
+ * Copyright (C) 2003 Rob Adams
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -352,6 +353,20 @@ reload_xinerama_infos (MetaScreen *screen)
g_assert (screen->n_xinerama_infos > 0);
g_assert (screen->xinerama_infos != NULL);
+
+ {
+ GList *tmp;
+
+ tmp = screen->workspaces;
+ while (tmp != NULL)
+ {
+ MetaWorkspace *space = tmp->data;
+
+ meta_workspace_invalidate_work_area (space);
+
+ tmp = tmp->next;
+ }
+ }
}
MetaScreen*
@@ -1283,18 +1298,15 @@ meta_screen_focus_default_window (MetaScreen *screen,
}
const MetaXineramaScreenInfo*
-meta_screen_get_xinerama_for_window (MetaScreen *screen,
- MetaWindow *window)
+meta_screen_get_xinerama_for_rect (MetaScreen *screen,
+ MetaRectangle *rect)
{
int i;
int best_xinerama, xinerama_score;
- MetaRectangle window_rect;
if (screen->n_xinerama_infos == 1)
return &screen->xinerama_infos[0];
-
- meta_window_get_outer_rect (window, &window_rect);
-
+
best_xinerama = 0;
xinerama_score = 0;
@@ -1308,7 +1320,7 @@ meta_screen_get_xinerama_for_window (MetaScreen *screen,
screen_info.width = screen->xinerama_infos[i].width;
screen_info.height = screen->xinerama_infos[i].height;
- if (meta_rectangle_intersect (&screen_info, &window_rect, &dest))
+ if (meta_rectangle_intersect (&screen_info, rect, &dest))
{
if (dest.width * dest.height > xinerama_score)
{
@@ -1316,7 +1328,7 @@ meta_screen_get_xinerama_for_window (MetaScreen *screen,
best_xinerama = i;
}
}
-
+
++i;
}
@@ -1324,11 +1336,43 @@ meta_screen_get_xinerama_for_window (MetaScreen *screen,
}
const MetaXineramaScreenInfo*
+meta_screen_get_xinerama_for_window (MetaScreen *screen,
+ MetaWindow *window)
+{
+ MetaRectangle window_rect;
+
+ meta_window_get_outer_rect (window, &window_rect);
+
+ return meta_screen_get_xinerama_for_rect (screen, &window_rect);
+}
+
+gboolean
+meta_screen_window_intersects_xinerama (MetaScreen *screen,
+ MetaWindow *window,
+ int which_xinerama)
+{
+ MetaRectangle window_rect;
+ MetaRectangle dest, screen_rect;
+
+ meta_window_get_outer_rect (window, &window_rect);
+
+ screen_rect.x = screen->xinerama_infos[which_xinerama].x_origin;
+ screen_rect.y = screen->xinerama_infos[which_xinerama].y_origin;
+ screen_rect.width = screen->xinerama_infos[which_xinerama].width;
+ screen_rect.height = screen->xinerama_infos[which_xinerama].height;
+
+ if (meta_rectangle_intersect (&screen_rect, &window_rect, &dest))
+ return TRUE;
+
+ return FALSE;
+}
+
+const MetaXineramaScreenInfo*
meta_screen_get_current_xinerama (MetaScreen *screen)
{
if (screen->n_xinerama_infos == 1)
return &screen->xinerama_infos[0];
-
+
/* Sadly, we have to do it this way. Yuck.
*/
@@ -1357,9 +1401,11 @@ meta_screen_get_current_xinerama (MetaScreen *screen)
while (i < screen->n_xinerama_infos)
{
if ((root_x_return >= screen->xinerama_infos[i].x_origin &&
- root_x_return < (screen->xinerama_infos[i].x_origin + screen->xinerama_infos[i].width) &&
+ root_x_return < (screen->xinerama_infos[i].x_origin +
+ screen->xinerama_infos[i].width) &&
root_y_return >= screen->xinerama_infos[i].y_origin &&
- root_y_return < (screen->xinerama_infos[i].y_origin + screen->xinerama_infos[i].height)))
+ root_y_return < (screen->xinerama_infos[i].y_origin +
+ screen->xinerama_infos[i].height)))
{
screen->last_xinerama_index = i;
break;
@@ -1594,7 +1640,7 @@ set_work_area_hint (MetaScreen *screen)
if (workspace->screen == screen)
{
- meta_workspace_get_work_area (workspace, &area);
+ meta_workspace_get_work_area_all_xineramas (workspace, &area);
tmp[0] = area.x;
tmp[1] = area.y;
tmp[2] = area.width;
diff --git a/src/screen.h b/src/screen.h
index dd47da95..d58bdd25 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -133,9 +133,17 @@ void meta_screen_focus_mouse_window (MetaScreen *scre
void meta_screen_focus_default_window (MetaScreen *screen,
MetaWindow *not_this_one);
-const MetaXineramaScreenInfo* meta_screen_get_current_xinerama (MetaScreen *screen);
-const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen,
- MetaWindow *window);
+
+const MetaXineramaScreenInfo* meta_screen_get_current_xinerama (MetaScreen *screen);
+const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_rect (MetaScreen *screen,
+ MetaRectangle *rect);
+const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen,
+ MetaWindow *window);
+
+
+gboolean meta_screen_window_intersects_xinerama (MetaScreen *screen,
+ MetaWindow *window,
+ int which_xinerama);
void meta_screen_update_workspace_layout (MetaScreen *screen);
void meta_screen_update_workspace_names (MetaScreen *screen);
diff --git a/src/stack.c b/src/stack.c
index 9aa4b9b0..1f81b5ea 100644
--- a/src/stack.c
+++ b/src/stack.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2001 Havoc Pennington
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -191,9 +191,9 @@ window_is_fullscreen_size (MetaWindow *window)
*/
MetaRectangle workarea;
- meta_window_get_work_area (window, FALSE, &workarea);
+ meta_window_get_work_area_current_xinerama (window, &workarea);
if (window->rect.x <= workarea.x &&
- window->rect.y <= workarea.y)
+ window->rect.y <= workarea.y)
return TRUE;
}
@@ -205,7 +205,7 @@ window_is_fullscreen_size (MetaWindow *window)
{
MetaRectangle workarea;
- meta_window_get_work_area (window, TRUE, &workarea);
+ meta_window_get_work_area_current_xinerama (window, &workarea);
if (window->rect.x <= workarea.x &&
window->rect.y <= workarea.y)
return TRUE;
diff --git a/src/window.c b/src/window.c
index a1d24704..2b0839bd 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2,7 +2,8 @@
/*
* Copyright (C) 2001 Havoc Pennington, Anders Carlsson
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
+ * Copyright (C) 2003 Rob Adams
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -668,9 +669,12 @@ meta_window_new (MetaDisplay *display,
{
MetaRectangle workarea;
MetaRectangle outer;
-
- meta_window_get_work_area (window, TRUE, &workarea);
+ if (!window->placed)
+ meta_warning ("Metacity issue: using position-based current xinerama prior to placement\n");
+
+ meta_window_get_work_area_current_xinerama (window, &workarea);
+
meta_window_get_outer_rect (window, &outer);
if (outer.width >= workarea.width &&
@@ -2181,7 +2185,7 @@ meta_window_move_resize_internal (MetaWindow *window,
/* We don't need it in the idle queue anymore. */
meta_window_unqueue_move_resize (window);
-
+
{
int oldx, oldy;
meta_window_get_position (window, &oldx, &oldy);
@@ -2702,7 +2706,7 @@ meta_window_fill_horizontal (MetaWindow *window)
w = window->rect.width;
h = window->rect.height;
- meta_window_get_work_area (window, TRUE, &work_area);
+ meta_window_get_work_area_current_xinerama (window, &work_area);
x = work_area.x;
w = work_area.width;
@@ -2730,7 +2734,7 @@ meta_window_fill_vertical (MetaWindow *window)
w = window->rect.width;
h = window->rect.height;
- meta_window_get_work_area (window, TRUE, &work_area);
+ meta_window_get_work_area_current_xinerama (window, &work_area);
y = work_area.y;
h = work_area.height;
@@ -5674,7 +5678,7 @@ constrain_size (MetaWindow *window,
{
MetaRectangle work_area;
- meta_window_get_work_area (window, TRUE, &work_area);
+ meta_window_get_work_area_current_xinerama (window, &work_area);
fullw = work_area.width;
fullh = work_area.height;
@@ -5823,9 +5827,15 @@ constrain_position (MetaWindow *window,
}
else if (window->maximized)
{
+ const MetaXineramaScreenInfo* xsi;
MetaRectangle work_area;
-
- meta_window_get_work_area (window, TRUE, &work_area);
+
+ xsi = meta_screen_get_xinerama_for_rect (window->screen,
+ &window->saved_rect);
+
+ meta_window_get_work_area_for_xinerama (window,
+ xsi->number,
+ &work_area);
x = work_area.x;
y = work_area.y;
@@ -5848,8 +5858,25 @@ constrain_position (MetaWindow *window,
int se_x, se_y;
int offscreen_w, offscreen_h;
MetaRectangle work_area;
+ MetaRectangle window_area;
+ const MetaXineramaScreenInfo* xsi;
+
+ /* this is the rect for the window if it were where we're moving
+ * it now
+ */
+ meta_window_get_outer_rect (window, &window_area);
+ window_area.x = x;
+ window_area.y = y;
+ if (fgeom)
+ {
+ window_area.x -= fgeom->left_width;
+ window_area.y -= fgeom->top_height;
+ }
- meta_window_get_work_area (window, FALSE, &work_area);
+ xsi = meta_screen_get_xinerama_for_rect (window->screen, &window_area);
+ meta_window_get_work_area_for_xinerama (window,
+ xsi->number,
+ &work_area);
/* (FIXME instead of TITLEBAR_LENGTH_ONSCREEN, get the actual
* size of the menu control?).
@@ -5936,7 +5963,7 @@ constrain_position (MetaWindow *window,
nw_y = se_y;
se_y = tmp;
}
-
+
/* Clamp window to the given positions.
* Do the SE clamp first, so that the NW clamp has precedence
* and we don't tend to lose the titlebar for too-large
@@ -5951,7 +5978,7 @@ constrain_position (MetaWindow *window,
x = nw_x;
if (y < nw_y)
y = nw_y;
-
+
#undef TITLEBAR_LENGTH_ONSCREEN
}
@@ -6568,65 +6595,89 @@ meta_window_set_gravity (MetaWindow *window,
meta_error_trap_pop (window->display, FALSE);
}
-void
-meta_window_get_work_area (MetaWindow *window,
- gboolean for_current_xinerama,
- MetaRectangle *area)
+static void
+get_work_area (MetaWindow *window,
+ MetaRectangle *area,
+ int which_xinerama)
{
MetaRectangle space_area;
- GList *tmp;
-
+ GList *tmp;
int left_strut;
int right_strut;
int top_strut;
int bottom_strut;
+ int xinerama_origin_x;
+ int xinerama_origin_y;
+ int xinerama_width;
+ int xinerama_height;
+
+ g_assert (which_xinerama >= 0);
- if (for_current_xinerama)
- {
- const MetaXineramaScreenInfo *xinerama;
-
- xinerama = meta_screen_get_xinerama_for_window (window->screen,
- window);
-
- left_strut = xinerama->x_origin;
- right_strut = window->screen->width - xinerama->width - xinerama->x_origin;
- top_strut = xinerama->y_origin;
- bottom_strut = window->screen->height - xinerama->height - xinerama->y_origin;
- }
- else
- {
- left_strut = 0;
- right_strut = 0;
- top_strut = 0;
- bottom_strut = 0;
- }
-
- tmp = meta_window_get_workspaces (window);
+ xinerama_origin_x = window->screen->xinerama_infos[which_xinerama].x_origin;
+ xinerama_origin_y = window->screen->xinerama_infos[which_xinerama].y_origin;
+ xinerama_width = window->screen->xinerama_infos[which_xinerama].width;
+ xinerama_height = window->screen->xinerama_infos[which_xinerama].height;
+
+ left_strut = 0;
+ right_strut = 0;
+ top_strut = 0;
+ bottom_strut = 0;
+ tmp = meta_window_get_workspaces (window);
while (tmp != NULL)
{
- meta_workspace_get_work_area (tmp->data, &space_area);
+ meta_workspace_get_work_area_for_xinerama (tmp->data,
+ which_xinerama,
+ &space_area);
- left_strut = MAX (left_strut, space_area.x);
+ left_strut = MAX (left_strut, space_area.x - xinerama_origin_x);
right_strut = MAX (right_strut,
- (window->screen->width - space_area.x - space_area.width));
- top_strut = MAX (top_strut, space_area.y);
+ (xinerama_width -
+ (space_area.x - xinerama_origin_x) -
+ space_area.width));
+ top_strut = MAX (top_strut, space_area.y - xinerama_origin_y);
bottom_strut = MAX (bottom_strut,
- (window->screen->height - space_area.y - space_area.height));
-
+ (xinerama_height -
+ (space_area.y - xinerama_origin_y) -
+ space_area.height));
tmp = tmp->next;
}
- area->x = left_strut;
- area->y = top_strut;
- area->width = window->screen->width - left_strut - right_strut;
- area->height = window->screen->height - top_strut - bottom_strut;
+ area->x = xinerama_origin_x + left_strut;
+ area->y = xinerama_origin_y + top_strut;
+ area->width = xinerama_width - left_strut - right_strut;
+ area->height = xinerama_height - top_strut - bottom_strut;
meta_topic (META_DEBUG_WORKAREA,
"Window %s has work area %d,%d %d x %d\n",
window->desc, area->x, area->y, area->width, area->height);
}
+void
+meta_window_get_work_area_current_xinerama (MetaWindow *window,
+ MetaRectangle *area)
+{
+ const MetaXineramaScreenInfo *xinerama = NULL;
+ xinerama = meta_screen_get_xinerama_for_window (window->screen,
+ window);
+
+ meta_window_get_work_area_for_xinerama (window,
+ xinerama->number,
+ area);
+}
+
+void
+meta_window_get_work_area_for_xinerama (MetaWindow *window,
+ int which_xinerama,
+ MetaRectangle *area)
+{
+ g_return_if_fail (which_xinerama >= 0);
+
+ get_work_area (window,
+ area,
+ which_xinerama);
+}
+
gboolean
meta_window_same_application (MetaWindow *window,
MetaWindow *other_window)
diff --git a/src/window.h b/src/window.h
index e8541f5c..9eb94a7a 100644
--- a/src/window.h
+++ b/src/window.h
@@ -413,10 +413,12 @@ void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
gboolean meta_window_visible_on_workspace (MetaWindow *window,
MetaWorkspace *workspace);
-/* Get minimum work area for all workspaces we're on */
-void meta_window_get_work_area (MetaWindow *window,
- gboolean for_current_xinerama,
- MetaRectangle *area);
+void meta_window_get_work_area_current_xinerama (MetaWindow *window,
+ MetaRectangle *area);
+void meta_window_get_work_area_for_xinerama (MetaWindow *window,
+ int which_xinerama,
+ MetaRectangle *area);
+
gboolean meta_window_same_application (MetaWindow *window,
MetaWindow *other_window);
diff --git a/src/workspace.c b/src/workspace.c
index f6eacc92..5f6476ba 100644
--- a/src/workspace.c
+++ b/src/workspace.c
@@ -42,11 +42,12 @@ meta_workspace_new (MetaScreen *screen)
g_list_append (workspace->screen->workspaces, workspace);
workspace->windows = NULL;
- workspace->work_area.x = 0;
- workspace->work_area.y = 0;
- workspace->work_area.width = screen->width;
- workspace->work_area.height = screen->height;
- workspace->work_area_invalid = TRUE;
+ workspace->work_areas = NULL;
+ workspace->work_areas_invalid = TRUE;
+ workspace->all_work_areas.x = 0;
+ workspace->all_work_areas.y = 0;
+ workspace->all_work_areas.width = 0;
+ workspace->all_work_areas.height = 0;
return workspace;
}
@@ -84,6 +85,7 @@ meta_workspace_free (MetaWorkspace *workspace)
workspace->screen->workspaces =
g_list_remove (workspace->screen->workspaces, workspace);
+ g_free (workspace->work_areas);
g_free (workspace);
/* don't bother to reset names, pagers can just ignore
@@ -304,7 +306,7 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
GList *tmp;
GList *windows;
- if (workspace->work_area_invalid)
+ if (workspace->work_areas_invalid)
{
meta_topic (META_DEBUG_WORKAREA,
"Work area for workspace %d is already invalid\n",
@@ -315,8 +317,11 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
meta_topic (META_DEBUG_WORKAREA,
"Invalidating work area for workspace %d\n",
meta_workspace_index (workspace));
+
+ g_free (workspace->work_areas);
+ workspace->work_areas = NULL;
- workspace->work_area_invalid = TRUE;
+ workspace->work_areas_invalid = TRUE;
/* redo the size/position constraints on all windows */
windows = meta_workspace_list_windows (workspace);
@@ -335,81 +340,201 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
meta_screen_queue_workarea_recalc (workspace->screen);
}
-void
-meta_workspace_get_work_area (MetaWorkspace *workspace,
- MetaRectangle *area)
-{
- if (workspace->work_area_invalid)
+static void
+ensure_work_areas_validated (MetaWorkspace *workspace)
+{
+ int left_strut = 0;
+ int right_strut = 0;
+ int top_strut = 0;
+ int bottom_strut = 0;
+ int all_left_strut = 0;
+ int all_right_strut = 0;
+ int all_top_strut = 0;
+ int all_bottom_strut = 0;
+ int i;
+ GList *tmp;
+ GList *windows;
+
+ if (!workspace->work_areas_invalid)
+ return;
+
+ windows = meta_workspace_list_windows (workspace);
+
+ g_free (workspace->work_areas);
+ workspace->work_areas = g_new (MetaRectangle,
+ workspace->screen->n_xinerama_infos);
+
+ i = 0;
+ while (i < workspace->screen->n_xinerama_infos)
{
- int left_strut = 0;
- int right_strut = 0;
- int top_strut = 0;
- int bottom_strut = 0;
- GList *tmp;
- GList *windows;
-
- windows = meta_workspace_list_windows (workspace);
+ left_strut = 0;
+ right_strut = 0;
+ top_strut = 0;
+ bottom_strut = 0;
+
tmp = windows;
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
- if (w->has_struts)
+ if (w->has_struts &&
+ (meta_screen_window_intersects_xinerama (w->screen, w, i)))
{
meta_topic (META_DEBUG_WORKAREA,
- "Merging win %s with %d %d %d %d with %d %d %d %d\n",
+ "Merging win %s with %d %d %d %d "
+ "with %d %d %d %d\n",
w->desc,
- w->left_strut, w->right_strut, w->top_strut, w->bottom_strut,
- left_strut, right_strut, top_strut, bottom_strut);
- left_strut = MAX (left_strut, w->left_strut);
+ w->left_strut, w->right_strut,
+ w->top_strut, w->bottom_strut,
+ left_strut, right_strut,
+ top_strut, bottom_strut);
+
+ left_strut = MAX (left_strut,
+ w->left_strut -
+ workspace->screen->xinerama_infos[i].x_origin);
+ all_left_strut = MAX (all_left_strut, w->left_strut);
+
right_strut = MAX (right_strut, w->right_strut);
- top_strut = MAX (top_strut, w->top_strut);
+ all_right_strut = MAX (all_right_strut, w->right_strut);
+
+ top_strut = MAX (top_strut,
+ w->top_strut -
+ workspace->screen->xinerama_infos[i].y_origin);
+ all_top_strut = MAX (all_top_strut, w->top_strut);
+
bottom_strut = MAX (bottom_strut, w->bottom_strut);
+ all_bottom_strut = MAX (all_bottom_strut, w->bottom_strut);
}
tmp = tmp->next;
}
- g_list_free (windows);
-
/* Some paranoid robustness */
#define MIN_SANE_AREA 100
- if ((left_strut + right_strut) > (workspace->screen->width - MIN_SANE_AREA))
+ if ((left_strut + right_strut) >
+ (workspace->screen->xinerama_infos[i].width - MIN_SANE_AREA))
{
meta_topic (META_DEBUG_WORKAREA,
- "Making left/right struts %d %d sane\n",
- left_strut, right_strut);
- left_strut = (workspace->screen->width - MIN_SANE_AREA) / 2;
+ "Making left/right struts %d %d sane xinerama %d\n",
+ left_strut, right_strut, i);
+ left_strut = (workspace->screen->xinerama_infos[i].width -
+ MIN_SANE_AREA) / 2;
right_strut = left_strut;
}
- if ((top_strut + bottom_strut) > (workspace->screen->height - MIN_SANE_AREA))
+ if ((top_strut + bottom_strut) >
+ (workspace->screen->xinerama_infos[i].height - MIN_SANE_AREA))
{
meta_topic (META_DEBUG_WORKAREA,
- "Making top/bottom struts %d %d sane\n",
- top_strut, bottom_strut);
- top_strut = (workspace->screen->height - MIN_SANE_AREA) / 2;
+ "Making top/bottom struts %d %d sane xinerama %d\n",
+ top_strut, bottom_strut, i);
+ top_strut = (workspace->screen->xinerama_infos[i].height -
+ MIN_SANE_AREA) / 2;
bottom_strut = top_strut;
}
-
- workspace->work_area.x = left_strut;
- workspace->work_area.y = top_strut;
- workspace->work_area.width = workspace->screen->width - left_strut - right_strut;
- workspace->work_area.height = workspace->screen->height - top_strut - bottom_strut;
- workspace->work_area_invalid = FALSE;
+ /* FIXME even if we take struts to apply only to xineramas
+ * that the strut-specifying window overlaps, is it right
+ * to make the struts *relative to* the xinerama?
+ */
+ workspace->work_areas[i].x =
+ left_strut + workspace->screen->xinerama_infos[i].x_origin;
+ workspace->work_areas[i].y = top_strut +
+ workspace->screen->xinerama_infos[i].y_origin;
+ workspace->work_areas[i].width =
+ workspace->screen->xinerama_infos[i].width -
+ left_strut - right_strut;
+ workspace->work_areas[i].height =
+ workspace->screen->xinerama_infos[i].height -
+ top_strut - bottom_strut;
meta_topic (META_DEBUG_WORKAREA,
- "Computed work area for workspace %d: %d,%d %d x %d\n",
+ "Computed [unused] work area for workspace %d "
+ "xinerama %d: %d,%d %d x %d\n",
meta_workspace_index (workspace),
- workspace->work_area.x,
- workspace->work_area.y,
- workspace->work_area.width,
- workspace->work_area.height);
+ i,
+ workspace->work_areas[i].x,
+ workspace->work_areas[i].y,
+ workspace->work_areas[i].width,
+ workspace->work_areas[i].height);
+
+ ++i;
+ }
+
+ g_list_free (windows);
+
+ if ((all_left_strut + all_right_strut) >
+ (workspace->screen->width - MIN_SANE_AREA))
+ {
+ meta_topic (META_DEBUG_WORKAREA,
+ "Making screen-wide left/right struts %d %d sane\n",
+ all_left_strut, all_right_strut);
+ all_left_strut = (workspace->screen->width - MIN_SANE_AREA) / 2;
+ all_right_strut = all_left_strut;
+ }
+
+ if ((all_top_strut + all_bottom_strut) >
+ (workspace->screen->height - MIN_SANE_AREA))
+ {
+ meta_topic (META_DEBUG_WORKAREA,
+ "Making top/bottom struts %d %d sane\n",
+ all_top_strut, all_bottom_strut);
+ all_top_strut = (workspace->screen->height - MIN_SANE_AREA) / 2;
+ all_bottom_strut = all_top_strut;
+ }
+
+ workspace->all_work_areas.x = all_left_strut;
+ workspace->all_work_areas.y = all_top_strut;
+ workspace->all_work_areas.width =
+ workspace->screen->width - all_left_strut - all_right_strut;
+ workspace->all_work_areas.height =
+ workspace->screen->height - all_top_strut - all_bottom_strut;
+
+ /* FIXME Here we disable all the per-xinerama work done earlier,
+ * because we don't have a spec for how it should work yet.
+ * If we do rely on which windows overlap what, work areas
+ * will need to be invalidated when we change a strut-setting
+ * window's size/position in move_resize_internal
+ */
+ i = 0;
+ while (i < workspace->screen->n_xinerama_infos)
+ {
+ workspace->work_areas[i] = workspace->all_work_areas;
+ ++i;
}
+
+ workspace->work_areas_invalid = FALSE;
+
+ meta_topic (META_DEBUG_WORKAREA,
+ "Computed work area for workspace %d: %d,%d %d x %d\n",
+ meta_workspace_index (workspace),
+ workspace->all_work_areas.x,
+ workspace->all_work_areas.y,
+ workspace->all_work_areas.width,
+ workspace->all_work_areas.height);
+}
+
+void
+meta_workspace_get_work_area_for_xinerama (MetaWorkspace *workspace,
+ int which_xinerama,
+ MetaRectangle *area)
+{
+ g_assert (which_xinerama >= 0);
- *area = workspace->work_area;
+ ensure_work_areas_validated (workspace);
+ g_assert (which_xinerama < workspace->screen->n_xinerama_infos);
+
+ *area = workspace->work_areas[which_xinerama];
+}
+
+void
+meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace,
+ MetaRectangle *area)
+{
+ ensure_work_areas_validated (workspace);
+
+ *area = workspace->all_work_areas;
}
#ifdef WITH_VERBOSE_MODE
diff --git a/src/workspace.h b/src/workspace.h
index 22d004b8..1e1ba92f 100644
--- a/src/workspace.h
+++ b/src/workspace.h
@@ -40,9 +40,11 @@ struct _MetaWorkspace
MetaScreen *screen;
GList *windows;
+
+ MetaRectangle all_work_areas;
- MetaRectangle work_area;
- guint work_area_invalid : 1;
+ MetaRectangle *work_areas;
+ guint work_areas_invalid : 1;
};
MetaWorkspace* meta_workspace_new (MetaScreen *screen);
@@ -61,8 +63,16 @@ int meta_workspace_index (MetaWorkspace *workspace);
GList* meta_workspace_list_windows (MetaWorkspace *workspace);
void meta_workspace_invalidate_work_area (MetaWorkspace *workspace);
-void meta_workspace_get_work_area (MetaWorkspace *workspace,
- MetaRectangle *area);
+
+
+void meta_workspace_get_work_area_for_xinerama (MetaWorkspace *workspace,
+ int which_xinerama,
+ MetaRectangle *area);
+void meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace,
+ MetaRectangle *area);
+
+
+
MetaWorkspace* meta_workspace_get_neighbor (MetaWorkspace *workspace,