1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4  * Copyright (C) 2012-2021 MATE Developers
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  */
21 
22 #include "config.h"
23 
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <math.h>
32 
33 #include <locale.h>
34 
35 #include <glib.h>
36 #include <glib/gi18n.h>
37 #include <gtk/gtk.h>
38 #include <gdk/gdk.h>
39 #include <gdk/gdkx.h>
40 #include <gdk/gdkkeysyms.h>
41 #include <X11/keysym.h>
42 #include <X11/Xatom.h>
43 #include <X11/extensions/XInput.h>
44 #include <X11/extensions/XIproto.h>
45 
46 #include <gio/gio.h>
47 
48 #include "mate-settings-profile.h"
49 #include "msd-mouse-manager.h"
50 #include "msd-input-helper.h"
51 
52 /* Keys with same names for both touchpad and mouse */
53 #define KEY_LEFT_HANDED                  "left-handed"          /*  a boolean for mouse, an enum for touchpad */
54 #define KEY_MOTION_ACCELERATION          "motion-acceleration"
55 #define KEY_MOTION_THRESHOLD             "motion-threshold"
56 #define KEY_ACCEL_PROFILE                "accel-profile"
57 
58 /* Mouse settings */
59 #define MATE_MOUSE_SCHEMA                "org.mate.peripherals-mouse"
60 #define KEY_MOUSE_LOCATE_POINTER         "locate-pointer"
61 #define KEY_MIDDLE_BUTTON_EMULATION      "middle-button-enabled"
62 
63 /* Touchpad settings */
64 #define MATE_TOUCHPAD_SCHEMA             "org.mate.peripherals-touchpad"
65 #define KEY_TOUCHPAD_DISABLE_W_TYPING    "disable-while-typing"
66 #define KEY_TOUCHPAD_TWO_FINGER_CLICK    "two-finger-click"
67 #define KEY_TOUCHPAD_THREE_FINGER_CLICK  "three-finger-click"
68 #define KEY_TOUCHPAD_NATURAL_SCROLL      "natural-scroll"
69 #define KEY_TOUCHPAD_TAP_TO_CLICK        "tap-to-click"
70 #define KEY_TOUCHPAD_ONE_FINGER_TAP      "tap-button-one-finger"
71 #define KEY_TOUCHPAD_TWO_FINGER_TAP      "tap-button-two-finger"
72 #define KEY_TOUCHPAD_THREE_FINGER_TAP    "tap-button-three-finger"
73 #define KEY_VERT_EDGE_SCROLL             "vertical-edge-scrolling"
74 #define KEY_HORIZ_EDGE_SCROLL            "horizontal-edge-scrolling"
75 #define KEY_VERT_TWO_FINGER_SCROLL       "vertical-two-finger-scrolling"
76 #define KEY_HORIZ_TWO_FINGER_SCROLL      "horizontal-two-finger-scrolling"
77 #define KEY_TOUCHPAD_ENABLED             "touchpad-enabled"
78 
79 
80 #if 0   /* FIXME need to fork (?) mousetweaks for this to work */
81 #define MATE_MOUSE_A11Y_SCHEMA           "org.mate.accessibility-mouse"
82 #define KEY_MOUSE_A11Y_DWELL_ENABLE      "dwell-enable"
83 #define KEY_MOUSE_A11Y_DELAY_ENABLE      "delay-enable"
84 #endif
85 
86 struct MsdMouseManagerPrivate
87 {
88         GSettings *settings_mouse;
89         GSettings *settings_touchpad;
90 
91 #if 0   /* FIXME need to fork (?) mousetweaks for this to work */
92         gboolean mousetweaks_daemon_running;
93 #endif
94         gboolean syndaemon_spawned;
95         GPid syndaemon_pid;
96         gboolean locate_pointer_spawned;
97         GPid locate_pointer_pid;
98 };
99 
100 typedef enum {
101         TOUCHPAD_HANDEDNESS_RIGHT,
102         TOUCHPAD_HANDEDNESS_LEFT,
103         TOUCHPAD_HANDEDNESS_MOUSE
104 } TouchpadHandedness;
105 
106 typedef enum {
107         ACCEL_PROFILE_DEFAULT,
108         ACCEL_PROFILE_ADAPTIVE,
109         ACCEL_PROFILE_FLAT
110 } AccelProfile;
111 
112 static void     msd_mouse_manager_finalize    (GObject              *object);
113 static void     set_mouse_settings            (MsdMouseManager      *manager);
114 static void     set_tap_to_click_synaptics    (XDeviceInfo          *device_info,
115                                                gboolean              state,
116                                                gboolean              left_handed,
117                                                gint                  one_finger_tap,
118                                                gint                  two_finger_tap,
119                                                gint                  three_finger_tap);
120 
121 
122 G_DEFINE_TYPE_WITH_PRIVATE (MsdMouseManager, msd_mouse_manager, G_TYPE_OBJECT)
123 
124 static gpointer manager_object = NULL;
125 
126 static void
msd_mouse_manager_class_init(MsdMouseManagerClass * klass)127 msd_mouse_manager_class_init (MsdMouseManagerClass *klass)
128 {
129         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
130 
131         object_class->finalize = msd_mouse_manager_finalize;
132 }
133 
134 static void
configure_button_layout(guchar * buttons,gint n_buttons,gboolean left_handed)135 configure_button_layout (guchar   *buttons,
136                          gint      n_buttons,
137                          gboolean  left_handed)
138 {
139         const gint left_button = 1;
140         gint right_button;
141         gint i;
142 
143         /* if the button is higher than 2 (3rd button) then it's
144          * probably one direction of a scroll wheel or something else
145          * uninteresting
146          */
147         right_button = MIN (n_buttons, 3);
148 
149         /* If we change things we need to make sure we only swap buttons.
150          * If we end up with multiple physical buttons assigned to the same
151          * logical button the server will complain. This code assumes physical
152          * button 0 is the physical left mouse button, and that the physical
153          * button other than 0 currently assigned left_button or right_button
154          * is the physical right mouse button.
155          */
156 
157         /* check if the current mapping satisfies the above assumptions */
158         if (buttons[left_button - 1] != left_button &&
159             buttons[left_button - 1] != right_button)
160                 /* The current mapping is weird. Swapping buttons is probably not a
161                  * good idea.
162                  */
163                 return;
164 
165         /* check if we are left_handed and currently not swapped */
166         if (left_handed && buttons[left_button - 1] == left_button) {
167                 /* find the right button */
168                 for (i = 0; i < n_buttons; i++) {
169                         if (buttons[i] == right_button) {
170                                 buttons[i] = left_button;
171                                 break;
172                         }
173                 }
174                 /* swap the buttons */
175                 buttons[left_button - 1] = right_button;
176         }
177         /* check if we are not left_handed but are swapped */
178         else if (!left_handed && buttons[left_button - 1] == right_button) {
179                 /* find the right button */
180                 for (i = 0; i < n_buttons; i++) {
181                         if (buttons[i] == left_button) {
182                                 buttons[i] = right_button;
183                                 break;
184                         }
185                 }
186                 /* swap the buttons */
187                 buttons[left_button - 1] = left_button;
188         }
189 }
190 
191 static gboolean
xinput_device_has_buttons(XDeviceInfo * device_info)192 xinput_device_has_buttons (XDeviceInfo *device_info)
193 {
194         int i;
195         XAnyClassInfo *class_info;
196 
197         class_info = device_info->inputclassinfo;
198         for (i = 0; i < device_info->num_classes; i++) {
199                 if (class_info->class == ButtonClass) {
200                         XButtonInfo *button_info;
201 
202                         button_info = (XButtonInfo *) class_info;
203                         if (button_info->num_buttons > 0)
204                                 return TRUE;
205                 }
206 
207                 class_info = (XAnyClassInfo *) (((guchar *) class_info) +
208                                                 class_info->length);
209         }
210         return FALSE;
211 }
212 
213 static Atom
property_from_name(const char * property_name)214 property_from_name (const char *property_name)
215 {
216         return XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), property_name, True);
217 }
218 
219 static void *
get_property(XDevice * device,const gchar * property,Atom type,int format,gulong nitems)220 get_property (XDevice     *device,
221               const gchar *property,
222               Atom         type,
223               int          format,
224               gulong       nitems)
225 {
226         GdkDisplay *display;
227         gulong nitems_ret, bytes_after_ret;
228         int rc, format_ret;
229         Atom property_atom, type_ret;
230         guchar *data = NULL;
231 
232         property_atom = property_from_name (property);
233         if (!property_atom)
234                 return NULL;
235 
236         display = gdk_display_get_default ();
237 
238         gdk_x11_display_error_trap_push (display);
239 
240         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, property_atom,
241                                  0, 10, False, type, &type_ret, &format_ret,
242                                  &nitems_ret, &bytes_after_ret, &data);
243 
244         gdk_x11_display_error_trap_pop_ignored (display);
245 
246         if (rc == Success && type_ret == type && format_ret == format && nitems_ret >= nitems)
247                 return data;
248 
249         if (data)
250                 XFree (data);
251 
252         return NULL;
253 }
254 
255 static void
change_property(XDevice * device,const gchar * property,Atom type,int format,void * data,gulong nitems)256 change_property (XDevice     *device,
257                  const gchar *property,
258                  Atom         type,
259                  int          format,
260                  void        *data,
261                  gulong       nitems)
262 {
263         GdkDisplay *display;
264         Atom property_atom;
265         guchar *data_ret;
266 
267         property_atom = property_from_name (property);
268         if (!property_atom)
269                 return;
270 
271         data_ret = get_property (device, property, type, format, nitems);
272         if (!data_ret)
273                 return;
274 
275         display = gdk_display_get_default ();
276 
277         gdk_x11_display_error_trap_push (display);
278 
279         XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device,
280                                property_atom, type, format,
281                                PropModeReplace, data, nitems);
282 
283         gdk_x11_display_error_trap_pop_ignored (display);
284 
285         XFree (data_ret);
286 }
287 
288 static gboolean
touchpad_has_single_button(XDevice * device)289 touchpad_has_single_button (XDevice *device)
290 {
291         Atom type, prop;
292         GdkDisplay  *display;
293         int format;
294         unsigned long nitems, bytes_after;
295         unsigned char *data;
296         gboolean is_single_button = FALSE;
297         int rc;
298 
299         prop = property_from_name ("Synaptics Capabilities");
300         if (!prop)
301                 return FALSE;
302 
303         display = gdk_display_get_default ();
304         gdk_x11_display_error_trap_push (display);
305         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop, 0, 1, False,
306                                  XA_INTEGER, &type, &format, &nitems,
307                                  &bytes_after, &data);
308         if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3)
309                 is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0);
310 
311         if (rc == Success)
312                 XFree (data);
313 
314         gdk_x11_display_error_trap_pop_ignored (display);
315 
316         return is_single_button;
317 }
318 
319 static gboolean
property_exists_on_device(XDeviceInfo * device_info,const char * property_name)320 property_exists_on_device (XDeviceInfo *device_info,
321                            const char  *property_name)
322 {
323         XDevice *device;
324         int rc;
325         Atom type, prop;
326         GdkDisplay  *display;
327         int format;
328         unsigned long nitems, bytes_after;
329         unsigned char *data;
330 
331         prop = property_from_name (property_name);
332         if (!prop)
333                 return FALSE;
334 
335         display = gdk_display_get_default ();
336 
337         gdk_x11_display_error_trap_push (display);
338         device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
339         if ((gdk_x11_display_error_trap_pop (display) != 0) || (device == NULL))
340                 return FALSE;
341 
342         gdk_x11_display_error_trap_push (display);
343         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display),
344                                  device, prop, 0, 1, False, XA_INTEGER, &type, &format,
345                                  &nitems, &bytes_after, &data);
346 
347         if (rc == Success)
348                 XFree (data);
349 
350         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
351         gdk_x11_display_error_trap_pop_ignored (display);
352 
353         return rc == Success;
354 }
355 
356 static void
property_set_bool(XDeviceInfo * device_info,XDevice * device,const char * property_name,int property_index,gboolean enabled)357 property_set_bool (XDeviceInfo *device_info,
358                    XDevice     *device,
359                    const char  *property_name,
360                    int          property_index,
361                    gboolean     enabled)
362 {
363         int rc;
364         unsigned long nitems, bytes_after;
365         unsigned char *data;
366         int act_format;
367         Atom act_type, property;
368         GdkDisplay  *display;
369 
370         property = property_from_name (property_name);
371         if (!property)
372                 return;
373 
374         display = gdk_display_get_default ();
375 
376         gdk_x11_display_error_trap_push (display);
377         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device,
378                                  property, 0, 1, False,
379                                  XA_INTEGER, &act_type, &act_format, &nitems,
380                                  &bytes_after, &data);
381 
382         if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems > property_index) {
383                 data[property_index] = enabled ? 1 : 0;
384                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device,
385                                        property, XA_INTEGER, 8,
386                                        PropModeReplace, data, nitems);
387         }
388 
389         if (rc == Success)
390                 XFree (data);
391 
392         if (gdk_x11_display_error_trap_pop (display)) {
393                 g_warning ("Error while setting %s on \"%s\"", property_name, device_info->name);
394         }
395 }
396 
397 static void
touchpad_set_bool(XDeviceInfo * device_info,const char * property_name,int property_index,gboolean enabled)398 touchpad_set_bool (XDeviceInfo *device_info,
399                    const char  *property_name,
400                    int          property_index,
401                    gboolean     enabled)
402 {
403         XDevice    *device;
404         GdkDisplay *display;
405 
406         device = device_is_touchpad (device_info);
407         if (device == NULL) {
408                 return;
409         }
410 
411         property_set_bool (device_info, device, property_name, property_index, enabled);
412 
413         display = gdk_display_get_default ();
414 
415         gdk_x11_display_error_trap_push (display);
416         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
417         gdk_x11_display_error_trap_pop_ignored (display);
418 }
419 
420 static void
set_left_handed_legacy_driver(MsdMouseManager * manager,XDeviceInfo * device_info,gboolean mouse_left_handed,gboolean touchpad_left_handed)421 set_left_handed_legacy_driver (MsdMouseManager *manager,
422                                XDeviceInfo     *device_info,
423                                gboolean         mouse_left_handed,
424                                gboolean         touchpad_left_handed)
425 {
426         XDevice *device;
427         GdkDisplay *display;
428         guchar *buttons;
429         gsize buttons_capacity = 16;
430         gint n_buttons;
431         gboolean left_handed;
432 
433         if ((device_info->use == IsXPointer) ||
434             (device_info->use == IsXKeyboard) ||
435             (g_strcmp0 ("Virtual core XTEST pointer", device_info->name) == 0) ||
436             (!xinput_device_has_buttons (device_info)))
437                 return;
438 
439         /* If the device is a touchpad, swap tap buttons
440          * around too, otherwise a tap would be a right-click */
441         device = device_is_touchpad (device_info);
442         display = gdk_display_get_default ();
443 
444         if (device != NULL) {
445                 gboolean tap = g_settings_get_boolean (manager->priv->settings_touchpad, KEY_TOUCHPAD_TAP_TO_CLICK);
446                 gboolean single_button = touchpad_has_single_button (device);
447 
448                 left_handed = touchpad_left_handed;
449 
450                 if (tap && !single_button) {
451                         gint one_finger_tap = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_ONE_FINGER_TAP);
452                         gint two_finger_tap = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_TWO_FINGER_TAP);
453                         gint three_finger_tap = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_THREE_FINGER_TAP);
454                         set_tap_to_click_synaptics (device_info, tap, left_handed, one_finger_tap, two_finger_tap, three_finger_tap);
455                 }
456 
457                 XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
458 
459                 if (single_button)
460                         return;
461         } else {
462                 left_handed = mouse_left_handed;
463         }
464 
465         gdk_x11_display_error_trap_push (display);
466 
467         device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
468         if ((gdk_x11_display_error_trap_pop (display) != 0) ||
469             (device == NULL))
470                 return;
471 
472         buttons = g_new (guchar, buttons_capacity);
473 
474         n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (display), device,
475                                              buttons,
476                                              buttons_capacity);
477 
478         while (n_buttons > buttons_capacity) {
479                 buttons_capacity = n_buttons;
480                 buttons = (guchar *) g_realloc (buttons,
481                                                 buttons_capacity * sizeof (guchar));
482 
483                 n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (display), device,
484                                                      buttons,
485                                                      buttons_capacity);
486         }
487 
488         configure_button_layout (buttons, n_buttons, left_handed);
489 
490         XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (display), device, buttons, n_buttons);
491         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
492 
493         g_free (buttons);
494 }
495 
496 static void
set_left_handed_libinput(XDeviceInfo * device_info,gboolean mouse_left_handed,gboolean touchpad_left_handed)497 set_left_handed_libinput (XDeviceInfo *device_info,
498                           gboolean     mouse_left_handed,
499                           gboolean     touchpad_left_handed)
500 {
501         XDevice    *device;
502         GdkDisplay *display;
503         gboolean   want_lefthanded;
504 
505         device = device_is_touchpad (device_info);
506         display = gdk_display_get_default ();
507 
508         if (device == NULL) {
509                 gdk_x11_display_error_trap_push (display);
510                 device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
511                 if ((gdk_x11_display_error_trap_pop (display) != 0) || (device == NULL))
512                         return;
513 
514                 want_lefthanded = mouse_left_handed;
515         } else {
516                 /* touchpad device is already open after
517                  * return from device_is_touchpad function
518                  */
519                 want_lefthanded = touchpad_left_handed;
520         }
521 
522         property_set_bool (device_info, device, "libinput Left Handed Enabled", 0, want_lefthanded);
523 
524         gdk_x11_display_error_trap_push (display);
525         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
526           gdk_x11_display_error_trap_pop_ignored (display);
527 
528 }
529 
530 static void
set_left_handed(MsdMouseManager * manager,XDeviceInfo * device_info,gboolean mouse_left_handed,gboolean touchpad_left_handed)531 set_left_handed (MsdMouseManager *manager,
532                  XDeviceInfo     *device_info,
533                  gboolean         mouse_left_handed,
534                  gboolean         touchpad_left_handed)
535 {
536         if (property_exists_on_device (device_info, "libinput Left Handed Enabled"))
537                 set_left_handed_libinput (device_info, mouse_left_handed, touchpad_left_handed);
538         else
539                 set_left_handed_legacy_driver (manager, device_info, mouse_left_handed, touchpad_left_handed);
540 }
541 
542 static void
set_left_handed_all(MsdMouseManager * manager,gboolean mouse_left_handed,gboolean touchpad_left_handed)543 set_left_handed_all (MsdMouseManager *manager,
544                      gboolean         mouse_left_handed,
545                      gboolean         touchpad_left_handed)
546 {
547         XDeviceInfo *device_info;
548         gint n_devices;
549         gint i;
550 
551         device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
552 
553         for (i = 0; i < n_devices; i++) {
554                 set_left_handed (manager, &device_info[i], mouse_left_handed, touchpad_left_handed);
555         }
556 
557         if (device_info != NULL)
558                 XFreeDeviceList (device_info);
559 }
560 
561 static GdkFilterReturn
devicepresence_filter(GdkXEvent * xevent,GdkEvent * event,gpointer data)562 devicepresence_filter (GdkXEvent *xevent,
563                        GdkEvent  *event,
564                        gpointer   data)
565 {
566         XEvent *xev = (XEvent *) xevent;
567         G_GNUC_UNUSED XEventClass class_presence;
568         int xi_presence;
569 
570         DevicePresence (gdk_x11_get_default_xdisplay (), xi_presence, class_presence);
571 
572         if (xev->type == xi_presence)
573         {
574                 XDevicePresenceNotifyEvent *dpn = (XDevicePresenceNotifyEvent *) xev;
575                 if (dpn->devchange == DeviceEnabled)
576                         set_mouse_settings ((MsdMouseManager *) data);
577         }
578 
579         return GDK_FILTER_CONTINUE;
580 }
581 
582 static void
set_devicepresence_handler(MsdMouseManager * manager)583 set_devicepresence_handler (MsdMouseManager *manager)
584 {
585         GdkDisplay    *gdk_display;
586         Display       *display;
587         XEventClass    class_presence;
588         G_GNUC_UNUSED  int xi_presence;
589 
590         gdk_display = gdk_display_get_default ();
591         display = gdk_x11_get_default_xdisplay ();
592 
593         gdk_x11_display_error_trap_push (gdk_display);
594         DevicePresence (display, xi_presence, class_presence);
595         XSelectExtensionEvent (display,
596                                RootWindow (display, DefaultScreen (display)),
597                                &class_presence, 1);
598 
599         gdk_display_flush (gdk_display);
600         if (!gdk_x11_display_error_trap_pop (gdk_display))
601                 gdk_window_add_filter (NULL, devicepresence_filter, manager);
602 }
603 
604 static void
set_motion_legacy_driver(MsdMouseManager * manager,XDeviceInfo * device_info)605 set_motion_legacy_driver (MsdMouseManager *manager,
606                           XDeviceInfo     *device_info)
607 {
608         XDevice *device;
609         GdkDisplay *display;
610         XPtrFeedbackControl feedback;
611         XFeedbackState *states, *state;
612         gint num_feedbacks, i;
613         GSettings *settings;
614         gdouble motion_acceleration;
615         gint motion_threshold;
616         gint numerator, denominator;
617 
618         device = device_is_touchpad (device_info);
619         display = gdk_display_get_default ();
620 
621         if (device != NULL) {
622                 settings = manager->priv->settings_touchpad;
623         } else {
624                 gdk_x11_display_error_trap_push (display);
625                 device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
626                 if ((gdk_x11_display_error_trap_pop (display) != 0) || (device == NULL))
627                         return;
628 
629                 settings = manager->priv->settings_mouse;
630         }
631 
632         /* Calculate acceleration */
633         motion_acceleration = g_settings_get_double (settings, KEY_MOTION_ACCELERATION);
634         if (motion_acceleration >= 1.0) {
635                 /* we want to get the acceleration, with a resolution of 0.5
636                  */
637                 if ((motion_acceleration - floor (motion_acceleration)) < 0.25) {
638                         numerator = floor (motion_acceleration);
639                         denominator = 1;
640                 } else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) {
641                         numerator = ceil (2.0 * motion_acceleration);
642                         denominator = 2;
643                 } else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) {
644                         numerator = floor (2.0 *motion_acceleration);
645                         denominator = 2;
646                 } else {
647                         numerator = ceil (motion_acceleration);
648                         denominator = 1;
649                 }
650         } else if (motion_acceleration < 1.0 && motion_acceleration > 0) {
651                 /* This we do to 1/10ths */
652                 numerator = floor (motion_acceleration * 10) + 1;
653                 denominator= 10;
654         } else {
655                 numerator = -1;
656                 denominator = -1;
657         }
658 
659         /* And threshold */
660         motion_threshold = g_settings_get_int (settings, KEY_MOTION_THRESHOLD);
661 
662         /* Get the list of feedbacks for the device */
663         states = XGetFeedbackControl (GDK_DISPLAY_XDISPLAY (display), device, &num_feedbacks);
664         if (states == NULL) {
665                 XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
666                 return;
667         }
668 
669         state = (XFeedbackState *) states;
670         for (i = 0; i < num_feedbacks; i++) {
671                 if (state->class == PtrFeedbackClass) {
672                         /* And tell the device */
673                         feedback.class      = PtrFeedbackClass;
674                         feedback.length     = sizeof (XPtrFeedbackControl);
675                         feedback.id         = state->id;
676                         feedback.threshold  = motion_threshold;
677                         feedback.accelNum   = numerator;
678                         feedback.accelDenom = denominator;
679 
680                         g_debug ("Setting accel %d/%d, threshold %d for device '%s'",
681                                  numerator, denominator, motion_threshold, device_info->name);
682 
683                         XChangeFeedbackControl (GDK_DISPLAY_XDISPLAY (display),
684                                                 device,
685                                                 DvAccelNum | DvAccelDenom | DvThreshold,
686                                                 (XFeedbackControl *) &feedback);
687                         break;
688                 }
689 
690                 state = (XFeedbackState *) ((char *) state + state->length);
691         }
692 
693         XFreeFeedbackList (states);
694         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
695 }
696 
697 static void
set_motion_libinput(MsdMouseManager * manager,XDeviceInfo * device_info)698 set_motion_libinput (MsdMouseManager *manager,
699                      XDeviceInfo     *device_info)
700 {
701         XDevice *device;
702         GdkDisplay *display;
703         Atom prop;
704         Atom type;
705         Atom float_type;
706         int format, rc;
707         unsigned long nitems, bytes_after;
708         GSettings *settings;
709         union {
710                 unsigned char *c;
711                 long *l;
712         } data;
713         gfloat accel;
714         gfloat motion_acceleration;
715 
716         float_type = property_from_name ("FLOAT");
717         if (!float_type)
718                 return;
719 
720         prop = property_from_name ("libinput Accel Speed");
721         if (!prop) {
722                 return;
723         }
724 
725         device = device_is_touchpad (device_info);
726         display = gdk_display_get_default ();
727 
728         if (device != NULL) {
729                 settings = manager->priv->settings_touchpad;
730         } else {
731                 gdk_x11_display_error_trap_push (display);
732                 device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
733                 if ((gdk_x11_display_error_trap_pop (display) != 0) || (device == NULL))
734                         return;
735 
736                 settings = manager->priv->settings_mouse;
737         }
738 
739         /* Calculate acceleration */
740         motion_acceleration = g_settings_get_double (settings, KEY_MOTION_ACCELERATION);
741 
742         /* panel gives us a range of 1.0-10.0, map to libinput's [-1, 1]
743          *
744          * oldrange = (oldmax - oldmin)
745          * newrange = (newmax - newmin)
746          *
747          * mapped = (value - oldmin) * newrange / oldrange + oldmin
748          */
749 
750         if (motion_acceleration == -1.0) /* unset */
751                 accel = 0.0;
752         else
753                 accel = (motion_acceleration - 1.0) * 2.0 / 9.0 - 1;
754 
755         gdk_x11_display_error_trap_push (display);
756         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display),
757                                  device, prop, 0, 1, False, float_type, &type, &format,
758                                  &nitems, &bytes_after, &data.c);
759 
760         if (rc == Success && type == float_type && format == 32 && nitems >= 1) {
761                 *(float *) data.l = accel;
762                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display),
763                                        device, prop, float_type, 32, PropModeReplace, data.c, nitems);
764         }
765 
766         if (rc == Success) {
767                 XFree (data.c);
768         }
769 
770         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
771         if (gdk_x11_display_error_trap_pop (display)) {
772                 g_warning ("Error while setting accel speed on \"%s\"", device_info->name);
773         }
774 }
775 
776 static void
set_motion(MsdMouseManager * manager,XDeviceInfo * device_info)777 set_motion (MsdMouseManager *manager,
778             XDeviceInfo     *device_info)
779 {
780         if (property_exists_on_device (device_info, "libinput Accel Speed"))
781                 set_motion_libinput (manager, device_info);
782         else
783                 set_motion_legacy_driver (manager, device_info);
784 }
785 
786 static void
set_motion_all(MsdMouseManager * manager)787 set_motion_all (MsdMouseManager *manager)
788 {
789         XDeviceInfo *device_info;
790         gint n_devices;
791         gint i;
792 
793         device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
794 
795         for (i = 0; i < n_devices; i++) {
796                 set_motion (manager, &device_info[i]);
797         }
798 
799         if (device_info != NULL)
800                 XFreeDeviceList (device_info);
801 }
802 
803 static void
set_middle_button_evdev(XDeviceInfo * device_info,gboolean middle_button)804 set_middle_button_evdev (XDeviceInfo *device_info,
805                          gboolean     middle_button)
806 {
807         GdkDisplay *display;
808         XDevice *device;
809         Atom prop;
810         Atom type;
811         int format, rc;
812         unsigned long nitems, bytes_after;
813         unsigned char *data;
814 
815         prop = property_from_name ("Evdev Middle Button Emulation");
816 
817         if (!prop) /* no evdev devices */
818                 return;
819 
820         display = gdk_display_get_default ();
821 
822         gdk_x11_display_error_trap_push (display);
823 
824         device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
825         if ((gdk_x11_display_error_trap_pop (display) != 0) ||
826             (device == NULL))
827                 return;
828 
829         gdk_x11_display_error_trap_push (display);
830         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display),
831                                  device, prop, 0, 1, False, XA_INTEGER, &type, &format,
832                                  &nitems, &bytes_after, &data);
833 
834         if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) {
835                 data[0] = middle_button ? 1 : 0;
836                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display),
837                                        device, prop, type, format, PropModeReplace, data, nitems);
838         }
839 
840         if (rc == Success)
841                 XFree (data);
842 
843         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
844         if (gdk_x11_display_error_trap_pop (display)) {
845                 g_warning ("Error in setting middle button emulation on \"%s\"", device_info->name);
846         }
847 }
848 
849 static void
set_middle_button_libinput(XDeviceInfo * device_info,gboolean middle_button)850 set_middle_button_libinput (XDeviceInfo *device_info,
851                             gboolean     middle_button)
852 {
853         XDevice *device;
854         GdkDisplay *display;
855 
856         /* touchpad devices are excluded as the old code
857          * only applies to evdev devices
858          */
859         device = device_is_touchpad (device_info);
860         display = gdk_display_get_default ();
861 
862         if (device != NULL) {
863                 gdk_x11_display_error_trap_push (display);
864                 XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
865                 gdk_x11_display_error_trap_pop_ignored (display);
866                 return;
867         }
868 
869         gdk_x11_display_error_trap_push (display);
870         device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
871         if ((gdk_x11_display_error_trap_pop (display) != 0) || (device == NULL))
872                 return;
873 
874         property_set_bool (device_info, device, "libinput Middle Emulation Enabled", 0, middle_button);
875 
876         gdk_x11_display_error_trap_push (display);
877         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
878         gdk_x11_display_error_trap_pop_ignored (display);
879 }
880 
881 static void
set_middle_button(XDeviceInfo * device_info,gboolean middle_button)882 set_middle_button (XDeviceInfo *device_info,
883                    gboolean     middle_button)
884 {
885         if (property_from_name ("Evdev Middle Button Emulation"))
886                 set_middle_button_evdev (device_info, middle_button);
887 
888         if (property_from_name ("libinput Middle Emulation Enabled"))
889                 set_middle_button_libinput (device_info, middle_button);
890 }
891 
892 static void
set_middle_button_all(gboolean middle_button)893 set_middle_button_all (gboolean middle_button)
894 {
895         XDeviceInfo *device_info;
896         gint n_devices;
897         gint i;
898 
899         device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
900 
901         for (i = 0; i < n_devices; i++) {
902                 set_middle_button (&device_info[i], middle_button);
903         }
904 
905         if (device_info != NULL)
906                 XFreeDeviceList (device_info);
907 }
908 
909 static gboolean
have_program_in_path(const char * name)910 have_program_in_path (const char *name)
911 {
912         gchar *path;
913         gboolean result;
914 
915         path = g_find_program_in_path (name);
916         result = (path != NULL);
917         g_free (path);
918         return result;
919 }
920 
921 static void
set_disable_w_typing_synaptics(MsdMouseManager * manager,gboolean state)922 set_disable_w_typing_synaptics (MsdMouseManager *manager,
923                                 gboolean         state)
924 {
925         if (state && touchpad_is_present ()) {
926                 GError *error = NULL;
927                 char *args[6];
928 
929                 if (manager->priv->syndaemon_spawned)
930                         return;
931 
932                 args[0] = "syndaemon";
933                 args[1] = "-i";
934                 args[2] = "0.5";
935                 args[3] = "-K";
936                 args[4] = "-R";
937                 args[5] = NULL;
938 
939                 if (!have_program_in_path (args[0]))
940                         return;
941 
942                 g_spawn_async (g_get_home_dir (), args, NULL,
943                                 G_SPAWN_SEARCH_PATH, NULL, NULL,
944                                 &manager->priv->syndaemon_pid, &error);
945 
946                 manager->priv->syndaemon_spawned = (error == NULL);
947 
948                 if (error) {
949                         g_settings_set_boolean (manager->priv->settings_touchpad, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE);
950                         g_error_free (error);
951                 }
952 
953         } else if (manager->priv->syndaemon_spawned)
954         {
955                 kill (manager->priv->syndaemon_pid, SIGHUP);
956                 g_spawn_close_pid (manager->priv->syndaemon_pid);
957                 manager->priv->syndaemon_spawned = FALSE;
958         }
959 }
960 
961 static void
set_disable_w_typing_libinput(MsdMouseManager * manager,gboolean state)962 set_disable_w_typing_libinput (MsdMouseManager *manager,
963                                gboolean         state)
964 {
965         XDeviceInfo *device_info;
966         gint n_devices;
967         gint i;
968 
969         /* This is only called once for synaptics but for libinput
970          * we need to loop through the list of devices
971          */
972         device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
973 
974         for (i = 0; i < n_devices; i++) {
975                 touchpad_set_bool (&device_info[i], "libinput Disable While Typing Enabled", 0, state);
976         }
977 
978         if (device_info != NULL)
979                 XFreeDeviceList (device_info);
980 }
981 
982 static void
set_disable_w_typing(MsdMouseManager * manager,gboolean state)983 set_disable_w_typing (MsdMouseManager *manager,
984                       gboolean         state)
985 {
986         if (property_from_name ("Synaptics Off"))
987                 set_disable_w_typing_synaptics (manager, state);
988 
989         if (property_from_name ("libinput Disable While Typing Enabled"))
990                 set_disable_w_typing_libinput (manager, state);
991 }
992 
993 static void
set_accel_profile_libinput(MsdMouseManager * manager,XDeviceInfo * device_info)994 set_accel_profile_libinput (MsdMouseManager *manager,
995                             XDeviceInfo     *device_info)
996 {
997         XDevice *device;
998         GdkDisplay *display;
999         GSettings *settings;
1000         guchar *available, *defaults, *values;
1001 
1002         display = gdk_display_get_default ();
1003 
1004         device = device_is_touchpad (device_info);
1005 
1006         if (device != NULL) {
1007                 settings = manager->priv->settings_touchpad;
1008         } else {
1009                 gdk_x11_display_error_trap_push (display);
1010                 device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), device_info->id);
1011                 if ((gdk_x11_display_error_trap_pop (display) != 0) || (device == NULL))
1012                         return;
1013 
1014                 settings = manager->priv->settings_mouse;
1015         }
1016 
1017         available = get_property (device, "libinput Accel Profiles Available", XA_INTEGER, 8, 2);
1018         if (!available)
1019                 return;
1020         XFree (available);
1021 
1022         defaults = get_property (device, "libinput Accel Profile Enabled Default", XA_INTEGER, 8, 2);
1023         if (!defaults)
1024                 return;
1025 
1026         values = get_property (device, "libinput Accel Profile Enabled", XA_INTEGER, 8, 2);
1027         if (!values) {
1028                 XFree (defaults);
1029                 return;
1030         }
1031 
1032         /* 2 boolean values (8 bit, 0 or 1), in order "adaptive", "flat". */
1033         switch (g_settings_get_enum (settings, KEY_ACCEL_PROFILE)) {
1034                 case ACCEL_PROFILE_ADAPTIVE:
1035                         values[0] = 1; /* enable adaptive */
1036                         values[1] = 0; /* disable flat */
1037                         break;
1038                 case ACCEL_PROFILE_FLAT:
1039                         values[0] = 0; /* disable adaptive */
1040                         values[1] = 1; /* enable flat */
1041                         break;
1042                 case ACCEL_PROFILE_DEFAULT:
1043                 default:
1044                         values[0] = defaults[0];
1045                         values[1] = defaults[1];
1046                         break;
1047         }
1048 
1049         change_property (device, "libinput Accel Profile Enabled", XA_INTEGER, 8, values, 2);
1050 
1051         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
1052 
1053         XFree (defaults);
1054         XFree (values);
1055 }
1056 
1057 static void
set_accel_profile(MsdMouseManager * manager,XDeviceInfo * device_info)1058 set_accel_profile (MsdMouseManager *manager,
1059                    XDeviceInfo     *device_info)
1060 {
1061         if (property_exists_on_device (device_info, "libinput Accel Profile Enabled"))
1062                 set_accel_profile_libinput (manager, device_info);
1063 
1064         /* TODO: Add acceleration profiles for synaptics/legacy drivers */
1065 }
1066 
1067 static void
set_accel_profile_all(MsdMouseManager * manager)1068 set_accel_profile_all (MsdMouseManager *manager)
1069 {
1070         int numdevices, i;
1071         XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices);
1072 
1073         if (devicelist == NULL)
1074                 return;
1075 
1076         for (i = 0; i < numdevices; i++) {
1077                 set_accel_profile (manager, &devicelist[i]);
1078         }
1079 
1080         XFreeDeviceList (devicelist);
1081 }
1082 
1083 static gboolean
get_touchpad_handedness(MsdMouseManager * manager,gboolean mouse_left_handed)1084 get_touchpad_handedness (MsdMouseManager *manager,
1085                          gboolean         mouse_left_handed)
1086 {
1087         switch (g_settings_get_enum (manager->priv->settings_touchpad, KEY_LEFT_HANDED)) {
1088         case TOUCHPAD_HANDEDNESS_RIGHT:
1089                 return FALSE;
1090         case TOUCHPAD_HANDEDNESS_LEFT:
1091                 return TRUE;
1092         case TOUCHPAD_HANDEDNESS_MOUSE:
1093                 return mouse_left_handed;
1094         default:
1095                 g_assert_not_reached ();
1096         }
1097 }
1098 
1099 static void
set_tap_to_click_synaptics(XDeviceInfo * device_info,gboolean state,gboolean left_handed,gint one_finger_tap,gint two_finger_tap,gint three_finger_tap)1100 set_tap_to_click_synaptics (XDeviceInfo *device_info,
1101                             gboolean     state,
1102                             gboolean     left_handed,
1103                             gint         one_finger_tap,
1104                             gint         two_finger_tap,
1105                             gint         three_finger_tap)
1106 {
1107         XDevice *device;
1108         GdkDisplay *display;
1109         int format, rc;
1110         unsigned long nitems, bytes_after;
1111         unsigned char* data;
1112         Atom prop, type;
1113 
1114         prop = property_from_name ("Synaptics Tap Action");
1115 
1116         if (!prop)
1117                 return;
1118 
1119         device = device_is_touchpad (device_info);
1120         if (device == NULL) {
1121                 return;
1122         }
1123 
1124         display = gdk_display_get_default ();
1125 
1126         gdk_x11_display_error_trap_push (display);
1127         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop, 0, 2,
1128                                  False, XA_INTEGER, &type, &format, &nitems,
1129                                  &bytes_after, &data);
1130 
1131         if (one_finger_tap > 3 || one_finger_tap < 1)
1132                 one_finger_tap = 1;
1133         if (two_finger_tap > 3 || two_finger_tap < 1)
1134                 two_finger_tap = 3;
1135         if (three_finger_tap > 3 || three_finger_tap < 1)
1136                 three_finger_tap = 2;
1137 
1138         if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7)
1139         {
1140                 /* Set RLM mapping for 1/2/3 fingers*/
1141                 data[4] = (state) ? ((left_handed) ? (4-one_finger_tap) : one_finger_tap) : 0;
1142                 data[5] = (state) ? ((left_handed) ? (4-two_finger_tap) : two_finger_tap) : 0;
1143                 data[6] = (state) ? three_finger_tap : 0;
1144                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop, XA_INTEGER, 8,
1145                                        PropModeReplace, data, nitems);
1146         }
1147 
1148         if (rc == Success)
1149                 XFree (data);
1150 
1151         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
1152         if (gdk_x11_display_error_trap_pop (display)) {
1153                 g_warning ("Error in setting tap to click on \"%s\"", device_info->name);
1154         }
1155 }
1156 
1157 static void
set_tap_to_click_libinput(XDeviceInfo * device_info,gboolean state)1158 set_tap_to_click_libinput (XDeviceInfo *device_info,
1159                            gboolean     state)
1160 {
1161         touchpad_set_bool (device_info, "libinput Tapping Enabled", 0, state);
1162 }
1163 
1164 static void
set_tap_to_click(XDeviceInfo * device_info,gboolean state,gboolean left_handed,gint one_finger_tap,gint two_finger_tap,gint three_finger_tap)1165 set_tap_to_click (XDeviceInfo *device_info,
1166                   gboolean     state,
1167                   gboolean     left_handed,
1168                   gint         one_finger_tap,
1169                   gint         two_finger_tap,
1170                   gint         three_finger_tap)
1171 {
1172         if (property_from_name ("Synaptics Tap Action"))
1173                 set_tap_to_click_synaptics (device_info, state, left_handed,
1174                                             one_finger_tap, two_finger_tap, three_finger_tap);
1175 
1176         if (property_from_name ("libinput Tapping Enabled"))
1177                 set_tap_to_click_libinput (device_info, state);
1178 }
1179 
1180 static void
set_tap_to_click_all(MsdMouseManager * manager)1181 set_tap_to_click_all (MsdMouseManager *manager)
1182 {
1183         int numdevices, i;
1184         XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices);
1185 
1186         if (devicelist == NULL)
1187                 return;
1188 
1189         gboolean state = g_settings_get_boolean (manager->priv->settings_touchpad, KEY_TOUCHPAD_TAP_TO_CLICK);
1190         gboolean left_handed = get_touchpad_handedness (manager, g_settings_get_boolean (manager->priv->settings_mouse, KEY_LEFT_HANDED));
1191         gint one_finger_tap = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_ONE_FINGER_TAP);
1192         gint two_finger_tap = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_TWO_FINGER_TAP);
1193         gint three_finger_tap = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_THREE_FINGER_TAP);
1194 
1195         for (i = 0; i < numdevices; i++) {
1196                 set_tap_to_click (&devicelist[i], state, left_handed, one_finger_tap, two_finger_tap, three_finger_tap);
1197         }
1198 
1199         XFreeDeviceList (devicelist);
1200 }
1201 
1202 static void
set_click_actions_synaptics(XDeviceInfo * device_info,gint enable_two_finger_click,gint enable_three_finger_click)1203 set_click_actions_synaptics (XDeviceInfo *device_info,
1204                              gint         enable_two_finger_click,
1205                              gint         enable_three_finger_click)
1206 {
1207         XDevice *device;
1208         int format, rc;
1209         unsigned long nitems, bytes_after;
1210         unsigned char* data;
1211         Atom prop, type;
1212         GdkDisplay *display;
1213 
1214         prop = property_from_name ("Synaptics Click Action");
1215         if (!prop)
1216                 return;
1217 
1218         device = device_is_touchpad (device_info);
1219         if (device == NULL) {
1220                 return;
1221         }
1222 
1223         g_debug ("setting click action to click on %s", device_info->name);
1224 
1225         display = gdk_display_get_default ();
1226 
1227         gdk_x11_display_error_trap_push (display);
1228         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop, 0, 2,
1229                                  False, XA_INTEGER, &type, &format, &nitems,
1230                                  &bytes_after, &data);
1231 
1232         if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) {
1233                 data[0] = 1;
1234                 data[1] = enable_two_finger_click;
1235                 data[2] = enable_three_finger_click;
1236                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop,
1237                                        XA_INTEGER, 8, PropModeReplace, data, nitems);
1238         }
1239 
1240         if (rc == Success)
1241                 XFree (data);
1242 
1243         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
1244         if (gdk_x11_display_error_trap_pop (display)) {
1245                 g_warning ("Error in setting click actions on \"%s\"", device_info->name);
1246         }
1247 }
1248 
1249 static void
set_click_actions_libinput(XDeviceInfo * device_info,gint enable_two_finger_click,gint enable_three_finger_click)1250 set_click_actions_libinput (XDeviceInfo *device_info,
1251                             gint         enable_two_finger_click,
1252                             gint         enable_three_finger_click)
1253 {
1254         XDevice *device;
1255         int format, rc;
1256         unsigned long nitems, bytes_after;
1257         unsigned char *data;
1258         Atom prop, type;
1259         gboolean want_clickfinger;
1260         gboolean want_softwarebuttons;
1261         GdkDisplay *display;
1262 
1263         prop = property_from_name ("libinput Click Method Enabled");
1264         if (!prop)
1265                 return;
1266 
1267         device = device_is_touchpad (device_info);
1268         if (device == NULL) {
1269                 return;
1270         }
1271 
1272         g_debug ("setting click action to click on %s", device_info->name);
1273 
1274         want_clickfinger = enable_two_finger_click || enable_three_finger_click;
1275         want_softwarebuttons = !want_clickfinger;
1276 
1277         display = gdk_display_get_default ();
1278 
1279         gdk_x11_display_error_trap_push (display);
1280         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop, 0, 2,
1281                                  False, XA_INTEGER, &type, &format, &nitems,
1282                                  &bytes_after, &data);
1283 
1284         if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 2) {
1285                 data[0] = want_softwarebuttons;
1286                 data[1] = want_clickfinger;
1287                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop,
1288                                        XA_INTEGER, 8, PropModeReplace, data, nitems);
1289         }
1290 
1291         if (rc == Success)
1292                 XFree (data);
1293 
1294         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
1295         if (gdk_x11_display_error_trap_pop (display)) {
1296                 g_warning ("Error in setting click actions on \"%s\"", device_info->name);
1297         }
1298 }
1299 
1300 static void
set_click_actions(XDeviceInfo * device_info,gint enable_two_finger_click,gint enable_three_finger_click)1301 set_click_actions (XDeviceInfo *device_info,
1302                    gint         enable_two_finger_click,
1303                    gint         enable_three_finger_click)
1304 {
1305         if (property_from_name ("Synaptics Click Action"))
1306                 set_click_actions_synaptics (device_info, enable_two_finger_click, enable_three_finger_click);
1307 
1308         if (property_from_name ("libinput Click Method Enabled"))
1309                 set_click_actions_libinput (device_info, enable_two_finger_click, enable_three_finger_click);
1310 }
1311 
1312 static void
set_click_actions_all(MsdMouseManager * manager)1313 set_click_actions_all (MsdMouseManager *manager)
1314 {
1315         int numdevices, i;
1316         XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices);
1317 
1318         if (devicelist == NULL)
1319                 return;
1320 
1321         gint enable_two_finger_click = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_TWO_FINGER_CLICK);
1322         gint enable_three_finger_click = g_settings_get_int (manager->priv->settings_touchpad, KEY_TOUCHPAD_THREE_FINGER_CLICK);
1323 
1324         for (i = 0; i < numdevices; i++) {
1325                 set_click_actions (&devicelist[i], enable_two_finger_click, enable_three_finger_click);
1326         }
1327 
1328         XFreeDeviceList (devicelist);
1329 }
1330 
1331 static void
set_natural_scroll_synaptics(XDeviceInfo * device_info,gboolean natural_scroll)1332 set_natural_scroll_synaptics (XDeviceInfo *device_info,
1333                               gboolean     natural_scroll)
1334 {
1335         XDevice *device;
1336         int format, rc;
1337         unsigned long nitems, bytes_after;
1338         unsigned char* data;
1339         glong *ptr;
1340         Atom prop, type;
1341         GdkDisplay *display;
1342 
1343         prop = property_from_name ("Synaptics Scrolling Distance");
1344         if (!prop)
1345                 return;
1346 
1347         device = device_is_touchpad (device_info);
1348         if (device == NULL) {
1349                 return;
1350         }
1351 
1352         g_debug ("Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", device_info->name);
1353 
1354         display = gdk_display_get_default ();
1355 
1356         gdk_x11_display_error_trap_push (display);
1357         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop, 0, 2,
1358                                  False, XA_INTEGER, &type, &format, &nitems,
1359                                  &bytes_after, &data);
1360 
1361         if (rc == Success && type == XA_INTEGER && format == 32 && nitems >= 2) {
1362                 ptr = (glong *) data;
1363                 if (natural_scroll) {
1364                         ptr[0] = -labs(ptr[0]);
1365                         ptr[1] = -labs(ptr[1]);
1366                 } else {
1367                         ptr[0] = labs(ptr[0]);
1368                         ptr[1] = labs(ptr[1]);
1369                 }
1370 
1371                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop,
1372                                        XA_INTEGER, 32, PropModeReplace, data, nitems);
1373         }
1374 
1375         if (rc == Success)
1376                 XFree (data);
1377 
1378         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
1379         if (gdk_x11_display_error_trap_pop (display)) {
1380                 g_warning ("Error in setting natural scroll on \"%s\"", device_info->name);
1381         }
1382 }
1383 
1384 static void
set_natural_scroll_libinput(XDeviceInfo * device_info,gboolean natural_scroll)1385 set_natural_scroll_libinput (XDeviceInfo *device_info,
1386                              gboolean     natural_scroll)
1387 {
1388         g_debug ("Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", device_info->name);
1389 
1390         touchpad_set_bool (device_info, "libinput Natural Scrolling Enabled", 0, natural_scroll);
1391 }
1392 
1393 static void
set_natural_scroll(XDeviceInfo * device_info,gboolean natural_scroll)1394 set_natural_scroll (XDeviceInfo *device_info,
1395                     gboolean     natural_scroll)
1396 {
1397         if (property_from_name ("Synaptics Scrolling Distance"))
1398                 set_natural_scroll_synaptics (device_info, natural_scroll);
1399 
1400         if (property_from_name ("libinput Natural Scrolling Enabled"))
1401                 set_natural_scroll_libinput (device_info, natural_scroll);
1402 }
1403 
1404 static void
set_natural_scroll_all(MsdMouseManager * manager)1405 set_natural_scroll_all (MsdMouseManager *manager)
1406 {
1407         int numdevices, i;
1408         XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices);
1409 
1410         if (devicelist == NULL)
1411                 return;
1412 
1413         gboolean natural_scroll = g_settings_get_boolean (manager->priv->settings_touchpad, KEY_TOUCHPAD_NATURAL_SCROLL);
1414 
1415         for (i = 0; i < numdevices; i++) {
1416                 set_natural_scroll (&devicelist[i], natural_scroll);
1417         }
1418 
1419         XFreeDeviceList (devicelist);
1420 }
1421 
1422 static void
set_scrolling_synaptics(XDeviceInfo * device_info,GSettings * settings)1423 set_scrolling_synaptics (XDeviceInfo *device_info,
1424                          GSettings   *settings)
1425 {
1426         touchpad_set_bool (device_info, "Synaptics Edge Scrolling", 0, g_settings_get_boolean (settings, KEY_VERT_EDGE_SCROLL));
1427         touchpad_set_bool (device_info, "Synaptics Edge Scrolling", 1, g_settings_get_boolean (settings, KEY_HORIZ_EDGE_SCROLL));
1428         touchpad_set_bool (device_info, "Synaptics Two-Finger Scrolling", 0, g_settings_get_boolean (settings, KEY_VERT_TWO_FINGER_SCROLL));
1429         touchpad_set_bool (device_info, "Synaptics Two-Finger Scrolling", 1, g_settings_get_boolean (settings, KEY_HORIZ_TWO_FINGER_SCROLL));
1430 }
1431 
1432 static void
set_scrolling_libinput(XDeviceInfo * device_info,GSettings * settings)1433 set_scrolling_libinput (XDeviceInfo *device_info,
1434                         GSettings   *settings)
1435 {
1436         XDevice *device;
1437         int format, rc;
1438         unsigned long nitems, bytes_after;
1439         unsigned char *data;
1440         Atom prop, type;
1441         gboolean want_edge, want_2fg;
1442         GdkDisplay *display;
1443         gboolean want_horiz;
1444 
1445         prop = property_from_name ("libinput Scroll Method Enabled");
1446         if (!prop)
1447                 return;
1448 
1449         device = device_is_touchpad (device_info);
1450         if (device == NULL) {
1451                 return;
1452         }
1453 
1454         want_2fg = g_settings_get_boolean (settings, KEY_VERT_TWO_FINGER_SCROLL);
1455         want_edge = g_settings_get_boolean (settings, KEY_VERT_EDGE_SCROLL);
1456 
1457         /* libinput only allows for one scroll method at a time.
1458          * If both are set, pick 2fg scrolling.
1459          */
1460         if (want_2fg)
1461                 want_edge = FALSE;
1462 
1463         g_debug ("setting scroll method on %s", device_info->name);
1464 
1465         display = gdk_display_get_default ();
1466 
1467         gdk_x11_display_error_trap_push (display);
1468         rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device, prop, 0, 2,
1469                                  False, XA_INTEGER, &type, &format, &nitems,
1470                                  &bytes_after, &data);
1471 
1472         if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) {
1473                 data[0] = want_2fg;
1474                 data[1] = want_edge;
1475                 XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device,
1476                                        prop, XA_INTEGER, 8, PropModeReplace, data, nitems);
1477         }
1478 
1479         if (rc == Success)
1480                 XFree (data);
1481 
1482         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
1483         if (gdk_x11_display_error_trap_pop (display)) {
1484                 g_warning ("Error in setting scroll method on \"%s\"", device_info->name);
1485         }
1486 
1487         /* Horizontal scrolling is handled by xf86-input-libinput and
1488          * there's only one bool. Pick the one matching the scroll method
1489          * we picked above.
1490          */
1491         if (want_2fg)
1492                 want_horiz = g_settings_get_boolean (settings, KEY_HORIZ_TWO_FINGER_SCROLL);
1493         else if (want_edge)
1494                 want_horiz = g_settings_get_boolean (settings, KEY_HORIZ_EDGE_SCROLL);
1495         else
1496                 return;
1497 
1498         touchpad_set_bool (device_info, "libinput Horizontal Scroll Enabled", 0, want_horiz);
1499 }
1500 
1501 static void
set_scrolling(XDeviceInfo * device_info,GSettings * settings)1502 set_scrolling (XDeviceInfo *device_info,
1503                GSettings   *settings)
1504 {
1505         if (property_from_name ("Synaptics Edge Scrolling"))
1506                 set_scrolling_synaptics (device_info, settings);
1507 
1508         if (property_from_name ("libinput Scroll Method Enabled"))
1509                 set_scrolling_libinput (device_info, settings);
1510 }
1511 
1512 static void
set_scrolling_all(GSettings * settings)1513 set_scrolling_all (GSettings *settings)
1514 {
1515         int numdevices, i;
1516         XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices);
1517 
1518         if (devicelist == NULL)
1519                 return;
1520 
1521         for (i = 0; i < numdevices; i++) {
1522                 set_scrolling (&devicelist[i], settings);
1523         }
1524 
1525         XFreeDeviceList (devicelist);
1526 }
1527 
1528 static void
set_touchpad_enabled(XDeviceInfo * device_info,gboolean state)1529 set_touchpad_enabled (XDeviceInfo *device_info,
1530                       gboolean     state)
1531 {
1532         XDevice *device;
1533         Atom prop_enabled;
1534         GdkDisplay *display;
1535         unsigned char data = state;
1536 
1537         prop_enabled = property_from_name ("Device Enabled");
1538         if (!prop_enabled)
1539                 return;
1540 
1541         device = device_is_touchpad (device_info);
1542         if (device == NULL) {
1543                 return;
1544         }
1545 
1546         display = gdk_display_get_default ();
1547 
1548         gdk_x11_display_error_trap_push (display);
1549         XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (display), device,
1550                                prop_enabled, XA_INTEGER, 8,
1551                                PropModeReplace, &data, 1);
1552 
1553         XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device);
1554         gdk_display_flush (display);
1555         if (gdk_x11_display_error_trap_pop (display)) {
1556                 g_warning ("Error %s device \"%s\"",
1557                            (state) ? "enabling" : "disabling",
1558                            device_info->name);
1559         }
1560 }
1561 
1562 static void
set_touchpad_enabled_all(gboolean state)1563 set_touchpad_enabled_all (gboolean state)
1564 {
1565         int numdevices, i;
1566         XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices);
1567 
1568         if (devicelist == NULL)
1569                 return;
1570 
1571         for (i = 0; i < numdevices; i++) {
1572                 set_touchpad_enabled (&devicelist[i], state);
1573         }
1574 
1575         XFreeDeviceList (devicelist);
1576 }
1577 
1578 static void
set_locate_pointer(MsdMouseManager * manager,gboolean state)1579 set_locate_pointer (MsdMouseManager *manager,
1580                     gboolean         state)
1581 {
1582         if (state) {
1583                 GError *error = NULL;
1584                 char *args[2];
1585 
1586                 if (manager->priv->locate_pointer_spawned)
1587                         return;
1588 
1589                 args[0] = LIBEXECDIR "/msd-locate-pointer";
1590                 args[1] = NULL;
1591 
1592                 g_spawn_async (NULL, args, NULL,
1593                                0, NULL, NULL,
1594                                &manager->priv->locate_pointer_pid, &error);
1595 
1596                 manager->priv->locate_pointer_spawned = (error == NULL);
1597 
1598                 if (error) {
1599                         g_settings_set_boolean (manager->priv->settings_mouse, KEY_MOUSE_LOCATE_POINTER, FALSE);
1600                         g_error_free (error);
1601                 }
1602 
1603         }
1604         else if (manager->priv->locate_pointer_spawned) {
1605                 kill (manager->priv->locate_pointer_pid, SIGHUP);
1606                 g_spawn_close_pid (manager->priv->locate_pointer_pid);
1607                 manager->priv->locate_pointer_spawned = FALSE;
1608         }
1609 }
1610 
1611 #if 0   /* FIXME need to fork (?) mousetweaks for this to work */
1612 static void
1613 set_mousetweaks_daemon (MsdMouseManager *manager,
1614                         gboolean         dwell_enable,
1615                         gboolean         delay_enable)
1616 {
1617         GError *error = NULL;
1618         gchar *comm;
1619         gboolean run_daemon = dwell_enable || delay_enable;
1620 
1621         if (run_daemon || manager->priv->mousetweaks_daemon_running)
1622                 comm = g_strdup_printf ("mousetweaks %s",
1623                                         run_daemon ? "" : "-s");
1624         else
1625                 return;
1626 
1627         if (run_daemon)
1628                 manager->priv->mousetweaks_daemon_running = TRUE;
1629 
1630 
1631         if (! g_spawn_command_line_async (comm, &error)) {
1632                 if (error->code == G_SPAWN_ERROR_NOENT &&
1633                     (dwell_enable || delay_enable)) {
1634                         GtkWidget *dialog;
1635 
1636                         GSettings *settings;
1637                         settings = g_settings_new (MATE_MOUSE_A11Y_SCHEMA);
1638                         if (dwell_enable)
1639                                 g_settings_set_boolean (settings,
1640                                                         MATE_MOUSE_A11Y_KEY_DWELL_ENABLE,
1641                                                         FALSE);
1642                         else if (delay_enable)
1643                                 g_settings_set_boolean (settings,
1644                                                         MATE_MOUSE_A11Y_KEY_DELAY_ENABLE,
1645                                                         FALSE);
1646                         g_object_unref (settings);
1647 
1648                         dialog = gtk_message_dialog_new (NULL, 0,
1649                                                          GTK_MESSAGE_WARNING,
1650                                                          GTK_BUTTONS_OK,
1651                                                          _("Could not enable mouse accessibility features"));
1652                         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1653                                                                   _("Mouse accessibility requires Mousetweaks "
1654                                                                     "to be installed on your system."));
1655                         gtk_window_set_title (GTK_WINDOW (dialog),
1656                                               _("Mouse Preferences"));
1657                         gtk_window_set_icon_name (GTK_WINDOW (dialog),
1658                                                   "input-mouse");
1659                         gtk_dialog_run (GTK_DIALOG (dialog));
1660                         gtk_widget_destroy (dialog);
1661                 }
1662                 g_error_free (error);
1663         }
1664         g_free (comm);
1665 }
1666 #endif  /* set_mousetweaks_daemon */
1667 
1668 static void
set_mouse_settings(MsdMouseManager * manager)1669 set_mouse_settings (MsdMouseManager *manager)
1670 {
1671         gboolean mouse_left_handed = g_settings_get_boolean (manager->priv->settings_mouse, KEY_LEFT_HANDED);
1672         gboolean touchpad_left_handed = get_touchpad_handedness (manager, mouse_left_handed);
1673         set_left_handed_all (manager, mouse_left_handed, touchpad_left_handed);
1674 
1675         set_motion_all (manager);
1676         set_middle_button_all (g_settings_get_boolean (manager->priv->settings_mouse, KEY_MIDDLE_BUTTON_EMULATION));
1677 
1678         set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->settings_touchpad, KEY_TOUCHPAD_DISABLE_W_TYPING));
1679 
1680         set_tap_to_click_all (manager);
1681         set_click_actions_all (manager);
1682         set_scrolling_all (manager->priv->settings_touchpad);
1683         set_natural_scroll_all (manager);
1684         set_touchpad_enabled_all (g_settings_get_boolean (manager->priv->settings_touchpad, KEY_TOUCHPAD_ENABLED));
1685         set_accel_profile_all (manager);
1686 }
1687 
1688 static void
mouse_callback(GSettings * settings,const gchar * key,MsdMouseManager * manager)1689 mouse_callback (GSettings          *settings,
1690                 const gchar        *key,
1691                 MsdMouseManager    *manager)
1692 {
1693         if (g_strcmp0 (key, KEY_LEFT_HANDED) == 0) {
1694                 gboolean mouse_left_handed = g_settings_get_boolean (settings, key);
1695                 gboolean touchpad_left_handed = get_touchpad_handedness (manager, mouse_left_handed);
1696                 set_left_handed_all (manager, mouse_left_handed, touchpad_left_handed);
1697         } else if ((g_strcmp0 (key, KEY_MOTION_ACCELERATION) == 0)
1698                 || (g_strcmp0 (key, KEY_MOTION_THRESHOLD) == 0)) {
1699                 set_motion_all (manager);
1700         } else if (g_strcmp0 (key, KEY_ACCEL_PROFILE) == 0) {
1701                 set_accel_profile_all (manager);
1702         } else if (g_strcmp0 (key, KEY_MIDDLE_BUTTON_EMULATION) == 0) {
1703                 set_middle_button_all (g_settings_get_boolean (settings, key));
1704         } else if (g_strcmp0 (key, KEY_MOUSE_LOCATE_POINTER) == 0) {
1705                 set_locate_pointer (manager, g_settings_get_boolean (settings, key));
1706 #if 0   /* FIXME need to fork (?) mousetweaks for this to work */
1707         } else if (g_strcmp0 (key, KEY_MOUSE_A11Y_DWELL_ENABLE) == 0) {
1708                 set_mousetweaks_daemon (manager,
1709                                         g_settings_get_boolean (settings, key),
1710                                         g_settings_get_boolean (settings, KEY_MOUSE_A11Y_DELAY_ENABLE, NULL));
1711                 }
1712         } else if (g_strcmp0 (key, KEY_MOUSE_A11Y_DELAY_ENABLE) == 0) {
1713                 set_mousetweaks_daemon (manager,
1714                                         g_settings_get_boolean (settings, KEY_MOUSE_A11Y_DWELL_ENABLE, NULL),
1715                                         g_settings_get_boolean (settings, key));
1716 #endif
1717         }
1718 }
1719 
1720 static void
touchpad_callback(GSettings * settings,const gchar * key,MsdMouseManager * manager)1721 touchpad_callback (GSettings          *settings,
1722                    const gchar        *key,
1723                    MsdMouseManager    *manager)
1724 {
1725         if (g_strcmp0 (key, KEY_TOUCHPAD_DISABLE_W_TYPING) == 0) {
1726                 set_disable_w_typing (manager, g_settings_get_boolean (settings, key));
1727         } else if (g_strcmp0 (key, KEY_LEFT_HANDED) == 0) {
1728                 gboolean mouse_left_handed = g_settings_get_boolean (manager->priv->settings_mouse, key);
1729                 gboolean touchpad_left_handed = get_touchpad_handedness (manager, mouse_left_handed);
1730                 set_left_handed_all (manager, mouse_left_handed, touchpad_left_handed);
1731         } else if ((g_strcmp0 (key, KEY_TOUCHPAD_TAP_TO_CLICK) == 0)
1732                 || (g_strcmp0 (key, KEY_TOUCHPAD_ONE_FINGER_TAP) == 0)
1733                 || (g_strcmp0 (key, KEY_TOUCHPAD_TWO_FINGER_TAP) == 0)
1734                 || (g_strcmp0 (key, KEY_TOUCHPAD_THREE_FINGER_TAP) == 0)) {
1735                 set_tap_to_click_all (manager);
1736         } else if ((g_strcmp0 (key, KEY_TOUCHPAD_TWO_FINGER_CLICK) == 0)
1737                 || (g_strcmp0 (key, KEY_TOUCHPAD_THREE_FINGER_CLICK) == 0)) {
1738                 set_click_actions_all (manager);
1739         } else if ((g_strcmp0 (key, KEY_VERT_EDGE_SCROLL) == 0)
1740                 || (g_strcmp0 (key, KEY_HORIZ_EDGE_SCROLL) == 0)
1741                 || (g_strcmp0 (key, KEY_VERT_TWO_FINGER_SCROLL) == 0)
1742                 || (g_strcmp0 (key, KEY_HORIZ_TWO_FINGER_SCROLL) == 0)) {
1743                 set_scrolling_all (manager->priv->settings_touchpad);
1744         } else if (g_strcmp0 (key, KEY_TOUCHPAD_NATURAL_SCROLL) == 0) {
1745                 set_natural_scroll_all (manager);
1746         } else if (g_strcmp0 (key, KEY_TOUCHPAD_ENABLED) == 0) {
1747                 set_touchpad_enabled_all (g_settings_get_boolean (settings, key));
1748         } else if ((g_strcmp0 (key, KEY_MOTION_ACCELERATION) == 0)
1749                 || (g_strcmp0 (key, KEY_MOTION_THRESHOLD) == 0)) {
1750                 set_motion_all (manager);
1751         } else if (g_strcmp0 (key, KEY_ACCEL_PROFILE) == 0) {
1752                 set_accel_profile_all (manager);
1753         }
1754 }
1755 
1756 static void
msd_mouse_manager_init(MsdMouseManager * manager)1757 msd_mouse_manager_init (MsdMouseManager *manager)
1758 {
1759         manager->priv = msd_mouse_manager_get_instance_private (manager);
1760 }
1761 
1762 static gboolean
msd_mouse_manager_idle_cb(MsdMouseManager * manager)1763 msd_mouse_manager_idle_cb (MsdMouseManager *manager)
1764 {
1765         mate_settings_profile_start (NULL);
1766 
1767         manager->priv->settings_mouse = g_settings_new (MATE_MOUSE_SCHEMA);
1768         manager->priv->settings_touchpad = g_settings_new (MATE_TOUCHPAD_SCHEMA);
1769 
1770         g_signal_connect (manager->priv->settings_mouse, "changed",
1771                           G_CALLBACK (mouse_callback), manager);
1772         g_signal_connect (manager->priv->settings_touchpad, "changed",
1773                           G_CALLBACK (touchpad_callback), manager);
1774 
1775         manager->priv->syndaemon_spawned = FALSE;
1776 
1777         set_devicepresence_handler (manager);
1778 
1779         set_mouse_settings (manager);
1780         set_locate_pointer (manager, g_settings_get_boolean (manager->priv->settings_mouse, KEY_MOUSE_LOCATE_POINTER));
1781 
1782 #if 0   /* FIXME need to fork (?) mousetweaks for this to work */
1783         set_mousetweaks_daemon (manager,
1784                                 g_settings_get_boolean (manager->priv->settings_mouse_a11y,
1785                                                         KEY_MOUSE_A11Y_DWELL_ENABLE),
1786                                 g_settings_get_boolean (manager->priv->settings_mouse_a11y,
1787                                                         KEY_MOUSE_A11Y_DELAY_ENABLE));
1788 #endif
1789 
1790         mate_settings_profile_end (NULL);
1791 
1792         return FALSE;
1793 }
1794 
1795 gboolean
msd_mouse_manager_start(MsdMouseManager * manager,GError ** error)1796 msd_mouse_manager_start (MsdMouseManager *manager,
1797                          GError         **error)
1798 {
1799         mate_settings_profile_start (NULL);
1800 
1801         if (!supports_xinput_devices ()) {
1802                 g_debug ("XInput is not supported, not applying any settings");
1803                 return TRUE;
1804         }
1805 
1806         g_idle_add ((GSourceFunc) msd_mouse_manager_idle_cb, manager);
1807 
1808         mate_settings_profile_end (NULL);
1809 
1810         return TRUE;
1811 }
1812 
1813 void
msd_mouse_manager_stop(MsdMouseManager * manager)1814 msd_mouse_manager_stop (MsdMouseManager *manager)
1815 {
1816         MsdMouseManagerPrivate *p = manager->priv;
1817 
1818         g_debug ("Stopping mouse manager");
1819 
1820         if (p->settings_mouse != NULL) {
1821                 g_object_unref(p->settings_mouse);
1822                 p->settings_mouse = NULL;
1823         }
1824 
1825         if (p->settings_touchpad != NULL) {
1826                 g_object_unref(p->settings_touchpad);
1827                 p->settings_touchpad = NULL;
1828         }
1829 
1830         set_locate_pointer (manager, FALSE);
1831 
1832         gdk_window_remove_filter (NULL, devicepresence_filter, manager);
1833 }
1834 
1835 static void
msd_mouse_manager_finalize(GObject * object)1836 msd_mouse_manager_finalize (GObject *object)
1837 {
1838         MsdMouseManager *mouse_manager;
1839 
1840         g_return_if_fail (object != NULL);
1841         g_return_if_fail (MSD_IS_MOUSE_MANAGER (object));
1842 
1843         mouse_manager = MSD_MOUSE_MANAGER (object);
1844 
1845         g_return_if_fail (mouse_manager->priv != NULL);
1846 
1847         G_OBJECT_CLASS (msd_mouse_manager_parent_class)->finalize (object);
1848 }
1849 
1850 MsdMouseManager *
msd_mouse_manager_new(void)1851 msd_mouse_manager_new (void)
1852 {
1853         if (manager_object != NULL) {
1854                 g_object_ref (manager_object);
1855         } else {
1856                 manager_object = g_object_new (MSD_TYPE_MOUSE_MANAGER, NULL);
1857                 g_object_add_weak_pointer (manager_object,
1858                                            (gpointer *) &manager_object);
1859         }
1860 
1861         return MSD_MOUSE_MANAGER (manager_object);
1862 }
1863