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:
Elijah Newren 2006-01-10 04:33:58 +00:00 committed by Elijah Newren
parent 9eb56f151c
commit 9516694385
4 changed files with 148 additions and 87 deletions

View File

@ -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> 2006-01-09 Elijah Newren <newren@gmail.com>
Plug a few leaks. Fixes #309178. Plug a few leaks. Fixes #309178.

View File

@ -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* static GList*
get_rect_minus_overlap (const GList *rect_in_list, get_rect_minus_overlap (const GList *rect_in_list,
MetaRectangle *overlap) MetaRectangle *overlap)
@ -1175,20 +1199,22 @@ get_disjoint_strut_list_in_region (const GSList *old_struts,
return struts; return struts;
} }
/* To make things easily testable, provide a nice way of sorting edges */
gint gint
meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b) meta_rectangle_edge_cmp_ignore_type (gconstpointer a, gconstpointer b)
{ {
const MetaEdge *a_edge_rect = (gconstpointer) a; const MetaEdge *a_edge_rect = (gconstpointer) a;
const MetaEdge *b_edge_rect = (gconstpointer) b; 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; int a_compare, b_compare;
a_compare = a_edge_rect->side_type; a_compare = b_compare = 0; /* gcc-3.4.2 sucks at figuring initialized'ness */
b_compare = b_edge_rect->side_type;
if (a_compare == b_compare)
{
if (a_edge_rect->side_type == META_DIRECTION_LEFT || if (a_edge_rect->side_type == META_DIRECTION_LEFT ||
a_edge_rect->side_type == META_DIRECTION_RIGHT) a_edge_rect->side_type == META_DIRECTION_RIGHT)
{ {
@ -1213,8 +1239,25 @@ meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b)
} }
else else
g_assert ("Some idiot wanted to sort sides of different types.\n"); 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)
{
const MetaEdge *a_edge_rect = (gconstpointer) a;
const MetaEdge *b_edge_rect = (gconstpointer) b;
int a_compare, b_compare;
a_compare = a_edge_rect->side_type;
b_compare = b_edge_rect->side_type;
if (a_compare == b_compare)
return meta_rectangle_edge_cmp_ignore_type (a, b);
return a_compare - b_compare; /* positive value denotes a > b ... */ return a_compare - b_compare; /* positive value denotes a > b ... */
} }

View File

@ -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 /* Compare two edges, so that sorting functions can put a list of edges in
* canonical order. * canonical order.
*/ */
gint meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b); 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 /* Removes an parts of edges in the given list that intersect any box in the
* given rectangle list. Returns the result. * given rectangle list. Returns the result.
*/ */

View File

