1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2015 Red Hat
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author: Carlos Garnacho <carlosg@gnome.org>
18 */
19
20 #include "gdkseatdefaultprivate.h"
21 #include "gdkdevicetoolprivate.h"
22 #include "gdkinternals.h"
23
24 typedef struct _GdkSeatDefaultPrivate GdkSeatDefaultPrivate;
25
26 struct _GdkSeatDefaultPrivate
27 {
28 GdkDevice *logical_pointer;
29 GdkDevice *logical_keyboard;
30 GList *physical_pointers;
31 GList *physical_keyboards;
32 GdkSeatCapabilities capabilities;
33
34 GPtrArray *tools;
35 };
36
37 #define KEYBOARD_EVENTS (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | \
38 GDK_FOCUS_CHANGE_MASK)
39 #define TOUCH_EVENTS (GDK_TOUCH_MASK)
40 #define POINTER_EVENTS (GDK_POINTER_MOTION_MASK | \
41 GDK_BUTTON_PRESS_MASK | \
42 GDK_BUTTON_RELEASE_MASK | \
43 GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | \
44 GDK_ENTER_NOTIFY_MASK | \
45 GDK_LEAVE_NOTIFY_MASK | \
46 GDK_PROXIMITY_IN_MASK | \
47 GDK_PROXIMITY_OUT_MASK)
48
G_DEFINE_TYPE_WITH_PRIVATE(GdkSeatDefault,gdk_seat_default,GDK_TYPE_SEAT)49 G_DEFINE_TYPE_WITH_PRIVATE (GdkSeatDefault, gdk_seat_default, GDK_TYPE_SEAT)
50
51 static void
52 gdk_seat_default_dispose (GObject *object)
53 {
54 GdkSeatDefault *seat = GDK_SEAT_DEFAULT (object);
55 GdkSeatDefaultPrivate *priv = gdk_seat_default_get_instance_private (seat);
56 GList *l;
57
58 if (priv->logical_pointer)
59 {
60 gdk_seat_device_removed (GDK_SEAT (seat), priv->logical_pointer);
61 g_clear_object (&priv->logical_pointer);
62 }
63
64 if (priv->logical_keyboard)
65 {
66 gdk_seat_device_removed (GDK_SEAT (seat), priv->logical_keyboard);
67 g_clear_object (&priv->logical_pointer);
68 }
69
70 for (l = priv->physical_pointers; l; l = l->next)
71 {
72 gdk_seat_device_removed (GDK_SEAT (seat), l->data);
73 g_object_unref (l->data);
74 }
75
76 for (l = priv->physical_keyboards; l; l = l->next)
77 {
78 gdk_seat_device_removed (GDK_SEAT (seat), l->data);
79 g_object_unref (l->data);
80 }
81
82 g_clear_pointer (&priv->tools, g_ptr_array_unref);
83
84 g_list_free (priv->physical_pointers);
85 g_list_free (priv->physical_keyboards);
86 priv->physical_pointers = NULL;
87 priv->physical_keyboards = NULL;
88
89 G_OBJECT_CLASS (gdk_seat_default_parent_class)->dispose (object);
90 }
91
92 static GdkSeatCapabilities
gdk_seat_default_get_capabilities(GdkSeat * seat)93 gdk_seat_default_get_capabilities (GdkSeat *seat)
94 {
95 GdkSeatDefaultPrivate *priv;
96
97 priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
98
99 return priv->capabilities;
100 }
101
102 static GdkGrabStatus
gdk_seat_default_grab(GdkSeat * seat,GdkSurface * surface,GdkSeatCapabilities capabilities,gboolean owner_events,GdkCursor * cursor,GdkEvent * event,GdkSeatGrabPrepareFunc prepare_func,gpointer prepare_func_data)103 gdk_seat_default_grab (GdkSeat *seat,
104 GdkSurface *surface,
105 GdkSeatCapabilities capabilities,
106 gboolean owner_events,
107 GdkCursor *cursor,
108 GdkEvent *event,
109 GdkSeatGrabPrepareFunc prepare_func,
110 gpointer prepare_func_data)
111 {
112 GdkSeatDefaultPrivate *priv;
113 guint32 evtime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME;
114 GdkGrabStatus status = GDK_GRAB_SUCCESS;
115 gboolean was_visible;
116
117 priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
118 was_visible = gdk_surface_get_mapped (surface);
119
120 if (prepare_func)
121 (prepare_func) (seat, surface, prepare_func_data);
122
123 if (!gdk_surface_get_mapped (surface))
124 {
125 g_critical ("Surface %p has not been mapped in GdkSeatGrabPrepareFunc",
126 surface);
127 return GDK_GRAB_NOT_VIEWABLE;
128 }
129
130 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
131
132 if (capabilities & GDK_SEAT_CAPABILITY_ALL_POINTING)
133 {
134 /* ALL_POINTING spans 3 capabilities; get the mask for the ones we have */
135 GdkEventMask pointer_evmask = 0;
136
137 /* We let tablet styli take over the pointer cursor */
138 if (capabilities & (GDK_SEAT_CAPABILITY_POINTER |
139 GDK_SEAT_CAPABILITY_TABLET_STYLUS))
140 {
141 pointer_evmask |= POINTER_EVENTS;
142 }
143
144 if (capabilities & GDK_SEAT_CAPABILITY_TOUCH)
145 pointer_evmask |= TOUCH_EVENTS;
146
147 status = gdk_device_grab (priv->logical_pointer, surface,
148 owner_events,
149 pointer_evmask, cursor,
150 evtime);
151 }
152
153 if (status == GDK_GRAB_SUCCESS &&
154 capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)
155 {
156 status = gdk_device_grab (priv->logical_keyboard, surface,
157 owner_events,
158 KEYBOARD_EVENTS, cursor,
159 evtime);
160
161 if (status != GDK_GRAB_SUCCESS)
162 {
163 if (capabilities & ~GDK_SEAT_CAPABILITY_KEYBOARD)
164 gdk_device_ungrab (priv->logical_pointer, evtime);
165 }
166 }
167
168 if (status != GDK_GRAB_SUCCESS && !was_visible)
169 gdk_surface_hide (surface);
170
171 G_GNUC_END_IGNORE_DEPRECATIONS;
172
173 return status;
174 }
175
176 static void
gdk_seat_default_ungrab(GdkSeat * seat)177 gdk_seat_default_ungrab (GdkSeat *seat)
178 {
179 GdkSeatDefaultPrivate *priv;
180
181 priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
182
183 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
184 gdk_device_ungrab (priv->logical_pointer, GDK_CURRENT_TIME);
185 gdk_device_ungrab (priv->logical_keyboard, GDK_CURRENT_TIME);
186 G_GNUC_END_IGNORE_DEPRECATIONS;
187 }
188
189 static GdkDevice *
gdk_seat_default_get_logical_device(GdkSeat * seat,GdkSeatCapabilities capability)190 gdk_seat_default_get_logical_device (GdkSeat *seat,
191 GdkSeatCapabilities capability)
192 {
193 GdkSeatDefaultPrivate *priv;
194
195 priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
196
197 /* There must be only one flag set */
198 switch ((guint) capability)
199 {
200 case GDK_SEAT_CAPABILITY_POINTER:
201 case GDK_SEAT_CAPABILITY_TOUCH:
202 return priv->logical_pointer;
203 case GDK_SEAT_CAPABILITY_KEYBOARD:
204 return priv->logical_keyboard;
205 default:
206 g_warning ("Unhandled capability %x", capability);
207 break;
208 }
209
210 return NULL;
211 }
212
213 static GdkSeatCapabilities
device_get_capability(GdkDevice * device)214 device_get_capability (GdkDevice *device)
215 {
216 GdkInputSource source;
217
218 source = gdk_device_get_source (device);
219
220 switch (source)
221 {
222 case GDK_SOURCE_KEYBOARD:
223 return GDK_SEAT_CAPABILITY_KEYBOARD;
224 case GDK_SOURCE_TOUCHSCREEN:
225 return GDK_SEAT_CAPABILITY_TOUCH;
226 case GDK_SOURCE_PEN:
227 return GDK_SEAT_CAPABILITY_TABLET_STYLUS;
228 case GDK_SOURCE_TABLET_PAD:
229 return GDK_SEAT_CAPABILITY_TABLET_PAD;
230 case GDK_SOURCE_MOUSE:
231 case GDK_SOURCE_TOUCHPAD:
232 case GDK_SOURCE_TRACKPOINT:
233 default:
234 return GDK_SEAT_CAPABILITY_POINTER;
235 }
236
237 return GDK_SEAT_CAPABILITY_NONE;
238 }
239
240 static GList *
append_filtered(GList * list,GList * devices,GdkSeatCapabilities capabilities)241 append_filtered (GList *list,
242 GList *devices,
243 GdkSeatCapabilities capabilities)
244 {
245 GList *l;
246
247 for (l = devices; l; l = l->next)
248 {
249 GdkSeatCapabilities device_cap;
250
251 device_cap = device_get_capability (l->data);
252
253 if ((device_cap & capabilities) != 0)
254 list = g_list_prepend (list, l->data);
255 }
256
257 return list;
258 }
259
260 static GList *
gdk_seat_default_get_devices(GdkSeat * seat,GdkSeatCapabilities capabilities)261 gdk_seat_default_get_devices (GdkSeat *seat,
262 GdkSeatCapabilities capabilities)
263 {
264 GdkSeatDefaultPrivate *priv;
265 GList *devices = NULL;
266
267 priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
268
269 if (capabilities & (GDK_SEAT_CAPABILITY_ALL_POINTING))
270 devices = append_filtered (devices, priv->physical_pointers, capabilities);
271
272 if (capabilities & (GDK_SEAT_CAPABILITY_KEYBOARD | GDK_SEAT_CAPABILITY_TABLET_PAD))
273 devices = append_filtered (devices, priv->physical_keyboards, capabilities);
274
275 return devices;
276 }
277
278 static GList *
gdk_seat_default_get_tools(GdkSeat * seat)279 gdk_seat_default_get_tools (GdkSeat *seat)
280 {
281 GdkSeatDefaultPrivate *priv;
282 GdkDeviceTool *tool;
283 GList *tools = NULL;
284 guint i;
285
286 priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
287
288 if (!priv->tools)
289 return NULL;
290
291 for (i = 0; i < priv->tools->len; i++)
292 {
293 tool = g_ptr_array_index (priv->tools, i);
294 tools = g_list_prepend (tools, tool);
295 }
296
297 return tools;
298 }
299
300 static void
gdk_seat_default_class_init(GdkSeatDefaultClass * klass)301 gdk_seat_default_class_init (GdkSeatDefaultClass *klass)
302 {
303 GObjectClass *object_class = G_OBJECT_CLASS (klass);
304 GdkSeatClass *seat_class = GDK_SEAT_CLASS (klass);
305
306 object_class->dispose = gdk_seat_default_dispose;
307
308 seat_class->get_capabilities = gdk_seat_default_get_capabilities;
309
310 seat_class->grab = gdk_seat_default_grab;
311 seat_class->ungrab = gdk_seat_default_ungrab;
312
313 seat_class->get_logical_device = gdk_seat_default_get_logical_device;
314 seat_class->get_devices = gdk_seat_default_get_devices;
315 seat_class->get_tools = gdk_seat_default_get_tools;
316 }
317
318 static void
gdk_seat_default_init(GdkSeatDefault * seat)319 gdk_seat_default_init (GdkSeatDefault *seat)
320 {
321 }
322
323 GdkSeat *
gdk_seat_default_new_for_logical_pair(GdkDevice * pointer,GdkDevice * keyboard)324 gdk_seat_default_new_for_logical_pair (GdkDevice *pointer,
325 GdkDevice *keyboard)
326 {
327 GdkSeatDefaultPrivate *priv;
328 GdkDisplay *display;
329 GdkSeat *seat;
330
331 display = gdk_device_get_display (pointer);
332
333 seat = g_object_new (GDK_TYPE_SEAT_DEFAULT,
334 "display", display,
335 NULL);
336
337 priv = gdk_seat_default_get_instance_private (GDK_SEAT_DEFAULT (seat));
338 priv->logical_pointer = g_object_ref (pointer);
339 priv->logical_keyboard = g_object_ref (keyboard);
340
341 gdk_seat_device_added (seat, priv->logical_pointer);
342 gdk_seat_device_added (seat, priv->logical_keyboard);
343
344 return seat;
345 }
346
347 void
gdk_seat_default_add_physical_device(GdkSeatDefault * seat,GdkDevice * device)348 gdk_seat_default_add_physical_device (GdkSeatDefault *seat,
349 GdkDevice *device)
350 {
351 GdkSeatDefaultPrivate *priv;
352 GdkSeatCapabilities capability;
353
354 g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
355 g_return_if_fail (GDK_IS_DEVICE (device));
356
357 priv = gdk_seat_default_get_instance_private (seat);
358 capability = device_get_capability (device);
359
360 if (capability & GDK_SEAT_CAPABILITY_ALL_POINTING)
361 priv->physical_pointers = g_list_prepend (priv->physical_pointers, g_object_ref (device));
362 else if (capability & (GDK_SEAT_CAPABILITY_KEYBOARD | GDK_SEAT_CAPABILITY_TABLET_PAD))
363 priv->physical_keyboards = g_list_prepend (priv->physical_keyboards, g_object_ref (device));
364 else
365 {
366 g_critical ("Unhandled capability %x for device '%s'",
367 capability, gdk_device_get_name (device));
368 return;
369 }
370
371 priv->capabilities |= capability;
372
373 gdk_seat_device_added (GDK_SEAT (seat), device);
374 }
375
376 void
gdk_seat_default_remove_physical_device(GdkSeatDefault * seat,GdkDevice * device)377 gdk_seat_default_remove_physical_device (GdkSeatDefault *seat,
378 GdkDevice *device)
379 {
380 GdkSeatDefaultPrivate *priv;
381 GList *l;
382
383 g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
384 g_return_if_fail (GDK_IS_DEVICE (device));
385
386 priv = gdk_seat_default_get_instance_private (seat);
387
388 if (g_list_find (priv->physical_pointers, device))
389 {
390 priv->physical_pointers = g_list_remove (priv->physical_pointers, device);
391
392 priv->capabilities &= ~(GDK_SEAT_CAPABILITY_ALL_POINTING);
393 for (l = priv->physical_pointers; l; l = l->next)
394 priv->capabilities |= device_get_capability (GDK_DEVICE (l->data));
395
396 gdk_seat_device_removed (GDK_SEAT (seat), device);
397 g_object_unref (device);
398 }
399 else if (g_list_find (priv->physical_keyboards, device))
400 {
401 priv->physical_keyboards = g_list_remove (priv->physical_keyboards, device);
402
403 priv->capabilities &= ~(GDK_SEAT_CAPABILITY_KEYBOARD | GDK_SEAT_CAPABILITY_TABLET_PAD);
404 for (l = priv->physical_keyboards; l; l = l->next)
405 priv->capabilities |= device_get_capability (GDK_DEVICE (l->data));
406
407 gdk_seat_device_removed (GDK_SEAT (seat), device);
408 g_object_unref (device);
409 }
410 }
411
412 void
gdk_seat_default_add_tool(GdkSeatDefault * seat,GdkDeviceTool * tool)413 gdk_seat_default_add_tool (GdkSeatDefault *seat,
414 GdkDeviceTool *tool)
415 {
416 GdkSeatDefaultPrivate *priv;
417
418 g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
419 g_return_if_fail (tool != NULL);
420
421 priv = gdk_seat_default_get_instance_private (seat);
422
423 if (!priv->tools)
424 priv->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
425
426 g_ptr_array_add (priv->tools, g_object_ref (tool));
427 g_signal_emit_by_name (seat, "tool-added", tool);
428 }
429
430 void
gdk_seat_default_remove_tool(GdkSeatDefault * seat,GdkDeviceTool * tool)431 gdk_seat_default_remove_tool (GdkSeatDefault *seat,
432 GdkDeviceTool *tool)
433 {
434 GdkSeatDefaultPrivate *priv;
435
436 g_return_if_fail (GDK_IS_SEAT_DEFAULT (seat));
437 g_return_if_fail (tool != NULL);
438
439 priv = gdk_seat_default_get_instance_private (seat);
440
441 if (tool != gdk_seat_get_tool (GDK_SEAT (seat), tool->serial, tool->hw_id, tool->type))
442 return;
443
444 g_signal_emit_by_name (seat, "tool-removed", tool);
445 g_ptr_array_remove (priv->tools, tool);
446 }
447