aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r--sway/input/cursor.c426
1 files changed, 202 insertions, 224 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 2ee63124..3d04826c 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 1#include <assert.h>
3#include <math.h> 2#include <math.h>
4#include <libevdev/libevdev.h> 3#include <libevdev/libevdev.h>
@@ -7,8 +6,9 @@
7#include <time.h> 6#include <time.h>
8#include <strings.h> 7#include <strings.h>
9#include <wlr/types/wlr_cursor.h> 8#include <wlr/types/wlr_cursor.h>
10#include <wlr/types/wlr_idle.h> 9#include <wlr/types/wlr_cursor_shape_v1.h>
11#include <wlr/types/wlr_pointer.h> 10#include <wlr/types/wlr_pointer.h>
11#include <wlr/types/wlr_relative_pointer_v1.h>
12#include <wlr/types/wlr_touch.h> 12#include <wlr/types/wlr_touch.h>
13#include <wlr/types/wlr_tablet_v2.h> 13#include <wlr/types/wlr_tablet_v2.h>
14#include <wlr/types/wlr_tablet_pad.h> 14#include <wlr/types/wlr_tablet_pad.h>
@@ -19,12 +19,12 @@
19#include "log.h" 19#include "log.h"
20#include "util.h" 20#include "util.h"
21#include "sway/commands.h" 21#include "sway/commands.h"
22#include "sway/desktop.h"
23#include "sway/input/cursor.h" 22#include "sway/input/cursor.h"
24#include "sway/input/keyboard.h" 23#include "sway/input/keyboard.h"
25#include "sway/input/tablet.h" 24#include "sway/input/tablet.h"
26#include "sway/layers.h" 25#include "sway/layers.h"
27#include "sway/output.h" 26#include "sway/output.h"
27#include "sway/scene_descriptor.h"
28#include "sway/tree/container.h" 28#include "sway/tree/container.h"
29#include "sway/tree/root.h" 29#include "sway/tree/root.h"
30#include "sway/tree/view.h" 30#include "sway/tree/view.h"
@@ -37,45 +37,6 @@ static uint32_t get_current_time_msec(void) {
37 return now.tv_sec * 1000 + now.tv_nsec / 1000000; 37 return now.tv_sec * 1000 + now.tv_nsec / 1000000;
38} 38}
39 39
40static struct wlr_surface *layer_surface_at(struct sway_output *output,
41 struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
42 struct sway_layer_surface *sway_layer;
43 wl_list_for_each_reverse(sway_layer, layer, link) {
44 double _sx = ox - sway_layer->geo.x;
45 double _sy = oy - sway_layer->geo.y;
46 struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
47 sway_layer->layer_surface, _sx, _sy, sx, sy);
48 if (sub) {
49 return sub;
50 }
51 }
52 return NULL;
53}
54
55static bool surface_is_xdg_popup(struct wlr_surface *surface) {
56 if (wlr_surface_is_xdg_surface(surface)) {
57 struct wlr_xdg_surface *xdg_surface =
58 wlr_xdg_surface_from_wlr_surface(surface);
59 return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP;
60 }
61 return false;
62}
63
64static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
65 struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
66 struct sway_layer_surface *sway_layer;
67 wl_list_for_each_reverse(sway_layer, layer, link) {
68 double _sx = ox - sway_layer->geo.x;
69 double _sy = oy - sway_layer->geo.y;
70 struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
71 sway_layer->layer_surface, _sx, _sy, sx, sy);
72 if (sub && surface_is_xdg_popup(sub)) {
73 return sub;
74 }
75 }
76 return NULL;
77}
78
79/** 40/**
80 * Returns the node at the cursor's position. If there is a surface at that 41 * Returns the node at the cursor's position. If there is a surface at that
81 * location, it is stored in **surface (it may not be a view). 42 * location, it is stored in **surface (it may not be a view).
@@ -83,116 +44,98 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
83struct sway_node *node_at_coords( 44struct sway_node *node_at_coords(
84 struct sway_seat *seat, double lx, double ly, 45 struct sway_seat *seat, double lx, double ly,
85 struct wlr_surface **surface, double *sx, double *sy) { 46 struct wlr_surface **surface, double *sx, double *sy) {
86 // find the output the cursor is on 47 struct wlr_scene_node *scene_node = NULL;
87 struct wlr_output *wlr_output = wlr_output_layout_output_at(
88 root->output_layout, lx, ly);
89 if (wlr_output == NULL) {
90 return NULL;
91 }
92 struct sway_output *output = wlr_output->data;
93 if (!output || !output->enabled) {
94 // output is being destroyed or is being enabled
95 return NULL;
96 }
97 double ox = lx, oy = ly;
98 wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
99 48
100 // layer surfaces on the overlay layer are rendered on top 49 struct wlr_scene_node *node;
101 if ((*surface = layer_surface_at(output, 50 wl_list_for_each_reverse(node, &root->layer_tree->children, link) {
102 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], 51 struct wlr_scene_tree *layer = wlr_scene_tree_from_node(node);
103 ox, oy, sx, sy))) {
104 return NULL;
105 }
106 52
107 // check for unmanaged views 53 bool non_interactive = scene_descriptor_try_get(&layer->node,
108#if HAVE_XWAYLAND 54 SWAY_SCENE_DESC_NON_INTERACTIVE);
109 struct wl_list *unmanaged = &root->xwayland_unmanaged; 55 if (non_interactive) {
110 struct sway_xwayland_unmanaged *unmanaged_surface; 56 continue;
111 wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
112 struct wlr_xwayland_surface *xsurface =
113 unmanaged_surface->wlr_xwayland_surface;
114
115 double _sx = lx - unmanaged_surface->lx;
116 double _sy = ly - unmanaged_surface->ly;
117 if (wlr_surface_point_accepts_input(xsurface->surface, _sx, _sy)) {
118 *surface = xsurface->surface;
119 *sx = _sx;
120 *sy = _sy;
121 return NULL;
122 } 57 }
123 }
124#endif
125 58
126 if (root->fullscreen_global) { 59 scene_node = wlr_scene_node_at(&layer->node, lx, ly, sx, sy);
127 // Try fullscreen container 60 if (scene_node) {
128 struct sway_container *con = tiling_container_at( 61 break;
129 &root->fullscreen_global->node, lx, ly, surface, sx, sy);
130 if (con) {
131 return &con->node;
132 } 62 }
133 return NULL;
134 } 63 }
135 64
136 // find the focused workspace on the output for this seat 65 if (scene_node) {
137 struct sway_workspace *ws = output_get_active_workspace(output); 66 // determine what wlr_surface we clicked on
138 if (!ws) { 67 if (scene_node->type == WLR_SCENE_NODE_BUFFER) {
139 return NULL; 68 struct wlr_scene_buffer *scene_buffer =
140 } 69 wlr_scene_buffer_from_node(scene_node);
70 struct wlr_scene_surface *scene_surface =
71 wlr_scene_surface_try_from_buffer(scene_buffer);
141 72
142 if (ws->fullscreen) { 73 if (scene_surface) {
143 // Try transient containers 74 *surface = scene_surface->surface;
144 for (int i = 0; i < ws->floating->length; ++i) {
145 struct sway_container *floater = ws->floating->items[i];
146 if (container_is_transient_for(floater, ws->fullscreen)) {
147 struct sway_container *con = tiling_container_at(
148 &floater->node, lx, ly, surface, sx, sy);
149 if (con) {
150 return &con->node;
151 }
152 } 75 }
153 } 76 }
154 // Try fullscreen container 77
155 struct sway_container *con = 78 // determine what container we clicked on
156 tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); 79 struct wlr_scene_node *current = scene_node;
157 if (con) { 80 while (true) {
158 return &con->node; 81 struct sway_container *con = scene_descriptor_try_get(current,
82 SWAY_SCENE_DESC_CONTAINER);
83
84 if (!con) {
85 struct sway_view *view = scene_descriptor_try_get(current,
86 SWAY_SCENE_DESC_VIEW);
87 if (view) {
88 con = view->container;
89 }
90 }
91
92 if (!con) {
93 struct sway_popup_desc *popup =
94 scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP);
95 if (popup && popup->view) {
96 con = popup->view->container;
97 }
98 }
99
100 if (con && (!con->view || con->view->surface)) {
101 return &con->node;
102 }
103
104 if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) {
105 // We don't want to feed through the current workspace on
106 // layer shells
107 return NULL;
108 }
109
110#if HAVE_XWAYLAND
111 if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) {
112 return NULL;
113 }
114#endif
115
116 if (!current->parent) {
117 break;
118 }
119
120 current = &current->parent->node;
159 } 121 }
160 return NULL;
161 }
162 if ((*surface = layer_surface_popup_at(output,
163 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
164 ox, oy, sx, sy))) {
165 return NULL;
166 }
167 if ((*surface = layer_surface_popup_at(output,
168 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
169 ox, oy, sx, sy))) {
170 return NULL;
171 }
172 if ((*surface = layer_surface_popup_at(output,
173 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
174 ox, oy, sx, sy))) {
175 return NULL;
176 }
177 if ((*surface = layer_surface_at(output,
178 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
179 ox, oy, sx, sy))) {
180 return NULL;
181 } 122 }
182 123
183 struct sway_container *c; 124 // if we aren't on a container, determine what workspace we are on
184 if ((c = container_at(ws, lx, ly, surface, sx, sy))) { 125 struct wlr_output *wlr_output = wlr_output_layout_output_at(
185 return &c->node; 126 root->output_layout, lx, ly);
127 if (wlr_output == NULL) {
128 return NULL;
186 } 129 }
187 130
188 if ((*surface = layer_surface_at(output, 131 struct sway_output *output = wlr_output->data;
189 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], 132 if (!output || !output->enabled) {
190 ox, oy, sx, sy))) { 133 // output is being destroyed or is being enabled
191 return NULL; 134 return NULL;
192 } 135 }
193 if ((*surface = layer_surface_at(output, 136
194 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], 137 struct sway_workspace *ws = output_get_active_workspace(output);
195 ox, oy, sx, sy))) { 138 if (!ws) {
196 return NULL; 139 return NULL;
197 } 140 }
198 141
@@ -221,7 +164,7 @@ void cursor_update_image(struct sway_cursor *cursor,
221 // Try a node's resize edge 164 // Try a node's resize edge
222 enum wlr_edges edge = find_resize_edge(node->sway_container, NULL, cursor); 165 enum wlr_edges edge = find_resize_edge(node->sway_container, NULL, cursor);
223 if (edge == WLR_EDGE_NONE) { 166 if (edge == WLR_EDGE_NONE) {
224 cursor_set_image(cursor, "left_ptr", NULL); 167 cursor_set_image(cursor, "default", NULL);
225 } else if (container_is_floating(node->sway_container)) { 168 } else if (container_is_floating(node->sway_container)) {
226 cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); 169 cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
227 } else { 170 } else {
@@ -232,12 +175,12 @@ void cursor_update_image(struct sway_cursor *cursor,
232 } 175 }
233 } 176 }
234 } else { 177 } else {
235 cursor_set_image(cursor, "left_ptr", NULL); 178 cursor_set_image(cursor, "default", NULL);
236 } 179 }
237} 180}
238 181
239static void cursor_hide(struct sway_cursor *cursor) { 182static void cursor_hide(struct sway_cursor *cursor) {
240 wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); 183 wlr_cursor_unset_image(cursor->cursor);
241 cursor->hidden = true; 184 cursor->hidden = true;
242 wlr_seat_pointer_notify_clear_focus(cursor->seat->wlr_seat); 185 wlr_seat_pointer_notify_clear_focus(cursor->seat->wlr_seat);
243} 186}
@@ -300,7 +243,7 @@ static enum sway_input_idle_source idle_source_from_device(
300 return IDLE_SOURCE_POINTER; 243 return IDLE_SOURCE_POINTER;
301 case WLR_INPUT_DEVICE_TOUCH: 244 case WLR_INPUT_DEVICE_TOUCH:
302 return IDLE_SOURCE_TOUCH; 245 return IDLE_SOURCE_TOUCH;
303 case WLR_INPUT_DEVICE_TABLET_TOOL: 246 case WLR_INPUT_DEVICE_TABLET:
304 return IDLE_SOURCE_TABLET_TOOL; 247 return IDLE_SOURCE_TABLET_TOOL;
305 case WLR_INPUT_DEVICE_TABLET_PAD: 248 case WLR_INPUT_DEVICE_TABLET_PAD:
306 return IDLE_SOURCE_TABLET_PAD; 249 return IDLE_SOURCE_TABLET_PAD;
@@ -349,7 +292,7 @@ void cursor_unhide(struct sway_cursor *cursor) {
349 wl_event_source_timer_update(cursor->hide_source, cursor_get_timeout(cursor)); 292 wl_event_source_timer_update(cursor->hide_source, cursor_get_timeout(cursor));
350} 293}
351 294
352static void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, 295void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
353 struct wlr_input_device *device, double dx, double dy, 296 struct wlr_input_device *device, double dx, double dy,
354 double dx_unaccel, double dy_unaccel) { 297 double dx_unaccel, double dy_unaccel) {
355 wlr_relative_pointer_manager_v1_send_relative_motion( 298 wlr_relative_pointer_manager_v1_send_relative_motion(
@@ -413,7 +356,7 @@ static void handle_pointer_motion_absolute(
413 356
414void dispatch_cursor_button(struct sway_cursor *cursor, 357void dispatch_cursor_button(struct sway_cursor *cursor,
415 struct wlr_input_device *device, uint32_t time_msec, uint32_t button, 358 struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
416 enum wlr_button_state state) { 359 enum wl_pointer_button_state state) {
417 if (time_msec == 0) { 360 if (time_msec == 0) {
418 time_msec = get_current_time_msec(); 361 time_msec = get_current_time_msec();
419 } 362 }
@@ -425,7 +368,7 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) {
425 struct sway_cursor *cursor = wl_container_of(listener, cursor, button); 368 struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
426 struct wlr_pointer_button_event *event = data; 369 struct wlr_pointer_button_event *event = data;
427 370
428 if (event->state == WLR_BUTTON_PRESSED) { 371 if (event->state == WL_POINTER_BUTTON_STATE_PRESSED) {
429 cursor->pressed_button_count++; 372 cursor->pressed_button_count++;
430 } else { 373 } else {
431 if (cursor->pressed_button_count > 0) { 374 if (cursor->pressed_button_count > 0) {
@@ -464,43 +407,16 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
464 cursor_hide(cursor); 407 cursor_hide(cursor);
465 408
466 struct sway_seat *seat = cursor->seat; 409 struct sway_seat *seat = cursor->seat;
467 struct wlr_seat *wlr_seat = seat->wlr_seat;
468 struct wlr_surface *surface = NULL;
469 410
470 double lx, ly; 411 double lx, ly;
471 wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base, 412 wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
472 event->x, event->y, &lx, &ly); 413 event->x, event->y, &lx, &ly);
473 double sx, sy;
474 struct sway_node *focused_node = node_at_coords(seat, lx, ly, &surface, &sx, &sy);
475 414
476 seat->touch_id = event->touch_id; 415 seat->touch_id = event->touch_id;
477 seat->touch_x = lx; 416 seat->touch_x = lx;
478 seat->touch_y = ly; 417 seat->touch_y = ly;
479 418
480 if (surface && wlr_surface_accepts_touch(wlr_seat, surface)) { 419 seatop_touch_down(seat, event, lx, ly);
481 if (seat_is_input_allowed(seat, surface)) {
482 wlr_seat_touch_notify_down(wlr_seat, surface, event->time_msec,
483 event->touch_id, sx, sy);
484
485 if (focused_node) {
486 seat_set_focus(seat, focused_node);
487 }
488 }
489 } else if (!cursor->simulating_pointer_from_touch &&
490 (!surface || seat_is_input_allowed(seat, surface))) {
491 // Fallback to cursor simulation.
492 // The pointer_touch_id state is needed, so drags are not aborted when over
493 // a surface supporting touch and multi touch events don't interfere.
494 cursor->simulating_pointer_from_touch = true;
495 cursor->pointer_touch_id = seat->touch_id;
496 double dx, dy;
497 dx = lx - cursor->cursor->x;
498 dy = ly - cursor->cursor->y;
499 pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy,
500 dx, dy);
501 dispatch_cursor_button(cursor, &event->touch->base, event->time_msec,
502 BTN_LEFT, WLR_BUTTON_PRESSED);
503 }
504} 420}
505 421
506static void handle_touch_up(struct wl_listener *listener, void *data) { 422static void handle_touch_up(struct wl_listener *listener, void *data) {
@@ -508,16 +424,34 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
508 struct wlr_touch_up_event *event = data; 424 struct wlr_touch_up_event *event = data;
509 cursor_handle_activity_from_device(cursor, &event->touch->base); 425 cursor_handle_activity_from_device(cursor, &event->touch->base);
510 426
511 struct wlr_seat *wlr_seat = cursor->seat->wlr_seat; 427 struct sway_seat *seat = cursor->seat;
512 428
513 if (cursor->simulating_pointer_from_touch) { 429 if (cursor->simulating_pointer_from_touch) {
514 if (cursor->pointer_touch_id == cursor->seat->touch_id) { 430 if (cursor->pointer_touch_id == cursor->seat->touch_id) {
515 cursor->pointer_touch_up = true; 431 cursor->pointer_touch_up = true;
516 dispatch_cursor_button(cursor, &event->touch->base, 432 dispatch_cursor_button(cursor, &event->touch->base,
517 event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED); 433 event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
518 } 434 }
519 } else { 435 } else {
520 wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id); 436 seatop_touch_up(seat, event);
437 }
438}
439
440static void handle_touch_cancel(struct wl_listener *listener, void *data) {
441 struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_cancel);
442 struct wlr_touch_cancel_event *event = data;
443 cursor_handle_activity_from_device(cursor, &event->touch->base);
444
445 struct sway_seat *seat = cursor->seat;
446
447 if (cursor->simulating_pointer_from_touch) {
448 if (cursor->pointer_touch_id == cursor->seat->touch_id) {
449 cursor->pointer_touch_up = true;
450 dispatch_cursor_button(cursor, &event->touch->base,
451 event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
452 }
453 } else {
454 seatop_touch_cancel(seat, event);
521 } 455 }
522} 456}
523 457
@@ -528,25 +462,16 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
528 cursor_handle_activity_from_device(cursor, &event->touch->base); 462 cursor_handle_activity_from_device(cursor, &event->touch->base);
529 463
530 struct sway_seat *seat = cursor->seat; 464 struct sway_seat *seat = cursor->seat;
531 struct wlr_seat *wlr_seat = seat->wlr_seat;
532 struct wlr_surface *surface = NULL;
533 465
534 double lx, ly; 466 double lx, ly;
535 wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base, 467 wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
536 event->x, event->y, &lx, &ly); 468 event->x, event->y, &lx, &ly);
537 double sx, sy;
538 node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
539 469
540 if (seat->touch_id == event->touch_id) { 470 if (seat->touch_id == event->touch_id) {
541 seat->touch_x = lx; 471 seat->touch_x = lx;
542 seat->touch_y = ly; 472 seat->touch_y = ly;
543 473
544 struct sway_drag_icon *drag_icon; 474 drag_icons_update_position(seat);
545 wl_list_for_each(drag_icon, &root->drag_icons, link) {
546 if (drag_icon->seat == seat) {
547 drag_icon_update_position(drag_icon);
548 }
549 }
550 } 475 }
551 476
552 if (cursor->simulating_pointer_from_touch) { 477 if (cursor->simulating_pointer_from_touch) {
@@ -557,9 +482,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
557 pointer_motion(cursor, event->time_msec, &event->touch->base, 482 pointer_motion(cursor, event->time_msec, &event->touch->base,
558 dx, dy, dx, dy); 483 dx, dy, dx, dy);
559 } 484 }
560 } else if (surface) { 485 } else {
561 wlr_seat_touch_notify_motion(wlr_seat, event->time_msec, 486 seatop_touch_motion(seat, event, lx, ly);
562 event->touch_id, sx, sy);
563 } 487 }
564} 488}
565 489
@@ -594,7 +518,7 @@ static void apply_mapping_from_region(struct wlr_input_device *device,
594 double x1 = region->x1, x2 = region->x2; 518 double x1 = region->x1, x2 = region->x2;
595 double y1 = region->y1, y2 = region->y2; 519 double y1 = region->y1, y2 = region->y2;
596 520
597 if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { 521 if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET) {
598 struct wlr_tablet *tablet = wlr_tablet_from_input_device(device); 522 struct wlr_tablet *tablet = wlr_tablet_from_input_device(device);
599 if (tablet->width_mm == 0 || tablet->height_mm == 0) { 523 if (tablet->width_mm == 0 || tablet->height_mm == 0) {
600 return; 524 return;
@@ -737,7 +661,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
737 event->state == WLR_TABLET_TOOL_TIP_UP) { 661 event->state == WLR_TABLET_TOOL_TIP_UP) {
738 cursor->simulating_pointer_from_tool_tip = false; 662 cursor->simulating_pointer_from_tool_tip = false;
739 dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec, 663 dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec,
740 BTN_LEFT, WLR_BUTTON_RELEASED); 664 BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
741 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 665 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
742 } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { 666 } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
743 // If we started holding the tool tip down on a surface that accepts 667 // If we started holding the tool tip down on a surface that accepts
@@ -749,7 +673,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
749 } else { 673 } else {
750 cursor->simulating_pointer_from_tool_tip = true; 674 cursor->simulating_pointer_from_tool_tip = true;
751 dispatch_cursor_button(cursor, &event->tablet->base, 675 dispatch_cursor_button(cursor, &event->tablet->base,
752 event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED); 676 event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
753 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 677 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
754 } 678 }
755 } else { 679 } else {
@@ -818,31 +742,71 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
818 node_at_coords(cursor->seat, cursor->cursor->x, cursor->cursor->y, 742 node_at_coords(cursor->seat, cursor->cursor->x, cursor->cursor->y,
819 &surface, &sx, &sy); 743 &surface, &sx, &sy);
820 744
821 if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { 745 // TODO: floating resize should support graphics tablet events
746 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat);
747 uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
748 bool mod_pressed = modifiers & config->floating_mod;
749
750 bool surface_supports_tablet_events =
751 surface && wlr_surface_accepts_tablet_v2(tablet_v2, surface);
752
753 // Simulate pointer when:
754 // 1. The modifier key is pressed, OR
755 // 2. The surface under the cursor does not support tablet events.
756 bool should_simulate_pointer = mod_pressed || !surface_supports_tablet_events;
757
758 // Similar to tool tip, we need to selectively simulate mouse events, but we
759 // want to make sure that it is always consistent. Because all tool buttons
760 // currently map to BTN_RIGHT, we need to keep count of how many tool
761 // buttons are currently pressed down so we can send consistent events.
762 //
763 // The logic follows:
764 // - If we are already simulating the pointer, we should continue to do so
765 // until at least no tool button is held down.
766 // - If we should simulate the pointer and no tool button is currently held
767 // down, begin simulating the pointer.
768 // - If neither of the above are true, send the tablet events.
769 if ((cursor->tool_buttons > 0 && cursor->simulating_pointer_from_tool_button)
770 || (cursor->tool_buttons == 0 && should_simulate_pointer)) {
771 cursor->simulating_pointer_from_tool_button = true;
772
822 // TODO: the user may want to configure which tool buttons are mapped to 773 // TODO: the user may want to configure which tool buttons are mapped to
823 // which simulated pointer buttons 774 // which simulated pointer buttons
824 switch (event->state) { 775 switch (event->state) {
825 case WLR_BUTTON_PRESSED: 776 case WLR_BUTTON_PRESSED:
826 if (cursor->tool_buttons == 0) { 777 if (cursor->tool_buttons == 0) {
827 dispatch_cursor_button(cursor, &event->tablet->base, 778 dispatch_cursor_button(cursor, &event->tablet->base,
828 event->time_msec, BTN_RIGHT, event->state); 779 event->time_msec, BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED);
829 } 780 }
830 cursor->tool_buttons++;
831 break; 781 break;
832 case WLR_BUTTON_RELEASED: 782 case WLR_BUTTON_RELEASED:
833 if (cursor->tool_buttons == 1) { 783 if (cursor->tool_buttons <= 1) {
834 dispatch_cursor_button(cursor, &event->tablet->base, 784 dispatch_cursor_button(cursor, &event->tablet->base,
835 event->time_msec, BTN_RIGHT, event->state); 785 event->time_msec, BTN_RIGHT, WL_POINTER_BUTTON_STATE_RELEASED);
836 } 786 }
837 cursor->tool_buttons--;
838 break; 787 break;
839 } 788 }
840 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 789 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
841 return; 790 } else {
791 cursor->simulating_pointer_from_tool_button = false;
792
793 wlr_tablet_v2_tablet_tool_notify_button(sway_tool->tablet_v2_tool,
794 event->button, (enum zwp_tablet_pad_v2_button_state)event->state);
842 } 795 }
843 796
844 wlr_tablet_v2_tablet_tool_notify_button(sway_tool->tablet_v2_tool, 797 // Update tool button count.
845 event->button, (enum zwp_tablet_pad_v2_button_state)event->state); 798 switch (event->state) {
799 case WLR_BUTTON_PRESSED:
800 cursor->tool_buttons++;
801 break;
802 case WLR_BUTTON_RELEASED:
803 if (cursor->tool_buttons == 0) {
804 sway_log(SWAY_ERROR, "inconsistent tablet tool button events");
805 } else {
806 cursor->tool_buttons--;
807 }
808 break;
809 }
846} 810}
847 811
848static void check_constraint_region(struct sway_cursor *cursor) { 812static void check_constraint_region(struct sway_cursor *cursor) {
@@ -1028,10 +992,9 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image,
1028 } 992 }
1029 993
1030 if (!image) { 994 if (!image) {
1031 wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); 995 wlr_cursor_unset_image(cursor->cursor);
1032 } else if (!current_image || strcmp(current_image, image) != 0) { 996 } else if (!current_image || strcmp(current_image, image) != 0) {
1033 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, 997 wlr_cursor_set_xcursor(cursor->cursor, cursor->xcursor_manager, image);
1034 cursor->cursor);
1035 } 998 }
1036} 999}
1037 1000
@@ -1078,6 +1041,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
1078 wl_list_remove(&cursor->frame.link); 1041 wl_list_remove(&cursor->frame.link);
1079 wl_list_remove(&cursor->touch_down.link); 1042 wl_list_remove(&cursor->touch_down.link);
1080 wl_list_remove(&cursor->touch_up.link); 1043 wl_list_remove(&cursor->touch_up.link);
1044 wl_list_remove(&cursor->touch_cancel.link);
1081 wl_list_remove(&cursor->touch_motion.link); 1045 wl_list_remove(&cursor->touch_motion.link);
1082 wl_list_remove(&cursor->touch_frame.link); 1046 wl_list_remove(&cursor->touch_frame.link);
1083 wl_list_remove(&cursor->tool_axis.link); 1047 wl_list_remove(&cursor->tool_axis.link);
@@ -1114,9 +1078,6 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
1114 wl_list_init(&cursor->image_surface_destroy.link); 1078 wl_list_init(&cursor->image_surface_destroy.link);
1115 cursor->image_surface_destroy.notify = handle_image_surface_destroy; 1079 cursor->image_surface_destroy.notify = handle_image_surface_destroy;
1116 1080
1117 // gesture events
1118 cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display);
1119
1120 wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin); 1081 wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin);
1121 cursor->hold_begin.notify = handle_pointer_hold_begin; 1082 cursor->hold_begin.notify = handle_pointer_hold_begin;
1122 wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end); 1083 wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end);
@@ -1159,6 +1120,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
1159 wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up); 1120 wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up);
1160 cursor->touch_up.notify = handle_touch_up; 1121 cursor->touch_up.notify = handle_touch_up;
1161 1122
1123 wl_signal_add(&wlr_cursor->events.touch_cancel, &cursor->touch_cancel);
1124 cursor->touch_cancel.notify = handle_touch_cancel;
1125
1162 wl_signal_add(&wlr_cursor->events.touch_motion, 1126 wl_signal_add(&wlr_cursor->events.touch_motion,
1163 &cursor->touch_motion); 1127 &cursor->touch_motion);
1164 cursor->touch_motion.notify = handle_touch_motion; 1128 cursor->touch_motion.notify = handle_touch_motion;
@@ -1251,11 +1215,7 @@ uint32_t get_mouse_bindsym(const char *name, char **error) {
1251 // Get event code from name 1215 // Get event code from name
1252 int code = libevdev_event_code_from_name(EV_KEY, name); 1216 int code = libevdev_event_code_from_name(EV_KEY, name);
1253 if (code == -1) { 1217 if (code == -1) {
1254 size_t len = snprintf(NULL, 0, "Unknown event %s", name) + 1; 1218 *error = format_str("Unknown event %s", name);
1255 *error = malloc(len);
1256 if (*error) {
1257 snprintf(*error, len, "Unknown event %s", name);
1258 }
1259 return 0; 1219 return 0;
1260 } 1220 }
1261 return code; 1221 return code;
@@ -1277,13 +1237,8 @@ uint32_t get_mouse_bindcode(const char *name, char **error) {
1277 } 1237 }
1278 const char *event = libevdev_event_code_get_name(EV_KEY, code); 1238 const char *event = libevdev_event_code_get_name(EV_KEY, code);
1279 if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) { 1239 if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
1280 size_t len = snprintf(NULL, 0, "Event code %d (%s) is not a button", 1240 *error = format_str("Event code %d (%s) is not a button",
1281 code, event ? event : "(null)") + 1; 1241 code, event ? event : "(null)");
1282 *error = malloc(len);
1283 if (*error) {
1284 snprintf(*error, len, "Event code %d (%s) is not a button",
1285 code, event ? event : "(null)");
1286 }
1287 return 0; 1242 return 0;
1288 } 1243 }
1289 return code; 1244 return code;
@@ -1316,12 +1271,15 @@ const char *get_mouse_button_name(uint32_t button) {
1316static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) { 1271static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) {
1317 struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint; 1272 struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint;
1318 1273
1319 if (constraint->current.committed & 1274 if (constraint->current.cursor_hint.enabled) {
1320 WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
1321 double sx = constraint->current.cursor_hint.x; 1275 double sx = constraint->current.cursor_hint.x;
1322 double sy = constraint->current.cursor_hint.y; 1276 double sy = constraint->current.cursor_hint.y;
1323 1277
1324 struct sway_view *view = view_from_wlr_surface(constraint->surface); 1278 struct sway_view *view = view_from_wlr_surface(constraint->surface);
1279 if (!view) {
1280 return;
1281 }
1282
1325 struct sway_container *con = view->container; 1283 struct sway_container *con = view->container;
1326 1284
1327 double lx = sx + con->pending.content_x - view->geometry.x; 1285 double lx = sx + con->pending.content_x - view->geometry.x;
@@ -1372,12 +1330,9 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) {
1372 sway_constraint->destroy.notify = handle_constraint_destroy; 1330 sway_constraint->destroy.notify = handle_constraint_destroy;
1373 wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy); 1331 wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy);
1374 1332
1375 struct sway_node *focus = seat_get_focus(seat); 1333 struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface;
1376 if (focus && node_is_view(focus)) { 1334 if (surface && surface == constraint->surface) {
1377 struct wlr_surface *surface = focus->sway_container->view->surface; 1335 sway_cursor_constrain(seat->cursor, constraint);
1378 if (surface == constraint->surface) {
1379 sway_cursor_constrain(seat->cursor, constraint);
1380 }
1381 } 1336 }
1382} 1337}
1383 1338
@@ -1435,3 +1390,26 @@ void sway_cursor_constrain(struct sway_cursor *cursor,
1435 wl_signal_add(&constraint->surface->events.commit, 1390 wl_signal_add(&constraint->surface->events.commit,
1436 &cursor->constraint_commit); 1391 &cursor->constraint_commit);
1437} 1392}
1393
1394void handle_request_set_cursor_shape(struct wl_listener *listener, void *data) {
1395 const struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
1396 struct sway_seat *seat = event->seat_client->seat->data;
1397
1398 if (!seatop_allows_set_cursor(seat)) {
1399 return;
1400 }
1401
1402 struct wl_client *focused_client = NULL;
1403 struct wlr_surface *focused_surface = seat->wlr_seat->pointer_state.focused_surface;
1404 if (focused_surface != NULL) {
1405 focused_client = wl_resource_get_client(focused_surface->resource);
1406 }
1407
1408 // TODO: check cursor mode
1409 if (focused_client == NULL || event->seat_client->client != focused_client) {
1410 sway_log(SWAY_DEBUG, "denying request to set cursor from unfocused client");
1411 return;
1412 }
1413
1414 cursor_set_image(seat->cursor, wlr_cursor_shape_v1_name(event->shape), focused_client);
1415}