Patch from Carlo Wood to fix handling of unidirectional maximization and

2007-04-02  Elijah Newren  <newren gmail com>

	Patch from Carlo Wood to fix handling of unidirectional
	maximization and partial struts.  #358311.

	* src/constraints.c (constrain_maximization):
	determine target size for unidirectionally maximized windows by
	determining how far they can be maximized without hitting
	orthogonal struts.  Avoids weird "empty spaces".

	* src/boxes.[ch] (meta_rectangle_expand_to_avoiding_struts):
	new function

2007-04-02  Elijah Newren  <newren gmail com>

	Make the strut lists (stored in workspaces) record both the
	rectangle and the side that the strut is on.  Lots of code
	cleanups relating to struts.

	* src/boxes.h (struct MetaStrut):
	new struct for struts

	* src/window.[ch] (struct MetaStruts, struct MetaWindow,
	  meta_window_update_struts):
	overhaul to make window's struts remember their side as well as
	their rectangular location, and just use a list instead of several
	copies of near-identical code for left/right/top/bottom (allowing
	us to nuke MetaStruts struct as well)
	
	* src/testboxes.c (new_meta_strut, get_strut_list):
	* src/workspace.c (ensure_work_areas_validated):
	* src/boxes.c (meta_rectangle_get_minimal_spanning_set_for_region,
	  meta_rectangle_expand_to_avoiding_struts,
	  get_disjoint_strut_rect_list_in_region, fix_up_edges,
	  meta_rectangle_find_onscreen_edges,
	  meta_rectangle_find_nonintersected_xinerama_edges):
	modify to handle struts being rectangle + side instead of just rectangle

	* src/workspace.c (ensure_work_areas_validated):
	simplify strut list creation considerably given MetaWindow change,
	modify work_area computations to take advantage of region
	computations being done (makes the code shorter as well as more
	robust against pathological cases).

	* src/util.[ch] (meta_free_gslist_and_elements):
	new convenience function

	* src/common.h (enum MetaDirection):
	* src/edge-resistance.c (movement_towards_edge):
	* src/boxes.c (meta_rectangle_edge_aligns,
	  rectangle_and_edge_intersection, split_edge):
	Add more MetaDirection fields for convenience

	* src/boxes.h (enum FixedDirections):
	* src/constraints.c (setup_constraint_info, place_window_if_needed):
	add a FIXED_DIRECTION_NONE to the FixedDirections enum to make
	code more clear

svn path=/trunk/; revision=3144
This commit is contained in:
Elijah Newren 2007-04-03 03:41:10 +00:00 committed by Elijah Newren
parent e82ce26425
commit 08f51fdf94
12 changed files with 544 additions and 418 deletions

View File

@ -1,3 +1,61 @@
2007-04-02 Elijah Newren <newren gmail com>
Patch from Carlo Wood to fix handling of unidirectional
maximization and partial struts. #358311.
* src/constraints.c (constrain_maximization):
determine target size for unidirectionally maximized windows by
determining how far they can be maximized without hitting
orthogonal struts. Avoids weird "empty spaces".
* src/boxes.[ch] (meta_rectangle_expand_to_avoiding_struts):
new function
2007-04-02 Elijah Newren <newren gmail com>
Make the strut lists (stored in workspaces) record both the
rectangle and the side that the strut is on. Lots of code
cleanups relating to struts.
* src/boxes.h (struct MetaStrut):
new struct for struts
* src/window.[ch] (struct MetaStruts, struct MetaWindow,
meta_window_update_struts):
overhaul to make window's struts remember their side as well as
their rectangular location, and just use a list instead of several
copies of near-identical code for left/right/top/bottom (allowing
us to nuke MetaStruts struct as well)
* src/testboxes.c (new_meta_strut, get_strut_list):
* src/workspace.c (ensure_work_areas_validated):
* src/boxes.c (meta_rectangle_get_minimal_spanning_set_for_region,
meta_rectangle_expand_to_avoiding_struts,
get_disjoint_strut_rect_list_in_region, fix_up_edges,
meta_rectangle_find_onscreen_edges,
meta_rectangle_find_nonintersected_xinerama_edges):
modify to handle struts being rectangle + side instead of just rectangle
* src/workspace.c (ensure_work_areas_validated):
simplify strut list creation considerably given MetaWindow change,
modify work_area computations to take advantage of region
computations being done (makes the code shorter as well as more
robust against pathological cases).
* src/util.[ch] (meta_free_gslist_and_elements):
new convenience function
* src/common.h (enum MetaDirection):
* src/edge-resistance.c (movement_towards_edge):
* src/boxes.c (meta_rectangle_edge_aligns,
rectangle_and_edge_intersection, split_edge):
Add more MetaDirection fields for convenience
* src/boxes.h (enum FixedDirections):
* src/constraints.c (setup_constraint_info, place_window_if_needed):
add a FIXED_DIRECTION_NONE to the FixedDirections enum to make
code more clear
2007-04-01 Bruno Boaventura <brunobol@gnome.org>
* src/theme.c (kill_window_question): Fallback to NORMAL state after

View File

