1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright 2014 Red Hat, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Carlos Garnacho <carlosg@gnome.org>
20 */
21
22 /**
23 * SECTION:input-settings
24 * @title: MetaInputSettings
25 * @short_description: Mutter input device configuration
26 */
27
28 #include "config.h"
29
30 #include <glib/gi18n-lib.h>
31 #include <string.h>
32
33 #include "backends/meta-backend-private.h"
34 #include "backends/meta-input-device-private.h"
35 #include "backends/meta-input-settings-private.h"
36 #include "backends/meta-input-mapper-private.h"
37 #include "backends/meta-logical-monitor.h"
38 #include "backends/meta-monitor.h"
39 #include "core/display-private.h"
40 #include "meta/util.h"
41
42 static GQuark quark_tool_settings = 0;
43
44 typedef struct _MetaInputSettingsPrivate MetaInputSettingsPrivate;
45 typedef struct _DeviceMappingInfo DeviceMappingInfo;
46 typedef struct _CurrentToolInfo CurrentToolInfo;
47
48 struct _CurrentToolInfo
49 {
50 MetaInputSettings *input_settings;
51 ClutterInputDevice *device;
52 ClutterInputDeviceTool *tool;
53 GSettings *settings;
54 gulong changed_id;
55 };
56
57 struct _DeviceMappingInfo
58 {
59 MetaInputSettings *input_settings;
60 ClutterInputDevice *device;
61 GSettings *settings;
62 gulong changed_id;
63 guint *group_modes;
64 double aspect_ratio;
65 };
66
67 struct _MetaInputSettingsPrivate
68 {
69 ClutterSeat *seat;
70 gulong monitors_changed_id;
71
72 GSettings *mouse_settings;
73 GSettings *touchpad_settings;
74 GSettings *trackball_settings;
75 GSettings *keyboard_settings;
76 GSettings *keyboard_a11y_settings;
77
78 GList *devices;
79 GHashTable *mappable_devices;
80
81 GHashTable *current_tools;
82
83 GHashTable *two_finger_devices;
84
85 MetaKbdA11ySettings kbd_a11y_settings;
86 };
87
88 typedef gboolean (* ConfigBoolMappingFunc) (MetaInputSettings *input_settings,
89 ClutterInputDevice *device,
90 gboolean value);
91
92 typedef void (*ConfigBoolFunc) (MetaInputSettings *input_settings,
93 ClutterInputDevice *device,
94 gboolean setting);
95 typedef void (*ConfigDoubleFunc) (MetaInputSettings *input_settings,
96 ClutterInputDevice *device,
97 gdouble value);
98 typedef void (*ConfigUintFunc) (MetaInputSettings *input_settings,
99 ClutterInputDevice *device,
100 guint value);
101
102 G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettings, meta_input_settings, G_TYPE_OBJECT)
103
104 enum
105 {
106 KBD_A11Y_CHANGED,
107 N_SIGNALS
108 };
109
110 static guint signals[N_SIGNALS] = { 0 };
111
112 static GSList *
meta_input_settings_get_devices(MetaInputSettings * settings,ClutterInputDeviceType type)113 meta_input_settings_get_devices (MetaInputSettings *settings,
114 ClutterInputDeviceType type)
115 {
116 MetaInputSettingsPrivate *priv;
117 GList *l;
118 GSList *list = NULL;
119
120 priv = meta_input_settings_get_instance_private (settings);
121
122 for (l = priv->devices; l; l = l->next)
123 {
124 ClutterInputDevice *device = l->data;
125
126 if (clutter_input_device_get_device_type (device) == type &&
127 clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL)
128 list = g_slist_prepend (list, device);
129 }
130
131 return list;
132 }
133
134 static void
meta_input_settings_dispose(GObject * object)135 meta_input_settings_dispose (GObject *object)
136 {
137 MetaInputSettings *settings = META_INPUT_SETTINGS (object);
138 MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (settings);
139
140 g_clear_object (&priv->mouse_settings);
141 g_clear_object (&priv->touchpad_settings);
142 g_clear_object (&priv->trackball_settings);
143 g_clear_object (&priv->keyboard_settings);
144 g_clear_object (&priv->keyboard_a11y_settings);
145 g_clear_pointer (&priv->mappable_devices, g_hash_table_unref);
146 g_clear_pointer (&priv->current_tools, g_hash_table_unref);
147
148 g_clear_pointer (&priv->two_finger_devices, g_hash_table_destroy);
149
150 G_OBJECT_CLASS (meta_input_settings_parent_class)->dispose (object);
151 }
152
153 static void
settings_device_set_bool_setting(MetaInputSettings * input_settings,ClutterInputDevice * device,ConfigBoolFunc func,gboolean enabled)154 settings_device_set_bool_setting (MetaInputSettings *input_settings,
155 ClutterInputDevice *device,
156 ConfigBoolFunc func,
157 gboolean enabled)
158 {
159 func (input_settings, device, enabled);
160 }
161
162 static void
settings_set_bool_setting(MetaInputSettings * input_settings,ClutterInputDeviceType type,ConfigBoolMappingFunc mapping_func,ConfigBoolFunc func,gboolean enabled)163 settings_set_bool_setting (MetaInputSettings *input_settings,
164 ClutterInputDeviceType type,
165 ConfigBoolMappingFunc mapping_func,
166 ConfigBoolFunc func,
167 gboolean enabled)
168 {
169 GSList *devices, *l;
170
171 devices = meta_input_settings_get_devices (input_settings, type);
172
173 for (l = devices; l; l = l->next)
174 {
175 gboolean value = enabled;
176
177 if (mapping_func)
178 value = mapping_func (input_settings, l->data, value);
179 settings_device_set_bool_setting (input_settings, l->data, func, value);
180 }
181
182 g_slist_free (devices);
183 }
184
185 static void
settings_device_set_double_setting(MetaInputSettings * input_settings,ClutterInputDevice * device,ConfigDoubleFunc func,gdouble value)186 settings_device_set_double_setting (MetaInputSettings *input_settings,
187 ClutterInputDevice *device,
188 ConfigDoubleFunc func,
189 gdouble value)
190 {
191 func (input_settings, device, value);
192 }
193
194 static void
settings_set_double_setting(MetaInputSettings * input_settings,ClutterInputDeviceType type,ConfigDoubleFunc func,gdouble value)195 settings_set_double_setting (MetaInputSettings *input_settings,
196 ClutterInputDeviceType type,
197 ConfigDoubleFunc func,
198 gdouble value)
199 {
200 GSList *devices, *d;
201
202 devices = meta_input_settings_get_devices (input_settings, type);
203
204 for (d = devices; d; d = d->next)
205 settings_device_set_double_setting (input_settings, d->data, func, value);
206
207 g_slist_free (devices);
208 }
209
210 static void
settings_device_set_uint_setting(MetaInputSettings * input_settings,ClutterInputDevice * device,ConfigUintFunc func,guint value)211 settings_device_set_uint_setting (MetaInputSettings *input_settings,
212 ClutterInputDevice *device,
213 ConfigUintFunc func,
214 guint value)
215 {
216 (func) (input_settings, device, value);
217 }
218
219 static void
settings_set_uint_setting(MetaInputSettings * input_settings,ClutterInputDeviceType type,ConfigUintFunc func,guint value)220 settings_set_uint_setting (MetaInputSettings *input_settings,
221 ClutterInputDeviceType type,
222 ConfigUintFunc func,
223 guint value)
224 {
225 GSList *devices, *d;
226
227 devices = meta_input_settings_get_devices (input_settings, type);
228
229 for (d = devices; d; d = d->next)
230 settings_device_set_uint_setting (input_settings, d->data, func, value);
231
232 g_slist_free (devices);
233 }
234
235 static void
update_touchpad_left_handed(MetaInputSettings * input_settings,ClutterInputDevice * device)236 update_touchpad_left_handed (MetaInputSettings *input_settings,
237 ClutterInputDevice *device)
238 {
239 MetaInputSettingsClass *input_settings_class;
240 GDesktopTouchpadHandedness handedness;
241 MetaInputSettingsPrivate *priv;
242 gboolean enabled = FALSE;
243
244 if (device &&
245 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
246 return;
247
248 priv = meta_input_settings_get_instance_private (input_settings);
249 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
250 handedness = g_settings_get_enum (priv->touchpad_settings, "left-handed");
251
252 switch (handedness)
253 {
254 case G_DESKTOP_TOUCHPAD_HANDEDNESS_RIGHT:
255 enabled = FALSE;
256 break;
257 case G_DESKTOP_TOUCHPAD_HANDEDNESS_LEFT:
258 enabled = TRUE;
259 break;
260 case G_DESKTOP_TOUCHPAD_HANDEDNESS_MOUSE:
261 enabled = g_settings_get_boolean (priv->mouse_settings, "left-handed");
262 break;
263 default:
264 g_assert_not_reached ();
265 }
266
267 if (device)
268 {
269 settings_device_set_bool_setting (input_settings, device,
270 input_settings_class->set_left_handed,
271 enabled);
272 }
273 else
274 {
275 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE, NULL,
276 input_settings_class->set_left_handed,
277 enabled);
278 }
279 }
280
281 static void
update_mouse_left_handed(MetaInputSettings * input_settings,ClutterInputDevice * device)282 update_mouse_left_handed (MetaInputSettings *input_settings,
283 ClutterInputDevice *device)
284 {
285 MetaInputSettingsClass *input_settings_class;
286 MetaInputSettingsPrivate *priv;
287 gboolean enabled;
288
289 if (device &&
290 clutter_input_device_get_device_type (device) != CLUTTER_POINTER_DEVICE)
291 return;
292
293 priv = meta_input_settings_get_instance_private (input_settings);
294 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
295 enabled = g_settings_get_boolean (priv->mouse_settings, "left-handed");
296
297 if (device)
298 {
299 settings_device_set_bool_setting (input_settings, device,
300 input_settings_class->set_left_handed,
301 enabled);
302 }
303 else
304 {
305 GDesktopTouchpadHandedness touchpad_handedness;
306
307 settings_set_bool_setting (input_settings, CLUTTER_POINTER_DEVICE, NULL,
308 input_settings_class->set_left_handed,
309 enabled);
310
311 touchpad_handedness = g_settings_get_enum (priv->touchpad_settings,
312 "left-handed");
313
314 /* Also update touchpads if they're following mouse settings */
315 if (touchpad_handedness == G_DESKTOP_TOUCHPAD_HANDEDNESS_MOUSE)
316 update_touchpad_left_handed (input_settings, NULL);
317 }
318 }
319
320 static void
do_update_pointer_accel_profile(MetaInputSettings * input_settings,GSettings * settings,ClutterInputDevice * device,GDesktopPointerAccelProfile profile)321 do_update_pointer_accel_profile (MetaInputSettings *input_settings,
322 GSettings *settings,
323 ClutterInputDevice *device,
324 GDesktopPointerAccelProfile profile)
325 {
326 MetaInputSettingsPrivate *priv =
327 meta_input_settings_get_instance_private (input_settings);
328 MetaInputSettingsClass *input_settings_class =
329 META_INPUT_SETTINGS_GET_CLASS (input_settings);
330
331 if (settings == priv->mouse_settings)
332 input_settings_class->set_mouse_accel_profile (input_settings,
333 device,
334 profile);
335 else if (settings == priv->trackball_settings)
336 input_settings_class->set_trackball_accel_profile (input_settings,
337 device,
338 profile);
339 }
340
341 static void
update_pointer_accel_profile(MetaInputSettings * input_settings,GSettings * settings,ClutterInputDevice * device)342 update_pointer_accel_profile (MetaInputSettings *input_settings,
343 GSettings *settings,
344 ClutterInputDevice *device)
345 {
346 GDesktopPointerAccelProfile profile;
347
348 profile = g_settings_get_enum (settings, "accel-profile");
349
350 if (device)
351 {
352 do_update_pointer_accel_profile (input_settings, settings,
353 device, profile);
354 }
355 else
356 {
357 MetaInputSettingsPrivate *priv =
358 meta_input_settings_get_instance_private (input_settings);
359 GList *l;
360
361 for (l = priv->devices; l; l = l->next)
362 {
363 device = l->data;
364
365 if (clutter_input_device_get_device_mode (device) ==
366 CLUTTER_INPUT_MODE_LOGICAL)
367 continue;
368
369 do_update_pointer_accel_profile (input_settings, settings,
370 device, profile);
371 }
372 }
373 }
374
375 static GSettings *
get_settings_for_device_type(MetaInputSettings * input_settings,ClutterInputDeviceType type)376 get_settings_for_device_type (MetaInputSettings *input_settings,
377 ClutterInputDeviceType type)
378 {
379 MetaInputSettingsPrivate *priv;
380 priv = meta_input_settings_get_instance_private (input_settings);
381 switch (type)
382 {
383 case CLUTTER_POINTER_DEVICE:
384 return priv->mouse_settings;
385 case CLUTTER_TOUCHPAD_DEVICE:
386 return priv->touchpad_settings;
387 default:
388 return NULL;
389 }
390 }
391
392 static void
update_middle_click_emulation(MetaInputSettings * input_settings,GSettings * settings,ClutterInputDevice * device)393 update_middle_click_emulation (MetaInputSettings *input_settings,
394 GSettings *settings,
395 ClutterInputDevice *device)
396 {
397 ConfigBoolFunc func;
398 const gchar *key = "middle-click-emulation";
399 MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
400
401 if (!settings)
402 return;
403
404 if (settings == priv->mouse_settings)
405 func = META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_mouse_middle_click_emulation;
406 else if (settings == priv->touchpad_settings)
407 func = META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_touchpad_middle_click_emulation;
408 else if (settings == priv->trackball_settings)
409 func = META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_trackball_middle_click_emulation;
410 else
411 return;
412
413 if (device)
414 {
415 settings_device_set_bool_setting (input_settings, device, func,
416 g_settings_get_boolean (settings, key));
417 }
418 else
419 {
420 settings_set_bool_setting (input_settings, CLUTTER_POINTER_DEVICE,
421 NULL, func,
422 g_settings_get_boolean (settings, key));
423 }
424 }
425
426 static void
update_device_speed(MetaInputSettings * input_settings,ClutterInputDevice * device)427 update_device_speed (MetaInputSettings *input_settings,
428 ClutterInputDevice *device)
429 {
430 GSettings *settings;
431 ConfigDoubleFunc func;
432 const gchar *key = "speed";
433
434 func = META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_speed;
435
436 if (device)
437 {
438 settings = get_settings_for_device_type (input_settings,
439 clutter_input_device_get_device_type (device));
440 if (!settings)
441 return;
442
443 settings_device_set_double_setting (input_settings, device, func,
444 g_settings_get_double (settings, key));
445 }
446 else
447 {
448 settings = get_settings_for_device_type (input_settings, CLUTTER_POINTER_DEVICE);
449 settings_set_double_setting (input_settings, CLUTTER_POINTER_DEVICE, func,
450 g_settings_get_double (settings, key));
451 settings = get_settings_for_device_type (input_settings, CLUTTER_TOUCHPAD_DEVICE);
452 settings_set_double_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE, func,
453 g_settings_get_double (settings, key));
454 }
455 }
456
457 static void
update_device_natural_scroll(MetaInputSettings * input_settings,ClutterInputDevice * device)458 update_device_natural_scroll (MetaInputSettings *input_settings,
459 ClutterInputDevice *device)
460 {
461 GSettings *settings;
462 ConfigBoolFunc func;
463 const gchar *key = "natural-scroll";
464
465 func = META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_invert_scroll;
466
467 if (device)
468 {
469 settings = get_settings_for_device_type (input_settings,
470 clutter_input_device_get_device_type (device));
471 if (!settings)
472 return;
473
474 settings_device_set_bool_setting (input_settings, device, func,
475 g_settings_get_boolean (settings, key));
476 }
477 else
478 {
479 settings = get_settings_for_device_type (input_settings, CLUTTER_POINTER_DEVICE);
480 settings_set_bool_setting (input_settings, CLUTTER_POINTER_DEVICE,
481 NULL, func,
482 g_settings_get_boolean (settings, key));
483 settings = get_settings_for_device_type (input_settings, CLUTTER_TOUCHPAD_DEVICE);
484 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
485 NULL, func,
486 g_settings_get_boolean (settings, key));
487 }
488 }
489
490 static void
update_touchpad_disable_while_typing(MetaInputSettings * input_settings,ClutterInputDevice * device)491 update_touchpad_disable_while_typing (MetaInputSettings *input_settings,
492 ClutterInputDevice *device)
493 {
494 GSettings *settings;
495 MetaInputSettingsClass *input_settings_class;
496 MetaInputSettingsPrivate *priv;
497 gboolean enabled;
498 const gchar *key = "disable-while-typing";
499
500 if (device &&
501 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
502 return;
503
504 priv = meta_input_settings_get_instance_private (input_settings);
505 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
506 enabled = g_settings_get_boolean (priv->touchpad_settings, key);
507
508 if (device)
509 {
510 settings = get_settings_for_device_type (input_settings,
511 clutter_input_device_get_device_type (device));
512
513 if (!settings)
514 return;
515
516 settings_device_set_bool_setting (input_settings, device,
517 input_settings_class->set_disable_while_typing,
518 enabled);
519 }
520 else
521 {
522 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE, NULL,
523 input_settings_class->set_disable_while_typing,
524 enabled);
525 }
526 }
527
528 static gboolean
device_is_tablet_touchpad(MetaInputSettings * input_settings,ClutterInputDevice * device)529 device_is_tablet_touchpad (MetaInputSettings *input_settings,
530 ClutterInputDevice *device)
531 {
532 #ifdef HAVE_LIBWACOM
533 WacomIntegrationFlags flags = 0;
534 WacomDevice *wacom_device;
535
536 if (clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
537 return FALSE;
538
539 wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
540
541 if (wacom_device)
542 {
543 flags = libwacom_get_integration_flags (wacom_device);
544
545 if ((flags & (WACOM_DEVICE_INTEGRATED_SYSTEM |
546 WACOM_DEVICE_INTEGRATED_DISPLAY)) == 0)
547 return TRUE;
548 }
549 #endif
550
551 return FALSE;
552 }
553
554 static gboolean
force_enable_on_tablet(MetaInputSettings * input_settings,ClutterInputDevice * device,gboolean value)555 force_enable_on_tablet (MetaInputSettings *input_settings,
556 ClutterInputDevice *device,
557 gboolean value)
558 {
559 return device_is_tablet_touchpad (input_settings, device) || value;
560 }
561
562 static void
update_touchpad_tap_enabled(MetaInputSettings * input_settings,ClutterInputDevice * device)563 update_touchpad_tap_enabled (MetaInputSettings *input_settings,
564 ClutterInputDevice *device)
565 {
566 MetaInputSettingsClass *input_settings_class;
567 MetaInputSettingsPrivate *priv;
568 gboolean enabled;
569
570 if (device &&
571 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
572 return;
573
574 priv = meta_input_settings_get_instance_private (input_settings);
575 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
576 enabled = g_settings_get_boolean (priv->touchpad_settings, "tap-to-click");
577
578 if (device)
579 {
580 enabled = force_enable_on_tablet (input_settings, device, enabled);
581 settings_device_set_bool_setting (input_settings, device,
582 input_settings_class->set_tap_enabled,
583 enabled);
584 }
585 else
586 {
587 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
588 force_enable_on_tablet,
589 input_settings_class->set_tap_enabled,
590 enabled);
591 }
592 }
593
594 static void
update_touchpad_tap_button_map(MetaInputSettings * input_settings,ClutterInputDevice * device)595 update_touchpad_tap_button_map (MetaInputSettings *input_settings,
596 ClutterInputDevice *device)
597 {
598 MetaInputSettingsClass *input_settings_class;
599 GDesktopTouchpadTapButtonMap method;
600 MetaInputSettingsPrivate *priv;
601
602 if (device &&
603 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
604 return;
605
606 priv = meta_input_settings_get_instance_private (input_settings);
607 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
608 method = g_settings_get_enum (priv->touchpad_settings, "tap-button-map");
609
610 if (device)
611 {
612 settings_device_set_uint_setting (input_settings, device,
613 input_settings_class->set_tap_button_map,
614 method);
615 }
616 else
617 {
618 settings_set_uint_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
619 (ConfigUintFunc) input_settings_class->set_tap_button_map,
620 method);
621 }
622 }
623
624 static void
update_touchpad_tap_and_drag_enabled(MetaInputSettings * input_settings,ClutterInputDevice * device)625 update_touchpad_tap_and_drag_enabled (MetaInputSettings *input_settings,
626 ClutterInputDevice *device)
627 {
628 MetaInputSettingsClass *input_settings_class;
629 MetaInputSettingsPrivate *priv;
630 gboolean enabled;
631
632 if (device &&
633 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
634 return;
635
636 priv = meta_input_settings_get_instance_private (input_settings);
637 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
638 enabled = g_settings_get_boolean (priv->touchpad_settings, "tap-and-drag");
639
640 if (device)
641 {
642 enabled = force_enable_on_tablet (input_settings, device, enabled);
643 settings_device_set_bool_setting (input_settings, device,
644 input_settings_class->set_tap_and_drag_enabled,
645 enabled);
646 }
647 else
648 {
649 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
650 force_enable_on_tablet,
651 input_settings_class->set_tap_and_drag_enabled,
652 enabled);
653 }
654 }
655
656 static void
update_touchpad_tap_and_drag_lock_enabled(MetaInputSettings * input_settings,ClutterInputDevice * device)657 update_touchpad_tap_and_drag_lock_enabled (MetaInputSettings *input_settings,
658 ClutterInputDevice *device)
659 {
660 MetaInputSettingsClass *input_settings_class;
661 MetaInputSettingsPrivate *priv;
662 gboolean enabled;
663
664 if (device &&
665 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
666 return;
667
668 priv = meta_input_settings_get_instance_private (input_settings);
669 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
670 enabled = g_settings_get_boolean (priv->touchpad_settings, "tap-and-drag-lock");
671
672 if (device)
673 {
674 settings_device_set_bool_setting (input_settings, device,
675 input_settings_class->set_tap_and_drag_lock_enabled,
676 enabled);
677 }
678 else
679 {
680 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
681 NULL,
682 input_settings_class->set_tap_and_drag_lock_enabled,
683 enabled);
684 }
685 }
686
687 static void
update_touchpad_edge_scroll(MetaInputSettings * input_settings,ClutterInputDevice * device)688 update_touchpad_edge_scroll (MetaInputSettings *input_settings,
689 ClutterInputDevice *device)
690 {
691 MetaInputSettingsClass *input_settings_class;
692 gboolean edge_scroll_enabled;
693 gboolean two_finger_scroll_enabled;
694 gboolean two_finger_scroll_available;
695 MetaInputSettingsPrivate *priv;
696
697 if (device &&
698 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
699 return;
700
701 priv = meta_input_settings_get_instance_private (input_settings);
702 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
703 edge_scroll_enabled = g_settings_get_boolean (priv->touchpad_settings, "edge-scrolling-enabled");
704 two_finger_scroll_enabled = g_settings_get_boolean (priv->touchpad_settings, "two-finger-scrolling-enabled");
705 two_finger_scroll_available = g_hash_table_size (priv->two_finger_devices) > 0;
706
707 /* If both are enabled we prefer two finger. */
708 if (edge_scroll_enabled && two_finger_scroll_enabled && two_finger_scroll_available)
709 edge_scroll_enabled = FALSE;
710
711 if (device)
712 {
713 settings_device_set_bool_setting (input_settings, device,
714 input_settings_class->set_edge_scroll,
715 edge_scroll_enabled);
716 }
717 else
718 {
719 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE, NULL,
720 (ConfigBoolFunc) input_settings_class->set_edge_scroll,
721 edge_scroll_enabled);
722 }
723 }
724
725 static void
update_touchpad_two_finger_scroll(MetaInputSettings * input_settings,ClutterInputDevice * device)726 update_touchpad_two_finger_scroll (MetaInputSettings *input_settings,
727 ClutterInputDevice *device)
728 {
729 MetaInputSettingsClass *input_settings_class;
730 gboolean two_finger_scroll_enabled;
731 MetaInputSettingsPrivate *priv;
732
733 if (device &&
734 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
735 return;
736
737 priv = meta_input_settings_get_instance_private (input_settings);
738 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
739 two_finger_scroll_enabled = g_settings_get_boolean (priv->touchpad_settings, "two-finger-scrolling-enabled");
740
741 /* Disable edge since they can't both be set. */
742 if (two_finger_scroll_enabled)
743 update_touchpad_edge_scroll (input_settings, device);
744
745 if (device)
746 {
747 settings_device_set_bool_setting (input_settings, device,
748 input_settings_class->set_two_finger_scroll,
749 two_finger_scroll_enabled);
750 }
751 else
752 {
753 settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE, NULL,
754 (ConfigBoolFunc) input_settings_class->set_two_finger_scroll,
755 two_finger_scroll_enabled);
756 }
757
758 /* Edge might have been disabled because two finger was on. */
759 if (!two_finger_scroll_enabled)
760 update_touchpad_edge_scroll (input_settings, device);
761 }
762
763 static void
update_touchpad_click_method(MetaInputSettings * input_settings,ClutterInputDevice * device)764 update_touchpad_click_method (MetaInputSettings *input_settings,
765 ClutterInputDevice *device)
766 {
767 MetaInputSettingsClass *input_settings_class;
768 GDesktopTouchpadClickMethod method;
769 MetaInputSettingsPrivate *priv;
770
771 if (device &&
772 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
773 return;
774
775 priv = meta_input_settings_get_instance_private (input_settings);
776 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
777 method = g_settings_get_enum (priv->touchpad_settings, "click-method");
778
779 if (device)
780 {
781 settings_device_set_uint_setting (input_settings, device,
782 input_settings_class->set_click_method,
783 method);
784 }
785 else
786 {
787 settings_set_uint_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
788 (ConfigUintFunc) input_settings_class->set_click_method,
789 method);
790 }
791 }
792
793 static void
update_touchpad_send_events(MetaInputSettings * input_settings,ClutterInputDevice * device)794 update_touchpad_send_events (MetaInputSettings *input_settings,
795 ClutterInputDevice *device)
796 {
797 MetaInputSettingsClass *input_settings_class;
798 MetaInputSettingsPrivate *priv;
799 GDesktopDeviceSendEvents mode;
800
801 if (device &&
802 clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
803 return;
804
805 priv = meta_input_settings_get_instance_private (input_settings);
806 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
807 mode = g_settings_get_enum (priv->touchpad_settings, "send-events");
808
809 if (device)
810 {
811 settings_device_set_uint_setting (input_settings, device,
812 input_settings_class->set_send_events,
813 mode);
814 }
815 else
816 {
817 settings_set_uint_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
818 input_settings_class->set_send_events,
819 mode);
820 }
821 }
822
823 static void
update_trackball_scroll_button(MetaInputSettings * input_settings,ClutterInputDevice * device)824 update_trackball_scroll_button (MetaInputSettings *input_settings,
825 ClutterInputDevice *device)
826 {
827 MetaInputSettingsClass *input_settings_class;
828 MetaInputSettingsPrivate *priv;
829 guint button;
830 gboolean button_lock;
831
832 priv = meta_input_settings_get_instance_private (input_settings);
833 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
834
835 if (device && !input_settings_class->is_trackball_device (input_settings, device))
836 return;
837
838 /* This key is 'i' in the schema but it also specifies a minimum
839 * range of 0 so the cast here is safe. */
840 button = (guint) g_settings_get_int (priv->trackball_settings, "scroll-wheel-emulation-button");
841 button_lock = g_settings_get_boolean (priv->trackball_settings, "scroll-wheel-emulation-button-lock");
842
843 if (device)
844 {
845 input_settings_class->set_scroll_button (input_settings, device, button, button_lock);
846 }
847 else if (!device)
848 {
849 GList *l;
850
851 for (l = priv->devices; l; l = l->next)
852 {
853 device = l->data;
854
855 if (input_settings_class->is_trackball_device (input_settings, device))
856 input_settings_class->set_scroll_button (input_settings, device, button, button_lock);
857 }
858 }
859 }
860
861 static void
update_keyboard_repeat(MetaInputSettings * input_settings)862 update_keyboard_repeat (MetaInputSettings *input_settings)
863 {
864 MetaInputSettingsClass *input_settings_class;
865 MetaInputSettingsPrivate *priv;
866 guint delay, interval;
867 gboolean repeat;
868
869 priv = meta_input_settings_get_instance_private (input_settings);
870 repeat = g_settings_get_boolean (priv->keyboard_settings, "repeat");
871 delay = g_settings_get_uint (priv->keyboard_settings, "delay");
872 interval = g_settings_get_uint (priv->keyboard_settings, "repeat-interval");
873
874 delay = MAX (1, delay);
875 interval = MAX (1, interval);
876
877 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
878 input_settings_class->set_keyboard_repeat (input_settings,
879 repeat, delay, interval);
880 }
881
882 static void
update_tablet_keep_aspect(MetaInputSettings * input_settings,GSettings * settings,ClutterInputDevice * device)883 update_tablet_keep_aspect (MetaInputSettings *input_settings,
884 GSettings *settings,
885 ClutterInputDevice *device)
886 {
887 MetaInputSettingsPrivate *priv;
888 MetaInputSettingsClass *input_settings_class;
889 DeviceMappingInfo *info;
890 gboolean keep_aspect;
891 double aspect_ratio;
892
893 if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
894 clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE &&
895 clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE)
896 return;
897
898 priv = meta_input_settings_get_instance_private (input_settings);
899
900 info = g_hash_table_lookup (priv->mappable_devices, device);
901 if (!info)
902 return;
903
904 #ifdef HAVE_LIBWACOM
905 {
906 WacomDevice *wacom_device;
907
908 wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
909
910 /* Keep aspect only makes sense in external tablets */
911 if (wacom_device &&
912 libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE)
913 return;
914 }
915 #endif
916
917 keep_aspect = g_settings_get_boolean (settings, "keep-aspect");
918
919 if (keep_aspect)
920 aspect_ratio = info->aspect_ratio;
921 else
922 aspect_ratio = 0;
923
924 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
925 input_settings_class->set_tablet_aspect_ratio (input_settings, device, aspect_ratio);
926 }
927
928 static void
update_tablet_mapping(MetaInputSettings * input_settings,GSettings * settings,ClutterInputDevice * device)929 update_tablet_mapping (MetaInputSettings *input_settings,
930 GSettings *settings,
931 ClutterInputDevice *device)
932 {
933 MetaInputSettingsClass *input_settings_class;
934 GDesktopTabletMapping mapping;
935
936 if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
937 clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE &&
938 clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE)
939 return;
940
941 #ifdef HAVE_LIBWACOM
942 {
943 WacomDevice *wacom_device;
944
945 wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
946
947 /* Tablet mapping only makes sense on external tablets */
948 if (wacom_device &&
949 (libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE))
950 return;
951 }
952 #endif
953
954 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
955 mapping = g_settings_get_enum (settings, "mapping");
956
957 settings_device_set_uint_setting (input_settings, device,
958 input_settings_class->set_tablet_mapping,
959 mapping);
960 }
961
962 static void
update_tablet_area(MetaInputSettings * input_settings,GSettings * settings,ClutterInputDevice * device)963 update_tablet_area (MetaInputSettings *input_settings,
964 GSettings *settings,
965 ClutterInputDevice *device)
966 {
967 MetaInputSettingsClass *input_settings_class;
968 GVariant *variant;
969 const gdouble *area;
970 gsize n_elems;
971
972 if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
973 clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE &&
974 clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE)
975 return;
976
977 #ifdef HAVE_LIBWACOM
978 {
979 WacomDevice *wacom_device;
980
981 wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
982
983 /* Tablet area only makes sense on system/display integrated tablets */
984 if (wacom_device &&
985 (libwacom_get_integration_flags (wacom_device) &
986 (WACOM_DEVICE_INTEGRATED_SYSTEM | WACOM_DEVICE_INTEGRATED_DISPLAY)) == 0)
987 return;
988 }
989 #endif
990
991 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
992 variant = g_settings_get_value (settings, "area");
993
994 area = g_variant_get_fixed_array (variant, &n_elems, sizeof (gdouble));
995 if (n_elems == 4)
996 {
997 input_settings_class->set_tablet_area (input_settings, device,
998 area[0], area[1],
999 area[2], area[3]);
1000 }
1001
1002 g_variant_unref (variant);
1003 }
1004
1005 static void
update_tablet_left_handed(MetaInputSettings * input_settings,GSettings * settings,ClutterInputDevice * device)1006 update_tablet_left_handed (MetaInputSettings *input_settings,
1007 GSettings *settings,
1008 ClutterInputDevice *device)
1009 {
1010 MetaInputSettingsClass *input_settings_class;
1011 gboolean enabled;
1012
1013 if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
1014 clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE &&
1015 clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE &&
1016 clutter_input_device_get_device_type (device) != CLUTTER_PAD_DEVICE)
1017 return;
1018
1019 #ifdef HAVE_LIBWACOM
1020 {
1021 WacomDevice *wacom_device;
1022
1023 wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
1024
1025 /* Left handed mode only makes sense on external tablets */
1026 if (wacom_device &&
1027 (libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE))
1028 return;
1029 }
1030 #endif
1031
1032 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
1033 enabled = g_settings_get_boolean (settings, "left-handed");
1034
1035 settings_device_set_bool_setting (input_settings, device,
1036 input_settings_class->set_left_handed,
1037 enabled);
1038 }
1039
1040 static void
meta_input_settings_changed_cb(GSettings * settings,const char * key,gpointer user_data)1041 meta_input_settings_changed_cb (GSettings *settings,
1042 const char *key,
1043 gpointer user_data)
1044 {
1045 MetaInputSettings *input_settings = META_INPUT_SETTINGS (user_data);
1046 MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
1047
1048 if (settings == priv->mouse_settings)
1049 {
1050 if (strcmp (key, "left-handed") == 0)
1051 update_mouse_left_handed (input_settings, NULL);
1052 else if (strcmp (key, "speed") == 0)
1053 update_device_speed (input_settings, NULL);
1054 else if (strcmp (key, "natural-scroll") == 0)
1055 update_device_natural_scroll (input_settings, NULL);
1056 else if (strcmp (key, "accel-profile") == 0)
1057 update_pointer_accel_profile (input_settings, settings, NULL);
1058 else if (strcmp (key, "middle-click-emulation") == 0)
1059 update_middle_click_emulation (input_settings, settings, NULL);
1060 }
1061 else if (settings == priv->touchpad_settings)
1062 {
1063 if (strcmp (key, "left-handed") == 0)
1064 update_touchpad_left_handed (input_settings, NULL);
1065 else if (strcmp (key, "speed") == 0)
1066 update_device_speed (input_settings, NULL);
1067 else if (strcmp (key, "natural-scroll") == 0)
1068 update_device_natural_scroll (input_settings, NULL);
1069 else if (strcmp (key, "tap-to-click") == 0)
1070 update_touchpad_tap_enabled (input_settings, NULL);
1071 else if (strcmp (key, "tap-button-map") == 0)
1072 update_touchpad_tap_button_map (input_settings, NULL);
1073 else if (strcmp (key, "tap-and-drag") == 0)
1074 update_touchpad_tap_and_drag_enabled (input_settings, NULL);
1075 else if (strcmp (key, "tap-and-drag-lock") == 0)
1076 update_touchpad_tap_and_drag_lock_enabled (input_settings, NULL);
1077 else if (strcmp(key, "disable-while-typing") == 0)
1078 update_touchpad_disable_while_typing (input_settings, NULL);
1079 else if (strcmp (key, "send-events") == 0)
1080 update_touchpad_send_events (input_settings, NULL);
1081 else if (strcmp (key, "edge-scrolling-enabled") == 0)
1082 update_touchpad_edge_scroll (input_settings, NULL);
1083 else if (strcmp (key, "two-finger-scrolling-enabled") == 0)
1084 update_touchpad_two_finger_scroll (input_settings, NULL);
1085 else if (strcmp (key, "click-method") == 0)
1086 update_touchpad_click_method (input_settings, NULL);
1087 else if (strcmp (key, "middle-click-emulation") == 0)
1088 update_middle_click_emulation (input_settings, settings, NULL);
1089 }
1090 else if (settings == priv->trackball_settings)
1091 {
1092 if (strcmp (key, "scroll-wheel-emulation-button") == 0 ||
1093 strcmp (key, "scroll-wheel-emulation-button-lock") == 0)
1094 update_trackball_scroll_button (input_settings, NULL);
1095 else if (strcmp (key, "accel-profile") == 0)
1096 update_pointer_accel_profile (input_settings, settings, NULL);
1097 else if (strcmp (key, "middle-click-emulation") == 0)
1098 update_middle_click_emulation (input_settings, settings, NULL);
1099 }
1100 else if (settings == priv->keyboard_settings)
1101 {
1102 if (strcmp (key, "repeat") == 0 ||
1103 strcmp (key, "repeat-interval") == 0 ||
1104 strcmp (key, "delay") == 0)
1105 update_keyboard_repeat (input_settings);
1106 }
1107 }
1108
1109 static void
mapped_device_changed_cb(GSettings * settings,const gchar * key,DeviceMappingInfo * info)1110 mapped_device_changed_cb (GSettings *settings,
1111 const gchar *key,
1112 DeviceMappingInfo *info)
1113 {
1114 if (strcmp (key, "mapping") == 0)
1115 update_tablet_mapping (info->input_settings, settings, info->device);
1116 else if (strcmp (key, "area") == 0)
1117 update_tablet_area (info->input_settings, settings, info->device);
1118 else if (strcmp (key, "keep-aspect") == 0)
1119 update_tablet_keep_aspect (info->input_settings, settings, info->device);
1120 else if (strcmp (key, "left-handed") == 0)
1121 update_tablet_left_handed (info->input_settings, settings, info->device);
1122 }
1123
1124 static void
apply_mappable_device_settings(MetaInputSettings * input_settings,DeviceMappingInfo * info)1125 apply_mappable_device_settings (MetaInputSettings *input_settings,
1126 DeviceMappingInfo *info)
1127 {
1128 ClutterInputDeviceType device_type;
1129
1130 device_type = clutter_input_device_get_device_type (info->device);
1131
1132 if (device_type == CLUTTER_TABLET_DEVICE ||
1133 device_type == CLUTTER_PEN_DEVICE ||
1134 device_type == CLUTTER_ERASER_DEVICE ||
1135 device_type == CLUTTER_PAD_DEVICE)
1136 {
1137 update_tablet_mapping (input_settings, info->settings, info->device);
1138 update_tablet_area (input_settings, info->settings, info->device);
1139 update_tablet_keep_aspect (input_settings, info->settings, info->device);
1140 update_tablet_left_handed (input_settings, info->settings, info->device);
1141 }
1142 }
1143
1144 struct _keyboard_a11y_settings_flags_pair {
1145 const char *name;
1146 MetaKeyboardA11yFlags flag;
1147 } keyboard_a11y_settings_flags_pair[] = {
1148 { "enable", META_A11Y_KEYBOARD_ENABLED },
1149 { "timeout-enable", META_A11Y_TIMEOUT_ENABLED },
1150 { "mousekeys-enable", META_A11Y_MOUSE_KEYS_ENABLED },
1151 { "slowkeys-enable", META_A11Y_SLOW_KEYS_ENABLED },
1152 { "slowkeys-beep-press", META_A11Y_SLOW_KEYS_BEEP_PRESS },
1153 { "slowkeys-beep-accept", META_A11Y_SLOW_KEYS_BEEP_ACCEPT },
1154 { "slowkeys-beep-reject", META_A11Y_SLOW_KEYS_BEEP_REJECT },
1155 { "bouncekeys-enable", META_A11Y_BOUNCE_KEYS_ENABLED },
1156 { "bouncekeys-beep-reject", META_A11Y_BOUNCE_KEYS_BEEP_REJECT },
1157 { "togglekeys-enable", META_A11Y_TOGGLE_KEYS_ENABLED },
1158 { "stickykeys-enable", META_A11Y_STICKY_KEYS_ENABLED },
1159 { "stickykeys-modifier-beep", META_A11Y_STICKY_KEYS_BEEP },
1160 { "stickykeys-two-key-off", META_A11Y_STICKY_KEYS_TWO_KEY_OFF },
1161 { "feature-state-change-beep", META_A11Y_FEATURE_STATE_CHANGE_BEEP },
1162 };
1163
1164 static void
load_keyboard_a11y_settings(MetaInputSettings * input_settings)1165 load_keyboard_a11y_settings (MetaInputSettings *input_settings)
1166 {
1167 MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
1168 MetaKbdA11ySettings kbd_a11y_settings = { 0 };
1169 guint i;
1170
1171 kbd_a11y_settings.controls = 0;
1172 for (i = 0; i < G_N_ELEMENTS (keyboard_a11y_settings_flags_pair); i++)
1173 {
1174 if (g_settings_get_boolean (priv->keyboard_a11y_settings, keyboard_a11y_settings_flags_pair[i].name))
1175 kbd_a11y_settings.controls |= keyboard_a11y_settings_flags_pair[i].flag;
1176 }
1177
1178 kbd_a11y_settings.timeout_delay = g_settings_get_int (priv->keyboard_a11y_settings,
1179 "disable-timeout");
1180 kbd_a11y_settings.slowkeys_delay = g_settings_get_int (priv->keyboard_a11y_settings,
1181 "slowkeys-delay");
1182 kbd_a11y_settings.debounce_delay = g_settings_get_int (priv->keyboard_a11y_settings,
1183 "bouncekeys-delay");
1184 kbd_a11y_settings.mousekeys_init_delay = g_settings_get_int (priv->keyboard_a11y_settings,
1185 "mousekeys-init-delay");
1186 kbd_a11y_settings.mousekeys_max_speed = g_settings_get_int (priv->keyboard_a11y_settings,
1187 "mousekeys-max-speed");
1188 kbd_a11y_settings.mousekeys_accel_time = g_settings_get_int (priv->keyboard_a11y_settings,
1189 "mousekeys-accel-time");
1190
1191 priv->kbd_a11y_settings = kbd_a11y_settings;
1192 g_signal_emit (input_settings, signals[KBD_A11Y_CHANGED], 0, &priv->kbd_a11y_settings);
1193 }
1194
1195 void
meta_input_settings_notify_kbd_a11y_change(MetaInputSettings * input_settings,MetaKeyboardA11yFlags new_flags,MetaKeyboardA11yFlags what_changed)1196 meta_input_settings_notify_kbd_a11y_change (MetaInputSettings *input_settings,
1197 MetaKeyboardA11yFlags new_flags,
1198 MetaKeyboardA11yFlags what_changed)
1199 {
1200 MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
1201 guint i;
1202
1203 for (i = 0; i < G_N_ELEMENTS (keyboard_a11y_settings_flags_pair); i++)
1204 {
1205 if (keyboard_a11y_settings_flags_pair[i].flag & what_changed)
1206 g_settings_set_boolean (priv->keyboard_a11y_settings,
1207 keyboard_a11y_settings_flags_pair[i].name,
1208 (new_flags & keyboard_a11y_settings_flags_pair[i].flag) ? TRUE : FALSE);
1209 }
1210 }
1211
1212 static void
meta_input_keyboard_a11y_settings_changed(GSettings * settings,const char * key,gpointer user_data)1213 meta_input_keyboard_a11y_settings_changed (GSettings *settings,
1214 const char *key,
1215 gpointer user_data)
1216 {
1217 MetaInputSettings *input_settings = META_INPUT_SETTINGS (user_data);
1218
1219 load_keyboard_a11y_settings (input_settings);
1220 }
1221
1222 static GSettings *
lookup_device_settings(ClutterInputDevice * device)1223 lookup_device_settings (ClutterInputDevice *device)
1224 {
1225 const gchar *group, *schema, *vendor, *product;
1226 ClutterInputDeviceType type;
1227 GSettings *settings;
1228 gchar *path;
1229
1230 type = clutter_input_device_get_device_type (device);
1231
1232 if (type == CLUTTER_TOUCHSCREEN_DEVICE)
1233 {
1234 group = "touchscreens";
1235 schema = "org.gnome.desktop.peripherals.touchscreen";
1236 }
1237 else if (type == CLUTTER_TABLET_DEVICE ||
1238 type == CLUTTER_PEN_DEVICE ||
1239 type == CLUTTER_ERASER_DEVICE ||
1240 type == CLUTTER_CURSOR_DEVICE ||
1241 type == CLUTTER_PAD_DEVICE)
1242 {
1243 group = "tablets";
1244 schema = "org.gnome.desktop.peripherals.tablet";
1245 }
1246 else
1247 return NULL;
1248
1249 vendor = clutter_input_device_get_vendor_id (device);
1250 product = clutter_input_device_get_product_id (device);
1251 path = g_strdup_printf ("/org/gnome/desktop/peripherals/%s/%s:%s/",
1252 group, vendor, product);
1253
1254 settings = g_settings_new_with_path (schema, path);
1255 g_free (path);
1256
1257 return settings;
1258 }
1259
1260 static GSettings *
lookup_tool_settings(ClutterInputDeviceTool * tool,ClutterInputDevice * device)1261 lookup_tool_settings (ClutterInputDeviceTool *tool,
1262 ClutterInputDevice *device)
1263 {
1264 GSettings *tool_settings;
1265 guint64 serial;
1266 gchar *path;
1267
1268 tool_settings = g_object_get_qdata (G_OBJECT (tool), quark_tool_settings);
1269 if (tool_settings)
1270 return tool_settings;
1271
1272 serial = clutter_input_device_tool_get_serial (tool);
1273
1274 /* The Wacom driver uses serial 1 for serial-less devices but 1 is not a
1275 * real serial, so let's custom-case this */
1276 if (serial == 0 || serial == 1)
1277 {
1278 path = g_strdup_printf ("/org/gnome/desktop/peripherals/stylus/default-%s:%s/",
1279 clutter_input_device_get_vendor_id (device),
1280 clutter_input_device_get_product_id (device));
1281 }
1282 else
1283 {
1284 path = g_strdup_printf ("/org/gnome/desktop/peripherals/stylus/%" G_GINT64_MODIFIER "x/",
1285 serial);
1286 }
1287
1288 tool_settings =
1289 g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.stylus",
1290 path);
1291 g_object_set_qdata_full (G_OBJECT (tool), quark_tool_settings, tool_settings,
1292 (GDestroyNotify) g_object_unref);
1293 g_free (path);
1294
1295 return tool_settings;
1296 }
1297
1298 static void
device_mapping_info_free(DeviceMappingInfo * info)1299 device_mapping_info_free (DeviceMappingInfo *info)
1300 {
1301 g_clear_signal_handler (&info->changed_id, info->settings);
1302 g_object_unref (info->settings);
1303 g_free (info->group_modes);
1304 g_free (info);
1305 }
1306
1307 static gboolean
check_add_mappable_device(MetaInputSettings * input_settings,ClutterInputDevice * device)1308 check_add_mappable_device (MetaInputSettings *input_settings,
1309 ClutterInputDevice *device)
1310 {
1311 MetaInputSettingsPrivate *priv;
1312 DeviceMappingInfo *info;
1313 ClutterInputDeviceType device_type;
1314 GSettings *settings;
1315
1316 device_type = clutter_input_device_get_device_type (device);
1317
1318 if ((device_type == CLUTTER_TABLET_DEVICE ||
1319 device_type == CLUTTER_PEN_DEVICE ||
1320 device_type == CLUTTER_ERASER_DEVICE ||
1321 device_type == CLUTTER_PAD_DEVICE) &&
1322 g_getenv ("MUTTER_DISABLE_WACOM_CONFIGURATION") != NULL)
1323 return FALSE;
1324
1325 settings = lookup_device_settings (device);
1326
1327 if (!settings)
1328 return FALSE;
1329
1330 priv = meta_input_settings_get_instance_private (input_settings);
1331
1332 info = g_new0 (DeviceMappingInfo, 1);
1333 info->input_settings = input_settings;
1334 info->device = device;
1335 info->settings = settings;
1336
1337 if (device_type == CLUTTER_PAD_DEVICE)
1338 {
1339 info->group_modes =
1340 g_new0 (guint, clutter_input_device_get_n_mode_groups (device));
1341 }
1342
1343 info->changed_id = g_signal_connect (settings, "changed",
1344 G_CALLBACK (mapped_device_changed_cb),
1345 info);
1346
1347 g_hash_table_insert (priv->mappable_devices, device, info);
1348
1349 apply_mappable_device_settings (input_settings, info);
1350
1351 return TRUE;
1352 }
1353
1354 static void
apply_device_settings(MetaInputSettings * input_settings,ClutterInputDevice * device)1355 apply_device_settings (MetaInputSettings *input_settings,
1356 ClutterInputDevice *device)
1357 {
1358 MetaInputSettingsPrivate *priv =
1359 meta_input_settings_get_instance_private (input_settings);
1360
1361 update_device_speed (input_settings, device);
1362 update_device_natural_scroll (input_settings, device);
1363
1364 update_mouse_left_handed (input_settings, device);
1365 update_pointer_accel_profile (input_settings,
1366 priv->mouse_settings,
1367 device);
1368
1369 update_touchpad_left_handed (input_settings, device);
1370 update_touchpad_tap_enabled (input_settings, device);
1371 update_touchpad_tap_button_map (input_settings, device);
1372 update_touchpad_tap_and_drag_enabled (input_settings, device);
1373 update_touchpad_tap_and_drag_lock_enabled (input_settings, device);
1374 update_touchpad_disable_while_typing (input_settings, device);
1375 update_touchpad_send_events (input_settings, device);
1376 update_touchpad_two_finger_scroll (input_settings, device);
1377 update_touchpad_edge_scroll (input_settings, device);
1378 update_touchpad_click_method (input_settings, device);
1379
1380 update_trackball_scroll_button (input_settings, device);
1381 update_pointer_accel_profile (input_settings,
1382 priv->trackball_settings,
1383 device);
1384
1385 update_middle_click_emulation (input_settings, priv->mouse_settings, device);
1386 update_middle_click_emulation (input_settings, priv->touchpad_settings, device);
1387 update_middle_click_emulation (input_settings, priv->trackball_settings, device);
1388 }
1389
1390 static void
update_stylus_pressure(MetaInputSettings * input_settings,ClutterInputDevice * device,ClutterInputDeviceTool * tool)1391 update_stylus_pressure (MetaInputSettings *input_settings,
1392 ClutterInputDevice *device,
1393 ClutterInputDeviceTool *tool)
1394 {
1395 MetaInputSettingsClass *input_settings_class;
1396 GSettings *tool_settings;
1397 const gint32 *curve;
1398 GVariant *variant;
1399 gsize n_elems;
1400
1401 if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
1402 clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE &&
1403 clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE)
1404 return;
1405
1406 if (!tool)
1407 return;
1408
1409 tool_settings = lookup_tool_settings (tool, device);
1410
1411 if (clutter_input_device_tool_get_tool_type (tool) ==
1412 CLUTTER_INPUT_DEVICE_TOOL_ERASER)
1413 variant = g_settings_get_value (tool_settings, "eraser-pressure-curve");
1414 else
1415 variant = g_settings_get_value (tool_settings, "pressure-curve");
1416
1417 curve = g_variant_get_fixed_array (variant, &n_elems, sizeof (gint32));
1418 if (n_elems != 4)
1419 return;
1420
1421 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
1422 input_settings_class->set_stylus_pressure (input_settings, device, tool, curve);
1423 }
1424
1425 static void
update_stylus_buttonmap(MetaInputSettings * input_settings,ClutterInputDevice * device,ClutterInputDeviceTool * tool)1426 update_stylus_buttonmap (MetaInputSettings *input_settings,
1427 ClutterInputDevice *device,
1428 ClutterInputDeviceTool *tool)
1429 {
1430 MetaInputSettingsClass *input_settings_class;
1431 GDesktopStylusButtonAction primary, secondary, tertiary;
1432 GSettings *tool_settings;
1433
1434 if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
1435 clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE &&
1436 clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE)
1437 return;
1438
1439 if (!tool)
1440 return;
1441
1442 tool_settings = lookup_tool_settings (tool, device);
1443
1444 primary = g_settings_get_enum (tool_settings, "button-action");
1445 secondary = g_settings_get_enum (tool_settings, "secondary-button-action");
1446 tertiary = g_settings_get_enum (tool_settings, "tertiary-button-action");
1447
1448 input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
1449 input_settings_class->set_stylus_button_map (input_settings, device, tool,
1450 primary, secondary, tertiary);
1451 }
1452
1453 static void
apply_stylus_settings(MetaInputSettings * input_settings,ClutterInputDevice * device,ClutterInputDeviceTool * tool)1454 apply_stylus_settings (MetaInputSettings *input_settings,
1455 ClutterInputDevice *device,
1456 ClutterInputDeviceTool *tool)
1457 {
1458 update_stylus_pressure (input_settings, device, tool);
1459 update_stylus_buttonmap (input_settings, device, tool);
1460 }
1461
1462 static void
evaluate_two_finger_scrolling(MetaInputSettings * input_settings,ClutterInputDevice * device)1463 evaluate_two_finger_scrolling (MetaInputSettings *input_settings,
1464 ClutterInputDevice *device)
1465 {
1466 MetaInputSettingsClass *klass;
1467 MetaInputSettingsPrivate *priv;
1468
1469 if (clutter_input_device_get_device_type (device) != CLUTTER_TOUCHPAD_DEVICE)
1470 return;
1471
1472 klass = META_INPUT_SETTINGS_GET_CLASS (input_settings);
1473 priv = meta_input_settings_get_instance_private (input_settings);
1474
1475 if (klass->has_two_finger_scroll (input_settings, device))
1476 g_hash_table_add (priv->two_finger_devices, device);
1477 }
1478
1479 void
meta_input_settings_add_device(MetaInputSettings * input_settings,ClutterInputDevice * device)1480 meta_input_settings_add_device (MetaInputSettings *input_settings,
1481 ClutterInputDevice *device)
1482 {
1483 MetaInputSettingsPrivate *priv =
1484 meta_input_settings_get_instance_private (input_settings);
1485
1486 if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_LOGICAL)
1487 return;
1488
1489 priv->devices = g_list_prepend (priv->devices, device);
1490 evaluate_two_finger_scrolling (input_settings, device);
1491
1492 apply_device_settings (input_settings, device);
1493 check_add_mappable_device (input_settings, device);
1494 }
1495
1496 void
meta_input_settings_remove_device(MetaInputSettings * input_settings,ClutterInputDevice * device)1497 meta_input_settings_remove_device (MetaInputSettings *input_settings,
1498 ClutterInputDevice *device)
1499 {
1500 MetaInputSettingsPrivate *priv;
1501
1502 priv = meta_input_settings_get_instance_private (input_settings);
1503 g_hash_table_remove (priv->mappable_devices, device);
1504 g_hash_table_remove (priv->current_tools, device);
1505
1506 if (g_hash_table_remove (priv->two_finger_devices, device) &&
1507 g_hash_table_size (priv->two_finger_devices) == 0)
1508 apply_device_settings (input_settings, NULL);
1509
1510 priv->devices = g_list_remove (priv->devices, device);
1511 }
1512
1513 static void
current_tool_changed_cb(GSettings * settings,const char * key,gpointer user_data)1514 current_tool_changed_cb (GSettings *settings,
1515 const char *key,
1516 gpointer user_data)
1517 {
1518 CurrentToolInfo *info = user_data;
1519
1520 apply_stylus_settings (info->input_settings, info->device, info->tool);
1521 }
1522
1523 static CurrentToolInfo *
current_tool_info_new(MetaInputSettings * input_settings,ClutterInputDevice * device,ClutterInputDeviceTool * tool)1524 current_tool_info_new (MetaInputSettings *input_settings,
1525 ClutterInputDevice *device,
1526 ClutterInputDeviceTool *tool)
1527 {
1528 CurrentToolInfo *info;
1529
1530 info = g_new0 (CurrentToolInfo, 1);
1531 info->input_settings = input_settings;
1532 info->device = device;
1533 info->tool = tool;
1534 info->settings = lookup_tool_settings (tool, device);
1535 info->changed_id =
1536 g_signal_connect (info->settings, "changed",
1537 G_CALLBACK (current_tool_changed_cb),
1538 info);
1539 return info;
1540 }
1541
1542 static void
current_tool_info_free(CurrentToolInfo * info)1543 current_tool_info_free (CurrentToolInfo *info)
1544 {
1545 g_clear_signal_handler (&info->changed_id, info->settings);
1546 g_free (info);
1547 }
1548
1549 void
meta_input_settings_notify_tool_change(MetaInputSettings * input_settings,ClutterInputDevice * device,ClutterInputDeviceTool * tool)1550 meta_input_settings_notify_tool_change (MetaInputSettings *input_settings,
1551 ClutterInputDevice *device,
1552 ClutterInputDeviceTool *tool)
1553 {
1554 MetaInputSettingsPrivate *priv;
1555
1556 priv = meta_input_settings_get_instance_private (input_settings);
1557
1558 if (tool)
1559 {
1560 CurrentToolInfo *current_tool;
1561
1562 current_tool = current_tool_info_new (input_settings, device, tool);
1563 g_hash_table_insert (priv->current_tools, device, current_tool);
1564 apply_stylus_settings (input_settings, device, tool);
1565 }
1566 else
1567 {
1568 g_hash_table_remove (priv->current_tools, device);
1569 }
1570 }
1571
1572 static void
check_mappable_devices(MetaInputSettings * input_settings)1573 check_mappable_devices (MetaInputSettings *input_settings)
1574 {
1575 MetaInputSettingsPrivate *priv;
1576 GList *l;
1577
1578 priv = meta_input_settings_get_instance_private (input_settings);
1579
1580 for (l = priv->devices; l; l = l->next)
1581 {
1582 ClutterInputDevice *device = l->data;
1583
1584 if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_LOGICAL)
1585 continue;
1586
1587 check_add_mappable_device (input_settings, device);
1588 }
1589 }
1590
1591 static void
meta_input_settings_constructed(GObject * object)1592 meta_input_settings_constructed (GObject *object)
1593 {
1594 MetaInputSettings *input_settings = META_INPUT_SETTINGS (object);
1595 GSList *devices, *d;
1596
1597 devices = meta_input_settings_get_devices (input_settings, CLUTTER_TOUCHPAD_DEVICE);
1598 for (d = devices; d; d = d->next)
1599 evaluate_two_finger_scrolling (input_settings, d->data);
1600
1601 g_slist_free (devices);
1602
1603 apply_device_settings (input_settings, NULL);
1604 update_keyboard_repeat (input_settings);
1605 check_mappable_devices (input_settings);
1606
1607 load_keyboard_a11y_settings (input_settings);
1608 }
1609
1610 static void
meta_input_settings_class_init(MetaInputSettingsClass * klass)1611 meta_input_settings_class_init (MetaInputSettingsClass *klass)
1612 {
1613 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1614
1615 object_class->dispose = meta_input_settings_dispose;
1616 object_class->constructed = meta_input_settings_constructed;
1617
1618 quark_tool_settings =
1619 g_quark_from_static_string ("meta-input-settings-tool-settings");
1620
1621 signals[KBD_A11Y_CHANGED] =
1622 g_signal_new ("kbd-a11y-changed",
1623 G_TYPE_FROM_CLASS (object_class),
1624 G_SIGNAL_RUN_LAST,
1625 0, NULL, NULL, NULL,
1626 G_TYPE_NONE, 1,
1627 G_TYPE_POINTER);
1628
1629 }
1630
1631 static void
meta_input_settings_init(MetaInputSettings * settings)1632 meta_input_settings_init (MetaInputSettings *settings)
1633 {
1634 MetaInputSettingsPrivate *priv;
1635
1636 priv = meta_input_settings_get_instance_private (settings);
1637
1638 priv->mouse_settings = g_settings_new ("org.gnome.desktop.peripherals.mouse");
1639 g_signal_connect (priv->mouse_settings, "changed",
1640 G_CALLBACK (meta_input_settings_changed_cb), settings);
1641
1642 priv->touchpad_settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad");
1643 g_signal_connect (priv->touchpad_settings, "changed",
1644 G_CALLBACK (meta_input_settings_changed_cb), settings);
1645
1646 priv->trackball_settings = g_settings_new ("org.gnome.desktop.peripherals.trackball");
1647 g_signal_connect (priv->trackball_settings, "changed",
1648 G_CALLBACK (meta_input_settings_changed_cb), settings);
1649
1650 priv->keyboard_settings = g_settings_new ("org.gnome.desktop.peripherals.keyboard");
1651 g_signal_connect (priv->keyboard_settings, "changed",
1652 G_CALLBACK (meta_input_settings_changed_cb), settings);
1653
1654 priv->keyboard_a11y_settings = g_settings_new ("org.gnome.desktop.a11y.keyboard");
1655 g_signal_connect (priv->keyboard_a11y_settings, "changed",
1656 G_CALLBACK (meta_input_keyboard_a11y_settings_changed), settings);
1657
1658 priv->mappable_devices =
1659 g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) device_mapping_info_free);
1660
1661 priv->current_tools =
1662 g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) current_tool_info_free);
1663
1664 priv->two_finger_devices = g_hash_table_new (NULL, NULL);
1665 }
1666
1667 void
meta_input_settings_maybe_save_numlock_state(MetaInputSettings * input_settings,gboolean numlock_state)1668 meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings,
1669 gboolean numlock_state)
1670 {
1671 MetaInputSettingsPrivate *priv;
1672
1673 priv = meta_input_settings_get_instance_private (input_settings);
1674
1675 if (!g_settings_get_boolean (priv->keyboard_settings, "remember-numlock-state"))
1676 return;
1677
1678 if (numlock_state == g_settings_get_boolean (priv->keyboard_settings, "numlock-state"))
1679 return;
1680
1681 g_settings_set_boolean (priv->keyboard_settings, "numlock-state", numlock_state);
1682 }
1683
1684 gboolean
meta_input_settings_maybe_restore_numlock_state(MetaInputSettings * input_settings)1685 meta_input_settings_maybe_restore_numlock_state (MetaInputSettings *input_settings)
1686 {
1687 MetaInputSettingsPrivate *priv;
1688 gboolean numlock_state = FALSE;
1689
1690 priv = meta_input_settings_get_instance_private (input_settings);
1691
1692 if (g_settings_get_boolean (priv->keyboard_settings, "remember-numlock-state"))
1693 numlock_state = g_settings_get_boolean (priv->keyboard_settings, "numlock-state");
1694
1695 return numlock_state;
1696 }
1697
1698 void
meta_input_settings_set_device_matrix(MetaInputSettings * input_settings,ClutterInputDevice * device,float matrix[6])1699 meta_input_settings_set_device_matrix (MetaInputSettings *input_settings,
1700 ClutterInputDevice *device,
1701 float matrix[6])
1702 {
1703 g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings));
1704 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1705
1706 META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_matrix (input_settings,
1707 device,
1708 matrix);
1709 }
1710
1711 void
meta_input_settings_set_device_enabled(MetaInputSettings * input_settings,ClutterInputDevice * device,gboolean enabled)1712 meta_input_settings_set_device_enabled (MetaInputSettings *input_settings,
1713 ClutterInputDevice *device,
1714 gboolean enabled)
1715 {
1716 GDesktopDeviceSendEvents mode;
1717
1718 g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings));
1719 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1720
1721 mode = enabled ?
1722 G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED :
1723 G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED;
1724
1725 META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_send_events (input_settings,
1726 device,
1727 mode);
1728 }
1729
1730 void
meta_input_settings_set_device_aspect_ratio(MetaInputSettings * input_settings,ClutterInputDevice * device,double aspect_ratio)1731 meta_input_settings_set_device_aspect_ratio (MetaInputSettings *input_settings,
1732 ClutterInputDevice *device,
1733 double aspect_ratio)
1734 {
1735 MetaInputSettingsPrivate *priv;
1736 DeviceMappingInfo *info;
1737
1738 g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings));
1739 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1740
1741 priv = meta_input_settings_get_instance_private (input_settings);
1742
1743 info = g_hash_table_lookup (priv->mappable_devices, device);
1744 if (!info)
1745 return;
1746
1747 info->aspect_ratio = aspect_ratio;
1748 update_tablet_keep_aspect (input_settings, info->settings, device);
1749 }
1750
1751 void
meta_input_settings_get_kbd_a11y_settings(MetaInputSettings * input_settings,MetaKbdA11ySettings * a11y_settings)1752 meta_input_settings_get_kbd_a11y_settings (MetaInputSettings *input_settings,
1753 MetaKbdA11ySettings *a11y_settings)
1754 {
1755 MetaInputSettingsPrivate *priv;
1756
1757 g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings));
1758
1759 priv = meta_input_settings_get_instance_private (input_settings);
1760
1761 *a11y_settings = priv->kbd_a11y_settings;
1762 }
1763