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-input-remote"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <adwaita.h>
9 : : #include <glib/gi18n-lib.h>
10 : : #include <gtk/gtk.h>
11 : : #include <valent.h>
12 : :
13 : : #include "valent-input-remote.h"
14 : : #include "valent-ui-utils-private.h"
15 : :
16 : : #define CAPTURE_THRESHOLD_MS 50
17 : :
18 : :
19 : : struct _ValentInputRemote
20 : : {
21 : : AdwWindow parent_instance;
22 : :
23 : : GListModel *adapters;
24 : : ValentInputAdapter *adapter;
25 : :
26 : : /* Keyboard State */
27 : : unsigned int capture_keyboard : 1;
28 : : unsigned int capture_keyboard_release : 1;
29 : :
30 : : /* Pointer State */
31 : : unsigned int claimed : 1;
32 : : uint32_t timestamp;
33 : : double last_x;
34 : : double last_y;
35 : : double last_v;
36 : : int scale;
37 : :
38 : : /* template */
39 : : GtkDropDown *input_adapter;
40 : : GtkEventController *keyboard;
41 : : GtkWidget *touchpad;
42 : : GtkGesture *pointer_scroll;
43 : : GtkGesture *touch_single;
44 : : GtkGesture *touch_double;
45 : : GtkGesture *touch_triple;
46 : : GtkTextBuffer *compose_text;
47 : : GtkFilter *filter;
48 : : GtkFilterListModel *model;
49 : : };
50 : :
51 [ + + + - ]: 36 : G_DEFINE_FINAL_TYPE (ValentInputRemote, valent_input_remote, ADW_TYPE_WINDOW)
52 : :
53 : : typedef enum {
54 : : PROP_ADAPTERS = 1,
55 : : PROP_CAPTURE_KEYBOARD,
56 : : } ValentInputRemoteProperty;
57 : :
58 : : static GParamSpec *properties[PROP_CAPTURE_KEYBOARD + 1] = { NULL, };
59 : :
60 : : static gboolean
61 : 1 : valent_input_remote_filter (gpointer item,
62 : : gpointer user_data)
63 : : {
64 : 1 : return VALENT_IS_DEVICE (valent_object_get_parent (VALENT_OBJECT (item)));
65 : : }
66 : :
67 : : static inline gboolean
68 : 0 : valent_input_remote_check_adapter (ValentInputRemote *self)
69 : : {
70 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
71 : :
72 [ # # ]: 0 : if G_UNLIKELY (self->adapter == NULL)
73 : : {
74 : 0 : self->claimed = FALSE;
75 : 0 : self->timestamp = 0;
76 : 0 : self->last_x = 0.0;
77 : 0 : self->last_y = 0.0;
78 : 0 : self->last_v = 0.0;
79 : :
80 : 0 : return FALSE;
81 : : }
82 : :
83 : : return TRUE;
84 : : }
85 : :
86 : : /*
87 : : * Keyboard Input
88 : : */
89 : : static gboolean
90 : 0 : on_key_pressed (GtkEventControllerKey *controller,
91 : : unsigned int keyval,
92 : : unsigned int keycode,
93 : : GdkModifierType state,
94 : : ValentInputRemote *self)
95 : : {
96 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
97 : :
98 [ # # ]: 0 : if (!self->capture_keyboard)
99 : : return FALSE;
100 : :
101 : : /* Check for <Control_L> + <Alt_L> capture release shortcut
102 : : */
103 [ # # ]: 0 : if ((keyval == GDK_KEY_Alt_L && state == GDK_CONTROL_MASK) ||
104 [ # # ]: 0 : (keyval == GDK_KEY_Control_L && state == GDK_ALT_MASK))
105 : : {
106 : 0 : self->capture_keyboard_release = TRUE;
107 : : }
108 : : else
109 : : {
110 : 0 : self->capture_keyboard_release = FALSE;
111 : : }
112 : :
113 [ # # ]: 0 : if (valent_input_remote_check_adapter (self))
114 : 0 : valent_input_adapter_keyboard_keysym (self->adapter, keyval, TRUE);
115 : :
116 : : return TRUE;
117 : : }
118 : :
119 : : static void
120 : 0 : on_key_released (GtkEventControllerKey *controller,
121 : : unsigned int keyval,
122 : : unsigned int keycode,
123 : : GdkModifierType state,
124 : : ValentInputRemote *self)
125 : : {
126 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
127 : :
128 [ # # ]: 0 : if (!self->capture_keyboard)
129 : : return;
130 : :
131 : : /* Check for <Control_L> + <Alt_L> capture release shortcut
132 : : */
133 [ # # ]: 0 : if (self->capture_keyboard_release)
134 : : {
135 [ # # ]: 0 : if ((keyval == GDK_KEY_Alt_L && state == GDK_ALT_MASK) ||
136 [ # # ]: 0 : (keyval == GDK_KEY_Control_L && state == GDK_CONTROL_MASK))
137 : : {
138 : 0 : self->capture_keyboard_release = FALSE;
139 : 0 : self->capture_keyboard = FALSE;
140 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CAPTURE_KEYBOARD]);
141 : : }
142 : : }
143 : :
144 [ # # ]: 0 : if (valent_input_remote_check_adapter (self))
145 : 0 : valent_input_adapter_keyboard_keysym (self->adapter, keyval, FALSE);
146 : : }
147 : :
148 : : /*
149 : : * Pointer Input
150 : : */
151 : : static inline void
152 : 0 : get_last_update_time (GtkGesture *gesture,
153 : : GdkEventSequence *sequence,
154 : : uint32_t *timestamp)
155 : : {
156 : 0 : GdkEvent *event = NULL;
157 : :
158 [ # # ]: 0 : if (sequence != NULL)
159 : 0 : event = gtk_gesture_get_last_event (gesture, sequence);
160 : :
161 [ # # ]: 0 : if (event != NULL)
162 : 0 : *timestamp = gdk_event_get_time (event);
163 : 0 : }
164 : :
165 : : static inline gboolean
166 : 0 : calculate_delta (ValentInputRemote *self,
167 : : double dx,
168 : : double dy,
169 : : uint32_t dt,
170 : : double *cx,
171 : : double *cy)
172 : : {
173 : 0 : double dr, v, m;
174 : :
175 : 0 : dr = sqrt (pow (dx, 2) + pow (dy, 2));
176 : 0 : v = dr / dt;
177 : :
178 [ # # # # ]: 0 : if (!G_APPROX_VALUE (self->last_v, 0.0, 0.01))
179 : 0 : self->last_v = (v + self->last_v) / 2;
180 : : else
181 : 0 : self->last_v = v;
182 : :
183 : : // TODO: acceleration setting
184 : 0 : m = pow (self->last_v, 1.0);
185 : 0 : m = fmin (4.0, fmax (m, 0.25));
186 : :
187 : 0 : *cx = round (dx * m);
188 : 0 : *cy = round (dy * m);
189 : :
190 : 0 : return dt >= CAPTURE_THRESHOLD_MS;
191 : : }
192 : :
193 : : static inline void
194 : 0 : valent_input_remote_pointer_reset (ValentInputRemote *self)
195 : : {
196 : 0 : self->claimed = FALSE;
197 : 0 : self->last_v = 0.0;
198 : 0 : self->last_x = 0.0;
199 : 0 : self->last_y = 0.0;
200 : 0 : self->timestamp = 0;
201 : 0 : }
202 : :
203 : : /*
204 : : * Scroll Mapping
205 : : */
206 : : static gboolean
207 : 0 : on_scroll (GtkEventControllerScroll *controller,
208 : : double dx,
209 : : double dy,
210 : : ValentInputRemote *self)
211 : : {
212 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
213 : :
214 [ # # ]: 0 : if (valent_input_remote_check_adapter (self))
215 : 0 : valent_input_adapter_pointer_axis (self->adapter, dx, dy);
216 : :
217 : 0 : return TRUE;
218 : : }
219 : :
220 : : /*
221 : : * Pointer Button Mapping
222 : : *
223 : : * This gesture maps pointer button presses and releases directly, except in the
224 : : * case of a press-move sequence of the primary button, which is used to emulate
225 : : * touchpad motion.
226 : : */
227 : : static void
228 : 0 : on_single_begin (GtkGestureDrag *gesture,
229 : : double start_x,
230 : : double start_y,
231 : : ValentInputRemote *self)
232 : : {
233 : 0 : GtkGestureSingle *single = GTK_GESTURE_SINGLE (gesture);
234 : 0 : unsigned int button = 0;
235 : :
236 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
237 : :
238 [ # # ]: 0 : if (!valent_input_remote_check_adapter (self))
239 : : return;
240 : :
241 : : /* Relative pointer motion is only emulated for the primary button, otherwise
242 : : * presses and releases are mapped directly to the adapter. */
243 : 0 : button = gtk_gesture_single_get_current_button (single);
244 : :
245 [ # # ]: 0 : if (button == GDK_BUTTON_PRIMARY)
246 : : {
247 : 0 : GdkEventSequence *sequence = NULL;
248 : 0 : uint32_t timestamp = 0;
249 : :
250 : 0 : sequence = gtk_gesture_single_get_current_sequence (single);
251 : 0 : get_last_update_time (GTK_GESTURE (gesture), sequence, ×tamp);
252 : :
253 : 0 : self->last_x = start_x;
254 : 0 : self->last_y = start_y;
255 : 0 : self->timestamp = timestamp;
256 : : }
257 : :
258 : : /* Always pass through the button press, since pointer motion is only
259 : : * emulated behaviour. */
260 : 0 : valent_input_adapter_pointer_button (self->adapter, button, TRUE);
261 : : }
262 : :
263 : : static void
264 : 0 : on_single_update (GtkGesture *gesture,
265 : : GdkEventSequence *sequence,
266 : : ValentInputRemote *self)
267 : : {
268 : 0 : unsigned int button = 0;
269 : 0 : uint32_t timestamp = 0;
270 : 0 : double x, y;
271 : 0 : double dx, dy;
272 : 0 : uint32_t dt;
273 : 0 : double cx, cy;
274 : :
275 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
276 : :
277 [ # # ]: 0 : if (!valent_input_remote_check_adapter (self))
278 : 0 : return;
279 : :
280 : 0 : button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
281 : :
282 [ # # ]: 0 : if (button != GDK_BUTTON_PRIMARY)
283 : : return;
284 : :
285 : 0 : get_last_update_time (gesture, sequence, ×tamp);
286 : 0 : gtk_gesture_get_point (gesture, sequence, &x, &y);
287 : :
288 : 0 : dt = timestamp - self->timestamp;
289 : 0 : dx = (x - self->last_x) * self->scale;
290 : 0 : dy = (y - self->last_y) * self->scale;
291 : :
292 [ # # ]: 0 : if (!calculate_delta (self, dx, dy, dt, &cx, &cy))
293 : : return;
294 : :
295 [ # # # # : 0 : if (dx >= 1.0 || dx <= -1.0 || dy >= 1.0 || dy <= -1.0)
# # # # ]
296 : : {
297 : 0 : self->claimed = TRUE;
298 : 0 : gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_CLAIMED);
299 : :
300 : 0 : self->last_x = x;
301 : 0 : self->last_y = y;
302 : 0 : self->timestamp = timestamp;
303 : :
304 : 0 : valent_input_adapter_pointer_motion (self->adapter, cx, cy);
305 : : }
306 : : }
307 : :
308 : : static void
309 : 0 : on_single_end (GtkGestureDrag *gesture,
310 : : double offset_x,
311 : : double offset_y,
312 : : ValentInputRemote *self)
313 : : {
314 : 0 : unsigned int button = 0;
315 : :
316 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
317 : :
318 [ # # ]: 0 : if (!valent_input_remote_check_adapter (self))
319 : : return;
320 : :
321 : 0 : button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
322 : 0 : valent_input_adapter_pointer_button (self->adapter, button, FALSE);
323 : 0 : valent_input_remote_pointer_reset (self);
324 : : }
325 : :
326 : : /*
327 : : * Touchpad Emulation
328 : : *
329 : : * These callbacks map gestures on the "touchpad" area to events including:
330 : : *
331 : : * - two-finger tap -> right click
332 : : * - three-finger tap -> middle click
333 : : */
334 : : static void
335 : 0 : on_double_begin (GtkGestureDrag *gesture,
336 : : double start_x,
337 : : double start_y,
338 : : ValentInputRemote *self)
339 : : {
340 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
341 : :
342 : : // TODO: In order to map two-finger presses directly to the input adapter,
343 : : // the implementation has to handle unpaired press-release sequences.
344 : : #if 0
345 : : if (!valent_input_remote_check_adapter (self))
346 : : return;
347 : :
348 : : valent_input_adapter_pointer_button (self->adapter,
349 : : GDK_BUTTON_SECONDARY,
350 : : TRUE);
351 : : #endif
352 : 0 : }
353 : :
354 : : static void
355 : 0 : on_double_end (GtkGestureDrag *gesture,
356 : : double offset_x,
357 : : double offset_y,
358 : : ValentInputRemote *self)
359 : : {
360 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
361 : :
362 [ # # ]: 0 : if (!valent_input_remote_check_adapter (self))
363 : : return;
364 : :
365 : : /* If the two-finger press wasn't claimed as a scroll event on the y-axis,
366 : : * simulate a right click by pressing and releasing the secondary button. */
367 : 0 : valent_input_adapter_pointer_button (self->adapter,
368 : : GDK_BUTTON_SECONDARY,
369 : : TRUE);
370 : 0 : valent_input_adapter_pointer_button (self->adapter,
371 : : GDK_BUTTON_SECONDARY,
372 : : FALSE);
373 : : }
374 : :
375 : : static void
376 : 0 : on_triple_begin (GtkGestureDrag *gesture,
377 : : double offset_x,
378 : : double offset_y,
379 : : ValentInputRemote *self)
380 : : {
381 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
382 : :
383 [ # # ]: 0 : if (!valent_input_remote_check_adapter (self))
384 : : return;
385 : :
386 : : /* Since there is no high-level event for three-finger drags, three-finger
387 : : * presses and releases can be mapped directly. */
388 : 0 : gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
389 : 0 : valent_input_adapter_pointer_button (self->adapter,
390 : : GDK_BUTTON_MIDDLE,
391 : : TRUE);
392 : : }
393 : :
394 : : static void
395 : 0 : on_triple_end (GtkGestureDrag *gesture,
396 : : double offset_x,
397 : : double offset_y,
398 : : ValentInputRemote *self)
399 : : {
400 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
401 : :
402 [ # # ]: 0 : if (!valent_input_remote_check_adapter (self))
403 : : return;
404 : :
405 : 0 : valent_input_adapter_pointer_button (self->adapter,
406 : : GDK_BUTTON_MIDDLE,
407 : : FALSE);
408 : : }
409 : :
410 : : /*
411 : : * Compose
412 : : */
413 : : static void
414 : 0 : on_compose_text_changed (GtkTextBuffer *buffer,
415 : : ValentInputRemote *self)
416 : : {
417 : 0 : gboolean enabled = FALSE;
418 : :
419 [ # # ]: 0 : if (gtk_text_buffer_get_char_count (buffer) > 0)
420 : 0 : enabled = valent_input_remote_check_adapter (self);
421 : :
422 : 0 : gtk_widget_action_set_enabled (GTK_WIDGET (self),
423 : : "remote.compose-send",
424 : : enabled);
425 : 0 : gtk_widget_action_set_enabled (GTK_WIDGET (self),
426 : : "remote.compose-clear",
427 : : enabled);
428 : 0 : }
429 : :
430 : : /*
431 : : * UI Callbacks
432 : : */
433 : : static void
434 : 0 : on_selected_item (GObject *object,
435 : : GParamSpec *pspec,
436 : : ValentInputRemote *self)
437 : : {
438 : 0 : ValentInputAdapter *adapter = NULL;
439 : :
440 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
441 : :
442 : 0 : adapter = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (object));
443 [ # # ]: 0 : if (g_set_object (&self->adapter, adapter))
444 : 0 : valent_input_remote_check_adapter (self);
445 : :
446 : 0 : on_compose_text_changed (self->compose_text, self);
447 : 0 : }
448 : :
449 : : static void
450 : 0 : on_stack_page_changed (GObject *object,
451 : : GParamSpec *pspec,
452 : : ValentInputRemote *self)
453 : : {
454 : 0 : AdwViewStack *stack = ADW_VIEW_STACK (object);
455 : 0 : const char *page_name = NULL;
456 : :
457 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
458 : :
459 : 0 : page_name = adw_view_stack_get_visible_child_name (stack);
460 [ # # # # ]: 0 : if (self->capture_keyboard && g_strcmp0 (page_name, "touchpad") != 0)
461 : 0 : g_object_set (self, "capture-keyboard", FALSE, NULL);
462 : 0 : }
463 : :
464 : : /*
465 : : * GActions
466 : : */
467 : : static void
468 : 0 : remote_compose_send_action (GtkWidget *widget,
469 : : const char *action_name,
470 : : GVariant *parameter)
471 : : {
472 : 0 : ValentInputRemote *self = VALENT_INPUT_REMOTE (widget);
473 : 0 : g_autofree char *text = NULL;
474 : 0 : const char *next;
475 : 0 : gunichar codepoint;
476 : :
477 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
478 : :
479 [ # # # # ]: 0 : if (!valent_input_remote_check_adapter (self) ||
480 : 0 : gtk_text_buffer_get_char_count (self->compose_text) == 0)
481 : 0 : return;
482 : :
483 : 0 : g_object_get (self->compose_text, "text", &text, NULL);
484 : 0 : g_object_set (self->compose_text, "text", "", NULL);
485 : :
486 : 0 : next = text;
487 [ # # ]: 0 : while ((codepoint = g_utf8_get_char (next)) != 0)
488 : : {
489 : 0 : uint32_t keysym;
490 : :
491 : 0 : keysym = gdk_unicode_to_keyval (codepoint);
492 : 0 : valent_input_adapter_keyboard_keysym (self->adapter, keysym, TRUE);
493 : 0 : valent_input_adapter_keyboard_keysym (self->adapter, keysym, FALSE);
494 : 0 : next = g_utf8_next_char (next);
495 : : }
496 : : }
497 : :
498 : : static void
499 : 0 : remote_compose_clear_action (GtkWidget *widget,
500 : : const char *action_name,
501 : : GVariant *parameter)
502 : : {
503 : 0 : ValentInputRemote *self = VALENT_INPUT_REMOTE (widget);
504 : :
505 [ # # ]: 0 : g_assert (VALENT_IS_INPUT_REMOTE (self));
506 : :
507 [ # # ]: 0 : if (gtk_text_buffer_get_char_count (self->compose_text) > 0)
508 : 0 : g_object_set (self->compose_text, "text", "", NULL);
509 : 0 : }
510 : :
511 : : /*
512 : : * GObject
513 : : */
514 : : static void
515 : 1 : valent_input_remote_dispose (GObject *object)
516 : : {
517 : 1 : ValentInputRemote *self = VALENT_INPUT_REMOTE (object);
518 : :
519 [ - + ]: 1 : g_clear_object (&self->adapter);
520 [ + - ]: 1 : g_clear_object (&self->adapters);
521 : :
522 : 1 : gtk_widget_dispose_template (GTK_WIDGET (object), VALENT_TYPE_INPUT_REMOTE);
523 : :
524 : 1 : G_OBJECT_CLASS (valent_input_remote_parent_class)->dispose (object);
525 : 1 : }
526 : :
527 : : static void
528 : 7 : valent_input_remote_get_property (GObject *object,
529 : : guint prop_id,
530 : : GValue *value,
531 : : GParamSpec *pspec)
532 : : {
533 : 7 : ValentInputRemote *self = VALENT_INPUT_REMOTE (object);
534 : :
535 [ + + - ]: 7 : switch ((ValentInputRemoteProperty)prop_id)
536 : : {
537 : 3 : case PROP_ADAPTERS:
538 : 3 : g_value_set_object (value, self->adapters);
539 : 3 : break;
540 : :
541 : 4 : case PROP_CAPTURE_KEYBOARD:
542 : 4 : g_value_set_boolean (value, self->capture_keyboard);
543 : 4 : break;
544 : :
545 : 0 : default:
546 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
547 : : }
548 : 7 : }
549 : :
550 : : static void
551 : 1 : valent_input_remote_set_property (GObject *object,
552 : : guint prop_id,
553 : : const GValue *value,
554 : : GParamSpec *pspec)
555 : : {
556 : 1 : ValentInputRemote *self = VALENT_INPUT_REMOTE (object);
557 : :
558 [ + - - ]: 1 : switch ((ValentInputRemoteProperty)prop_id)
559 : : {
560 : 1 : case PROP_ADAPTERS:
561 : 1 : self->adapters = g_value_dup_object (value);
562 : 1 : break;
563 : :
564 : 0 : case PROP_CAPTURE_KEYBOARD:
565 : 0 : self->capture_keyboard = g_value_get_boolean (value);
566 : 0 : break;
567 : :
568 : 0 : default:
569 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
570 : : }
571 : 1 : }
572 : :
573 : : static void
574 : 1 : valent_input_remote_class_init (ValentInputRemoteClass *klass)
575 : : {
576 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
577 : 1 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
578 : :
579 : 1 : object_class->dispose = valent_input_remote_dispose;
580 : 1 : object_class->get_property = valent_input_remote_get_property;
581 : 1 : object_class->set_property = valent_input_remote_set_property;
582 : :
583 : 1 : gtk_widget_class_set_template_from_resource (widget_class, "/plugins/gnome/valent-input-remote.ui");
584 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, input_adapter);
585 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, keyboard);
586 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, pointer_scroll);
587 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, touchpad);
588 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, touch_single);
589 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, touch_double);
590 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, touch_triple);
591 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, compose_text);
592 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, filter);
593 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentInputRemote, model);
594 : :
595 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_selected_item);
596 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_stack_page_changed);
597 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_key_pressed);
598 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_key_released);
599 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_scroll);
600 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_single_begin);
601 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_single_update);
602 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_single_end);
603 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_double_begin);
604 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_double_end);
605 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_triple_begin);
606 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_triple_end);
607 : 1 : gtk_widget_class_bind_template_callback (widget_class, on_compose_text_changed);
608 : :
609 : 2 : properties [PROP_ADAPTERS] =
610 : 1 : g_param_spec_object ("adapters", NULL, NULL,
611 : : G_TYPE_LIST_MODEL,
612 : : (G_PARAM_READWRITE |
613 : : G_PARAM_CONSTRUCT_ONLY |
614 : : G_PARAM_STATIC_STRINGS));
615 : :
616 : 2 : properties [PROP_CAPTURE_KEYBOARD] =
617 : 1 : g_param_spec_boolean ("capture-keyboard", NULL, NULL,
618 : : FALSE,
619 : : (G_PARAM_READWRITE |
620 : : G_PARAM_STATIC_STRINGS));
621 : :
622 : 1 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
623 : :
624 : 1 : gtk_widget_class_install_action (widget_class, "remote.compose-clear", NULL, remote_compose_clear_action);
625 : 1 : gtk_widget_class_install_action (widget_class, "remote.compose-send", NULL, remote_compose_send_action);
626 : 1 : gtk_widget_class_install_property_action (widget_class,
627 : : "remote.capture-keyboard",
628 : : "capture-keyboard");
629 : 1 : }
630 : :
631 : : static void
632 : 1 : valent_input_remote_init (ValentInputRemote *self)
633 : : {
634 : 1 : gtk_widget_init_template (GTK_WIDGET (self));
635 : 1 : gtk_gesture_group (self->touch_single, self->touch_double);
636 : 1 : gtk_gesture_group (self->touch_single, self->touch_triple);
637 : 1 : gtk_custom_filter_set_filter_func (GTK_CUSTOM_FILTER (self->filter),
638 : : valent_input_remote_filter,
639 : : self,
640 : : NULL);
641 : 1 : self->scale = gtk_widget_get_scale_factor (GTK_WIDGET (self));
642 : 1 : }
643 : :
|