@ -547,10 +547,10 @@ meta_rectangle_get_minimal_spanning_set_for_region (
ret = g_list_prepend (NULL, temp_rect);
strut_iter = all_struts;
while (strut_iter)
for (strut_iter = all_struts; strut_iter; strut_iter = strut_iter->next)
{
GList *rect_iter;
MetaRectangle *strut = (MetaRectangle*) strut_iter->data;
MetaRectangle *strut_rect = &((MetaStrut*)strut_iter->data)->rect;
tmp_list = ret;
ret = NULL;
@ -558,45 +558,45 @@ meta_rectangle_get_minimal_spanning_set_for_region (
while (rect_iter)
{
MetaRectangle *rect = (MetaRectangle*) rect_iter->data;
if (!meta_rectangle_overlap (rect, strut))
if (!meta_rectangle_overlap (rect, strut_rect))
ret = g_list_prepend (ret, rect);
else
{
/* If there is area in rect left of strut */
if (rect->x < strut->x)
if (BOX_LEFT (*rect) < BOX_LEFT (*strut_rect))
{
temp_rect = g_new (MetaRectangle, 1);
*temp_rect = *rect;
temp_rect->width = strut->x - rect->x;
temp_rect->width = BOX_LEFT (*strut_rect) - BOX_LEFT (*rect);
ret = g_list_prepend (ret, temp_rect);
}
/* If there is area in rect right of strut */
if (rect->x + rect->width > strut->x + strut->width)
if (BOX_RIGHT (*rect) > BOX_RIGHT (*strut_rect))
{
int new_x;
temp_rect = g_new (MetaRectangle, 1);
*temp_rect = *rect;
new_x = strut->x + strut->width;
temp_rect->width = rect->x + rect->width - new_x;
new_x = BOX_RIGHT (*strut_rect);
temp_rect->width = BOX_RIGHT(*rect) - new_x;
temp_rect->x = new_x;
ret = g_list_prepend (ret, temp_rect);
}
/* If there is area in rect above strut */
if (rect->y < strut->y)
if (BOX_TOP (*rect) < BOX_TOP (*strut_rect))
{
temp_rect = g_new (MetaRectangle, 1);
*temp_rect = *rect;
temp_rect->height = strut->y - rect->y;
temp_rect->height = BOX_TOP (*strut_rect) - BOX_TOP (*rect);
ret = g_list_prepend (ret, temp_rect);
}
/* If there is area in rect below strut */
if (rect->y + rect->height > strut->y + strut->height)
if (BOX_BOTTOM (*rect) > BOX_BOTTOM (*strut_rect))
{
int new_y;
temp_rect = g_new (MetaRectangle, 1);
*temp_rect = *rect;
new_y = strut->y + strut->height;
temp_rect->height = rect->y + rect->height - new_y;
new_y = BOX_BOTTOM (*strut_rect);
temp_rect->height = BOX_BOTTOM (*rect) - new_y;
temp_rect->y = new_y;
ret = g_list_prepend (ret, temp_rect);
}
@ -605,7 +605,6 @@ meta_rectangle_get_minimal_spanning_set_for_region (
rect_iter = rect_iter->next;
}
g_list_free (tmp_list);
strut_iter = strut_iter->next;
}
/* Sort by maximal area, just because I feel like it... */
@ -662,6 +661,76 @@ meta_rectangle_expand_region_conditionally (GList *region,
return region;
}
void
meta_rectangle_expand_to_avoiding_struts (MetaRectangle *rect,
const MetaRectangle *expand_to,
const MetaDirection direction,
const GSList *all_struts)
{
const GSList *strut_iter;
/* If someone wants this function to handle more fine-grained
* direction expanding in the future (e.g. only left, or fully
* horizontal plus upward), feel free. But I'm hard-coding for both
* horizontal directions (exclusive-)or both vertical directions.
*/
g_assert ((direction == META_DIRECTION_HORIZONTAL) ^
(direction == META_DIRECTION_VERTICAL ));
if (direction == META_DIRECTION_HORIZONTAL)
{
rect->x = expand_to->x;
rect->width = expand_to->width;
}
else
{
rect->y = expand_to->y;
rect->height = expand_to->height;
}
/* Run over all struts */
for (strut_iter = all_struts; strut_iter; strut_iter = strut_iter->next)
{
MetaStrut *strut = (MetaStrut*) strut_iter->data;
/* Skip struts that don't overlap */
if (!meta_rectangle_overlap (&strut->rect, rect))
continue;
if (direction == META_DIRECTION_HORIZONTAL)
{
if (strut->side == META_SIDE_LEFT)
{
int offset = BOX_RIGHT(strut->rect) - BOX_LEFT(*rect);
rect->x += offset;
rect->width -= offset;
}
else if (strut->side == META_SIDE_RIGHT)
{
int offset = BOX_RIGHT (*rect) - BOX_LEFT(strut->rect);
rect->width -= offset;
}
/* else ignore the strut */
}
else /* direction == META_DIRECTION_VERTICAL */
{
if (strut->side == META_SIDE_TOP)
{
int offset = BOX_BOTTOM(strut->rect) - BOX_TOP(*rect);
rect->y += offset;
rect->height -= offset;
}
else if (strut->side == META_SIDE_BOTTOM)
{
int offset = BOX_BOTTOM(*rect) - BOX_TOP(strut->rect);
rect->height -= offset;
}
/* else ignore the strut */
}
} /* end loop over struts */
} /* end meta_rectangle_expand_to_avoiding_struts */
void
meta_rectangle_free_list_and_elements (GList *filled_list)
{
@ -1075,9 +1144,9 @@ meta_rectangle_edge_aligns (const MetaRectangle *rect, const MetaEdge *edge)
case META_DIRECTION_BOTTOM:
return BOX_LEFT (*rect) <= BOX_RIGHT (edge->rect) &&
BOX_LEFT (edge->rect) <= BOX_RIGHT (*rect);
}
default:
g_assert_not_reached ();
}
}
static GList*
@ -1161,27 +1230,27 @@ replace_rect_with_list (GList *old_element,
}
/* Make a copy of the strut list, make sure that copy only contains parts
* of the old_struts that intersect with the rection rect, and then do some
* of the old_struts that intersect with the region rect, and then do some
* magic to make all the new struts disjoint (okay, we we break up struts
* that aren't disjoint in a way that the overlapping part is only included
* once, so it's not really magic...).
*/
static GList*
get_disjoint_strut_list_in_region (const GSList *old_struts,
get_disjoint_strut_rect_list_in_region (const GSList *old_struts,
const MetaRectangle *region)
{
GList *struts;
GList *strut_rects;
GList *tmp;
/* First, copy the list */
struts = NULL;
strut_rects = NULL;
while (old_struts)
{
MetaRectangle *cur = old_struts->data;
MetaRectangle *cur = &((MetaStrut*)old_struts->data)->rect;
MetaRectangle *copy = g_new (MetaRectangle, 1);
*copy = *cur;
if (meta_rectangle_intersect (copy, region, copy))
struts = g_list_prepend (struts, copy);
strut_rects = g_list_prepend (strut_rects, copy);
else
g_free (copy);
@ -1191,7 +1260,7 @@ get_disjoint_strut_list_in_region (const GSList *old_struts,
/* Now, loop over the list and check for intersections, fixing things up
* where they do intersect.
*/
tmp = struts;
tmp = strut_rects;
while (tmp)
{
GList *compare;
@ -1218,10 +1287,10 @@ get_disjoint_strut_list_in_region (const GSList *old_struts,
cur_leftover = g_list_prepend (cur_leftover, overlap_allocated);
/* Fix up tmp, compare, and cur -- maybe struts too */
if (struts == tmp)
if (strut_rects == tmp)
{
struts = replace_rect_with_list (tmp, cur_leftover);
tmp = struts;
strut_rects = replace_rect_with_list (tmp, cur_leftover);
tmp = strut_rects;
}
else
tmp = replace_rect_with_list (tmp, cur_leftover);
@ -1239,7 +1308,7 @@ get_disjoint_strut_list_in_region (const GSList *old_struts,
tmp = tmp->next;
}
return struts;
return strut_rects;
}
gint
@ -1397,6 +1466,8 @@ rectangle_and_edge_intersection (const MetaRectangle *rect,
else
*handle_type = 0;
break;
default:
g_assert_not_reached ();
}
}
return intersect;
@ -1503,23 +1574,25 @@ split_edge (GList *cur_list,
cur_list = g_list_prepend (cur_list, temp_edge);
}
break;
default:
g_assert_not_reached ();
}
return cur_list;
}
/* Split up edge and remove preliminary edges from strut_edges depending on
* if and how strut and edge intersect.
* if and how rect and edge intersect.
*/
static void
fix_up_edges (MetaRectangle *strut, MetaEdge *edge,
fix_up_edges (MetaRectangle *rect, MetaEdge *edge,
GList **strut_edges, GList **edge_splits,
gboolean *edge_needs_removal)
{
MetaEdge overlap;
int handle_type;
if (!rectangle_and_edge_intersection (strut, edge, &overlap, &handle_type))
if (!rectangle_and_edge_intersection (rect, edge, &overlap, &handle_type))
return;
if (handle_type == 0 || handle_type == 1)
@ -1628,9 +1701,9 @@ meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
const GSList *all_struts)
{
GList *ret;
GList *fixed_struts;
GList *fixed_strut_rects;
GList *edge_iter;
const GList *strut_iter;
const GList *strut_rect_iter;
/* The algorithm is basically as follows:
* Make sure the struts are disjoint
@ -1648,18 +1721,19 @@ meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
*/
/* Make sure the struts are disjoint */
fixed_struts = get_disjoint_strut_list_in_region (all_struts, basic_rect);
fixed_strut_rects =
get_disjoint_strut_rect_list_in_region (all_struts, basic_rect);
/* Start off the list with the edges of basic_rect */
ret = add_edges (NULL, basic_rect, TRUE);
strut_iter = fixed_struts;
while (strut_iter)
strut_rect_iter = fixed_strut_rects;
while (strut_rect_iter)
{
MetaRectangle *strut = (MetaRectangle*) strut_iter->data;
MetaRectangle *strut_rect = (MetaRectangle*) strut_rect_iter->data;
/* Get the new possible edges we may need to add from the strut */
GList *new_strut_edges = add_edges (NULL, strut, FALSE);
GList *new_strut_edges = add_edges (NULL, strut_rect, FALSE);
edge_iter = ret;
while (edge_iter)
@ -1668,7 +1742,7 @@ meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
GList *splits_of_cur_edge = NULL;
gboolean edge_needs_removal = FALSE;
fix_up_edges (strut, cur_edge,
fix_up_edges (strut_rect, cur_edge,
&new_strut_edges, &splits_of_cur_edge,
&edge_needs_removal);
@ -1692,14 +1766,14 @@ meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect,
}
ret = g_list_concat (new_strut_edges, ret);
strut_iter = strut_iter->next;
strut_rect_iter = strut_rect_iter->next;
}
/* Sort the list */
ret = g_list_sort (ret, meta_rectangle_edge_cmp);
/* Free the fixed struts list */
meta_rectangle_free_list_and_elements (fixed_struts);
meta_rectangle_free_list_and_elements (fixed_strut_rects);
return ret;
}
@ -1716,6 +1790,7 @@ meta_rectangle_find_nonintersected_xinerama_edges (
*/
GList *ret;
const GList *cur;
GSList *temp_rects;
/* Initialize the return list to be empty */
ret = NULL;
@ -1823,8 +1898,13 @@ meta_rectangle_find_nonintersected_xinerama_edges (
cur = cur->next;
}
temp_rects = NULL;
for (; all_struts; all_struts = all_struts->next)
temp_rects = g_slist_prepend (temp_rects,
&((MetaStrut*)all_struts->data)->rect);
ret = meta_rectangle_remove_intersections_with_boxes_from_edges (ret,
all_struts);
temp_rects);
g_slist_free (temp_rects);
/* Sort the list */
ret = g_list_sort (ret, meta_rectangle_edge_cmp);

View File

@ -28,7 +28,6 @@
#include "common.h"
typedef struct _MetaRectangle MetaRectangle;
struct _MetaRectangle
{
int x;
@ -37,6 +36,13 @@ struct _MetaRectangle
int height;
};
typedef struct _MetaStrut MetaStrut;
struct _MetaStrut
{
MetaRectangle rect;
MetaDirection side;
};
#define BOX_LEFT(box) ((box).x) /* Leftmost pixel of rect */
#define BOX_RIGHT(box) ((box).x + (box).width) /* One pixel past right */
#define BOX_TOP(box) ((box).y) /* Topmost pixel of rect */
@ -44,6 +50,7 @@ struct _MetaRectangle
typedef enum
{
FIXED_DIRECTION_NONE = 0,
FIXED_DIRECTION_X = 1 << 0,
FIXED_DIRECTION_Y = 1 << 1,
} FixedDirections;
@ -166,6 +173,16 @@ GList* meta_rectangle_expand_region_conditionally (
const int min_x,
const int min_y);
/* Expand rect in direction to the size of expand_to, and then clip out any
* overlapping struts oriented orthognal to the expansion direction. (Think
* horizontal or vertical maximization)
*/
void meta_rectangle_expand_to_avoiding_struts (
MetaRectangle *rect,
const MetaRectangle *expand_to,
const MetaDirection direction,
const GSList *all_struts);
/* Free the list created by
* meta_rectangle_get_minimal_spanning_set_for_region()
* or

View File

@ -220,8 +220,20 @@ typedef enum
META_DIRECTION_RIGHT = 1 << 1,
META_DIRECTION_TOP = 1 << 2,
META_DIRECTION_BOTTOM = 1 << 3,
META_DIRECTION_UP = 1 << 2, /* Alternate name for TOP */
META_DIRECTION_DOWN = 1 << 3 /* Alternate name for BOTTOM */
/* Some aliases for making code more readable for various circumstances. */
META_DIRECTION_UP = META_DIRECTION_TOP,
META_DIRECTION_DOWN = META_DIRECTION_BOTTOM,
/* A few more definitions using aliases */
META_DIRECTION_HORIZONTAL = META_DIRECTION_LEFT | META_DIRECTION_RIGHT,
META_DIRECTION_VERTICAL = META_DIRECTION_UP | META_DIRECTION_DOWN,
/* And a few more aliases */
META_SIDE_LEFT = META_DIRECTION_LEFT,
META_SIDE_RIGHT = META_DIRECTION_RIGHT,
META_SIDE_TOP = META_DIRECTION_TOP,
META_SIDE_BOTTOM = META_DIRECTION_BOTTOM
} MetaDirection;
/* Function a window button can have. Note, you can't add stuff here

View File

@ -365,7 +365,7 @@ setup_constraint_info (ConstraintInfo *info,
* and (b) ignored it for aspect ratio windows -- at least in those
* cases where both directions do actually change size.
*/
info->fixed_directions = 0;
info->fixed_directions = FIXED_DIRECTION_NONE;
/* If x directions don't change but either y direction does */
if ( orig->x == new->x && orig->x + orig->width == new->x + new->width &&
(orig->y != new->y || orig->y + orig->height != new->y + new->height))
@ -385,7 +385,7 @@ setup_constraint_info (ConstraintInfo *info,
* aren't explicit user interaction, though, so just clear it out.
*/
if (!info->is_user_action)
info->fixed_directions = 0;
info->fixed_directions = FIXED_DIRECTION_NONE;
xinerama_info =
meta_screen_get_xinerama_for_rect (window->screen, &info->current);
@ -441,7 +441,7 @@ setup_constraint_info (ConstraintInfo *info,
"Freakin' Invalid Stupid",
(info->is_user_action) ? "true" : "false",
meta_gravity_to_string (info->resize_gravity),
(info->fixed_directions == 0) ? "None" :
(info->fixed_directions == FIXED_DIRECTION_NONE) ? "None" :
(info->fixed_directions == FIXED_DIRECTION_X) ? "X fixed" :
(info->fixed_directions == FIXED_DIRECTION_Y) ? "Y fixed" :
"Freakin' Invalid Stupid",
@ -500,7 +500,7 @@ place_window_if_needed(MetaWindow *window,
/* Since we just barely placed the window, there's no reason to
* consider any of the directions fixed.
*/
info->fixed_directions = 0;
info->fixed_directions = FIXED_DIRECTION_NONE;
}
if (window->placed || did_placement)
@ -691,7 +691,8 @@ constrain_maximization (MetaWindow *window,
ConstraintPriority priority,
gboolean check_only)
{
MetaRectangle min_size, max_size, work_area;
MetaRectangle target_size;
MetaRectangle min_size, max_size;
gboolean hminbad, vminbad;
gboolean horiz_equal, vert_equal;
gboolean constraint_already_satisfied;
@ -703,20 +704,51 @@ constrain_maximization (MetaWindow *window,
if (!window->maximized_horizontally && !window->maximized_vertically)
return TRUE;
work_area = info->work_area_xinerama;
unextend_by_frame (&work_area, info->fgeom);
get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size);
/* Calculate target_size = maximized size of (window + frame) */
if (window->maximized_horizontally && window->maximized_vertically)
target_size = info->work_area_xinerama;
else
{
/* Amount of maximization possible in a single direction depends
* on which struts could occlude the window given its current
* position. For example, a vertical partial strut on the right
* is only relevant for a horizontally maximized window when the
* window is at a vertical position where it could be occluded
* by that partial strut.
*/
MetaDirection direction;
GSList *active_workspace_struts;
hminbad = work_area.width < min_size.width && window->maximized_horizontally;
vminbad = work_area.height < min_size.height && window->maximized_vertically;
if (window->maximized_horizontally)
direction = META_DIRECTION_HORIZONTAL;
else
direction = META_DIRECTION_VERTICAL;
active_workspace_struts = window->screen->active_workspace->all_struts;
target_size = info->current;
extend_by_frame (&target_size, info->fgeom);
meta_rectangle_expand_to_avoiding_struts (&target_size,
&info->entire_xinerama,
direction,
active_workspace_struts);
}
/* Now make target_size = maximized size of client window */
unextend_by_frame (&target_size, info->fgeom);
/* Check min size constraints; max size constraints are ignored for maximized
* windows, as per bug 327543.
*/
get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size);
hminbad = target_size.width < min_size.width && window->maximized_horizontally;
vminbad = target_size.height < min_size.height && window->maximized_vertically;
if (hminbad || vminbad)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
horiz_equal = work_area.x == info->current.x &&
work_area.width == info->current.width;
vert_equal = work_area.y == info->current.y &&
work_area.height == info->current.height;
horiz_equal = target_size.x == info->current.x &&
target_size.width == info->current.width;
vert_equal = target_size.y == info->current.y &&
target_size.height == info->current.height;
constraint_already_satisfied =
(horiz_equal || !window->maximized_horizontally) &&
(vert_equal || !window->maximized_vertically);
@ -726,13 +758,13 @@ constrain_maximization (MetaWindow *window,
/*** Enforce constraint ***/
if (window->maximized_horizontally)
{
info->current.x = work_area.x;
info->current.width = work_area.width;
info->current.x = target_size.x;
info->current.width = target_size.width;
}
if (window->maximized_vertically)
{
info->current.y = work_area.y;
info->current.height = work_area.height;
info->current.y = target_size.y;
info->current.height = target_size.height;
}
return TRUE;
}

View File

@ -300,9 +300,9 @@ movement_towards_edge (MetaDirection side, int increment)
case META_DIRECTION_RIGHT:
case META_DIRECTION_BOTTOM:
return increment > 0;
}
default:
g_assert_not_reached ();
}
}
static gboolean

View File

@ -58,6 +58,17 @@ new_meta_rect (int x, int y, int width, int height)
return temporary;
}
static MetaStrut*
new_meta_strut (int x, int y, int width, int height, int side)
{
MetaStrut* temporary;
temporary = g_new (MetaStrut, 1);
temporary->rect = meta_rect(x, y, width, height);
temporary->side = side;
return temporary;
}
static MetaEdge*
new_screen_edge (int x, int y, int width, int height, int side_type)
{
@ -228,9 +239,10 @@ free_strut_list (GSList *struts)
static GSList*
get_strut_list (int which)
{
GSList *struts;
GSList *ans;
MetaDirection wc = 0; /* wc == who cares? ;-) */
struts = NULL;
ans = NULL;
g_assert (which >=0 && which <= 6);
switch (which)
@ -238,36 +250,36 @@ get_strut_list (int which)
case 0:
break;
case 1:
struts = g_slist_prepend (struts, new_meta_rect ( 0, 0, 1600, 20));
struts = g_slist_prepend (struts, new_meta_rect ( 400, 1160, 1600, 40));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 400, 1160, 1600, 40, wc));
break;
case 2:
struts = g_slist_prepend (struts, new_meta_rect ( 0, 0, 1600, 20));
struts = g_slist_prepend (struts, new_meta_rect ( 800, 1100, 400, 100));
struts = g_slist_prepend (struts, new_meta_rect ( 300, 1150, 150, 50));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100, 400, 100, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150, 150, 50, wc));
break;
case 3:
struts = g_slist_prepend (struts, new_meta_rect ( 0, 0, 1600, 20));
struts = g_slist_prepend (struts, new_meta_rect ( 800, 1100, 400, 100));
struts = g_slist_prepend (struts, new_meta_rect ( 300, 1150, 80, 50));
struts = g_slist_prepend (struts, new_meta_rect ( 700, 525, 200, 150));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100, 400, 100, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150, 80, 50, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 700, 525, 200, 150, wc));
break;
case 4:
struts = g_slist_prepend (struts, new_meta_rect ( 0, 0, 800, 1200));
struts = g_slist_prepend (struts, new_meta_rect ( 800, 0, 1600, 20));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 800, 1200, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 0, 1600, 20, wc));
break;
case 5:
struts = g_slist_prepend (struts, new_meta_rect ( 800, 0, 1600, 20));
struts = g_slist_prepend (struts, new_meta_rect ( 0, 0, 800, 1200));
struts = g_slist_prepend (struts, new_meta_rect ( 800, 10, 800, 1200));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 0, 1600, 20, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 800, 1200, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 10, 800, 1200, wc));
break;
case 6:
struts = g_slist_prepend (struts, new_meta_rect ( 0, 0, 1600, 40));
struts = g_slist_prepend (struts, new_meta_rect ( 0, 0, 1600, 20));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 40, wc));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, wc));
break;
}
return struts;
return ans;
}
static GList*

