Allow edge resistance at both sides of a window and also when edges don't
2006-01-09 Elijah Newren <newren@gmail.com> Allow edge resistance at both sides of a window and also when edges don't overlap but are a single pixel away from doing so. Fixes one of the zillions of issues covered in #321905. * src/boxes.[ch]: (meta_rectangle_edges_align): new function to handle the overlap or off by one determining whether edge resistance should kick in for an edge. (meta_rectangle_edge_cmp_ignore_type): new function to sort edges but ignore the type so that e.g. left & right edges of windows can be used interchangeably. (meta_rectangle_edge_cmp): now uses meta_rectangle_edge_cmp_ignore_type() to do most the work and just adds an extra condition * src/edge-resistance.c: (find_nearest_position): use meta_rectangle_edges_align() now to determine whether the edges align, (apply_edge_resistance, apply_edge_resistance_to_each_side): have the edge resistance kick in if either the beginning or ending positions would cause overlap in the given direction -- fixes an uncommon but annoying corner case, (apply_edge_snapping, apply_edge_resistance_to_each_side, meta_display_cleanup_edges, stupid_sort_requiring_extra_pointer_dereference, cache_edges): mix edges from both sides now
This commit is contained in:
parent
9eb56f151c
commit
9516694385
34
ChangeLog
34
ChangeLog
@ -1,3 +1,37 @@
|
||||
2006-01-09 Elijah Newren <newren@gmail.com>
|
||||
|
||||
Allow edge resistance at both sides of a window and also when
|
||||
edges don't overlap but are a single pixel away from doing so.
|
||||
Fixes one of the zillions of issues covered in #321905.
|
||||
|
||||
* src/boxes.[ch]:
|
||||
(meta_rectangle_edges_align):
|
||||
new function to handle the overlap or off by one determining
|
||||
whether edge resistance should kick in for an edge.
|
||||
|
||||
(meta_rectangle_edge_cmp_ignore_type):
|
||||
new function to sort edges but ignore the type so that e.g. left &
|
||||
right edges of windows can be used interchangeably.
|
||||
|
||||
(meta_rectangle_edge_cmp):
|
||||
now uses meta_rectangle_edge_cmp_ignore_type() to do most the work
|
||||
and just adds an extra condition
|
||||
|
||||
* src/edge-resistance.c:
|
||||
(find_nearest_position):
|
||||
use meta_rectangle_edges_align() now to determine whether the
|
||||
edges align,
|
||||
|
||||
(apply_edge_resistance, apply_edge_resistance_to_each_side):
|
||||
have the edge resistance kick in if either the beginning or ending
|
||||
positions would cause overlap in the given direction -- fixes an
|
||||
uncommon but annoying corner case,
|
||||
|
||||
(apply_edge_snapping, apply_edge_resistance_to_each_side,
|
||||
meta_display_cleanup_edges,
|
||||
stupid_sort_requiring_extra_pointer_dereference, cache_edges):
|
||||
mix edges from both sides now
|
||||
|
||||
2006-01-09 Elijah Newren <newren@gmail.com>
|
||||
|
||||
Plug a few leaks. Fixes #309178.
|
||||
|
95
src/boxes.c
95
src/boxes.c
@ -1012,6 +1012,30 @@ meta_rectangle_find_linepoint_closest_to_point (double x1,
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
gboolean
|
||||
meta_rectangle_edge_aligns (const MetaRectangle *rect, const MetaEdge *edge)
|
||||
{
|
||||
/* The reason for the usage of <= below instead of < is because we are
|
||||
* interested in in-the-way-or-adject'ness. So, a left (i.e. vertical
|
||||
* edge) occupying y positions 0-9 (which has a y of 0 and a height of
|
||||
* 10) and a rectangle with top at y=10 would be considered to "align" by
|
||||
* this function.
|
||||
*/
|
||||
switch (edge->side_type)
|
||||
{
|
||||
case META_DIRECTION_LEFT:
|
||||
case META_DIRECTION_RIGHT:
|
||||
return BOX_TOP (*rect) <= BOX_BOTTOM (edge->rect) &&
|
||||
BOX_TOP (edge->rect) <= BOX_BOTTOM (*rect);
|
||||
case META_DIRECTION_TOP:
|
||||
case META_DIRECTION_BOTTOM:
|
||||
return BOX_LEFT (*rect) <= BOX_RIGHT (edge->rect) &&
|
||||
BOX_LEFT (edge->rect) <= BOX_RIGHT (*rect);
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static GList*
|
||||
get_rect_minus_overlap (const GList *rect_in_list,
|
||||
MetaRectangle *overlap)
|
||||
@ -1175,6 +1199,50 @@ get_disjoint_strut_list_in_region (const GSList *old_struts,
|
||||
return struts;
|
||||
}
|
||||
|
||||
gint
|
||||
meta_rectangle_edge_cmp_ignore_type (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const MetaEdge *a_edge_rect = (gconstpointer) a;
|
||||
const MetaEdge *b_edge_rect = (gconstpointer) b;
|
||||
|
||||
/* Edges must be both vertical or both horizontal, or it doesn't make
|
||||
* sense to compare them.
|
||||
*/
|
||||
g_assert ((a_edge_rect->rect.width == 0 && b_edge_rect->rect.width == 0) ||
|
||||
(a_edge_rect->rect.height == 0 && b_edge_rect->rect.height == 0));
|
||||
|
||||
int a_compare, b_compare;
|
||||
|
||||
a_compare = b_compare = 0; /* gcc-3.4.2 sucks at figuring initialized'ness */
|
||||
|
||||
if (a_edge_rect->side_type == META_DIRECTION_LEFT ||
|
||||
a_edge_rect->side_type == META_DIRECTION_RIGHT)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.x;
|
||||
b_compare = b_edge_rect->rect.x;
|
||||
if (a_compare == b_compare)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.y;
|
||||
b_compare = b_edge_rect->rect.y;
|
||||
}
|
||||
}
|
||||
else if (a_edge_rect->side_type == META_DIRECTION_TOP ||
|
||||
a_edge_rect->side_type == META_DIRECTION_BOTTOM)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.y;
|
||||
b_compare = b_edge_rect->rect.y;
|
||||
if (a_compare == b_compare)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.x;
|
||||
b_compare = b_edge_rect->rect.x;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_assert ("Some idiot wanted to sort sides of different types.\n");
|
||||
|
||||
return a_compare - b_compare; /* positive value denotes a > b ... */
|
||||
}
|
||||
|
||||
/* To make things easily testable, provide a nice way of sorting edges */
|
||||
gint
|
||||
meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b)
|
||||
@ -1188,32 +1256,7 @@ meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b)
|
||||
b_compare = b_edge_rect->side_type;
|
||||
|
||||
if (a_compare == b_compare)
|
||||
{
|
||||
if (a_edge_rect->side_type == META_DIRECTION_LEFT ||
|
||||
a_edge_rect->side_type == META_DIRECTION_RIGHT)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.x;
|
||||
b_compare = b_edge_rect->rect.x;
|
||||
if (a_compare == b_compare)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.y;
|
||||
b_compare = b_edge_rect->rect.y;
|
||||
}
|
||||
}
|
||||
else if (a_edge_rect->side_type == META_DIRECTION_TOP ||
|
||||
a_edge_rect->side_type == META_DIRECTION_BOTTOM)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.y;
|
||||
b_compare = b_edge_rect->rect.y;
|
||||
if (a_compare == b_compare)
|
||||
{
|
||||
a_compare = a_edge_rect->rect.x;
|
||||
b_compare = b_edge_rect->rect.x;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_assert ("Some idiot wanted to sort sides of different types.\n");
|
||||
}
|
||||
return meta_rectangle_edge_cmp_ignore_type (a, b);
|
||||
|
||||
return a_compare - b_compare; /* positive value denotes a > b ... */
|
||||
}
|
||||
|
12
src/boxes.h
12
src/boxes.h
@ -211,11 +211,23 @@ void meta_rectangle_find_linepoint_closest_to_point (double x1, double y1,
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
/* Return whether an edge overlaps or is adjacent to the rectangle in the
|
||||
* nonzero-width dimension of the edge.
|
||||
*/
|
||||
gboolean meta_rectangle_edge_aligns (const MetaRectangle *rect,
|
||||
const MetaEdge *edge);
|
||||
|
||||
/* Compare two edges, so that sorting functions can put a list of edges in
|
||||
* canonical order.
|
||||
*/
|
||||
gint meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b);
|
||||
|
||||
/* Compare two edges, so that sorting functions can put a list of edges in
|
||||
* order. This function doesn't separate left edges first, then right edges,
|
||||
* etc., but rather compares only upon location.
|
||||
*/
|
||||
gint meta_rectangle_edge_cmp_ignore_type (gconstpointer a, gconstpointer b);
|
||||
|
||||
/* Removes an parts of edges in the given list that intersect any box in the
|
||||
* given rectangle list. Returns the result.
|
||||
*/
|
||||
|
@ -224,9 +224,7 @@ find_nearest_position (const GArray *edges,
|
||||
/* Start the search at mid */
|
||||
edge = g_array_index (edges, MetaEdge*, mid);
|
||||
compare = horizontal ? edge->rect.x : edge->rect.y;
|
||||
edges_align = horizontal ?
|
||||
meta_rectangle_vert_overlap (&edge->rect, new_rect) :
|
||||
meta_rectangle_horiz_overlap (&edge->rect, new_rect);
|
||||
edges_align = meta_rectangle_edge_aligns (new_rect, edge);
|
||||
if (edges_align &&
|
||||
(!only_forward || !points_on_same_side (position, compare, old_position)))
|
||||
{
|
||||
@ -322,6 +320,7 @@ static int
|
||||
apply_edge_resistance (MetaWindow *window,
|
||||
int old_pos,
|
||||
int new_pos,
|
||||
const MetaRectangle *old_rect,
|
||||
const MetaRectangle *new_rect,
|
||||
GArray *edges,
|
||||
ResistanceDataForAnEdge *resistance_data,
|
||||
@ -384,9 +383,8 @@ apply_edge_resistance (MetaWindow *window,
|
||||
int compare = xdir ? edge->rect.x : edge->rect.y;
|
||||
|
||||
/* Find out if this edge is relevant */
|
||||
edges_align = xdir ?
|
||||
meta_rectangle_vert_overlap (&edge->rect, new_rect) :
|
||||
meta_rectangle_horiz_overlap (&edge->rect, new_rect);
|
||||
edges_align = meta_rectangle_edge_aligns (new_rect, edge) ||
|
||||
meta_rectangle_edge_aligns (old_rect, edge);
|
||||
|
||||
/* Nothing to do unless the edges align */
|
||||
if (!edges_align)
|
||||
@ -578,50 +576,21 @@ static int
|
||||
apply_edge_snapping (int old_pos,
|
||||
int new_pos,
|
||||
const MetaRectangle *new_rect,
|
||||
GArray *edges1,
|
||||
GArray *edges2,
|
||||
GArray *edges,
|
||||
gboolean xdir,
|
||||
gboolean keyboard_op)
|
||||
{
|
||||
int pos1, pos2;
|
||||
int best;
|
||||
int snap_to;
|
||||
|
||||
if (old_pos == new_pos)
|
||||
return new_pos;
|
||||
|
||||
/* We look at two sets of edges (e.g. left and right) individually
|
||||
* finding the nearest position among each set of edges and then later
|
||||
* finding the better of these two bests.
|
||||
*/
|
||||
pos1 = find_nearest_position (edges1,
|
||||
new_pos,
|
||||
old_pos,
|
||||
new_rect,
|
||||
xdir,
|
||||
keyboard_op);
|
||||
pos2 = find_nearest_position (edges2,
|
||||
new_pos,
|
||||
old_pos,
|
||||
new_rect,
|
||||
xdir,
|
||||
keyboard_op);
|
||||
|
||||
/* For keyboard snapping, ignore either pos1 or pos2 if they aren't in the
|
||||
* right direction.
|
||||
*/
|
||||
if (keyboard_op)
|
||||
{
|
||||
if (!points_on_same_side (old_pos, pos1, new_pos))
|
||||
return pos2;
|
||||
if (!points_on_same_side (old_pos, pos2, new_pos))
|
||||
return pos1;
|
||||
}
|
||||
|
||||
/* Find the better of pos1 and pos2 and return it */
|
||||
if (ABS (pos1 - new_pos) < ABS (pos2 - new_pos))
|
||||
best = pos1;
|
||||
else
|
||||
best = pos2;
|
||||
snap_to = find_nearest_position (edges,
|
||||
new_pos,
|
||||
old_pos,
|
||||
new_rect,
|
||||
xdir,
|
||||
keyboard_op);
|
||||
|
||||
/* If mouse snap-moving, the user could easily accidentally move just a
|
||||
* couple pixels in a direction they didn't mean to move; so ignore snap
|
||||
@ -629,12 +598,12 @@ apply_edge_snapping (int old_pos,
|
||||
* anyway.
|
||||
*/
|
||||
if (!keyboard_op &&
|
||||
ABS (best - old_pos) >= 8 &&
|
||||
ABS (snap_to - old_pos) >= 8 &&
|
||||
ABS (new_pos - old_pos) < 8)
|
||||
return old_pos;
|
||||
else
|
||||
/* Otherwise, return the best of the snapping positions found */
|
||||
return best;
|
||||
/* Otherwise, return the snapping position found */
|
||||
return snap_to;
|
||||
}
|
||||
|
||||
/* This function takes the position (including any frame) of the window and
|
||||
@ -673,14 +642,12 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
|
||||
BOX_LEFT (*new_outer),
|
||||
new_outer,
|
||||
edge_data->left_edges,
|
||||
edge_data->right_edges,
|
||||
TRUE,
|
||||
keyboard_op);
|
||||
|
||||
new_right = apply_edge_snapping (BOX_RIGHT (*old_outer),
|
||||
BOX_RIGHT (*new_outer),
|
||||
new_outer,
|
||||
edge_data->left_edges,
|
||||
edge_data->right_edges,
|
||||
TRUE,
|
||||
keyboard_op);
|
||||
@ -689,14 +656,12 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
|
||||
BOX_TOP (*new_outer),
|
||||
new_outer,
|
||||
edge_data->top_edges,
|
||||
edge_data->bottom_edges,
|
||||
FALSE,
|
||||
keyboard_op);
|
||||
|
||||
new_bottom = apply_edge_snapping (BOX_BOTTOM (*old_outer),
|
||||
BOX_BOTTOM (*new_outer),
|
||||
new_outer,
|
||||
edge_data->top_edges,
|
||||
edge_data->bottom_edges,
|
||||
FALSE,
|
||||
keyboard_op);
|
||||
@ -707,6 +672,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
|
||||
new_left = apply_edge_resistance (window,
|
||||
BOX_LEFT (*old_outer),
|
||||
BOX_LEFT (*new_outer),
|
||||
old_outer,
|
||||
new_outer,
|
||||
edge_data->left_edges,
|
||||
&edge_data->left_data,
|
||||
@ -716,6 +682,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
|
||||
new_right = apply_edge_resistance (window,
|
||||
BOX_RIGHT (*old_outer),
|
||||
BOX_RIGHT (*new_outer),
|
||||
old_outer,
|
||||
new_outer,
|
||||
edge_data->right_edges,
|
||||
&edge_data->right_data,
|
||||
@ -725,6 +692,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
|
||||
new_top = apply_edge_resistance (window,
|
||||
BOX_TOP (*old_outer),
|
||||
BOX_TOP (*new_outer),
|
||||
old_outer,
|
||||
new_outer,
|
||||
edge_data->top_edges,
|
||||
&edge_data->top_data,
|
||||
@ -734,6 +702,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
|
||||
new_bottom = apply_edge_resistance (window,
|
||||
BOX_BOTTOM (*old_outer),
|
||||
BOX_BOTTOM (*new_outer),
|
||||
old_outer,
|
||||
new_outer,
|
||||
edge_data->bottom_edges,
|
||||
&edge_data->bottom_data,
|
||||
@ -764,19 +733,24 @@ meta_display_cleanup_edges (MetaDisplay *display)
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
GArray *tmp = NULL;
|
||||
MetaDirection dir;
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
tmp = edge_data->left_edges;
|
||||
dir = META_DIRECTION_LEFT;
|
||||
break;
|
||||
case 1:
|
||||
tmp = edge_data->right_edges;
|
||||
dir = META_DIRECTION_RIGHT;
|
||||
break;
|
||||
case 2:
|
||||
tmp = edge_data->top_edges;
|
||||
dir = META_DIRECTION_TOP;
|
||||
break;
|
||||
case 3:
|
||||
tmp = edge_data->bottom_edges;
|
||||
dir = META_DIRECTION_BOTTOM;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -785,7 +759,8 @@ meta_display_cleanup_edges (MetaDisplay *display)
|
||||
for (j = 0; j < tmp->len; j++)
|
||||
{
|
||||
MetaEdge *edge = g_array_index (tmp, MetaEdge*, j);
|
||||
if (edge->edge_type == META_EDGE_WINDOW)
|
||||
if (edge->edge_type == META_EDGE_WINDOW &&
|
||||
edge->side_type == dir)
|
||||
g_free (edge);
|
||||
}
|
||||
}
|
||||
@ -820,7 +795,7 @@ stupid_sort_requiring_extra_pointer_dereference (gconstpointer a,
|
||||
{
|
||||
const MetaEdge * const *a_edge = a;
|
||||
const MetaEdge * const *b_edge = b;
|
||||
return meta_rectangle_edge_cmp (*a_edge, *b_edge);
|
||||
return meta_rectangle_edge_cmp_ignore_type (*a_edge, *b_edge);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -889,24 +864,23 @@ cache_edges (MetaDisplay *display,
|
||||
edge_data->left_edges = g_array_sized_new (FALSE,
|
||||
FALSE,
|
||||
sizeof(MetaEdge*),
|
||||
num_left);
|
||||
num_left + num_right);
|
||||
edge_data->right_edges = g_array_sized_new (FALSE,
|
||||
FALSE,
|
||||
sizeof(MetaEdge*),
|
||||
num_right);
|
||||
num_left + num_right);
|
||||
edge_data->top_edges = g_array_sized_new (FALSE,
|
||||
FALSE,
|
||||
sizeof(MetaEdge*),
|
||||
num_top);
|
||||
num_top + num_bottom);
|
||||
edge_data->bottom_edges = g_array_sized_new (FALSE,
|
||||
FALSE,
|
||||
sizeof(MetaEdge*),
|
||||
num_bottom);
|
||||
num_top + num_bottom);
|
||||
|
||||
/*
|
||||
* 3rd: Add the edges to the arrays
|
||||
*/
|
||||
num_left = num_right = num_top = num_bottom = 0;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
tmp = NULL;
|
||||
@ -931,15 +905,13 @@ cache_edges (MetaDisplay *display,
|
||||
switch (edge->side_type)
|
||||
{
|
||||
case META_DIRECTION_LEFT:
|
||||
g_array_append_val (edge_data->left_edges, edge);
|
||||
break;
|
||||
case META_DIRECTION_RIGHT:
|
||||
g_array_append_val (edge_data->left_edges, edge);
|
||||
g_array_append_val (edge_data->right_edges, edge);
|
||||
break;
|
||||
case META_DIRECTION_TOP:
|
||||
g_array_append_val (edge_data->top_edges, edge);
|
||||
break;
|
||||
case META_DIRECTION_BOTTOM:
|
||||
g_array_append_val (edge_data->top_edges, edge);
|
||||
g_array_append_val (edge_data->bottom_edges, edge);
|
||||
break;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user