summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2002-01-10 06:31:31 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-01-10 06:31:31 +0000
commitb2bbb306f4cb142d3f649773312f78aac0dc93dc (patch)
tree6ba06f4a43737d8d718f5d11d4684400fdb468fb
parentda6ded6f3f917524289fa9a076acf4f97b1c9a8d (diff)
downloadmetacity-b2bbb306f4cb142d3f649773312f78aac0dc93dc.tar.gz
metacity-b2bbb306f4cb142d3f649773312f78aac0dc93dc.tar.bz2
store strut information, update it on property changes, etc. etc. so we
2002-01-09 Havoc Pennington <hp@pobox.com> * src/window.c, src/window.h: store strut information, update it on property changes, etc. etc. so we avoid panel on maximize. * src/workspace.c (meta_workspace_get_work_area): add accessor for work area so we can compute it lazily * src/display.h, src/display.c: add _NET_WM_STRUT atom and _WIN_HINTS atom
-rw-r--r--ChangeLog12
-rw-r--r--src/display.c6
-rw-r--r--src/display.h2
-rw-r--r--src/place.c35
-rw-r--r--src/window.c309
-rw-r--r--src/window.h15
-rw-r--r--src/workspace.c147
-rw-r--r--src/workspace.h9
8 files changed, 497 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index d25ed18..3ac0bfb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2002-01-09 Havoc Pennington <hp@pobox.com>
+
+ * src/window.c, src/window.h: store strut information,
+ update it on property changes, etc. etc. so we avoid panel
+ on maximize.
+
+ * src/workspace.c (meta_workspace_get_work_area): add accessor for
+ work area so we can compute it lazily
+
+ * src/display.h, src/display.c: add _NET_WM_STRUT atom
+ and _WIN_HINTS atom
+
2002-01-08 Havoc Pennington <hp@pobox.com>
* configure.in (ACLOCAL): add code to save ACLOCAL_FLAGS
diff --git a/src/display.c b/src/display.c
index 28a627e..9e77113 100644
--- a/src/display.c
+++ b/src/display.c
@@ -139,7 +139,9 @@ meta_display_open (const char *name)
"_KWM_WIN_ICON",
"_NET_WM_MOVERESIZE",
"_NET_ACTIVE_WINDOW",
- "_METACITY_RESTART_MESSAGE"
+ "_METACITY_RESTART_MESSAGE",
+ "_NET_WM_STRUT",
+ "_WIN_HINTS"
};
Atom atoms[G_N_ELEMENTS(atom_names)];
@@ -230,6 +232,8 @@ meta_display_open (const char *name)
display->atom_net_wm_moveresize = atoms[42];
display->atom_net_active_window = atoms[43];
display->atom_metacity_restart_message = atoms[44];
+ display->atom_net_wm_strut = atoms[45];
+ display->atom_win_hints = atoms[46];
/* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK,
* created in screen_new
diff --git a/src/display.h b/src/display.h
index 51f4aba..ca7351b 100644
--- a/src/display.h
+++ b/src/display.h
@@ -104,6 +104,8 @@ struct _MetaDisplay
Atom atom_net_wm_moveresize;
Atom atom_net_active_window;
Atom atom_metacity_restart_message;
+ Atom atom_net_wm_strut;
+ Atom atom_win_hints;
/* This is the actual window from focus events,
* not the one we last set
diff --git a/src/place.c b/src/place.c
index b67af69..6574d50 100644
--- a/src/place.c
+++ b/src/place.c
@@ -85,6 +85,7 @@ find_next_cascade (MetaWindow *window,
GList *sorted;
int cascade_x, cascade_y;
int x_threshold, y_threshold;
+ MetaRectangle work_area;
sorted = g_list_copy (windows);
sorted = g_list_sort (sorted, northwestcmp);
@@ -99,18 +100,10 @@ find_next_cascade (MetaWindow *window,
* cascade_x, cascade_y are the target position
* of NW corner of window frame.
*/
- cascade_x = 0;
- cascade_y = 0;
- tmp = window->workspaces;
- while (tmp != NULL)
- {
- MetaWorkspace *space = tmp->data;
-
- cascade_x = MAX (cascade_x, space->workarea.x);
- cascade_y = MAX (cascade_y, space->workarea.y);
-
- tmp = tmp->next;
- }
+ meta_window_get_work_area (window, &work_area);
+
+ cascade_x = MAX (0, work_area.x);
+ cascade_y = MAX (0, work_area.y);
/* Find first cascade position that's not used. */
@@ -445,6 +438,7 @@ get_vertical_edges (MetaWindow *window,
int i;
int n_edges;
MetaRectangle rect;
+ MetaRectangle work_area;
windows = get_windows_on_same_workspace (window, &n_windows);
@@ -453,11 +447,13 @@ get_vertical_edges (MetaWindow *window,
edges = g_new (int, n_edges);
/* workspace/screen edges */
- edges[i] = window->screen->active_workspace->workarea.x;
+ meta_window_get_work_area (window, &work_area);
+
+ edges[i] = work_area.x;
++i;
edges[i] =
- window->screen->active_workspace->workarea.x +
- window->screen->active_workspace->workarea.width;
+ work_area.x +
+ work_area.width;
++i;
edges[i] = 0;
++i;
@@ -508,6 +504,7 @@ get_horizontal_edges (MetaWindow *window,
int i;
int n_edges;
MetaRectangle rect;
+ MetaRectangle work_area;
windows = get_windows_on_same_workspace (window, &n_windows);
@@ -516,11 +513,13 @@ get_horizontal_edges (MetaWindow *window,
edges = g_new (int, n_edges);
/* workspace/screen edges */
- edges[i] = window->screen->active_workspace->workarea.y;
+ meta_window_get_work_area (window, &work_area);
+
+ edges[i] = work_area.y;
++i;
edges[i] =
- window->screen->active_workspace->workarea.y +
- window->screen->active_workspace->workarea.height;
+ work_area.y +
+ work_area.height;
++i;
edges[i] = 0;
++i;
diff --git a/src/window.c b/src/window.c
index 914a0c3..b13f52f 100644
--- a/src/window.c
+++ b/src/window.c
@@ -43,6 +43,16 @@ typedef enum
META_USER_MOVE_RESIZE = 1 << 2
} MetaMoveResizeFlags;
+typedef enum
+{
+ WIN_HINTS_SKIP_FOCUS = (1<<0), /* "alt-tab" skips this win */
+ WIN_HINTS_SKIP_WINLIST = (1<<1), /* not in win list */
+ WIN_HINTS_SKIP_TASKBAR = (1<<2), /* not on taskbar */
+ WIN_HINTS_GROUP_TRANSIENT = (1<<3), /* ??????? */
+ WIN_HINTS_FOCUS_ON_CLICK = (1<<4), /* app only accepts focus when clicked */
+ WIN_HINTS_DO_NOT_COVER = (1<<5) /* attempt to not cover this window */
+} GnomeWinHints;
+
static void constrain_size (MetaWindow *window,
MetaFrameGeometry *fgeom,
int width,
@@ -72,8 +82,11 @@ static int update_icon_name (MetaWindow *window);
static int update_icon (MetaWindow *window,
gboolean reread_rgb_icon);
static int update_kwm_icon (MetaWindow *window);
+static void update_struts (MetaWindow *window);
static void recalc_window_type (MetaWindow *window);
static void recalc_window_features (MetaWindow *window);
+static void recalc_do_not_cover_struts(MetaWindow *window);
+static void invalidate_work_areas (MetaWindow *window);
static int set_wm_state (MetaWindow *window,
int state);
static int set_net_wm_state (MetaWindow *window);
@@ -83,6 +96,8 @@ static gboolean process_property_notify (MetaWindow *window,
static void meta_window_show (MetaWindow *window);
static void meta_window_hide (MetaWindow *window);
+static GList* meta_window_get_workspaces (MetaWindow *window);
+
static gboolean meta_window_get_icon_geometry (MetaWindow *window,
MetaRectangle *rect);
@@ -350,6 +365,12 @@ meta_window_new (MetaDisplay *display, Window xwindow,
window->type = META_WINDOW_NORMAL;
window->type_atom = None;
+ window->has_struts = FALSE;
+ window->left_strut = 0;
+ window->right_strut = 0;
+ window->top_strut = 0;
+ window->bottom_strut = 0;
+
window->layer = META_LAYER_NORMAL;
window->stack_op = NULL;
window->initial_workspace = 0; /* not used */
@@ -359,6 +380,7 @@ meta_window_new (MetaDisplay *display, Window xwindow,
update_title (window);
update_protocols (window);
update_wm_hints (window);
+ update_struts (window);
update_net_wm_state (window);
/* Initially maximize if window is fullscreen; FIXME
@@ -1193,6 +1215,8 @@ meta_window_maximize (MetaWindow *window)
{
if (!window->maximized)
{
+ meta_verbose ("Maximizing %s\n", window->desc);
+
window->maximized = TRUE;
meta_window_raise (window);
@@ -1218,6 +1242,8 @@ meta_window_unmaximize (MetaWindow *window)
{
if (window->maximized)
{
+ meta_verbose ("Unmaximizing %s\n", window->desc);
+
window->maximized = FALSE;
meta_window_move_resize (window,
@@ -1660,7 +1686,7 @@ meta_window_move_resize_internal (MetaWindow *window,
window->frame->right_width = fgeom.right_width;
window->frame->bottom_height = fgeom.bottom_height;
}
-
+
/* See ICCCM 4.1.5 for when to send ConfigureNotify */
need_configure_notify = FALSE;
@@ -1756,6 +1782,19 @@ meta_window_move_resize_internal (MetaWindow *window,
{
meta_verbose ("Size/position not modified\n");
}
+
+ /* Update struts for new window size */
+ if (window->do_not_cover && (need_resize_client || need_move_client))
+ {
+ recalc_do_not_cover_struts (window);
+
+ /* Does a resize on all windows on entire current workspace,
+ * would be an infinite loop except for need_resize_client
+ * above.
+ */
+
+ invalidate_work_areas (window);
+ }
/* Invariants leaving this function are:
* a) window->rect and frame->rect reflect the actual
@@ -2636,6 +2675,44 @@ meta_window_client_message (MetaWindow *window,
return TRUE;
}
+ else if (event->xclient.message_type ==
+ display->atom_win_hints)
+ {
+ /* gnome-winhints.c seems to indicate that the hints are
+ * in l[1], though god knows why it's like that
+ */
+ gulong data[1];
+
+ meta_verbose ("_WIN_HINTS client message, hints: %ld\n",
+ event->xclient.data.l[1]);
+
+ if (event->xclient.data.l[1] & WIN_HINTS_DO_NOT_COVER)
+ {
+ meta_verbose ("Setting WIN_HINTS_DO_NOT_COVER\n");
+
+ data[0] = WIN_HINTS_DO_NOT_COVER;
+
+ meta_error_trap_push (window->display);
+ XChangeProperty (window->display->xdisplay,
+ window->xwindow, window->display->atom_win_hints,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)data, 1);
+ meta_error_trap_pop (window->display);
+ }
+ else
+ {
+ meta_verbose ("Unsetting WIN_HINTS_DO_NOT_COVER\n");
+
+ data[0] = 0;
+
+ meta_error_trap_push (window->display);
+ XDeleteProperty (window->display->xdisplay,
+ window->xwindow, window->display->atom_win_hints);
+ meta_error_trap_pop (window->display);
+ }
+
+ return TRUE;
+ }
return FALSE;
}
@@ -2858,6 +2935,16 @@ process_property_notify (MetaWindow *window,
update_kwm_icon (window);
update_icon (window, FALSE);
}
+ else if (event->atom == window->display->atom_net_wm_strut)
+ {
+ meta_verbose ("Property notify on %s for _NET_WM_STRUT\n", window->desc);
+ update_struts (window);
+ }
+ else if (event->atom == window->display->atom_win_hints)
+ {
+ meta_verbose ("Property notify on %s for _WIN_HINTS\n", window->desc);
+ update_struts (window);
+ }
return TRUE;
}
@@ -4377,6 +4464,166 @@ update_kwm_icon (MetaWindow *window)
return Success;
}
+static GList*
+meta_window_get_workspaces (MetaWindow *window)
+{
+ if (window->on_all_workspaces)
+ return window->display->workspaces;
+ else
+ return window->workspaces;
+}
+
+static void
+invalidate_work_areas (MetaWindow *window)
+{
+ GList *tmp;
+
+ tmp = meta_window_get_workspaces (window);
+
+ while (tmp != NULL)
+ {
+ meta_workspace_invalidate_work_area (tmp->data);
+ tmp = tmp->next;
+ }
+}
+
+static void
+update_struts (MetaWindow *window)
+{
+ gulong *struts = NULL;
+ int nitems;
+
+ meta_verbose ("Updating struts for %s\n", window->desc);
+
+ window->has_struts = FALSE;
+ window->do_not_cover = FALSE;
+ window->left_strut = 0;
+ window->right_strut = 0;
+ window->top_strut = 0;
+ window->bottom_strut = 0;
+
+ if (meta_prop_get_cardinal_list (window->display,
+ window->xwindow,
+ window->display->atom_net_wm_strut,
+ &struts, &nitems))
+ {
+ if (nitems != 4)
+ {
+ meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4\n",
+ window->desc, nitems);
+ meta_XFree (struts);
+ }
+
+ window->has_struts = TRUE;
+ window->left_strut = struts[0];
+ window->right_strut = struts[1];
+ window->top_strut = struts[2];
+ window->bottom_strut = struts[3];
+
+ meta_verbose ("Using _NET_WM_STRUT struts %d %d %d %d for window %s\n",
+ window->left_strut, window->right_strut,
+ window->top_strut, window->bottom_strut,
+ window->desc);
+
+ meta_XFree (struts);
+ }
+ else
+ {
+ meta_verbose ("No _NET_WM_STRUT property for %s\n",
+ window->desc);
+ }
+
+ if (!window->has_struts)
+ {
+ /* Try _WIN_HINTS */
+ gulong hints;
+
+ if (meta_prop_get_cardinal (window->display,
+ window->xwindow,
+ window->display->atom_win_hints,
+ &hints))
+ {
+ if (hints & WIN_HINTS_DO_NOT_COVER)
+ {
+ window->has_struts = TRUE;
+ window->do_not_cover = TRUE;
+ recalc_do_not_cover_struts (window);
+
+ meta_verbose ("Using _WIN_HINTS struts %d %d %d %d for window %s\n",
+ window->left_strut, window->right_strut,
+ window->top_strut, window->bottom_strut,
+ window->desc);
+ }
+ else
+ {
+ meta_verbose ("DO_NOT_COVER hint not set in _WIN_HINTS\n");
+ }
+ }
+ else
+ {
+ meta_verbose ("No _WIN_HINTS property on %s\n",
+ window->desc);
+ }
+ }
+
+ invalidate_work_areas (window);
+}
+
+static void
+recalc_do_not_cover_struts (MetaWindow *window)
+{
+ if (window->do_not_cover)
+ {
+ /* We only understand windows that are aligned to
+ * a screen edge
+ */
+ gboolean horizontal;
+ gboolean on_left_edge;
+ gboolean on_right_edge;
+ gboolean on_bottom_edge;
+ gboolean on_top_edge;
+
+ window->left_strut = 0;
+ window->right_strut = 0;
+ window->top_strut = 0;
+ window->bottom_strut = 0;
+
+ on_left_edge = window->rect.x == 0;
+ on_right_edge = (window->rect.x + window->rect.width) ==
+ window->screen->width;
+ on_top_edge = window->rect.y == 0;
+ on_bottom_edge = (window->rect.y + window->rect.height) ==
+ window->screen->height;
+
+ /* cheesy heuristic to decide where the strut goes */
+ if (on_left_edge && on_right_edge && on_bottom_edge)
+ horizontal = TRUE;
+ else if (on_left_edge && on_right_edge && on_top_edge)
+ horizontal = TRUE;
+ else if (on_top_edge && on_bottom_edge && on_left_edge)
+ horizontal = FALSE;
+ else if (on_top_edge && on_bottom_edge && on_right_edge)
+ horizontal = FALSE;
+ else
+ horizontal = window->rect.width > window->rect.height;
+
+ if (horizontal)
+ {
+ if (on_top_edge)
+ window->top_strut = window->rect.height;
+ else if (on_bottom_edge)
+ window->bottom_strut = window->rect.height;
+ }
+ else
+ {
+ if (on_left_edge)
+ window->left_strut = window->rect.width;
+ else if (on_right_edge)
+ window->right_strut = window->rect.width;
+ }
+ }
+}
+
static void
recalc_window_type (MetaWindow *window)
{
@@ -4499,10 +4746,13 @@ constrain_size (MetaWindow *window,
int delta;
double min_aspect, max_aspect;
int minw, minh, maxw, maxh, fullw, fullh;
-
+ MetaRectangle work_area;
+
/* frame member variables should NEVER be used in here */
#define FLOOR(value, base) ( ((int) ((value) / (base))) * (base) )
+
+ meta_window_get_work_area (window, &work_area);
/* Get the allowed size ranges, considering maximized, etc. */
if (window->type == META_WINDOW_DESKTOP ||
@@ -4513,8 +4763,8 @@ constrain_size (MetaWindow *window,
}
else
{
- fullw = window->screen->active_workspace->workarea.width;
- fullh = window->screen->active_workspace->workarea.height;
+ fullw = work_area.width;
+ fullh = work_area.height;
}
if (window->frame)
@@ -4620,6 +4870,10 @@ constrain_position (MetaWindow *window,
int *new_x,
int *new_y)
{
+ MetaRectangle work_area;
+
+ meta_window_get_work_area (window, &work_area);
+
/* frame member variables should NEVER be used in here, only
* MetaFrameGeometry
*/
@@ -4644,8 +4898,8 @@ constrain_position (MetaWindow *window,
/* find furthest northwest point the window can occupy,
* to disallow moving titlebar off the top or left
*/
- nw_x = window->screen->active_workspace->workarea.x;
- nw_y = window->screen->active_workspace->workarea.y;
+ nw_x = work_area.x;
+ nw_y = work_area.y;
if (window->frame)
{
nw_x += fgeom->left_width;
@@ -4653,10 +4907,8 @@ constrain_position (MetaWindow *window,
}
/* find bottom-right corner of workarea */
- se_x = window->screen->active_workspace->workarea.x +
- window->screen->active_workspace->workarea.width;
- se_y = window->screen->active_workspace->workarea.y +
- window->screen->active_workspace->workarea.height;
+ se_x = work_area.x + work_area.width;
+ se_y = work_area.y + work_area.height;
/* if the window's size exceeds the screen size,
* we allow it to go off the top/left far enough
@@ -5181,3 +5433,40 @@ meta_window_set_gravity (MetaWindow *window,
meta_error_trap_pop (window->display);
}
+
+void
+meta_window_get_work_area (MetaWindow *window,
+ MetaRectangle *area)
+{
+ MetaRectangle space_area;
+ GList *tmp;
+
+ int left_strut = 0;
+ int right_strut = 0;
+ int top_strut = 0;
+ int bottom_strut = 0;
+
+ tmp = meta_window_get_workspaces (window);
+
+ while (tmp != NULL)
+ {
+ meta_workspace_get_work_area (tmp->data, &space_area);
+
+ left_strut = MAX (left_strut, space_area.x);
+ right_strut = MAX (right_strut,
+ (window->screen->width - space_area.x - space_area.width));
+ top_strut = MAX (top_strut, space_area.y);
+ bottom_strut = MAX (bottom_strut,
+ (window->screen->height - space_area.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;
+
+ meta_verbose ("Window %s has work area %d,%d %d x %d\n",
+ window->desc, area->x, area->y, area->width, area->height);
+}
diff --git a/src/window.h b/src/window.h
index 9744656..4fbea57 100644
--- a/src/window.h
+++ b/src/window.h
@@ -183,6 +183,11 @@ struct _MetaWindow
* only relevant if !window->placed
*/
guint calc_placement : 1;
+
+ /* Has nonzero struts */
+ guint has_struts : 1;
+ /* Struts are from the _WIN_HINTS do not cover deal */
+ guint do_not_cover : 1;
/* Number of UnmapNotify that are caused by us, if
* we get UnmapNotify with none pending then the client
@@ -220,6 +225,12 @@ struct _MetaWindow
/* x/y/w/h here get filled with ConfigureRequest values */
XSizeHints size_hints;
+ /* struts */
+ int left_strut;
+ int right_strut;
+ int top_strut;
+ int bottom_strut;
+
/* Managed by stack.c */
MetaStackLayer layer;
MetaStackOp *stack_op;
@@ -342,4 +353,8 @@ 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,
+ MetaRectangle *area);
+
#endif
diff --git a/src/workspace.c b/src/workspace.c
index 1b65915..77c02e5 100644
--- a/src/workspace.c
+++ b/src/workspace.c
@@ -40,14 +40,12 @@ meta_workspace_new (MetaScreen *screen)
g_list_append (workspace->screen->display->workspaces, workspace);
workspace->windows = NULL;
- /* This may have something to do with the strut hints
- * eventually
- */
- workspace->workarea.x = 0;
- workspace->workarea.y = 0;
- workspace->workarea.width = screen->width;
- workspace->workarea.height = screen->height;
-
+ 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;
+
/* Update hint for current number of workspaces */
set_number_of_spaces_hint (screen);
@@ -105,6 +103,13 @@ meta_workspace_add_window (MetaWorkspace *workspace,
meta_window_set_current_workspace_hint (window);
meta_window_queue_calc_showing (window);
+ if (window->has_struts)
+ meta_workspace_invalidate_work_area (workspace);
+
+ /* queue a move_resize since changing workspaces may change
+ * the relevant struts
+ */
+ meta_window_queue_move_resize (window);
}
void
@@ -119,6 +124,14 @@ meta_workspace_remove_window (MetaWorkspace *workspace,
meta_window_set_current_workspace_hint (window);
meta_window_queue_calc_showing (window);
+
+ if (window->has_struts)
+ meta_workspace_invalidate_work_area (workspace);
+
+ /* queue a move_resize since changing workspaces may change
+ * the relevant struts
+ */
+ meta_window_queue_move_resize (window);
}
void
@@ -242,6 +255,37 @@ meta_workspace_screen_index (MetaWorkspace *workspace)
meta_bug ("Workspace does not exist to index!\n");
}
+/* get windows contained on workspace, including workspace->windows
+ * and also sticky windows.
+ */
+GList*
+meta_workspace_list_windows (MetaWorkspace *workspace)
+{
+ GSList *display_windows;
+ GSList *tmp;
+ GList *workspace_windows;
+
+ display_windows = meta_display_list_windows (workspace->screen->display);
+
+ workspace_windows = NULL;
+ tmp = display_windows;
+ while (tmp != NULL)
+ {
+ MetaWindow *window = tmp->data;
+
+ if (window->on_all_workspaces ||
+ meta_workspace_contains_window (workspace, window))
+ workspace_windows = g_list_prepend (workspace_windows,
+ window);
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (display_windows);
+
+ return workspace_windows;
+}
+
static int
set_number_of_spaces_hint (MetaScreen *screen)
{
@@ -275,3 +319,90 @@ set_active_space_hint (MetaScreen *screen)
32, PropModeReplace, (guchar*) data, 1);
return meta_error_trap_pop (screen->display);
}
+
+void
+meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
+{
+ GList *tmp;
+
+ if (workspace->work_area_invalid)
+ return;
+
+ workspace->work_area_invalid = TRUE;
+
+ /* redo the size/position constraints on all windows */
+ tmp = workspace->windows;
+ while (tmp != NULL)
+ {
+ MetaWindow *w = tmp->data;
+
+ meta_window_queue_move_resize (w);
+
+ tmp = tmp->next;
+ }
+}
+
+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;
+
+ windows = meta_workspace_list_windows (workspace);
+ tmp = windows;
+ while (tmp != NULL)
+ {
+ MetaWindow *w = tmp->data;
+
+ if (w->has_struts)
+ {
+ left_strut = MAX (left_strut, w->left_strut);
+ right_strut = MAX (right_strut, w->right_strut);
+ top_strut = MAX (top_strut, w->top_strut);
+ bottom_strut = MAX (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))
+ {
+ left_strut = (workspace->screen->width - MIN_SANE_AREA) / 2;
+ right_strut = left_strut;
+ }
+
+ if ((top_strut + bottom_strut) > (workspace->screen->height - MIN_SANE_AREA))
+ {
+ top_strut = (workspace->screen->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;
+
+ meta_verbose ("Workspace %d has work area %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);
+ }
+
+ *area = workspace->work_area;
+}
diff --git a/src/workspace.h b/src/workspace.h
index 97f12ec..46439d2 100644
--- a/src/workspace.h
+++ b/src/workspace.h
@@ -30,7 +30,8 @@ struct _MetaWorkspace
GList *windows;
- MetaRectangle workarea;
+ MetaRectangle work_area;
+ guint work_area_invalid : 1;
};
MetaWorkspace* meta_workspace_new (MetaScreen *screen);
@@ -47,6 +48,12 @@ gboolean meta_workspace_contains_window (MetaWorkspace *workspace,
void meta_workspace_activate (MetaWorkspace *workspace);
int meta_workspace_index (MetaWorkspace *workspace);
int meta_workspace_screen_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);
+
#endif