diff --git a/ChangeLog b/ChangeLog index aafd938dd..2df40b110 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,61 @@ +2007-04-02 Elijah Newren + + 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 + + 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 * src/theme.c (kill_window_question): Fallback to NORMAL state after diff --git a/src/boxes.c b/src/boxes.c index f40a085ee..cc0fbac96 100644 --- a/src/boxes.c +++ b/src/boxes.c @@ -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 (); } - - 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, - const MetaRectangle *region) +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 @@ -1347,7 +1416,7 @@ rectangle_and_edge_intersection (const MetaRectangle *rect, /* Find out if the intersection is empty; have to do it this way since * edges have a thickness of 0 */ - if ((result->width < 0 || result->height < 0) || + if ((result->width < 0 || result->height < 0) || (result->width == 0 && result->height == 0)) { result->width = 0; @@ -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); diff --git a/src/boxes.h b/src/boxes.h index 5c9552da3..145dbb055 100644 --- a/src/boxes.h +++ b/src/boxes.h @@ -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,8 +50,9 @@ struct _MetaRectangle typedef enum { - FIXED_DIRECTION_X = 1 << 0, - FIXED_DIRECTION_Y = 1 << 1, + FIXED_DIRECTION_NONE = 0, + FIXED_DIRECTION_X = 1 << 0, + FIXED_DIRECTION_Y = 1 << 1, } FixedDirections; typedef enum @@ -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 diff --git a/src/common.h b/src/common.h index 087798e00..c24def532 100644 --- a/src/common.h +++ b/src/common.h @@ -216,12 +216,24 @@ typedef enum */ typedef enum { - META_DIRECTION_LEFT = 1 << 0, - 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 */ + META_DIRECTION_LEFT = 1 << 0, + META_DIRECTION_RIGHT = 1 << 1, + META_DIRECTION_TOP = 1 << 2, + META_DIRECTION_BOTTOM = 1 << 3, + + /* 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 diff --git a/src/constraints.c b/src/constraints.c index c6044ef4c..d868c9646 100644 --- a/src/constraints.c +++ b/src/constraints.c @@ -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; } diff --git a/src/edge-resistance.c b/src/edge-resistance.c index 3db21ab4d..688066487 100644 --- a/src/edge-resistance.c +++ b/src/edge-resistance.c @@ -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 (); } - - g_assert_not_reached (); } static gboolean diff --git a/src/testboxes.c b/src/testboxes.c index 9e958b75a..0da297506 100644 --- a/src/testboxes.c +++ b/src/testboxes.c @@ -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* diff --git a/src/util.c b/src/util.c index 9fdecd6ff..ca2452f3d 100644 --- a/src/util.c +++ b/src/util.c @@ -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, ...) diff --git a/src/util.h b/src/util.h index d88c7752c..161ae9382 100644 --- a/src/util.h +++ b/src/util.h @@ -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 diff --git a/src/window.c b/src/window.c index 0f2ac2366..2f94a9986 100644 --- a/src/window.c +++ b/src/window.c @@ -5675,86 +5675,74 @@ 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; + old_struts = window->struts; + new_struts = NULL; - 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; - if (meta_prop_get_cardinal_list (window->display, window->xwindow, window->display->atom_net_wm_strut_partial, &struts, &nitems)) { if (nitems != 12) - { - meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead of 12\n", - window->desc, nitems); - } + 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; - - 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, + /* 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; + + 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 (!new_struts && + meta_prop_get_cardinal_list (window->display, + window->xwindow, + window->display->atom_net_wm_strut, + &struts, &nitems)) { - 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); - } - 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; - - 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, - window->desc); - - } - meta_XFree (struts); - } + if (nitems != 4) + meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4\n", + window->desc, nitems); else { - meta_verbose ("No _NET_WM_STRUT property for %s\n", + /* Pull out the strut info for each side in the hint */ + int i; + for (i=0; i<4; i++) + { + MetaStrut *temp; + int thickness; + + 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 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) + { + MetaStrut *old_strut = (MetaStrut*) old_iter->data; + MetaStrut *new_strut = (MetaStrut*) new_iter->data; + + 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; + } + changed = (old_iter != NULL || new_iter != NULL); + + /* Update appropriately */ + meta_free_gslist_and_elements (old_struts); + window->struts = new_struts; + if (changed) { - if (new_has_struts) - { - if (!window->struts) - window->struts = g_new (MetaStruts, 1); - - window->struts->left = new_left; - window->struts->right = new_right; - window->struts->top = new_top; - window->struts->bottom = new_bottom; - } - else - { - 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); diff --git a/src/window.h b/src/window.h index 0dac50d20..2fb271bbd 100644 --- a/src/window.h +++ b/src/window.h @@ -36,7 +36,6 @@ #include 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; diff --git a/src/workspace.c b/src/workspace.c index 8ea5e8ebd..d11fcecd7 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -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 *windows; + GList *tmp; + MetaRectangle work_area; + int i; /* C89 absolutely sucks... */ if (!workspace->work_areas_invalid) return; @@ -513,183 +506,22 @@ ensure_work_areas_validated (MetaWorkspace *workspace) g_assert (workspace->screen_region == NULL); 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)) - { - workspace->all_struts = g_slist_prepend (workspace->all_struts, - &w->struts->left); - } - - 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; + for (s_iter = win->struts; s_iter != NULL; s_iter = s_iter->next) + workspace->all_struts = g_slist_prepend (workspace->all_struts, + s_iter->data); } - 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 - * on-single-xinerama regions + /* STEP 2: Get the maximal/spanning rects for the onscreen and + * on-single-xinerama regions */ g_assert (workspace->xinerama_region == NULL); g_assert (workspace->screen_region == NULL); @@ -707,13 +539,97 @@ 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) { MetaRectangle *nonempty_region; @@ -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