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 : : #include <linux/input-event-codes.h>
9 : :
10 : : #include <gio/gio.h>
11 : : #include <libportal/portal.h>
12 : : #include <valent.h>
13 : :
14 : : #ifdef HAVE_LIBEI
15 : : # include "valent-ei-input.h"
16 : : #endif /* HAVE_LIBEI */
17 : : #include "valent-xdp-utils.h"
18 : :
19 : : #include "valent-xdp-input.h"
20 : :
21 : : struct _ValentXdpInput
22 : : {
23 : : ValentInputAdapter parent_instance;
24 : :
25 : : ValentInputAdapter *delegate;
26 : : GSettings *settings;
27 : : XdpSession *session;
28 : : gboolean session_starting;
29 : : gboolean started;
30 : : };
31 : :
32 : 0 : G_DEFINE_FINAL_TYPE (ValentXdpInput, valent_xdp_input, VALENT_TYPE_INPUT_ADAPTER)
33 : :
34 : :
35 : : /*
36 : : * Portal Callbacks
37 : : */
38 : : static void
39 : 0 : on_session_closed (ValentXdpInput *self)
40 : : {
41 : 0 : g_clear_object (&self->delegate);
42 : 0 : g_clear_object (&self->session);
43 : 0 : self->session_starting = FALSE;
44 : 0 : self->started = FALSE;
45 : 0 : }
46 : :
47 : : static void
48 : 0 : on_session_started (XdpSession *session,
49 : : GAsyncResult *res,
50 : : gpointer user_data)
51 : : {
52 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (user_data);
53 : 0 : g_autofree char *session_token = NULL;
54 : 0 : g_autoptr (GError) error = NULL;
55 : :
56 : 0 : self->started = xdp_session_start_finish (session, res, &error);
57 : 0 : if (!self->started)
58 : : {
59 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
60 : 0 : on_session_closed (self);
61 : 0 : return;
62 : : }
63 : :
64 : : #ifdef HAVE_LIBEI
65 : 0 : int ei_fd = xdp_session_connect_to_eis (self->session, &error);
66 : 0 : if (ei_fd > -1)
67 : : {
68 : 0 : self->delegate = g_initable_new (VALENT_TYPE_EI_INPUT, NULL, &error,
69 : : "parent", self,
70 : : "fd", ei_fd,
71 : : NULL);
72 : 0 : if (self->delegate == NULL)
73 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
74 : : }
75 : : else
76 : : {
77 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
78 : : }
79 : : #endif /* HAVE_LIBEI */
80 : :
81 : 0 : session_token = xdp_session_get_restore_token (session);
82 : 0 : g_settings_set_string (self->settings,
83 : : "session-token",
84 : : session_token ? session_token : "");
85 : 0 : self->session_starting = FALSE;
86 : : }
87 : :
88 : : static void
89 : 0 : on_session_created (XdpPortal *portal,
90 : : GAsyncResult *result,
91 : : gpointer user_data)
92 : : {
93 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (user_data);
94 : 0 : g_autoptr (XdpParent) parent = NULL;
95 : 0 : g_autoptr (GError) error = NULL;
96 : :
97 : 0 : self->session = xdp_portal_create_remote_desktop_session_finish (portal,
98 : : result,
99 : : &error);
100 : 0 : if (self->session == NULL)
101 : : {
102 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
103 : 0 : on_session_closed (self);
104 : 0 : return;
105 : : }
106 : :
107 : 0 : g_signal_connect_object (self->session,
108 : : "closed",
109 : : G_CALLBACK (on_session_closed),
110 : : self,
111 : : G_CONNECT_SWAPPED);
112 : :
113 : 0 : parent = valent_xdp_get_parent ();
114 : 0 : xdp_session_start (self->session,
115 : : parent,
116 : : g_task_get_cancellable (G_TASK (result)),
117 : : (GAsyncReadyCallback)on_session_started,
118 : : self);
119 : : }
120 : :
121 : : static gboolean
122 : 0 : ensure_session (ValentXdpInput *self)
123 : : {
124 : 0 : g_autoptr (GCancellable) cancellable = NULL;
125 : 0 : g_autofree char *restore_token = NULL;
126 : :
127 : 0 : if (self->session_starting)
128 : : return FALSE;
129 : :
130 : 0 : if G_LIKELY (self->started)
131 : : return TRUE;
132 : :
133 : 0 : self->session_starting = TRUE;
134 : 0 : cancellable = valent_object_ref_cancellable (VALENT_OBJECT (self));
135 : 0 : restore_token = g_settings_get_string (self->settings, "session-token");
136 : 0 : if (!g_uuid_string_is_valid (restore_token))
137 : 0 : g_clear_pointer (&restore_token, g_free);
138 : :
139 : 0 : xdp_portal_create_remote_desktop_session_full (valent_xdp_get_default (),
140 : : (XDP_DEVICE_KEYBOARD |
141 : : XDP_DEVICE_POINTER),
142 : : XDP_OUTPUT_NONE,
143 : : XDP_REMOTE_DESKTOP_FLAG_NONE,
144 : : XDP_CURSOR_MODE_HIDDEN,
145 : : XDP_PERSIST_MODE_PERSISTENT,
146 : : restore_token,
147 : : cancellable,
148 : : (GAsyncReadyCallback)on_session_created,
149 : : self);
150 : :
151 : 0 : return FALSE;
152 : : }
153 : :
154 : :
155 : : /*
156 : : * ValentInputAdapter
157 : : */
158 : : static void
159 : 0 : valent_xdp_input_keyboard_keysym (ValentInputAdapter *adapter,
160 : : uint32_t keysym,
161 : : gboolean state)
162 : : {
163 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (adapter);
164 : :
165 : 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
166 : 0 : g_assert (VALENT_IS_XDP_INPUT (self));
167 : :
168 : 0 : if G_UNLIKELY (!ensure_session (self))
169 : : return;
170 : :
171 : 0 : if (self->delegate != NULL)
172 : : {
173 : : #ifdef HAVE_LIBEI
174 : 0 : valent_input_adapter_keyboard_keysym (self->delegate, keysym, state);
175 : : #endif /* HAVE_LIBEI */
176 : : }
177 : : else
178 : : {
179 : : // TODO: XDP_KEY_PRESSED/XDP_KEY_RELEASED
180 : 0 : xdp_session_keyboard_key (self->session, TRUE, keysym, state);
181 : : }
182 : : }
183 : :
184 : : static unsigned int
185 : 0 : translate_to_evdev_button (unsigned int button)
186 : : {
187 : 0 : switch (button)
188 : : {
189 : : case VALENT_POINTER_PRIMARY:
190 : : return BTN_LEFT;
191 : :
192 : : case VALENT_POINTER_MIDDLE:
193 : : return BTN_MIDDLE;
194 : :
195 : : case VALENT_POINTER_SECONDARY:
196 : : return BTN_RIGHT;
197 : :
198 : 0 : default:
199 : : /* Any other buttons go after the legacy scroll buttons (4-7). */
200 : 0 : return button + (BTN_LEFT - 1) - 4;
201 : : }
202 : : }
203 : :
204 : : static void
205 : 0 : valent_xdp_input_pointer_axis (ValentInputAdapter *adapter,
206 : : double dx,
207 : : double dy)
208 : : {
209 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (adapter);
210 : :
211 : 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
212 : 0 : g_assert (VALENT_IS_XDP_INPUT (self));
213 : 0 : g_assert (!G_APPROX_VALUE (dx, 0.0, 0.01) || !G_APPROX_VALUE (dy, 0.0, 0.01));
214 : :
215 : 0 : if G_UNLIKELY (!ensure_session (self))
216 : : return;
217 : :
218 : 0 : if (self->delegate != NULL)
219 : : {
220 : : #ifdef HAVE_LIBEI
221 : 0 : valent_input_adapter_pointer_axis (self->delegate, dx, dy);
222 : : #endif /* HAVE_LIBEI */
223 : : }
224 : : else
225 : : {
226 : 0 : xdp_session_pointer_axis (self->session, FALSE, dx, dy);
227 : 0 : xdp_session_pointer_axis (self->session, TRUE, 0.0, 0.0);
228 : : }
229 : : }
230 : :
231 : : static void
232 : 0 : valent_xdp_input_pointer_button (ValentInputAdapter *adapter,
233 : : unsigned int button,
234 : : gboolean pressed)
235 : : {
236 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (adapter);
237 : :
238 : 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
239 : 0 : g_assert (VALENT_IS_XDP_INPUT (self));
240 : :
241 : 0 : if G_UNLIKELY (!ensure_session (self))
242 : : return;
243 : :
244 : 0 : if (self->delegate != NULL)
245 : : {
246 : : #ifdef HAVE_LIBEI
247 : 0 : valent_input_adapter_pointer_button (self->delegate, button, pressed);
248 : : #endif /* HAVE_LIBEI */
249 : : }
250 : : else
251 : : {
252 : 0 : button = translate_to_evdev_button (button);
253 : 0 : xdp_session_pointer_button (self->session, button, pressed);
254 : : }
255 : : }
256 : :
257 : : static void
258 : 0 : valent_xdp_input_pointer_motion (ValentInputAdapter *adapter,
259 : : double dx,
260 : : double dy)
261 : : {
262 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (adapter);
263 : :
264 : 0 : g_assert (VALENT_IS_INPUT_ADAPTER (adapter));
265 : 0 : g_assert (VALENT_IS_XDP_INPUT (self));
266 : :
267 : 0 : if G_UNLIKELY (!ensure_session (self))
268 : : return;
269 : :
270 : 0 : if (self->delegate != NULL)
271 : : {
272 : : #ifdef HAVE_LIBEI
273 : 0 : valent_input_adapter_pointer_motion (self->delegate, dx, dy);
274 : : #endif /* HAVE_LIBEI */
275 : : }
276 : : else
277 : : {
278 : 0 : xdp_session_pointer_motion (self->session, dx, dy);
279 : : }
280 : : }
281 : :
282 : :
283 : : /*
284 : : * ValentObject
285 : : */
286 : : static void
287 : 0 : valent_xdp_input_destroy (ValentObject *object)
288 : : {
289 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (object);
290 : :
291 : 0 : if (self->session != NULL)
292 : 0 : xdp_session_close (self->session);
293 : :
294 : 0 : on_session_closed (self);
295 : :
296 : 0 : VALENT_OBJECT_CLASS (valent_xdp_input_parent_class)->destroy (object);
297 : 0 : }
298 : :
299 : : /*
300 : : * GObject
301 : : */
302 : : static void
303 : 0 : valent_xdp_input_finalize (GObject *object)
304 : : {
305 : 0 : ValentXdpInput *self = VALENT_XDP_INPUT (object);
306 : :
307 : 0 : g_clear_object (&self->settings);
308 : 0 : g_clear_object (&self->session);
309 : :
310 : 0 : G_OBJECT_CLASS (valent_xdp_input_parent_class)->finalize (object);
311 : 0 : }
312 : :
313 : : static void
314 : 0 : valent_xdp_input_class_init (ValentXdpInputClass *klass)
315 : : {
316 : 0 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
317 : 0 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
318 : 0 : ValentInputAdapterClass *adapter_class = VALENT_INPUT_ADAPTER_CLASS (klass);
319 : :
320 : 0 : object_class->finalize = valent_xdp_input_finalize;
321 : :
322 : 0 : vobject_class->destroy = valent_xdp_input_destroy;
323 : :
324 : 0 : adapter_class->keyboard_keysym = valent_xdp_input_keyboard_keysym;
325 : 0 : adapter_class->pointer_axis = valent_xdp_input_pointer_axis;
326 : 0 : adapter_class->pointer_button = valent_xdp_input_pointer_button;
327 : 0 : adapter_class->pointer_motion = valent_xdp_input_pointer_motion;
328 : : }
329 : :
330 : : static void
331 : 0 : valent_xdp_input_init (ValentXdpInput *self)
332 : : {
333 : 0 : self->settings = g_settings_new ("ca.andyholmes.Valent.Plugin.xdp");
334 : 0 : }
335 : :
|