From 9fbe13b9be18c732b58033a57a22a299af91a170 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 18 Jul 2018 16:13:28 +1000 Subject: Implement floating_modifier and mouse operations for floating views This implements the following: * `floating_modifier` configuration directive * Drag a floating window by its title bar * Hold mod + drag a floating window from anywhere * Resize a floating view by dragging the border * Resize a floating view by holding mod and right clicking anywhere on the view * Resize a floating view and keep aspect ratio by holding shift while resizing using either method * Mouse cursor turns into resize when hovering floating border or corner --- include/sway/input/seat.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'include/sway/input') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index eac1626b..be1f3610 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -34,6 +34,8 @@ struct sway_drag_icon { struct wl_listener destroy; }; +enum resize_edge; + struct sway_seat { struct wlr_seat *wlr_seat; struct sway_cursor *cursor; @@ -52,6 +54,20 @@ struct sway_seat { int32_t touch_id; double touch_x, touch_y; + // Operations (drag and resize) + enum { + OP_NONE, + OP_DRAG, + OP_RESIZE, + } operation; + struct sway_container *op_container; + enum resize_edge op_resize_edge; + uint32_t op_button; + bool op_resize_preserve_ratio; + double op_ref_lx, op_ref_ly; // cursor's x/y at start of op + double op_ref_width, op_ref_height; // container's size at start of op + double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op + struct wl_listener focus_destroy; struct wl_listener new_container; struct wl_listener new_drag_icon; -- cgit v1.2.3 From ff445cc85597ee6bfae01f03d3c246e2326f3981 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 20 Jul 2018 09:28:22 +1000 Subject: Implement xdg shell request_move and request_resize events Also does a few other related things: * Now uses enum wlr_edges instead of our own enum resize_edge * Now uses wlr_xcursor_get_resize_name and removes our own find_resize_edge_name * Renames drag to move for consistency --- include/sway/input/seat.h | 13 ++++-- sway/desktop/xdg_shell.c | 33 +++++++++++++++ sway/desktop/xdg_shell_v6.c | 33 +++++++++++++++ sway/input/cursor.c | 100 ++++++++++++++------------------------------ sway/input/seat.c | 38 +++++++++++++++++ 5 files changed, 144 insertions(+), 73 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index be1f3610..35a965ee 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -3,6 +3,7 @@ #include #include +#include #include "sway/input/input-manager.h" struct sway_seat_device { @@ -34,8 +35,6 @@ struct sway_drag_icon { struct wl_listener destroy; }; -enum resize_edge; - struct sway_seat { struct wlr_seat *wlr_seat; struct sway_cursor *cursor; @@ -57,11 +56,12 @@ struct sway_seat { // Operations (drag and resize) enum { OP_NONE, - OP_DRAG, + OP_MOVE, OP_RESIZE, } operation; + struct sway_container *op_container; - enum resize_edge op_resize_edge; + enum wlr_edges op_resize_edge; uint32_t op_button; bool op_resize_preserve_ratio; double op_ref_lx, op_ref_ly; // cursor's x/y at start of op @@ -150,4 +150,9 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); void drag_icon_update_position(struct sway_drag_icon *icon); +void seat_begin_move(struct sway_seat *seat, struct sway_container *con); + +void seat_begin_resize(struct sway_seat *seat, struct sway_container *con, + uint32_t button, enum wlr_edges edge); + #endif diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 98c16faf..d6c3a9a7 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -1,4 +1,9 @@ #define _POSIX_C_SOURCE 199309L +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include #include @@ -248,6 +253,24 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) transaction_commit_dirty(); } +static void handle_request_move(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_view *xdg_shell_view = + wl_container_of(listener, xdg_shell_view, request_move); + struct sway_view *view = &xdg_shell_view->view; + struct wlr_xdg_toplevel_move_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_move(seat, view->swayc); +} + +static void handle_request_resize(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_view *xdg_shell_view = + wl_container_of(listener, xdg_shell_view, request_resize); + struct sway_view *view = &xdg_shell_view->view; + struct wlr_xdg_toplevel_resize_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); +} + static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, unmap); @@ -262,6 +285,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->new_popup.link); wl_list_remove(&xdg_shell_view->request_fullscreen.link); + wl_list_remove(&xdg_shell_view->request_move.link); + wl_list_remove(&xdg_shell_view->request_resize.link); } static void handle_map(struct wl_listener *listener, void *data) { @@ -299,6 +324,14 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); + + xdg_shell_view->request_move.notify = handle_request_move; + wl_signal_add(&xdg_surface->toplevel->events.request_move, + &xdg_shell_view->request_move); + + xdg_shell_view->request_resize.notify = handle_request_resize; + wl_signal_add(&xdg_surface->toplevel->events.request_resize, + &xdg_shell_view->request_resize); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 4d76f0a7..241bd9b0 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -1,4 +1,9 @@ #define _POSIX_C_SOURCE 199309L +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include #include @@ -243,6 +248,24 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) transaction_commit_dirty(); } +static void handle_request_move(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, request_move); + struct sway_view *view = &xdg_shell_v6_view->view; + struct wlr_xdg_toplevel_v6_move_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_move(seat, view->swayc); +} + +static void handle_request_resize(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, request_resize); + struct sway_view *view = &xdg_shell_v6_view->view; + struct wlr_xdg_toplevel_v6_resize_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); +} + static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, unmap); @@ -257,6 +280,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_v6_view->commit.link); wl_list_remove(&xdg_shell_v6_view->new_popup.link); wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link); + wl_list_remove(&xdg_shell_v6_view->request_move.link); + wl_list_remove(&xdg_shell_v6_view->request_resize.link); } static void handle_map(struct wl_listener *listener, void *data) { @@ -294,6 +319,14 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_v6_view->request_fullscreen); + + xdg_shell_v6_view->request_move.notify = handle_request_move; + wl_signal_add(&xdg_surface->toplevel->events.request_move, + &xdg_shell_v6_view->request_move); + + xdg_shell_v6_view->request_resize.notify = handle_request_resize; + wl_signal_add(&xdg_surface->toplevel->events.request_resize, + &xdg_shell_v6_view->request_resize); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 8723e2b4..8b9208c6 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -143,33 +143,33 @@ static struct sway_container *container_at_coords( return output->swayc; } -static enum resize_edge find_resize_edge(struct sway_container *cont, +static enum wlr_edges find_resize_edge(struct sway_container *cont, struct sway_cursor *cursor) { if (cont->type != C_VIEW) { - return RESIZE_EDGE_NONE; + return WLR_EDGE_NONE; } struct sway_view *view = cont->sway_view; if (view->border == B_NONE || !view->border_thickness || view->using_csd) { - return RESIZE_EDGE_NONE; + return WLR_EDGE_NONE; } - enum resize_edge edge = 0; + enum wlr_edges edge = 0; if (cursor->cursor->x < cont->x + view->border_thickness) { - edge |= RESIZE_EDGE_LEFT; + edge |= WLR_EDGE_LEFT; } if (cursor->cursor->y < cont->y + view->border_thickness) { - edge |= RESIZE_EDGE_TOP; + edge |= WLR_EDGE_TOP; } if (cursor->cursor->x >= cont->x + cont->width - view->border_thickness) { - edge |= RESIZE_EDGE_RIGHT; + edge |= WLR_EDGE_RIGHT; } if (cursor->cursor->y >= cont->y + cont->height - view->border_thickness) { - edge |= RESIZE_EDGE_BOTTOM; + edge |= WLR_EDGE_BOTTOM; } return edge; } -static void handle_drag_motion(struct sway_seat *seat, +static void handle_move_motion(struct sway_seat *seat, struct sway_cursor *cursor) { struct sway_container *con = seat->op_container; desktop_damage_whole_container(con); @@ -218,22 +218,22 @@ static void calculate_floating_constraints(struct sway_container *con, static void handle_resize_motion(struct sway_seat *seat, struct sway_cursor *cursor) { struct sway_container *con = seat->op_container; - enum resize_edge edge = seat->op_resize_edge; + enum wlr_edges edge = seat->op_resize_edge; // The amount the mouse has moved since the start of the resize operation // Positive is down/right double mouse_move_x = cursor->cursor->x - seat->op_ref_lx; double mouse_move_y = cursor->cursor->y - seat->op_ref_ly; - if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { + if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) { mouse_move_x = 0; } - if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { + if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) { mouse_move_y = 0; } - double grow_width = edge & RESIZE_EDGE_LEFT ? -mouse_move_x : mouse_move_x; - double grow_height = edge & RESIZE_EDGE_TOP ? -mouse_move_y : mouse_move_y; + double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x; + double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y; if (seat->op_resize_preserve_ratio) { double x_multiplier = grow_width / seat->op_ref_width; @@ -259,16 +259,16 @@ static void handle_resize_motion(struct sway_seat *seat, // Determine grow x/y values - these are relative to the container's x/y at // the start of the resize operation. double grow_x = 0, grow_y = 0; - if (edge & RESIZE_EDGE_LEFT) { + if (edge & WLR_EDGE_LEFT) { grow_x = -grow_width; - } else if (edge & RESIZE_EDGE_RIGHT) { + } else if (edge & WLR_EDGE_RIGHT) { grow_x = 0; } else { grow_x = -grow_width / 2; } - if (edge & RESIZE_EDGE_TOP) { + if (edge & WLR_EDGE_TOP) { grow_y = -grow_height; - } else if (edge & RESIZE_EDGE_BOTTOM) { + } else if (edge & WLR_EDGE_BOTTOM) { grow_y = 0; } else { grow_y = -grow_height / 2; @@ -299,31 +299,6 @@ static void handle_resize_motion(struct sway_seat *seat, transaction_commit_dirty(); } -static const char *edge_to_image_name(enum resize_edge edge) { - switch (edge) { - case RESIZE_EDGE_NONE: - return "left_ptr"; - case RESIZE_EDGE_TOP: - return "top_side"; - case RESIZE_EDGE_RIGHT: - return "right_side"; - case RESIZE_EDGE_BOTTOM: - return "bottom_side"; - case RESIZE_EDGE_LEFT: - return "left_side"; - } - if (edge == (RESIZE_EDGE_TOP | RESIZE_EDGE_LEFT)) { - return "top_left_corner"; - } else if (edge == (RESIZE_EDGE_TOP | RESIZE_EDGE_RIGHT)) { - return "top_right_corner"; - } else if (edge == (RESIZE_EDGE_BOTTOM | RESIZE_EDGE_LEFT)) { - return "bottom_left_corner"; - } else if (edge == (RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT)) { - return "bottom_right_corner"; - } - return "left_ptr"; -} - void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, bool allow_refocusing) { if (time_msec == 0) { @@ -333,8 +308,8 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, struct sway_seat *seat = cursor->seat; if (seat->operation != OP_NONE) { - if (seat->operation == OP_DRAG) { - handle_drag_motion(seat, cursor); + if (seat->operation == OP_MOVE) { + handle_move_motion(seat, cursor); } else { handle_resize_motion(seat, cursor); } @@ -402,8 +377,9 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, } } else if (c && container_is_floating(c)) { // Try a floating container's resize edge - enum resize_edge edge = find_resize_edge(c, cursor); - const char *image = edge_to_image_name(edge); + enum wlr_edges edge = find_resize_edge(c, cursor); + const char *image = edge == WLR_EDGE_NONE ? + "left_ptr" : wlr_xcursor_get_resize_name(edge); wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, cursor->cursor); cursor->image_client = NULL; @@ -452,7 +428,7 @@ static void handle_cursor_motion_absolute( } static void handle_end_operation(struct sway_seat *seat) { - if (seat->operation == OP_DRAG) { + if (seat->operation == OP_MOVE) { // We "move" the container to its own location so it discovers its // output again. struct sway_container *con = seat->op_container; @@ -472,7 +448,7 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, struct sway_container *cont) { struct sway_seat *seat = cursor->seat; - // Deny dragging or resizing a fullscreen view + // Deny moving or resizing a fullscreen view if (cont->type == C_VIEW && cont->sway_view->is_fullscreen) { wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state); return; @@ -481,36 +457,22 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); bool mod_pressed = keyboard && (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); - enum resize_edge edge = find_resize_edge(cont, cursor); - bool over_title = edge == RESIZE_EDGE_NONE && !surface; + enum wlr_edges edge = find_resize_edge(cont, cursor); + bool over_title = edge == WLR_EDGE_NONE && !surface; - // Check for beginning drag + // Check for beginning move if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED && (mod_pressed || over_title)) { - seat->operation = OP_DRAG; - seat->op_container = cont; - seat->op_button = button; + seat_begin_move(seat, cont); return; } // Check for beginning resize - bool resizing_via_border = button == BTN_LEFT && edge != RESIZE_EDGE_NONE; + bool resizing_via_border = button == BTN_LEFT && edge != WLR_EDGE_NONE; bool resizing_via_mod = button == BTN_RIGHT && mod_pressed; if ((resizing_via_border || resizing_via_mod) && state == WLR_BUTTON_PRESSED) { - seat->operation = OP_RESIZE; - seat->op_container = cont; - seat->op_resize_preserve_ratio = keyboard && - (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); - seat->op_resize_edge = resizing_via_mod ? - RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT : edge; - seat->op_button = button; - seat->op_ref_lx = cursor->cursor->x; - seat->op_ref_ly = cursor->cursor->y; - seat->op_ref_con_lx = cont->x; - seat->op_ref_con_ly = cont->y; - seat->op_ref_width = cont->width; - seat->op_ref_height = cont->height; + seat_begin_resize(seat, cont, button, edge); return; } diff --git a/sway/input/seat.c b/sway/input/seat.c index e77d88a8..cc5b2e0f 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1,6 +1,11 @@ #define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 199309L #include +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include #include @@ -348,6 +353,7 @@ struct sway_seat *seat_create(struct sway_input_manager *input, free(seat); return NULL; } + seat->wlr_seat->data = seat; seat->cursor = sway_cursor_create(seat); if (!seat->cursor) { @@ -894,3 +900,35 @@ struct seat_config *seat_get_config(struct sway_seat *seat) { return NULL; } + +void seat_begin_move(struct sway_seat *seat, struct sway_container *con) { + if (!seat->cursor) { + wlr_log(WLR_DEBUG, "Ignoring move request due to no cursor device"); + return; + } + seat->operation = OP_MOVE; + seat->op_container = con; + seat->op_button = BTN_LEFT; +} + +void seat_begin_resize(struct sway_seat *seat, struct sway_container *con, + uint32_t button, enum wlr_edges edge) { + if (!seat->cursor) { + wlr_log(WLR_DEBUG, "Ignoring resize request due to no cursor device"); + return; + } + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); + seat->operation = OP_RESIZE; + seat->op_container = con; + seat->op_resize_preserve_ratio = keyboard && + (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); + seat->op_resize_edge = edge == WLR_EDGE_NONE ? + RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT : edge; + seat->op_button = button; + seat->op_ref_lx = seat->cursor->cursor->x; + seat->op_ref_ly = seat->cursor->cursor->y; + seat->op_ref_con_lx = con->x; + seat->op_ref_con_ly = con->y; + seat->op_ref_width = con->width; + seat->op_ref_height = con->height; +} -- cgit v1.2.3 From 0c87bff5d1ce686afdc25d37eee4bdd8f08abdd3 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 21 Jul 2018 10:40:12 +1000 Subject: Replace static handle_end_operation with seat_end_mouse_operation --- include/sway/input/seat.h | 2 ++ sway/input/cursor.c | 17 +---------------- sway/input/seat.c | 19 +++++++++++++++++++ sway/tree/container.c | 3 +-- 4 files changed, 23 insertions(+), 18 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 35a965ee..cd36ef5a 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -155,4 +155,6 @@ void seat_begin_move(struct sway_seat *seat, struct sway_container *con); void seat_begin_resize(struct sway_seat *seat, struct sway_container *con, uint32_t button, enum wlr_edges edge); +void seat_end_mouse_operation(struct sway_seat *seat); + #endif diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 8b9208c6..ec83746e 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -427,21 +427,6 @@ static void handle_cursor_motion_absolute( transaction_commit_dirty(); } -static void handle_end_operation(struct sway_seat *seat) { - if (seat->operation == OP_MOVE) { - // We "move" the container to its own location so it discovers its - // output again. - struct sway_container *con = seat->op_container; - container_floating_move_to(con, con->x, con->y); - seat->operation = OP_NONE; - seat->op_container = NULL; - } else { - // OP_RESIZE - seat->operation = OP_NONE; - seat->op_container = NULL; - } -} - static void dispatch_cursor_button_floating(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state, struct wlr_surface *surface, double sx, double sy, @@ -484,7 +469,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state) { if (cursor->seat->operation != OP_NONE && button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) { - handle_end_operation(cursor->seat); + seat_end_mouse_operation(cursor->seat); return; } if (time_msec == 0) { diff --git a/sway/input/seat.c b/sway/input/seat.c index cc5b2e0f..3a3350e1 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -932,3 +932,22 @@ void seat_begin_resize(struct sway_seat *seat, struct sway_container *con, seat->op_ref_width = con->width; seat->op_ref_height = con->height; } + +void seat_end_mouse_operation(struct sway_seat *seat) { + switch (seat->operation) { + case OP_MOVE: + { + // We "move" the container to its own location so it discovers its + // output again. + struct sway_container *con = seat->op_container; + container_floating_move_to(con, con->x, con->y); + } + case OP_RESIZE: + // Don't need to do anything here. + break; + case OP_NONE: + break; + } + seat->operation = OP_NONE; + seat->op_container = NULL; +} diff --git a/sway/tree/container.c b/sway/tree/container.c index ba4af352..42c1d024 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1114,8 +1114,7 @@ void container_end_mouse_operation(struct sway_container *container) { struct sway_seat *seat; wl_list_for_each(seat, &input_manager->seats, link) { if (seat->op_container == container) { - seat->op_container = NULL; - seat->operation = OP_NONE; + seat_end_mouse_operation(seat); } } } -- cgit v1.2.3 From 6767d8a593723a9b69d018eed13d24a789be9516 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 21 Jul 2018 10:57:14 +1000 Subject: Prevent re-uploading the same cursor image multiple times --- include/sway/input/cursor.h | 4 ++++ sway/input/cursor.c | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 5dd109ca..b0a3a7c5 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -11,6 +11,7 @@ struct sway_cursor { } previous; struct wlr_xcursor_manager *xcursor_manager; + const char *image; struct wl_client *image_client; struct wl_listener motion; @@ -37,4 +38,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state); +void cursor_set_image(struct sway_cursor *cursor, const char *image, + struct wl_client *client); + #endif diff --git a/sway/input/cursor.c b/sway/input/cursor.c index ec83746e..43721d28 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -371,22 +371,16 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, // Reset cursor if switching between clients struct wl_client *client = wl_resource_get_client(surface->resource); if (client != cursor->image_client) { - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - "left_ptr", cursor->cursor); - cursor->image_client = client; + cursor_set_image(cursor, "left_ptr", client); } } else if (c && container_is_floating(c)) { // Try a floating container's resize edge enum wlr_edges edge = find_resize_edge(c, cursor); const char *image = edge == WLR_EDGE_NONE ? "left_ptr" : wlr_xcursor_get_resize_name(edge); - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, - cursor->cursor); - cursor->image_client = NULL; + cursor_set_image(cursor, image, NULL); } else { - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - "left_ptr", cursor->cursor); - cursor->image_client = NULL; + cursor_set_image(cursor, "left_ptr", NULL); } // send pointer enter/leave @@ -725,6 +719,16 @@ static void handle_request_set_cursor(struct wl_listener *listener, cursor->image_client = focused_client; } +void cursor_set_image(struct sway_cursor *cursor, const char *image, + struct wl_client *client) { + if (!cursor->image || strcmp(cursor->image, image) != 0) { + wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, + cursor->cursor); + cursor->image = image; + } + cursor->image_client = client; +} + void sway_cursor_destroy(struct sway_cursor *cursor) { if (!cursor) { return; -- cgit v1.2.3 From 9df660ee3188386c907d8feb999636ce8d61d095 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 21 Jul 2018 11:23:48 +1000 Subject: Store last button and use it when views request to move or resize --- include/sway/input/seat.h | 9 ++++++++- sway/desktop/xdg_shell.c | 13 ++++++------- sway/desktop/xdg_shell_v6.c | 13 ++++++------- sway/input/cursor.c | 18 +++++++----------- sway/input/seat.c | 12 ++++++++++-- 5 files changed, 37 insertions(+), 28 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index cd36ef5a..ab25788f 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -68,6 +68,9 @@ struct sway_seat { double op_ref_width, op_ref_height; // container's size at start of op double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op + uint32_t last_button; + uint32_t last_button_serial; + struct wl_listener focus_destroy; struct wl_listener new_container; struct wl_listener new_drag_icon; @@ -150,11 +153,15 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); void drag_icon_update_position(struct sway_drag_icon *icon); -void seat_begin_move(struct sway_seat *seat, struct sway_container *con); +void seat_begin_move(struct sway_seat *seat, struct sway_container *con, + uint32_t button); void seat_begin_resize(struct sway_seat *seat, struct sway_container *con, uint32_t button, enum wlr_edges edge); void seat_end_mouse_operation(struct sway_seat *seat); +void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, + uint32_t button, enum wlr_button_state state); + #endif diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index d6c3a9a7..c5d53d1d 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -1,9 +1,4 @@ #define _POSIX_C_SOURCE 199309L -#ifdef __linux__ -#include -#elif __FreeBSD__ -#include -#endif #include #include #include @@ -259,7 +254,9 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_view->view; struct wlr_xdg_toplevel_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_move(seat, view->swayc); + if (e->serial == seat->last_button_serial) { + seat_begin_move(seat, view->swayc, seat->last_button); + } } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -268,7 +265,9 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_view->view; struct wlr_xdg_toplevel_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); + if (e->serial == seat->last_button_serial) { + seat_begin_resize(seat, view->swayc, seat->last_button, e->edges); + } } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 241bd9b0..4bd6af5e 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -1,9 +1,4 @@ #define _POSIX_C_SOURCE 199309L -#ifdef __linux__ -#include -#elif __FreeBSD__ -#include -#endif #include #include #include @@ -254,7 +249,9 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_v6_view->view; struct wlr_xdg_toplevel_v6_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_move(seat, view->swayc); + if (e->serial == seat->last_button_serial) { + seat_begin_move(seat, view->swayc, seat->last_button); + } } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -263,7 +260,9 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_v6_view->view; struct wlr_xdg_toplevel_v6_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); + if (e->serial == seat->last_button_serial) { + seat_begin_resize(seat, view->swayc, seat->last_button, e->edges); + } } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 43721d28..ad0ceb94 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -429,7 +429,7 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, // Deny moving or resizing a fullscreen view if (cont->type == C_VIEW && cont->sway_view->is_fullscreen) { - wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state); + seat_pointer_notify_button(seat, time_msec, button, state); return; } @@ -442,7 +442,7 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, // Check for beginning move if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED && (mod_pressed || over_title)) { - seat_begin_move(seat, cont); + seat_begin_move(seat, cont, BTN_LEFT); return; } @@ -456,7 +456,7 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, } // Send event to surface - wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state); + seat_pointer_notify_button(seat, time_msec, button, state); } void dispatch_cursor_button(struct sway_cursor *cursor, @@ -480,8 +480,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, if (layer->current.keyboard_interactive) { seat_set_focus_layer(cursor->seat, layer); } - wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, - time_msec, button, state); + seat_pointer_notify_button(cursor->seat, time_msec, button, state); } else if (cont && container_is_floating(cont)) { dispatch_cursor_button_floating(cursor, time_msec, button, state, surface, sx, sy, cont); @@ -501,15 +500,12 @@ void dispatch_cursor_button(struct sway_cursor *cursor, if (new_ws != old_ws) { seat_set_focus(cursor->seat, cont); } - wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, - time_msec, button, state); + seat_pointer_notify_button(cursor->seat, time_msec, button, state); } else if (cont) { seat_set_focus(cursor->seat, cont); - wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, - time_msec, button, state); + seat_pointer_notify_button(cursor->seat, time_msec, button, state); } else { - wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, - time_msec, button, state); + seat_pointer_notify_button(cursor->seat, time_msec, button, state); } transaction_commit_dirty(); diff --git a/sway/input/seat.c b/sway/input/seat.c index 3a3350e1..4e803efd 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -901,14 +901,15 @@ struct seat_config *seat_get_config(struct sway_seat *seat) { return NULL; } -void seat_begin_move(struct sway_seat *seat, struct sway_container *con) { +void seat_begin_move(struct sway_seat *seat, struct sway_container *con, + uint32_t button) { if (!seat->cursor) { wlr_log(WLR_DEBUG, "Ignoring move request due to no cursor device"); return; } seat->operation = OP_MOVE; seat->op_container = con; - seat->op_button = BTN_LEFT; + seat->op_button = button; } void seat_begin_resize(struct sway_seat *seat, struct sway_container *con, @@ -951,3 +952,10 @@ void seat_end_mouse_operation(struct sway_seat *seat) { seat->operation = OP_NONE; seat->op_container = NULL; } + +void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, + uint32_t button, enum wlr_button_state state) { + seat->last_button = button; + seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat, + time_msec, button, state); +} -- cgit v1.2.3 From 94dd8823a0081f7983dce368d5d093d1d3eeaefe Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Mon, 23 Jul 2018 21:38:29 -0400 Subject: Invoke mouse bindings The mouse binding logic is inspired/copied from the keyboard binding logic; we store a sorted list of the currently pressed buttons, and trigger a binding when the currently pressed (or just recently pressed, in the case of a release binding) buttons, as well as modifiers/container region, match those of a given binding. As the code to execute a binding is not very keyboard specific, keyboard_execute_command is renamed to seat_execute_command and moved to where the other binding handling functions are. The call to transaction_commit_dirty has been lifted out. --- include/sway/config.h | 2 + include/sway/input/cursor.h | 6 +++ sway/commands/bind.c | 16 +++++++ sway/input/cursor.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ sway/input/keyboard.c | 40 ++++++----------- 5 files changed, 139 insertions(+), 27 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/config.h b/include/sway/config.h index 92536d10..bcd503a4 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -497,6 +497,8 @@ void free_sway_binding(struct sway_binding *sb); struct sway_binding *sway_binding_dup(struct sway_binding *sb); +void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); + void load_swaybars(); void invoke_swaybar(struct bar_config *bar); diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index b0a3a7c5..7ec45120 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -3,6 +3,8 @@ #include #include "sway/input/seat.h" +#define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32 + struct sway_cursor { struct sway_seat *seat; struct wlr_cursor *cursor; @@ -29,6 +31,10 @@ struct sway_cursor { uint32_t tool_buttons; struct wl_listener request_set_cursor; + + // Mouse binding state + uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; + size_t pressed_button_count; }; void sway_cursor_destroy(struct sway_cursor *cursor); diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 6910237f..133fd089 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -267,3 +267,19 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { struct cmd_results *cmd_bindcode(int argc, char **argv) { return cmd_bindsym_or_bindcode(argc, argv, true); } + + +/** + * Execute the command associated to a binding + */ +void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { + wlr_log(WLR_DEBUG, "running command for binding: %s", + binding->command); + config->handler_context.seat = seat; + struct cmd_results *results = execute_command(binding->command, NULL); + if (results->status != CMD_SUCCESS) { + wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", + binding->command, results->error); + } + free_cmd_results(results); +} diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 65d04cac..f1481936 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -469,6 +469,83 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, seat_pointer_notify_button(seat, time_msec, button, state); } +/** + * Remove a button (and duplicates) to the sorted list of currently pressed buttons + */ +static void state_erase_button(struct sway_cursor *cursor, uint32_t button) { + size_t j = 0; + for (size_t i = 0; i < cursor->pressed_button_count; ++i) { + if (i > j) { + cursor->pressed_buttons[j] = cursor->pressed_buttons[i]; + } + if (cursor->pressed_buttons[i] != button) { + ++j; + } + } + while (cursor->pressed_button_count > j) { + --cursor->pressed_button_count; + cursor->pressed_buttons[cursor->pressed_button_count] = 0; + } +} + +/** + * Add a button to the sorted list of currently pressed buttons, if there + * is space. + */ +static void state_add_button(struct sway_cursor *cursor, uint32_t button) { + if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) { + return; + } + size_t i = 0; + while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) { + ++i; + } + size_t j = cursor->pressed_button_count; + while (j > i) { + cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1]; + --j; + } + cursor->pressed_buttons[i] = button; + cursor->pressed_button_count++; +} + +/** + * Return the mouse binding which matches modifier, click location, release, + * and pressed button state, otherwise return null. + */ +static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *cursor, + list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar, + bool on_border, bool on_content) { + uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) | + (on_border ? BINDING_BORDER : 0) | + (on_content ? BINDING_CONTENTS : 0); + + for (int i = 0; i < bindings->length; ++i) { + struct sway_binding *binding = bindings->items[i]; + if (modifiers ^ binding->modifiers || + cursor->pressed_button_count != (size_t)binding->keys->length || + release != (binding->flags & BINDING_RELEASE) || + !(click_region & binding->flags)) { + continue; + } + + bool match = true; + for (size_t j = 0; j < cursor->pressed_button_count; j++) { + uint32_t key = *(uint32_t *)binding->keys->items[j]; + if (key != cursor->pressed_buttons[j]) { + match = false; + break; + } + } + if (!match) { + continue; + } + + return binding; + } + return NULL; +} + void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state) { if (cursor->seat->operation != OP_NONE && @@ -485,6 +562,31 @@ void dispatch_cursor_button(struct sway_cursor *cursor, double sx, sy; struct sway_container *cont = container_at_coords(cursor->seat, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + + // Handle mouse bindings + bool on_border = find_resize_edge(cont, cursor) != WLR_EDGE_NONE; + bool on_contents = !on_border && surface; + bool on_titlebar = !on_border && !surface; + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat); + uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; + + struct sway_binding *binding = NULL; + if (state == WLR_BUTTON_PRESSED) { + state_add_button(cursor, button); + binding = get_active_mouse_binding(cursor, + config->current_mode->mouse_bindings, modifiers, false, + on_titlebar, on_border, on_contents); + } else { + binding = get_active_mouse_binding(cursor, + config->current_mode->mouse_bindings, modifiers, true, + on_titlebar, on_border, on_contents); + state_erase_button(cursor, button); + } + if (binding) { + seat_execute_command(cursor->seat, binding); + // TODO: do we want to pass on the event? + } + if (surface && wlr_surface_is_layer_surface(surface)) { struct wlr_layer_surface *layer = wlr_layer_surface_from_wlr_surface(surface); diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index e6c5c335..49241db8 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -3,11 +3,11 @@ #include #include #include +#include "sway/commands.h" #include "sway/desktop/transaction.h" -#include "sway/input/seat.h" -#include "sway/input/keyboard.h" #include "sway/input/input-manager.h" -#include "sway/commands.h" +#include "sway/input/keyboard.h" +#include "sway/input/seat.h" #include "log.h" /** @@ -88,8 +88,8 @@ static void get_active_binding(const struct sway_shortcut_state *state, uint32_t modifiers, bool release, bool locked) { for (int i = 0; i < bindings->length; ++i) { struct sway_binding *binding = bindings->items[i]; - bool binding_locked = binding->flags | BINDING_LOCKED; - bool binding_release = binding->flags | BINDING_RELEASE; + bool binding_locked = binding->flags & BINDING_LOCKED; + bool binding_release = binding->flags & BINDING_RELEASE; if (modifiers ^ binding->modifiers || state->npressed != (size_t)binding->keys->length || @@ -120,23 +120,6 @@ static void get_active_binding(const struct sway_shortcut_state *state, } } -/** - * Execute the command associated to a binding - */ -static void keyboard_execute_command(struct sway_keyboard *keyboard, - struct sway_binding *binding) { - wlr_log(WLR_DEBUG, "running command for binding: %s", - binding->command); - config->handler_context.seat = keyboard->seat_device->sway_seat; - struct cmd_results *results = execute_command(binding->command, NULL); - transaction_commit_dirty(); - if (results->status != CMD_SUCCESS) { - wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", - binding->command, results->error); - } - free_cmd_results(results); -} - /** * Execute a built-in, hardcoded compositor binding. These are triggered from a * single keysym. @@ -213,12 +196,13 @@ static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard, static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct sway_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_key); - struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; + struct sway_seat* seat = keyboard->seat_device->sway_seat; + struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_input_device *wlr_device = keyboard->seat_device->input_device->wlr_device; - wlr_idle_notify_activity(keyboard->seat_device->sway_seat->input->server->idle, wlr_seat); + wlr_idle_notify_activity(seat->input->server->idle, wlr_seat); struct wlr_event_keyboard_key *event = data; - bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL; + bool input_inhibited = seat->exclusive_client != NULL; // Identify new keycode, raw keysym(s), and translated keysym(s) xkb_keycode_t keycode = event->keycode + 8; @@ -268,7 +252,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { // Execute stored release binding once no longer active if (keyboard->held_binding && binding_released != keyboard->held_binding && event->state == WLR_KEY_RELEASED) { - keyboard_execute_command(keyboard, keyboard->held_binding); + seat_execute_command(seat, keyboard->held_binding); handled = true; } if (binding_released != keyboard->held_binding) { @@ -292,7 +276,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { raw_modifiers, false, input_inhibited); if (binding_pressed) { - keyboard_execute_command(keyboard, binding_pressed); + seat_execute_command(seat, binding_pressed); handled = true; } } @@ -314,6 +298,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, event->keycode, event->state); } + + transaction_commit_dirty(); } static void handle_keyboard_modifiers(struct wl_listener *listener, -- cgit v1.2.3 From da2a87f6c71bfe90a4d77542bfc7ed22899f67be Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 26 Jul 2018 22:58:42 +1000 Subject: When unfloating, return container to previously focused tiled container This introduces seat_get_focus_inactive_tiling and updates `focus mode_toggle` to use it instead, because the previous method wasn't guaranteed to return a tiling view. --- include/sway/input/seat.h | 3 +++ sway/commands/focus.c | 14 ++++++++------ sway/input/seat.c | 23 +++++++++++++++++------ sway/tree/container.c | 5 ++++- 4 files changed, 32 insertions(+), 13 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index ab25788f..07febe2c 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -124,6 +124,9 @@ struct sway_container *seat_get_focus(struct sway_seat *seat); struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container); +struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, + struct sway_container *container); + /** * Descend into the focus stack to find the focus-inactive view. Useful for * container placement when they change position in the tree. diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 9cd8bfae..ce3d032f 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -35,14 +35,16 @@ static struct cmd_results *focus_mode(struct sway_container *con, struct sway_seat *seat, bool floating) { struct sway_container *ws = con->type == C_WORKSPACE ? con : container_parent(con, C_WORKSPACE); - struct sway_container *new_focus = ws; + struct sway_container *new_focus = NULL; if (floating) { - new_focus = ws->sway_workspace->floating; - if (new_focus->children->length == 0) { - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } + new_focus = seat_get_focus_inactive(seat, ws->sway_workspace->floating); + } else { + new_focus = seat_get_focus_inactive_tiling(seat, ws); + } + if (!new_focus) { + new_focus = ws; } - seat_set_focus(seat, seat_get_active_child(seat, new_focus)); + seat_set_focus(seat, new_focus); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/input/seat.c b/sway/input/seat.c index 877a93c6..18d5591d 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -124,12 +124,14 @@ static void seat_send_focus(struct sway_container *con, } static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, - struct sway_container *container, enum sway_container_type type) { + struct sway_container *container, enum sway_container_type type, + bool only_tiling) { if (container->type == C_VIEW) { return container; } - struct sway_container *floating = container->type == C_WORKSPACE ? + struct sway_container *floating = + container->type == C_WORKSPACE && !only_tiling ? container->sway_workspace->floating : NULL; if (container->children->length == 0 && (!floating || floating->children->length == 0)) { @@ -143,6 +145,10 @@ static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, } if (container_has_child(container, current->container)) { + if (only_tiling && + container_is_floating_or_child(current->container)) { + continue; + } return current->container; } if (floating && container_has_child(floating, current->container)) { @@ -169,7 +175,7 @@ void seat_focus_inactive_children_for_each(struct sway_seat *seat, struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, struct sway_container *container) { - return seat_get_focus_by_type(seat, container, C_VIEW); + return seat_get_focus_by_type(seat, container, C_VIEW, false); } static void handle_seat_container_destroy(struct wl_listener *listener, @@ -191,7 +197,7 @@ static void handle_seat_container_destroy(struct wl_listener *listener, if (set_focus) { struct sway_container *next_focus = NULL; while (next_focus == NULL) { - next_focus = seat_get_focus_by_type(seat, parent, C_VIEW); + next_focus = seat_get_focus_by_type(seat, parent, C_VIEW, false); if (next_focus == NULL && parent->type == C_WORKSPACE) { next_focus = parent; @@ -648,7 +654,7 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_container *new_output_last_ws = NULL; if (last_output && new_output && last_output != new_output) { new_output_last_ws = - seat_get_focus_by_type(seat, new_output, C_WORKSPACE); + seat_get_focus_by_type(seat, new_output, C_WORKSPACE, false); } if (container && container->parent) { @@ -853,7 +859,12 @@ void seat_set_exclusive_client(struct sway_seat *seat, struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) { - return seat_get_focus_by_type(seat, container, C_TYPES); + return seat_get_focus_by_type(seat, container, C_TYPES, false); +} + +struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, + struct sway_container *container) { + return seat_get_focus_by_type(seat, container, C_TYPES, true); } struct sway_container *seat_get_active_child(struct sway_seat *seat, diff --git a/sway/tree/container.c b/sway/tree/container.c index 566432b1..b8ff87e1 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1015,6 +1015,7 @@ void container_set_floating(struct sway_container *container, bool enable) { return; } + struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *workspace = container_parent(container, C_WORKSPACE); if (enable) { @@ -1029,8 +1030,10 @@ void container_set_floating(struct sway_container *container, bool enable) { if (container->scratchpad) { scratchpad_remove_container(container); } + struct sway_container *sibling = + seat_get_focus_inactive_tiling(seat, workspace); container_remove_child(container); - container_add_child(workspace, container); + container_add_child(sibling, container); container->width = container->parent->width; container->height = container->parent->height; if (container->type == C_VIEW) { -- cgit v1.2.3 From 1e65439a5448ac203fa0476d410ad303e0766552 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 28 Jul 2018 20:47:56 -0400 Subject: Add virtual keyboard protocol Ref #2373 --- include/sway/input/input-manager.h | 3 +++ sway/input/input-manager.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'include/sway/input') diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 89a3ac71..aa2f6f19 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -2,6 +2,7 @@ #define _SWAY_INPUT_INPUT_MANAGER_H #include #include +#include #include "sway/server.h" #include "sway/config.h" #include "list.h" @@ -25,10 +26,12 @@ struct sway_input_manager { struct wl_list seats; struct wlr_input_inhibit_manager *inhibit; + struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; struct wl_listener new_input; struct wl_listener inhibit_activate; struct wl_listener inhibit_deactivate; + struct wl_listener virtual_keyboard_new; }; struct sway_input_manager *input_manager_create(struct sway_server *server); diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 0b7cb766..c820e032 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "sway/config.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" @@ -303,6 +304,35 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data) } } +void handle_virtual_keyboard(struct wl_listener *listener, void *data) { + struct sway_input_manager *input_manager = + wl_container_of(listener, input_manager, virtual_keyboard_new); + struct wlr_virtual_keyboard_v1 *keyboard = data; + struct wlr_input_device *device = &keyboard->input_device; + + struct sway_seat *seat = input_manager_get_default_seat(input_manager); + + // TODO: The user might want this on a different seat + struct sway_input_device *input_device = + calloc(1, sizeof(struct sway_input_device)); + if (!sway_assert(input_device, "could not allocate input device")) { + return; + } + device->data = input_device; + + input_device->wlr_device = device; + input_device->identifier = get_device_identifier(device); + wl_list_insert(&input_manager->devices, &input_device->link); + + wlr_log(WLR_DEBUG, "adding virtual keyboard: '%s'", + input_device->identifier); + + wl_signal_add(&device->events.destroy, &input_device->device_destroy); + input_device->device_destroy.notify = handle_device_destroy; + + seat_add_device(seat, input_device); +} + struct sway_input_manager *input_manager_create( struct sway_server *server) { struct sway_input_manager *input = @@ -321,6 +351,12 @@ struct sway_input_manager *input_manager_create( input->new_input.notify = handle_new_input; wl_signal_add(&server->backend->events.new_input, &input->new_input); + input->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create( + server->wl_display); + wl_signal_add(&input->virtual_keyboard->events.new_virtual_keyboard, + &input->virtual_keyboard_new); + input->virtual_keyboard_new.notify = handle_virtual_keyboard; + input->inhibit = wlr_input_inhibit_manager_create(server->wl_display); input->inhibit_activate.notify = handle_inhibit_activate; wl_signal_add(&input->inhibit->events.activate, -- cgit v1.2.3 From e33dfbfa758fb899c276135d06f25359ceee0002 Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Sun, 29 Jul 2018 16:25:43 -0400 Subject: Implement key repeat for pressed key bindings Each sway_keyboard is provided with a wayland timer event source. When a valid keypress binding has been found, a callback to handle_keyboard_repeat is set. Any key event will either clear the callback or (if the new key event is a valid keypress binding) delay the callback again. --- include/sway/input/keyboard.h | 5 +++++ sway/input/keyboard.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) (limited to 'include/sway/input') diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h index 6713398e..660cdc9c 100644 --- a/include/sway/input/keyboard.h +++ b/include/sway/input/keyboard.h @@ -38,6 +38,11 @@ struct sway_keyboard { struct sway_shortcut_state state_keysyms_raw; struct sway_shortcut_state state_keycodes; struct sway_binding *held_binding; + + struct wl_event_source *key_repeat_source; + struct sway_binding *repeat_binding; + int key_repeat_initial_delay; // first key repeat event delay, in ms + int key_repeat_step_delay; // subsequent repeat delay, in ms }; struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 8dc8239c..be000fb9 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -264,6 +264,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { } // Identify and execute active pressed binding + struct sway_binding *next_repeat_binding = NULL; if (event->state == WLR_KEY_PRESSED) { struct sway_binding *binding_pressed = NULL; get_active_binding(&keyboard->state_keycodes, @@ -279,6 +280,21 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { if (binding_pressed) { seat_execute_command(seat, binding_pressed); handled = true; + next_repeat_binding = binding_pressed; + } + } + + // Set up (or clear) keyboard repeat for a pressed binding + if (next_repeat_binding) { + keyboard->repeat_binding = next_repeat_binding; + if (wl_event_source_timer_update(keyboard->key_repeat_source, + keyboard->key_repeat_initial_delay) < 0) { + wlr_log(WLR_DEBUG, "failed to set key repeat timer"); + } + } else if (keyboard->repeat_binding) { + keyboard->repeat_binding = NULL; + if (wl_event_source_timer_update(keyboard->key_repeat_source, 0) < 0) { + wlr_log(WLR_DEBUG, "failed to disarm key repeat timer"); } } @@ -303,6 +319,22 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { transaction_commit_dirty(); } +static int handle_keyboard_repeat(void *data) { + struct sway_keyboard *keyboard = (struct sway_keyboard *)data; + if (keyboard->repeat_binding) { + // We queue the next event first, as the command might cancel it + if (wl_event_source_timer_update(keyboard->key_repeat_source, + keyboard->key_repeat_step_delay) < 0) { + wlr_log(WLR_DEBUG, "failed to update key repeat timer"); + } + + seat_execute_command(keyboard->seat_device->sway_seat, + keyboard->repeat_binding); + transaction_commit_dirty(); + } + return 0; +} + static void handle_keyboard_modifiers(struct wl_listener *listener, void *data) { struct sway_keyboard *keyboard = @@ -328,6 +360,11 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, wl_list_init(&keyboard->keyboard_key.link); wl_list_init(&keyboard->keyboard_modifiers.link); + keyboard->key_repeat_source = wl_event_loop_add_timer(server.wl_event_loop, + handle_keyboard_repeat, keyboard); + keyboard->key_repeat_initial_delay = 660; + keyboard->key_repeat_step_delay = 40; + return keyboard; } @@ -441,5 +478,6 @@ void sway_keyboard_destroy(struct sway_keyboard *keyboard) { } wl_list_remove(&keyboard->keyboard_key.link); wl_list_remove(&keyboard->keyboard_modifiers.link); + wl_event_source_remove(keyboard->key_repeat_source); free(keyboard); } -- cgit v1.2.3 From 8dbbfa5965ca8bfe4bc023100387dd657bafe48e Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Sun, 29 Jul 2018 18:50:20 -0400 Subject: Bindings use advised keyboard repeat parameters Now 'repeat_delay' and 'repeat_rate' control the initial delay and rate (per second) of repeated binding invocations. If the repeat delay is zero, binding repetition is disabled. When the repeat rate is zero, the binding is repeated exactly once, assuming no other key events intervene. --- include/sway/input/keyboard.h | 2 -- sway/input/keyboard.c | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h index 660cdc9c..6d28454c 100644 --- a/include/sway/input/keyboard.h +++ b/include/sway/input/keyboard.h @@ -41,8 +41,6 @@ struct sway_keyboard { struct wl_event_source *key_repeat_source; struct sway_binding *repeat_binding; - int key_repeat_initial_delay; // first key repeat event delay, in ms - int key_repeat_step_delay; // subsequent repeat delay, in ms }; struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index be000fb9..160ef10b 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -285,10 +285,10 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { } // Set up (or clear) keyboard repeat for a pressed binding - if (next_repeat_binding) { + if (next_repeat_binding && wlr_device->keyboard->repeat_info.delay > 0) { keyboard->repeat_binding = next_repeat_binding; if (wl_event_source_timer_update(keyboard->key_repeat_source, - keyboard->key_repeat_initial_delay) < 0) { + wlr_device->keyboard->repeat_info.delay) < 0) { wlr_log(WLR_DEBUG, "failed to set key repeat timer"); } } else if (keyboard->repeat_binding) { @@ -321,11 +321,15 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { static int handle_keyboard_repeat(void *data) { struct sway_keyboard *keyboard = (struct sway_keyboard *)data; + struct wlr_keyboard *wlr_device = + keyboard->seat_device->input_device->wlr_device->keyboard; if (keyboard->repeat_binding) { - // We queue the next event first, as the command might cancel it - if (wl_event_source_timer_update(keyboard->key_repeat_source, - keyboard->key_repeat_step_delay) < 0) { - wlr_log(WLR_DEBUG, "failed to update key repeat timer"); + if (wlr_device->repeat_info.rate > 0) { + // We queue the next event first, as the command might cancel it + if (wl_event_source_timer_update(keyboard->key_repeat_source, + 1000 / wlr_device->repeat_info.rate) < 0) { + wlr_log(WLR_DEBUG, "failed to update key repeat timer"); + } } seat_execute_command(keyboard->seat_device->sway_seat, @@ -362,8 +366,6 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, keyboard->key_repeat_source = wl_event_loop_add_timer(server.wl_event_loop, handle_keyboard_repeat, keyboard); - keyboard->key_repeat_initial_delay = 660; - keyboard->key_repeat_step_delay = 40; return keyboard; } -- cgit v1.2.3 From 03eaf444a4a432e5712d40f93d849b51d2028b63 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 21:55:14 +0100 Subject: ipc: prevent emitting a workspace::focus event when moving a container to a different workspace or output When a container is moved from, say, workspace 1 to workspace 2, workspace 2 is focused in order to arrange the windows before focus is moved back to workspace 1, which caused a workspace:focus event from workspace 2 to workspace 1 to be emitted. This commit inhibits that event. --- include/sway/input/seat.h | 2 +- sway/commands/move.c | 4 ++-- sway/input/cursor.c | 6 +++--- sway/input/seat.c | 6 +++--- sway/tree/layout.c | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/sway/input') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 07febe2c..92387601 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -99,7 +99,7 @@ void seat_configure_xcursor(struct sway_seat *seat); void seat_set_focus(struct sway_seat *seat, struct sway_container *container); void seat_set_focus_warp(struct sway_seat *seat, - struct sway_container *container, bool warp); + struct sway_container *container, bool warp, bool notify); void seat_set_focus_surface(struct sway_seat *seat, struct wlr_surface *surface, bool unfocus); diff --git a/sway/commands/move.c b/sway/commands/move.c index 1aae3838..46ebcd83 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -98,7 +98,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, container_move_to(current, destination); struct sway_container *focus = seat_get_focus_inactive( config->handler_context.seat, old_parent); - seat_set_focus(config->handler_context.seat, focus); + seat_set_focus_warp(config->handler_context.seat, focus, true, false); container_reap_empty(old_parent); container_reap_empty(destination->parent); @@ -135,7 +135,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, struct sway_container *old_parent = current->parent; struct sway_container *old_ws = container_parent(current, C_WORKSPACE); container_move_to(current, focus); - seat_set_focus(config->handler_context.seat, old_parent); + seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); container_reap_empty(old_parent); container_reap_empty(focus->parent); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 96ac7b33..d6fdc1da 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -349,7 +349,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, output = container_parent(c, C_OUTPUT); } if (output != focus) { - seat_set_focus_warp(seat, c, false); + seat_set_focus_warp(seat, c, false, true); } } else if (c->type == C_VIEW) { // Focus c if the following are true: @@ -359,13 +359,13 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && c != prev_c && view_is_visible(c->sway_view)) { - seat_set_focus_warp(seat, c, false); + seat_set_focus_warp(seat, c, false, true); } else { struct sway_container *next_focus = seat_get_focus_inactive(seat, &root_container); if (next_focus && next_focus->type == C_VIEW && view_is_visible(next_focus->sway_view)) { - seat_set_focus_warp(seat, next_focus, false); + seat_set_focus_warp(seat, next_focus, false, true); } } } diff --git a/sway/input/seat.c b/sway/input/seat.c index 76050aa9..fe3cbc53 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -617,7 +617,7 @@ static int handle_urgent_timeout(void *data) { } void seat_set_focus_warp(struct sway_seat *seat, - struct sway_container *container, bool warp) { + struct sway_container *container, bool warp, bool notify) { if (seat->focused_layer) { return; } @@ -739,7 +739,7 @@ void seat_set_focus_warp(struct sway_seat *seat, if (last_focus) { if (last_workspace) { - if (last_workspace != new_workspace) { + if (notify && last_workspace != new_workspace) { ipc_event_workspace(last_workspace, new_workspace, "focus"); } if (!workspace_is_visible(last_workspace) @@ -779,7 +779,7 @@ void seat_set_focus_warp(struct sway_seat *seat, void seat_set_focus(struct sway_seat *seat, struct sway_container *container) { - seat_set_focus_warp(seat, container, true); + seat_set_focus_warp(seat, container, true, true); } void seat_set_focus_surface(struct sway_seat *seat, diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 9fbbccaf..1f82e534 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -1001,13 +1001,13 @@ static void swap_focus(struct sway_container *con1, if (focus == con1 && (con2->parent->layout == L_TABBED || con2->parent->layout == L_STACKED)) { if (workspace_is_visible(ws2)) { - seat_set_focus_warp(seat, con2, false); + seat_set_focus_warp(seat, con2, false, true); } seat_set_focus(seat, ws1 != ws2 ? con2 : con1); } else if (focus == con2 && (con1->parent->layout == L_TABBED || con1->parent->layout == L_STACKED)) { if (workspace_is_visible(ws1)) { - seat_set_focus_warp(seat, con1, false); + seat_set_focus_warp(seat, con1, false, true); } seat_set_focus(seat, ws1 != ws2 ? con1 : con2); } else if (ws1 != ws2) { -- cgit v1.2.3