aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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',