@ -224,9 +224,7 @@ find_nearest_position (const GArray *edges,
/* Start the search at mid */ /* Start the search at mid */
edge = g_array_index (edges, MetaEdge*, mid); edge = g_array_index (edges, MetaEdge*, mid);
compare = horizontal ? edge->rect.x : edge->rect.y; compare = horizontal ? edge->rect.x : edge->rect.y;
edges_align = horizontal ? edges_align = meta_rectangle_edge_aligns (new_rect, edge);
meta_rectangle_vert_overlap (&edge->rect, new_rect) :
meta_rectangle_horiz_overlap (&edge->rect, new_rect);
if (edges_align && if (edges_align &&
(!only_forward || !points_on_same_side (position, compare, old_position))) (!only_forward || !points_on_same_side (position, compare, old_position)))
{ {
@ -322,6 +320,7 @@ static int
apply_edge_resistance (MetaWindow *window, apply_edge_resistance (MetaWindow *window,
int old_pos, int old_pos,
int new_pos, int new_pos,
const MetaRectangle *old_rect,
const MetaRectangle *new_rect, const MetaRectangle *new_rect,
GArray *edges, GArray *edges,
ResistanceDataForAnEdge *resistance_data, ResistanceDataForAnEdge *resistance_data,
@ -384,9 +383,8 @@ apply_edge_resistance (MetaWindow *window,
int compare = xdir ? edge->rect.x : edge->rect.y; int compare = xdir ? edge->rect.x : edge->rect.y;
/* Find out if this edge is relevant */ /* Find out if this edge is relevant */
edges_align = xdir ? edges_align = meta_rectangle_edge_aligns (new_rect, edge) ||
meta_rectangle_vert_overlap (&edge->rect, new_rect) : meta_rectangle_edge_aligns (old_rect, edge);
meta_rectangle_horiz_overlap (&edge->rect, new_rect);
/* Nothing to do unless the edges align */ /* Nothing to do unless the edges align */
if (!edges_align) if (!edges_align)
@ -578,50 +576,21 @@ static int
apply_edge_snapping (int old_pos, apply_edge_snapping (int old_pos,
int new_pos, int new_pos,
const MetaRectangle *new_rect, const MetaRectangle *new_rect,
GArray *edges1, GArray *edges,
GArray *edges2,
gboolean xdir, gboolean xdir,
gboolean keyboard_op) gboolean keyboard_op)
{ {
int pos1, pos2; int snap_to;
int best;
if (old_pos == new_pos) if (old_pos == new_pos)
return new_pos; return new_pos;
/* We look at two sets of edges (e.g. left and right) individually snap_to = find_nearest_position (edges,
* 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, new_pos,
old_pos, old_pos,
new_rect, new_rect,
xdir, xdir,
keyboard_op); 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;
/* If mouse snap-moving, the user could easily accidentally move just a /* 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 * 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. * anyway.
*/ */
if (!keyboard_op && if (!keyboard_op &&
ABS (best - old_pos) >= 8 && ABS (snap_to - old_pos) >= 8 &&
ABS (new_pos - old_pos) < 8) ABS (new_pos - old_pos) < 8)
return old_pos; return old_pos;
else else
/* Otherwise, return the best of the snapping positions found */ /* Otherwise, return the snapping position found */
return best; return snap_to;
} }
/* This function takes the position (including any frame) of the window and /* 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), BOX_LEFT (*new_outer),
new_outer, new_outer,
edge_data->left_edges, edge_data->left_edges,
edge_data->right_edges,
TRUE, TRUE,
keyboard_op); keyboard_op);
new_right = apply_edge_snapping (BOX_RIGHT (*old_outer), new_right = apply_edge_snapping (BOX_RIGHT (*old_outer),
BOX_RIGHT (*new_outer), BOX_RIGHT (*new_outer),
new_outer, new_outer,
edge_data->left_edges,
edge_data->right_edges, edge_data->right_edges,
TRUE, TRUE,
keyboard_op); keyboard_op);
@ -689,14 +656,12 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
BOX_TOP (*new_outer), BOX_TOP (*new_outer),
new_outer, new_outer,
edge_data->top_edges, edge_data->top_edges,
edge_data->bottom_edges,
FALSE, FALSE,
keyboard_op); keyboard_op);
new_bottom = apply_edge_snapping (BOX_BOTTOM (*old_outer), new_bottom = apply_edge_snapping (BOX_BOTTOM (*old_outer),
BOX_BOTTOM (*new_outer), BOX_BOTTOM (*new_outer),
new_outer, new_outer,
edge_data->top_edges,
edge_data->bottom_edges, edge_data->bottom_edges,
FALSE, FALSE,
keyboard_op); keyboard_op);
@ -707,6 +672,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
new_left = apply_edge_resistance (window, new_left = apply_edge_resistance (window,
BOX_LEFT (*old_outer), BOX_LEFT (*old_outer),
BOX_LEFT (*new_outer), BOX_LEFT (*new_outer),
old_outer,
new_outer, new_outer,
edge_data->left_edges, edge_data->left_edges,
&edge_data->left_data, &edge_data->left_data,
@ -716,6 +682,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
new_right = apply_edge_resistance (window, new_right = apply_edge_resistance (window,
BOX_RIGHT (*old_outer), BOX_RIGHT (*old_outer),
BOX_RIGHT (*new_outer), BOX_RIGHT (*new_outer),
old_outer,
new_outer, new_outer,
edge_data->right_edges, edge_data->right_edges,
&edge_data->right_data, &edge_data->right_data,
@ -725,6 +692,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
new_top = apply_edge_resistance (window, new_top = apply_edge_resistance (window,
BOX_TOP (*old_outer), BOX_TOP (*old_outer),
BOX_TOP (*new_outer), BOX_TOP (*new_outer),
old_outer,
new_outer, new_outer,
edge_data->top_edges, edge_data->top_edges,
&edge_data->top_data, &edge_data->top_data,
@ -734,6 +702,7 @@ apply_edge_resistance_to_each_side (MetaDisplay *display,
new_bottom = apply_edge_resistance (window, new_bottom = apply_edge_resistance (window,
BOX_BOTTOM (*old_outer), BOX_BOTTOM (*old_outer),
BOX_BOTTOM (*new_outer), BOX_BOTTOM (*new_outer),
old_outer,
new_outer, new_outer,
edge_data->bottom_edges, edge_data->bottom_edges,
&edge_data->bottom_data, &edge_data->bottom_data,
@ -764,19 +733,24 @@ meta_display_cleanup_edges (MetaDisplay *display)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
GArray *tmp = NULL; GArray *tmp = NULL;
MetaDirection dir;
switch (i) switch (i)
{ {
case 0: case 0:
tmp = edge_data->left_edges; tmp = edge_data->left_edges;
dir = META_DIRECTION_LEFT;
break; break;
case 1: case 1:
tmp = edge_data->right_edges; tmp = edge_data->right_edges;
dir = META_DIRECTION_RIGHT;
break; break;
case 2: case 2:
tmp = edge_data->top_edges; tmp = edge_data->top_edges;
dir = META_DIRECTION_TOP;
break; break;
case 3: case 3:
tmp = edge_data->bottom_edges; tmp = edge_data->bottom_edges;
dir = META_DIRECTION_BOTTOM;
break; break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
@ -785,7 +759,8 @@ meta_display_cleanup_edges (MetaDisplay *display)
for (j = 0; j < tmp->len; j++) for (j = 0; j < tmp->len; j++)
{ {
MetaEdge *edge = g_array_index (tmp, MetaEdge*, 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); g_free (edge);
} }
} }
@ -820,7 +795,7 @@ stupid_sort_requiring_extra_pointer_dereference (gconstpointer a,
{ {
const MetaEdge * const *a_edge = a; const MetaEdge * const *a_edge = a;
const MetaEdge * const *b_edge = b; 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 static void
@ -889,24 +864,23 @@ cache_edges (MetaDisplay *display,
edge_data->left_edges = g_array_sized_new (FALSE, edge_data->left_edges = g_array_sized_new (FALSE,
FALSE, FALSE,
sizeof(MetaEdge*), sizeof(MetaEdge*),
num_left); num_left + num_right);
edge_data->right_edges = g_array_sized_new (FALSE, edge_data->right_edges = g_array_sized_new (FALSE,
FALSE, FALSE,
sizeof(MetaEdge*), sizeof(MetaEdge*),
num_right); num_left + num_right);
edge_data->top_edges = g_array_sized_new (FALSE, edge_data->top_edges = g_array_sized_new (FALSE,
FALSE, FALSE,
sizeof(MetaEdge*), sizeof(MetaEdge*),
num_top); num_top + num_bottom);
edge_data->bottom_edges = g_array_sized_new (FALSE, edge_data->bottom_edges = g_array_sized_new (FALSE,
FALSE, FALSE,
sizeof(MetaEdge*), sizeof(MetaEdge*),
num_bottom); num_top + num_bottom);
/* /*
* 3rd: Add the edges to the arrays * 3rd: Add the edges to the arrays
*/ */
num_left = num_right = num_top = num_bottom = 0;
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
tmp = NULL; tmp = NULL;
@ -931,15 +905,13 @@ cache_edges (MetaDisplay *display,
switch (edge->side_type) switch (edge->side_type)
{ {
case META_DIRECTION_LEFT: case META_DIRECTION_LEFT:
g_array_append_val (edge_data->left_edges, edge);
break;
case META_DIRECTION_RIGHT: case META_DIRECTION_RIGHT:
g_array_append_val (edge_data->left_edges, edge);
g_array_append_val (edge_data->right_edges, edge); g_array_append_val (edge_data->right_edges, edge);
break; break;
case META_DIRECTION_TOP: case META_DIRECTION_TOP:
g_array_append_val (edge_data->top_edges, edge);
break;
case META_DIRECTION_BOTTOM: case META_DIRECTION_BOTTOM:
g_array_append_val (edge_data->top_edges, edge);
g_array_append_val (edge_data->bottom_edges, edge); g_array_append_val (edge_data->bottom_edges, edge);
break; break;
default: default: