diff options
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r-- | sway/input/cursor.c | 426 |
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 | ||
40 | static 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 | |||
55 | static 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 | |||
64 | static 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, | |||
83 | struct sway_node *node_at_coords( | 44 | struct 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 = ¤t->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 | ||
239 | static void cursor_hide(struct sway_cursor *cursor) { | 182 | static 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 | ||
352 | static void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | 295 | void 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 | ||
414 | void dispatch_cursor_button(struct sway_cursor *cursor, | 357 | void 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 | ||
506 | static void handle_touch_up(struct wl_listener *listener, void *data) { | 422 | static 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 | |||
440 | static 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 | ||
848 | static void check_constraint_region(struct sway_cursor *cursor) { | 812 | static 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) { | |||
1316 | static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) { | 1271 | static 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 | |||
1394 | void 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 | } | ||