diff --git a/ChangeLog b/ChangeLog index c60d5ea9e..2fa0a08c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2006-01-09 Elijah Newren + + 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 Plug a few leaks. Fixes #309178. diff --git a/src/boxes.c b/src/boxes.c index 96d0869a2..33255337c 100644 --- a/src/boxes.c +++ b/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 ... */ } diff --git a/src/boxes.h b/src/boxes.h index cea7cf32f..d60358ece 100644 --- a/src/boxes.h +++ b/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. */ diff --git a/src/edge-resistance.c b/src/edge-resistance.c index fc96d3c3a..40979beba 100644 --- a/src/edge-resistance.c +++ b/src/edge-resistance.c @@ -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: