Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-xdp-input"
5 : :
6 : : #include "config.h"
7 : :
8 : : #ifdef __linux__
9 : : # include <linux/input-event-codes.h>
10 : : #else
11 : : # define BTN_LEFT 0x110
12 : : # define BTN_RIGHT 0x111
13 : : # define BTN_MIDDLE 0x112
14 : : #endif /* __linux */
15 : :
16 : : #include <gio/gio.h>
17 : : #include <valent.h>
18 : :
19 : : #include "valent-mutter-input.h"
20 : :
21 : : #define SERVICE_NAME "org.gnome.Shell"
22 : : #define SERVICE_PATH "/org/gnome/Mutter/RemoteDesktop"
23 : : #define SERVICE_IFACE "org.gnome.Mutter.RemoteDesktop"
24 : :
25 : : #define SESSION_NAME "org.gnome.Shell"
26 : : #define SESSION_IFACE "org.gnome.Mutter.RemoteDesktop.Session"
27 : :
28 : :
29 : : struct _ValentMutterInput
30 : : {
31 : : ValentInputAdapter parent_instance;
32 : :
33 : : GDBusProxy *proxy;
34 : : GDBusProxy *session;
35 : : uint8_t session_state : 2;
36 : : };
37 : :
38 : : static void g_async_initable_iface_init (GAsyncInitableIface *iface);
39 : :
40 [ + + + - ]: 5 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentMutterInput, valent_mutter_input, VALENT_TYPE_INPUT_ADAPTER,
41 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, g_async_initable_iface_init));
42 : :
43 : : enum {
44 : : SESSION_STATE_CLOSED,
45 : : SESSION_STATE_STARTING = (1 << 0),
46 : : SESSION_STATE_ACTIVE = (1 << 1),
47 : : };
48 : :
49 : : /*< private >
50 : : * KeyboardKeyState:
51 : : * @KEYBOARD_KEY_RELEASED: The key is pressed
52 : : * @KEYBOARD_KEY_PRESSED: The key is released
53 : : *
54 : : * Enumeration of keyboard bey states.
55 : : */
56 : : typedef enum {
57 : : KEYBOARD_KEY_RELEASED,
58 : : KEYBOARD_KEY_PRESSED,
59 : : } KeyboardKeyState;
60 : :
61 : : /*< private >
62 : : * PointerAxisFlags:
63 : : * @POINTER_AXIS_FINISH: scroll motion was finished (e.g. fingers lifted)
64 : : * @POINTER_AXIS_WHEEL: The scroll event is originated by a mouse wheel.
65 : : * @POINTER_AXIS_TOUCH: The scroll event is originated by one or more fingers
66 : : * on the device (eg. touchpads).
67 : : * @POINTER_AXIS_CONTINUOUS: The scroll event is originated by the motion of
68 : : * some device (eg. a scroll button is set).
69 : : *
70 : : * Flags for pointer axis events.
71 : : */
72 : : typedef enum {
73 : : POINTER_AXIS_NONE,
74 : : POINTER_AXIS_FINISH = (1 << 0),
75 : : POINTER_AXIS_WHEEL = (1 << 1),
76 : : POINTER_AXIS_TOUCH = (1 << 2),
77 : : POINTER_AXIS_CONTINUOUS = (1 << 3),
78 : : } PointerAxisFlags;
79 : :
80 : : /*< private >
81 : : * PointerAxisOrientation:
82 : : * @POINTER_AXIS_HORIZONTAL: The x-axis
83 : : * @POINTER_AXIS_VERTICAL: The y-axis
84 : : *
85 : : * Enumeration of pointer axis.
86 : : */
87 : : typedef enum {
88 : : POINTER_AXIS_HORIZONTAL,
89 : : POINTER_AXIS_VERTICAL,
90 : : } PointerAxisOrientation;
91 : :
92 : :
93 : : /*
94 : : * org.gnome.Mutter.RemoteDesktop.Session Callbacks
95 : : */
96 : : static void
97 : 0 : on_g_signal (GDBusProxy *proxy,
98 : : const char *sender_name,
99 : : const char *signal_name,
100 : : GVariant *parameters,
101 : : ValentMutterInput *self)
102 : : {
103 [ # # # # : 0 : g_assert (G_IS_DBUS_PROXY (proxy));
# # # # ]
104 [ # # # # ]: 0 : g_assert (sender_name != NULL && *sender_name != '\0');
105 [ # # ]: 0 : g_assert (VALENT_MUTTER_INPUT (self));
106 : :
107 : : /* This is the only signal relevant to this adapter */
108 [ # # ]: 0 : if (g_str_equal (signal_name, "Closed"))
109 : : {
110 : 0 : g_signal_handlers_disconnect_by_func (proxy, self, on_g_signal);
111 : :
112 [ # # ]: 0 : if (self->session == proxy)
113 : : {
114 : 0 : g_clear_object (&self->session);
115 : 0 : self->session_state = SESSION_STATE_CLOSED;
116 : : }
117 : : }
118 : 0 : }
119 : :
120 : : static void
121 : 0 : remote_desktop_start_session_cb (GDBusProxy *proxy,
122 : : GAsyncResult *result,
123 : : ValentMutterInput *self)
124 : : {
125 : 0 : g_autoptr (GVariant) reply = NULL;
126 : 0 : g_autoptr (GError) error = NULL;
127 : :
128 [ # # # # : 0 : g_assert (G_IS_DBUS_PROXY (proxy));
# # # # ]
129 [ # # # # : 0 : g_assert (G_IS_TASK (result));
# # # # ]
130 : :
131 [ # # ]: 0 : if ((reply = g_dbus_proxy_call_finish (proxy, result, &error)) == NULL)
132 : : {
133 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
134 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
135 : :
136 [ # # ]: 0 : g_clear_object (&self->session);
137 : 0 : self->session_state = SESSION_STATE_CLOSED;
138 [ # # ]: 0 : return;
139 : : }
140 : :
141 [ # # ]: 0 : self->session_state = SESSION_STATE_ACTIVE;
142 : : }
143 : :
144 : : static void
145 : 0 : remote_desktop_create_proxy_cb (GDBusProxy *proxy,
146 : : GAsyncResult *result,
147 : : ValentMutterInput *self)
148 : : {
149 : 0 : GCancellable *destroy = NULL;
150 : 0 : g_autoptr (GError) error = NULL;
151 : :
152 [ # # # # : 0 : g_assert (G_IS_DBUS_PROXY (proxy));
# # # # ]
153 [ # # # # : 0 : g_assert (G_IS_TASK (result));
# # # # ]
154 : :
155 [ # # ]: 0 : if ((self->session = g_dbus_proxy_new_for_bus_finish (result, &error)) == NULL)
156 : : {
157 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
158 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
159 : :
160 : 0 : self->session_state = SESSION_STATE_CLOSED;
161 [ # # ]: 0 : return;
162 : : }
163 : :
164 : 0 : g_signal_connect_object (self->session,
165 : : "g-signal",
166 : : G_CALLBACK (on_g_signal),
167 : : self, 0);
168 : :
169 : 0 : destroy = g_task_get_cancellable (G_TASK (result));
170 [ # # ]: 0 : g_dbus_proxy_call (self->session,
171 : : "Start",
172 : : NULL,
173 : : G_DBUS_CALL_FLAGS_NONE,
174 : : -1,
175 : : destroy,
176 : : (GAsyncReadyCallback)remote_desktop_start_session_cb,
177 : : self);
178 : : }
179 : :
180 : : static void
181 : 0 : remote_desktop_create_session_cb (GDBusProxy *proxy,
182 : : GAsyncResult *result,
183 : : ValentMutterInput *self)
184 : : {
185 : 0 : g_autoptr (GVariant) reply = NULL;
186 : 0 : const char *object_path = NULL;
187 : 0 : GCancellable *destroy = NULL;
188 [ # # ]: 0 : g_autoptr (GError) error = NULL;
189 : :
190 [ # # # # : 0 : g_assert (G_IS_DBUS_PROXY (proxy));
# # # # ]
191 [ # # # # : 0 : g_assert (G_IS_TASK (result));
# # # # ]
192 : :
193 [ # # ]: 0 : if ((reply = g_dbus_proxy_call_finish (proxy, result, &error)) == NULL)
194 : : {
195 [ # # ]: 0 : if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
196 : : return;
197 : :
198 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
199 : 0 : self->session_state = SESSION_STATE_CLOSED;
200 : :
201 : 0 : return;
202 : : }
203 : :
204 [ # # ]: 0 : g_return_if_fail (g_variant_is_of_type (reply, G_VARIANT_TYPE ("(o)")));
205 : 0 : g_variant_get (reply, "(&o)", &object_path);
206 : :
207 : 0 : destroy = g_task_get_cancellable (G_TASK (result));
208 [ # # ]: 0 : g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
209 : : G_DBUS_PROXY_FLAGS_NONE,
210 : : NULL,
211 : : SESSION_NAME,
212 : : object_path,
213 : : SESSION_IFACE,
214 : : destroy,
215 : : (GAsyncReadyCallback)remote_desktop_create_proxy_cb,
216 : : self);
217 : : }
218 : :
219 : : static inline gboolean
220 : 0 : valent_mutter_input_check (ValentMutterInput *self)
221 : : {
222 : 0 : g_autoptr (GCancellable) destroy = NULL;
223 : :
224 [ # # ]: 0 : if G_LIKELY (self->session_state == SESSION_STATE_ACTIVE)
225 : : return TRUE;
226 : :
227 [ # # ]: 0 : if (self->session_state == SESSION_STATE_STARTING)
228 : : return FALSE;
229 : :
230 : 0 : self->session_state = SESSION_STATE_STARTING;
231 : 0 : destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
232 : 0 : g_dbus_proxy_call (self->proxy,
233 : : "CreateSession",
234 : : NULL,
235 : : G_DBUS_CALL_FLAGS_NONE,
236 : : -1,
237 : : destroy,
238 : : (GAsyncReadyCallback)remote_desktop_create_session_cb,
239 : : self);
240 : :
241 [ # # ]: 0 : return FALSE;
242 : : }
243 : :
244 : : static void
245 : 1 : valent_mutter_input_close (ValentMutterInput *self)
246 : : {
247 [ - + ]: 1 : if (self->session_state == SESSION_STATE_CLOSED)
248 : : return;
249 : :
250 : 0 : g_dbus_proxy_call (self->session,
251 : : "Stop",
252 : : NULL,
253 : : G_DBUS_CALL_FLAGS_NONE,
254 : : -1,
255 : : NULL, NULL, NULL);
256 : 0 : self->session_state = SESSION_STATE_CLOSED;
257 : : }
258 : :
259 : :
260 : : /*
261 : : * ValentInputAdapter
262 : : */
263 : : static void
264 : 0 : valent_mutter_input_keyboard_keysym (ValentInputAdapter *adapter,
265 : : uint32_t keysym,
266 : : gboolean state)
267 : : {
268 : 0 : ValentMutterInput *self = VALENT_MUTTER_INPUT (adapter);
269 : :
270 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
271 [ # # ]: 0 : g_assert (VALENT_IS_MUTTER_INPUT (self));
272 : :
273 [ # # ]: 0 : if G_UNLIKELY (!valent_mutter_input_check (self))
274 : : return;
275 : :
276 : : // TODO: XDP_KEY_PRESSED/XDP_KEY_RELEASED
277 : 0 : g_dbus_proxy_call (self->session,
278 : : "NotifyKeyboardKeysym",
279 : : g_variant_new ("(ub)", keysym, state),
280 : : G_DBUS_CALL_FLAGS_NONE,
281 : : -1,
282 : : NULL, NULL, NULL);
283 : : }
284 : :
285 : : static unsigned int
286 : 0 : translate_to_evdev_button (unsigned int button)
287 : : {
288 : 0 : switch (button)
289 : : {
290 : : case VALENT_POINTER_PRIMARY:
291 : : return BTN_LEFT;
292 : :
293 : : case VALENT_POINTER_MIDDLE:
294 : : return BTN_MIDDLE;
295 : :
296 : : case VALENT_POINTER_SECONDARY:
297 : : return BTN_RIGHT;
298 : :
299 : 0 : default:
300 : : /* Any other buttons go after the legacy scroll buttons (4-7). */
301 : 0 : return button + (BTN_LEFT - 1) - 4;
302 : : }
303 : : }
304 : :
305 : : static void
306 : 0 : valent_mutter_input_pointer_axis (ValentInputAdapter *adapter,
307 : : double dx,
308 : : double dy)
309 : : {
310 : 0 : ValentMutterInput *self = VALENT_MUTTER_INPUT (adapter);
311 : :
312 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
313 [ # # ]: 0 : g_assert (VALENT_IS_MUTTER_INPUT (self));
314 [ # # # # : 0 : g_assert (!G_APPROX_VALUE (dx, 0.0, 0.01) || !G_APPROX_VALUE (dy, 0.0, 0.01));
# # # # #
# # # ]
315 : :
316 [ # # ]: 0 : if G_UNLIKELY (!valent_mutter_input_check (self))
317 : : return;
318 : :
319 : 0 : g_dbus_proxy_call (self->session,
320 : : "NotifyPointerAxis",
321 : : g_variant_new ("(ddu)", dx, dy, POINTER_AXIS_TOUCH),
322 : : G_DBUS_CALL_FLAGS_NONE,
323 : : -1,
324 : : NULL, NULL, NULL);
325 : 0 : g_dbus_proxy_call (self->session,
326 : : "NotifyPointerAxis",
327 : : g_variant_new ("(ddu)", 0.0, 0.0, POINTER_AXIS_FINISH),
328 : : G_DBUS_CALL_FLAGS_NONE,
329 : : -1,
330 : : NULL, NULL, NULL);
331 : : }
332 : :
333 : : static void
334 : 0 : valent_mutter_input_pointer_button (ValentInputAdapter *adapter,
335 : : unsigned int button,
336 : : gboolean pressed)
337 : : {
338 : 0 : ValentMutterInput *self = VALENT_MUTTER_INPUT (adapter);
339 : :
340 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
341 [ # # ]: 0 : g_assert (VALENT_IS_MUTTER_INPUT (self));
342 : :
343 [ # # ]: 0 : if G_UNLIKELY (!valent_mutter_input_check (self))
344 : : return;
345 : :
346 : : /* Translate the button to EVDEV constant */
347 [ # # ]: 0 : button = translate_to_evdev_button (button);
348 : 0 : g_dbus_proxy_call (self->session,
349 : : "NotifyPointerButton",
350 : : g_variant_new ("(ib)", (int32_t)button, pressed),
351 : : G_DBUS_CALL_FLAGS_NONE,
352 : : -1,
353 : : NULL, NULL, NULL);
354 : : }
355 : :
356 : : static void
357 : 0 : valent_mutter_input_pointer_motion (ValentInputAdapter *adapter,
358 : : double dx,
359 : : double dy)
360 : : {
361 : 0 : ValentMutterInput *self = VALENT_MUTTER_INPUT (adapter);
362 : :
363 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
364 [ # # ]: 0 : g_assert (VALENT_IS_MUTTER_INPUT (self));
365 : :
366 [ # # ]: 0 : if G_UNLIKELY (!valent_mutter_input_check (self))
367 : : return;
368 : :
369 : 0 : g_dbus_proxy_call (self->session,
370 : : "NotifyPointerMotionRelative",
371 : : g_variant_new ("(dd)", dx, dy),
372 : : G_DBUS_CALL_FLAGS_NONE,
373 : : -1,
374 : : NULL, NULL, NULL);
375 : : }
376 : :
377 : : /*
378 : : * GAsyncInitable
379 : : */
380 : : static void
381 : 1 : on_name_owner_changed (GDBusProxy *proxy,
382 : : GParamSpec *pspec,
383 : : ValentMutterInput *self)
384 : : {
385 : 2 : g_autofree char *name_owner = NULL;
386 : :
387 [ + - ]: 1 : g_assert (VALENT_IS_MUTTER_INPUT (self));
388 : :
389 [ - + ]: 1 : if ((name_owner = g_dbus_proxy_get_name_owner (proxy)) != NULL)
390 : : {
391 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
392 : : VALENT_PLUGIN_STATE_ACTIVE,
393 : : NULL);
394 : : }
395 : : else
396 : : {
397 : 1 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
398 : : VALENT_PLUGIN_STATE_INACTIVE,
399 : : NULL);
400 : : }
401 : 1 : }
402 : :
403 : : static void
404 : 1 : g_dbus_proxy_new_for_bus_cb (GDBusProxy *proxy,
405 : : GAsyncResult *result,
406 : : gpointer user_data)
407 : : {
408 : 1 : g_autoptr (GTask) task = G_TASK (user_data);
409 : 1 : ValentMutterInput *self = g_task_get_source_object (task);
410 : 1 : g_autoptr (GError) error = NULL;
411 : :
412 [ + - + - : 1 : g_assert (G_IS_TASK (task));
- + - - ]
413 : :
414 [ - + ]: 1 : if ((self->proxy = g_dbus_proxy_new_for_bus_finish (result, &error)) == NULL)
415 : : {
416 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
417 : : VALENT_PLUGIN_STATE_ERROR,
418 : : error);
419 [ # # ]: 0 : return g_task_return_error (task, g_steal_pointer (&error));
420 : : }
421 : :
422 : 1 : g_signal_connect_object (self->proxy,
423 : : "notify::g-name-owner",
424 : : G_CALLBACK (on_name_owner_changed),
425 : : self, 0);
426 : 1 : on_name_owner_changed (self->proxy, NULL, self);
427 : :
428 [ - + ]: 1 : g_task_return_boolean (task, TRUE);
429 : : }
430 : :
431 : : static void
432 : 1 : valent_mutter_input_init_async (GAsyncInitable *initable,
433 : : int io_priority,
434 : : GCancellable *cancellable,
435 : : GAsyncReadyCallback callback,
436 : : gpointer user_data)
437 : : {
438 : 2 : g_autoptr (GTask) task = NULL;
439 : 2 : g_autoptr (GCancellable) destroy = NULL;
440 : :
441 [ + - ]: 1 : g_assert (VALENT_IS_MUTTER_INPUT (initable));
442 : :
443 : : /* Cede the primary position until complete */
444 : 1 : valent_extension_plugin_state_changed (VALENT_EXTENSION (initable),
445 : : VALENT_PLUGIN_STATE_INACTIVE,
446 : : NULL);
447 : :
448 : : /* Cancel initialization if the object is destroyed */
449 : 1 : destroy = valent_object_chain_cancellable (VALENT_OBJECT (initable),
450 : : cancellable);
451 : :
452 : 1 : task = g_task_new (initable, destroy, callback, user_data);
453 : 1 : g_task_set_priority (task, io_priority);
454 [ + - ]: 1 : g_task_set_source_tag (task, valent_mutter_input_init_async);
455 : :
456 [ + - ]: 1 : g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
457 : : G_DBUS_PROXY_FLAGS_NONE,
458 : : NULL,
459 : : SERVICE_NAME,
460 : : SERVICE_PATH,
461 : : SERVICE_IFACE,
462 : : destroy,
463 : : (GAsyncReadyCallback)g_dbus_proxy_new_for_bus_cb,
464 : : g_steal_pointer (&task));
465 : 1 : }
466 : :
467 : : static void
468 : 1 : g_async_initable_iface_init (GAsyncInitableIface *iface)
469 : : {
470 : 1 : iface->init_async = valent_mutter_input_init_async;
471 : 1 : }
472 : :
473 : : /*
474 : : * ValentObject
475 : : */
476 : : static void
477 : 1 : valent_mutter_input_destroy (ValentObject *object)
478 : : {
479 : 1 : ValentMutterInput *self = VALENT_MUTTER_INPUT (object);
480 : :
481 : 1 : valent_mutter_input_close (self);
482 : :
483 : 1 : VALENT_OBJECT_CLASS (valent_mutter_input_parent_class)->destroy (object);
484 : 1 : }
485 : :
486 : : /*
487 : : * GObject
488 : : */
489 : : static void
490 : 1 : valent_mutter_input_finalize (GObject *object)
491 : : {
492 : 1 : ValentMutterInput *self = VALENT_MUTTER_INPUT (object);
493 : :
494 [ + - ]: 1 : g_clear_object (&self->proxy);
495 [ - + ]: 1 : g_clear_object (&self->session);
496 : :
497 : 1 : G_OBJECT_CLASS (valent_mutter_input_parent_class)->finalize (object);
498 : 1 : }
499 : :
500 : : static void
501 : 1 : valent_mutter_input_class_init (ValentMutterInputClass *klass)
502 : : {
503 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
504 : 1 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
505 : 1 : ValentInputAdapterClass *adapter_class = VALENT_INPUT_ADAPTER_CLASS (klass);
506 : :
507 : 1 : object_class->finalize = valent_mutter_input_finalize;
508 : :
509 : 1 : vobject_class->destroy = valent_mutter_input_destroy;
510 : :
511 : 1 : adapter_class->keyboard_keysym = valent_mutter_input_keyboard_keysym;
512 : 1 : adapter_class->pointer_axis = valent_mutter_input_pointer_axis;
513 : 1 : adapter_class->pointer_button = valent_mutter_input_pointer_button;
514 : 1 : adapter_class->pointer_motion = valent_mutter_input_pointer_motion;
515 : : }
516 : :
517 : : static void
518 : 1 : valent_mutter_input_init (ValentMutterInput *self)
519 : : {
520 : 1 : }
521 : :
522 : :
|