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"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <glib-object.h>
9 : : #include <libpeas.h>
10 : : #include <libvalent-core.h>
11 : :
12 : : #include "valent-input.h"
13 : : #include "valent-input-adapter.h"
14 : :
15 : :
16 : : /**
17 : : * ValentInput:
18 : : *
19 : : * A class for controlling pointer and keyboard devices.
20 : : *
21 : : * `ValentInput` is an abstraction of virtual input devices, intended for use by
22 : : * [class@Valent.DevicePlugin] implementations.
23 : : *
24 : : * Plugins can implement [class@Valent.InputAdapter] to provide an interface to
25 : : * control the pointer and keyboard.
26 : : *
27 : : * Since: 1.0
28 : : */
29 : :
30 : : struct _ValentInput
31 : : {
32 : : ValentComponent parent_instance;
33 : :
34 : : ValentInputAdapter *default_adapter;
35 : : GPtrArray *adapters; /* complete list of adapters */
36 : : GListModel *exports; /* adapters marked for export */
37 : : GPtrArray *items; /* adapters exposed by GListModel */
38 : : };
39 : :
40 : : static void g_list_model_iface_init (GListModelInterface *iface);
41 : :
42 [ + + + - ]: 211 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentInput, valent_input, VALENT_TYPE_COMPONENT,
43 : : G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_model_iface_init))
44 : :
45 : :
46 : : static ValentInput *default_input = NULL;
47 : :
48 : :
49 : : static void
50 : 7 : on_items_changed (GListModel *list,
51 : : unsigned int position,
52 : : unsigned int removed,
53 : : unsigned int added,
54 : : ValentInput *self)
55 : : {
56 : 7 : unsigned int real_position = 0;
57 : :
58 : 7 : VALENT_ENTRY;
59 : :
60 [ + - ]: 7 : g_assert (G_IS_LIST_MODEL (list));
61 [ + - ]: 7 : g_assert (VALENT_IS_INPUT (self));
62 : :
63 : : /* Translate the adapter position */
64 [ + - ]: 7 : for (unsigned int i = 0; i < self->adapters->len; i++)
65 : : {
66 : 7 : GListModel *adapter = g_ptr_array_index (self->adapters, i);
67 : :
68 [ - + ]: 7 : if (adapter == list)
69 : : break;
70 : :
71 : 0 : real_position += g_list_model_get_n_items (adapter);
72 : : }
73 : :
74 : 7 : real_position += position;
75 : :
76 : : /* Propagate the changes */
77 [ + + ]: 9 : for (unsigned int i = 0; i < removed; i++)
78 : : {
79 : 2 : g_autoptr (ValentInputAdapter) adapter = NULL;
80 : :
81 : 2 : adapter = g_ptr_array_steal_index (self->items, real_position);
82 : :
83 [ + - ]: 2 : VALENT_NOTE ("removed %s", G_OBJECT_TYPE_NAME (adapter));
84 : : }
85 : :
86 [ + + ]: 9 : for (unsigned int i = 0; i < added; i++)
87 : : {
88 : 2 : ValentInputAdapter *adapter = NULL;
89 : :
90 : 2 : adapter = g_list_model_get_item (list, position + i);
91 : 2 : g_ptr_array_insert (self->items, real_position + i, adapter);
92 : :
93 : 2 : VALENT_NOTE ("added %s", G_OBJECT_TYPE_NAME (adapter));
94 : : }
95 : :
96 : 7 : g_list_model_items_changed (G_LIST_MODEL (self), real_position, removed, added);
97 : :
98 : 7 : VALENT_EXIT;
99 : : }
100 : :
101 : : /*
102 : : * GListModel
103 : : */
104 : : static gpointer
105 : 0 : valent_input_get_item (GListModel *list,
106 : : unsigned int position)
107 : : {
108 : 0 : ValentInput *self = VALENT_INPUT (list);
109 : :
110 [ # # ]: 0 : g_assert (VALENT_IS_INPUT (self));
111 : :
112 [ # # ]: 0 : if G_UNLIKELY (position >= self->items->len)
113 : : return NULL;
114 : :
115 : 0 : return g_object_ref (g_ptr_array_index (self->items, position));
116 : : }
117 : :
118 : : static GType
119 : 0 : valent_input_get_item_type (GListModel *list)
120 : : {
121 : 0 : return VALENT_TYPE_INPUT_ADAPTER;
122 : : }
123 : :
124 : : static unsigned int
125 : 0 : valent_input_get_n_items (GListModel *list)
126 : : {
127 : 0 : ValentInput *self = VALENT_INPUT (list);
128 : :
129 [ # # ]: 0 : g_assert (VALENT_IS_INPUT (self));
130 : :
131 : 0 : return self->items->len;
132 : : }
133 : :
134 : : static void
135 : 5 : g_list_model_iface_init (GListModelInterface *iface)
136 : : {
137 : 5 : iface->get_item = valent_input_get_item;
138 : 5 : iface->get_item_type = valent_input_get_item_type;
139 : 5 : iface->get_n_items = valent_input_get_n_items;
140 : 5 : }
141 : :
142 : : /*
143 : : * ValentComponent
144 : : */
145 : : static void
146 : 7 : valent_input_bind_preferred (ValentComponent *component,
147 : : GObject *extension)
148 : : {
149 : 7 : ValentInput *self = VALENT_INPUT (component);
150 : 7 : ValentInputAdapter *adapter = VALENT_INPUT_ADAPTER (extension);
151 : :
152 : 7 : VALENT_ENTRY;
153 : :
154 [ + - ]: 7 : g_assert (VALENT_IS_INPUT (self));
155 [ + - - + ]: 7 : g_assert (adapter == NULL || VALENT_IS_INPUT_ADAPTER (adapter));
156 : :
157 : 7 : self->default_adapter = adapter;
158 : :
159 : 7 : VALENT_EXIT;
160 : : }
161 : :
162 : : /*
163 : : * ValentObject
164 : : */
165 : : static void
166 : 3 : valent_input_destroy (ValentObject *object)
167 : : {
168 : 3 : ValentInput *self = VALENT_INPUT (object);
169 : :
170 : 3 : g_list_store_remove_all (G_LIST_STORE (self->exports));
171 : :
172 : 3 : VALENT_OBJECT_CLASS (valent_input_parent_class)->destroy (object);
173 : 3 : }
174 : :
175 : : /*
176 : : * GObject
177 : : */
178 : : static void
179 : 3 : valent_input_finalize (GObject *object)
180 : : {
181 : 3 : ValentInput *self = VALENT_INPUT (object);
182 : :
183 [ + - ]: 3 : g_clear_object (&self->exports);
184 [ + - ]: 3 : g_clear_pointer (&self->adapters, g_ptr_array_unref);
185 [ + - ]: 3 : g_clear_pointer (&self->items, g_ptr_array_unref);
186 : :
187 : 3 : G_OBJECT_CLASS (valent_input_parent_class)->finalize (object);
188 : 3 : }
189 : :
190 : : static void
191 : 5 : valent_input_class_init (ValentInputClass *klass)
192 : : {
193 : 5 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
194 : 5 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
195 : 5 : ValentComponentClass *component_class = VALENT_COMPONENT_CLASS (klass);
196 : :
197 : 5 : object_class->finalize = valent_input_finalize;
198 : :
199 : 5 : vobject_class->destroy = valent_input_destroy;
200 : :
201 : 5 : component_class->bind_preferred = valent_input_bind_preferred;
202 : : }
203 : :
204 : : static void
205 : 5 : valent_input_init (ValentInput *self)
206 : : {
207 : 5 : self->adapters = g_ptr_array_new_with_free_func (g_object_unref);
208 : 5 : self->items = g_ptr_array_new_with_free_func (g_object_unref);
209 : :
210 : 5 : self->exports = G_LIST_MODEL (g_list_store_new (VALENT_TYPE_INPUT_ADAPTER));
211 : 5 : g_signal_connect_object (self->exports,
212 : : "items-changed",
213 : : G_CALLBACK (on_items_changed),
214 : : self, 0);
215 : 5 : g_ptr_array_add (self->adapters, g_object_ref (self->exports));
216 : 5 : }
217 : :
218 : : /**
219 : : * valent_input_get_default:
220 : : *
221 : : * Get the default [class@Valent.Input].
222 : : *
223 : : * Returns: (transfer none) (not nullable): a `ValentInput`
224 : : *
225 : : * Since: 1.0
226 : : */
227 : : ValentInput *
228 : 12 : valent_input_get_default (void)
229 : : {
230 [ + + ]: 12 : if (default_input == NULL)
231 : : {
232 : 5 : default_input = g_object_new (VALENT_TYPE_INPUT,
233 : : "plugin-domain", "input",
234 : : "plugin-type", VALENT_TYPE_INPUT_ADAPTER,
235 : : NULL);
236 : :
237 : 5 : g_object_add_weak_pointer (G_OBJECT (default_input),
238 : : (gpointer)&default_input);
239 : : }
240 : :
241 : 12 : return default_input;
242 : : }
243 : :
244 : : /**
245 : : * valent_input_export_adapter:
246 : : * @input: a `ValentInput`
247 : : * @adapter: a `ValentInputAdapter`
248 : : *
249 : : * Export @adapter on all adapters that support it.
250 : : *
251 : : * Since: 1.0
252 : : */
253 : : void
254 : 2 : valent_input_export_adapter (ValentInput *input,
255 : : ValentInputAdapter *adapter)
256 : : {
257 : 2 : VALENT_ENTRY;
258 : :
259 [ + - ]: 2 : g_return_if_fail (VALENT_IS_INPUT (input));
260 [ - + ]: 2 : g_return_if_fail (VALENT_IS_INPUT_ADAPTER (adapter));
261 : :
262 : 2 : g_list_store_append (G_LIST_STORE (input->exports), adapter);
263 : :
264 : 2 : VALENT_EXIT;
265 : : }
266 : :
267 : : /**
268 : : * valent_input_unexport_adapter:
269 : : * @input: a `ValentInput`
270 : : * @adapter: a `ValentInputAdapter`
271 : : *
272 : : * Unexport @adapter from all adapters that support it.
273 : : *
274 : : * Since: 1.0
275 : : */
276 : : void
277 : 2 : valent_input_unexport_adapter (ValentInput *input,
278 : : ValentInputAdapter *adapter)
279 : : {
280 : 2 : unsigned int position = 0;
281 : :
282 : 2 : VALENT_ENTRY;
283 : :
284 [ + - ]: 2 : g_return_if_fail (VALENT_IS_INPUT (input));
285 [ - + ]: 2 : g_return_if_fail (VALENT_IS_INPUT_ADAPTER (adapter));
286 : :
287 [ - + ]: 2 : if (!g_list_store_find (G_LIST_STORE (input->exports), adapter, &position))
288 : : {
289 : 0 : g_critical ("%s(): unknown adapter %s",
290 : : G_STRFUNC,
291 : : G_OBJECT_TYPE_NAME (adapter));
292 : 0 : return;
293 : : }
294 : :
295 : 2 : g_list_store_remove (G_LIST_STORE (input->exports), position);
296 : :
297 : 2 : VALENT_EXIT;
298 : : }
299 : :
300 : : /**
301 : : * valent_input_keyboard_keysym:
302 : : * @input: a `ValentInput`
303 : : * @keysym: a keysym
304 : : * @state: %TRUE to press, or %FALSE to release
305 : : *
306 : : * Press or release @keysym.
307 : : *
308 : : * Since: 1.0
309 : : */
310 : : void
311 : 26 : valent_input_keyboard_keysym (ValentInput *input,
312 : : uint32_t keysym,
313 : : gboolean state)
314 : : {
315 : 26 : VALENT_ENTRY;
316 : :
317 [ + - ]: 26 : g_return_if_fail (VALENT_IS_INPUT (input));
318 : :
319 [ + - ]: 26 : if G_LIKELY (input->default_adapter != NULL)
320 : 26 : valent_input_adapter_keyboard_keysym (input->default_adapter, keysym, state);
321 : :
322 : 26 : VALENT_EXIT;
323 : : }
324 : :
325 : : /**
326 : : * valent_input_pointer_axis:
327 : : * @input: a `ValentInput`
328 : : * @dx: movement on x-axis
329 : : * @dy: movement on y-axis
330 : : *
331 : : * Scroll the surface under the pointer (@dx, @dy), relative to its current
332 : : * position.
333 : : *
334 : : * Since: 1.0
335 : : */
336 : : void
337 : 3 : valent_input_pointer_axis (ValentInput *input,
338 : : double dx,
339 : : double dy)
340 : : {
341 : 3 : VALENT_ENTRY;
342 : :
343 [ + - ]: 3 : g_return_if_fail (VALENT_IS_INPUT (input));
344 : :
345 [ + - ]: 3 : if G_LIKELY (input->default_adapter != NULL)
346 : 3 : valent_input_adapter_pointer_axis (input->default_adapter, dx, dy);
347 : :
348 : 3 : VALENT_EXIT;
349 : : }
350 : :
351 : : /**
352 : : * valent_input_pointer_button:
353 : : * @input: a `ValentInput`
354 : : * @button: a button
355 : : * @state: %TRUE to press, or %FALSE to release
356 : : *
357 : : * Press or release @button.
358 : : *
359 : : * Since: 1.0
360 : : */
361 : : void
362 : 16 : valent_input_pointer_button (ValentInput *input,
363 : : unsigned int button,
364 : : gboolean state)
365 : : {
366 : 16 : VALENT_ENTRY;
367 : :
368 [ + - ]: 16 : g_return_if_fail (VALENT_IS_INPUT (input));
369 : :
370 [ + - ]: 16 : if G_LIKELY (input->default_adapter != NULL)
371 : 16 : valent_input_adapter_pointer_button (input->default_adapter, button, state);
372 : :
373 : 16 : VALENT_EXIT;
374 : : }
375 : :
376 : : /**
377 : : * valent_input_pointer_motion:
378 : : * @input: a `ValentInput`
379 : : * @dx: position on x-axis
380 : : * @dy: position on y-axis
381 : : *
382 : : * Move the pointer (@dx, @dy), relative to its current position.
383 : : *
384 : : * Since: 1.0
385 : : */
386 : : void
387 : 6 : valent_input_pointer_motion (ValentInput *input,
388 : : double dx,
389 : : double dy)
390 : : {
391 : 6 : VALENT_ENTRY;
392 : :
393 [ + - ]: 6 : g_return_if_fail (VALENT_IS_INPUT (input));
394 : :
395 [ + - ]: 6 : if G_LIKELY (input->default_adapter != NULL)
396 : 6 : valent_input_adapter_pointer_motion (input->default_adapter, dx, dy);
397 : :
398 : 6 : VALENT_EXIT;
399 : : }
400 : :
|