From 551ec20941060a02b1d621abfd4c43731176c5d8 Mon Sep 17 00:00:00 2001 From: Albert Safin Date: Wed, 12 Dec 2018 15:35:11 +0700 Subject: [PATCH] drag_pointer(): add use_treshold parameter --- include/drag.h | 20 +++++++++++++------- src/drag.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------ src/floating.c | 10 +++------- src/resize.c | 2 +- 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/include/drag.h b/include/drag.h index 924ff98c6..2027f9349 100644 --- a/include/drag.h +++ b/include/drag.h @@ -12,12 +12,13 @@ #include /** Callback for dragging */ -typedef void (*callback_t)(Con *, Rect *, uint32_t, uint32_t, const void *); +typedef void (*callback_t)(Con *, Rect *, uint32_t, uint32_t, + const xcb_button_press_event_t *, const void *); /** Macro to create a callback function for dragging */ -#define DRAGGING_CB(name) \ - static void name(Con *con, Rect *old_rect, uint32_t new_x, \ - uint32_t new_y, const void *extra) +#define DRAGGING_CB(name) \ + static void name(Con *con, Rect *old_rect, uint32_t new_x, uint32_t new_y, \ + const xcb_button_press_event_t *event, const void *extra) /** * This is the return value of a drag operation like drag_pointer. @@ -46,10 +47,15 @@ typedef enum { * This function grabs your pointer and keyboard and lets you drag stuff around * (borders). Every time you move your mouse, an XCB_MOTION_NOTIFY event will * be received and the given callback will be called with the parameters - * specified (client, border on which the click originally was), the original - * rect of the client, the event and the new coordinates (x, y). + * specified (client, the original event), the original rect of the client, + * and the new coordinates (x, y). + * + * If use_threshold is set, dragging only starts after the user moves the + * pointer past a certain threshold. That is, the cursor will not be set and the + * callback will not be called until then. * */ drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t confine_to, int cursor, - callback_t callback, const void *extra); + bool use_threshold, callback_t callback, + const void *extra); diff --git a/src/drag.c b/src/drag.c index 57d9f9a9b..6b05311af 100644 --- a/src/drag.c +++ b/src/drag.c @@ -20,16 +20,32 @@ struct drag_x11_cb { * drag of the resize handle. */ Con *con; + /* The original event that initiated the drag. */ + const xcb_button_press_event_t *event; + /* The dimensions of con when the loop was started. */ Rect old_rect; /* The callback to invoke after every pointer movement. */ callback_t callback; + /* Drag distance threshold exceeded. If use_threshold is not set, then + * threshold_exceeded is always true. */ + bool threshold_exceeded; + + /* Cursor to set after the threshold is exceeded. */ + xcb_cursor_t xcursor; + /* User data pointer for callback. */ const void *extra; }; +static bool threshold_exceeded(uint32_t x1, uint32_t y1, + uint32_t x2, uint32_t y2) { + const uint32_t threshold = 9; + return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) > threshold * threshold; +} + static bool drain_drag_events(EV_P, struct drag_x11_cb *dragloop) { xcb_motion_notify_event_t *last_motion_notify = NULL; xcb_generic_event_t *event; @@ -105,15 +121,29 @@ static bool drain_drag_events(EV_P, struct drag_x11_cb *dragloop) { return true; } + if (!dragloop->threshold_exceeded && + threshold_exceeded(last_motion_notify->root_x, last_motion_notify->root_y, + dragloop->event->root_x, dragloop->event->root_y)) { + if (dragloop->xcursor != XCB_NONE) { + xcb_change_active_pointer_grab( + conn, + dragloop->xcursor, + XCB_CURRENT_TIME, + XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION); + } + dragloop->threshold_exceeded = true; + } + /* Ensure that we are either dragging the resize handle (con is NULL) or that the * container still exists. The latter might not be true, e.g., if the window closed * for any reason while the user was dragging it. */ - if (!dragloop->con || con_exists(dragloop->con)) { + if (dragloop->threshold_exceeded && (!dragloop->con || con_exists(dragloop->con))) { dragloop->callback( dragloop->con, &(dragloop->old_rect), last_motion_notify->root_x, last_motion_notify->root_y, + dragloop->event, dragloop->extra); } FREE(last_motion_notify); @@ -133,12 +163,18 @@ static void xcb_drag_prepare_cb(EV_P_ ev_prepare *w, int revents) { * This function grabs your pointer and keyboard and lets you drag stuff around * (borders). Every time you move your mouse, an XCB_MOTION_NOTIFY event will * be received and the given callback will be called with the parameters - * specified (client, border on which the click originally was), the original - * rect of the client, the event and the new coordinates (x, y). + * specified (client, the original event), the original rect of the client, + * and the new coordinates (x, y). + * + * If use_threshold is set, dragging only starts after the user moves the + * pointer past a certain threshold. That is, the cursor will not be set and the + * callback will not be called until then. * */ -drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t confine_to, - int cursor, callback_t callback, const void *extra) { +drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, + xcb_window_t confine_to, int cursor, + bool use_threshold, callback_t callback, + const void *extra) { xcb_cursor_t xcursor = (cursor && xcursor_supported) ? xcursor_get_cursor(cursor) : XCB_NONE; /* Grab the pointer */ @@ -153,7 +189,7 @@ drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_ XCB_GRAB_MODE_ASYNC, /* pointer events should continue as normal */ XCB_GRAB_MODE_ASYNC, /* keyboard mode */ confine_to, /* confine_to = in which window should the cursor stay */ - xcursor, /* possibly display a special cursor */ + use_threshold ? XCB_NONE : xcursor, /* possibly display a special cursor */ XCB_CURRENT_TIME); if ((reply = xcb_grab_pointer_reply(conn, cookie, &error)) == NULL) { @@ -189,7 +225,10 @@ drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_ struct drag_x11_cb loop = { .result = DRAGGING, .con = con, + .event = event, .callback = callback, + .threshold_exceeded = !use_threshold, + .xcursor = xcursor, .extra = extra, }; ev_prepare *prepare = &loop.prepare; diff --git a/src/floating.c b/src/floating.c index 6772128ae..59c8c7979 100644 --- a/src/floating.c +++ b/src/floating.c @@ -561,8 +561,6 @@ void floating_move_to_pointer(Con *con) { } DRAGGING_CB(drag_window_callback) { - const struct xcb_button_press_event_t *event = extra; - /* Reposition the client correctly while moving */ con->rect.x = old_rect->x + (new_x - event->root_x); con->rect.y = old_rect->y + (new_y - event->root_y); @@ -595,7 +593,7 @@ void floating_drag_window(Con *con, const xcb_button_press_event_t *event) { Rect initial_rect = con->rect; /* Drag the window */ - drag_result_t drag_result = drag_pointer(con, event, XCB_NONE, XCURSOR_CURSOR_MOVE, drag_window_callback, event); + drag_result_t drag_result = drag_pointer(con, event, XCB_NONE, XCURSOR_CURSOR_MOVE, false, drag_window_callback, NULL); if (!con_exists(con)) { DLOG("The container has been closed in the meantime.\n"); @@ -625,12 +623,10 @@ void floating_drag_window(Con *con, const xcb_button_press_event_t *event) { struct resize_window_callback_params { const border_t corner; const bool proportional; - const xcb_button_press_event_t *event; }; DRAGGING_CB(resize_window_callback) { const struct resize_window_callback_params *params = extra; - const xcb_button_press_event_t *event = params->event; border_t corner = params->corner; int32_t dest_x = con->rect.x; @@ -706,12 +702,12 @@ void floating_resize_window(Con *con, const bool proportional, cursor = (corner & BORDER_LEFT) ? XCURSOR_CURSOR_BOTTOM_LEFT_CORNER : XCURSOR_CURSOR_BOTTOM_RIGHT_CORNER; } - struct resize_window_callback_params params = {corner, proportional, event}; + struct resize_window_callback_params params = {corner, proportional}; /* get the initial rect in case of revert/cancel */ Rect initial_rect = con->rect; - drag_result_t drag_result = drag_pointer(con, event, XCB_NONE, cursor, resize_window_callback, ¶ms); + drag_result_t drag_result = drag_pointer(con, event, XCB_NONE, cursor, false, resize_window_callback, ¶ms); if (!con_exists(con)) { DLOG("The container has been closed in the meantime.\n"); diff --git a/src/resize.c b/src/resize.c index a63e337b9..f3c1f6781 100644 --- a/src/resize.c +++ b/src/resize.c @@ -208,7 +208,7 @@ void resize_graphical_handler(Con *first, Con *second, orientation_t orientation 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, 0, resize_callback, ¶ms); + drag_result_t drag_result = drag_pointer(NULL, event, grabwin, 0, false, resize_callback, ¶ms); xcb_destroy_window(conn, helpwin); xcb_destroy_window(conn, grabwin);