View File

@ -199,6 +199,15 @@ utf8_fputs (const char *str,
return retval;
}
void
meta_free_gslist_and_elements (GSList *list_to_deep_free)
{
g_slist_foreach (list_to_deep_free,
(void (*)(gpointer,gpointer))&g_free, /* ew, for ugly */
NULL);
g_slist_free (list_to_deep_free);
}
#ifdef WITH_VERBOSE_MODE
void
meta_debug_spew_real (const char *format, ...)

View File

@ -95,6 +95,8 @@ const char* meta_gravity_to_string (int gravity);
char* meta_g_utf8_strndup (const gchar *src, gsize n);
void meta_free_gslist_and_elements (GSList *list_to_deep_free);
/* To disable verbose mode, we make these functions into no-ops */
#ifdef WITH_VERBOSE_MODE

View File

@ -5675,50 +5675,17 @@ invalidate_work_areas (MetaWindow *window)
void
meta_window_update_struts (MetaWindow *window)
{
GSList *old_struts;
GSList *new_struts;
GSList *old_iter, *new_iter;
gulong *struts = NULL;
int nitems;
gboolean old_has_struts;
gboolean new_has_struts;
MetaRectangle old_left;
MetaRectangle old_right;
MetaRectangle old_top;
MetaRectangle old_bottom;
MetaRectangle new_left;
MetaRectangle new_right;
MetaRectangle new_top;
MetaRectangle new_bottom;
gboolean changed;
meta_verbose ("Updating struts for %s\n", window->desc);
if (window->struts)
{
old_has_struts = TRUE;
old_left = window->struts->left;
old_right = window->struts->right;
old_top = window->struts->top;
old_bottom = window->struts->bottom;
}
else
{
old_has_struts = FALSE;
}
new_has_struts = FALSE;
new_left = window->screen->rect;
new_left.width = 0;
new_right = window->screen->rect;
new_right.width = 0;
new_right.x = window->screen->rect.width;
new_top = window->screen->rect;
new_top.height = 0;
new_bottom = window->screen->rect;
new_bottom.height = 0;
new_bottom.y = window->screen->rect.height;
old_struts = window->struts;
new_struts = NULL;
if (meta_prop_get_cardinal_list (window->display,
window->xwindow,
@ -5726,35 +5693,56 @@ meta_window_update_struts (MetaWindow *window)
&struts, &nitems))
{
if (nitems != 12)
{
meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead of 12\n",
meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead "
"of 12\n",
window->desc, nitems);
}
else
{
new_has_struts = TRUE;
new_left.width = (int) struts[0];
new_right.width = (int) struts[1];
new_top.height = (int)struts[2];
new_bottom.height = (int)struts[3];
new_right.x = window->screen->rect.width - new_right.width;
new_bottom.y = window->screen->rect.height - new_bottom.height;
new_left.y = struts[4];
new_left.height = struts[5] - new_left.y + 1;
new_right.y = struts[6];
new_right.height = struts[7] - new_right.y + 1;
new_top.x = struts[8];
new_top.width = struts[9] - new_top.x + 1;
new_bottom.x = struts[10];
new_bottom.width = struts[11] - new_bottom.x + 1;
/* Pull out the strut info for each side in the hint */
int i;
for (i=0; i<4; i++)
{
MetaStrut *temp;
int thickness, strut_begin, strut_end;
meta_verbose ("_NET_WM_STRUT_PARTIAL struts %d %d %d %d for window %s\n",
new_left.width,
new_right.width,
new_top.height,
new_bottom.height,
thickness = struts[i];
if (thickness == 0)
continue;
strut_begin = struts[4+(i*2)];
strut_end = struts[4+(i*2)+1];
temp = g_new (MetaStrut, 1);
temp->side = 1 << i; // See MetaDirection def. Matches nicely, eh?
temp->rect = window->screen->rect;
switch (temp->side)
{
case META_SIDE_RIGHT:
temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
/* Intentionally fall through without breaking */
case META_SIDE_LEFT:
temp->rect.width = thickness;
temp->rect.y = strut_begin;
temp->rect.height = strut_end - strut_begin + 1;
break;
case META_SIDE_BOTTOM:
temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
/* Intentionally fall through without breaking */
case META_SIDE_TOP:
temp->rect.height = thickness;
temp->rect.x = strut_begin;
temp->rect.width = strut_end - strut_begin + 1;
break;
default:
g_assert_not_reached ();
}
new_struts = g_slist_prepend (new_struts, temp);
}
meta_verbose ("_NET_WM_STRUT_PARTIAL struts %lu %lu %lu %lu for "
"window %s\n",
struts[0], struts[1], struts[2], struts[3],
window->desc);
}
meta_XFree (struts);
}
@ -5764,67 +5752,86 @@ meta_window_update_struts (MetaWindow *window)
window->desc);
}
if (!new_has_struts)
{
if (meta_prop_get_cardinal_list (window->display,
if (!new_struts &&
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);
}
else
{
new_has_struts = TRUE;
new_left.width = (int) struts[0];
new_right.width = (int) struts[1];
new_top.height = (int)struts[2];
new_bottom.height = (int)struts[3];
new_right.x = window->screen->rect.width - new_right.width;
new_bottom.y = window->screen->rect.height - new_bottom.height;
/* Pull out the strut info for each side in the hint */
int i;
for (i=0; i<4; i++)
{
MetaStrut *temp;
int thickness;
meta_verbose ("_NET_WM_STRUT struts %d %d %d %d for window %s\n",
new_left.width,
new_right.width,
new_top.height,
new_bottom.height,
thickness = struts[i];
if (thickness == 0)
continue;
temp = g_new (MetaStrut, 1);
temp->side = 1 << i;
temp->rect = window->screen->rect;
switch (temp->side)
{
case META_SIDE_RIGHT:
temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
/* Intentionally fall through without breaking */
case META_SIDE_LEFT:
temp->rect.width = thickness;
break;
case META_SIDE_BOTTOM:
temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
/* Intentionally fall through without breaking */
case META_SIDE_TOP:
temp->rect.height = thickness;
break;
default:
g_assert_not_reached ();
}
new_struts = g_slist_prepend (new_struts, temp);
}
meta_verbose ("_NET_WM_STRUT struts %lu %lu %lu %lu for window %s\n",
struts[0], struts[1], struts[2], struts[3],
window->desc);
}
meta_XFree (struts);
}
else
else if (!new_struts)
{
meta_verbose ("No _NET_WM_STRUT property for %s\n",
window->desc);
}
}
if (old_has_struts != new_has_struts ||
(new_has_struts && old_has_struts &&
(!meta_rectangle_equal(&old_left, &new_left) ||
!meta_rectangle_equal(&old_right, &new_right) ||
!meta_rectangle_equal(&old_top, &new_top) ||
!meta_rectangle_equal(&old_bottom, &new_bottom))))
/* Determine whether old_struts and new_struts are the same */
old_iter = old_struts;
new_iter = new_struts;
while (old_iter && new_iter)
{
if (new_has_struts)
{
if (!window->struts)
window->struts = g_new (MetaStruts, 1);
MetaStrut *old_strut = (MetaStrut*) old_iter->data;
MetaStrut *new_strut = (MetaStrut*) new_iter->data;
window->struts->left = new_left;
window->struts->right = new_right;
window->struts->top = new_top;
window->struts->bottom = new_bottom;
if (old_strut->side != new_strut->side ||
!meta_rectangle_equal (&old_strut->rect, &new_strut->rect))
break;
old_iter = old_iter->next;
new_iter = new_iter->next;
}
else
changed = (old_iter != NULL || new_iter != NULL);
/* Update appropriately */
meta_free_gslist_and_elements (old_struts);
window->struts = new_struts;
if (changed)
{
g_free (window->struts);
window->struts = NULL;
}
meta_topic (META_DEBUG_WORKAREA,
"Invalidating work areas of window %s due to struts update\n",
window->desc);

View File

@ -36,7 +36,6 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
typedef struct _MetaGroup MetaGroup;
typedef struct _MetaStruts MetaStruts;
typedef gboolean (*MetaWindowForeachFunc) (MetaWindow *window,
void *data);
@ -67,15 +66,6 @@ typedef enum {
META_CLIENT_TYPE_MAX_RECOGNIZED = 2
} MetaClientType;
struct _MetaStruts
{
/* struts */
MetaRectangle left;
MetaRectangle right;
MetaRectangle top;
MetaRectangle bottom;
};
struct _MetaWindow
{
MetaDisplay *display;
@ -276,7 +266,7 @@ struct _MetaWindow
guint calc_placement : 1;
/* Note: can be NULL */
MetaStruts *struts;
GSList *struts;
/* Transient parent is a root window */
guint transient_parent_is_root_window : 1;

View File

@ -493,17 +493,10 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
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;
GList *tmp;
MetaRectangle work_area;
int i; /* C89 absolutely sucks... */
if (!workspace->work_areas_invalid)
return;
@ -514,181 +507,20 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
g_assert (workspace->screen_edges == NULL);
g_assert (workspace->xinerama_edges == NULL);
/* STEP 1: Get the list of struts */
windows = meta_workspace_list_windows (workspace);
g_free (workspace->work_area_xinerama);
workspace->work_area_xinerama = g_new (MetaRectangle,
workspace->screen->n_xinerama_infos);
i = 0;
while (i < workspace->screen->n_xinerama_infos)
for (tmp = windows; tmp != NULL; tmp = tmp->next)
{
left_strut = 0;
right_strut = 0;
top_strut = 0;
bottom_strut = 0;
MetaWindow *win = tmp->data;
GSList *s_iter;
tmp = windows;
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
if (w->struts)
{
meta_topic (META_DEBUG_WORKAREA,
"Merging win %s with %d %d %d %d "
"with %d %d %d %d\n",
w->desc,
w->struts->left.width, w->struts->right.width,
w->struts->top.height, w->struts->bottom.height,
left_strut, right_strut,
top_strut, bottom_strut);
if ((i == 0) && (w->struts->left.width > 0))
{
for (s_iter = win->struts; s_iter != NULL; s_iter = s_iter->next)
workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->left);
s_iter->data);
}
if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->left))
{
left_strut = MAX (left_strut,
w->struts->left.width -
workspace->screen->xinerama_infos[i].rect.x);
all_left_strut = MAX (all_left_strut, w->struts->left.width);
}
if ((i == 0) && (w->struts->right.width > 0))
{
workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->right);
}
if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->right))
{
right_strut = MAX (right_strut, w->struts->right.width -
workspace->screen->rect.width +
workspace->screen->xinerama_infos[i].rect.width +
workspace->screen->xinerama_infos[i].rect.x);
all_right_strut = MAX (all_right_strut, w->struts->right.width);
}
if ((i == 0) && (w->struts->top.height > 0))
{
workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->top);
}
if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->top))
{
top_strut = MAX (top_strut,
w->struts->top.height -
workspace->screen->xinerama_infos[i].rect.y);
all_top_strut = MAX (all_top_strut, w->struts->top.height);
}
if ((i == 0) && (w->struts->bottom.height > 0))
{
workspace->all_struts = g_slist_prepend (workspace->all_struts,
&w->struts->bottom);
}
if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
&w->struts->bottom))
{
bottom_strut = MAX (bottom_strut, w->struts->bottom.height -
workspace->screen->rect.height +
workspace->screen->xinerama_infos[i].rect.height +
workspace->screen->xinerama_infos[i].rect.y);
all_bottom_strut = MAX (all_bottom_strut, w->struts->bottom.height);
}
}
tmp = tmp->next;
}
/* Some paranoid robustness */
#define MIN_SANE_AREA 100
if ((left_strut + right_strut) >
(workspace->screen->xinerama_infos[i].rect.width - MIN_SANE_AREA))
{
meta_topic (META_DEBUG_WORKAREA,
"Making left/right struts %d %d sane xinerama %d\n",
left_strut, right_strut, i);
left_strut = (workspace->screen->xinerama_infos[i].rect.width -
MIN_SANE_AREA) / 2;
right_strut = left_strut;
}
if ((top_strut + bottom_strut) >
(workspace->screen->xinerama_infos[i].rect.height - MIN_SANE_AREA))
{
meta_topic (META_DEBUG_WORKAREA,
"Making top/bottom struts %d %d sane xinerama %d\n",
top_strut, bottom_strut, i);
top_strut = (workspace->screen->xinerama_infos[i].rect.height -
MIN_SANE_AREA) / 2;
bottom_strut = top_strut;
}
workspace->work_area_xinerama[i].x =
left_strut + workspace->screen->xinerama_infos[i].rect.x;
workspace->work_area_xinerama[i].y = top_strut +
workspace->screen->xinerama_infos[i].rect.y;
workspace->work_area_xinerama[i].width =
workspace->screen->xinerama_infos[i].rect.width -
left_strut - right_strut;
workspace->work_area_xinerama[i].height =
workspace->screen->xinerama_infos[i].rect.height -
top_strut - bottom_strut;
meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d "
"xinerama %d: %d,%d %d x %d\n",
meta_workspace_index (workspace),
i,
workspace->work_area_xinerama[i].x,
workspace->work_area_xinerama[i].y,
workspace->work_area_xinerama[i].width,
workspace->work_area_xinerama[i].height);
++i;
}
g_list_free (windows);
if ((all_left_strut + all_right_strut) >
(workspace->screen->rect.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->rect.width - MIN_SANE_AREA) / 2;
all_right_strut = all_left_strut;
}
if ((all_top_strut + all_bottom_strut) >
(workspace->screen->rect.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->rect.height - MIN_SANE_AREA) / 2;
all_bottom_strut = all_top_strut;
}
workspace->work_area_screen.x = all_left_strut;
workspace->work_area_screen.y = all_top_strut;
workspace->work_area_screen.width =
workspace->screen->rect.width - all_left_strut - all_right_strut;
workspace->work_area_screen.height =
workspace->screen->rect.height - all_top_strut - all_bottom_strut;
/* Now cache the spanning rects for the onscreen and
/* STEP 2: Get the maximal/spanning rects for the onscreen and
* on-single-xinerama regions
*/
g_assert (workspace->xinerama_region == NULL);
@ -707,12 +539,96 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
meta_rectangle_get_minimal_spanning_set_for_region (
&workspace->screen->rect,
workspace->all_struts);
/* Since get_minimal_spanning_set_for_region() doesn't do the
* MIN_SANE_AREA thing, manually account for it. Note that it's okay if
* get_minimal_spanning_set_for_region() returns a very small region--all
* we really need here is a 1x1 region that corresponds to somewhere on
* the monitor for the partially onscreen constraint. If we don't get
* anything, though, we use work_area_screen just for convenience.
/* STEP 3: Get the work areas (region-to-maximize-to) for the screen and
* xineramas.
*/
work_area = workspace->screen->rect; /* start with the screen */
if (workspace->screen_region == NULL)
work_area = meta_rect (0, 0, -1, -1);
else
meta_rectangle_clip_to_region (workspace->screen_region,
FIXED_DIRECTION_NONE,
&work_area);
/* Lots of paranoia checks, forcing work_area_screen to be sane */
#define MIN_SANE_AREA 100
if (work_area.width < MIN_SANE_AREA)
{
meta_warning ("struts occupy an unusually large percentage of the screen; "
"available remaining width = %d < %d",
work_area.width, MIN_SANE_AREA);
if (work_area.width < 1)
{
work_area.x = (workspace->screen->rect.width - MIN_SANE_AREA)/2;
work_area.width = MIN_SANE_AREA;
}
else
{
int amount = (MIN_SANE_AREA - work_area.width)/2;
work_area.x -= amount;
work_area.width += 2*amount;
}
}
if (work_area.height < MIN_SANE_AREA)
{
meta_warning ("struts occupy an unusually large percentage of the screen; "
"available remaining height = %d < %d",
work_area.height, MIN_SANE_AREA);
if (work_area.height < 1)
{
work_area.y = (workspace->screen->rect.height - MIN_SANE_AREA)/2;
work_area.height = MIN_SANE_AREA;
}
else
{
int amount = (MIN_SANE_AREA - work_area.height)/2;
work_area.y -= amount;
work_area.height += 2*amount;
}
}
workspace->work_area_screen = work_area;
meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d: %d,%d %d x %d\n",
meta_workspace_index (workspace),
workspace->work_area_screen.x,
workspace->work_area_screen.y,
workspace->work_area_screen.width,
workspace->work_area_screen.height);
/* Now find the work areas for each xinerama */
g_free (workspace->work_area_xinerama);
workspace->work_area_xinerama = g_new (MetaRectangle,
workspace->screen->n_xinerama_infos);
for (i = 0; i < workspace->screen->n_xinerama_infos; i++)
{
work_area = workspace->screen->xinerama_infos[i].rect;
if (workspace->xinerama_region[i] == NULL)
/* FIXME: constraints.c untested with this, but it might be nice for
* a screen reader or magnifier.
*/
work_area = meta_rect (work_area.x, work_area.y, -1, -1);
else
meta_rectangle_clip_to_region (workspace->xinerama_region[i],
FIXED_DIRECTION_NONE,
&work_area);
workspace->work_area_xinerama[i] = work_area;
meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d "
"xinerama %d: %d,%d %d x %d\n",
meta_workspace_index (workspace),
i,
workspace->work_area_xinerama[i].x,
workspace->work_area_xinerama[i].y,
workspace->work_area_xinerama[i].width,
workspace->work_area_xinerama[i].height);
}
/* STEP 4: Make sure the screen_region is nonempty (separate from step 2
* since it relies on step 3).
*/
if (workspace->screen_region == NULL)
{
@ -722,7 +638,7 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
workspace->screen_region = g_list_prepend (NULL, nonempty_region);
}
/* Now cache the screen and xinerama edges for edge resistance and snapping */
/* STEP 5: Cache screen and xinerama edges for edge resistance and snapping */
g_assert (workspace->screen_edges == NULL);
g_assert (workspace->xinerama_edges == NULL);
workspace->screen_edges =
@ -736,17 +652,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
workspace->all_struts);
g_list_free (tmp);
/* We're all done, YAAY! Record that everything has been validated. */
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->work_area_screen.x,
workspace->work_area_screen.y,
workspace->work_area_screen.width,
workspace->work_area_screen.height);
}
void