diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 98eb4679b..516718c97 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -52,8 +52,6 @@ struct sway_cursor { struct wl_event_source *hide_source; bool hidden; - // Mouse binding state - uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; size_t pressed_button_count; }; @@ -78,13 +76,6 @@ void cursor_handle_activity(struct sway_cursor *cursor); void cursor_unhide(struct sway_cursor *cursor); int cursor_get_timeout(struct sway_cursor *cursor); -/** - * Like cursor_rebase, but also allows focus to change when the cursor enters a - * new container. - */ -void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, - struct sway_node *node, struct wlr_surface *surface, double sx, double sy); - void dispatch_cursor_button(struct sway_cursor *cursor, struct wlr_input_device *device, uint32_t time_msec, uint32_t button, enum wlr_button_state state); diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index ff4476d19..a5361e8c1 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -12,12 +12,15 @@ struct sway_seatop_impl { void (*button)(struct sway_seat *seat, uint32_t time_msec, struct wlr_input_device *device, uint32_t button, enum wlr_button_state state); - void (*motion)(struct sway_seat *seat, uint32_t time_msec); - void (*finish)(struct sway_seat *seat, uint32_t time_msec); - void (*abort)(struct sway_seat *seat); + void (*motion)(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy); + void (*axis)(struct sway_seat *seat, struct wlr_event_pointer_axis *event); + void (*rebase)(struct sway_seat *seat, uint32_t time_msec); + void (*end)(struct sway_seat *seat); void (*unref)(struct sway_seat *seat, struct sway_container *con); void (*render)(struct sway_seat *seat, struct sway_output *output, pixman_region32_t *damage); + bool allow_set_cursor; }; struct sway_seat_device { @@ -71,9 +74,7 @@ struct sway_seat { // Seat operations (drag and resize) const struct sway_seatop_impl *seatop_impl; void *seatop_data; - uint32_t seatop_button; - uint32_t last_button; uint32_t last_button_serial; struct wl_listener focus_destroy; @@ -188,23 +189,25 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); void drag_icon_update_position(struct sway_drag_icon *icon); +void seatop_begin_default(struct sway_seat *seat); + void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, - uint32_t time_msec, uint32_t button, int sx, int sy); + uint32_t time_msec, int sx, int sy); void seatop_begin_move_floating(struct sway_seat *seat, - struct sway_container *con, uint32_t button); + struct sway_container *con); void seatop_begin_move_tiling_threshold(struct sway_seat *seat, - struct sway_container *con, uint32_t button); + struct sway_container *con); void seatop_begin_move_tiling(struct sway_seat *seat, - struct sway_container *con, uint32_t button); + struct sway_container *con); void seatop_begin_resize_floating(struct sway_seat *seat, - struct sway_container *con, uint32_t button, enum wlr_edges edge); + struct sway_container *con, enum wlr_edges edge); void seatop_begin_resize_tiling(struct sway_seat *seat, - struct sway_container *con, uint32_t button, enum wlr_edges edge); + struct sway_container *con, enum wlr_edges edge); struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, struct sway_workspace *workspace); @@ -214,23 +217,24 @@ void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, void seat_consider_warp_to_focus(struct sway_seat *seat); -bool seat_doing_seatop(struct sway_seat *seat); - void seatop_button(struct sway_seat *seat, uint32_t time_msec, struct wlr_input_device *device, uint32_t button, enum wlr_button_state state); -void seatop_motion(struct sway_seat *seat, uint32_t time_msec); +/** + * dx and dy are distances relative to previous position. + */ +void seatop_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy); + +void seatop_axis(struct sway_seat *seat, struct wlr_event_pointer_axis *event); + +void seatop_rebase(struct sway_seat *seat, uint32_t time_msec); /** - * End a seatop and apply the affects. + * End a seatop (ie. free any seatop specific resources). */ -void seatop_finish(struct sway_seat *seat, uint32_t time_msec); - -/** - * End a seatop without applying the affects. - */ -void seatop_abort(struct sway_seat *seat); +void seatop_end(struct sway_seat *seat); /** * Instructs the seatop implementation to drop any references to the given @@ -246,4 +250,6 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con); void seatop_render(struct sway_seat *seat, struct sway_output *output, pixman_region32_t *damage); +bool seatop_allows_set_cursor(struct sway_seat *seat); + #endif diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index c84ca1115..ea5dcd16c 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -355,7 +355,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seatop_begin_move_floating(seat, view->container, seat->last_button); + seatop_begin_move_floating(seat, view->container); } } @@ -369,8 +369,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seatop_begin_resize_floating(seat, view->container, - seat->last_button, e->edges); + seatop_begin_resize_floating(seat, view->container, e->edges); } } diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 3eed54ab0..7ff4c4de8 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -355,7 +355,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel_v6_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seatop_begin_move_floating(seat, view->container, seat->last_button); + seatop_begin_move_floating(seat, view->container); } } @@ -369,8 +369,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel_v6_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { - seatop_begin_resize_floating(seat, view->container, - seat->last_button, e->edges); + seatop_begin_resize_floating(seat, view->container, e->edges); } } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index a2aa2e08e..f5ade8dcb 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -476,7 +476,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { return; } struct sway_seat *seat = input_manager_current_seat(); - seatop_begin_move_floating(seat, view->container, seat->last_button); + seatop_begin_move_floating(seat, view->container); } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -492,8 +492,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { } struct wlr_xwayland_resize_event *e = data; struct sway_seat *seat = input_manager_current_seat(); - seatop_begin_resize_floating(seat, view->container, - seat->last_button, e->edges); + seatop_begin_resize_floating(seat, view->container, e->edges); } static void handle_request_activate(struct wl_listener *listener, void *data) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 011b4929a..610844479 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -158,132 +158,9 @@ struct sway_node *node_at_coords( return &ws->node; } -/** - * Determine if the edge of the given container is on the edge of the - * workspace/output. - */ -static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { - enum sway_container_layout layout = L_NONE; - switch (edge) { - case WLR_EDGE_TOP: - case WLR_EDGE_BOTTOM: - layout = L_VERT; - break; - case WLR_EDGE_LEFT: - case WLR_EDGE_RIGHT: - layout = L_HORIZ; - break; - case WLR_EDGE_NONE: - sway_assert(false, "Never reached"); - return false; - } - - // Iterate the parents until we find one with the layout we want, - // then check if the child has siblings between it and the edge. - while (cont) { - if (container_parent_layout(cont) == layout) { - list_t *siblings = container_get_siblings(cont); - int index = list_find(siblings, cont); - if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { - return false; - } - if (index < siblings->length - 1 && - (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) { - return false; - } - } - cont = cont->parent; - } - return true; -} - -static enum wlr_edges find_edge(struct sway_container *cont, - struct sway_cursor *cursor) { - if (!cont->view) { - return WLR_EDGE_NONE; - } - if (cont->border == B_NONE || !cont->border_thickness || - cont->border == B_CSD) { - return WLR_EDGE_NONE; - } - - enum wlr_edges edge = 0; - if (cursor->cursor->x < cont->x + cont->border_thickness) { - edge |= WLR_EDGE_LEFT; - } - if (cursor->cursor->y < cont->y + cont->border_thickness) { - edge |= WLR_EDGE_TOP; - } - if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) { - edge |= WLR_EDGE_RIGHT; - } - if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) { - edge |= WLR_EDGE_BOTTOM; - } - - return edge; -} - -/** - * If the cursor is over a _resizable_ edge, return the edge. - * Edges that can't be resized are edges of the workspace. - */ -static enum wlr_edges find_resize_edge(struct sway_container *cont, - struct sway_cursor *cursor) { - enum wlr_edges edge = find_edge(cont, cursor); - if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) { - return WLR_EDGE_NONE; - } - return edge; -} - -static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec, - struct sway_node *node, struct wlr_surface *surface, - double sx, double sy) { - // Handle cursor image - if (surface) { - // Reset cursor if switching between clients - struct wl_client *client = wl_resource_get_client(surface->resource); - if (client != cursor->image_client) { - cursor_set_image(cursor, "left_ptr", client); - } - } else if (node && node->type == N_CONTAINER) { - // Try a node's resize edge - enum wlr_edges edge = find_resize_edge(node->sway_container, cursor); - if (edge == WLR_EDGE_NONE) { - cursor_set_image(cursor, "left_ptr", NULL); - } else if (container_is_floating(node->sway_container)) { - cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); - } else { - if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { - cursor_set_image(cursor, "col-resize", NULL); - } else { - cursor_set_image(cursor, "row-resize", NULL); - } - } - } else { - cursor_set_image(cursor, "left_ptr", NULL); - } - - // Send pointer enter/leave - struct wlr_seat *wlr_seat = cursor->seat->wlr_seat; - if (surface) { - if (seat_is_input_allowed(cursor->seat, surface)) { - wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(wlr_seat, time_msec, sx, sy); - } - } else { - wlr_seat_pointer_clear_focus(wlr_seat); - } -} - void cursor_rebase(struct sway_cursor *cursor) { uint32_t time_msec = get_current_time_msec(); - struct wlr_surface *surface = NULL; - double sx = 0.0, sy = 0.0; - cursor->previous.node = node_at_coords(cursor->seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - cursor_do_rebase(cursor, time_msec, cursor->previous.node, surface, sx, sy); + seatop_rebase(cursor->seat, time_msec); } void cursor_rebase_all(void) { @@ -293,9 +170,7 @@ void cursor_rebase_all(void) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { - if (!seat_doing_seatop(seat)) { - cursor_rebase(seat->cursor); - } + cursor_rebase(seat->cursor); } } @@ -345,90 +220,17 @@ void cursor_unhide(struct sway_cursor *cursor) { cursor_rebase(cursor); } -void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, - struct sway_node *node, struct wlr_surface *surface, - double sx, double sy) { - if (time_msec == 0) { - time_msec = get_current_time_msec(); - } - - struct sway_seat *seat = cursor->seat; - - if (seat_doing_seatop(seat)) { - seatop_motion(seat, time_msec); - cursor->previous.x = cursor->cursor->x; - cursor->previous.y = cursor->cursor->y; - return; - } - - struct sway_node *prev_node = cursor->previous.node; - - // Update the stored previous position - cursor->previous.x = cursor->cursor->x; - cursor->previous.y = cursor->cursor->y; - cursor->previous.node = node; - - if (node && (config->focus_follows_mouse == FOLLOWS_YES || - config->focus_follows_mouse == FOLLOWS_ALWAYS)) { - struct sway_node *focus = seat_get_focus(seat); - if (focus && node->type == N_WORKSPACE) { - // Only follow the mouse if it would move to a new output - // Otherwise we'll focus the workspace, which is probably wrong - struct sway_output *focused_output = node_get_output(focus); - struct sway_output *output = node_get_output(node); - if (output != focused_output) { - seat_set_focus(seat, seat_get_focus_inactive(seat, node)); - } - } else if (node->type == N_CONTAINER && node->sway_container->view) { - // Focus node if the following are true: - // - cursor is over a new view, i.e. entered a new window; and - // - the new view is visible, i.e. not hidden in a stack or tab; and - // - the seat does not have a keyboard grab - if ((!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && - node != prev_node && - view_is_visible(node->sway_container->view)) || - config->focus_follows_mouse == FOLLOWS_ALWAYS) { - seat_set_focus(seat, node); - } else { - struct sway_node *next_focus = - seat_get_focus_inactive(seat, &root->node); - if (next_focus && next_focus->type == N_CONTAINER && - next_focus->sway_container->view && - view_is_visible(next_focus->sway_container->view)) { - seat_set_focus(seat, next_focus); - } - } - } - } - - cursor_do_rebase(cursor, time_msec, node, surface, sx, sy); - - struct sway_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &root->drag_icons, link) { - if (drag_icon->seat == seat) { - drag_icon_update_position(drag_icon); - } - } -} - -static void handle_cursor_motion(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, motion); - struct wlr_event_pointer_motion *event = data; +static void cursor_motion(struct sway_cursor *cursor, uint32_t time_msec, + struct wlr_input_device *device, double dx, double dy, + double dx_unaccel, double dy_unaccel) { cursor_handle_activity(cursor); - double dx = event->delta_x; - double dy = event->delta_y; - - double dx_unaccel = event->unaccel_dx; - double dy_unaccel = event->unaccel_dy; - wlr_relative_pointer_manager_v1_send_relative_motion( server.relative_pointer_manager, - cursor->seat->wlr_seat, (uint64_t)event->time_msec * 1000, + cursor->seat->wlr_seat, (uint64_t)time_msec * 1000, dx, dy, dx_unaccel, dy_unaccel); struct wlr_surface *surface = NULL; - struct sway_node *node = NULL; double sx, sy; if (cursor->active_constraint) { node_at_coords(cursor->seat, @@ -448,50 +250,18 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { dy = sy_confined - sy; } - wlr_cursor_move(cursor->cursor, event->device, dx, dy); + wlr_cursor_move(cursor->cursor, device, dx, dy); - // Recalculate pointer location after layout checks - node = node_at_coords(cursor->seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - cursor_send_pointer_motion(cursor, event->time_msec, node, surface, - sx, sy); - transaction_commit_dirty(); + seatop_motion(cursor->seat, time_msec, dx, dy); } -static void cursor_motion_absolute(struct sway_cursor *cursor, - uint32_t time_msec, struct wlr_input_device *dev, - double x, double y) { - cursor_handle_activity(cursor); +static void handle_cursor_motion_relative( + struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = wl_container_of(listener, cursor, motion); + struct wlr_event_pointer_motion *e = data; - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, dev, - x, y, &lx, &ly); - - double dx = lx - cursor->cursor->x; - double dy = ly - cursor->cursor->y; - wlr_relative_pointer_manager_v1_send_relative_motion( - server.relative_pointer_manager, - cursor->seat->wlr_seat, (uint64_t)time_msec * 1000, - dx, dy, dx, dy); - - struct wlr_surface *surface = NULL; - double sx = 0.0, sy = 0.0; - struct sway_node *node = node_at_coords(cursor->seat, - lx, ly, &surface, &sx, &sy); - - if (cursor->active_constraint) { - if (cursor->active_constraint->surface != surface) { - return; - } - if (!pixman_region32_contains_point(&cursor->confine, - floor(sx), floor(sy), NULL)) { - return; - } - } - - wlr_cursor_warp_closest(cursor->cursor, dev, lx, ly); - cursor_send_pointer_motion(cursor, time_msec, node, surface, sx, sy); + cursor_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y, + e->unaccel_dx, e->unaccel_dy); transaction_commit_dirty(); } @@ -501,98 +271,15 @@ static void handle_cursor_motion_absolute( wl_container_of(listener, cursor, motion_absolute); struct wlr_event_pointer_motion_absolute *event = data; - cursor_motion_absolute(cursor, event->time_msec, event->device, - event->x, event->y); -} + double lx, ly; + wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, + event->x, event->y, &lx, &ly); -/** - * 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; - } -} + double dx = lx - cursor->cursor->x; + double dy = ly - cursor->cursor->y; -/** - * 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, - bool on_workspace, const char *identifier) { - uint32_t click_region = - ((on_titlebar || on_workspace) ? BINDING_TITLEBAR : 0) | - ((on_border || on_workspace) ? BINDING_BORDER : 0) | - ((on_content || on_workspace) ? BINDING_CONTENTS : 0); - - struct sway_binding *current = NULL; - 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) || - (on_workspace && - (click_region & binding->flags) != click_region) || - (strcmp(binding->input, identifier) != 0 && - strcmp(binding->input, "*") != 0)) { - 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; - } - - if (!current || strcmp(current->input, "*") == 0) { - current = binding; - if (strcmp(current->input, identifier) == 0) { - // If a binding is found for the exact input, quit searching - break; - } - } - } - return current; + cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); + transaction_commit_dirty(); } void dispatch_cursor_button(struct sway_cursor *cursor, @@ -601,318 +288,33 @@ void dispatch_cursor_button(struct sway_cursor *cursor, if (time_msec == 0) { time_msec = get_current_time_msec(); } - struct sway_seat *seat = cursor->seat; - // Handle existing seat operation - if (seat_doing_seatop(seat)) { - if (state == WLR_BUTTON_PRESSED) { - state_add_button(cursor, button); - } else { - state_erase_button(cursor, button); - } - seatop_button(seat, time_msec, device, button, state); - if (button == seat->seatop_button && state == WLR_BUTTON_RELEASED) { - seatop_finish(seat, time_msec); - } - return; - } - - // Determine what's under the cursor - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - struct sway_container *cont = node && node->type == N_CONTAINER ? - node->sway_container : NULL; - bool is_floating = cont && container_is_floating(cont); - bool is_floating_or_child = cont && container_is_floating_or_child(cont); - bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont); - enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE; - enum wlr_edges resize_edge = edge ? - find_resize_edge(cont, cursor) : WLR_EDGE_NONE; - bool on_border = edge != WLR_EDGE_NONE; - bool on_contents = cont && !on_border && surface; - bool on_workspace = node && node->type == N_WORKSPACE; - bool on_titlebar = cont && !on_border && !surface; - - // Handle mouse bindings - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; - - char *device_identifier = device ? input_device_get_identifier(device) - : strdup("*"); - 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, on_workspace, - device_identifier); - } else { - binding = get_active_mouse_binding(cursor, - config->current_mode->mouse_bindings, modifiers, true, - on_titlebar, on_border, on_contents, on_workspace, - device_identifier); - state_erase_button(cursor, button); - } - free(device_identifier); - if (binding) { - seat_execute_command(seat, binding); - return; - } - - // Handle clicking an empty workspace - if (node && node->type == N_WORKSPACE) { - seat_set_focus(seat, node); - return; - } - - // Handle clicking a layer surface - if (surface && wlr_surface_is_layer_surface(surface)) { - struct wlr_layer_surface_v1 *layer = - wlr_layer_surface_v1_from_wlr_surface(surface); - if (layer->current.keyboard_interactive) { - seat_set_focus_layer(seat, layer); - } - seat_pointer_notify_button(seat, time_msec, button, state); - return; - } - - // Handle tiling resize via border - if (cont && resize_edge && button == BTN_LEFT && - state == WLR_BUTTON_PRESSED && !is_floating) { - seat_set_focus_container(seat, cont); - seatop_begin_resize_tiling(seat, cont, button, edge); - return; - } - - // Handle tiling resize via mod - bool mod_pressed = keyboard && - (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); - if (cont && !is_floating_or_child && mod_pressed && - state == WLR_BUTTON_PRESSED) { - uint32_t btn_resize = config->floating_mod_inverse ? - BTN_LEFT : BTN_RIGHT; - if (button == btn_resize) { - edge = 0; - edge |= cursor->cursor->x > cont->x + cont->width / 2 ? - WLR_EDGE_RIGHT : WLR_EDGE_LEFT; - edge |= cursor->cursor->y > cont->y + cont->height / 2 ? - WLR_EDGE_BOTTOM : WLR_EDGE_TOP; - - const char *image = NULL; - if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) { - image = "nw-resize"; - } else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) { - image = "ne-resize"; - } else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) { - image = "se-resize"; - } else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) { - image = "sw-resize"; - } - cursor_set_image(seat->cursor, image, NULL); - seat_set_focus_container(seat, cont); - seatop_begin_resize_tiling(seat, cont, button, edge); - return; - } - } - - // Handle beginning floating move - if (cont && is_floating_or_child && !is_fullscreen_or_child && - state == WLR_BUTTON_PRESSED) { - uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; - if (button == btn_move && state == WLR_BUTTON_PRESSED && - (mod_pressed || on_titlebar)) { - while (cont->parent) { - cont = cont->parent; - } - seat_set_focus_container(seat, cont); - seatop_begin_move_floating(seat, cont, button); - return; - } - } - - // Handle beginning floating resize - if (cont && is_floating_or_child && !is_fullscreen_or_child && - state == WLR_BUTTON_PRESSED) { - // Via border - if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { - seatop_begin_resize_floating(seat, cont, button, resize_edge); - return; - } - - // Via mod+click - uint32_t btn_resize = config->floating_mod_inverse ? - BTN_LEFT : BTN_RIGHT; - if (mod_pressed && button == btn_resize) { - struct sway_container *floater = cont; - while (floater->parent) { - floater = floater->parent; - } - edge = 0; - edge |= cursor->cursor->x > floater->x + floater->width / 2 ? - WLR_EDGE_RIGHT : WLR_EDGE_LEFT; - edge |= cursor->cursor->y > floater->y + floater->height / 2 ? - WLR_EDGE_BOTTOM : WLR_EDGE_TOP; - seatop_begin_resize_floating(seat, floater, button, edge); - return; - } - } - - // Handle moving a tiling container - if (config->tiling_drag && (mod_pressed || on_titlebar) && - state == WLR_BUTTON_PRESSED && !is_floating_or_child && - cont && cont->fullscreen_mode == FULLSCREEN_NONE) { - struct sway_container *focus = seat_get_focused_container(seat); - bool focused = focus == cont || container_has_ancestor(focus, cont); - if (on_titlebar && !focused) { - node = seat_get_focus_inactive(seat, &cont->node); - seat_set_focus(seat, node); - } - - // If moving a container by it's title bar, use a threshold for the drag - if (!mod_pressed && config->tiling_drag_threshold > 0) { - seatop_begin_move_tiling_threshold(seat, cont, button); - } else { - seatop_begin_move_tiling(seat, cont, button); - } - return; - } - - // Handle mousedown on a container surface - if (surface && cont && state == WLR_BUTTON_PRESSED) { - seat_set_focus_container(seat, cont); - seatop_begin_down(seat, cont, time_msec, button, sx, sy); - seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED); - return; - } - - // Handle clicking a container surface or decorations - if (cont) { - node = seat_get_focus_inactive(seat, &cont->node); - seat_set_focus(seat, node); - seat_pointer_notify_button(seat, time_msec, button, state); - return; - } - - seat_pointer_notify_button(seat, time_msec, button, state); + seatop_button(cursor->seat, time_msec, device, button, state); } static void handle_cursor_button(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, button); struct wlr_event_pointer_button *event = data; cursor_handle_activity(cursor); + + if (event->state == WLR_BUTTON_PRESSED) { + cursor->pressed_button_count++; + } else { + if (cursor->pressed_button_count > 0) { + cursor->pressed_button_count--; + } else { + sway_log(SWAY_ERROR, "Pressed button count was wrong"); + } + } + dispatch_cursor_button(cursor, event->device, event->time_msec, event->button, event->state); transaction_commit_dirty(); } -static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) { - switch (event->orientation) { - case WLR_AXIS_ORIENTATION_VERTICAL: - return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; - case WLR_AXIS_ORIENTATION_HORIZONTAL: - return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT; - default: - sway_log(SWAY_DEBUG, "Unknown axis orientation"); - return 0; - } -} - void dispatch_cursor_axis(struct sway_cursor *cursor, struct wlr_event_pointer_axis *event) { - struct sway_seat *seat = cursor->seat; - struct sway_input_device *input_device = - event->device ? event->device->data : NULL; - struct input_config *ic = - input_device ? input_device_get_config(input_device) : NULL; - - // Determine what's under the cursor - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - struct sway_container *cont = node && node->type == N_CONTAINER ? - node->sway_container : NULL; - enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE; - bool on_border = edge != WLR_EDGE_NONE; - bool on_titlebar = cont && !on_border && !surface; - bool on_titlebar_border = cont && on_border && - cursor->cursor->y < cont->content_y; - bool on_contents = cont && !on_border && surface; - bool on_workspace = node && node->type == N_WORKSPACE; - float scroll_factor = - (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor; - - bool handled = false; - - // Gather information needed for mouse bindings - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; - struct wlr_input_device *device = - input_device ? input_device->wlr_device : NULL; - char *dev_id = device ? input_device_get_identifier(device) : strdup("*"); - uint32_t button = wl_axis_to_button(event); - - // Handle mouse bindings - x11 mouse buttons 4-7 - press event - struct sway_binding *binding = NULL; - state_add_button(cursor, button); - binding = get_active_mouse_binding(cursor, - config->current_mode->mouse_bindings, modifiers, false, - on_titlebar, on_border, on_contents, on_workspace, dev_id); - if (binding) { - seat_execute_command(seat, binding); - handled = true; - } - - // Scrolling on a tabbed or stacked title bar (handled as press event) - if (!handled && (on_titlebar || on_titlebar_border)) { - enum sway_container_layout layout = container_parent_layout(cont); - if (layout == L_TABBED || layout == L_STACKED) { - struct sway_node *tabcontainer = node_get_parent(node); - struct sway_node *active = - seat_get_active_tiling_child(seat, tabcontainer); - list_t *siblings = container_get_siblings(cont); - int desired = list_find(siblings, active->sway_container) + - round(scroll_factor * event->delta_discrete); - if (desired < 0) { - desired = 0; - } else if (desired >= siblings->length) { - desired = siblings->length - 1; - } - struct sway_node *old_focus = seat_get_focus(seat); - struct sway_container *new_sibling_con = siblings->items[desired]; - struct sway_node *new_sibling = &new_sibling_con->node; - struct sway_node *new_focus = - seat_get_focus_inactive(seat, new_sibling); - if (node_has_ancestor(old_focus, tabcontainer)) { - seat_set_focus(seat, new_focus); - } else { - // Scrolling when focus is not in the tabbed container at all - seat_set_raw_focus(seat, new_sibling); - seat_set_raw_focus(seat, new_focus); - seat_set_raw_focus(seat, old_focus); - } - handled = true; - } - } - - // Handle mouse bindings - x11 mouse buttons 4-7 - release event - binding = get_active_mouse_binding(cursor, - config->current_mode->mouse_bindings, modifiers, true, - on_titlebar, on_border, on_contents, on_workspace, dev_id); - state_erase_button(cursor, button); - if (binding) { - seat_execute_command(seat, binding); - handled = true; - } - free(dev_id); - - if (!handled) { - wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, - event->orientation, scroll_factor * event->delta, - round(scroll_factor * event->delta_discrete), event->source); - } + seatop_axis(cursor->seat, event); } static void handle_cursor_axis(struct wl_listener *listener, void *data) { @@ -1054,8 +456,16 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) { apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y); } - cursor_motion_absolute(cursor, event->time_msec, event->device, x, y); + double lx, ly; + wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, + x, y, &lx, &ly); + + double dx = lx - cursor->cursor->x; + double dy = ly - cursor->cursor->y; + + cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); + transaction_commit_dirty(); } static void handle_tool_tip(struct wl_listener *listener, void *data) { @@ -1142,7 +552,7 @@ static void handle_request_set_cursor(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, request_set_cursor); - if (seat_doing_seatop(cursor->seat)) { + if (!seatop_allows_set_cursor(cursor->seat)) { return; } struct wlr_seat_pointer_request_set_cursor_event *event = data; @@ -1257,7 +667,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { // input events wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); - cursor->motion.notify = handle_cursor_motion; + cursor->motion.notify = handle_cursor_motion_relative; wl_signal_add(&wlr_cursor->events.motion_absolute, &cursor->motion_absolute); diff --git a/sway/input/seat.c b/sway/input/seat.c index 2c9a85c49..2d3552753 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -365,7 +365,7 @@ static void handle_start_drag(struct wl_listener *listener, void *data) { wl_list_insert(&root->drag_icons, &icon->link); drag_icon_update_position(icon); - seatop_abort(seat); + seatop_begin_default(seat); } static void handle_request_set_selection(struct wl_listener *listener, @@ -461,6 +461,8 @@ struct sway_seat *seat_create(const char *seat_name) { wl_list_insert(&server.input->seats, &seat->link); + seatop_begin_default(seat); + return seat; } @@ -1175,7 +1177,6 @@ struct seat_config *seat_get_config_by_name(const char *name) { 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); } @@ -1206,12 +1207,8 @@ void seat_consider_warp_to_focus(struct sway_seat *seat) { } } -bool seat_doing_seatop(struct sway_seat *seat) { - return seat->seatop_impl != NULL; -} - void seatop_unref(struct sway_seat *seat, struct sway_container *con) { - if (seat->seatop_impl && seat->seatop_impl->unref) { + if (seat->seatop_impl->unref) { seat->seatop_impl->unref(seat, con); } } @@ -1219,29 +1216,33 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con) { void seatop_button(struct sway_seat *seat, uint32_t time_msec, struct wlr_input_device *device, uint32_t button, enum wlr_button_state state) { - if (seat->seatop_impl && seat->seatop_impl->button) { + if (seat->seatop_impl->button) { seat->seatop_impl->button(seat, time_msec, device, button, state); } } -void seatop_motion(struct sway_seat *seat, uint32_t time_msec) { - if (seat->seatop_impl && seat->seatop_impl->motion) { - seat->seatop_impl->motion(seat, time_msec); +void seatop_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy) { + if (seat->seatop_impl->motion) { + seat->seatop_impl->motion(seat, time_msec, dx, dy); } } -void seatop_finish(struct sway_seat *seat, uint32_t time_msec) { - if (seat->seatop_impl && seat->seatop_impl->finish) { - seat->seatop_impl->finish(seat, time_msec); +void seatop_axis(struct sway_seat *seat, struct wlr_event_pointer_axis *event) { + if (seat->seatop_impl->axis) { + seat->seatop_impl->axis(seat, event); } - free(seat->seatop_data); - seat->seatop_data = NULL; - seat->seatop_impl = NULL; } -void seatop_abort(struct sway_seat *seat) { - if (seat->seatop_impl && seat->seatop_impl->abort) { - seat->seatop_impl->abort(seat); +void seatop_rebase(struct sway_seat *seat, uint32_t time_msec) { + if (seat->seatop_impl->rebase) { + seat->seatop_impl->rebase(seat, time_msec); + } +} + +void seatop_end(struct sway_seat *seat) { + if (seat->seatop_impl && seat->seatop_impl->end) { + seat->seatop_impl->end(seat); } free(seat->seatop_data); seat->seatop_data = NULL; @@ -1250,7 +1251,11 @@ void seatop_abort(struct sway_seat *seat) { void seatop_render(struct sway_seat *seat, struct sway_output *output, pixman_region32_t *damage) { - if (seat->seatop_impl && seat->seatop_impl->render) { + if (seat->seatop_impl->render) { seat->seatop_impl->render(seat, output, damage); } } + +bool seatop_allows_set_cursor(struct sway_seat *seat) { + return seat->seatop_impl->allow_set_cursor; +} diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c new file mode 100644 index 000000000..fc785cda4 --- /dev/null +++ b/sway/input/seatop_default.c @@ -0,0 +1,629 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include "sway/input/cursor.h" +#include "sway/input/seat.h" +#include "sway/tree/view.h" +#include "log.h" + +struct seatop_default_event { + struct sway_node *previous_node; + uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; + size_t pressed_button_count; +}; + +/*-----------------------------------------\ + * Functions shared by multiple callbacks / + *---------------------------------------*/ + +/** + * Determine if the edge of the given container is on the edge of the + * workspace/output. + */ +static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { + enum sway_container_layout layout = L_NONE; + switch (edge) { + case WLR_EDGE_TOP: + case WLR_EDGE_BOTTOM: + layout = L_VERT; + break; + case WLR_EDGE_LEFT: + case WLR_EDGE_RIGHT: + layout = L_HORIZ; + break; + case WLR_EDGE_NONE: + sway_assert(false, "Never reached"); + return false; + } + + // Iterate the parents until we find one with the layout we want, + // then check if the child has siblings between it and the edge. + while (cont) { + if (container_parent_layout(cont) == layout) { + list_t *siblings = container_get_siblings(cont); + int index = list_find(siblings, cont); + if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { + return false; + } + if (index < siblings->length - 1 && + (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) { + return false; + } + } + cont = cont->parent; + } + return true; +} + +static enum wlr_edges find_edge(struct sway_container *cont, + struct sway_cursor *cursor) { + if (!cont->view) { + return WLR_EDGE_NONE; + } + if (cont->border == B_NONE || !cont->border_thickness || + cont->border == B_CSD) { + return WLR_EDGE_NONE; + } + + enum wlr_edges edge = 0; + if (cursor->cursor->x < cont->x + cont->border_thickness) { + edge |= WLR_EDGE_LEFT; + } + if (cursor->cursor->y < cont->y + cont->border_thickness) { + edge |= WLR_EDGE_TOP; + } + if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) { + edge |= WLR_EDGE_RIGHT; + } + if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) { + edge |= WLR_EDGE_BOTTOM; + } + + return edge; +} + +/** + * If the cursor is over a _resizable_ edge, return the edge. + * Edges that can't be resized are edges of the workspace. + */ +static enum wlr_edges find_resize_edge(struct sway_container *cont, + struct sway_cursor *cursor) { + enum wlr_edges edge = find_edge(cont, cursor); + if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) { + return WLR_EDGE_NONE; + } + return edge; +} + +/** + * 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( + struct seatop_default_event *e, list_t *bindings, uint32_t modifiers, + bool release, bool on_titlebar, bool on_border, bool on_content, + bool on_workspace, const char *identifier) { + uint32_t click_region = + ((on_titlebar || on_workspace) ? BINDING_TITLEBAR : 0) | + ((on_border || on_workspace) ? BINDING_BORDER : 0) | + ((on_content || on_workspace) ? BINDING_CONTENTS : 0); + + struct sway_binding *current = NULL; + for (int i = 0; i < bindings->length; ++i) { + struct sway_binding *binding = bindings->items[i]; + if (modifiers ^ binding->modifiers || + e->pressed_button_count != (size_t)binding->keys->length || + release != (binding->flags & BINDING_RELEASE) || + !(click_region & binding->flags) || + (on_workspace && + (click_region & binding->flags) != click_region) || + (strcmp(binding->input, identifier) != 0 && + strcmp(binding->input, "*") != 0)) { + continue; + } + + bool match = true; + for (size_t j = 0; j < e->pressed_button_count; j++) { + uint32_t key = *(uint32_t *)binding->keys->items[j]; + if (key != e->pressed_buttons[j]) { + match = false; + break; + } + } + if (!match) { + continue; + } + + if (!current || strcmp(current->input, "*") == 0) { + current = binding; + if (strcmp(current->input, identifier) == 0) { + // If a binding is found for the exact input, quit searching + break; + } + } + } + return current; +} + +/** + * Remove a button (and duplicates) from the sorted list of currently pressed + * buttons. + */ +static void state_erase_button(struct seatop_default_event *e, + uint32_t button) { + size_t j = 0; + for (size_t i = 0; i < e->pressed_button_count; ++i) { + if (i > j) { + e->pressed_buttons[j] = e->pressed_buttons[i]; + } + if (e->pressed_buttons[i] != button) { + ++j; + } + } + while (e->pressed_button_count > j) { + --e->pressed_button_count; + e->pressed_buttons[e->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 seatop_default_event *e, uint32_t button) { + if (e->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) { + return; + } + size_t i = 0; + while (i < e->pressed_button_count && e->pressed_buttons[i] < button) { + ++i; + } + size_t j = e->pressed_button_count; + while (j > i) { + e->pressed_buttons[j] = e->pressed_buttons[j - 1]; + --j; + } + e->pressed_buttons[i] = button; + e->pressed_button_count++; +} + +static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec, + struct sway_node *node, struct wlr_surface *surface, + double sx, double sy) { + // Handle cursor image + if (surface) { + // Reset cursor if switching between clients + struct wl_client *client = wl_resource_get_client(surface->resource); + if (client != cursor->image_client) { + cursor_set_image(cursor, "left_ptr", client); + } + } else if (node && node->type == N_CONTAINER) { + // Try a node's resize edge + enum wlr_edges edge = find_resize_edge(node->sway_container, cursor); + if (edge == WLR_EDGE_NONE) { + cursor_set_image(cursor, "left_ptr", NULL); + } else if (container_is_floating(node->sway_container)) { + cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); + } else { + if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { + cursor_set_image(cursor, "col-resize", NULL); + } else { + cursor_set_image(cursor, "row-resize", NULL); + } + } + } else { + cursor_set_image(cursor, "left_ptr", NULL); + } + + // Send pointer enter/leave + struct wlr_seat *wlr_seat = cursor->seat->wlr_seat; + if (surface) { + if (seat_is_input_allowed(cursor->seat, surface)) { + wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(wlr_seat, time_msec, sx, sy); + } + } else { + wlr_seat_pointer_clear_focus(wlr_seat); + } +} + +/*----------------------------------\ + * Functions used by handle_button / + *--------------------------------*/ + +static void handle_button(struct sway_seat *seat, uint32_t time_msec, + struct wlr_input_device *device, uint32_t button, + enum wlr_button_state state) { + struct seatop_default_event *e = seat->seatop_data; + struct sway_cursor *cursor = seat->cursor; + + // Determine what's under the cursor + struct wlr_surface *surface = NULL; + double sx, sy; + struct sway_node *node = node_at_coords(seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + struct sway_container *cont = node && node->type == N_CONTAINER ? + node->sway_container : NULL; + bool is_floating = cont && container_is_floating(cont); + bool is_floating_or_child = cont && container_is_floating_or_child(cont); + bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont); + enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE; + enum wlr_edges resize_edge = edge ? + find_resize_edge(cont, cursor) : WLR_EDGE_NONE; + bool on_border = edge != WLR_EDGE_NONE; + bool on_contents = cont && !on_border && surface; + bool on_workspace = node && node->type == N_WORKSPACE; + bool on_titlebar = cont && !on_border && !surface; + + // Handle mouse bindings + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); + uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; + + char *device_identifier = device ? input_device_get_identifier(device) + : strdup("*"); + struct sway_binding *binding = NULL; + if (state == WLR_BUTTON_PRESSED) { + state_add_button(e, button); + binding = get_active_mouse_binding(e, + config->current_mode->mouse_bindings, modifiers, false, + on_titlebar, on_border, on_contents, on_workspace, + device_identifier); + } else { + binding = get_active_mouse_binding(e, + config->current_mode->mouse_bindings, modifiers, true, + on_titlebar, on_border, on_contents, on_workspace, + device_identifier); + state_erase_button(e, button); + } + free(device_identifier); + if (binding) { + seat_execute_command(seat, binding); + return; + } + + // Handle clicking an empty workspace + if (node && node->type == N_WORKSPACE) { + seat_set_focus(seat, node); + return; + } + + // Handle clicking a layer surface + if (surface && wlr_surface_is_layer_surface(surface)) { + struct wlr_layer_surface_v1 *layer = + wlr_layer_surface_v1_from_wlr_surface(surface); + if (layer->current.keyboard_interactive) { + seat_set_focus_layer(seat, layer); + } + seat_pointer_notify_button(seat, time_msec, button, state); + return; + } + + // Handle tiling resize via border + if (cont && resize_edge && button == BTN_LEFT && + state == WLR_BUTTON_PRESSED && !is_floating) { + seat_set_focus_container(seat, cont); + seatop_begin_resize_tiling(seat, cont, edge); + return; + } + + // Handle tiling resize via mod + bool mod_pressed = keyboard && + (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); + if (cont && !is_floating_or_child && mod_pressed && + state == WLR_BUTTON_PRESSED) { + uint32_t btn_resize = config->floating_mod_inverse ? + BTN_LEFT : BTN_RIGHT; + if (button == btn_resize) { + edge = 0; + edge |= cursor->cursor->x > cont->x + cont->width / 2 ? + WLR_EDGE_RIGHT : WLR_EDGE_LEFT; + edge |= cursor->cursor->y > cont->y + cont->height / 2 ? + WLR_EDGE_BOTTOM : WLR_EDGE_TOP; + + const char *image = NULL; + if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) { + image = "nw-resize"; + } else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) { + image = "ne-resize"; + } else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) { + image = "se-resize"; + } else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) { + image = "sw-resize"; + } + cursor_set_image(seat->cursor, image, NULL); + seat_set_focus_container(seat, cont); + seatop_begin_resize_tiling(seat, cont, edge); + return; + } + } + + // Handle beginning floating move + if (cont && is_floating_or_child && !is_fullscreen_or_child && + state == WLR_BUTTON_PRESSED) { + uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; + if (button == btn_move && state == WLR_BUTTON_PRESSED && + (mod_pressed || on_titlebar)) { + while (cont->parent) { + cont = cont->parent; + } + seat_set_focus_container(seat, cont); + seatop_begin_move_floating(seat, cont); + return; + } + } + + // Handle beginning floating resize + if (cont && is_floating_or_child && !is_fullscreen_or_child && + state == WLR_BUTTON_PRESSED) { + // Via border + if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { + seatop_begin_resize_floating(seat, cont, resize_edge); + return; + } + + // Via mod+click + uint32_t btn_resize = config->floating_mod_inverse ? + BTN_LEFT : BTN_RIGHT; + if (mod_pressed && button == btn_resize) { + struct sway_container *floater = cont; + while (floater->parent) { + floater = floater->parent; + } + edge = 0; + edge |= cursor->cursor->x > floater->x + floater->width / 2 ? + WLR_EDGE_RIGHT : WLR_EDGE_LEFT; + edge |= cursor->cursor->y > floater->y + floater->height / 2 ? + WLR_EDGE_BOTTOM : WLR_EDGE_TOP; + seatop_begin_resize_floating(seat, floater, edge); + return; + } + } + + // Handle moving a tiling container + if (config->tiling_drag && (mod_pressed || on_titlebar) && + state == WLR_BUTTON_PRESSED && !is_floating_or_child && + cont && cont->fullscreen_mode == FULLSCREEN_NONE) { + struct sway_container *focus = seat_get_focused_container(seat); + bool focused = focus == cont || container_has_ancestor(focus, cont); + if (on_titlebar && !focused) { + node = seat_get_focus_inactive(seat, &cont->node); + seat_set_focus(seat, node); + } + + // If moving a container by it's title bar, use a threshold for the drag + if (!mod_pressed && config->tiling_drag_threshold > 0) { + seatop_begin_move_tiling_threshold(seat, cont); + } else { + seatop_begin_move_tiling(seat, cont); + } + return; + } + + // Handle mousedown on a container surface + if (surface && cont && state == WLR_BUTTON_PRESSED) { + seat_set_focus_container(seat, cont); + seatop_begin_down(seat, cont, time_msec, sx, sy); + seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED); + return; + } + + // Handle clicking a container surface or decorations + if (cont) { + node = seat_get_focus_inactive(seat, &cont->node); + seat_set_focus(seat, node); + seat_pointer_notify_button(seat, time_msec, button, state); + return; + } + + seat_pointer_notify_button(seat, time_msec, button, state); +} + +/*----------------------------------\ + * Functions used by handle_motion / + *--------------------------------*/ + +static void check_focus_follows_mouse(struct sway_seat *seat, + struct seatop_default_event *e, struct sway_node *hovered_node) { + struct sway_node *focus = seat_get_focus(seat); + + // If a workspace node is hovered (eg. in the gap area), only set focus if + // the workspace is on a different output to the previous focus. + if (focus && hovered_node->type == N_WORKSPACE) { + struct sway_output *focused_output = node_get_output(focus); + struct sway_output *hovered_output = node_get_output(hovered_node); + if (hovered_output != focused_output) { + seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node)); + } + return; + } + + if (node_is_view(hovered_node)) { + if (hovered_node != e->previous_node || + config->focus_follows_mouse == FOLLOWS_ALWAYS) { + seat_set_focus(seat, hovered_node); + } else { + // Focusing a tab which contains a split child + struct sway_node *next_focus = + seat_get_focus_inactive(seat, &root->node); + if (next_focus && node_is_view(next_focus) && + view_is_visible(next_focus->sway_container->view)) { + seat_set_focus(seat, next_focus); + } + } + } +} + +static void handle_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy) { + struct seatop_default_event *e = seat->seatop_data; + struct sway_cursor *cursor = seat->cursor; + + struct wlr_surface *surface = NULL; + double sx, sy; + struct sway_node *node = node_at_coords(seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + + if (node && config->focus_follows_mouse != FOLLOWS_NO) { + check_focus_follows_mouse(seat, e, node); + } + + cursor_do_rebase(cursor, time_msec, node, surface, sx, sy); + + struct sway_drag_icon *drag_icon; + wl_list_for_each(drag_icon, &root->drag_icons, link) { + if (drag_icon->seat == seat) { + drag_icon_update_position(drag_icon); + } + } + + e->previous_node = node; +} + +/*--------------------------------\ + * Functions used by handle_axis / + *------------------------------*/ + +static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) { + switch (event->orientation) { + case WLR_AXIS_ORIENTATION_VERTICAL: + return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; + case WLR_AXIS_ORIENTATION_HORIZONTAL: + return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT; + default: + sway_log(SWAY_DEBUG, "Unknown axis orientation"); + return 0; + } +} + +static void handle_axis(struct sway_seat *seat, + struct wlr_event_pointer_axis *event) { + struct sway_input_device *input_device = + event->device ? event->device->data : NULL; + struct input_config *ic = + input_device ? input_device_get_config(input_device) : NULL; + struct sway_cursor *cursor = seat->cursor; + struct seatop_default_event *e = seat->seatop_data; + + // Determine what's under the cursor + struct wlr_surface *surface = NULL; + double sx, sy; + struct sway_node *node = node_at_coords(seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + struct sway_container *cont = node && node->type == N_CONTAINER ? + node->sway_container : NULL; + enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE; + bool on_border = edge != WLR_EDGE_NONE; + bool on_titlebar = cont && !on_border && !surface; + bool on_titlebar_border = cont && on_border && + cursor->cursor->y < cont->content_y; + bool on_contents = cont && !on_border && surface; + bool on_workspace = node && node->type == N_WORKSPACE; + float scroll_factor = + (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor; + + bool handled = false; + + // Gather information needed for mouse bindings + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); + uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; + struct wlr_input_device *device = + input_device ? input_device->wlr_device : NULL; + char *dev_id = device ? input_device_get_identifier(device) : strdup("*"); + uint32_t button = wl_axis_to_button(event); + + // Handle mouse bindings - x11 mouse buttons 4-7 - press event + struct sway_binding *binding = NULL; + state_add_button(e, button); + binding = get_active_mouse_binding(e, config->current_mode->mouse_bindings, + modifiers, false, on_titlebar, on_border, on_contents, on_workspace, + dev_id); + if (binding) { + seat_execute_command(seat, binding); + handled = true; + } + + // Scrolling on a tabbed or stacked title bar (handled as press event) + if (!handled && (on_titlebar || on_titlebar_border)) { + enum sway_container_layout layout = container_parent_layout(cont); + if (layout == L_TABBED || layout == L_STACKED) { + struct sway_node *tabcontainer = node_get_parent(node); + struct sway_node *active = + seat_get_active_tiling_child(seat, tabcontainer); + list_t *siblings = container_get_siblings(cont); + int desired = list_find(siblings, active->sway_container) + + round(scroll_factor * event->delta_discrete); + if (desired < 0) { + desired = 0; + } else if (desired >= siblings->length) { + desired = siblings->length - 1; + } + struct sway_node *old_focus = seat_get_focus(seat); + struct sway_container *new_sibling_con = siblings->items[desired]; + struct sway_node *new_sibling = &new_sibling_con->node; + struct sway_node *new_focus = + seat_get_focus_inactive(seat, new_sibling); + if (node_has_ancestor(old_focus, tabcontainer)) { + seat_set_focus(seat, new_focus); + } else { + // Scrolling when focus is not in the tabbed container at all + seat_set_raw_focus(seat, new_sibling); + seat_set_raw_focus(seat, new_focus); + seat_set_raw_focus(seat, old_focus); + } + handled = true; + } + } + + // Handle mouse bindings - x11 mouse buttons 4-7 - release event + binding = get_active_mouse_binding(e, config->current_mode->mouse_bindings, + modifiers, true, on_titlebar, on_border, on_contents, on_workspace, + dev_id); + state_erase_button(e, button); + if (binding) { + seat_execute_command(seat, binding); + handled = true; + } + free(dev_id); + + if (!handled) { + wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, + event->orientation, scroll_factor * event->delta, + round(scroll_factor * event->delta_discrete), event->source); + } +} + +/*----------------------------------\ + * Functions used by handle_rebase / + *--------------------------------*/ + +static void handle_rebase(struct sway_seat *seat, uint32_t time_msec) { + struct seatop_default_event *e = seat->seatop_data; + struct sway_cursor *cursor = seat->cursor; + struct wlr_surface *surface = NULL; + double sx = 0.0, sy = 0.0; + e->previous_node = node_at_coords(seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + cursor_do_rebase(cursor, time_msec, e->previous_node, surface, sx, sy); +} + +static const struct sway_seatop_impl seatop_impl = { + .button = handle_button, + .motion = handle_motion, + .axis = handle_axis, + .rebase = handle_rebase, + .allow_set_cursor = true, +}; + +void seatop_begin_default(struct sway_seat *seat) { + seatop_end(seat); + + struct seatop_default_event *e = + calloc(1, sizeof(struct seatop_default_event)); + sway_assert(e, "Unable to allocate seatop_default_event"); + seat->seatop_impl = &seatop_impl; + seat->seatop_data = e; + + seatop_rebase(seat, 0); +} diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index fb2cf1d07..95ea7cbb2 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -3,21 +3,26 @@ #include "sway/input/cursor.h" #include "sway/input/seat.h" #include "sway/tree/view.h" +#include "log.h" struct seatop_down_event { struct sway_container *con; double ref_lx, ref_ly; // cursor's x/y at start of op double ref_con_lx, ref_con_ly; // container's x/y at start of op - bool moved; }; static void handle_button(struct sway_seat *seat, uint32_t time_msec, struct wlr_input_device *device, uint32_t button, enum wlr_button_state state) { seat_pointer_notify_button(seat, time_msec, button, state); + + if (seat->cursor->pressed_button_count == 0) { + seatop_begin_default(seat); + } } -static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { +static void handle_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy) { struct seatop_down_event *e = seat->seatop_data; struct sway_container *con = e->con; if (seat_is_input_allowed(seat, con->view->surface)) { @@ -27,49 +32,25 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { double sy = e->ref_con_ly + moved_y; wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); } - e->moved = true; -} - -static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_down_event *e = seat->seatop_data; - struct sway_cursor *cursor = seat->cursor; - // Set the cursor's previous coords to the x/y at the start of the - // operation, so the container change will be detected if using - // focus_follows_mouse and the cursor moved off the original container - // during the operation. - cursor->previous.x = e->ref_lx; - cursor->previous.y = e->ref_ly; - if (e->moved) { - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - cursor_send_pointer_motion(cursor, 0, node, surface, sx, sy); - } -} - -static void handle_abort(struct sway_seat *seat) { - cursor_set_image(seat->cursor, "left_ptr", NULL); } static void handle_unref(struct sway_seat *seat, struct sway_container *con) { struct seatop_down_event *e = seat->seatop_data; if (e->con == con) { - seatop_abort(seat); + seatop_begin_default(seat); } } static const struct sway_seatop_impl seatop_impl = { .button = handle_button, .motion = handle_motion, - .finish = handle_finish, - .abort = handle_abort, .unref = handle_unref, + .allow_set_cursor = true, }; void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, - uint32_t time_msec, uint32_t button, int sx, int sy) { - seatop_abort(seat); + uint32_t time_msec, int sx, int sy) { + seatop_end(seat); struct seatop_down_event *e = calloc(1, sizeof(struct seatop_down_event)); @@ -81,11 +62,9 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, e->ref_ly = seat->cursor->cursor->y; e->ref_con_lx = sx; e->ref_con_ly = sy; - e->moved = false; seat->seatop_impl = &seatop_impl; seat->seatop_data = e; - seat->seatop_button = button; container_raise_floating(con); } diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c index 8a48a9681..73e489642 100644 --- a/sway/input/seatop_move_floating.c +++ b/sway/input/seatop_move_floating.c @@ -8,45 +8,44 @@ struct seatop_move_floating_event { struct sway_container *con; }; -static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_move_floating_event *e = seat->seatop_data; - desktop_damage_whole_container(e->con); - container_floating_translate(e->con, - seat->cursor->cursor->x - seat->cursor->previous.x, - seat->cursor->cursor->y - seat->cursor->previous.y); - desktop_damage_whole_container(e->con); +static void handle_button(struct sway_seat *seat, uint32_t time_msec, + struct wlr_input_device *device, uint32_t button, + enum wlr_button_state state) { + if (seat->cursor->pressed_button_count == 0) { + struct seatop_move_floating_event *e = seat->seatop_data; + + // We "move" the container to its own location + // so it discovers its output again. + container_floating_move_to(e->con, e->con->x, e->con->y); + + seatop_begin_default(seat); + } } -static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { +static void handle_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy) { struct seatop_move_floating_event *e = seat->seatop_data; - - // We "move" the container to its own location - // so it discovers its output again. - container_floating_move_to(e->con, e->con->x, e->con->y); - cursor_set_image(seat->cursor, "left_ptr", NULL); -} - -static void handle_abort(struct sway_seat *seat) { - cursor_set_image(seat->cursor, "left_ptr", NULL); + desktop_damage_whole_container(e->con); + container_floating_translate(e->con, dx, dy); + desktop_damage_whole_container(e->con); } static void handle_unref(struct sway_seat *seat, struct sway_container *con) { struct seatop_move_floating_event *e = seat->seatop_data; if (e->con == con) { - seatop_abort(seat); + seatop_begin_default(seat); } } static const struct sway_seatop_impl seatop_impl = { + .button = handle_button, .motion = handle_motion, - .finish = handle_finish, - .abort = handle_abort, .unref = handle_unref, }; void seatop_begin_move_floating(struct sway_seat *seat, - struct sway_container *con, uint32_t button) { - seatop_abort(seat); + struct sway_container *con) { + seatop_end(seat); struct seatop_move_floating_event *e = calloc(1, sizeof(struct seatop_move_floating_event)); @@ -57,7 +56,6 @@ void seatop_begin_move_floating(struct sway_seat *seat, seat->seatop_impl = &seatop_impl; seat->seatop_data = e; - seat->seatop_button = button; container_raise_floating(con); diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 2904792bd..0a2480919 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -206,7 +206,8 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { desktop_damage_box(&e->drop_box); } -static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { +static void handle_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy) { struct seatop_move_tiling_event *e = seat->seatop_data; if (e->threshold_reached) { handle_motion_postthreshold(seat); @@ -215,10 +216,6 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { } } -static void handle_abort(struct sway_seat *seat) { - cursor_set_image(seat->cursor, "left_ptr", NULL); -} - static bool is_parallel(enum sway_container_layout layout, enum wlr_edges edge) { bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED; @@ -226,11 +223,17 @@ static bool is_parallel(enum sway_container_layout layout, return layout_is_horiz == edge_is_horiz; } -static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { +static void handle_button(struct sway_seat *seat, uint32_t time_msec, + struct wlr_input_device *device, uint32_t button, + enum wlr_button_state state) { + if (seat->cursor->pressed_button_count != 0) { + return; + } + struct seatop_move_tiling_event *e = seat->seatop_data; if (!e->target_node) { - handle_abort(seat); + seatop_begin_default(seat); return; } @@ -287,7 +290,7 @@ static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { arrange_workspace(new_ws); } - cursor_set_image(seat->cursor, "left_ptr", NULL); + seatop_begin_default(seat); } static void handle_unref(struct sway_seat *seat, struct sway_container *con) { @@ -296,21 +299,20 @@ static void handle_unref(struct sway_seat *seat, struct sway_container *con) { e->target_node = NULL; } if (e->con == con) { // The container being moved - seatop_abort(seat); + seatop_begin_default(seat); } } static const struct sway_seatop_impl seatop_impl = { + .button = handle_button, .motion = handle_motion, - .finish = handle_finish, - .abort = handle_abort, .unref = handle_unref, .render = handle_render, }; void seatop_begin_move_tiling_threshold(struct sway_seat *seat, - struct sway_container *con, uint32_t button) { - seatop_abort(seat); + struct sway_container *con) { + seatop_end(seat); struct seatop_move_tiling_event *e = calloc(1, sizeof(struct seatop_move_tiling_event)); @@ -323,14 +325,13 @@ void seatop_begin_move_tiling_threshold(struct sway_seat *seat, seat->seatop_impl = &seatop_impl; seat->seatop_data = e; - seat->seatop_button = button; container_raise_floating(con); } void seatop_begin_move_tiling(struct sway_seat *seat, - struct sway_container *con, uint32_t button) { - seatop_begin_move_tiling_threshold(seat, con, button); + struct sway_container *con) { + seatop_begin_move_tiling_threshold(seat, con); struct seatop_move_tiling_event *e = seat->seatop_data; if (e) { e->threshold_reached = true; diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c index 18c6db73b..b6950bbf3 100644 --- a/sway/input/seatop_resize_floating.c +++ b/sway/input/seatop_resize_floating.c @@ -17,7 +17,16 @@ struct seatop_resize_floating_event { double ref_con_lx, ref_con_ly; // container's x/y at start of op }; -static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { +static void handle_button(struct sway_seat *seat, uint32_t time_msec, + struct wlr_input_device *device, uint32_t button, + enum wlr_button_state state) { + if (seat->cursor->pressed_button_count == 0) { + seatop_begin_default(seat); + } +} + +static void handle_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy) { struct seatop_resize_floating_event *e = seat->seatop_data; struct sway_container *con = e->con; enum wlr_edges edge = e->edge; @@ -107,31 +116,22 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { arrange_container(con); } -static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { - cursor_set_image(seat->cursor, "left_ptr", NULL); -} - -static void handle_abort(struct sway_seat *seat) { - cursor_set_image(seat->cursor, "left_ptr", NULL); -} - static void handle_unref(struct sway_seat *seat, struct sway_container *con) { struct seatop_resize_floating_event *e = seat->seatop_data; if (e->con == con) { - seatop_abort(seat); + seatop_begin_default(seat); } } static const struct sway_seatop_impl seatop_impl = { + .button = handle_button, .motion = handle_motion, - .finish = handle_finish, - .abort = handle_abort, .unref = handle_unref, }; void seatop_begin_resize_floating(struct sway_seat *seat, - struct sway_container *con, uint32_t button, enum wlr_edges edge) { - seatop_abort(seat); + struct sway_container *con, enum wlr_edges edge) { + seatop_end(seat); struct seatop_resize_floating_event *e = calloc(1, sizeof(struct seatop_resize_floating_event)); @@ -154,7 +154,6 @@ void seatop_begin_resize_floating(struct sway_seat *seat, seat->seatop_impl = &seatop_impl; seat->seatop_data = e; - seat->seatop_button = button; container_raise_floating(con); diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c index db32065c7..6b705823a 100644 --- a/sway/input/seatop_resize_tiling.c +++ b/sway/input/seatop_resize_tiling.c @@ -19,7 +19,16 @@ struct seatop_resize_tiling_event { double v_con_orig_height; // height of the vertical ancestor at start }; -static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { +static void handle_button(struct sway_seat *seat, uint32_t time_msec, + struct wlr_input_device *device, uint32_t button, + enum wlr_button_state state) { + if (seat->cursor->pressed_button_count == 0) { + seatop_begin_default(seat); + } +} + +static void handle_motion(struct sway_seat *seat, uint32_t time_msec, + double dx, double dy) { struct seatop_resize_tiling_event *e = seat->seatop_data; int amount_x = 0; int amount_y = 0; @@ -49,31 +58,22 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { } } -static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { - cursor_set_image(seat->cursor, "left_ptr", NULL); -} - -static void handle_abort(struct sway_seat *seat) { - cursor_set_image(seat->cursor, "left_ptr", NULL); -} - static void handle_unref(struct sway_seat *seat, struct sway_container *con) { struct seatop_resize_tiling_event *e = seat->seatop_data; if (e->con == con) { - seatop_abort(seat); + seatop_begin_default(seat); } } static const struct sway_seatop_impl seatop_impl = { + .button = handle_button, .motion = handle_motion, - .finish = handle_finish, - .abort = handle_abort, .unref = handle_unref, }; void seatop_begin_resize_tiling(struct sway_seat *seat, - struct sway_container *con, uint32_t button, enum wlr_edges edge) { - seatop_abort(seat); + struct sway_container *con, enum wlr_edges edge) { + seatop_end(seat); struct seatop_resize_tiling_event *e = calloc(1, sizeof(struct seatop_resize_tiling_event)); @@ -105,5 +105,4 @@ void seatop_begin_resize_tiling(struct sway_seat *seat, seat->seatop_impl = &seatop_impl; seat->seatop_data = e; - seat->seatop_button = button; } diff --git a/sway/meson.build b/sway/meson.build index 293a4ed20..cb1f8e258 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -23,6 +23,7 @@ sway_sources = files( 'input/input-manager.c', 'input/seat.c', + 'input/seatop_default.c', 'input/seatop_down.c', 'input/seatop_move_floating.c', 'input/seatop_move_tiling.c',