summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2005-11-08 12:45:21 +0000
committerElijah Newren <newren@src.gnome.org>2005-11-08 12:45:21 +0000
commitad6558a2fa03a44e8e6ae845fe2ac3ab77eb7d50 (patch)
tree24974f804be2d62729b31555e34a70127de82031
parent6c13db359da586905da00be30197c1fe0f7a3c76 (diff)
downloadmetacity-ad6558a2fa03a44e8e6ae845fe2ac3ab77eb7d50.tar.gz
Get edge auto-snapping to work again (and for the first time ever for
2005-11-08 Elijah Newren <newren@gmail.com> Get edge auto-snapping to work again (and for the first time ever for mouse resizing). NOTE THAT EDGE RESISTANCE IS STILL NOT COMPLETE AND I STILL HAVE A RIDICULOUSLY HUGE THRESHOLD FOR THAT REASON. ;-) * src/display.h: (struct MetaDisplay): new display->grab_last_used_state_for_resize field, so that xsync messages know whether to snap-resize or just normally resize. I don't know if this is the right way to do this or not... (meta_display_apply_edge_resistance): take an auto_snap parameter * src/display.c: (meta_display_begin_grab_op): initialize display->grab_last_used_state_for_resize (find_index_of_edge_near_position): declare the edge array to be const (find_nearest_position): new function, also binary-search-esque (apply_edge_snapping): simple front-end to find_nearest_position() so that it can be called for multiple edge arrays and the closest overall one used. (meta_display_apply_edge_resistance): take an auto_snap parameter and use apply_edge_snapping() instead of apply_edge_resistance() if it is set * src/window.c: (update_move): track the proposed window size so that we can compare the edge-resisted-modifications to both the original window and the size initially proposed, handle snapping too (update_resize_timeout, meta_window_handle_mouse_grab_op_event): make use of display->grab_last_used_state_for_resize so that the resize knows whether to snap or not. I hope this is the right way to do this. (update_resize): take a mask tracking which buttons are pressed (like update_move), save the mask to window->display->grab_last_used_state_for_resize, handle snapping (meta_window_handle_mouse_grab_op_event): pass the xbutton/xmotion/xcrossing modifier state to update_resize()
-rw-r--r--ChangeLog57
-rw-r--r--src/display.c237
-rw-r--r--src/display.h4
-rw-r--r--src/window.c79
4 files changed, 313 insertions, 64 deletions
diff --git a/ChangeLog b/ChangeLog
index 64a5d20c..c9c527b4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,62 @@
2005-11-08 Elijah Newren <newren@gmail.com>
+ Get edge auto-snapping to work again (and for the first time ever
+ for mouse resizing). NOTE THAT EDGE RESISTANCE IS STILL NOT
+ COMPLETE AND I STILL HAVE A RIDICULOUSLY HUGE THRESHOLD FOR THAT
+ REASON. ;-)
+
+ * src/display.h:
+
+ (struct MetaDisplay):
+ new display->grab_last_used_state_for_resize field, so that xsync
+ messages know whether to snap-resize or just normally resize. I
+ don't know if this is the right way to do this or not...
+
+ (meta_display_apply_edge_resistance):
+ take an auto_snap parameter
+
+ * src/display.c:
+
+ (meta_display_begin_grab_op):
+ initialize display->grab_last_used_state_for_resize
+
+ (find_index_of_edge_near_position):
+ declare the edge array to be const
+
+ (find_nearest_position):
+ new function, also binary-search-esque
+
+ (apply_edge_snapping):
+ simple front-end to find_nearest_position() so that it can be
+ called for multiple edge arrays and the closest overall one used.
+
+ (meta_display_apply_edge_resistance):
+ take an auto_snap parameter and use apply_edge_snapping() instead
+ of apply_edge_resistance() if it is set
+
+ * src/window.c:
+
+ (update_move):
+ track the proposed window size so that we can compare the
+ edge-resisted-modifications to both the original window and the
+ size initially proposed, handle snapping too
+
+ (update_resize_timeout, meta_window_handle_mouse_grab_op_event):
+ make use of display->grab_last_used_state_for_resize so that the
+ resize knows whether to snap or not. I hope this is the right way
+ to do this.
+
+ (update_resize):
+ take a mask tracking which buttons are pressed (like update_move),
+ save the mask to window->display->grab_last_used_state_for_resize,
+ handle snapping
+
+ (meta_window_handle_mouse_grab_op_event):
+ pass the xbutton/xmotion/xcrossing modifier state to
+ update_resize()
+
+2005-11-08 Elijah Newren <newren@gmail.com>
+
* src/window.c (update_resize): get basic edge resistance to work
with resizing too. I'm so cool. :-)
diff --git a/src/display.c b/src/display.c
index 1f97327f..e9ca3416 100644
--- a/src/display.c
+++ b/src/display.c
@@ -3303,6 +3303,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
display->grab_old_window_stacking = NULL;
#ifdef HAVE_XSYNC
display->grab_sync_request_alarm = None;
+ display->grab_last_used_state_for_resize = 0;
#endif
display->grab_was_cancelled = FALSE;
@@ -3771,12 +3772,11 @@ meta_display_ungrab_focus_window_button (MetaDisplay *display,
/***** Begin gobs of edge_resistance functions *****/
static int
-find_index_of_edge_near_position (GArray *edges,
- int position,
- gboolean want_interval_min,
- gboolean horizontal)
+find_index_of_edge_near_position (const GArray *edges,
+ int position,
+ gboolean want_interval_min,
+ gboolean horizontal)
{
-
/* This is basically like a binary search, except that we're trying to
* find a range instead of an exact value. So, if we have in our array
* Value: 3 27 316 316 316 505 522 800 1213
@@ -3875,6 +3875,119 @@ find_index_of_edge_near_position (GArray *edges,
}
static int
+find_nearest_position (const GArray *edges,
+ int position,
+ int old_position,
+ const MetaRectangle *new_rect,
+ gboolean horizontal)
+{
+ /* This is basically just a binary search except that we're looking
+ * for the value closest to position, rather than finding that
+ * actual value. Also, we ignore any edges that aren't relevant
+ * given the horizontal/vertical position of new_rect.
+ */
+ int low, high, mid;
+ int compare;
+ MetaEdge *edge;
+ int best, best_dist, i;
+
+ /* Initialize mid, edge, & compare in the off change that the array only
+ * has one element.
+ */
+ mid = 0;
+ edge = g_array_index (edges, MetaEdge*, mid);
+ compare = horizontal ? edge->rect.x : edge->rect.y;
+
+ /* Begin the search... */
+ low = 0;
+ high = edges->len - 1;
+ while (low < high)
+ {
+ mid = low + (high - low)/2;
+ edge = g_array_index (edges, MetaEdge*, mid);
+ compare = horizontal ? edge->rect.x : edge->rect.y;
+
+ if (compare == position)
+ break;
+
+ if (compare > position)
+ high = mid - 1;
+ else
+ low = mid + 1;
+ }
+
+ /* mid should now be _really_ close to the index we want, so we
+ * start searching nearby for something that overlaps and is closer
+ * than the original position.
+ */
+ best = old_position;
+ best_dist = INT_MAX;
+
+ /* Start the search at mid */
+ edge = g_array_index (edges, MetaEdge*, mid);
+ compare = horizontal ? edge->rect.x : edge->rect.y;
+ gboolean edges_align = horizontal ?
+ meta_rectangle_vert_overlap (&edge->rect, new_rect) :
+ meta_rectangle_horiz_overlap (&edge->rect, new_rect);
+ if (edges_align)
+ {
+ int dist = ABS (compare - position);
+ if (dist < best_dist)
+ {
+ best = compare;
+ best_dist = dist;
+ }
+ }
+
+ /* Now start searching higher than mid */
+ for (i = mid + 1; i < (int)edges->len; i++)
+ {
+ edge = g_array_index (edges, MetaEdge*, i);
+ compare = horizontal ? edge->rect.x : edge->rect.y;
+
+ gboolean edges_align = horizontal ?
+ meta_rectangle_vert_overlap (&edge->rect, new_rect) :
+ meta_rectangle_horiz_overlap (&edge->rect, new_rect);
+
+ if (edges_align)
+ {
+ int dist = ABS (compare - position);
+ if (dist < best_dist)
+ {
+ best = compare;
+ best_dist = dist;
+ }
+ break;
+ }
+ }
+
+ /* Now start searching lower than mid */
+ for (i = mid-1; i >= 0; i--)
+ {
+ edge = g_array_index (edges, MetaEdge*, i);
+ compare = horizontal ? edge->rect.x : edge->rect.y;
+
+ gboolean edges_align = horizontal ?
+ meta_rectangle_vert_overlap (&edge->rect, new_rect) :
+ meta_rectangle_horiz_overlap (&edge->rect, new_rect);
+
+ if (edges_align)
+ {
+ int dist = ABS (compare - position);
+ if (dist < best_dist)
+ {
+ best = compare;
+ best_dist = dist;
+ }
+ break;
+ }
+ }
+
+ /* Return the best one found */
+ return best;
+}
+
+static int
apply_edge_resistance (int old_pos,
int new_pos,
const MetaRectangle *new_rect,
@@ -3921,6 +4034,36 @@ apply_edge_resistance (int old_pos,
return new_pos;
}
+static int
+apply_edge_snapping (int old_pos,
+ int new_pos,
+ const MetaRectangle *new_rect,
+ GArray *edges1,
+ GArray *edges2,
+ gboolean xdir)
+{
+ int pos1, pos2;
+
+ if (old_pos == new_pos)
+ return new_pos;
+
+ pos1 = find_nearest_position (edges1,
+ new_pos,
+ old_pos,
+ new_rect,
+ xdir);
+ pos2 = find_nearest_position (edges2,
+ new_pos,
+ old_pos,
+ new_rect,
+ xdir);
+
+ if (ABS (pos1 - new_pos) < ABS (pos2 - new_pos))
+ return pos1;
+ else
+ return pos2;
+}
+
/* This function takes the position (including any frame) of the window and
* a proposed new position (ignoring edge resistance/snapping), and then
* applies edge resistance to EACH edge (separately) updating new_outer.
@@ -3931,7 +4074,8 @@ apply_edge_resistance (int old_pos,
*/
gboolean meta_display_apply_edge_resistance (MetaDisplay *display,
const MetaRectangle *old_outer,
- MetaRectangle *new_outer)
+ MetaRectangle *new_outer,
+ gboolean auto_snap)
{
/* FIXME: I need to know and use
* a) whether this is mouse or keyboard resize (if keyboard resize, a
@@ -3947,27 +4091,66 @@ gboolean meta_display_apply_edge_resistance (MetaDisplay *display,
g_assert (display->grab_edge_resistance_data != NULL);
edge_data = display->grab_edge_resistance_data;
- /* Now, do the edge resistance application */
- new_left = apply_edge_resistance (BOX_LEFT (*old_outer),
- BOX_LEFT (*new_outer),
- new_outer,
- edge_data->left_edges,
- TRUE);
- new_right = apply_edge_resistance (BOX_RIGHT (*old_outer),
- BOX_RIGHT (*new_outer),
- new_outer,
- edge_data->right_edges,
- TRUE);
- new_top = apply_edge_resistance (BOX_TOP (*old_outer),
- BOX_TOP (*new_outer),
- new_outer,
- edge_data->top_edges,
- FALSE);
- new_bottom = apply_edge_resistance (BOX_BOTTOM (*old_outer),
- BOX_BOTTOM (*new_outer),
- new_outer,
- edge_data->bottom_edges,
- FALSE);
+ if (auto_snap)
+ {
+ /* Do the auto snapping instead of normal edge resistance; in all
+ * cases, we allow snapping to opposite kinds of edges (e.g. left
+ * sides of windows to both left and right edges.
+ */
+
+ new_left = apply_edge_snapping (BOX_LEFT (*old_outer),
+ BOX_LEFT (*new_outer),
+ new_outer,
+ edge_data->left_edges,
+ edge_data->right_edges,
+ TRUE);
+
+ new_right = apply_edge_snapping (BOX_RIGHT (*old_outer),
+ BOX_RIGHT (*new_outer),
+ new_outer,
+ edge_data->left_edges,
+ edge_data->right_edges,
+ TRUE);
+
+ new_top = apply_edge_snapping (BOX_TOP (*old_outer),
+ BOX_TOP (*new_outer),
+ new_outer,
+ edge_data->top_edges,
+ edge_data->bottom_edges,
+ FALSE);
+
+ new_bottom = apply_edge_snapping (BOX_BOTTOM (*old_outer),
+ BOX_BOTTOM (*new_outer),
+ new_outer,
+ edge_data->top_edges,
+ edge_data->bottom_edges,
+ FALSE);
+
+ }
+ else
+ {
+ /* Now, apply the normal edge resistance */
+ new_left = apply_edge_resistance (BOX_LEFT (*old_outer),
+ BOX_LEFT (*new_outer),
+ new_outer,
+ edge_data->left_edges,
+ TRUE);
+ new_right = apply_edge_resistance (BOX_RIGHT (*old_outer),
+ BOX_RIGHT (*new_outer),
+ new_outer,
+ edge_data->right_edges,
+ TRUE);
+ new_top = apply_edge_resistance (BOX_TOP (*old_outer),
+ BOX_TOP (*new_outer),
+ new_outer,
+ edge_data->top_edges,
+ FALSE);
+ new_bottom = apply_edge_resistance (BOX_BOTTOM (*old_outer),
+ BOX_BOTTOM (*new_outer),
+ new_outer,
+ edge_data->bottom_edges,
+ FALSE);
+ }
/* Determine whether anything changed, and save the changes */
modified_rect = meta_rect (new_left,
diff --git a/src/display.h b/src/display.h
index 6a438127..74c5efe8 100644
--- a/src/display.h
+++ b/src/display.h
@@ -340,6 +340,7 @@ struct _MetaDisplay
int render_error_base;
#endif
#ifdef HAVE_XSYNC
+ unsigned int grab_last_used_state_for_resize;
unsigned int have_xsync : 1;
#define META_DISPLAY_HAS_XSYNC(display) ((display)->have_xsync)
#else
@@ -451,7 +452,8 @@ void meta_display_ungrab_focus_window_button (MetaDisplay *display,
gboolean meta_display_apply_edge_resistance (MetaDisplay *display,
const MetaRectangle *old_outer,
- MetaRectangle *new_outer);
+ MetaRectangle *new_outer,
+ gboolean auto_snap);
/* make a request to ensure the event serial has changed */
void meta_display_increment_event_serial (MetaDisplay *display);
diff --git a/src/window.c b/src/window.c
index 229dc1ed..32029905 100644
--- a/src/window.c
+++ b/src/window.c
@@ -6377,7 +6377,7 @@ update_move (MetaWindow *window,
int dx, dy;
int new_x, new_y;
int old_x, old_y;
- MetaRectangle old_outer, new_outer;
+ MetaRectangle old_outer, proposed_outer, new_outer;
int shake_threshold;
window->display->grab_latest_motion_x = x;
@@ -6495,13 +6495,15 @@ update_move (MetaWindow *window,
/* Do any edge resistance/snapping */
meta_window_get_outer_rect (window, &old_outer);
- new_outer = old_outer;
- new_outer.x += (new_x - old_x);
- new_outer.y += (new_y - old_y);
+ proposed_outer = old_outer;
+ proposed_outer.x += (new_x - old_x);
+ proposed_outer.y += (new_y - old_y);
+ new_outer = proposed_outer;
if (meta_display_apply_edge_resistance (window->display,
&old_outer,
- &new_outer))
+ &new_outer,
+ mask & ShiftMask))
{
/* meta_display_apply_edge_resistance independently applies
* resistance to both the right and left edges of new_outer as both
@@ -6509,39 +6511,35 @@ update_move (MetaWindow *window,
* just have both edges move according to the stricter of the
* resistances. Same thing goes for top & bottom edges.
*/
+ MetaRectangle *reference;
int left_change, right_change, smaller_x_change;
int top_change, bottom_change, smaller_y_change;
- left_change = BOX_LEFT (new_outer) - BOX_LEFT (old_outer);
- right_change = BOX_RIGHT (new_outer) - BOX_RIGHT (old_outer);
+ if (mask & ShiftMask)
+ reference = &proposed_outer;
+ else
+ reference = &old_outer;
+
+ left_change = BOX_LEFT (new_outer) - BOX_LEFT (*reference);
+ right_change = BOX_RIGHT (new_outer) - BOX_RIGHT (*reference);
if (ABS (left_change) < ABS (right_change))
smaller_x_change = left_change;
else
smaller_x_change = right_change;
- top_change = BOX_TOP (new_outer) - BOX_TOP (old_outer);
- bottom_change = BOX_BOTTOM (new_outer) - BOX_BOTTOM (old_outer);
+ top_change = BOX_TOP (new_outer) - BOX_TOP (*reference);
+ bottom_change = BOX_BOTTOM (new_outer) - BOX_BOTTOM (*reference);
if (ABS (top_change) < ABS (bottom_change))
smaller_y_change = top_change;
else
smaller_y_change = bottom_change;
- new_x = old_x + smaller_x_change;
- new_y = old_y + smaller_y_change;
+ new_x = old_x + smaller_x_change +
+ (BOX_LEFT (*reference) - BOX_LEFT (old_outer));
+ new_y = old_y + smaller_y_change +
+ (BOX_TOP (*reference) - BOX_TOP (old_outer));
}
-#if 0
- if (mask & ShiftMask)
- {
- /* snap to edges */
- if (new_x != old_x)
- new_x = meta_window_find_nearest_vertical_edge (window, new_x);
-
- if (new_y != old_y)
- new_y = meta_window_find_nearest_horizontal_edge (window, new_y);
- }
-#endif
-
if (window->display->grab_wireframe_active)
meta_window_update_wireframe (window, new_x, new_y,
window->display->grab_wireframe_rect.width,
@@ -6550,10 +6548,11 @@ update_move (MetaWindow *window,
meta_window_move (window, TRUE, new_x, new_y);
}
-static void update_resize (MetaWindow *window,
- int x,
- int y,
- gboolean force);
+static void update_resize (MetaWindow *window,
+ unsigned int mask,
+ int x,
+ int y,
+ gboolean force);
static gboolean
update_resize_timeout (gpointer data)
@@ -6561,14 +6560,16 @@ update_resize_timeout (gpointer data)
MetaWindow *window = data;
update_resize (window,
- window->display->grab_latest_motion_x,
- window->display->grab_latest_motion_y,
- TRUE);
+ window->display->grab_last_used_state_for_resize,
+ window->display->grab_latest_motion_x,
+ window->display->grab_latest_motion_y,
+ TRUE);
return FALSE;
}
static void
update_resize (MetaWindow *window,
+ unsigned int mask,
int x, int y,
gboolean force)
{
@@ -6768,9 +6769,11 @@ update_resize (MetaWindow *window,
new_outer_width,
new_outer_height);
+ window->display->grab_last_used_state_for_resize = mask;
if (meta_display_apply_edge_resistance (window->display,
&old_outer,
- &new_outer))
+ &new_outer,
+ mask & ShiftMask))
{
new_w = old.width + (new_outer.width - old_outer.width);
new_h = old.height + (new_outer.height - old_outer.height);
@@ -6909,6 +6912,7 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
case META_GRAB_OP_KEYBOARD_RESIZING_NW:
/* no pointer round trip here, to keep in sync */
update_resize (window,
+ window->display->grab_last_used_state_for_resize,
window->display->grab_latest_motion_x,
window->display->grab_latest_motion_y,
TRUE);
@@ -6933,9 +6937,10 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
{
if (event->xbutton.root == window->screen->xroot)
update_resize (window,
- event->xbutton.x_root,
- event->xbutton.y_root,
- TRUE);
+ event->xbutton.state,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ TRUE);
}
meta_display_end_grab_op (window->display, event->xbutton.time);
@@ -6961,9 +6966,10 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
if (check_use_this_motion_notify (window,
event))
update_resize (window,
+ event->xmotion.state,
event->xmotion.x_root,
event->xmotion.y_root,
- FALSE);
+ FALSE);
}
}
break;
@@ -6983,9 +6989,10 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
{
if (event->xcrossing.root == window->screen->xroot)
update_resize (window,
+ event->xcrossing.state,
event->xcrossing.x_root,
event->xcrossing.y_root,
- FALSE);
+ FALSE);
}
break;
#endif