From c27d89218ce16d99a2045241dbb1c411141217a5 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 23 Feb 2003 17:09:46 +0000 Subject: [PATCH] Patch from Rob Adams addresses #95014 (placement issues), makes first fit 2003-02-23 Havoc Pennington 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. --- ChangeLog | 31 +++++++ src/place.c | 137 ++++++++++++++++++------------ src/screen.c | 70 ++++++++++++--- src/screen.h | 14 ++- src/stack.c | 8 +- src/window.c | 151 ++++++++++++++++++++++----------- src/window.h | 10 ++- src/workspace.c | 221 +++++++++++++++++++++++++++++++++++++----------- src/workspace.h | 18 +++- 9 files changed, 481 insertions(+), 179 deletions(-) diff --git a/ChangeLog b/ChangeLog index 159599e71..9e516a58d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2003-02-23 Havoc Pennington + + 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 * src/metacity.schemas.in: change toggle_maximized to diff --git a/src/place.c b/src/place.c index 7e03faa37..68b62b6bd 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; + 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 xinerama screen */ - return - ((rect->x + rect->width) < (xsi->x_origin + xsi->width)) && - ((rect->y + rect->height) < (xsi->y_origin + xsi->height)); + /* 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 */ + tmp = tmp->next; + } + + /* 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 25fc8313e..f02e947fd 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,19 +1328,51 @@ meta_screen_get_xinerama_for_window (MetaScreen *screen, best_xinerama = i; } } - + ++i; } return &screen->xinerama_infos[best_xinerama]; } +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 dd47da95d..d58bdd251 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 9aa4b9b03..1f81b5ea6 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 a1d247043..2b0839bdc 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; - - 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); + int xinerama_origin_x; + int xinerama_origin_y; + int xinerama_width; + int xinerama_height; + g_assert (which_xinerama >= 0); + + 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 e8541f5c0..9eb94a7ac 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 f6eacc925..5f6476bae 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) - { - int left_strut = 0; - int right_strut = 0; - int top_strut = 0; - int bottom_strut = 0; - GList *tmp; - GList *windows; +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) + { + left_strut = 0; + right_strut = 0; + top_strut = 0; + bottom_strut = 0; - windows = meta_workspace_list_windows (workspace); 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; } - *area = workspace->work_area; + 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); + + 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 22d004b80..1e1ba92f6 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,