mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
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:
parent
e82ce26425
commit
08f51fdf94
58
ChangeLog
58
ChangeLog
@ -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
|
||||
|
162
src/boxes.c
162
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,10 +1144,10 @@ 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*
|
||||
get_rect_minus_overlap (const GList *rect_in_list,
|
||||
@ -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);
|
||||
|
19
src/boxes.h
19
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,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
|
||||
|
16
src/common.h
16
src/common.h
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -300,10 +300,10 @@ 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
|
||||
edge_resistance_timeout (gpointer data)
|
||||
|
@ -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*
|
||||
|
@ -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, ...)
|
||||
|
@ -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
|
||||
|
||||
|
209
src/window.c
209
src/window.c
@ -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);
|
||||
|
12
src/window.h
12
src/window.h
@ -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;
|
||||
|
295
src/workspace.c
295
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 *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
|
||||
|
Loading…
Reference in New Issue
Block a user