diff --git a/include/resize.h b/include/resize.h index 162d8f6ba..5439fab54 100644 --- a/include/resize.h +++ b/include/resize.h @@ -13,7 +13,9 @@ bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction, bool both_sides); -void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event); +void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, + const xcb_button_press_event_t *event, + bool use_threshold); /** * Resize the two given containers using the given amount of pixels or diff --git a/src/click.c b/src/click.c index 4fcc22ec1..8ab5c5f06 100644 --- a/src/click.c +++ b/src/click.c @@ -26,7 +26,7 @@ typedef enum { CLICK_BORDER = 0, * then calls resize_graphical_handler(). * */ -static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press_event_t *event) { +static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press_event_t *event, bool use_threshold) { DLOG("border = %d, con = %p\n", border, con); Con *second = NULL; Con *first = con; @@ -64,7 +64,7 @@ static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press const orientation_t orientation = ((border == BORDER_LEFT || border == BORDER_RIGHT) ? HORIZ : VERT); - resize_graphical_handler(first, second, orientation, event); + resize_graphical_handler(first, second, orientation, event, use_threshold); DLOG("After resize handler, rendering\n"); tree_render(); @@ -94,22 +94,22 @@ static bool floating_mod_on_tiled_client(Con *con, xcb_button_press_event_t *eve if (to_right < to_left && to_right < to_top && to_right < to_bottom) - return tiling_resize_for_border(con, BORDER_RIGHT, event); + return tiling_resize_for_border(con, BORDER_RIGHT, event, false); if (to_left < to_right && to_left < to_top && to_left < to_bottom) - return tiling_resize_for_border(con, BORDER_LEFT, event); + return tiling_resize_for_border(con, BORDER_LEFT, event, false); if (to_top < to_right && to_top < to_left && to_top < to_bottom) - return tiling_resize_for_border(con, BORDER_TOP, event); + return tiling_resize_for_border(con, BORDER_TOP, event, false); if (to_bottom < to_right && to_bottom < to_left && to_bottom < to_top) - return tiling_resize_for_border(con, BORDER_BOTTOM, event); + return tiling_resize_for_border(con, BORDER_BOTTOM, event, false); return false; } @@ -118,45 +118,26 @@ static bool floating_mod_on_tiled_client(Con *con, xcb_button_press_event_t *eve * Finds out which border was clicked on and calls tiling_resize_for_border(). * */ -static bool tiling_resize(Con *con, xcb_button_press_event_t *event, const click_destination_t dest) { +static bool tiling_resize(Con *con, xcb_button_press_event_t *event, const click_destination_t dest, bool use_threshold) { /* check if this was a click on the window border (and on which one) */ Rect bsr = con_border_style_rect(con); DLOG("BORDER x = %d, y = %d for con %p, window 0x%08x\n", event->event_x, event->event_y, con, event->event); DLOG("checks for right >= %d\n", con->window_rect.x + con->window_rect.width); if (dest == CLICK_DECORATION) { - /* The user clicked on a window decoration. We ignore the following case: - * The container is a h-split, tabbed or stacked container with > 1 - * window. Decorations will end up next to each other and the user - * expects to switch to a window by clicking on its decoration. */ - - /* Since the container might either be the child *or* already a split - * container (in the case of a nested split container), we need to make - * sure that we are dealing with the split container here. */ - Con *check_con = con; - if (con_is_leaf(check_con) && check_con->parent->type == CT_CON) - check_con = check_con->parent; - - if ((check_con->layout == L_STACKED || - check_con->layout == L_TABBED || - con_orientation(check_con) == HORIZ) && - con_num_children(check_con) > 1) { - DLOG("Not handling this resize, this container has > 1 child.\n"); - return false; - } - return tiling_resize_for_border(con, BORDER_TOP, event); + return tiling_resize_for_border(con, BORDER_TOP, event, use_threshold); } if (event->event_x >= 0 && event->event_x <= (int32_t)bsr.x && event->event_y >= (int32_t)bsr.y && event->event_y <= (int32_t)(con->rect.height + bsr.height)) - return tiling_resize_for_border(con, BORDER_LEFT, event); + return tiling_resize_for_border(con, BORDER_LEFT, event, false); if (event->event_x >= (int32_t)(con->window_rect.x + con->window_rect.width) && event->event_y >= (int32_t)bsr.y && event->event_y <= (int32_t)(con->rect.height + bsr.height)) - return tiling_resize_for_border(con, BORDER_RIGHT, event); + return tiling_resize_for_border(con, BORDER_RIGHT, event, false); if (event->event_y >= (int32_t)(con->window_rect.y + con->window_rect.height)) - return tiling_resize_for_border(con, BORDER_BOTTOM, event); + return tiling_resize_for_border(con, BORDER_BOTTOM, event, false); return false; } @@ -276,7 +257,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod is_left_or_right_click) { /* try tiling resize, but continue if it doesn’t work */ DLOG("tiling resize with fallback\n"); - if (tiling_resize(con, event, dest)) + if (tiling_resize(con, event, dest, !was_focused)) goto done; } @@ -311,7 +292,11 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod else if ((dest == CLICK_BORDER || dest == CLICK_DECORATION) && is_left_or_right_click) { DLOG("Trying to resize (tiling)\n"); - tiling_resize(con, event, dest); + /* Since we updated the tree (con_activate() above), we need to + * re-render the tree before returning to the event loop (drag_pointer() + * inside tiling_resize() runs its own event-loop). */ + tree_render(); + tiling_resize(con, event, dest, dest == CLICK_DECORATION && !was_focused); } done: diff --git a/src/resize.c b/src/resize.c index f3c1f6781..97a0f946b 100644 --- a/src/resize.c +++ b/src/resize.c @@ -21,12 +21,32 @@ struct callback_params { Con *output; xcb_window_t helpwin; uint32_t *new_position; + bool *threshold_exceeded; }; DRAGGING_CB(resize_callback) { const struct callback_params *params = extra; Con *output = params->output; DLOG("new x = %d, y = %d\n", new_x, new_y); + + if (!*params->threshold_exceeded) { + xcb_map_window(conn, params->helpwin); + /* Warp pointer in the same way as resize_graphical_handler() would do + * if threshold wasn't enabled, but also take into account travelled + * distance. */ + if (params->orientation == HORIZ) { + xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, + *params->new_position + new_x - event->root_x, + new_y); + } else { + xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, + new_x, + *params->new_position + new_y - event->root_y); + } + *params->threshold_exceeded = true; + return; + } + if (params->orientation == HORIZ) { /* Check if the new coordinates are within screen boundaries */ if (new_x > (output->rect.x + output->rect.width - 25) || @@ -148,7 +168,9 @@ bool resize_neighboring_cons(Con *first, Con *second, int px, int ppt) { return true; } -void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) { +void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, + const xcb_button_press_event_t *event, + bool use_threshold) { Con *output = con_get_output(first); DLOG("x = %d, width = %d\n", output->rect.x, output->rect.width); @@ -179,14 +201,10 @@ void resize_graphical_handler(Con *first, Con *second, orientation_t orientation helprect.width = logical_px(2); helprect.height = second->rect.height; 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.width = second->rect.width; helprect.height = logical_px(2); 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; @@ -196,7 +214,18 @@ void resize_graphical_handler(Con *first, Con *second, orientation_t orientation values[1] = 1; xcb_window_t helpwin = create_window(conn, helprect, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, - XCB_WINDOW_CLASS_INPUT_OUTPUT, (orientation == HORIZ ? XCURSOR_CURSOR_RESIZE_HORIZONTAL : XCURSOR_CURSOR_RESIZE_VERTICAL), true, mask, values); + XCB_WINDOW_CLASS_INPUT_OUTPUT, (orientation == HORIZ ? XCURSOR_CURSOR_RESIZE_HORIZONTAL : XCURSOR_CURSOR_RESIZE_VERTICAL), false, mask, values); + + if (!use_threshold) { + xcb_map_window(conn, helpwin); + if (orientation == HORIZ) { + xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, + second->rect.x, event->root_y); + } else { + xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, + event->root_x, second->rect.y); + } + } xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, helpwin); @@ -205,10 +234,12 @@ void resize_graphical_handler(Con *first, Con *second, orientation_t orientation /* `new_position' will be updated by the `resize_callback'. */ new_position = initial_position; - const struct callback_params params = {orientation, output, helpwin, &new_position}; + bool threshold_exceeded = !use_threshold; + + const struct callback_params params = {orientation, output, helpwin, &new_position, &threshold_exceeded}; /* `drag_pointer' blocks until the drag is completed. */ - drag_result_t drag_result = drag_pointer(NULL, event, grabwin, 0, false, resize_callback, ¶ms); + drag_result_t drag_result = drag_pointer(NULL, event, grabwin, 0, use_threshold, resize_callback, ¶ms); xcb_destroy_window(conn, helpwin); xcb_destroy_window(conn, grabwin);