aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2019-03-16 17:47:39 +1000
committerLibravatar Drew DeVault <sir@cmpwn.com>2019-03-17 10:02:04 -0600
commit7b9ae42331e49fea0f566fa7592855dee5da1991 (patch)
treeba03e7826af566f871580cd2a1ec344013cebd4f
parentReplace seatup allows_events with button callback (diff)
downloadsway-7b9ae42331e49fea0f566fa7592855dee5da1991.tar.gz
sway-7b9ae42331e49fea0f566fa7592855dee5da1991.tar.zst
sway-7b9ae42331e49fea0f566fa7592855dee5da1991.zip
Introduce default seatop
This introduces a `default` seat operation which is used when no mouse buttons are being held. This means there is now always a seat operation in progress. It allows us to separate `default` code from the standard cursor management code. The sway_seatop_impl struct has gained callbacks `axis`, `rebase` and `end`, and lost callbacks `finish` and `abort`. `axis` and `rebase` are only used by the default seatop. `end` is called when a seatop is being replaced by another one and allows the seatop to free any resources, though no seatop currently needs to do this. `finish` is no longer required, as each seatop can gracefully finish in their `button` callback. And `abort` is not needed, as calling `end` would achieve the same thing. The struct has also gained a bool named allow_set_cursor which allows the client to set a new cursor during `default` and `down` seatops. Seatops would previously store which button they were started with and stop when that button was released. This behaviour is changed so that it only ends once all buttons are released. So you can start a drag with $mod+left, then click and hold right, release left and it'll continue dragging while the right button is held. The motion callback now accepts dx and dy. Most seatops don't use this as they store the cursor position when the seatop is started and compare it with the current cursor position. This approach doesn't make sense for the default seatop though, hence why dx and dy are needed. The pressed_buttons array has been moved from the sway_cursor struct to the default seatop's data. This is only used for the default seatop to check bindings. The total pressed button count remains in the sway_cursor struct though, because all the other seatops check it to know if they should end. The `down` seatop no longer has a `moved` property. This was used to track if the cursor moved and to recheck focus_follows_mouse, but seems to work without it. The logic for focus_follows_mouse has been refactored. As part of this I've removed the call to wlr_seat_keyboard_has_grab as we don't appear to use keyboard grabs. The functions for handling relative motion, absolute motion and tool axis have been changed. Previously the handler functions were handle_cursor_motion, handle_cursor_motion_absolute and handle_tool_axis. The latter two both called cursor_motion_absolute. Both handle_cursor_motion and cursor_motion_absolute did very similar things. These are now simplified into three handlers and a single common function called cursor_motion. All three handlers call cursor_motion. As cursor_motion works with relative distances, the absolute and tool axis handlers convert them to relative first.
-rw-r--r--include/sway/input/cursor.h9
-rw-r--r--include/sway/input/seat.h44
-rw-r--r--sway/desktop/xdg_shell.c5
-rw-r--r--sway/desktop/xdg_shell_v6.c5
-rw-r--r--sway/desktop/xwayland.c5
-rw-r--r--sway/input/cursor.c680
-rw-r--r--sway/input/seat.c47
-rw-r--r--sway/input/seatop_default.c629
-rw-r--r--sway/input/seatop_down.c43
-rw-r--r--sway/input/seatop_move_floating.c42
-rw-r--r--sway/input/seatop_move_tiling.c33
-rw-r--r--sway/input/seatop_resize_floating.c29
-rw-r--r--sway/input/seatop_resize_tiling.c29
-rw-r--r--sway/meson.build1
14 files changed, 808 insertions, 793 deletions
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h
index 98eb4679..516718c9 100644
--- a/include/sway/input/cursor.h
+++ b/include/sway/input/cursor.h
@@ -52,8 +52,6 @@ struct sway_cursor {
52 struct wl_event_source *hide_source; 52 struct wl_event_source *hide_source;
53 bool hidden; 53 bool hidden;
54 54
55 // Mouse binding state
56 uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
57 size_t pressed_button_count; 55 size_t pressed_button_count;
58}; 56};
59 57
@@ -78,13 +76,6 @@ void cursor_handle_activity(struct sway_cursor *cursor);
78void cursor_unhide(struct sway_cursor *cursor); 76void cursor_unhide(struct sway_cursor *cursor);
79int cursor_get_timeout(struct sway_cursor *cursor); 77int cursor_get_timeout(struct sway_cursor *cursor);
80 78
81/**
82 * Like cursor_rebase, but also allows focus to change when the cursor enters a
83 * new container.
84 */
85void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
86 struct sway_node *node, struct wlr_surface *surface, double sx, double sy);
87
88void dispatch_cursor_button(struct sway_cursor *cursor, 79void dispatch_cursor_button(struct sway_cursor *cursor,
89 struct wlr_input_device *device, uint32_t time_msec, uint32_t button, 80 struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
90 enum wlr_button_state state); 81 enum wlr_button_state state);
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index ff4476d1..a5361e8c 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -12,12 +12,15 @@ struct sway_seatop_impl {
12 void (*button)(struct sway_seat *seat, uint32_t time_msec, 12 void (*button)(struct sway_seat *seat, uint32_t time_msec,
13 struct wlr_input_device *device, uint32_t button, 13 struct wlr_input_device *device, uint32_t button,
14 enum wlr_button_state state); 14 enum wlr_button_state state);
15 void (*motion)(struct sway_seat *seat, uint32_t time_msec); 15 void (*motion)(struct sway_seat *seat, uint32_t time_msec,
16 void (*finish)(struct sway_seat *seat, uint32_t time_msec); 16 double dx, double dy);
17 void (*abort)(struct sway_seat *seat); 17 void (*axis)(struct sway_seat *seat, struct wlr_event_pointer_axis *event);
18 void (*rebase)(struct sway_seat *seat, uint32_t time_msec);
19 void (*end)(struct sway_seat *seat);
18 void (*unref)(struct sway_seat *seat, struct sway_container *con); 20 void (*unref)(struct sway_seat *seat, struct sway_container *con);
19 void (*render)(struct sway_seat *seat, struct sway_output *output, 21 void (*render)(struct sway_seat *seat, struct sway_output *output,
20 pixman_region32_t *damage); 22 pixman_region32_t *damage);
23 bool allow_set_cursor;
21}; 24};
22 25
23struct sway_seat_device { 26struct sway_seat_device {
@@ -71,9 +74,7 @@ struct sway_seat {
71 // Seat operations (drag and resize) 74 // Seat operations (drag and resize)
72 const struct sway_seatop_impl *seatop_impl; 75 const struct sway_seatop_impl *seatop_impl;
73 void *seatop_data; 76 void *seatop_data;
74 uint32_t seatop_button;
75 77
76 uint32_t last_button;
77 uint32_t last_button_serial; 78 uint32_t last_button_serial;
78 79
79 struct wl_listener focus_destroy; 80 struct wl_listener focus_destroy;
@@ -188,23 +189,25 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
188 189
189void drag_icon_update_position(struct sway_drag_icon *icon); 190void drag_icon_update_position(struct sway_drag_icon *icon);
190 191
192void seatop_begin_default(struct sway_seat *seat);
193
191void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, 194void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
192 uint32_t time_msec, uint32_t button, int sx, int sy); 195 uint32_t time_msec, int sx, int sy);
193 196
194void seatop_begin_move_floating(struct sway_seat *seat, 197void seatop_begin_move_floating(struct sway_seat *seat,
195 struct sway_container *con, uint32_t button); 198 struct sway_container *con);
196 199
197void seatop_begin_move_tiling_threshold(struct sway_seat *seat, 200void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
198 struct sway_container *con, uint32_t button); 201 struct sway_container *con);
199 202
200void seatop_begin_move_tiling(struct sway_seat *seat, 203void seatop_begin_move_tiling(struct sway_seat *seat,
201 struct sway_container *con, uint32_t button); 204 struct sway_container *con);
202 205
203void seatop_begin_resize_floating(struct sway_seat *seat, 206void seatop_begin_resize_floating(struct sway_seat *seat,
204 struct sway_container *con, uint32_t button, enum wlr_edges edge); 207 struct sway_container *con, enum wlr_edges edge);
205 208
206void seatop_begin_resize_tiling(struct sway_seat *seat, 209void seatop_begin_resize_tiling(struct sway_seat *seat,
207 struct sway_container *con, uint32_t button, enum wlr_edges edge); 210 struct sway_container *con, enum wlr_edges edge);
208 211
209struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, 212struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat,
210 struct sway_workspace *workspace); 213 struct sway_workspace *workspace);
@@ -214,23 +217,24 @@ void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
214 217
215void seat_consider_warp_to_focus(struct sway_seat *seat); 218void seat_consider_warp_to_focus(struct sway_seat *seat);
216 219
217bool seat_doing_seatop(struct sway_seat *seat);
218
219void seatop_button(struct sway_seat *seat, uint32_t time_msec, 220void seatop_button(struct sway_seat *seat, uint32_t time_msec,
220 struct wlr_input_device *device, uint32_t button, 221 struct wlr_input_device *device, uint32_t button,
221 enum wlr_button_state state); 222 enum wlr_button_state state);
222 223
223void seatop_motion(struct sway_seat *seat, uint32_t time_msec);
224
225/** 224/**
226 * End a seatop and apply the affects. 225 * dx and dy are distances relative to previous position.
227 */ 226 */
228void seatop_finish(struct sway_seat *seat, uint32_t time_msec); 227void seatop_motion(struct sway_seat *seat, uint32_t time_msec,
228 double dx, double dy);
229
230void seatop_axis(struct sway_seat *seat, struct wlr_event_pointer_axis *event);
231
232void seatop_rebase(struct sway_seat *seat, uint32_t time_msec);
229 233
230/** 234/**
231 * End a seatop without applying the affects. 235 * End a seatop (ie. free any seatop specific resources).
232 */ 236 */
233void seatop_abort(struct sway_seat *seat); 237void seatop_end(struct sway_seat *seat);
234 238
235/** 239/**
236 * Instructs the seatop implementation to drop any references to the given 240 * 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);
246void seatop_render(struct sway_seat *seat, struct sway_output *output, 250void seatop_render(struct sway_seat *seat, struct sway_output *output,
247 pixman_region32_t *damage); 251 pixman_region32_t *damage);
248 252
253bool seatop_allows_set_cursor(struct sway_seat *seat);
254
249#endif 255#endif
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index c84ca111..ea5dcd16 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) {
355 struct wlr_xdg_toplevel_move_event *e = data; 355 struct wlr_xdg_toplevel_move_event *e = data;
356 struct sway_seat *seat = e->seat->seat->data; 356 struct sway_seat *seat = e->seat->seat->data;
357 if (e->serial == seat->last_button_serial) { 357 if (e->serial == seat->last_button_serial) {
358 seatop_begin_move_floating(seat, view->container, seat->last_button); 358 seatop_begin_move_floating(seat, view->container);
359 } 359 }
360} 360}
361 361
@@ -369,8 +369,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
369 struct wlr_xdg_toplevel_resize_event *e = data; 369 struct wlr_xdg_toplevel_resize_event *e = data;
370 struct sway_seat *seat = e->seat->seat->data; 370 struct sway_seat *seat = e->seat->seat->data;
371 if (e->serial == seat->last_button_serial) { 371 if (e->serial == seat->last_button_serial) {
372 seatop_begin_resize_floating(seat, view->container, 372 seatop_begin_resize_floating(seat, view->container, e->edges);
373 seat->last_button, e->edges);
374 } 373 }
375} 374}
376 375
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 3eed54ab..7ff4c4de 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) {
355 struct wlr_xdg_toplevel_v6_move_event *e = data; 355 struct wlr_xdg_toplevel_v6_move_event *e = data;
356 struct sway_seat *seat = e->seat->seat->data; 356 struct sway_seat *seat = e->seat->seat->data;
357 if (e->serial == seat->last_button_serial) { 357 if (e->serial == seat->last_button_serial) {
358 seatop_begin_move_floating(seat, view->container, seat->last_button); 358 seatop_begin_move_floating(seat, view->container);
359 } 359 }
360} 360}
361 361
@@ -369,8 +369,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
369 struct wlr_xdg_toplevel_v6_resize_event *e = data; 369 struct wlr_xdg_toplevel_v6_resize_event *e = data;
370 struct sway_seat *seat = e->seat->seat->data; 370 struct sway_seat *seat = e->seat->seat->data;
371 if (e->serial == seat->last_button_serial) { 371 if (e->serial == seat->last_button_serial) {
372 seatop_begin_resize_floating(seat, view->container, 372 seatop_begin_resize_floating(seat, view->container, e->edges);
373 seat->last_button, e->edges);
374 } 373 }
375} 374}
376 375
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index a2aa2e08..f5ade8dc 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) {
476 return; 476 return;
477 } 477 }
478 struct sway_seat *seat = input_manager_current_seat(); 478 struct sway_seat *seat = input_manager_current_seat();
479 seatop_begin_move_floating(seat, view->container, seat->last_button); 479 seatop_begin_move_floating(seat, view->container);
480} 480}
481 481
482static void handle_request_resize(struct wl_listener *listener, void *data) { 482static 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) {
492 } 492 }
493 struct wlr_xwayland_resize_event *e = data; 493 struct wlr_xwayland_resize_event *e = data;
494 struct sway_seat *seat = input_manager_current_seat(); 494 struct sway_seat *seat = input_manager_current_seat();
495 seatop_begin_resize_floating(seat, view->container, 495 seatop_begin_resize_floating(seat, view->container, e->edges);
496 seat->last_button, e->edges);
497} 496}
498 497
499static void handle_request_activate(struct wl_listener *listener, void *data) { 498static void handle_request_activate(struct wl_listener *listener, void *data) {
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 011b4929..61084447 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -158,132 +158,9 @@ struct sway_node *node_at_coords(
158 return &ws->node; 158 return &ws->node;
159} 159}
160 160
161/**
162 * Determine if the edge of the given container is on the edge of the
163 * workspace/output.
164 */
165static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
166 enum sway_container_layout layout = L_NONE;
167 switch (edge) {
168 case WLR_EDGE_TOP:
169 case WLR_EDGE_BOTTOM:
170 layout = L_VERT;
171 break;
172 case WLR_EDGE_LEFT:
173 case WLR_EDGE_RIGHT:
174 layout = L_HORIZ;
175 break;
176 case WLR_EDGE_NONE:
177 sway_assert(false, "Never reached");
178 return false;
179 }
180
181 // Iterate the parents until we find one with the layout we want,
182 // then check if the child has siblings between it and the edge.
183 while (cont) {
184 if (container_parent_layout(cont) == layout) {
185 list_t *siblings = container_get_siblings(cont);
186 int index = list_find(siblings, cont);
187 if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) {
188 return false;
189 }
190 if (index < siblings->length - 1 &&
191 (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) {
192 return false;
193 }
194 }
195 cont = cont->parent;
196 }
197 return true;
198}
199
200static enum wlr_edges find_edge(struct sway_container *cont,
201 struct sway_cursor *cursor) {
202 if (!cont->view) {
203 return WLR_EDGE_NONE;
204 }
205 if (cont->border == B_NONE || !cont->border_thickness ||
206 cont->border == B_CSD) {
207 return WLR_EDGE_NONE;
208 }
209
210 enum wlr_edges edge = 0;
211 if (cursor->cursor->x < cont->x + cont->border_thickness) {
212 edge |= WLR_EDGE_LEFT;
213 }
214 if (cursor->cursor->y < cont->y + cont->border_thickness) {
215 edge |= WLR_EDGE_TOP;
216 }
217 if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) {
218 edge |= WLR_EDGE_RIGHT;
219 }
220 if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) {
221 edge |= WLR_EDGE_BOTTOM;
222 }
223
224 return edge;
225}
226
227/**
228 * If the cursor is over a _resizable_ edge, return the edge.
229 * Edges that can't be resized are edges of the workspace.
230 */
231static enum wlr_edges find_resize_edge(struct sway_container *cont,
232 struct sway_cursor *cursor) {
233 enum wlr_edges edge = find_edge(cont, cursor);
234 if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) {
235 return WLR_EDGE_NONE;
236 }
237 return edge;
238}
239
240static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec,
241 struct sway_node *node, struct wlr_surface *surface,
242 double sx, double sy) {
243 // Handle cursor image
244 if (surface) {
245 // Reset cursor if switching between clients
246 struct wl_client *client = wl_resource_get_client(surface->resource);
247 if (client != cursor->image_client) {
248 cursor_set_image(cursor, "left_ptr", client);
249 }
250 } else if (node && node->type == N_CONTAINER) {
251 // Try a node's resize edge
252 enum wlr_edges edge = find_resize_edge(node->sway_container, cursor);
253 if (edge == WLR_EDGE_NONE) {
254 cursor_set_image(cursor, "left_ptr", NULL);
255 } else if (container_is_floating(node->sway_container)) {
256 cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
257 } else {
258 if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
259 cursor_set_image(cursor, "col-resize", NULL);
260 } else {
261 cursor_set_image(cursor, "row-resize", NULL);
262 }
263 }
264 } else {
265 cursor_set_image(cursor, "left_ptr", NULL);
266 }
267
268 // Send pointer enter/leave
269 struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
270 if (surface) {
271 if (seat_is_input_allowed(cursor->seat, surface)) {
272 wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
273 wlr_seat_pointer_notify_motion(wlr_seat, time_msec, sx, sy);
274 }
275 } else {
276 wlr_seat_pointer_clear_focus(wlr_seat);
277 }
278}
279
280void cursor_rebase(struct sway_cursor *cursor) { 161void cursor_rebase(struct sway_cursor *cursor) {
281 uint32_t time_msec = get_current_time_msec(); 162 uint32_t time_msec = get_current_time_msec();
282 struct wlr_surface *surface = NULL; 163 seatop_rebase(cursor->seat, time_msec);
283 double sx = 0.0, sy = 0.0;
284 cursor->previous.node = node_at_coords(cursor->seat,
285 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
286 cursor_do_rebase(cursor, time_msec, cursor->previous.node, surface, sx, sy);
287} 164}
288 165
289void cursor_rebase_all(void) { 166void cursor_rebase_all(void) {
@@ -293,9 +170,7 @@ void cursor_rebase_all(void) {
293 170
294 struct sway_seat *seat; 171 struct sway_seat *seat;
295 wl_list_for_each(seat, &server.input->seats, link) { 172 wl_list_for_each(seat, &server.input->seats, link) {
296 if (!seat_doing_seatop(seat)) { 173 cursor_rebase(seat->cursor);
297 cursor_rebase(seat->cursor);
298 }
299 } 174 }
300} 175}
301 176
@@ -345,90 +220,17 @@ void cursor_unhide(struct sway_cursor *cursor) {
345 cursor_rebase(cursor); 220 cursor_rebase(cursor);
346} 221}
347 222
348void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, 223static void cursor_motion(struct sway_cursor *cursor, uint32_t time_msec,
349 struct sway_node *node, struct wlr_surface *surface, 224 struct wlr_input_device *device, double dx, double dy,
350 double sx, double sy) { 225 double dx_unaccel, double dy_unaccel) {
351 if (time_msec == 0) {
352 time_msec = get_current_time_msec();
353 }
354
355 struct sway_seat *seat = cursor->seat;
356
357 if (seat_doing_seatop(seat)) {
358 seatop_motion(seat, time_msec);
359 cursor->previous.x = cursor->cursor->x;
360 cursor->previous.y = cursor->cursor->y;
361 return;
362 }
363
364 struct sway_node *prev_node = cursor->previous.node;
365
366 // Update the stored previous position
367 cursor->previous.x = cursor->cursor->x;
368 cursor->previous.y = cursor->cursor->y;
369 cursor->previous.node = node;
370
371 if (node && (config->focus_follows_mouse == FOLLOWS_YES ||
372 config->focus_follows_mouse == FOLLOWS_ALWAYS)) {
373 struct sway_node *focus = seat_get_focus(seat);
374 if (focus && node->type == N_WORKSPACE) {
375 // Only follow the mouse if it would move to a new output
376 // Otherwise we'll focus the workspace, which is probably wrong
377 struct sway_output *focused_output = node_get_output(focus);
378 struct sway_output *output = node_get_output(node);
379 if (output != focused_output) {
380 seat_set_focus(seat, seat_get_focus_inactive(seat, node));
381 }
382 } else if (node->type == N_CONTAINER && node->sway_container->view) {
383 // Focus node if the following are true:
384 // - cursor is over a new view, i.e. entered a new window; and
385 // - the new view is visible, i.e. not hidden in a stack or tab; and
386 // - the seat does not have a keyboard grab
387 if ((!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
388 node != prev_node &&
389 view_is_visible(node->sway_container->view)) ||
390 config->focus_follows_mouse == FOLLOWS_ALWAYS) {
391 seat_set_focus(seat, node);
392 } else {
393 struct sway_node *next_focus =
394 seat_get_focus_inactive(seat, &root->node);
395 if (next_focus && next_focus->type == N_CONTAINER &&
396 next_focus->sway_container->view &&
397 view_is_visible(next_focus->sway_container->view)) {
398 seat_set_focus(seat, next_focus);
399 }
400 }
401 }
402 }
403
404 cursor_do_rebase(cursor, time_msec, node, surface, sx, sy);
405
406 struct sway_drag_icon *drag_icon;
407 wl_list_for_each(drag_icon, &root->drag_icons, link) {
408 if (drag_icon->seat == seat) {
409 drag_icon_update_position(drag_icon);
410 }
411 }
412}
413
414static void handle_cursor_motion(struct wl_listener *listener, void *data) {
415 struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
416 struct wlr_event_pointer_motion *event = data;
417 cursor_handle_activity(cursor); 226 cursor_handle_activity(cursor);
418 227
419 double dx = event->delta_x;
420 double dy = event->delta_y;
421
422 double dx_unaccel = event->unaccel_dx;
423 double dy_unaccel = event->unaccel_dy;
424
425 wlr_relative_pointer_manager_v1_send_relative_motion( 228 wlr_relative_pointer_manager_v1_send_relative_motion(
426 server.relative_pointer_manager, 229 server.relative_pointer_manager,
427 cursor->seat->wlr_seat, (uint64_t)event->time_msec * 1000, 230 cursor->seat->wlr_seat, (uint64_t)time_msec * 1000,
428 dx, dy, dx_unaccel, dy_unaccel); 231 dx, dy, dx_unaccel, dy_unaccel);
429 232
430 struct wlr_surface *surface = NULL; 233 struct wlr_surface *surface = NULL;
431 struct sway_node *node = NULL;
432 double sx, sy; 234 double sx, sy;
433 if (cursor->active_constraint) { 235 if (cursor->active_constraint) {
434 node_at_coords(cursor->seat, 236 node_at_coords(cursor->seat,
@@ -448,50 +250,18 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
448 dy = sy_confined - sy; 250 dy = sy_confined - sy;
449 } 251 }
450 252
451 wlr_cursor_move(cursor->cursor, event->device, dx, dy); 253 wlr_cursor_move(cursor->cursor, device, dx, dy);
452
453 // Recalculate pointer location after layout checks
454 node = node_at_coords(cursor->seat,
455 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
456 254
457 cursor_send_pointer_motion(cursor, event->time_msec, node, surface, 255 seatop_motion(cursor->seat, time_msec, dx, dy);
458 sx, sy);
459 transaction_commit_dirty();
460} 256}
461 257
462static void cursor_motion_absolute(struct sway_cursor *cursor, 258static void handle_cursor_motion_relative(
463 uint32_t time_msec, struct wlr_input_device *dev, 259 struct wl_listener *listener, void *data) {
464 double x, double y) { 260 struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
465 cursor_handle_activity(cursor); 261 struct wlr_event_pointer_motion *e = data;
466
467 double lx, ly;
468 wlr_cursor_absolute_to_layout_coords(cursor->cursor, dev,
469 x, y, &lx, &ly);
470
471 double dx = lx - cursor->cursor->x;
472 double dy = ly - cursor->cursor->y;
473 wlr_relative_pointer_manager_v1_send_relative_motion(
474 server.relative_pointer_manager,
475 cursor->seat->wlr_seat, (uint64_t)time_msec * 1000,
476 dx, dy, dx, dy);
477
478 struct wlr_surface *surface = NULL;
479 double sx = 0.0, sy = 0.0;
480 struct sway_node *node = node_at_coords(cursor->seat,
481 lx, ly, &surface, &sx, &sy);
482
483 if (cursor->active_constraint) {
484 if (cursor->active_constraint->surface != surface) {
485 return;
486 }
487 if (!pixman_region32_contains_point(&cursor->confine,
488 floor(sx), floor(sy), NULL)) {
489 return;
490 }
491 }
492 262
493 wlr_cursor_warp_closest(cursor->cursor, dev, lx, ly); 263 cursor_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y,
494 cursor_send_pointer_motion(cursor, time_msec, node, surface, sx, sy); 264 e->unaccel_dx, e->unaccel_dy);
495 transaction_commit_dirty(); 265 transaction_commit_dirty();
496} 266}
497 267
@@ -501,98 +271,15 @@ static void handle_cursor_motion_absolute(
501 wl_container_of(listener, cursor, motion_absolute); 271 wl_container_of(listener, cursor, motion_absolute);
502 struct wlr_event_pointer_motion_absolute *event = data; 272 struct wlr_event_pointer_motion_absolute *event = data;
503 273
504 cursor_motion_absolute(cursor, event->time_msec, event->device, 274 double lx, ly;
505 event->x, event->y); 275 wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
506} 276 event->x, event->y, &lx, &ly);
507
508/**
509 * Remove a button (and duplicates) to the sorted list of currently pressed buttons
510 */
511static void state_erase_button(struct sway_cursor *cursor, uint32_t button) {
512 size_t j = 0;
513 for (size_t i = 0; i < cursor->pressed_button_count; ++i) {
514 if (i > j) {
515 cursor->pressed_buttons[j] = cursor->pressed_buttons[i];
516 }
517 if (cursor->pressed_buttons[i] != button) {
518 ++j;
519 }
520 }
521 while (cursor->pressed_button_count > j) {
522 --cursor->pressed_button_count;
523 cursor->pressed_buttons[cursor->pressed_button_count] = 0;
524 }
525}
526
527/**
528 * Add a button to the sorted list of currently pressed buttons, if there
529 * is space.
530 */
531static void state_add_button(struct sway_cursor *cursor, uint32_t button) {
532 if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) {
533 return;
534 }
535 size_t i = 0;
536 while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) {
537 ++i;
538 }
539 size_t j = cursor->pressed_button_count;
540 while (j > i) {
541 cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1];
542 --j;
543 }
544 cursor->pressed_buttons[i] = button;
545 cursor->pressed_button_count++;
546}
547
548/**
549 * Return the mouse binding which matches modifier, click location, release,
550 * and pressed button state, otherwise return null.
551 */
552static struct sway_binding* get_active_mouse_binding(
553 const struct sway_cursor *cursor, list_t *bindings, uint32_t modifiers,
554 bool release, bool on_titlebar, bool on_border, bool on_content,
555 bool on_workspace, const char *identifier) {
556 uint32_t click_region =
557 ((on_titlebar || on_workspace) ? BINDING_TITLEBAR : 0) |
558 ((on_border || on_workspace) ? BINDING_BORDER : 0) |
559 ((on_content || on_workspace) ? BINDING_CONTENTS : 0);
560
561 struct sway_binding *current = NULL;
562 for (int i = 0; i < bindings->length; ++i) {
563 struct sway_binding *binding = bindings->items[i];
564 if (modifiers ^ binding->modifiers ||
565 cursor->pressed_button_count != (size_t)binding->keys->length ||
566 release != (binding->flags & BINDING_RELEASE) ||
567 !(click_region & binding->flags) ||
568 (on_workspace &&
569 (click_region & binding->flags) != click_region) ||
570 (strcmp(binding->input, identifier) != 0 &&
571 strcmp(binding->input, "*") != 0)) {
572 continue;
573 }
574 277
575 bool match = true; 278 double dx = lx - cursor->cursor->x;
576 for (size_t j = 0; j < cursor->pressed_button_count; j++) { 279 double dy = ly - cursor->cursor->y;
577 uint32_t key = *(uint32_t *)binding->keys->items[j];
578 if (key != cursor->pressed_buttons[j]) {
579 match = false;
580 break;
581 }
582 }
583 if (!match) {
584 continue;
585 }
586 280
587 if (!current || strcmp(current->input, "*") == 0) { 281 cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
588 current = binding; 282 transaction_commit_dirty();
589 if (strcmp(current->input, identifier) == 0) {
590 // If a binding is found for the exact input, quit searching
591 break;
592 }
593 }
594 }
595 return current;
596} 283}
597 284
598void dispatch_cursor_button(struct sway_cursor *cursor, 285void dispatch_cursor_button(struct sway_cursor *cursor,
@@ -601,318 +288,33 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
601 if (time_msec == 0) { 288 if (time_msec == 0) {
602 time_msec = get_current_time_msec(); 289 time_msec = get_current_time_msec();
603 } 290 }
604 struct sway_seat *seat = cursor->seat;
605 291
606 // Handle existing seat operation 292 seatop_button(cursor->seat, time_msec, device, button, state);
607 if (seat_doing_seatop(seat)) {
608 if (state == WLR_BUTTON_PRESSED) {
609 state_add_button(cursor, button);
610 } else {
611 state_erase_button(cursor, button);
612 }
613 seatop_button(seat, time_msec, device, button, state);
614 if (button == seat->seatop_button && state == WLR_BUTTON_RELEASED) {
615 seatop_finish(seat, time_msec);
616 }
617 return;
618 }
619
620 // Determine what's under the cursor
621 struct wlr_surface *surface = NULL;
622 double sx, sy;
623 struct sway_node *node = node_at_coords(seat,
624 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
625 struct sway_container *cont = node && node->type == N_CONTAINER ?
626 node->sway_container : NULL;
627 bool is_floating = cont && container_is_floating(cont);
628 bool is_floating_or_child = cont && container_is_floating_or_child(cont);
629 bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont);
630 enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
631 enum wlr_edges resize_edge = edge ?
632 find_resize_edge(cont, cursor) : WLR_EDGE_NONE;
633 bool on_border = edge != WLR_EDGE_NONE;
634 bool on_contents = cont && !on_border && surface;
635 bool on_workspace = node && node->type == N_WORKSPACE;
636 bool on_titlebar = cont && !on_border && !surface;
637
638 // Handle mouse bindings
639 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
640 uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
641
642 char *device_identifier = device ? input_device_get_identifier(device)
643 : strdup("*");
644 struct sway_binding *binding = NULL;
645 if (state == WLR_BUTTON_PRESSED) {
646 state_add_button(cursor, button);
647 binding = get_active_mouse_binding(cursor,
648 config->current_mode->mouse_bindings, modifiers, false,
649 on_titlebar, on_border, on_contents, on_workspace,
650 device_identifier);
651 } else {
652 binding = get_active_mouse_binding(cursor,
653 config->current_mode->mouse_bindings, modifiers, true,
654 on_titlebar, on_border, on_contents, on_workspace,
655 device_identifier);
656 state_erase_button(cursor, button);
657 }
658 free(device_identifier);
659 if (binding) {
660 seat_execute_command(seat, binding);
661 return;
662 }
663
664 // Handle clicking an empty workspace
665 if (node && node->type == N_WORKSPACE) {
666 seat_set_focus(seat, node);
667 return;
668 }
669
670 // Handle clicking a layer surface
671 if (surface && wlr_surface_is_layer_surface(surface)) {
672 struct wlr_layer_surface_v1 *layer =
673 wlr_layer_surface_v1_from_wlr_surface(surface);
674 if (layer->current.keyboard_interactive) {
675 seat_set_focus_layer(seat, layer);
676 }
677 seat_pointer_notify_button(seat, time_msec, button, state);
678 return;
679 }
680
681 // Handle tiling resize via border
682 if (cont && resize_edge && button == BTN_LEFT &&
683 state == WLR_BUTTON_PRESSED && !is_floating) {
684 seat_set_focus_container(seat, cont);
685 seatop_begin_resize_tiling(seat, cont, button, edge);
686 return;
687 }
688
689 // Handle tiling resize via mod
690 bool mod_pressed = keyboard &&
691 (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod);
692 if (cont && !is_floating_or_child && mod_pressed &&
693 state == WLR_BUTTON_PRESSED) {
694 uint32_t btn_resize = config->floating_mod_inverse ?
695 BTN_LEFT : BTN_RIGHT;
696 if (button == btn_resize) {
697 edge = 0;
698 edge |= cursor->cursor->x > cont->x + cont->width / 2 ?
699 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
700 edge |= cursor->cursor->y > cont->y + cont->height / 2 ?
701 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
702
703 const char *image = NULL;
704 if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) {
705 image = "nw-resize";
706 } else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) {
707 image = "ne-resize";
708 } else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) {
709 image = "se-resize";
710 } else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) {
711 image = "sw-resize";
712 }
713 cursor_set_image(seat->cursor, image, NULL);
714 seat_set_focus_container(seat, cont);
715 seatop_begin_resize_tiling(seat, cont, button, edge);
716 return;
717 }
718 }
719
720 // Handle beginning floating move
721 if (cont && is_floating_or_child && !is_fullscreen_or_child &&
722 state == WLR_BUTTON_PRESSED) {
723 uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
724 if (button == btn_move && state == WLR_BUTTON_PRESSED &&
725 (mod_pressed || on_titlebar)) {
726 while (cont->parent) {
727 cont = cont->parent;
728 }
729 seat_set_focus_container(seat, cont);
730 seatop_begin_move_floating(seat, cont, button);
731 return;
732 }
733 }
734
735 // Handle beginning floating resize
736 if (cont && is_floating_or_child && !is_fullscreen_or_child &&
737 state == WLR_BUTTON_PRESSED) {
738 // Via border
739 if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
740 seatop_begin_resize_floating(seat, cont, button, resize_edge);
741 return;
742 }
743
744 // Via mod+click
745 uint32_t btn_resize = config->floating_mod_inverse ?
746 BTN_LEFT : BTN_RIGHT;
747 if (mod_pressed && button == btn_resize) {
748 struct sway_container *floater = cont;
749 while (floater->parent) {
750 floater = floater->parent;
751 }
752 edge = 0;
753 edge |= cursor->cursor->x > floater->x + floater->width / 2 ?
754 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
755 edge |= cursor->cursor->y > floater->y + floater->height / 2 ?
756 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
757 seatop_begin_resize_floating(seat, floater, button, edge);
758 return;
759 }
760 }
761
762 // Handle moving a tiling container
763 if (config->tiling_drag && (mod_pressed || on_titlebar) &&
764 state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
765 cont && cont->fullscreen_mode == FULLSCREEN_NONE) {
766 struct sway_container *focus = seat_get_focused_container(seat);
767 bool focused = focus == cont || container_has_ancestor(focus, cont);
768 if (on_titlebar && !focused) {
769 node = seat_get_focus_inactive(seat, &cont->node);
770 seat_set_focus(seat, node);
771 }
772
773 // If moving a container by it's title bar, use a threshold for the drag
774 if (!mod_pressed && config->tiling_drag_threshold > 0) {
775 seatop_begin_move_tiling_threshold(seat, cont, button);
776 } else {
777 seatop_begin_move_tiling(seat, cont, button);
778 }
779 return;
780 }
781
782 // Handle mousedown on a container surface
783 if (surface && cont && state == WLR_BUTTON_PRESSED) {
784 seat_set_focus_container(seat, cont);
785 seatop_begin_down(seat, cont, time_msec, button, sx, sy);
786 seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
787 return;
788 }
789
790 // Handle clicking a container surface or decorations
791 if (cont) {
792 node = seat_get_focus_inactive(seat, &cont->node);
793 seat_set_focus(seat, node);
794 seat_pointer_notify_button(seat, time_msec, button, state);
795 return;
796 }
797
798 seat_pointer_notify_button(seat, time_msec, button, state);
799} 293}
800 294
801static void handle_cursor_button(struct wl_listener *listener, void *data) { 295static void handle_cursor_button(struct wl_listener *listener, void *data) {
802 struct sway_cursor *cursor = wl_container_of(listener, cursor, button); 296 struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
803 struct wlr_event_pointer_button *event = data; 297 struct wlr_event_pointer_button *event = data;
804 cursor_handle_activity(cursor); 298 cursor_handle_activity(cursor);
299
300 if (event->state == WLR_BUTTON_PRESSED) {
301 cursor->pressed_button_count++;
302 } else {
303 if (cursor->pressed_button_count > 0) {
304 cursor->pressed_button_count--;
305 } else {
306 sway_log(SWAY_ERROR, "Pressed button count was wrong");
307 }
308 }
309
805 dispatch_cursor_button(cursor, event->device, 310 dispatch_cursor_button(cursor, event->device,
806 event->time_msec, event->button, event->state); 311 event->time_msec, event->button, event->state);
807 transaction_commit_dirty(); 312 transaction_commit_dirty();
808} 313}
809 314
810static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
811 switch (event->orientation) {
812 case WLR_AXIS_ORIENTATION_VERTICAL:
813 return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
814 case WLR_AXIS_ORIENTATION_HORIZONTAL:
815 return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT;
816 default:
817 sway_log(SWAY_DEBUG, "Unknown axis orientation");
818 return 0;
819 }
820}
821
822void dispatch_cursor_axis(struct sway_cursor *cursor, 315void dispatch_cursor_axis(struct sway_cursor *cursor,
823 struct wlr_event_pointer_axis *event) { 316 struct wlr_event_pointer_axis *event) {
824 struct sway_seat *seat = cursor->seat; 317 seatop_axis(cursor->seat, event);
825 struct sway_input_device *input_device =
826 event->device ? event->device->data : NULL;
827 struct input_config *ic =
828 input_device ? input_device_get_config(input_device) : NULL;
829
830 // Determine what's under the cursor
831 struct wlr_surface *surface = NULL;
832 double sx, sy;
833 struct sway_node *node = node_at_coords(seat,
834 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
835 struct sway_container *cont = node && node->type == N_CONTAINER ?
836 node->sway_container : NULL;
837 enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
838 bool on_border = edge != WLR_EDGE_NONE;
839 bool on_titlebar = cont && !on_border && !surface;
840 bool on_titlebar_border = cont && on_border &&
841 cursor->cursor->y < cont->content_y;
842 bool on_contents = cont && !on_border && surface;
843 bool on_workspace = node && node->type == N_WORKSPACE;
844 float scroll_factor =
845 (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor;
846
847 bool handled = false;
848
849 // Gather information needed for mouse bindings
850 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
851 uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
852 struct wlr_input_device *device =
853 input_device ? input_device->wlr_device : NULL;
854 char *dev_id = device ? input_device_get_identifier(device) : strdup("*");
855 uint32_t button = wl_axis_to_button(event);
856
857 // Handle mouse bindings - x11 mouse buttons 4-7 - press event
858 struct sway_binding *binding = NULL;
859 state_add_button(cursor, button);
860 binding = get_active_mouse_binding(cursor,
861 config->current_mode->mouse_bindings, modifiers, false,
862 on_titlebar, on_border, on_contents, on_workspace, dev_id);
863 if (binding) {
864 seat_execute_command(seat, binding);
865 handled = true;
866 }
867
868 // Scrolling on a tabbed or stacked title bar (handled as press event)
869 if (!handled && (on_titlebar || on_titlebar_border)) {
870 enum sway_container_layout layout = container_parent_layout(cont);
871 if (layout == L_TABBED || layout == L_STACKED) {
872 struct sway_node *tabcontainer = node_get_parent(node);
873 struct sway_node *active =
874 seat_get_active_tiling_child(seat, tabcontainer);
875 list_t *siblings = container_get_siblings(cont);
876 int desired = list_find(siblings, active->sway_container) +
877 round(scroll_factor * event->delta_discrete);
878 if (desired < 0) {
879 desired = 0;
880 } else if (desired >= siblings->length) {
881 desired = siblings->length - 1;
882 }
883 struct sway_node *old_focus = seat_get_focus(seat);
884 struct sway_container *new_sibling_con = siblings->items[desired];
885 struct sway_node *new_sibling = &new_sibling_con->node;
886 struct sway_node *new_focus =
887 seat_get_focus_inactive(seat, new_sibling);
888 if (node_has_ancestor(old_focus, tabcontainer)) {
889 seat_set_focus(seat, new_focus);
890 } else {
891 // Scrolling when focus is not in the tabbed container at all
892 seat_set_raw_focus(seat, new_sibling);
893 seat_set_raw_focus(seat, new_focus);
894 seat_set_raw_focus(seat, old_focus);
895 }
896 handled = true;
897 }
898 }
899
900 // Handle mouse bindings - x11 mouse buttons 4-7 - release event
901 binding = get_active_mouse_binding(cursor,
902 config->current_mode->mouse_bindings, modifiers, true,
903 on_titlebar, on_border, on_contents, on_workspace, dev_id);
904 state_erase_button(cursor, button);
905 if (binding) {
906 seat_execute_command(seat, binding);
907 handled = true;
908 }
909 free(dev_id);
910
911 if (!handled) {
912 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
913 event->orientation, scroll_factor * event->delta,
914 round(scroll_factor * event->delta_discrete), event->source);
915 }
916} 318}
917 319
918static void handle_cursor_axis(struct wl_listener *listener, void *data) { 320static 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) {
1054 apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y); 456 apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y);
1055 } 457 }
1056 458
1057 cursor_motion_absolute(cursor, event->time_msec, event->device, x, y); 459 double lx, ly;
460 wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
461 x, y, &lx, &ly);
462
463 double dx = lx - cursor->cursor->x;
464 double dy = ly - cursor->cursor->y;
465
466 cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
1058 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 467 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
468 transaction_commit_dirty();
1059} 469}
1060 470
1061static void handle_tool_tip(struct wl_listener *listener, void *data) { 471static void handle_tool_tip(struct wl_listener *listener, void *data) {
@@ -1142,7 +552,7 @@ static void handle_request_set_cursor(struct wl_listener *listener,
1142 void *data) { 552 void *data) {
1143 struct sway_cursor *cursor = 553 struct sway_cursor *cursor =
1144 wl_container_of(listener, cursor, request_set_cursor); 554 wl_container_of(listener, cursor, request_set_cursor);
1145 if (seat_doing_seatop(cursor->seat)) { 555 if (!seatop_allows_set_cursor(cursor->seat)) {
1146 return; 556 return;
1147 } 557 }
1148 struct wlr_seat_pointer_request_set_cursor_event *event = data; 558 struct wlr_seat_pointer_request_set_cursor_event *event = data;
@@ -1257,7 +667,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
1257 667
1258 // input events 668 // input events
1259 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); 669 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
1260 cursor->motion.notify = handle_cursor_motion; 670 cursor->motion.notify = handle_cursor_motion_relative;
1261 671
1262 wl_signal_add(&wlr_cursor->events.motion_absolute, 672 wl_signal_add(&wlr_cursor->events.motion_absolute,
1263 &cursor->motion_absolute); 673 &cursor->motion_absolute);
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 2c9a85c4..2d355275 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) {
365 wl_list_insert(&root->drag_icons, &icon->link); 365 wl_list_insert(&root->drag_icons, &icon->link);
366 366
367 drag_icon_update_position(icon); 367 drag_icon_update_position(icon);
368 seatop_abort(seat); 368 seatop_begin_default(seat);
369} 369}
370 370
371static void handle_request_set_selection(struct wl_listener *listener, 371static void handle_request_set_selection(struct wl_listener *listener,
@@ -461,6 +461,8 @@ struct sway_seat *seat_create(const char *seat_name) {
461 461
462 wl_list_insert(&server.input->seats, &seat->link); 462 wl_list_insert(&server.input->seats, &seat->link);
463 463
464 seatop_begin_default(seat);
465
464 return seat; 466 return seat;
465} 467}
466 468
@@ -1175,7 +1177,6 @@ struct seat_config *seat_get_config_by_name(const char *name) {
1175 1177
1176void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, 1178void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
1177 uint32_t button, enum wlr_button_state state) { 1179 uint32_t button, enum wlr_button_state state) {
1178 seat->last_button = button;
1179 seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat, 1180 seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat,
1180 time_msec, button, state); 1181 time_msec, button, state);
1181} 1182}
@@ -1206,12 +1207,8 @@ void seat_consider_warp_to_focus(struct sway_seat *seat) {
1206 } 1207 }
1207} 1208}
1208 1209
1209bool seat_doing_seatop(struct sway_seat *seat) {
1210 return seat->seatop_impl != NULL;
1211}
1212
1213void seatop_unref(struct sway_seat *seat, struct sway_container *con) { 1210void seatop_unref(struct sway_seat *seat, struct sway_container *con) {
1214 if (seat->seatop_impl && seat->seatop_impl->unref) { 1211 if (seat->seatop_impl->unref) {
1215 seat->seatop_impl->unref(seat, con); 1212 seat->seatop_impl->unref(seat, con);
1216 } 1213 }
1217} 1214}
@@ -1219,29 +1216,33 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con) {
1219void seatop_button(struct sway_seat *seat, uint32_t time_msec, 1216void seatop_button(struct sway_seat *seat, uint32_t time_msec,
1220 struct wlr_input_device *device, uint32_t button, 1217 struct wlr_input_device *device, uint32_t button,
1221 enum wlr_button_state state) { 1218 enum wlr_button_state state) {
1222 if (seat->seatop_impl && seat->seatop_impl->button) { 1219 if (seat->seatop_impl->button) {
1223 seat->seatop_impl->button(seat, time_msec, device, button, state); 1220 seat->seatop_impl->button(seat, time_msec, device, button, state);
1224 } 1221 }
1225} 1222}
1226 1223
1227void seatop_motion(struct sway_seat *seat, uint32_t time_msec) { 1224void seatop_motion(struct sway_seat *seat, uint32_t time_msec,
1228 if (seat->seatop_impl && seat->seatop_impl->motion) { 1225 double dx, double dy) {
1229 seat->seatop_impl->motion(seat, time_msec); 1226 if (seat->seatop_impl->motion) {
1227 seat->seatop_impl->motion(seat, time_msec, dx, dy);
1230 } 1228 }
1231} 1229}
1232 1230
1233void seatop_finish(struct sway_seat *seat, uint32_t time_msec) { 1231void seatop_axis(struct sway_seat *seat, struct wlr_event_pointer_axis *event) {
1234 if (seat->seatop_impl && seat->seatop_impl->finish) { 1232 if (seat->seatop_impl->axis) {
1235 seat->seatop_impl->finish(seat, time_msec); 1233 seat->seatop_impl->axis(seat, event);
1236 } 1234 }
1237 free(seat->seatop_data);
1238 seat->seatop_data = NULL;
1239 seat->seatop_impl = NULL;
1240} 1235}
1241 1236
1242void seatop_abort(struct sway_seat *seat) { 1237void seatop_rebase(struct sway_seat *seat, uint32_t time_msec) {
1243 if (seat->seatop_impl && seat->seatop_impl->abort) { 1238 if (seat->seatop_impl->rebase) {
1244 seat->seatop_impl->abort(seat); 1239 seat->seatop_impl->rebase(seat, time_msec);
1240 }
1241}
1242
1243void seatop_end(struct sway_seat *seat) {
1244 if (seat->seatop_impl && seat->seatop_impl->end) {
1245 seat->seatop_impl->end(seat);
1245 } 1246 }
1246 free(seat->seatop_data); 1247 free(seat->seatop_data);
1247 seat->seatop_data = NULL; 1248 seat->seatop_data = NULL;
@@ -1250,7 +1251,11 @@ void seatop_abort(struct sway_seat *seat) {
1250 1251
1251void seatop_render(struct sway_seat *seat, struct sway_output *output, 1252void seatop_render(struct sway_seat *seat, struct sway_output *output,
1252 pixman_region32_t *damage) { 1253 pixman_region32_t *damage) {
1253 if (seat->seatop_impl && seat->seatop_impl->render) { 1254 if (seat->seatop_impl->render) {
1254 seat->seatop_impl->render(seat, output, damage); 1255 seat->seatop_impl->render(seat, output, damage);
1255 } 1256 }
1256} 1257}
1258
1259bool seatop_allows_set_cursor(struct sway_seat *seat) {
1260 return seat->seatop_impl->allow_set_cursor;
1261}
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c
new file mode 100644
index 00000000..fc785cda
--- /dev/null
+++ b/sway/input/seatop_default.c
@@ -0,0 +1,629 @@
1#define _POSIX_C_SOURCE 200809L
2#include <float.h>
3#include <libevdev/libevdev.h>
4#include <wlr/types/wlr_cursor.h>
5#include <wlr/types/wlr_xcursor_manager.h>
6#include "sway/input/cursor.h"
7#include "sway/input/seat.h"
8#include "sway/tree/view.h"
9#include "log.h"
10
11struct seatop_default_event {
12 struct sway_node *previous_node;
13 uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
14 size_t pressed_button_count;
15};
16
17/*-----------------------------------------\
18 * Functions shared by multiple callbacks /
19 *---------------------------------------*/
20
21/**
22 * Determine if the edge of the given container is on the edge of the
23 * workspace/output.
24 */
25static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
26 enum sway_container_layout layout = L_NONE;
27 switch (edge) {
28 case WLR_EDGE_TOP:
29 case WLR_EDGE_BOTTOM:
30 layout = L_VERT;
31 break;
32 case WLR_EDGE_LEFT:
33 case WLR_EDGE_RIGHT:
34 layout = L_HORIZ;
35 break;
36 case WLR_EDGE_NONE:
37 sway_assert(false, "Never reached");
38 return false;
39 }
40
41 // Iterate the parents until we find one with the layout we want,
42 // then check if the child has siblings between it and the edge.
43 while (cont) {
44 if (container_parent_layout(cont) == layout) {
45 list_t *siblings = container_get_siblings(cont);
46 int index = list_find(siblings, cont);
47 if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) {
48 return false;
49 }
50 if (index < siblings->length - 1 &&
51 (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) {
52 return false;
53 }
54 }
55 cont = cont->parent;
56 }
57 return true;
58}
59
60static enum wlr_edges find_edge(struct sway_container *cont,
61 struct sway_cursor *cursor) {
62 if (!cont->view) {
63 return WLR_EDGE_NONE;
64 }
65 if (cont->border == B_NONE || !cont->border_thickness ||
66 cont->border == B_CSD) {
67 return WLR_EDGE_NONE;
68 }
69
70 enum wlr_edges edge = 0;
71 if (cursor->cursor->x < cont->x + cont->border_thickness) {
72 edge |= WLR_EDGE_LEFT;
73 }
74 if (cursor->cursor->y < cont->y + cont->border_thickness) {
75 edge |= WLR_EDGE_TOP;
76 }
77 if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) {
78 edge |= WLR_EDGE_RIGHT;
79 }
80 if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) {
81 edge |= WLR_EDGE_BOTTOM;
82 }
83
84 return edge;
85}
86
87/**
88 * If the cursor is over a _resizable_ edge, return the edge.
89 * Edges that can't be resized are edges of the workspace.
90 */
91static enum wlr_edges find_resize_edge(struct sway_container *cont,
92 struct sway_cursor *cursor) {
93 enum wlr_edges edge = find_edge(cont, cursor);
94 if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) {
95 return WLR_EDGE_NONE;
96 }
97 return edge;
98}
99
100/**
101 * Return the mouse binding which matches modifier, click location, release,
102 * and pressed button state, otherwise return null.
103 */
104static struct sway_binding* get_active_mouse_binding(
105 struct seatop_default_event *e, list_t *bindings, uint32_t modifiers,
106 bool release, bool on_titlebar, bool on_border, bool on_content,
107 bool on_workspace, const char *identifier) {
108 uint32_t click_region =
109 ((on_titlebar || on_workspace) ? BINDING_TITLEBAR : 0) |
110 ((on_border || on_workspace) ? BINDING_BORDER : 0) |
111 ((on_content || on_workspace) ? BINDING_CONTENTS : 0);
112
113 struct sway_binding *current = NULL;
114 for (int i = 0; i < bindings->length; ++i) {
115 struct sway_binding *binding = bindings->items[i];
116 if (modifiers ^ binding->modifiers ||
117 e->pressed_button_count != (size_t)binding->keys->length ||
118 release != (binding->flags & BINDING_RELEASE) ||
119 !(click_region & binding->flags) ||
120 (on_workspace &&
121 (click_region & binding->flags) != click_region) ||
122 (strcmp(binding->input, identifier) != 0 &&
123 strcmp(binding->input, "*") != 0)) {
124 continue;
125 }
126
127 bool match = true;
128 for (size_t j = 0; j < e->pressed_button_count; j++) {
129 uint32_t key = *(uint32_t *)binding->keys->items[j];
130 if (key != e->pressed_buttons[j]) {
131 match = false;
132 break;
133 }
134 }
135 if (!match) {
136 continue;
137 }
138
139 if (!current || strcmp(current->input, "*") == 0) {
140 current = binding;
141 if (strcmp(current->input, identifier) == 0) {
142 // If a binding is found for the exact input, quit searching
143 break;
144 }
145 }
146 }
147 return current;
148}
149
150/**
151 * Remove a button (and duplicates) from the sorted list of currently pressed
152 * buttons.
153 */
154static void state_erase_button(struct seatop_default_event *e,
155 uint32_t button) {
156 size_t j = 0;
157 for (size_t i = 0; i < e->pressed_button_count; ++i) {
158 if (i > j) {
159 e->pressed_buttons[j] = e->pressed_buttons[i];
160 }
161 if (e->pressed_buttons[i] != button) {
162 ++j;
163 }
164 }
165 while (e->pressed_button_count > j) {
166 --e->pressed_button_count;
167 e->pressed_buttons[e->pressed_button_count] = 0;
168 }
169}
170
171/**
172 * Add a button to the sorted list of currently pressed buttons, if there
173 * is space.
174 */
175static void state_add_button(struct seatop_default_event *e, uint32_t button) {
176 if (e->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) {
177 return;
178 }
179 size_t i = 0;
180 while (i < e->pressed_button_count && e->pressed_buttons[i] < button) {
181 ++i;
182 }
183 size_t j = e->pressed_button_count;
184 while (j > i) {
185 e->pressed_buttons[j] = e->pressed_buttons[j - 1];
186 --j;
187 }
188 e->pressed_buttons[i] = button;
189 e->pressed_button_count++;
190}
191
192static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec,
193 struct sway_node *node, struct wlr_surface *surface,
194 double sx, double sy) {
195 // Handle cursor image
196 if (surface) {
197 // Reset cursor if switching between clients
198 struct wl_client *client = wl_resource_get_client(surface->resource);
199 if (client != cursor->image_client) {
200 cursor_set_image(cursor, "left_ptr", client);
201 }
202 } else if (node && node->type == N_CONTAINER) {
203 // Try a node's resize edge
204 enum wlr_edges edge = find_resize_edge(node->sway_container, cursor);
205 if (edge == WLR_EDGE_NONE) {
206 cursor_set_image(cursor, "left_ptr", NULL);
207 } else if (container_is_floating(node->sway_container)) {
208 cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
209 } else {
210 if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
211 cursor_set_image(cursor, "col-resize", NULL);
212 } else {
213 cursor_set_image(cursor, "row-resize", NULL);
214 }
215 }
216 } else {
217 cursor_set_image(cursor, "left_ptr", NULL);
218 }
219
220 // Send pointer enter/leave
221 struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
222 if (surface) {
223 if (seat_is_input_allowed(cursor->seat, surface)) {
224 wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
225 wlr_seat_pointer_notify_motion(wlr_seat, time_msec, sx, sy);
226 }
227 } else {
228 wlr_seat_pointer_clear_focus(wlr_seat);
229 }
230}
231
232/*----------------------------------\
233 * Functions used by handle_button /
234 *--------------------------------*/
235
236static void handle_button(struct sway_seat *seat, uint32_t time_msec,
237 struct wlr_input_device *device, uint32_t button,
238 enum wlr_button_state state) {
239 struct seatop_default_event *e = seat->seatop_data;
240 struct sway_cursor *cursor = seat->cursor;
241
242 // Determine what's under the cursor
243 struct wlr_surface *surface = NULL;
244 double sx, sy;
245 struct sway_node *node = node_at_coords(seat,
246 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
247 struct sway_container *cont = node && node->type == N_CONTAINER ?
248 node->sway_container : NULL;
249 bool is_floating = cont && container_is_floating(cont);
250 bool is_floating_or_child = cont && container_is_floating_or_child(cont);
251 bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont);
252 enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
253 enum wlr_edges resize_edge = edge ?
254 find_resize_edge(cont, cursor) : WLR_EDGE_NONE;
255 bool on_border = edge != WLR_EDGE_NONE;
256 bool on_contents = cont && !on_border && surface;
257 bool on_workspace = node && node->type == N_WORKSPACE;
258 bool on_titlebar = cont && !on_border && !surface;
259
260 // Handle mouse bindings
261 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
262 uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
263
264 char *device_identifier = device ? input_device_get_identifier(device)
265 : strdup("*");
266 struct sway_binding *binding = NULL;
267 if (state == WLR_BUTTON_PRESSED) {
268 state_add_button(e, button);
269 binding = get_active_mouse_binding(e,
270 config->current_mode->mouse_bindings, modifiers, false,
271 on_titlebar, on_border, on_contents, on_workspace,
272 device_identifier);
273 } else {
274 binding = get_active_mouse_binding(e,
275 config->current_mode->mouse_bindings, modifiers, true,
276 on_titlebar, on_border, on_contents, on_workspace,
277 device_identifier);
278 state_erase_button(e, button);
279 }
280 free(device_identifier);
281 if (binding) {
282 seat_execute_command(seat, binding);
283 return;
284 }
285
286 // Handle clicking an empty workspace
287 if (node && node->type == N_WORKSPACE) {
288 seat_set_focus(seat, node);
289 return;
290 }
291
292 // Handle clicking a layer surface
293 if (surface && wlr_surface_is_layer_surface(surface)) {
294 struct wlr_layer_surface_v1 *layer =
295 wlr_layer_surface_v1_from_wlr_surface(surface);
296 if (layer->current.keyboard_interactive) {
297 seat_set_focus_layer(seat, layer);
298 }
299 seat_pointer_notify_button(seat, time_msec, button, state);
300 return;
301 }
302
303 // Handle tiling resize via border
304 if (cont && resize_edge && button == BTN_LEFT &&
305 state == WLR_BUTTON_PRESSED && !is_floating) {
306 seat_set_focus_container(seat, cont);
307 seatop_begin_resize_tiling(seat, cont, edge);
308 return;
309 }
310
311 // Handle tiling resize via mod
312 bool mod_pressed = keyboard &&
313 (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod);
314 if (cont && !is_floating_or_child && mod_pressed &&
315 state == WLR_BUTTON_PRESSED) {
316 uint32_t btn_resize = config->floating_mod_inverse ?
317 BTN_LEFT : BTN_RIGHT;
318 if (button == btn_resize) {
319 edge = 0;
320 edge |= cursor->cursor->x > cont->x + cont->width / 2 ?
321 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
322 edge |= cursor->cursor->y > cont->y + cont->height / 2 ?
323 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
324
325 const char *image = NULL;
326 if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) {
327 image = "nw-resize";
328 } else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) {
329 image = "ne-resize";
330 } else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) {
331 image = "se-resize";
332 } else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) {
333 image = "sw-resize";
334 }
335 cursor_set_image(seat->cursor, image, NULL);
336 seat_set_focus_container(seat, cont);
337 seatop_begin_resize_tiling(seat, cont, edge);
338 return;
339 }
340 }
341
342 // Handle beginning floating move
343 if (cont && is_floating_or_child && !is_fullscreen_or_child &&
344 state == WLR_BUTTON_PRESSED) {
345 uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
346 if (button == btn_move && state == WLR_BUTTON_PRESSED &&
347 (mod_pressed || on_titlebar)) {
348 while (cont->parent) {
349 cont = cont->parent;
350 }
351 seat_set_focus_container(seat, cont);
352 seatop_begin_move_floating(seat, cont);
353 return;
354 }
355 }
356
357 // Handle beginning floating resize
358 if (cont && is_floating_or_child && !is_fullscreen_or_child &&
359 state == WLR_BUTTON_PRESSED) {
360 // Via border
361 if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
362 seatop_begin_resize_floating(seat, cont, resize_edge);
363 return;
364 }
365
366 // Via mod+click
367 uint32_t btn_resize = config->floating_mod_inverse ?
368 BTN_LEFT : BTN_RIGHT;
369 if (mod_pressed && button == btn_resize) {
370 struct sway_container *floater = cont;
371 while (floater->parent) {
372 floater = floater->parent;
373 }
374 edge = 0;
375 edge |= cursor->cursor->x > floater->x + floater->width / 2 ?
376 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
377 edge |= cursor->cursor->y > floater->y + floater->height / 2 ?
378 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
379 seatop_begin_resize_floating(seat, floater, edge);
380 return;
381 }
382 }
383
384 // Handle moving a tiling container
385 if (config->tiling_drag && (mod_pressed || on_titlebar) &&
386 state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
387 cont && cont->fullscreen_mode == FULLSCREEN_NONE) {
388 struct sway_container *focus = seat_get_focused_container(seat);
389 bool focused = focus == cont || container_has_ancestor(focus, cont);
390 if (on_titlebar && !focused) {
391 node = seat_get_focus_inactive(seat, &cont->node);
392 seat_set_focus(seat, node);
393 }
394
395 // If moving a container by it's title bar, use a threshold for the drag
396 if (!mod_pressed && config->tiling_drag_threshold > 0) {
397 seatop_begin_move_tiling_threshold(seat, cont);
398 } else {
399 seatop_begin_move_tiling(seat, cont);
400 }
401 return;
402 }
403
404 // Handle mousedown on a container surface
405 if (surface && cont && state == WLR_BUTTON_PRESSED) {
406 seat_set_focus_container(seat, cont);
407 seatop_begin_down(seat, cont, time_msec, sx, sy);
408 seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
409 return;
410 }
411
412 // Handle clicking a container surface or decorations
413 if (cont) {
414 node = seat_get_focus_inactive(seat, &cont->node);
415 seat_set_focus(seat, node);
416 seat_pointer_notify_button(seat, time_msec, button, state);
417 return;
418 }
419
420 seat_pointer_notify_button(seat, time_msec, button, state);
421}
422
423/*----------------------------------\
424 * Functions used by handle_motion /
425 *--------------------------------*/
426
427static void check_focus_follows_mouse(struct sway_seat *seat,
428 struct seatop_default_event *e, struct sway_node *hovered_node) {
429 struct sway_node *focus = seat_get_focus(seat);
430
431 // If a workspace node is hovered (eg. in the gap area), only set focus if
432 // the workspace is on a different output to the previous focus.
433 if (focus && hovered_node->type == N_WORKSPACE) {
434 struct sway_output *focused_output = node_get_output(focus);
435 struct sway_output *hovered_output = node_get_output(hovered_node);
436 if (hovered_output != focused_output) {
437 seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node));
438 }
439 return;
440 }
441
442 if (node_is_view(hovered_node)) {
443 if (hovered_node != e->previous_node ||
444 config->focus_follows_mouse == FOLLOWS_ALWAYS) {
445 seat_set_focus(seat, hovered_node);
446 } else {
447 // Focusing a tab which contains a split child
448 struct sway_node *next_focus =
449 seat_get_focus_inactive(seat, &root->node);
450 if (next_focus && node_is_view(next_focus) &&
451 view_is_visible(next_focus->sway_container->view)) {
452 seat_set_focus(seat, next_focus);
453 }
454 }
455 }
456}
457
458static void handle_motion(struct sway_seat *seat, uint32_t time_msec,
459 double dx, double dy) {
460 struct seatop_default_event *e = seat->seatop_data;
461 struct sway_cursor *cursor = seat->cursor;
462
463 struct wlr_surface *surface = NULL;
464 double sx, sy;
465 struct sway_node *node = node_at_coords(seat,
466 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
467
468 if (node && config->focus_follows_mouse != FOLLOWS_NO) {
469 check_focus_follows_mouse(seat, e, node);
470 }
471
472 cursor_do_rebase(cursor, time_msec, node, surface, sx, sy);
473
474 struct sway_drag_icon *drag_icon;
475 wl_list_for_each(drag_icon, &root->drag_icons, link) {
476 if (drag_icon->seat == seat) {
477 drag_icon_update_position(drag_icon);
478 }
479 }
480
481 e->previous_node = node;
482}
483
484/*--------------------------------\
485 * Functions used by handle_axis /
486 *------------------------------*/
487
488static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
489 switch (event->orientation) {
490 case WLR_AXIS_ORIENTATION_VERTICAL:
491 return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
492 case WLR_AXIS_ORIENTATION_HORIZONTAL:
493 return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT;
494 default:
495 sway_log(SWAY_DEBUG, "Unknown axis orientation");
496 return 0;
497 }
498}
499
500static void handle_axis(struct sway_seat *seat,
501 struct wlr_event_pointer_axis *event) {
502 struct sway_input_device *input_device =
503 event->device ? event->device->data : NULL;
504 struct input_config *ic =
505 input_device ? input_device_get_config(input_device) : NULL;
506 struct sway_cursor *cursor = seat->cursor;
507 struct seatop_default_event *e = seat->seatop_data;
508
509 // Determine what's under the cursor
510 struct wlr_surface *surface = NULL;
511 double sx, sy;
512 struct sway_node *node = node_at_coords(seat,
513 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
514 struct sway_container *cont = node && node->type == N_CONTAINER ?
515 node->sway_container : NULL;
516 enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
517 bool on_border = edge != WLR_EDGE_NONE;
518 bool on_titlebar = cont && !on_border && !surface;
519 bool on_titlebar_border = cont && on_border &&
520 cursor->cursor->y < cont->content_y;
521 bool on_contents = cont && !on_border && surface;
522 bool on_workspace = node && node->type == N_WORKSPACE;
523 float scroll_factor =
524 (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor;
525
526 bool handled = false;
527
528 // Gather information needed for mouse bindings
529 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
530 uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
531 struct wlr_input_device *device =
532 input_device ? input_device->wlr_device : NULL;
533 char *dev_id = device ? input_device_get_identifier(device) : strdup("*");
534 uint32_t button = wl_axis_to_button(event);
535
536 // Handle mouse bindings - x11 mouse buttons 4-7 - press event
537 struct sway_binding *binding = NULL;
538 state_add_button(e, button);
539 binding = get_active_mouse_binding(e, config->current_mode->mouse_bindings,
540 modifiers, false, on_titlebar, on_border, on_contents, on_workspace,
541 dev_id);
542 if (binding) {
543 seat_execute_command(seat, binding);
544 handled = true;
545 }
546
547 // Scrolling on a tabbed or stacked title bar (handled as press event)
548 if (!handled && (on_titlebar || on_titlebar_border)) {
549 enum sway_container_layout layout = container_parent_layout(cont);
550 if (layout == L_TABBED || layout == L_STACKED) {
551 struct sway_node *tabcontainer = node_get_parent(node);
552 struct sway_node *active =
553 seat_get_active_tiling_child(seat, tabcontainer);
554 list_t *siblings = container_get_siblings(cont);
555 int desired = list_find(siblings, active->sway_container) +
556 round(scroll_factor * event->delta_discrete);
557 if (desired < 0) {
558 desired = 0;
559 } else if (desired >= siblings->length) {
560 desired = siblings->length - 1;
561 }
562 struct sway_node *old_focus = seat_get_focus(seat);
563 struct sway_container *new_sibling_con = siblings->items[desired];
564 struct sway_node *new_sibling = &new_sibling_con->node;
565 struct sway_node *new_focus =
566 seat_get_focus_inactive(seat, new_sibling);
567 if (node_has_ancestor(old_focus, tabcontainer)) {
568 seat_set_focus(seat, new_focus);
569 } else {
570 // Scrolling when focus is not in the tabbed container at all
571 seat_set_raw_focus(seat, new_sibling);
572 seat_set_raw_focus(seat, new_focus);
573 seat_set_raw_focus(seat, old_focus);
574 }
575 handled = true;
576 }
577 }
578
579 // Handle mouse bindings - x11 mouse buttons 4-7 - release event
580 binding = get_active_mouse_binding(e, config->current_mode->mouse_bindings,
581 modifiers, true, on_titlebar, on_border, on_contents, on_workspace,
582 dev_id);
583 state_erase_button(e, button);
584 if (binding) {
585 seat_execute_command(seat, binding);
586 handled = true;
587 }
588 free(dev_id);
589
590 if (!handled) {
591 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
592 event->orientation, scroll_factor * event->delta,
593 round(scroll_factor * event->delta_discrete), event->source);
594 }
595}
596
597/*----------------------------------\
598 * Functions used by handle_rebase /
599 *--------------------------------*/
600
601static void handle_rebase(struct sway_seat *seat, uint32_t time_msec) {
602 struct seatop_default_event *e = seat->seatop_data;
603 struct sway_cursor *cursor = seat->cursor;
604 struct wlr_surface *surface = NULL;
605 double sx = 0.0, sy = 0.0;
606 e->previous_node = node_at_coords(seat,
607 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
608 cursor_do_rebase(cursor, time_msec, e->previous_node, surface, sx, sy);
609}
610
611static const struct sway_seatop_impl seatop_impl = {
612 .button = handle_button,
613 .motion = handle_motion,
614 .axis = handle_axis,
615 .rebase = handle_rebase,
616 .allow_set_cursor = true,
617};
618
619void seatop_begin_default(struct sway_seat *seat) {
620 seatop_end(seat);
621
622 struct seatop_default_event *e =
623 calloc(1, sizeof(struct seatop_default_event));
624 sway_assert(e, "Unable to allocate seatop_default_event");
625 seat->seatop_impl = &seatop_impl;
626 seat->seatop_data = e;
627
628 seatop_rebase(seat, 0);
629}
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c
index fb2cf1d0..95ea7cbb 100644
--- a/sway/input/seatop_down.c
+++ b/sway/input/seatop_down.c
@@ -3,21 +3,26 @@
3#include "sway/input/cursor.h" 3#include "sway/input/cursor.h"
4#include "sway/input/seat.h" 4#include "sway/input/seat.h"
5#include "sway/tree/view.h" 5#include "sway/tree/view.h"
6#include "log.h"
6 7
7struct seatop_down_event { 8struct seatop_down_event {
8 struct sway_container *con; 9 struct sway_container *con;
9 double ref_lx, ref_ly; // cursor's x/y at start of op 10 double ref_lx, ref_ly; // cursor's x/y at start of op
10 double ref_con_lx, ref_con_ly; // container's x/y at start of op 11 double ref_con_lx, ref_con_ly; // container's x/y at start of op
11 bool moved;
12}; 12};
13 13
14static void handle_button(struct sway_seat *seat, uint32_t time_msec, 14static void handle_button(struct sway_seat *seat, uint32_t time_msec,
15 struct wlr_input_device *device, uint32_t button, 15 struct wlr_input_device *device, uint32_t button,
16 enum wlr_button_state state) { 16 enum wlr_button_state state) {
17 seat_pointer_notify_button(seat, time_msec, button, state); 17 seat_pointer_notify_button(seat, time_msec, button, state);
18
19 if (seat->cursor->pressed_button_count == 0) {
20 seatop_begin_default(seat);
21 }
18} 22}
19 23
20static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { 24static void handle_motion(struct sway_seat *seat, uint32_t time_msec,
25 double dx, double dy) {
21 struct seatop_down_event *e = seat->seatop_data; 26 struct seatop_down_event *e = seat->seatop_data;
22 struct sway_container *con = e->con; 27 struct sway_container *con = e->con;
23 if (seat_is_input_allowed(seat, con->view->surface)) { 28 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) {
27 double sy = e->ref_con_ly + moved_y; 32 double sy = e->ref_con_ly + moved_y;
28 wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); 33 wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);
29 } 34 }
30 e->moved = true;
31}
32
33static void handle_finish(struct sway_seat *seat, uint32_t time_msec) {
34 struct seatop_down_event *e = seat->seatop_data;
35 struct sway_cursor *cursor = seat->cursor;
36 // Set the cursor's previous coords to the x/y at the start of the
37 // operation, so the container change will be detected if using
38 // focus_follows_mouse and the cursor moved off the original container
39 // during the operation.
40 cursor->previous.x = e->ref_lx;
41 cursor->previous.y = e->ref_ly;
42 if (e->moved) {
43 struct wlr_surface *surface = NULL;
44 double sx, sy;
45 struct sway_node *node = node_at_coords(seat,
46 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
47 cursor_send_pointer_motion(cursor, 0, node, surface, sx, sy);
48 }
49}
50
51static void handle_abort(struct sway_seat *seat) {
52 cursor_set_image(seat->cursor, "left_ptr", NULL);
53} 35}
54 36
55static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 37static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
56 struct seatop_down_event *e = seat->seatop_data; 38 struct seatop_down_event *e = seat->seatop_data;
57 if (e->con == con) { 39 if (e->con == con) {
58 seatop_abort(seat); 40 seatop_begin_default(seat);
59 } 41 }
60} 42}
61 43
62static const struct sway_seatop_impl seatop_impl = { 44static const struct sway_seatop_impl seatop_impl = {
63 .button = handle_button, 45 .button = handle_button,
64 .motion = handle_motion, 46 .motion = handle_motion,
65 .finish = handle_finish,
66 .abort = handle_abort,
67 .unref = handle_unref, 47 .unref = handle_unref,
48 .allow_set_cursor = true,
68}; 49};
69 50
70void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, 51void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
71 uint32_t time_msec, uint32_t button, int sx, int sy) { 52 uint32_t time_msec, int sx, int sy) {
72 seatop_abort(seat); 53 seatop_end(seat);
73 54
74 struct seatop_down_event *e = 55 struct seatop_down_event *e =
75 calloc(1, sizeof(struct seatop_down_event)); 56 calloc(1, sizeof(struct seatop_down_event));
@@ -81,11 +62,9 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
81 e->ref_ly = seat->cursor->cursor->y; 62 e->ref_ly = seat->cursor->cursor->y;
82 e->ref_con_lx = sx; 63 e->ref_con_lx = sx;
83 e->ref_con_ly = sy; 64 e->ref_con_ly = sy;
84 e->moved = false;
85 65
86 seat->seatop_impl = &seatop_impl; 66 seat->seatop_impl = &seatop_impl;
87 seat->seatop_data = e; 67 seat->seatop_data = e;
88 seat->seatop_button = button;
89 68
90 container_raise_floating(con); 69 container_raise_floating(con);
91} 70}
diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c
index 8a48a968..73e48964 100644
--- a/sway/input/seatop_move_floating.c
+++ b/sway/input/seatop_move_floating.c
@@ -8,45 +8,44 @@ struct seatop_move_floating_event {
8 struct sway_container *con; 8 struct sway_container *con;
9}; 9};
10 10
11static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { 11static void handle_button(struct sway_seat *seat, uint32_t time_msec,
12 struct seatop_move_floating_event *e = seat->seatop_data; 12 struct wlr_input_device *device, uint32_t button,
13 desktop_damage_whole_container(e->con); 13 enum wlr_button_state state) {
14 container_floating_translate(e->con, 14 if (seat->cursor->pressed_button_count == 0) {
15 seat->cursor->cursor->x - seat->cursor->previous.x, 15 struct seatop_move_floating_event *e = seat->seatop_data;
16 seat->cursor->cursor->y - seat->cursor->previous.y);
17 desktop_damage_whole_container(e->con);
18}
19 16
20static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { 17 // We "move" the container to its own location
21 struct seatop_move_floating_event *e = seat->seatop_data; 18 // so it discovers its output again.
19 container_floating_move_to(e->con, e->con->x, e->con->y);
22 20
23 // We "move" the container to its own location 21 seatop_begin_default(seat);
24 // so it discovers its output again. 22 }
25 container_floating_move_to(e->con, e->con->x, e->con->y);
26 cursor_set_image(seat->cursor, "left_ptr", NULL);
27} 23}
28 24
29static void handle_abort(struct sway_seat *seat) { 25static void handle_motion(struct sway_seat *seat, uint32_t time_msec,
30 cursor_set_image(seat->cursor, "left_ptr", NULL); 26 double dx, double dy) {
27 struct seatop_move_floating_event *e = seat->seatop_data;
28 desktop_damage_whole_container(e->con);
29 container_floating_translate(e->con, dx, dy);
30 desktop_damage_whole_container(e->con);
31} 31}
32 32
33static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 33static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
34 struct seatop_move_floating_event *e = seat->seatop_data; 34 struct seatop_move_floating_event *e = seat->seatop_data;
35 if (e->con == con) { 35 if (e->con == con) {
36 seatop_abort(seat); 36 seatop_begin_default(seat);
37 } 37 }
38} 38}
39 39
40static const struct sway_seatop_impl seatop_impl = { 40static const struct sway_seatop_impl seatop_impl = {
41 .button = handle_button,
41 .motion = handle_motion, 42 .motion = handle_motion,
42 .finish = handle_finish,
43 .abort = handle_abort,
44 .unref = handle_unref, 43 .unref = handle_unref,
45}; 44};
46 45
47void seatop_begin_move_floating(struct sway_seat *seat, 46void seatop_begin_move_floating(struct sway_seat *seat,
48 struct sway_container *con, uint32_t button) { 47 struct sway_container *con) {
49 seatop_abort(seat); 48 seatop_end(seat);
50 49
51 struct seatop_move_floating_event *e = 50 struct seatop_move_floating_event *e =
52 calloc(1, sizeof(struct seatop_move_floating_event)); 51 calloc(1, sizeof(struct seatop_move_floating_event));
@@ -57,7 +56,6 @@ void seatop_begin_move_floating(struct sway_seat *seat,
57 56
58 seat->seatop_impl = &seatop_impl; 57 seat->seatop_impl = &seatop_impl;
59 seat->seatop_data = e; 58 seat->seatop_data = e;
60 seat->seatop_button = button;
61 59
62 container_raise_floating(con); 60 container_raise_floating(con);
63 61
diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c
index 2904792b..0a248091 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) {
206 desktop_damage_box(&e->drop_box); 206 desktop_damage_box(&e->drop_box);
207} 207}
208 208
209static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { 209static void handle_motion(struct sway_seat *seat, uint32_t time_msec,
210 double dx, double dy) {
210 struct seatop_move_tiling_event *e = seat->seatop_data; 211 struct seatop_move_tiling_event *e = seat->seatop_data;
211 if (e->threshold_reached) { 212 if (e->threshold_reached) {
212 handle_motion_postthreshold(seat); 213 handle_motion_postthreshold(seat);
@@ -215,10 +216,6 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
215 } 216 }
216} 217}
217 218
218static void handle_abort(struct sway_seat *seat) {
219 cursor_set_image(seat->cursor, "left_ptr", NULL);
220}
221
222static bool is_parallel(enum sway_container_layout layout, 219static bool is_parallel(enum sway_container_layout layout,
223 enum wlr_edges edge) { 220 enum wlr_edges edge) {
224 bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED; 221 bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED;
@@ -226,11 +223,17 @@ static bool is_parallel(enum sway_container_layout layout,
226 return layout_is_horiz == edge_is_horiz; 223 return layout_is_horiz == edge_is_horiz;
227} 224}
228 225
229static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { 226static void handle_button(struct sway_seat *seat, uint32_t time_msec,
227 struct wlr_input_device *device, uint32_t button,
228 enum wlr_button_state state) {
229 if (seat->cursor->pressed_button_count != 0) {
230 return;
231 }
232
230 struct seatop_move_tiling_event *e = seat->seatop_data; 233 struct seatop_move_tiling_event *e = seat->seatop_data;
231 234
232 if (!e->target_node) { 235 if (!e->target_node) {
233 handle_abort(seat); 236 seatop_begin_default(seat);
234 return; 237 return;
235 } 238 }
236 239
@@ -287,7 +290,7 @@ static void handle_finish(struct sway_seat *seat, uint32_t time_msec) {
287 arrange_workspace(new_ws); 290 arrange_workspace(new_ws);
288 } 291 }
289 292
290 cursor_set_image(seat->cursor, "left_ptr", NULL); 293 seatop_begin_default(seat);
291} 294}
292 295
293static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 296static 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) {
296 e->target_node = NULL; 299 e->target_node = NULL;
297 } 300 }
298 if (e->con == con) { // The container being moved 301 if (e->con == con) { // The container being moved
299 seatop_abort(seat); 302 seatop_begin_default(seat);
300 } 303 }
301} 304}
302 305
303static const struct sway_seatop_impl seatop_impl = { 306static const struct sway_seatop_impl seatop_impl = {
307 .button = handle_button,
304 .motion = handle_motion, 308 .motion = handle_motion,
305 .finish = handle_finish,
306 .abort = handle_abort,
307 .unref = handle_unref, 309 .unref = handle_unref,
308 .render = handle_render, 310 .render = handle_render,
309}; 311};
310 312
311void seatop_begin_move_tiling_threshold(struct sway_seat *seat, 313void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
312 struct sway_container *con, uint32_t button) { 314 struct sway_container *con) {
313 seatop_abort(seat); 315 seatop_end(seat);
314 316
315 struct seatop_move_tiling_event *e = 317 struct seatop_move_tiling_event *e =
316 calloc(1, sizeof(struct seatop_move_tiling_event)); 318 calloc(1, sizeof(struct seatop_move_tiling_event));
@@ -323,14 +325,13 @@ void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
323 325
324 seat->seatop_impl = &seatop_impl; 326 seat->seatop_impl = &seatop_impl;
325 seat->seatop_data = e; 327 seat->seatop_data = e;
326 seat->seatop_button = button;
327 328
328 container_raise_floating(con); 329 container_raise_floating(con);
329} 330}
330 331
331void seatop_begin_move_tiling(struct sway_seat *seat, 332void seatop_begin_move_tiling(struct sway_seat *seat,
332 struct sway_container *con, uint32_t button) { 333 struct sway_container *con) {
333 seatop_begin_move_tiling_threshold(seat, con, button); 334 seatop_begin_move_tiling_threshold(seat, con);
334 struct seatop_move_tiling_event *e = seat->seatop_data; 335 struct seatop_move_tiling_event *e = seat->seatop_data;
335 if (e) { 336 if (e) {
336 e->threshold_reached = true; 337 e->threshold_reached = true;
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c
index 18c6db73..b6950bbf 100644
--- a/sway/input/seatop_resize_floating.c
+++ b/sway/input/seatop_resize_floating.c
@@ -17,7 +17,16 @@ struct seatop_resize_floating_event {
17 double ref_con_lx, ref_con_ly; // container's x/y at start of op 17 double ref_con_lx, ref_con_ly; // container's x/y at start of op
18}; 18};
19 19
20static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { 20static void handle_button(struct sway_seat *seat, uint32_t time_msec,
21 struct wlr_input_device *device, uint32_t button,
22 enum wlr_button_state state) {
23 if (seat->cursor->pressed_button_count == 0) {
24 seatop_begin_default(seat);
25 }
26}
27
28static void handle_motion(struct sway_seat *seat, uint32_t time_msec,
29 double dx, double dy) {
21 struct seatop_resize_floating_event *e = seat->seatop_data; 30 struct seatop_resize_floating_event *e = seat->seatop_data;
22 struct sway_container *con = e->con; 31 struct sway_container *con = e->con;
23 enum wlr_edges edge = e->edge; 32 enum wlr_edges edge = e->edge;
@@ -107,31 +116,22 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
107 arrange_container(con); 116 arrange_container(con);
108} 117}
109 118
110static void handle_finish(struct sway_seat *seat, uint32_t time_msec) {
111 cursor_set_image(seat->cursor, "left_ptr", NULL);
112}
113
114static void handle_abort(struct sway_seat *seat) {
115 cursor_set_image(seat->cursor, "left_ptr", NULL);
116}
117
118static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 119static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
119 struct seatop_resize_floating_event *e = seat->seatop_data; 120 struct seatop_resize_floating_event *e = seat->seatop_data;
120 if (e->con == con) { 121 if (e->con == con) {
121 seatop_abort(seat); 122 seatop_begin_default(seat);
122 } 123 }
123} 124}
124 125
125static const struct sway_seatop_impl seatop_impl = { 126static const struct sway_seatop_impl seatop_impl = {
127 .button = handle_button,
126 .motion = handle_motion, 128 .motion = handle_motion,
127 .finish = handle_finish,
128 .abort = handle_abort,
129 .unref = handle_unref, 129 .unref = handle_unref,
130}; 130};
131 131
132void seatop_begin_resize_floating(struct sway_seat *seat, 132void seatop_begin_resize_floating(struct sway_seat *seat,
133 struct sway_container *con, uint32_t button, enum wlr_edges edge) { 133 struct sway_container *con, enum wlr_edges edge) {
134 seatop_abort(seat); 134 seatop_end(seat);
135 135
136 struct seatop_resize_floating_event *e = 136 struct seatop_resize_floating_event *e =
137 calloc(1, sizeof(struct seatop_resize_floating_event)); 137 calloc(1, sizeof(struct seatop_resize_floating_event));
@@ -154,7 +154,6 @@ void seatop_begin_resize_floating(struct sway_seat *seat,
154 154
155 seat->seatop_impl = &seatop_impl; 155 seat->seatop_impl = &seatop_impl;
156 seat->seatop_data = e; 156 seat->seatop_data = e;
157 seat->seatop_button = button;
158 157
159 container_raise_floating(con); 158 container_raise_floating(con);
160 159
diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c
index db32065c..6b705823 100644
--- a/sway/input/seatop_resize_tiling.c
+++ b/sway/input/seatop_resize_tiling.c
@@ -19,7 +19,16 @@ struct seatop_resize_tiling_event {
19 double v_con_orig_height; // height of the vertical ancestor at start 19 double v_con_orig_height; // height of the vertical ancestor at start
20}; 20};
21 21
22static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { 22static void handle_button(struct sway_seat *seat, uint32_t time_msec,
23 struct wlr_input_device *device, uint32_t button,
24 enum wlr_button_state state) {
25 if (seat->cursor->pressed_button_count == 0) {
26 seatop_begin_default(seat);
27 }
28}
29
30static void handle_motion(struct sway_seat *seat, uint32_t time_msec,
31 double dx, double dy) {
23 struct seatop_resize_tiling_event *e = seat->seatop_data; 32 struct seatop_resize_tiling_event *e = seat->seatop_data;
24 int amount_x = 0; 33 int amount_x = 0;
25 int amount_y = 0; 34 int amount_y = 0;
@@ -49,31 +58,22 @@ static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
49 } 58 }
50} 59}
51 60
52static void handle_finish(struct sway_seat *seat, uint32_t time_msec) {
53 cursor_set_image(seat->cursor, "left_ptr", NULL);
54}
55
56static void handle_abort(struct sway_seat *seat) {
57 cursor_set_image(seat->cursor, "left_ptr", NULL);
58}
59
60static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 61static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
61 struct seatop_resize_tiling_event *e = seat->seatop_data; 62 struct seatop_resize_tiling_event *e = seat->seatop_data;
62 if (e->con == con) { 63 if (e->con == con) {
63 seatop_abort(seat); 64 seatop_begin_default(seat);
64 } 65 }
65} 66}
66 67
67static const struct sway_seatop_impl seatop_impl = { 68static const struct sway_seatop_impl seatop_impl = {
69 .button = handle_button,
68 .motion = handle_motion, 70 .motion = handle_motion,
69 .finish = handle_finish,
70 .abort = handle_abort,
71 .unref = handle_unref, 71 .unref = handle_unref,
72}; 72};
73 73
74void seatop_begin_resize_tiling(struct sway_seat *seat, 74void seatop_begin_resize_tiling(struct sway_seat *seat,
75 struct sway_container *con, uint32_t button, enum wlr_edges edge) { 75 struct sway_container *con, enum wlr_edges edge) {
76 seatop_abort(seat); 76 seatop_end(seat);
77 77
78 struct seatop_resize_tiling_event *e = 78 struct seatop_resize_tiling_event *e =
79 calloc(1, sizeof(struct seatop_resize_tiling_event)); 79 calloc(1, sizeof(struct seatop_resize_tiling_event));
@@ -105,5 +105,4 @@ void seatop_begin_resize_tiling(struct sway_seat *seat,
105 105
106 seat->seatop_impl = &seatop_impl; 106 seat->seatop_impl = &seatop_impl;
107 seat->seatop_data = e; 107 seat->seatop_data = e;
108 seat->seatop_button = button;
109} 108}
diff --git a/sway/meson.build b/sway/meson.build
index 293a4ed2..cb1f8e25 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -23,6 +23,7 @@ sway_sources = files(
23 23
24 'input/input-manager.c', 24 'input/input-manager.c',
25 'input/seat.c', 25 'input/seat.c',
26 'input/seatop_default.c',
26 'input/seatop_down.c', 27 'input/seatop_down.c',
27 'input/seatop_move_floating.c', 28 'input/seatop_move_floating.c',
28 'input/seatop_move_tiling.c', 29 'input/seatop_move_tiling.c',