]> git.sur5r.net Git - i3/i3/commitdiff
Snap pointer to resize bar on drag resize
authorTony Crisci <tony@dubstepdish.com>
Sat, 21 Dec 2013 19:29:22 +0000 (14:29 -0500)
committerMichael Stapelberg <michael@stapelberg.de>
Wed, 1 Jan 2014 14:18:54 +0000 (15:18 +0100)
When the user initiates a drag resize, draw the resize bar on the border
of the two involved containers and snap the pointer.

This solution produces cleaner code than the former approach where the
caller obfuscated the click coordinates of the event. This may confuse
someone expecting a true button press event.

Fixes an issue where the resize cursor is not shown when the resize bar
is clicked until the user begins to drag the mouse.

Fixes an issue where focus is not properly updated after the drag is
complete when `focus_follows_mouse' option is set, leaving the pointer
in an unfocused window in some cases.

Fixes an issue where the resize bar may jump a few pixels when the mouse
is first moved.

(Thanks to pbos for suggesting this fix and providing an example
implementation)

src/click.c
src/resize.c

index 340c8414696040313fc30d4231d61580c6e90a11..a517838a9a02f42ba900a60cdf6eab4908375ab2 100644 (file)
@@ -62,12 +62,7 @@ static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press
         second = tmp;
     }
 
-    /* We modify the X/Y position in the event so that the divider line is at
-     * the actual position of the border, not at the position of the click. */
     const orientation_t orientation = ((border == BORDER_LEFT || border == BORDER_RIGHT) ? HORIZ : VERT);
-    if (orientation == HORIZ)
-        event->root_x = second->rect.x;
-    else event->root_y = second->rect.y;
 
     resize_graphical_handler(first, second, orientation, event);
 
index cc4ba841f8b34377d353ad4eea46787dca3be4dd..bacadf2efe6ced1092f110518d314882d11a7e93 100644 (file)
@@ -102,8 +102,6 @@ bool resize_find_tiling_participants(Con **current, Con **other, direction_t dir
 int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) {
     DLOG("resize handler\n");
 
-    uint32_t new_position;
-
     /* TODO: previously, we were getting a rect containing all screens. why? */
     Con *output = con_get_output(first);
     DLOG("x = %d, width = %d\n", output->rect.x, output->rect.width);
@@ -122,19 +120,29 @@ int resize_graphical_handler(Con *first, Con *second, orientation_t orientation,
     xcb_window_t grabwin = create_window(conn, output->rect, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT,
             XCB_WINDOW_CLASS_INPUT_ONLY, XCURSOR_CURSOR_POINTER, true, mask, values);
 
+    /* Keep track of the coordinate orthogonal to motion so we can determine
+     * the length of the resize afterward. */
+    uint32_t initial_position, new_position;
+
+    /* Configure the resizebar and snap the pointer. The resizebar runs along
+     * the rect of the second con and follows the motion of the pointer. */
     Rect helprect;
     if (orientation == HORIZ) {
-        helprect.x = event->root_x;
+        helprect.x = second->rect.x;
         helprect.y = output->rect.y;
         helprect.width = 2;
         helprect.height = output->rect.height;
-        new_position = event->root_x;
+        initial_position = second->rect.x;
+        xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0,
+                second->rect.x, event->root_y);
     } else {
         helprect.x = output->rect.x;
-        helprect.y = event->root_y;
+        helprect.y = second->rect.y;
         helprect.width = output->rect.width;
         helprect.height = 2;
-        new_position = event->root_y;
+        initial_position = second->rect.y;
+        xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0,
+                event->root_x, second->rect.y);
     }
 
     mask = XCB_CW_BACK_PIXEL;
@@ -152,8 +160,12 @@ int resize_graphical_handler(Con *first, Con *second, orientation_t orientation,
 
     xcb_flush(conn);
 
+    /* `new_position' will be updated by the `resize_callback'. */
+    new_position = initial_position;
+
     const struct callback_params params = { orientation, output, helpwin, &new_position };
 
+    /* `drag_pointer' blocks until the drag is completed. */
     drag_result_t drag_result = drag_pointer(NULL, event, grabwin, BORDER_TOP, 0, resize_callback, &params);
 
     xcb_destroy_window(conn, helpwin);
@@ -164,10 +176,7 @@ int resize_graphical_handler(Con *first, Con *second, orientation_t orientation,
     if (drag_result == DRAG_REVERT)
         return 0;
 
-    int pixels;
-    if (orientation == HORIZ)
-        pixels = (new_position - event->root_x);
-    else pixels = (new_position - event->root_y);
+    int pixels = (new_position - initial_position);
 
     DLOG("Done, pixels = %d\n", pixels);