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