diff options
-rw-r--r-- | include/sway/input/cursor.h | 9 | ||||
-rw-r--r-- | include/sway/input/seat.h | 44 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 5 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 5 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 5 | ||||
-rw-r--r-- | sway/input/cursor.c | 680 | ||||
-rw-r--r-- | sway/input/seat.c | 47 | ||||
-rw-r--r-- | sway/input/seatop_default.c | 629 | ||||
-rw-r--r-- | sway/input/seatop_down.c | 43 | ||||
-rw-r--r-- | sway/input/seatop_move_floating.c | 42 | ||||
-rw-r--r-- | sway/input/seatop_move_tiling.c | 33 | ||||
-rw-r--r-- | sway/input/seatop_resize_floating.c | 29 | ||||
-rw-r--r-- | sway/input/seatop_resize_tiling.c | 29 | ||||
-rw-r--r-- | sway/meson.build | 1 |
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); | |||
78 | void cursor_unhide(struct sway_cursor *cursor); | 76 | void cursor_unhide(struct sway_cursor *cursor); |
79 | int cursor_get_timeout(struct sway_cursor *cursor); | 77 | int 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 | */ | ||
85 | void 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 | |||
88 | void dispatch_cursor_button(struct sway_cursor *cursor, | 79 | void 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 | ||
23 | struct sway_seat_device { | 26 | struct 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 | ||
189 | void drag_icon_update_position(struct sway_drag_icon *icon); | 190 | void drag_icon_update_position(struct sway_drag_icon *icon); |
190 | 191 | ||
192 | void seatop_begin_default(struct sway_seat *seat); | ||
193 | |||
191 | void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, | 194 | void 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 | ||
194 | void seatop_begin_move_floating(struct sway_seat *seat, | 197 | void seatop_begin_move_floating(struct sway_seat *seat, |
195 | struct sway_container *con, uint32_t button); | 198 | struct sway_container *con); |
196 | 199 | ||
197 | void seatop_begin_move_tiling_threshold(struct sway_seat *seat, | 200 | void seatop_begin_move_tiling_threshold(struct sway_seat *seat, |
198 | struct sway_container *con, uint32_t button); | 201 | struct sway_container *con); |
199 | 202 | ||
200 | void seatop_begin_move_tiling(struct sway_seat *seat, | 203 | void seatop_begin_move_tiling(struct sway_seat *seat, |
201 | struct sway_container *con, uint32_t button); | 204 | struct sway_container *con); |
202 | 205 | ||
203 | void seatop_begin_resize_floating(struct sway_seat *seat, | 206 | void 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 | ||
206 | void seatop_begin_resize_tiling(struct sway_seat *seat, | 209 | void 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 | ||
209 | struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, | 212 | struct 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 | ||
215 | void seat_consider_warp_to_focus(struct sway_seat *seat); | 218 | void seat_consider_warp_to_focus(struct sway_seat *seat); |
216 | 219 | ||
217 | bool seat_doing_seatop(struct sway_seat *seat); | ||
218 | |||
219 | void seatop_button(struct sway_seat *seat, uint32_t time_msec, | 220 | void 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 | ||
223 | void 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 | */ |
228 | void seatop_finish(struct sway_seat *seat, uint32_t time_msec); | 227 | void seatop_motion(struct sway_seat *seat, uint32_t time_msec, |
228 | double dx, double dy); | ||
229 | |||
230 | void seatop_axis(struct sway_seat *seat, struct wlr_event_pointer_axis *event); | ||
231 | |||
232 | void 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 | */ |
233 | void seatop_abort(struct sway_seat *seat); | 237 | void 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); | |||
246 | void seatop_render(struct sway_seat *seat, struct sway_output *output, | 250 | void seatop_render(struct sway_seat *seat, struct sway_output *output, |
247 | pixman_region32_t *damage); | 251 | pixman_region32_t *damage); |
248 | 252 | ||
253 | bool 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 | ||
482 | static void handle_request_resize(struct wl_listener *listener, void *data) { | 482 | static void handle_request_resize(struct wl_listener *listener, void *data) { |
@@ -492,8 +492,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { | |||
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 | ||
499 | static void handle_request_activate(struct wl_listener *listener, void *data) { | 498 | static 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 | */ | ||
165 | static 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 | |||
200 | static 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 | */ | ||
231 | static 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 | |||
240 | static 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 | |||
280 | void cursor_rebase(struct sway_cursor *cursor) { | 161 | void 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 | ||
289 | void cursor_rebase_all(void) { | 166 | void 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 | ||
348 | void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | 223 | static 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 | |||
414 | static 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 | ||
462 | static void cursor_motion_absolute(struct sway_cursor *cursor, | 258 | static 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 | */ | ||
511 | static 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 | */ | ||
531 | static 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 | */ | ||
552 | static 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 | ||
598 | void dispatch_cursor_button(struct sway_cursor *cursor, | 285 | void 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 | ||
801 | static void handle_cursor_button(struct wl_listener *listener, void *data) { | 295 | static 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 | ||
810 | static 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 | |||
822 | void dispatch_cursor_axis(struct sway_cursor *cursor, | 315 | void 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 | ||
918 | static void handle_cursor_axis(struct wl_listener *listener, void *data) { | 320 | static void handle_cursor_axis(struct wl_listener *listener, void *data) { |
@@ -1054,8 +456,16 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) { | |||
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 | ||
1061 | static void handle_tool_tip(struct wl_listener *listener, void *data) { | 471 | static void handle_tool_tip(struct wl_listener *listener, void *data) { |
@@ -1142,7 +552,7 @@ static void handle_request_set_cursor(struct wl_listener *listener, | |||
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 | ||
371 | static void handle_request_set_selection(struct wl_listener *listener, | 371 | static 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 | ||
1176 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, | 1178 | void 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 | ||
1209 | bool seat_doing_seatop(struct sway_seat *seat) { | ||
1210 | return seat->seatop_impl != NULL; | ||
1211 | } | ||
1212 | |||
1213 | void seatop_unref(struct sway_seat *seat, struct sway_container *con) { | 1210 | void 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) { | |||
1219 | void seatop_button(struct sway_seat *seat, uint32_t time_msec, | 1216 | void 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 | ||
1227 | void seatop_motion(struct sway_seat *seat, uint32_t time_msec) { | 1224 | void 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 | ||
1233 | void seatop_finish(struct sway_seat *seat, uint32_t time_msec) { | 1231 | void 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 | ||
1242 | void seatop_abort(struct sway_seat *seat) { | 1237 | void 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 | |||
1243 | void 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 | ||
1251 | void seatop_render(struct sway_seat *seat, struct sway_output *output, | 1252 | void 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 | |||
1259 | bool 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 | |||
11 | struct 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 | */ | ||
25 | static 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 | |||
60 | static 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 | */ | ||
91 | static 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 | */ | ||
104 | static 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 | */ | ||
154 | static 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 | */ | ||
175 | static 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 | |||
192 | static 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 | |||
236 | static 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 | |||
427 | static 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 | |||
458 | static 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 | |||
488 | static 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 | |||
500 | static 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 | |||
601 | static 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 | |||
611 | static 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 | |||
619 | void 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 | ||
7 | struct seatop_down_event { | 8 | struct 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 | ||
14 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, | 14 | static 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 | ||
20 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | 24 | static 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 | |||
33 | static 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 | |||
51 | static void handle_abort(struct sway_seat *seat) { | ||
52 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
53 | } | 35 | } |
54 | 36 | ||
55 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 37 | static 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 | ||
62 | static const struct sway_seatop_impl seatop_impl = { | 44 | static 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 | ||
70 | void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, | 51 | void 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 | ||
11 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | 11 | static 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 | ||
20 | static 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 | ||
29 | static void handle_abort(struct sway_seat *seat) { | 25 | static 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 | ||
33 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 33 | static 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 | ||
40 | static const struct sway_seatop_impl seatop_impl = { | 40 | static 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 | ||
47 | void seatop_begin_move_floating(struct sway_seat *seat, | 46 | void 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 | ||
209 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | 209 | static 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 | ||
218 | static void handle_abort(struct sway_seat *seat) { | ||
219 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
220 | } | ||
221 | |||
222 | static bool is_parallel(enum sway_container_layout layout, | 219 | static 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 | ||
229 | static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { | 226 | static 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 | ||
293 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 296 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { |
@@ -296,21 +299,20 @@ static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | |||
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 | ||
303 | static const struct sway_seatop_impl seatop_impl = { | 306 | static 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 | ||
311 | void seatop_begin_move_tiling_threshold(struct sway_seat *seat, | 313 | void 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 | ||
331 | void seatop_begin_move_tiling(struct sway_seat *seat, | 332 | void 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 | ||
20 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | 20 | static 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 | |||
28 | static 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 | ||
110 | static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { | ||
111 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
112 | } | ||
113 | |||
114 | static void handle_abort(struct sway_seat *seat) { | ||
115 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
116 | } | ||
117 | |||
118 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 119 | static 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 | ||
125 | static const struct sway_seatop_impl seatop_impl = { | 126 | static 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 | ||
132 | void seatop_begin_resize_floating(struct sway_seat *seat, | 132 | void 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 | ||
22 | static void handle_motion(struct sway_seat *seat, uint32_t time_msec) { | 22 | static 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 | |||
30 | static 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 | ||
52 | static void handle_finish(struct sway_seat *seat, uint32_t time_msec) { | ||
53 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
54 | } | ||
55 | |||
56 | static void handle_abort(struct sway_seat *seat) { | ||
57 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
58 | } | ||
59 | |||
60 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 61 | static 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 | ||
67 | static const struct sway_seatop_impl seatop_impl = { | 68 | static 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 | ||
74 | void seatop_begin_resize_tiling(struct sway_seat *seat, | 74 | void 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', |