Dunst
Lightweight notification daemon
Loading...
Searching...
No Matches
wl_seat.c
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-3-Clause */
7
8#define _POSIX_C_SOURCE 200112L
9#include <linux/input-event-codes.h>
10
11#include "protocols/idle.h"
12
13#ifdef HAVE_WL_CURSOR_SHAPE
14#include "protocols/cursor-shape-v1.h"
15#include "protocols/tablet-unstable-v2.h"
16#endif
17
18#ifdef HAVE_WL_EXT_IDLE_NOTIFY
19#include "protocols/ext-idle-notify-v1.h"
20#endif
21
22#include "../dunst.h"
23#include "../input.h"
24#include "../log.h"
25#include "../settings.h"
26#include "wl_seat.h"
27#include "wl_ctx.h"
28
29static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
30 uint32_t time, int32_t id,
31 wl_fixed_t surface_x, wl_fixed_t surface_y) {
32 struct dunst_seat *seat = data;
33
34 if (id >= MAX_TOUCHPOINTS) {
35 return;
36 }
37 seat->touch.pts[id].x = wl_fixed_to_int(surface_x);
38 seat->touch.pts[id].y = wl_fixed_to_int(surface_y);
39}
40
41static void touch_handle_down(void *data, struct wl_touch *wl_touch,
42 uint32_t serial, uint32_t time, struct wl_surface *sfc, int32_t id,
43 wl_fixed_t surface_x, wl_fixed_t surface_y) {
44 struct dunst_seat *seat = data;
45
46 if (id >= MAX_TOUCHPOINTS) {
47 return;
48 }
49 seat->touch.pts[id].x = wl_fixed_to_int(surface_x);
50 seat->touch.pts[id].y = wl_fixed_to_int(surface_y);
51}
52
53static void touch_handle_up(void *data, struct wl_touch *wl_touch,
54 uint32_t serial, uint32_t time, int32_t id) {
55 struct dunst_seat *seat = data;
56
57 if (id >= MAX_TOUCHPOINTS) {
58 return;
59 }
60 input_handle_click(BTN_TOUCH, false,
61 seat->touch.pts[id].x, seat->touch.pts[id].y);
62
63}
64
65static void touch_handle_frame(void *data, struct wl_touch *wl_touch) {
66}
67
68static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) {
69}
70
71static const struct wl_touch_listener touch_listener = {
72 .down = touch_handle_down,
73 .up = touch_handle_up,
74 .motion = touch_handle_motion,
75 .frame = touch_handle_frame,
76 .cancel = touch_handle_cancel,
77};
78
79static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
80 uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) {
81 if (settings.pause_on_mouse_over) {
82 dunst_status(S_MOUSE_OVER, true);
83 wake_up();
84 }
85
86 // Change the mouse cursor to "left_ptr"
87#ifdef HAVE_WL_CURSOR_SHAPE
88 if (ctx.cursor_shape_manager != NULL) {
89 struct wp_cursor_shape_device_v1 *device =
90 wp_cursor_shape_manager_v1_get_pointer(ctx.cursor_shape_manager, wl_pointer);
91 wp_cursor_shape_device_v1_set_shape(device, serial,
92 WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
93 wp_cursor_shape_device_v1_destroy(device);
94 return;
95 }
96#endif
97 if (ctx.cursor_theme != NULL) {
98 wl_pointer_set_cursor(wl_pointer, serial, ctx.cursor_surface, ctx.cursor_image->hotspot_x, ctx.cursor_image->hotspot_y);
99 }
100}
101
102static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
103 uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
104 struct dunst_seat *seat = data;
105
106 seat->pointer.x = wl_fixed_to_int(surface_x);
107 seat->pointer.y = wl_fixed_to_int(surface_y);
108}
109
110static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
111 uint32_t serial, uint32_t time, uint32_t button,
112 uint32_t button_state) {
113 struct dunst_seat *seat = data;
114
115 input_handle_click(button, button_state, seat->pointer.x, seat->pointer.y);
116}
117
118static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
119 uint32_t serial, struct wl_surface *surface) {
120 if (settings.pause_on_mouse_over) {
121 dunst_status(S_MOUSE_OVER, false);
122 wake_up();
123 }
124}
125
126static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
127 uint32_t time, uint32_t axis, wl_fixed_t value) {
128}
129
130static const struct wl_pointer_listener pointer_listener = {
131 .enter = pointer_handle_enter,
132 .leave = pointer_handle_leave,
133 .motion = pointer_handle_motion,
134 .button = pointer_handle_button,
135 .axis = pointer_handle_axis,
136};
137
138static void destroy_seat_pointer(struct dunst_seat *seat) {
139 wl_pointer_release(seat->pointer.wl_pointer);
140 seat->pointer.wl_pointer = NULL;
141}
142
143static void destroy_seat_touch(struct dunst_seat *seat) {
144 wl_touch_release(seat->touch.wl_touch);
145 seat->touch.wl_touch = NULL;
146}
147
148void destroy_seat(struct dunst_seat *seat) {
149 if (seat == NULL) {
150 return;
151 }
152
153 if (seat->pointer.wl_pointer != NULL) {
154 destroy_seat_pointer(seat);
155 }
156
157 if (seat->touch.wl_touch != NULL) {
158 destroy_seat_touch(seat);
159 }
160
161 if (seat->idle_timeout != NULL) {
162 org_kde_kwin_idle_timeout_release(seat->idle_timeout);
163 seat->idle_timeout = NULL;
164 }
165
166#ifdef HAVE_WL_EXT_IDLE_NOTIFY
167 if (seat->ext_idle_notification != NULL) {
168 ext_idle_notification_v1_destroy(seat->ext_idle_notification);
169 seat->ext_idle_notification = NULL;
170 }
171#endif
172
173 wl_list_remove(&seat->link);
174
175#ifdef WL_SEAT_RELEASE_SINCE_VERSION
176 if (wl_seat_get_version(seat->wl_seat) >= WL_SEAT_RELEASE_SINCE_VERSION) {
177 wl_seat_release(seat->wl_seat);
178 } else
179#endif
180 {
181 wl_seat_destroy(seat->wl_seat);
182 }
183 seat->wl_seat = NULL;
184
185 g_free(seat->name);
186 seat->name = NULL;
187
188 g_free(seat);
189}
190
191static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
192 uint32_t capabilities) {
193 struct dunst_seat *seat = data;
194
195 if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
196 if (seat->pointer.wl_pointer == NULL) {
197 seat->pointer.wl_pointer = wl_seat_get_pointer(wl_seat);
198 wl_pointer_add_listener(seat->pointer.wl_pointer,
199 &pointer_listener, seat);
200 }
201 } else if (seat->pointer.wl_pointer != NULL) {
202 destroy_seat_pointer(seat);
203 }
204
205 if (capabilities & WL_SEAT_CAPABILITY_TOUCH) {
206 if (seat->touch.wl_touch == NULL) {
207 seat->touch.wl_touch = wl_seat_get_touch(wl_seat);
208 wl_touch_add_listener(seat->touch.wl_touch,
209 &touch_listener, seat);
210 }
211 } else if (seat->touch.wl_touch != NULL) {
212 destroy_seat_touch(seat);
213 }
214}
215
216static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) {
217 struct dunst_seat *seat = data;
218
219 seat->name = g_strdup(name);
220 LOG_I("New seat found - id %" PRIu32 " name %s", seat->global_name, seat->name);
221}
222
223static const struct wl_seat_listener seat_listener = {
224 .capabilities = seat_handle_capabilities,
225 .name = seat_handle_name,
226};
227
228
229static void idle_start (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
230 struct dunst_seat *seat = data;
231
232 seat->is_idle = true;
233 LOG_D("User went idle on seat \"%s\"", seat->name);
234}
235static void idle_stop (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
236 struct dunst_seat *seat = data;
237
238 seat->is_idle = false;
239 LOG_D("User isn't idle anymore on seat \"%s\"", seat->name);
240}
241
242static const struct org_kde_kwin_idle_timeout_listener idle_timeout_listener = {
243 .idle = idle_start,
244 .resumed = idle_stop,
245};
246
247#ifdef HAVE_WL_EXT_IDLE_NOTIFY
248static void ext_idle_notification_handle_idled(void *data, struct ext_idle_notification_v1 *notification) {
249 struct dunst_seat *seat = data;
250
251 seat->is_idle = true;
252 LOG_D("User went idle on seat \"%s\"", seat->name);
253}
254
255static void ext_idle_notification_handle_resumed(void *data, struct ext_idle_notification_v1 *notification) {
256 struct dunst_seat *seat = data;
257
258 seat->is_idle = false;
259 LOG_D("User isn't idle anymore on seat \"%s\"", seat->name);
260}
261
262static const struct ext_idle_notification_v1_listener ext_idle_notification_listener = {
263 .idled = ext_idle_notification_handle_idled,
264 .resumed = ext_idle_notification_handle_resumed,
265};
266#endif
267
268void add_seat_to_idle_handler(struct dunst_seat *seat) {
269 if (settings.idle_threshold <= 0) {
270 return;
271 }
272 uint32_t timeout_ms = settings.idle_threshold/1000;
273
274#ifdef HAVE_WL_EXT_IDLE_NOTIFY
275 if (ctx.ext_idle_notifier != NULL) {
276 if (seat->ext_idle_notification == NULL) {
277 seat->ext_idle_notification =
278 ext_idle_notifier_v1_get_idle_notification(ctx.ext_idle_notifier,
279 timeout_ms, seat->wl_seat);
280 ext_idle_notification_v1_add_listener(seat->ext_idle_notification,
281 &ext_idle_notification_listener, seat);
282 }
283 // In the unlikely case where we already set up org_kde_kwin_idle_timeout, destroy it
284 if (seat->idle_timeout != NULL) {
285 org_kde_kwin_idle_timeout_release(seat->idle_timeout);
286 seat->idle_timeout = NULL;
287 }
288 return;
289 }
290#endif
291 if (ctx.idle_handler != NULL && seat->idle_timeout == NULL) {
292 seat->idle_timeout = org_kde_kwin_idle_get_idle_timeout(ctx.idle_handler, seat->wl_seat, timeout_ms);
293 org_kde_kwin_idle_timeout_add_listener(seat->idle_timeout, &idle_timeout_listener, seat);
294 }
295}
296
297void create_seat(struct wl_registry *registry, uint32_t global_name, uint32_t version) {
298 struct dunst_seat *seat = g_malloc0(sizeof(struct dunst_seat));
299 if (seat == NULL) {
300 LOG_E("allocation failed");
301 return;
302 }
303 seat->global_name = global_name;
304 seat->wl_seat = wl_registry_bind(registry, global_name, &wl_seat_interface, 3);
305 wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
306 add_seat_to_idle_handler(seat);
307 wl_list_insert(&ctx.seats, &seat->link);
308}
void dunst_status(const enum dunst_status_field field, bool value)
Modify the current status of dunst.
Definition dunst.c:35
Main event loop logic.
void input_handle_click(unsigned int button, bool button_down, int mouse_x, int mouse_y)
Handle incoming mouse click events.
Definition input.c:67
Input handling for mouse events.
Logging subsystem and helpers.
#define LOG_E
Prefix message with "[<source path>:<function name>:<line number>] ".
Definition log.h:42
Type definitions for settings.
Wayland context tracking.
Wayland seat managment.