Line |
Branch |
Exec |
Source |
1 |
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2014 Red Hat |
4 |
|
|
* |
5 |
|
|
* This program is free software; you can redistribute it and/or modify |
6 |
|
|
* it under the terms of the GNU General Public License as published by |
7 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
8 |
|
|
* (at your option) any later version. |
9 |
|
|
* |
10 |
|
|
* This program is distributed in the hope that it will be useful, |
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
* GNU General Public License for more details. |
14 |
|
|
* |
15 |
|
|
* You should have received a copy of the GNU General Public License |
16 |
|
|
* along with this program; if not, write to the Free Software |
17 |
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 |
|
|
* |
19 |
|
|
* Author: Carlos Garnacho <carlosg@gnome.org> |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
#include "config.h" |
23 |
|
|
|
24 |
|
|
#include <string.h> |
25 |
|
|
#include <gudev/gudev.h> |
26 |
|
|
|
27 |
|
|
#include "gsd-device-manager.h" |
28 |
|
|
#include "gsd-common-enums.h" |
29 |
|
|
#include "gnome-settings-bus.h" |
30 |
|
|
#include "gsd-input-helper.h" |
31 |
|
|
|
32 |
|
|
#ifdef GDK_WINDOWING_X11 |
33 |
|
|
#include <gdk/x11/gdkx.h> |
34 |
|
|
#include <X11/extensions/XInput2.h> |
35 |
|
|
#endif |
36 |
|
|
#ifdef GDK_WINDOWING_WAYLAND |
37 |
|
|
#include <gdk/wayland/gdkwayland.h> |
38 |
|
|
#endif |
39 |
|
|
|
40 |
|
|
typedef struct |
41 |
|
|
{ |
42 |
|
|
gchar *name; |
43 |
|
|
gchar *device_file; |
44 |
|
|
gchar *vendor_id; |
45 |
|
|
gchar *product_id; |
46 |
|
|
gchar *group; |
47 |
|
|
GsdDeviceType type; |
48 |
|
|
guint width; |
49 |
|
|
guint height; |
50 |
|
|
} GsdDevicePrivate; |
51 |
|
|
|
52 |
|
✗ |
G_DEFINE_TYPE_WITH_PRIVATE (GsdDevice, gsd_device, G_TYPE_OBJECT) |
53 |
|
|
|
54 |
|
|
typedef struct |
55 |
|
|
{ |
56 |
|
|
GObject parent_instance; |
57 |
|
|
GHashTable *devices; |
58 |
|
|
GUdevClient *udev_client; |
59 |
|
|
} GsdDeviceManagerPrivate; |
60 |
|
|
|
61 |
|
|
enum { |
62 |
|
|
PROP_NAME = 1, |
63 |
|
|
PROP_DEVICE_FILE, |
64 |
|
|
PROP_VENDOR_ID, |
65 |
|
|
PROP_PRODUCT_ID, |
66 |
|
|
PROP_TYPE, |
67 |
|
|
PROP_WIDTH, |
68 |
|
|
PROP_HEIGHT, |
69 |
|
|
PROP_GROUP |
70 |
|
|
}; |
71 |
|
|
|
72 |
|
|
enum { |
73 |
|
|
DEVICE_ADDED, |
74 |
|
|
DEVICE_REMOVED, |
75 |
|
|
DEVICE_CHANGED, |
76 |
|
|
N_SIGNALS |
77 |
|
|
}; |
78 |
|
|
|
79 |
|
|
/* Index matches GsdDeviceType */ |
80 |
|
|
const gchar *udev_ids[] = { |
81 |
|
|
"ID_INPUT_MOUSE", |
82 |
|
|
"ID_INPUT_KEYBOARD", |
83 |
|
|
"ID_INPUT_TOUCHPAD", |
84 |
|
|
"ID_INPUT_TABLET", |
85 |
|
|
"ID_INPUT_TOUCHSCREEN", |
86 |
|
|
"ID_INPUT_TABLET_PAD", |
87 |
|
|
}; |
88 |
|
|
|
89 |
|
|
static guint signals[N_SIGNALS] = { 0 }; |
90 |
|
|
|
91 |
|
✗ |
G_DEFINE_TYPE_WITH_PRIVATE (GsdDeviceManager, gsd_device_manager, G_TYPE_OBJECT) |
92 |
|
|
|
93 |
|
|
static void |
94 |
|
✗ |
gsd_device_init (GsdDevice *device) |
95 |
|
|
{ |
96 |
|
✗ |
} |
97 |
|
|
|
98 |
|
|
static void |
99 |
|
✗ |
gsd_device_set_property (GObject *object, |
100 |
|
|
guint prop_id, |
101 |
|
|
const GValue *value, |
102 |
|
|
GParamSpec *pspec) |
103 |
|
|
{ |
104 |
|
|
GsdDevicePrivate *priv; |
105 |
|
|
|
106 |
|
✗ |
priv = gsd_device_get_instance_private (GSD_DEVICE (object)); |
107 |
|
|
|
108 |
|
✗ |
switch (prop_id) { |
109 |
|
✗ |
case PROP_NAME: |
110 |
|
✗ |
priv->name = g_value_dup_string (value); |
111 |
|
✗ |
break; |
112 |
|
✗ |
case PROP_DEVICE_FILE: |
113 |
|
✗ |
priv->device_file = g_value_dup_string (value); |
114 |
|
✗ |
break; |
115 |
|
✗ |
case PROP_VENDOR_ID: |
116 |
|
✗ |
priv->vendor_id = g_value_dup_string (value); |
117 |
|
✗ |
break; |
118 |
|
✗ |
case PROP_PRODUCT_ID: |
119 |
|
✗ |
priv->product_id = g_value_dup_string (value); |
120 |
|
✗ |
break; |
121 |
|
✗ |
case PROP_TYPE: |
122 |
|
✗ |
priv->type = g_value_get_flags (value); |
123 |
|
✗ |
break; |
124 |
|
✗ |
case PROP_WIDTH: |
125 |
|
✗ |
priv->width = g_value_get_uint (value); |
126 |
|
✗ |
break; |
127 |
|
✗ |
case PROP_HEIGHT: |
128 |
|
✗ |
priv->height = g_value_get_uint (value); |
129 |
|
✗ |
break; |
130 |
|
✗ |
case PROP_GROUP: |
131 |
|
✗ |
priv->group = g_value_dup_string (value); |
132 |
|
✗ |
break; |
133 |
|
✗ |
default: |
134 |
|
✗ |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
135 |
|
✗ |
break; |
136 |
|
|
} |
137 |
|
✗ |
} |
138 |
|
|
|
139 |
|
|
static void |
140 |
|
✗ |
gsd_device_get_property (GObject *object, |
141 |
|
|
guint prop_id, |
142 |
|
|
GValue *value, |
143 |
|
|
GParamSpec *pspec) |
144 |
|
|
{ |
145 |
|
|
GsdDevicePrivate *priv; |
146 |
|
|
|
147 |
|
✗ |
priv = gsd_device_get_instance_private (GSD_DEVICE (object)); |
148 |
|
|
|
149 |
|
✗ |
switch (prop_id) { |
150 |
|
✗ |
case PROP_NAME: |
151 |
|
✗ |
g_value_set_string (value, priv->name); |
152 |
|
✗ |
break; |
153 |
|
✗ |
case PROP_DEVICE_FILE: |
154 |
|
✗ |
g_value_set_string (value, priv->device_file); |
155 |
|
✗ |
break; |
156 |
|
✗ |
case PROP_VENDOR_ID: |
157 |
|
✗ |
g_value_set_string (value, priv->vendor_id); |
158 |
|
✗ |
break; |
159 |
|
✗ |
case PROP_PRODUCT_ID: |
160 |
|
✗ |
g_value_set_string (value, priv->product_id); |
161 |
|
✗ |
break; |
162 |
|
✗ |
case PROP_TYPE: |
163 |
|
✗ |
g_value_set_flags (value, priv->type); |
164 |
|
✗ |
break; |
165 |
|
✗ |
case PROP_WIDTH: |
166 |
|
✗ |
g_value_set_uint (value, priv->width); |
167 |
|
✗ |
break; |
168 |
|
✗ |
case PROP_HEIGHT: |
169 |
|
✗ |
g_value_set_uint (value, priv->height); |
170 |
|
✗ |
break; |
171 |
|
✗ |
case PROP_GROUP: |
172 |
|
✗ |
g_value_set_string (value, priv->group); |
173 |
|
✗ |
break; |
174 |
|
✗ |
default: |
175 |
|
✗ |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
176 |
|
✗ |
break; |
177 |
|
|
} |
178 |
|
✗ |
} |
179 |
|
|
|
180 |
|
|
static void |
181 |
|
✗ |
gsd_device_finalize (GObject *object) |
182 |
|
|
{ |
183 |
|
|
GsdDevicePrivate *priv; |
184 |
|
|
|
185 |
|
✗ |
priv = gsd_device_get_instance_private (GSD_DEVICE (object)); |
186 |
|
|
|
187 |
|
✗ |
g_free (priv->name); |
188 |
|
✗ |
g_free (priv->vendor_id); |
189 |
|
✗ |
g_free (priv->product_id); |
190 |
|
✗ |
g_free (priv->device_file); |
191 |
|
✗ |
g_free (priv->group); |
192 |
|
|
|
193 |
|
✗ |
G_OBJECT_CLASS (gsd_device_parent_class)->finalize (object); |
194 |
|
✗ |
} |
195 |
|
|
|
196 |
|
|
static void |
197 |
|
✗ |
gsd_device_class_init (GsdDeviceClass *klass) |
198 |
|
|
{ |
199 |
|
✗ |
GObjectClass *object_class = G_OBJECT_CLASS (klass); |
200 |
|
|
|
201 |
|
✗ |
object_class->set_property = gsd_device_set_property; |
202 |
|
✗ |
object_class->get_property = gsd_device_get_property; |
203 |
|
✗ |
object_class->finalize = gsd_device_finalize; |
204 |
|
|
|
205 |
|
✗ |
g_object_class_install_property (object_class, |
206 |
|
|
PROP_NAME, |
207 |
|
|
g_param_spec_string ("name", |
208 |
|
|
"Name", |
209 |
|
|
"Name", |
210 |
|
|
NULL, |
211 |
|
|
G_PARAM_READWRITE | |
212 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
213 |
|
✗ |
g_object_class_install_property (object_class, |
214 |
|
|
PROP_DEVICE_FILE, |
215 |
|
|
g_param_spec_string ("device-file", |
216 |
|
|
"Device file", |
217 |
|
|
"Device file", |
218 |
|
|
NULL, |
219 |
|
|
G_PARAM_READWRITE | |
220 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
221 |
|
✗ |
g_object_class_install_property (object_class, |
222 |
|
|
PROP_VENDOR_ID, |
223 |
|
|
g_param_spec_string ("vendor-id", |
224 |
|
|
"Vendor ID", |
225 |
|
|
"Vendor ID", |
226 |
|
|
NULL, |
227 |
|
|
G_PARAM_READWRITE | |
228 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
229 |
|
✗ |
g_object_class_install_property (object_class, |
230 |
|
|
PROP_PRODUCT_ID, |
231 |
|
|
g_param_spec_string ("product-id", |
232 |
|
|
"Product ID", |
233 |
|
|
"Product ID", |
234 |
|
|
NULL, |
235 |
|
|
G_PARAM_READWRITE | |
236 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
237 |
|
✗ |
g_object_class_install_property (object_class, |
238 |
|
|
PROP_TYPE, |
239 |
|
|
g_param_spec_flags ("type", |
240 |
|
|
"Device type", |
241 |
|
|
"Device type", |
242 |
|
|
GSD_TYPE_DEVICE_TYPE, 0, |
243 |
|
|
G_PARAM_READWRITE | |
244 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
245 |
|
✗ |
g_object_class_install_property (object_class, |
246 |
|
|
PROP_WIDTH, |
247 |
|
|
g_param_spec_uint ("width", |
248 |
|
|
"Width", |
249 |
|
|
"Width", |
250 |
|
|
0, G_MAXUINT, 0, |
251 |
|
|
G_PARAM_READWRITE | |
252 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
253 |
|
✗ |
g_object_class_install_property (object_class, |
254 |
|
|
PROP_HEIGHT, |
255 |
|
|
g_param_spec_uint ("height", |
256 |
|
|
"Height", |
257 |
|
|
"Height", |
258 |
|
|
0, G_MAXUINT, 0, |
259 |
|
|
G_PARAM_READWRITE | |
260 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
261 |
|
✗ |
g_object_class_install_property (object_class, |
262 |
|
|
PROP_GROUP, |
263 |
|
|
g_param_spec_string ("group", |
264 |
|
|
"Group", |
265 |
|
|
"Group", |
266 |
|
|
NULL, |
267 |
|
|
G_PARAM_READWRITE | |
268 |
|
|
G_PARAM_CONSTRUCT_ONLY)); |
269 |
|
✗ |
} |
270 |
|
|
|
271 |
|
|
static void |
272 |
|
✗ |
gsd_device_manager_finalize (GObject *object) |
273 |
|
|
{ |
274 |
|
✗ |
GsdDeviceManager *manager = GSD_DEVICE_MANAGER (object); |
275 |
|
✗ |
GsdDeviceManagerPrivate *priv = gsd_device_manager_get_instance_private (manager); |
276 |
|
|
|
277 |
|
✗ |
g_hash_table_destroy (priv->devices); |
278 |
|
✗ |
g_object_unref (priv->udev_client); |
279 |
|
|
|
280 |
|
✗ |
G_OBJECT_CLASS (gsd_device_manager_parent_class)->finalize (object); |
281 |
|
✗ |
} |
282 |
|
|
|
283 |
|
|
static GList * |
284 |
|
✗ |
gsd_device_manager_real_list_devices (GsdDeviceManager *manager, |
285 |
|
|
GsdDeviceType type) |
286 |
|
|
{ |
287 |
|
✗ |
GsdDeviceManagerPrivate *priv = gsd_device_manager_get_instance_private (manager); |
288 |
|
|
GsdDeviceType device_type; |
289 |
|
✗ |
GList *devices = NULL; |
290 |
|
|
GHashTableIter iter; |
291 |
|
|
GsdDevice *device; |
292 |
|
|
|
293 |
|
✗ |
g_hash_table_iter_init (&iter, priv->devices); |
294 |
|
|
|
295 |
|
✗ |
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &device)) { |
296 |
|
✗ |
device_type = gsd_device_get_device_type (device); |
297 |
|
|
|
298 |
|
✗ |
if ((device_type & type) == type) |
299 |
|
✗ |
devices = g_list_prepend (devices, device); |
300 |
|
|
} |
301 |
|
|
|
302 |
|
✗ |
return devices; |
303 |
|
|
} |
304 |
|
|
|
305 |
|
|
static GsdDevice * |
306 |
|
✗ |
gsd_device_manager_real_lookup_device (GsdDeviceManager *manager, |
307 |
|
|
GdkDevice *gdk_device) |
308 |
|
|
{ |
309 |
|
✗ |
GsdDeviceManagerPrivate *priv = gsd_device_manager_get_instance_private (manager); |
310 |
|
✗ |
GdkDisplay *display = gdk_device_get_display (gdk_device); |
311 |
|
✗ |
const gchar *node_path = NULL; |
312 |
|
|
GHashTableIter iter; |
313 |
|
|
GsdDevice *device; |
314 |
|
|
|
315 |
|
|
#ifdef GDK_WINDOWING_X11 |
316 |
|
✗ |
if (GDK_IS_X11_DISPLAY (display)) { |
317 |
|
|
XIDeviceInfo *info; |
318 |
|
✗ |
int n_infos, i, source_id = 0; |
319 |
|
|
|
320 |
|
✗ |
gdk_x11_display_error_trap_push (display); |
321 |
|
✗ |
info = XIQueryDevice (gdk_x11_display_get_xdisplay (display), |
322 |
|
|
gdk_x11_device_get_id (gdk_device), |
323 |
|
|
&n_infos); |
324 |
|
✗ |
if (gdk_x11_display_error_trap_pop (display) != 0) |
325 |
|
✗ |
return NULL; |
326 |
|
✗ |
if (!info || n_infos != 1) |
327 |
|
✗ |
return NULL; |
328 |
|
|
|
329 |
|
✗ |
for (i = 0; i < info->num_classes; i++) { |
330 |
|
✗ |
if (info->classes[i]->type == XIValuatorClass) |
331 |
|
✗ |
source_id = info->classes[i]->sourceid; |
332 |
|
|
} |
333 |
|
|
|
334 |
|
✗ |
if (source_id != 0) |
335 |
|
✗ |
node_path = xdevice_get_device_node (source_id); |
336 |
|
|
} |
337 |
|
|
#endif |
338 |
|
|
#ifdef GDK_WINDOWING_WAYLAND |
339 |
|
✗ |
if (GDK_IS_WAYLAND_DISPLAY (display)) |
340 |
|
✗ |
node_path = g_strdup (gdk_wayland_device_get_node_path (gdk_device)); |
341 |
|
|
#endif |
342 |
|
✗ |
if (!node_path) |
343 |
|
✗ |
return NULL; |
344 |
|
|
|
345 |
|
✗ |
g_hash_table_iter_init (&iter, priv->devices); |
346 |
|
|
|
347 |
|
✗ |
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &device)) { |
348 |
|
✗ |
if (g_strcmp0 (node_path, |
349 |
|
✗ |
gsd_device_get_device_file (device)) == 0) { |
350 |
|
✗ |
return device; |
351 |
|
|
} |
352 |
|
|
} |
353 |
|
|
|
354 |
|
✗ |
return NULL; |
355 |
|
|
} |
356 |
|
|
|
357 |
|
|
static void |
358 |
|
✗ |
gsd_device_manager_class_init (GsdDeviceManagerClass *klass) |
359 |
|
|
{ |
360 |
|
✗ |
GsdDeviceManagerClass *manager_class = GSD_DEVICE_MANAGER_CLASS (klass); |
361 |
|
✗ |
GObjectClass *object_class = G_OBJECT_CLASS (klass); |
362 |
|
|
|
363 |
|
✗ |
object_class->finalize = gsd_device_manager_finalize; |
364 |
|
✗ |
manager_class->list_devices = gsd_device_manager_real_list_devices; |
365 |
|
✗ |
manager_class->lookup_device = gsd_device_manager_real_lookup_device; |
366 |
|
|
|
367 |
|
✗ |
signals[DEVICE_ADDED] = |
368 |
|
✗ |
g_signal_new ("device-added", |
369 |
|
|
GSD_TYPE_DEVICE_MANAGER, |
370 |
|
|
G_SIGNAL_RUN_LAST, |
371 |
|
|
G_STRUCT_OFFSET (GsdDeviceManagerClass, device_added), |
372 |
|
|
NULL, NULL, NULL, |
373 |
|
|
G_TYPE_NONE, 1, |
374 |
|
✗ |
GSD_TYPE_DEVICE | G_SIGNAL_TYPE_STATIC_SCOPE); |
375 |
|
|
|
376 |
|
✗ |
signals[DEVICE_REMOVED] = |
377 |
|
✗ |
g_signal_new ("device-removed", |
378 |
|
|
GSD_TYPE_DEVICE_MANAGER, |
379 |
|
|
G_SIGNAL_RUN_LAST, |
380 |
|
|
G_STRUCT_OFFSET (GsdDeviceManagerClass, device_removed), |
381 |
|
|
NULL, NULL, NULL, |
382 |
|
|
G_TYPE_NONE, 1, |
383 |
|
✗ |
GSD_TYPE_DEVICE | G_SIGNAL_TYPE_STATIC_SCOPE); |
384 |
|
|
|
385 |
|
✗ |
signals[DEVICE_CHANGED] = |
386 |
|
✗ |
g_signal_new ("device-changed", |
387 |
|
|
GSD_TYPE_DEVICE_MANAGER, |
388 |
|
|
G_SIGNAL_RUN_LAST, |
389 |
|
|
G_STRUCT_OFFSET (GsdDeviceManagerClass, device_changed), |
390 |
|
|
NULL, NULL, NULL, |
391 |
|
|
G_TYPE_NONE, 1, |
392 |
|
✗ |
GSD_TYPE_DEVICE | G_SIGNAL_TYPE_STATIC_SCOPE); |
393 |
|
✗ |
} |
394 |
|
|
|
395 |
|
|
static GsdDeviceType |
396 |
|
✗ |
udev_device_get_device_type (GUdevDevice *device) |
397 |
|
|
{ |
398 |
|
✗ |
GsdDeviceType type = 0; |
399 |
|
|
gint i; |
400 |
|
|
|
401 |
|
✗ |
for (i = 0; i < G_N_ELEMENTS (udev_ids); i++) { |
402 |
|
✗ |
if (g_udev_device_get_property_as_boolean (device, udev_ids[i])) |
403 |
|
✗ |
type |= (1 << i); |
404 |
|
|
} |
405 |
|
|
|
406 |
|
✗ |
return type; |
407 |
|
|
} |
408 |
|
|
|
409 |
|
|
static gboolean |
410 |
|
✗ |
device_is_evdev (GUdevDevice *device) |
411 |
|
|
{ |
412 |
|
|
const gchar *device_file; |
413 |
|
|
|
414 |
|
✗ |
device_file = g_udev_device_get_device_file (device); |
415 |
|
|
|
416 |
|
✗ |
if (!device_file || strstr (device_file, "/event") == NULL) |
417 |
|
✗ |
return FALSE; |
418 |
|
|
|
419 |
|
✗ |
return g_udev_device_get_property_as_boolean (device, "ID_INPUT"); |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
static GsdDevice * |
423 |
|
✗ |
create_device (GUdevDevice *udev_device, GUdevDevice *parent) |
424 |
|
|
{ |
425 |
|
|
const gchar *vendor, *product, *name, *group; |
426 |
|
|
guint width, height; |
427 |
|
|
|
428 |
|
✗ |
name = g_udev_device_get_sysfs_attr (parent, "name"); |
429 |
|
✗ |
vendor = g_udev_device_get_property (udev_device, "ID_VENDOR_ID"); |
430 |
|
✗ |
product = g_udev_device_get_property (udev_device, "ID_MODEL_ID"); |
431 |
|
|
|
432 |
|
✗ |
if (!vendor || !product) { |
433 |
|
✗ |
vendor = g_udev_device_get_sysfs_attr (udev_device, "device/id/vendor"); |
434 |
|
✗ |
product = g_udev_device_get_sysfs_attr (udev_device, "device/id/product"); |
435 |
|
|
} |
436 |
|
|
|
437 |
|
✗ |
width = g_udev_device_get_property_as_int (udev_device, "ID_INPUT_WIDTH_MM"); |
438 |
|
✗ |
height = g_udev_device_get_property_as_int (udev_device, "ID_INPUT_HEIGHT_MM"); |
439 |
|
|
|
440 |
|
✗ |
group = g_udev_device_get_property (udev_device, "LIBINPUT_DEVICE_GROUP"); |
441 |
|
|
|
442 |
|
✗ |
return g_object_new (GSD_TYPE_DEVICE, |
443 |
|
|
"name", name, |
444 |
|
|
"device-file", g_udev_device_get_device_file (udev_device), |
445 |
|
✗ |
"type", udev_device_get_device_type (udev_device), |
446 |
|
|
"vendor-id", vendor, |
447 |
|
|
"product-id", product, |
448 |
|
|
"width", width, |
449 |
|
|
"height", height, |
450 |
|
|
"group", group, |
451 |
|
|
NULL); |
452 |
|
|
} |
453 |
|
|
|
454 |
|
|
static void |
455 |
|
✗ |
add_device (GsdDeviceManager *manager, |
456 |
|
|
GUdevDevice *udev_device) |
457 |
|
|
{ |
458 |
|
✗ |
GsdDeviceManagerPrivate *priv = gsd_device_manager_get_instance_private (manager); |
459 |
|
✗ |
g_autoptr(GUdevDevice) parent = NULL; |
460 |
|
|
GsdDevice *device; |
461 |
|
|
const gchar *syspath; |
462 |
|
|
|
463 |
|
✗ |
parent = g_udev_device_get_parent (udev_device); |
464 |
|
|
|
465 |
|
✗ |
if (!parent) |
466 |
|
✗ |
return; |
467 |
|
|
|
468 |
|
✗ |
device = create_device (udev_device, parent); |
469 |
|
✗ |
syspath = g_udev_device_get_sysfs_path (udev_device); |
470 |
|
✗ |
g_hash_table_insert (priv->devices, g_strdup (syspath), device); |
471 |
|
✗ |
g_signal_emit_by_name (manager, "device-added", device); |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
static void |
475 |
|
✗ |
remove_device (GsdDeviceManager *manager, |
476 |
|
|
GUdevDevice *udev_device) |
477 |
|
|
{ |
478 |
|
✗ |
GsdDeviceManagerPrivate *priv = gsd_device_manager_get_instance_private (manager); |
479 |
|
|
GsdDevice *device; |
480 |
|
|
const gchar *syspath; |
481 |
|
|
|
482 |
|
✗ |
syspath = g_udev_device_get_sysfs_path (udev_device); |
483 |
|
✗ |
device = g_hash_table_lookup (priv->devices, syspath); |
484 |
|
|
|
485 |
|
✗ |
if (!device) |
486 |
|
✗ |
return; |
487 |
|
|
|
488 |
|
✗ |
g_hash_table_steal (priv->devices, syspath); |
489 |
|
✗ |
g_signal_emit_by_name (manager, "device-removed", device); |
490 |
|
|
|
491 |
|
✗ |
g_object_unref (device); |
492 |
|
|
} |
493 |
|
|
|
494 |
|
|
static void |
495 |
|
✗ |
udev_event_cb (GUdevClient *client, |
496 |
|
|
gchar *action, |
497 |
|
|
GUdevDevice *device, |
498 |
|
|
GsdDeviceManager *manager) |
499 |
|
|
{ |
500 |
|
✗ |
if (!device_is_evdev (device)) |
501 |
|
✗ |
return; |
502 |
|
|
|
503 |
|
✗ |
if (g_strcmp0 (action, "add") == 0) { |
504 |
|
✗ |
add_device (manager, device); |
505 |
|
✗ |
} else if (g_strcmp0 (action, "remove") == 0) { |
506 |
|
✗ |
remove_device (manager, device); |
507 |
|
|
} |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
static void |
511 |
|
✗ |
gsd_device_manager_init (GsdDeviceManager *manager) |
512 |
|
|
{ |
513 |
|
✗ |
GsdDeviceManagerPrivate *priv = gsd_device_manager_get_instance_private (manager); |
514 |
|
✗ |
const gchar *subsystems[] = { "input", NULL }; |
515 |
|
✗ |
g_autoptr(GList) devices = NULL; |
516 |
|
|
GList *l; |
517 |
|
|
|
518 |
|
✗ |
priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, |
519 |
|
|
(GDestroyNotify) g_free, |
520 |
|
|
(GDestroyNotify) g_object_unref); |
521 |
|
|
|
522 |
|
✗ |
priv->udev_client = g_udev_client_new (subsystems); |
523 |
|
✗ |
g_signal_connect (priv->udev_client, "uevent", |
524 |
|
|
G_CALLBACK (udev_event_cb), manager); |
525 |
|
|
|
526 |
|
✗ |
devices = g_udev_client_query_by_subsystem (priv->udev_client, |
527 |
|
|
subsystems[0]); |
528 |
|
|
|
529 |
|
✗ |
for (l = devices; l; l = l->next) { |
530 |
|
✗ |
g_autoptr(GUdevDevice) device = l->data; |
531 |
|
|
|
532 |
|
✗ |
if (device_is_evdev (device)) |
533 |
|
✗ |
add_device (manager, device); |
534 |
|
|
} |
535 |
|
✗ |
} |
536 |
|
|
|
537 |
|
|
GsdDeviceManager * |
538 |
|
✗ |
gsd_device_manager_get (void) |
539 |
|
|
{ |
540 |
|
|
GsdDeviceManager *manager; |
541 |
|
|
GdkDisplay *display; |
542 |
|
|
|
543 |
|
✗ |
display = gdk_display_get_default (); |
544 |
|
✗ |
g_return_val_if_fail (display != NULL, NULL); |
545 |
|
|
|
546 |
|
✗ |
manager = g_object_get_data (G_OBJECT (display), "gsd-device-manager-data"); |
547 |
|
|
|
548 |
|
✗ |
if (!manager) { |
549 |
|
✗ |
manager = g_object_new (GSD_TYPE_DEVICE_MANAGER, |
550 |
|
|
NULL); |
551 |
|
|
|
552 |
|
✗ |
g_object_set_data_full (G_OBJECT (display), "gsd-device-manager-data", |
553 |
|
|
manager, (GDestroyNotify) g_object_unref); |
554 |
|
|
} |
555 |
|
|
|
556 |
|
✗ |
return manager; |
557 |
|
|
} |
558 |
|
|
|
559 |
|
|
GList * |
560 |
|
✗ |
gsd_device_manager_list_devices (GsdDeviceManager *manager, |
561 |
|
|
GsdDeviceType type) |
562 |
|
|
{ |
563 |
|
✗ |
g_return_val_if_fail (GSD_IS_DEVICE_MANAGER (manager), NULL); |
564 |
|
|
|
565 |
|
✗ |
return GSD_DEVICE_MANAGER_GET_CLASS (manager)->list_devices (manager, type); |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
GsdDeviceType |
569 |
|
✗ |
gsd_device_get_device_type (GsdDevice *device) |
570 |
|
|
{ |
571 |
|
|
GsdDevicePrivate *priv; |
572 |
|
|
|
573 |
|
✗ |
g_return_val_if_fail (GSD_IS_DEVICE (device), 0); |
574 |
|
|
|
575 |
|
✗ |
priv = gsd_device_get_instance_private (device); |
576 |
|
|
|
577 |
|
✗ |
return priv->type; |
578 |
|
|
} |
579 |
|
|
|
580 |
|
|
void |
581 |
|
✗ |
gsd_device_get_device_ids (GsdDevice *device, |
582 |
|
|
const gchar **vendor, |
583 |
|
|
const gchar **product) |
584 |
|
|
{ |
585 |
|
|
GsdDevicePrivate *priv; |
586 |
|
|
|
587 |
|
✗ |
g_return_if_fail (GSD_IS_DEVICE (device)); |
588 |
|
|
|
589 |
|
✗ |
priv = gsd_device_get_instance_private (device); |
590 |
|
|
|
591 |
|
✗ |
if (vendor) |
592 |
|
✗ |
*vendor = priv->vendor_id; |
593 |
|
✗ |
if (product) |
594 |
|
✗ |
*product = priv->product_id; |
595 |
|
|
} |
596 |
|
|
|
597 |
|
|
GSettings * |
598 |
|
✗ |
gsd_device_get_settings (GsdDevice *device) |
599 |
|
|
{ |
600 |
|
✗ |
const gchar *schema = NULL, *vendor, *product; |
601 |
|
|
GsdDeviceType type; |
602 |
|
✗ |
g_autofree gchar *path = NULL; |
603 |
|
|
|
604 |
|
✗ |
g_return_val_if_fail (GSD_IS_DEVICE (device), NULL); |
605 |
|
|
|
606 |
|
✗ |
type = gsd_device_get_device_type (device); |
607 |
|
|
|
608 |
|
✗ |
if (type & (GSD_DEVICE_TYPE_TOUCHSCREEN | GSD_DEVICE_TYPE_TABLET)) { |
609 |
|
✗ |
gsd_device_get_device_ids (device, &vendor, &product); |
610 |
|
|
|
611 |
|
✗ |
if (type & GSD_DEVICE_TYPE_TOUCHSCREEN) { |
612 |
|
✗ |
schema = "org.gnome.desktop.peripherals.touchscreen"; |
613 |
|
✗ |
path = g_strdup_printf ("/org/gnome/desktop/peripherals/touchscreens/%s:%s/", |
614 |
|
|
vendor, product); |
615 |
|
✗ |
} else if (type & GSD_DEVICE_TYPE_TABLET) { |
616 |
|
✗ |
schema = "org.gnome.desktop.peripherals.tablet"; |
617 |
|
✗ |
path = g_strdup_printf ("/org/gnome/desktop/peripherals/tablets/%s:%s/", |
618 |
|
|
vendor, product); |
619 |
|
|
} |
620 |
|
✗ |
} else if (type & (GSD_DEVICE_TYPE_MOUSE | GSD_DEVICE_TYPE_TOUCHPAD)) { |
621 |
|
✗ |
schema = "org.gnome.desktop.peripherals.mouse"; |
622 |
|
✗ |
} else if (type & GSD_DEVICE_TYPE_KEYBOARD) { |
623 |
|
✗ |
schema = "org.gnome.desktop.peripherals.keyboard"; |
624 |
|
|
} else { |
625 |
|
✗ |
return NULL; |
626 |
|
|
} |
627 |
|
|
|
628 |
|
✗ |
if (path) { |
629 |
|
✗ |
return g_settings_new_with_path (schema, path); |
630 |
|
|
} else { |
631 |
|
✗ |
return g_settings_new (schema); |
632 |
|
|
} |
633 |
|
|
} |
634 |
|
|
|
635 |
|
|
const gchar * |
636 |
|
✗ |
gsd_device_get_name (GsdDevice *device) |
637 |
|
|
{ |
638 |
|
|
GsdDevicePrivate *priv; |
639 |
|
|
|
640 |
|
✗ |
g_return_val_if_fail (GSD_IS_DEVICE (device), NULL); |
641 |
|
|
|
642 |
|
✗ |
priv = gsd_device_get_instance_private (device); |
643 |
|
|
|
644 |
|
✗ |
return priv->name; |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
const gchar * |
648 |
|
✗ |
gsd_device_get_device_file (GsdDevice *device) |
649 |
|
|
{ |
650 |
|
|
GsdDevicePrivate *priv; |
651 |
|
|
|
652 |
|
✗ |
g_return_val_if_fail (GSD_IS_DEVICE (device), NULL); |
653 |
|
|
|
654 |
|
✗ |
priv = gsd_device_get_instance_private (device); |
655 |
|
|
|
656 |
|
✗ |
return priv->device_file; |
657 |
|
|
} |
658 |
|
|
|
659 |
|
|
gboolean |
660 |
|
✗ |
gsd_device_get_dimensions (GsdDevice *device, |
661 |
|
|
guint *width, |
662 |
|
|
guint *height) |
663 |
|
|
{ |
664 |
|
|
GsdDevicePrivate *priv; |
665 |
|
|
|
666 |
|
✗ |
g_return_val_if_fail (GSD_IS_DEVICE (device), FALSE); |
667 |
|
|
|
668 |
|
✗ |
priv = gsd_device_get_instance_private (device); |
669 |
|
|
|
670 |
|
✗ |
if (width) |
671 |
|
✗ |
*width = priv->width; |
672 |
|
✗ |
if (height) |
673 |
|
✗ |
*height = priv->height; |
674 |
|
|
|
675 |
|
✗ |
return priv->width > 0 && priv->height > 0; |
676 |
|
|
} |
677 |
|
|
|
678 |
|
|
GsdDevice * |
679 |
|
✗ |
gsd_device_manager_lookup_gdk_device (GsdDeviceManager *manager, |
680 |
|
|
GdkDevice *gdk_device) |
681 |
|
|
{ |
682 |
|
|
GsdDeviceManagerClass *klass; |
683 |
|
|
|
684 |
|
✗ |
g_return_val_if_fail (GSD_IS_DEVICE_MANAGER (manager), NULL); |
685 |
|
✗ |
g_return_val_if_fail (GDK_IS_DEVICE (gdk_device), NULL); |
686 |
|
|
|
687 |
|
✗ |
klass = GSD_DEVICE_MANAGER_GET_CLASS (manager); |
688 |
|
✗ |
if (!klass->lookup_device) |
689 |
|
✗ |
return NULL; |
690 |
|
|
|
691 |
|
✗ |
return klass->lookup_device (manager, gdk_device); |
692 |
|
|
} |
693 |
|
|
|
694 |
|
|
gboolean |
695 |
|
✗ |
gsd_device_shares_group (GsdDevice *device1, |
696 |
|
|
GsdDevice *device2) |
697 |
|
|
{ |
698 |
|
|
GsdDevicePrivate *priv1, *priv2; |
699 |
|
|
|
700 |
|
✗ |
priv1 = gsd_device_get_instance_private (GSD_DEVICE (device1)); |
701 |
|
✗ |
priv2 = gsd_device_get_instance_private (GSD_DEVICE (device2)); |
702 |
|
|
|
703 |
|
|
/* Don't group NULLs together */ |
704 |
|
✗ |
if (!priv1->group && !priv2->group) |
705 |
|
✗ |
return FALSE; |
706 |
|
|
|
707 |
|
✗ |
return g_strcmp0 (priv1->group, priv2->group) == 0; |
708 |
|
|
} |
709 |
|
|
|