Add ability to escape out of a mouse-resize operation
Implement #1074. drag_cancel grabs the keyboard and returns DRAG_CANCEL when the user presses any key during the grab.
This commit is contained in:
parent
a49dfaf26c
commit
459490b67b
@ -134,14 +134,22 @@ void floating_toggle_hide(xcb_connection_t *conn, Workspace *workspace);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* This function grabs your pointer and lets you drag stuff around (borders).
|
* This is the return value of a drag operation like drag_pointer. DRAG_CANCEL
|
||||||
* Every time you move your mouse, an XCB_MOTION_NOTIFY event will be received
|
* will indicate the intention of the drag should not be carried out, or that
|
||||||
* and the given callback will be called with the parameters specified (client,
|
* the drag actions should be undone.
|
||||||
* border on which the click originally was), the original rect of the client,
|
|
||||||
* the event and the new coordinates (x, y).
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void drag_pointer(Con *con, const xcb_button_press_event_t *event,
|
typedef enum { DRAG_SUCCESS = 0, DRAG_CANCEL } drag_result_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event,
|
||||||
xcb_window_t confine_to, border_t border, int cursor,
|
xcb_window_t confine_to, border_t border, int cursor,
|
||||||
callback_t callback, const void *extra);
|
callback_t callback, const void *extra);
|
||||||
|
|
||||||
|
@ -441,8 +441,15 @@ void floating_drag_window(Con *con, const xcb_button_press_event_t *event) {
|
|||||||
* after the user releases the mouse button */
|
* after the user releases the mouse button */
|
||||||
tree_render();
|
tree_render();
|
||||||
|
|
||||||
|
/* Store the initial rect in case of user cancel */
|
||||||
|
Rect initial_rect = con->rect;
|
||||||
|
|
||||||
/* Drag the window */
|
/* Drag the window */
|
||||||
drag_pointer(con, event, XCB_NONE, BORDER_TOP /* irrelevant */, XCURSOR_CURSOR_MOVE, drag_window_callback, event);
|
drag_result_t drag_result = drag_pointer(con, event, XCB_NONE, BORDER_TOP /* irrelevant */, XCURSOR_CURSOR_MOVE, drag_window_callback, event);
|
||||||
|
|
||||||
|
/* If the user cancelled, undo the changes. */
|
||||||
|
if (drag_result == DRAG_CANCEL)
|
||||||
|
floating_reposition(con, initial_rect);
|
||||||
|
|
||||||
/* If this is a scratchpad window, don't auto center it from now on. */
|
/* If this is a scratchpad window, don't auto center it from now on. */
|
||||||
if (con->scratchpad_state == SCRATCHPAD_FRESH)
|
if (con->scratchpad_state == SCRATCHPAD_FRESH)
|
||||||
@ -546,7 +553,14 @@ void floating_resize_window(Con *con, const bool proportional,
|
|||||||
|
|
||||||
struct resize_window_callback_params params = { corner, proportional, event };
|
struct resize_window_callback_params params = { corner, proportional, event };
|
||||||
|
|
||||||
drag_pointer(con, event, XCB_NONE, BORDER_TOP /* irrelevant */, cursor, resize_window_callback, ¶ms);
|
/* get the initial rect in case of cancel */
|
||||||
|
Rect initial_rect = con->rect;
|
||||||
|
|
||||||
|
drag_result_t drag_result = drag_pointer(con, event, XCB_NONE, BORDER_TOP /* irrelevant */, cursor, resize_window_callback, ¶ms);
|
||||||
|
|
||||||
|
/* If the user cancels, undo the resize */
|
||||||
|
if (drag_result == DRAG_CANCEL)
|
||||||
|
floating_reposition(con, initial_rect);
|
||||||
|
|
||||||
/* If this is a scratchpad window, don't auto center it from now on. */
|
/* If this is a scratchpad window, don't auto center it from now on. */
|
||||||
if (con->scratchpad_state == SCRATCHPAD_FRESH)
|
if (con->scratchpad_state == SCRATCHPAD_FRESH)
|
||||||
@ -554,14 +568,14 @@ void floating_resize_window(Con *con, const bool proportional,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function grabs your pointer and lets you drag stuff around (borders).
|
* This function grabs your pointer and keyboard and lets you drag stuff around
|
||||||
* Every time you move your mouse, an XCB_MOTION_NOTIFY event will be received
|
* (borders). Every time you move your mouse, an XCB_MOTION_NOTIFY event will
|
||||||
* and the given callback will be called with the parameters specified (client,
|
* be received and the given callback will be called with the parameters
|
||||||
* border on which the click originally was), the original rect of the client,
|
* specified (client, border on which the click originally was), the original
|
||||||
* the event and the new coordinates (x, y).
|
* rect of the client, the event and the new coordinates (x, y).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t
|
drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t
|
||||||
confine_to, border_t border, int cursor, callback_t callback, const void *extra)
|
confine_to, border_t border, int cursor, callback_t callback, const void *extra)
|
||||||
{
|
{
|
||||||
uint32_t new_x, new_y;
|
uint32_t new_x, new_y;
|
||||||
@ -587,16 +601,37 @@ void drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t
|
|||||||
|
|
||||||
if ((reply = xcb_grab_pointer_reply(conn, cookie, NULL)) == NULL) {
|
if ((reply = xcb_grab_pointer_reply(conn, cookie, NULL)) == NULL) {
|
||||||
ELOG("Could not grab pointer\n");
|
ELOG("Could not grab pointer\n");
|
||||||
return;
|
return DRAG_CANCEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(reply);
|
free(reply);
|
||||||
|
|
||||||
|
/* Grab the keyboard */
|
||||||
|
xcb_grab_keyboard_cookie_t keyb_cookie;
|
||||||
|
xcb_grab_keyboard_reply_t *keyb_reply;
|
||||||
|
|
||||||
|
keyb_cookie = xcb_grab_keyboard(conn,
|
||||||
|
false, /* get all keyboard events */
|
||||||
|
root, /* grab the root window */
|
||||||
|
XCB_CURRENT_TIME,
|
||||||
|
XCB_GRAB_MODE_ASYNC, /* continue processing pointer events as normal */
|
||||||
|
XCB_GRAB_MODE_ASYNC /* keyboard mode */
|
||||||
|
);
|
||||||
|
|
||||||
|
if ((keyb_reply = xcb_grab_keyboard_reply(conn, keyb_cookie, NULL)) == NULL) {
|
||||||
|
ELOG("Could not grab keyboard\n");
|
||||||
|
return DRAG_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(keyb_reply);
|
||||||
|
|
||||||
/* Go into our own event loop */
|
/* Go into our own event loop */
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
xcb_generic_event_t *inside_event, *last_motion_notify = NULL;
|
xcb_generic_event_t *inside_event, *last_motion_notify = NULL;
|
||||||
bool loop_done = false;
|
bool loop_done = false;
|
||||||
|
/* The return value, set to DRAG_CANCEL on user cancel */
|
||||||
|
drag_result_t drag_result = DRAG_SUCCESS;
|
||||||
/* I’ve always wanted to have my own eventhandler… */
|
/* I’ve always wanted to have my own eventhandler… */
|
||||||
while (!loop_done && (inside_event = xcb_wait_for_event(conn))) {
|
while (!loop_done && (inside_event = xcb_wait_for_event(conn))) {
|
||||||
/* We now handle all events we can get using xcb_poll_for_event */
|
/* We now handle all events we can get using xcb_poll_for_event */
|
||||||
@ -621,11 +656,20 @@ void drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case XCB_UNMAP_NOTIFY:
|
case XCB_UNMAP_NOTIFY:
|
||||||
case XCB_KEY_PRESS:
|
|
||||||
case XCB_KEY_RELEASE:
|
|
||||||
DLOG("Unmap-notify, aborting\n");
|
DLOG("Unmap-notify, aborting\n");
|
||||||
handle_event(type, inside_event);
|
handle_event(type, inside_event);
|
||||||
loop_done = true;
|
loop_done = true;
|
||||||
|
drag_result = DRAG_CANCEL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_KEY_PRESS:
|
||||||
|
case XCB_KEY_RELEASE:
|
||||||
|
/* Cancel the drag if a key was pressed */
|
||||||
|
DLOG("A key was pressed during drag, canceling.");
|
||||||
|
loop_done = true;
|
||||||
|
drag_result = DRAG_CANCEL;
|
||||||
|
|
||||||
|
handle_event(type, inside_event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -648,8 +692,12 @@ void drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t
|
|||||||
FREE(last_motion_notify);
|
FREE(last_motion_notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xcb_ungrab_keyboard(conn, XCB_CURRENT_TIME);
|
||||||
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
|
return drag_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -154,12 +154,16 @@ int resize_graphical_handler(Con *first, Con *second, orientation_t orientation,
|
|||||||
|
|
||||||
const struct callback_params params = { orientation, output, helpwin, &new_position };
|
const struct callback_params params = { orientation, output, helpwin, &new_position };
|
||||||
|
|
||||||
drag_pointer(NULL, event, grabwin, BORDER_TOP, 0, resize_callback, ¶ms);
|
drag_result_t drag_result = drag_pointer(NULL, event, grabwin, BORDER_TOP, 0, resize_callback, ¶ms);
|
||||||
|
|
||||||
xcb_destroy_window(conn, helpwin);
|
xcb_destroy_window(conn, helpwin);
|
||||||
xcb_destroy_window(conn, grabwin);
|
xcb_destroy_window(conn, grabwin);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
|
/* User cancelled the drag so no action should be taken. */
|
||||||
|
if (drag_result == DRAG_CANCEL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
int pixels;
|
int pixels;
|
||||||
if (orientation == HORIZ)
|
if (orientation == HORIZ)
|
||||||
pixels = (new_position - event->root_x);
|
pixels = (new_position - event->root_x);
|
||||||
|
Loading…
Reference in New Issue
Block a user