[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: synaptics vs libinput and GNOME 3.20 no longer supporting synaptics



On Mon, 11 Jul 2016, Raphael Hertzog wrote:
> I'm starting now to prepare updated packages with the above changes
> reverted... just to see how hard it is and whether it seems to work.

Please find attached the two patches that I came up with. The packages
compile and seem to work in so far that I can enable/disable tap-to-click
at least (I see the touchpad in control-center). In the process, I lost
double-finger scrolling that seemed to work by default before...

What does the GNOME team think? Shall I commit those changes and do we
want to maintain those patches?

Cheers,
-- 
Raphaël Hertzog ◈ Debian Developer

Support Debian LTS: http://www.freexian.com/services/debian-lts.html
Learn to master Debian: http://debian-handbook.info/get/
Index: debian/changelog
===================================================================
--- debian/changelog	(révision 49289)
+++ debian/changelog	(copie de travail)
@@ -1,3 +1,12 @@
+gnome-settings-daemon (3.20.1-3) UNRELEASED; urgency=medium
+
+  * Reinstate support for synaptics and evdev-managed touchpads by
+    reverting those upstream commits:
+    https://git.gnome.org/browse/gnome-settings-daemon/commit/?id=66c211ff24bec6a938d6a6a0dd8730f4689ef383
+    https://git.gnome.org/browse/gnome-settings-daemon/commit/?id=9287ef9ac5b119abdcbbabd920c19f353e577f90
+
+ -- Raphaël Hertzog <hertzog@debian.org>  Mon, 11 Jul 2016 22:09:04 +0200
+
 gnome-settings-daemon (3.20.1-2) unstable; urgency=medium
 
   * debian/gnome-settings-daemon.install,
Index: debian/patches/Revert-common-Remove-unused-functions.patch
===================================================================
--- debian/patches/Revert-common-Remove-unused-functions.patch	(nonexistent)
+++ debian/patches/Revert-common-Remove-unused-functions.patch	(copie de travail)
@@ -0,0 +1,311 @@
+From c104cdab9f807c82ffa00e99d953f1408fa53549 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hertzog@debian.org>
+Date: Mon, 11 Jul 2016 22:29:47 +0200
+Subject: [PATCH] Revert "common: Remove unused functions"
+
+This reverts commit 9287ef9ac5b119abdcbbabd920c19f353e577f90.
+
+Add functions used by the patch enabling non-libinput managed touchpads.
+Those functions have been dropped because they were no longer being used.
+But we need them again...
+---
+ plugins/common/gsd-input-helper.c  | 189 +++++++++++++++++++++++++++++++++++++
+ plugins/common/gsd-input-helper.h  |  12 +++
+ plugins/common/test-input-helper.c |   5 +-
+ 3 files changed, 205 insertions(+), 1 deletion(-)
+
+diff --git a/plugins/common/gsd-input-helper.c b/plugins/common/gsd-input-helper.c
+index 077ff1c..1d10341 100644
+--- a/plugins/common/gsd-input-helper.c
++++ b/plugins/common/gsd-input-helper.c
+@@ -115,6 +115,12 @@ supports_xinput_devices_with_opcode (int *opcode)
+ }
+ 
+ gboolean
++supports_xinput_devices (void)
++{
++	return supports_xinput_devices_with_opcode (NULL);
++}
++
++gboolean
+ supports_xtest (void)
+ {
+         gint op_code, event, error;
+@@ -154,6 +160,66 @@ supports_xinput2_devices (int *opcode)
+         return TRUE;
+ }
+ 
++gboolean
++xdevice_is_synaptics (XDevice *xdevice)
++{
++        Atom realtype, prop;
++        int realformat;
++        unsigned long nitems, bytes_after;
++        unsigned char *data;
++
++        /* we don't check on the type being XI_TOUCHPAD here,
++         * but having a "Synaptics Off" property should be enough */
++
++        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Off", False);
++        if (!prop)
++                return FALSE;
++
++        gdk_error_trap_push ();
++        if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 1, False,
++                                XA_INTEGER, &realtype, &realformat, &nitems,
++                                &bytes_after, &data) == Success) && (realtype != None)) {
++                gdk_error_trap_pop_ignored ();
++                XFree (data);
++                return TRUE;
++        }
++        gdk_error_trap_pop_ignored ();
++
++        return FALSE;
++}
++
++gboolean
++synaptics_is_present (void)
++{
++        XDeviceInfo *device_info;
++        gint n_devices;
++        guint i;
++        gboolean retval;
++
++        retval = FALSE;
++
++        device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
++        if (device_info == NULL)
++                return FALSE;
++
++        for (i = 0; i < n_devices; i++) {
++                XDevice *device;
++
++                gdk_error_trap_push ();
++                device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id);
++                if (gdk_error_trap_pop () || (device == NULL))
++                        continue;
++
++                retval = xdevice_is_synaptics (device);
++                xdevice_close (device);
++                if (retval)
++                        break;
++        }
++        XFreeDeviceList (device_info);
++
++        return retval;
++}
++
+ static gboolean
+ device_type_is_present (GsdDeviceType type)
+ {
+@@ -181,6 +247,29 @@ mouse_is_present (void)
+         return device_type_is_present (GSD_DEVICE_TYPE_MOUSE);
+ }
+ 
++gboolean
++trackball_is_present (void)
++{
++        gboolean retval = FALSE;
++        GList *l, *mice = gsd_device_manager_list_devices (gsd_device_manager_get (),
++                                                           GSD_DEVICE_TYPE_MOUSE);
++        if (mice == NULL)
++                return FALSE;
++
++        for (l = mice; l != NULL; l = l->next) {
++                gchar *lowercase;
++                const gchar *name = gsd_device_get_name (l->data);
++                if (!name)
++                        continue;
++                lowercase = g_ascii_strdown (name, -1);
++                retval = strstr (lowercase, "trackball") != NULL;
++                g_free (lowercase);
++        }
++
++        g_list_free (mice);
++        return retval;
++}
++
+ char *
+ xdevice_get_device_node (int deviceid)
+ {
+@@ -339,6 +428,82 @@ set_device_enabled (int device_id,
+         return TRUE;
+ }
+ 
++gboolean
++set_synaptics_device_enabled (int device_id,
++                              gboolean enabled)
++{
++        Atom prop;
++        guchar value;
++
++        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Off", False);
++        if (!prop)
++                return FALSE;
++
++        gdk_error_trap_push ();
++
++        value = enabled ? 0 : 1;
++        XIChangeProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                          device_id, prop, XA_INTEGER, 8, PropModeReplace, &value, 1);
++
++        if (gdk_error_trap_pop ())
++                return FALSE;
++
++        return TRUE;
++}
++
++GList *
++get_disabled_synaptics (void)
++{
++        GdkDisplay *display;
++        XDeviceInfo *device_info;
++        gint n_devices, act_format, rc;
++        guint i;
++        GList *ret;
++        Atom prop, act_type;
++        unsigned long  nitems, bytes_after;
++        unsigned char *data;
++
++        ret = NULL;
++
++        display = gdk_display_get_default ();
++        prop = gdk_x11_get_xatom_by_name ("Synaptics Off");
++
++        gdk_error_trap_push ();
++
++        device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (display), &n_devices);
++        if (device_info == NULL) {
++                gdk_error_trap_pop_ignored ();
++
++                return ret;
++        }
++
++        for (i = 0; i < n_devices; i++) {
++                rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display),
++                                    device_info[i].id, prop, 0, 1, False,
++                                    XA_INTEGER, &act_type, &act_format,
++                                    &nitems, &bytes_after, &data);
++
++                if (rc != Success || act_type != XA_INTEGER ||
++                    act_format != 8 || nitems < 1)
++                        continue;
++
++                if (!(data[0])) {
++                        XFree (data);
++                        continue;
++                }
++
++                XFree (data);
++
++                ret = g_list_prepend (ret, GINT_TO_POINTER (device_info[i].id));
++        }
++
++        gdk_error_trap_pop_ignored ();
++
++        XFreeDeviceList (device_info);
++
++        return ret;
++}
++
+ const char *
+ xdevice_get_wacom_tool_type (int deviceid)
+ {
+@@ -425,3 +590,27 @@ xdevice_get_dimensions (int    deviceid,
+ 
+         return (w != 0 && h != 0);
+ }
++
++gboolean
++xdevice_is_libinput (gint deviceid)
++{
++        GdkDisplay *display = gdk_display_get_default ();
++        gulong nitems, bytes_after;
++        gint rc, format;
++        guchar *data;
++        Atom type;
++
++        gdk_error_trap_push ();
++
++        /* Lookup a libinput driver specific property */
++        rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display), deviceid,
++                            gdk_x11_get_xatom_by_name ("libinput Send Events Mode Enabled"),
++                            0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data);
++
++        if (rc == Success)
++                XFree (data);
++
++        gdk_error_trap_pop_ignored ();
++
++        return rc == Success && nitems > 0;
++}
+diff --git a/plugins/common/gsd-input-helper.h b/plugins/common/gsd-input-helper.h
+index 31e2e47..9d31f28 100644
+--- a/plugins/common/gsd-input-helper.h
++++ b/plugins/common/gsd-input-helper.h
+@@ -44,20 +44,29 @@ typedef struct {
+         } data;
+ } PropertyHelper;
+ 
++gboolean  supports_xinput_devices  (void);
+ gboolean  supports_xinput2_devices (int *opcode);
+ gboolean  supports_xtest           (void);
+ 
+ gboolean set_device_enabled       (int device_id,
+                                    gboolean enabled);
+ 
++gboolean  set_synaptics_device_enabled (int device_id,
++                                        gboolean enabled);
++
++gboolean  xdevice_is_synaptics       (XDevice                *xdevice);
++
++gboolean  synaptics_is_present    (void);
+ gboolean  touchpad_is_present     (void);
+ gboolean  touchscreen_is_present  (void);
+ gboolean  mouse_is_present        (void);
++gboolean  trackball_is_present    (void);
+ 
+ gboolean  device_set_property     (XDevice                *xdevice,
+                                    const char             *device_name,
+                                    PropertyHelper         *property);
+ 
++GList *   get_disabled_synaptics     (void);
+ char *    xdevice_get_device_node  (int                     deviceid);
+ int       xdevice_get_last_tool_id (int                     deviceid);
+ gboolean  xdevice_get_dimensions   (int                     deviceid,
+@@ -67,6 +76,9 @@ void      xdevice_close      (XDevice                *xdevice);
+ 
+ const char * xdevice_get_wacom_tool_type (int               deviceid);
+ 
++gboolean  xdevice_is_libinput (gint deviceid);
++
++
+ G_END_DECLS
+ 
+ #endif /* __GSD_INPUT_HELPER_H */
+diff --git a/plugins/common/test-input-helper.c b/plugins/common/test-input-helper.c
+index 954ac30..e78f463 100644
+--- a/plugins/common/test-input-helper.c
++++ b/plugins/common/test-input-helper.c
+@@ -32,7 +32,7 @@
+ int main (int argc, char **argv)
+ {
+         GList *devices, *l;
+-	gboolean has_touchpad, has_touchscreen;
++	gboolean has_touchpad, has_touchscreen, has_trackball;
+ 
+ 	gtk_init (&argc, &argv);
+ 
+@@ -42,6 +42,9 @@ int main (int argc, char **argv)
+ 	has_touchscreen = touchscreen_is_present ();
+ 	g_print ("Has touchscreen:\t\t\t%s\n", has_touchscreen ? "yes" : "no");
+ 
++	has_trackball = trackball_is_present ();
++	g_print ("Has trackball:\t\t\t\t%s\n", has_trackball ? "yes" : "no");
++
+         devices = gsd_device_manager_list_devices (gsd_device_manager_get (), GSD_DEVICE_TYPE_MOUSE);
+         for (l = devices; l != NULL; l = l->next)
+                 g_print ("Device '%s' is a mouse\n", gsd_device_get_name (l->data));
+-- 
+2.8.1
+
Index: debian/patches/Revert-mouse-Remove-support-for-non-libinput-mouse-c.patch
===================================================================
--- debian/patches/Revert-mouse-Remove-support-for-non-libinput-mouse-c.patch	(nonexistent)
+++ debian/patches/Revert-mouse-Remove-support-for-non-libinput-mouse-c.patch	(copie de travail)
@@ -0,0 +1,1385 @@
+From 1c3cef330e36c6c3bc6e00bfc176550203571929 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hertzog@debian.org>
+Date: Mon, 11 Jul 2016 22:02:53 +0200
+Subject: [PATCH] Revert "mouse: Remove support for non-libinput mouse
+ configurations"
+
+This reverts commit 66c211ff24bec6a938d6a6a0dd8730f4689ef383.
+
+We want to support synaptics/evdev managed touchpads until all desktops
+have been updated to use libinput.
+
+Also we should keep that for non-linux ports as well.
+
+[hertzog@debian.org: drop calls to run_custom_command as that feature
+has been dropped in the mean time]
+---
+ plugins/mouse/gsd-mouse-manager.c | 1255 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 1252 insertions(+), 3 deletions(-)
+
+--- a/plugins/mouse/gsd-mouse-manager.c
++++ b/plugins/mouse/gsd-mouse-manager.c
+@@ -19,17 +19,39 @@
+ 
+ #include "config.h"
+ 
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <math.h>
++#ifdef __linux
++#include <sys/prctl.h>
++#endif
++
+ #include <locale.h>
+ 
+ #include <glib.h>
+ #include <glib/gi18n.h>
+ #include <gio/gio.h>
++#include <gtk/gtk.h>
++#include <gdk/gdk.h>
++#include <gdk/gdkx.h>
++#include <gdk/gdkkeysyms.h>
++#include <X11/keysym.h>
++#include <X11/Xatom.h>
+ 
+ #include <gdesktop-enums.h>
+ 
++#include <X11/extensions/XInput.h>
++#include <X11/extensions/XIproto.h>
++
+ #include "gnome-settings-bus.h"
+ #include "gnome-settings-profile.h"
+ #include "gsd-mouse-manager.h"
++#include "gsd-input-helper.h"
+ #include "gsd-enums.h"
+ #include "gsd-settings-migrate.h"
+ 
+@@ -38,20 +60,42 @@
+ #define GSD_SETTINGS_MOUSE_SCHEMA  "org.gnome.settings-daemon.peripherals.mouse"
+ #define GSETTINGS_MOUSE_SCHEMA     "org.gnome.desktop.peripherals.mouse"
+ #define GSETTINGS_TOUCHPAD_SCHEMA  "org.gnome.desktop.peripherals.touchpad"
++#define GSETTINGS_TRACKBALL_SCHEMA "org.gnome.desktop.peripherals.trackball"
++
++/* Keys for both touchpad and mouse */
++#define KEY_LEFT_HANDED         "left-handed"                /* a boolean for mouse, an enum for touchpad */
++#define KEY_SPEED               "speed"
++
++/* Touchpad settings */
++#define KEY_EDGE_SCROLLING_ENABLED       "edge-scrolling-enabled"
++#define KEY_TAP_TO_CLICK                 "tap-to-click"
++#define KEY_SEND_EVENTS                  "send-events"
++#define KEY_NATURAL_SCROLL_ENABLED       "natural-scroll"
+ 
+ /* Mouse settings */
+ #define KEY_LOCATE_POINTER               "locate-pointer"
+ #define KEY_DWELL_CLICK_ENABLED          "dwell-click-enabled"
+ #define KEY_SECONDARY_CLICK_ENABLED      "secondary-click-enabled"
+ 
++/* Trackball settings */
++#define KEY_SCROLL_WHEEL_BUTTON          "scroll-wheel-emulation-button"
++
+ struct GsdMouseManagerPrivate
+ {
+         guint start_idle_id;
+         GSettings *touchpad_settings;
+-        GSettings *mouse_a11y_settings;
+         GSettings *mouse_settings;
++        GSettings *mouse_a11y_settings;
++        GSettings *trackball_settings;
+         GSettings *gsd_mouse_settings;
++        GdkDeviceManager *device_manager;
++        guint device_added_id;
++        guint device_removed_id;
++        GHashTable *blacklist;
++
+         gboolean mousetweaks_daemon_running;
++        gboolean syndaemon_spawned;
++        GPid syndaemon_pid;
+         gboolean locate_pointer_spawned;
+         GPid locate_pointer_pid;
+ };
+@@ -59,6 +103,12 @@ struct GsdMouseManagerPrivate
+ static void     gsd_mouse_manager_class_init  (GsdMouseManagerClass *klass);
+ static void     gsd_mouse_manager_init        (GsdMouseManager      *mouse_manager);
+ static void     gsd_mouse_manager_finalize    (GObject             *object);
++static void     set_tap_to_click              (GdkDevice           *device,
++                                               gboolean             state,
++                                               gboolean             left_handed);
++static void     ensure_touchpad_active        (GsdMouseManager     *manager);
++static gboolean get_touchpad_enabled          (GsdMouseManager     *manager);
++
+ 
+ G_DEFINE_TYPE (GsdMouseManager, gsd_mouse_manager, G_TYPE_OBJECT)
+ 
+@@ -76,6 +126,775 @@ gsd_mouse_manager_class_init (GsdMouseMa
+         g_type_class_add_private (klass, sizeof (GsdMouseManagerPrivate));
+ }
+ 
++static XDevice *
++open_gdk_device (GdkDevice *device)
++{
++        XDevice *xdevice;
++        int id;
++
++        g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++
++        gdk_error_trap_push ();
++
++        xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id);
++
++        if (gdk_error_trap_pop () != 0)
++                return NULL;
++
++        return xdevice;
++}
++
++static gboolean
++device_info_is_trackball (XDeviceInfo *device_info)
++{
++        gboolean retval;
++
++        retval = (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TRACKBALL, False));
++        if (retval == FALSE &&
++            device_info->name != NULL) {
++                char *lowercase;
++
++                lowercase = g_ascii_strdown (device_info->name, -1);
++                retval = strstr (lowercase, "trackball") != NULL;
++                g_free (lowercase);
++        }
++
++        return retval;
++}
++
++static gboolean
++device_is_trackball (GdkDevice *device)
++{
++        XDeviceInfo *device_info;
++        gboolean retval = FALSE;
++        gint n_devices;
++        guint i;
++        int id;
++
++        g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++
++        gdk_error_trap_push ();
++
++        device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
++        if (device_info == NULL)
++                return retval;
++
++        for (i = 0; i < n_devices; i++) {
++                if (device_info[i].id != id)
++                        continue;
++
++                retval = device_info_is_trackball (&device_info[i]);
++                break;
++        }
++        XFreeDeviceList (device_info);
++
++        if (gdk_error_trap_pop () != 0)
++                return FALSE;
++
++        return retval;
++}
++
++static gboolean
++device_is_blacklisted (GsdMouseManager *manager,
++                       GdkDevice       *device)
++{
++        int id;
++        g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++        if (g_hash_table_lookup (manager->priv->blacklist, GINT_TO_POINTER (id)) != NULL) {
++                g_debug ("device %s (%d) is blacklisted", gdk_device_get_name (device), id);
++                return TRUE;
++        }
++        return FALSE;
++}
++
++static gboolean
++device_is_ignored (GsdMouseManager *manager,
++		   GdkDevice       *device)
++{
++	GdkInputSource source;
++	const char *name;
++
++	if (device_is_blacklisted (manager, device))
++		return TRUE;
++
++	source = gdk_device_get_source (device);
++	if (source != GDK_SOURCE_MOUSE &&
++	    source != GDK_SOURCE_TOUCHPAD &&
++	    source != GDK_SOURCE_CURSOR)
++		return TRUE;
++
++	name = gdk_device_get_name (device);
++	if (name != NULL && g_str_equal ("Virtual core XTEST pointer", name))
++		return TRUE;
++
++	return FALSE;
++}
++
++static void
++configure_button_layout (guchar   *buttons,
++                         gint      n_buttons,
++                         gboolean  left_handed)
++{
++        const gint left_button = 1;
++        gint right_button;
++        gint i;
++
++        /* if the button is higher than 2 (3rd button) then it's
++         * probably one direction of a scroll wheel or something else
++         * uninteresting
++         */
++        right_button = MIN (n_buttons, 3);
++
++        /* If we change things we need to make sure we only swap buttons.
++         * If we end up with multiple physical buttons assigned to the same
++         * logical button the server will complain. This code assumes physical
++         * button 0 is the physical left mouse button, and that the physical
++         * button other than 0 currently assigned left_button or right_button
++         * is the physical right mouse button.
++         */
++
++        /* check if the current mapping satisfies the above assumptions */
++        if (buttons[left_button - 1] != left_button &&
++            buttons[left_button - 1] != right_button)
++                /* The current mapping is weird. Swapping buttons is probably not a
++                 * good idea.
++                 */
++                return;
++
++        /* check if we are left_handed and currently not swapped */
++        if (left_handed && buttons[left_button - 1] == left_button) {
++                /* find the right button */
++                for (i = 0; i < n_buttons; i++) {
++                        if (buttons[i] == right_button) {
++                                buttons[i] = left_button;
++                                break;
++                        }
++                }
++                /* swap the buttons */
++                buttons[left_button - 1] = right_button;
++        }
++        /* check if we are not left_handed but are swapped */
++        else if (!left_handed && buttons[left_button - 1] == right_button) {
++                /* find the right button */
++                for (i = 0; i < n_buttons; i++) {
++                        if (buttons[i] == left_button) {
++                                buttons[i] = right_button;
++                                break;
++                        }
++                }
++                /* swap the buttons */
++                buttons[left_button - 1] = left_button;
++        }
++}
++
++static gboolean
++xinput_device_has_buttons (GdkDevice *device)
++{
++        int i;
++        XAnyClassInfo *class_info;
++
++        /* FIXME can we use the XDevice's classes here instead? */
++        XDeviceInfo *device_info, *info;
++        gint n_devices;
++        int id;
++
++        /* Find the XDeviceInfo for the GdkDevice */
++        g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++
++        device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
++        if (device_info == NULL)
++                return FALSE;
++
++        info = NULL;
++        for (i = 0; i < n_devices; i++) {
++                if (device_info[i].id == id) {
++                        info = &device_info[i];
++                        break;
++                }
++        }
++        if (info == NULL)
++                goto bail;
++
++        class_info = info->inputclassinfo;
++        for (i = 0; i < info->num_classes; i++) {
++                if (class_info->class == ButtonClass) {
++                        XButtonInfo *button_info;
++
++                        button_info = (XButtonInfo *) class_info;
++                        if (button_info->num_buttons > 0) {
++                                XFreeDeviceList (device_info);
++                                return TRUE;
++                        }
++                }
++
++                class_info = (XAnyClassInfo *) (((guchar *) class_info) +
++                                                class_info->length);
++        }
++
++bail:
++        XFreeDeviceList (device_info);
++
++        return FALSE;
++}
++
++static gboolean
++touchpad_has_single_button (XDevice *device)
++{
++        Atom type, prop;
++        int format;
++        unsigned long nitems, bytes_after;
++        unsigned char *data;
++        gboolean is_single_button = FALSE;
++        int rc;
++
++        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", False);
++        if (!prop)
++                return FALSE;
++
++        gdk_error_trap_push ();
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 1, False,
++                                XA_INTEGER, &type, &format, &nitems,
++                                &bytes_after, &data);
++        if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3)
++                is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0);
++
++        if (rc == Success)
++                XFree (data);
++
++        gdk_error_trap_pop_ignored ();
++
++        return is_single_button;
++}
++
++static void
++set_left_handed (GsdMouseManager *manager,
++                 GdkDevice       *device,
++                 gboolean mouse_left_handed,
++                 gboolean touchpad_left_handed)
++{
++        XDevice *xdevice;
++        guchar *buttons;
++        gsize buttons_capacity = 16;
++        gboolean left_handed;
++        gint n_buttons;
++
++        if (!xinput_device_has_buttons (device))
++                return;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++	g_debug ("setting handedness on %s", gdk_device_get_name (device));
++
++        buttons = g_new (guchar, buttons_capacity);
++
++        /* If the device is a touchpad, swap tap buttons
++         * around too, otherwise a tap would be a right-click */
++        if (xdevice_is_synaptics (xdevice)) {
++                gboolean tap = g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK);
++                gboolean single_button = touchpad_has_single_button (xdevice);
++
++                left_handed = touchpad_left_handed;
++
++                if (tap && !single_button)
++                        set_tap_to_click (device, tap, left_handed);
++
++                if (single_button)
++                        goto out;
++        } else {
++                left_handed = mouse_left_handed;
++        }
++
++        gdk_error_trap_push ();
++
++        n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                             buttons,
++                                             buttons_capacity);
++
++        while (n_buttons > buttons_capacity) {
++                buttons_capacity = n_buttons;
++                buttons = (guchar *) g_realloc (buttons,
++                                                buttons_capacity * sizeof (guchar));
++
++                n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                                     buttons,
++                                                     buttons_capacity);
++        }
++
++        configure_button_layout (buttons, n_buttons, left_handed);
++
++        XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, n_buttons);
++        gdk_error_trap_pop_ignored ();
++
++out:
++        xdevice_close (xdevice);
++        g_free (buttons);
++}
++
++static void
++set_motion (GsdMouseManager *manager,
++            GdkDevice       *device)
++{
++        XDevice *xdevice;
++        XPtrFeedbackControl feedback;
++        XFeedbackState *states, *state;
++        int num_feedbacks;
++        int numerator, denominator;
++        gfloat motion_acceleration;
++        int motion_threshold;
++        GSettings *settings;
++        gdouble speed;
++        guint i;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++	g_debug ("setting motion on %s", gdk_device_get_name (device));
++
++        if (xdevice_is_synaptics (xdevice))
++                settings = manager->priv->touchpad_settings;
++        else
++                settings = manager->priv->mouse_settings;
++
++        speed = g_settings_get_double (settings, KEY_SPEED);
++
++        /* Calculate acceleration and threshold */
++        motion_acceleration = (speed + 1) * 5; /* speed is [-1..1], map to [0..10] */
++        motion_threshold = CLAMP (10 - floor (motion_acceleration), 1, 10);
++
++        if (motion_acceleration >= 1.0) {
++                /* we want to get the acceleration, with a resolution of 0.5
++                 */
++                if ((motion_acceleration - floor (motion_acceleration)) < 0.25) {
++                        numerator = floor (motion_acceleration);
++                        denominator = 1;
++                } else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) {
++                        numerator = ceil (2.0 * motion_acceleration);
++                        denominator = 2;
++                } else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) {
++                        numerator = floor (2.0 *motion_acceleration);
++                        denominator = 2;
++                } else {
++                        numerator = ceil (motion_acceleration);
++                        denominator = 1;
++                }
++        } else if (motion_acceleration < 1.0 && motion_acceleration > 0) {
++                /* This we do to 1/10ths */
++                numerator = floor (motion_acceleration * 10) + 1;
++                denominator= 10;
++        } else {
++                numerator = -1;
++                denominator = -1;
++        }
++
++        gdk_error_trap_push ();
++
++        /* Get the list of feedbacks for the device */
++        states = XGetFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, &num_feedbacks);
++        if (states == NULL)
++                goto out;
++        state = (XFeedbackState *) states;
++        for (i = 0; i < num_feedbacks; i++) {
++                if (state->class == PtrFeedbackClass) {
++                        /* And tell the device */
++                        feedback.class      = PtrFeedbackClass;
++                        feedback.length     = sizeof (XPtrFeedbackControl);
++                        feedback.id         = state->id;
++                        feedback.threshold  = motion_threshold;
++                        feedback.accelNum   = numerator;
++                        feedback.accelDenom = denominator;
++
++                        g_debug ("Setting accel %d/%d, threshold %d for device '%s'",
++                                 numerator, denominator, motion_threshold, gdk_device_get_name (device));
++
++                        XChangeFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                                xdevice,
++                                                DvAccelNum | DvAccelDenom | DvThreshold,
++                                                (XFeedbackControl *) &feedback);
++
++                        break;
++                }
++                state = (XFeedbackState *) ((char *) state + state->length);
++        }
++
++        if (gdk_error_trap_pop ())
++                g_warning ("Error setting acceleration on \"%s\"", gdk_device_get_name (device));
++
++        XFreeFeedbackList (states);
++
++    out:
++
++        xdevice_close (xdevice);
++}
++
++/* Ensure that syndaemon dies together with us, to avoid running several of
++ * them */
++static void
++setup_syndaemon (gpointer user_data)
++{
++#ifdef __linux
++        prctl (PR_SET_PDEATHSIG, SIGHUP);
++#endif
++}
++
++static gboolean
++have_program_in_path (const char *name)
++{
++        gchar *path;
++        gboolean result;
++
++        path = g_find_program_in_path (name);
++        result = (path != NULL);
++        g_free (path);
++        return result;
++}
++
++static void
++syndaemon_died (GPid pid, gint status, gpointer user_data)
++{
++        GsdMouseManager *manager = GSD_MOUSE_MANAGER (user_data);
++
++        g_debug ("syndaemon stopped with status %i", status);
++        g_spawn_close_pid (pid);
++        manager->priv->syndaemon_spawned = FALSE;
++}
++
++static int
++set_disable_w_typing (GsdMouseManager *manager, gboolean state)
++{
++        if (state && synaptics_is_present ()) {
++                GError *error = NULL;
++                GPtrArray *args;
++
++                if (manager->priv->syndaemon_spawned)
++                        return 0;
++
++                if (!have_program_in_path ("syndaemon"))
++                        return 0;
++
++                args = g_ptr_array_new ();
++
++                g_ptr_array_add (args, "syndaemon");
++                g_ptr_array_add (args, "-i");
++                g_ptr_array_add (args, "1.0");
++                g_ptr_array_add (args, "-t");
++                g_ptr_array_add (args, "-K");
++                g_ptr_array_add (args, "-R");
++                g_ptr_array_add (args, NULL);
++
++                /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
++                 * double-forking, otherwise syndaemon will immediately get
++                 * killed again through (PR_SET_PDEATHSIG when the intermediate
++                 * process dies */
++                g_spawn_async (g_get_home_dir (), (char **) args->pdata, NULL,
++                                G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL,
++                                &manager->priv->syndaemon_pid, &error);
++
++                manager->priv->syndaemon_spawned = (error == NULL);
++                g_ptr_array_free (args, FALSE);
++
++                if (error) {
++                        g_warning ("Failed to launch syndaemon: %s", error->message);
++                        g_error_free (error);
++                } else {
++                        g_child_watch_add (manager->priv->syndaemon_pid, syndaemon_died, manager);
++                        g_debug ("Launched syndaemon");
++                }
++        } else if (manager->priv->syndaemon_spawned) {
++                kill (manager->priv->syndaemon_pid, SIGHUP);
++                g_spawn_close_pid (manager->priv->syndaemon_pid);
++                manager->priv->syndaemon_spawned = FALSE;
++                g_debug ("Killed syndaemon");
++        }
++
++        return 0;
++}
++
++static void
++set_tap_to_click (GdkDevice *device,
++                  gboolean   state,
++                  gboolean   left_handed)
++{
++        int format, rc;
++        unsigned long nitems, bytes_after;
++        XDevice *xdevice;
++        unsigned char* data;
++        Atom prop_capabilities, prop, type;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Tap Action", False);
++        prop_capabilities = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", False);
++        if (!prop || !prop_capabilities)
++                return;
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++        if (!xdevice_is_synaptics (xdevice)) {
++                xdevice_close (xdevice);
++                return;
++        }
++
++	g_debug ("setting tap to click on %s", gdk_device_get_name (device));
++
++        gdk_error_trap_push ();
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_capabilities, 0, 1,
++                                 False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data);
++        if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 1) {
++                if (!(data[0])) {
++                        g_debug ("No hardware buttons, enabling tap to click on %s", gdk_device_get_name (device));
++                        state = TRUE;
++                }
++
++                XFree (data);
++        }
++
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2,
++                                 False, XA_INTEGER, &type, &format, &nitems,
++                                 &bytes_after, &data);
++
++        if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7) {
++                /* Set RLM mapping for 1/2/3 fingers*/
++                data[4] = (state) ? ((left_handed) ? 3 : 1) : 0;
++                data[5] = (state) ? ((left_handed) ? 1 : 3) : 0;
++                data[6] = (state) ? 2 : 0;
++                XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8,
++                                       PropModeReplace, data, nitems);
++        }
++
++        if (rc == Success)
++                XFree (data);
++
++        if (gdk_error_trap_pop ())
++                g_warning ("Error in setting tap to click on \"%s\"", gdk_device_get_name (device));
++
++        xdevice_close (xdevice);
++}
++
++static void
++set_horiz_scroll (GdkDevice *device,
++                  gboolean   state)
++{
++        int rc;
++        XDevice *xdevice;
++        Atom act_type, prop_edge, prop_twofinger;
++        int act_format;
++        unsigned long nitems, bytes_after;
++        unsigned char *data;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Edge Scrolling", False);
++        prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Two-Finger Scrolling", False);
++
++        if (!prop_edge || !prop_twofinger)
++                return;
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++        if (!xdevice_is_synaptics (xdevice)) {
++                xdevice_close (xdevice);
++                return;
++        }
++
++	g_debug ("setting horiz scroll on %s", gdk_device_get_name (device));
++
++        gdk_error_trap_push ();
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                 prop_edge, 0, 1, False,
++                                 XA_INTEGER, &act_type, &act_format, &nitems,
++                                 &bytes_after, &data);
++        if (rc == Success && act_type == XA_INTEGER &&
++            act_format == 8 && nitems >= 2) {
++                data[1] = (state && data[0]);
++                XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                       prop_edge, XA_INTEGER, 8,
++                                       PropModeReplace, data, nitems);
++        }
++
++        XFree (data);
++
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                 prop_twofinger, 0, 1, False,
++                                 XA_INTEGER, &act_type, &act_format, &nitems,
++                                 &bytes_after, &data);
++        if (rc == Success && act_type == XA_INTEGER &&
++            act_format == 8 && nitems >= 2) {
++                data[1] = (state && data[0]);
++                XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                       prop_twofinger, XA_INTEGER, 8,
++                                       PropModeReplace, data, nitems);
++        }
++
++        if (gdk_error_trap_pop ())
++                g_warning ("Error in setting horiz scroll on \"%s\"", gdk_device_get_name (device));
++
++        if (rc == Success)
++                XFree (data);
++
++        xdevice_close (xdevice);
++
++}
++
++static void
++set_edge_scrolling_enabled (GsdMouseManager         *manager,
++                            GdkDevice               *device,
++                            gboolean                 enabled)
++{
++        int rc;
++        XDevice *xdevice;
++        Atom act_type, prop, prop_edge, prop_twofinger;
++        int act_format;
++        unsigned long nitems, bytes_after;
++        unsigned char *data;
++        GsdTouchpadScrollMethod method;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", True);
++        prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Edge Scrolling", False);
++        prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Two-Finger Scrolling", False);
++
++        if (!prop_edge || !prop_twofinger || !prop)
++                return;
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++        if (!xdevice_is_synaptics (xdevice)) {
++                xdevice_close (xdevice);
++                return;
++        }
++
++	g_debug ("setting edge scroll on %s", gdk_device_get_name (device));
++
++        gdk_error_trap_push ();
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                 prop, 0, 2, False,
++                                 XA_INTEGER, &act_type, &act_format, &nitems,
++                                 &bytes_after, &data);
++        if (rc == Success && act_type != None) {
++                /* Two-finger scrolling is supported, so enable it */
++                if (data[3])
++                        method = GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING;
++
++                XFree (data);
++        }
++
++        if (enabled && method != GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING)
++                method = GSD_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING;
++        else
++                method = GSD_TOUCHPAD_SCROLL_METHOD_DISABLED;
++
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                 prop_edge, 0, 1, False,
++                                 XA_INTEGER, &act_type, &act_format, &nitems,
++                                 &bytes_after, &data);
++        if (rc == Success && act_type == XA_INTEGER &&
++            act_format == 8 && nitems >= 2) {
++                data[0] = (method == GSD_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING) ? 1 : 0;
++                XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                       prop_edge, XA_INTEGER, 8,
++                                       PropModeReplace, data, nitems);
++        }
++
++        XFree (data);
++
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                 prop_twofinger, 0, 1, False,
++                                 XA_INTEGER, &act_type, &act_format, &nitems,
++                                 &bytes_after, &data);
++        if (rc == Success && act_type == XA_INTEGER &&
++            act_format == 8 && nitems >= 2) {
++                data[0] = (method == GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING) ? 1 : 0;
++                XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                       prop_twofinger, XA_INTEGER, 8,
++                                       PropModeReplace, data, nitems);
++        }
++
++        if (gdk_error_trap_pop ())
++                g_warning ("Error in setting edge scroll on \"%s\"", gdk_device_get_name (device));
++
++        if (rc == Success)
++                XFree (data);
++
++        xdevice_close (xdevice);
++}
++
++static void
++set_touchpad_disabled (GdkDevice *device)
++{
++        int id;
++        XDevice *xdevice;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++
++        g_debug ("Trying to set device disabled for \"%s\" (%d)", gdk_device_get_name (device), id);
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++        if (!xdevice_is_synaptics (xdevice)) {
++                xdevice_close (xdevice);
++                return;
++        }
++
++        if (set_synaptics_device_enabled (id, FALSE) == FALSE)
++                g_warning ("Error disabling device \"%s\" (%d)", gdk_device_get_name (device), id);
++        else
++                g_debug ("Disabled device \"%s\" (%d)", gdk_device_get_name (device), id);
++
++        xdevice_close (xdevice);
++}
++
++static void
++set_touchpad_enabled (int id)
++{
++        XDevice *xdevice;
++
++        if (xdevice_is_libinput (id))
++                return;
++
++        g_debug ("Trying to set device enabled for %d", id);
++
++        gdk_error_trap_push ();
++        xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id);
++        if (gdk_error_trap_pop () != 0)
++                return;
++
++        if (!xdevice_is_synaptics (xdevice)) {
++                xdevice_close (xdevice);
++                return;
++        }
++
++        if (set_synaptics_device_enabled (id, TRUE) == FALSE)
++                g_warning ("Error enabling device \"%d\"", id);
++        else
++                g_debug ("Enabled device %d", id);
++
++        xdevice_close (xdevice);
++}
++
+ static void
+ set_locate_pointer (GsdMouseManager *manager,
+                     gboolean         state)
+@@ -143,32 +962,409 @@ set_mousetweaks_daemon (GsdMouseManager
+         g_free (comm);
+ }
+ 
++static gboolean
++get_touchpad_handedness (GsdMouseManager *manager, gboolean mouse_left_handed)
++{
++        switch (g_settings_get_enum (manager->priv->touchpad_settings, KEY_LEFT_HANDED)) {
++        case GSD_TOUCHPAD_HANDEDNESS_RIGHT:
++                return FALSE;
++        case GSD_TOUCHPAD_HANDEDNESS_LEFT:
++                return TRUE;
++        case GSD_TOUCHPAD_HANDEDNESS_MOUSE:
++                return mouse_left_handed;
++        default:
++                g_assert_not_reached ();
++        }
++}
++
++static void
++set_natural_scroll (GsdMouseManager *manager,
++                    GdkDevice       *device,
++                    gboolean         natural_scroll)
++{
++        XDevice *xdevice;
++        Atom scrolling_distance, act_type;
++        int rc, act_format;
++        unsigned long nitems, bytes_after;
++        unsigned char *data;
++        glong *ptr;
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++        if (!xdevice_is_synaptics (xdevice)) {
++                xdevice_close (xdevice);
++                return;
++        }
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        g_debug ("Trying to set %s for \"%s\"",
++                 natural_scroll ? "natural (reverse) scroll" : "normal scroll",
++                 gdk_device_get_name (device));
++
++        scrolling_distance = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                          "Synaptics Scrolling Distance", False);
++
++        gdk_error_trap_push ();
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                 scrolling_distance, 0, 2, False,
++                                 XA_INTEGER, &act_type, &act_format, &nitems,
++                                 &bytes_after, &data);
++
++        if (rc == Success && act_type == XA_INTEGER && act_format == 32 && nitems >= 2) {
++                ptr = (glong *) data;
++
++                if (natural_scroll) {
++                        ptr[0] = -abs(ptr[0]);
++                        ptr[1] = -abs(ptr[1]);
++                } else {
++                        ptr[0] = abs(ptr[0]);
++                        ptr[1] = abs(ptr[1]);
++                }
++
++                XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
++                                       scrolling_distance, XA_INTEGER, act_format,
++                                       PropModeReplace, data, nitems);
++        }
++
++        if (gdk_error_trap_pop ())
++                g_warning ("Error setting %s for \"%s\"",
++                           natural_scroll ? "natural (reverse) scroll" : "normal scroll",
++                           gdk_device_get_name (device));
++
++        if (rc == Success)
++                XFree (data);
++
++        xdevice_close (xdevice);
++}
++
++static void
++set_scroll_wheel_button (GsdMouseManager *manager,
++                         GdkDevice       *device)
++{
++        Atom wheel_prop, button_prop;
++        XDevice *xdevice;
++        Atom type;
++        int format;
++        unsigned long nitems, bytes_after;
++        unsigned char *data = NULL;
++        int button;
++        int rc;
++
++        if (!device_is_trackball (device))
++                return;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        xdevice = open_gdk_device (device);
++        if (xdevice == NULL)
++                return;
++
++        wheel_prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                  "Evdev Wheel Emulation", True);
++        button_prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                   "Evdev Wheel Emulation Button", True);
++
++        if (!wheel_prop || !button_prop) {
++                xdevice_close (xdevice);
++                return;
++        }
++
++        g_debug ("setting scroll wheel emulation on %s", gdk_device_get_name (device));
++
++        gdk_error_trap_push ();
++
++        button = g_settings_get_int (manager->priv->trackball_settings, KEY_SCROLL_WHEEL_BUTTON);
++
++        /* Whether scroll wheel emulation is enabled */
++        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                 xdevice, wheel_prop, 0, 1, False, XA_INTEGER, &type, &format,
++                                 &nitems, &bytes_after, &data);
++
++        if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) {
++                data[0] = button > 0 ? 1 : 0;
++
++                XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                       xdevice, wheel_prop, type, format, PropModeReplace, data, nitems);
++        }
++
++        if (data) {
++                XFree (data);
++                data = NULL;
++        }
++
++        /* Which button is used for the emulation */
++        if (button > 0) {
++                rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                         xdevice, button_prop, 0, 1, False, XA_INTEGER, &type, &format,
++                                         &nitems, &bytes_after, &data);
++
++                if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) {
++                        data[0] = button;
++
++                        XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
++                                               xdevice, button_prop, type, format, PropModeReplace, data, nitems);
++                }
++
++                if (data)
++                        XFree (data);
++        }
++
++        if (gdk_error_trap_pop ())
++                g_warning ("Error in setting scroll wheel emulation on \"%s\"", gdk_device_get_name (device));
++
++        xdevice_close (xdevice);
++}
++
++static gboolean
++get_touchpad_enabled (GsdMouseManager *manager)
++{
++        GDesktopDeviceSendEvents send_events;
++
++        send_events = g_settings_get_enum (manager->priv->touchpad_settings, KEY_SEND_EVENTS);
++
++        if (send_events == G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) {
++                /* FIXME: mouse_is_present() also finds internal ones... */
++                return (!mouse_is_present () && !trackball_is_present ());
++
++        }
++
++        return send_events == G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED ? TRUE : FALSE;
++}
++
++static void
++set_mouse_settings (GsdMouseManager *manager,
++                    GdkDevice       *device)
++{
++        gboolean mouse_left_handed, touchpad_left_handed;
++
++        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                return;
++
++        mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED);
++        touchpad_left_handed = get_touchpad_handedness (manager, mouse_left_handed);
++        set_left_handed (manager, device, mouse_left_handed, touchpad_left_handed);
++
++        set_motion (manager, device);
++
++        set_tap_to_click (device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK), touchpad_left_handed);
++        set_edge_scrolling_enabled (manager, device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_EDGE_SCROLLING_ENABLED));
++        set_horiz_scroll (device, TRUE);
++        set_natural_scroll (manager, device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_NATURAL_SCROLL_ENABLED));
++
++        set_scroll_wheel_button (manager, device);
++}
++
+ static void
+ mouse_callback (GSettings       *settings,
+                 const gchar     *key,
+                 GsdMouseManager *manager)
+ {
++        GList *devices, *l;
++
+         if (g_str_equal (key, KEY_DWELL_CLICK_ENABLED) ||
+             g_str_equal (key, KEY_SECONDARY_CLICK_ENABLED)) {
+                 set_mousetweaks_daemon (manager,
+                                         g_settings_get_boolean (settings, KEY_DWELL_CLICK_ENABLED),
+                                         g_settings_get_boolean (settings, KEY_SECONDARY_CLICK_ENABLED));
++                return;
+         } else if (g_str_equal (key, KEY_LOCATE_POINTER)) {
+                 set_locate_pointer (manager, g_settings_get_boolean (settings, KEY_LOCATE_POINTER));
++                return;
++        }
++
++        devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE);
++
++        for (l = devices; l != NULL; l = l->next) {
++                GdkDevice *device = l->data;
++
++                if (device_is_ignored (manager, device))
++                        continue;
++
++                if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                        continue;
++
++                if (g_str_equal (key, KEY_LEFT_HANDED)) {
++                        gboolean mouse_left_handed;
++                        mouse_left_handed = g_settings_get_boolean (settings, KEY_LEFT_HANDED);
++                        set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed));
++                } else if (g_str_equal (key, KEY_SPEED)) {
++                        set_motion (manager, device);
++                }
++        }
++        g_list_free (devices);
++}
++
++static void
++touchpad_callback (GSettings       *settings,
++                   const gchar     *key,
++                   GsdMouseManager *manager)
++{
++        GList *devices, *l;
++
++        devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE);
++
++        for (l = devices; l != NULL; l = l->next) {
++                GdkDevice *device = l->data;
++
++                if (device_is_ignored (manager, device))
++                        continue;
++
++                if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                        continue;
++
++                if (g_str_equal (key, KEY_TAP_TO_CLICK)) {
++                        gboolean mouse_left_handed;
++                        mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED);
++                        set_tap_to_click (device, g_settings_get_boolean (settings, key),
++                                          get_touchpad_handedness (manager, mouse_left_handed));
++                } else if (g_str_equal (key, KEY_EDGE_SCROLLING_ENABLED)) {
++                        set_edge_scrolling_enabled (manager, device, g_settings_get_boolean (settings, key));
++                        set_horiz_scroll (device, TRUE);
++                } else if (g_str_equal (key, KEY_SPEED)) {
++                        set_motion (manager, device);
++                } else if (g_str_equal (key, KEY_LEFT_HANDED)) {
++                        gboolean mouse_left_handed;
++                        mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED);
++                        set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed));
++                } else if (g_str_equal (key, KEY_NATURAL_SCROLL_ENABLED)) {
++                        set_natural_scroll (manager, device, g_settings_get_boolean (settings, key));
++                }
++        }
++        g_list_free (devices);
++
++        if (g_str_equal (key, KEY_SEND_EVENTS)) {
++                ensure_touchpad_active (manager);
+         }
+ }
+ 
+ static void
++trackball_callback (GSettings       *settings,
++                    const gchar     *key,
++                    GsdMouseManager *manager)
++{
++        GList *devices, *l;
++
++        devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE);
++
++        for (l = devices; l != NULL; l = l->next) {
++                GdkDevice *device = l->data;
++
++                if (device_is_ignored (manager, device))
++                        continue;
++
++                if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                        return;
++
++                set_scroll_wheel_button (manager, device);
++        }
++        g_list_free (devices);
++}
++
++/* Re-enable touchpad when any other pointing device isn't present. */
++static void
++ensure_touchpad_active (GsdMouseManager *manager)
++{
++        GList *devices, *l;
++        gboolean state;
++
++        state = get_touchpad_enabled (manager);
++        if (state) {
++                devices = get_disabled_synaptics ();
++                for (l = devices; l != NULL; l = l->next) {
++                        int device_id;
++
++                        device_id = GPOINTER_TO_INT (l->data);
++                        set_touchpad_enabled (device_id);
++                }
++                g_list_free (devices);
++        } else {
++                devices = gdk_device_manager_list_devices (manager->priv->device_manager,
++                                                           GDK_DEVICE_TYPE_SLAVE);
++
++                for (l = devices; l != NULL; l = l->next) {
++                        GdkDevice *device = l->data;
++
++                        if (device_is_ignored (manager, device))
++                                continue;
++                        if (xdevice_is_libinput (gdk_x11_device_get_id (device)))
++                                continue;
++                        if (gdk_device_get_source (device) != GDK_SOURCE_TOUCHPAD)
++                                continue;
++
++                        set_touchpad_disabled (device);
++                }
++
++                g_list_free (devices);
++        }
++
++        set_disable_w_typing (manager, state);
++}
++
++static void
++device_added_cb (GdkDeviceManager *device_manager,
++                 GdkDevice        *device,
++                 GsdMouseManager  *manager)
++{
++        if (device_is_ignored (manager, device) == FALSE) {
++                set_mouse_settings (manager, device);
++
++                ensure_touchpad_active (manager);
++        }
++}
++
++static void
++device_removed_cb (GdkDeviceManager *device_manager,
++                   GdkDevice        *device,
++                   GsdMouseManager  *manager)
++{
++	int id;
++
++	/* Remove the device from the hash table so that
++	 * device_is_ignored () doesn't check for blacklisted devices */
++	g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++	g_hash_table_remove (manager->priv->blacklist,
++			     GINT_TO_POINTER (id));
++
++        if (device_is_ignored (manager, device) == FALSE) {
++                ensure_touchpad_active (manager);
++        }
++}
++
++static void
++set_devicepresence_handler (GsdMouseManager *manager)
++{
++        GdkDeviceManager *device_manager;
++
++        device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
++
++        manager->priv->device_added_id = g_signal_connect (G_OBJECT (device_manager), "device-added",
++                                                           G_CALLBACK (device_added_cb), manager);
++        manager->priv->device_removed_id = g_signal_connect (G_OBJECT (device_manager), "device-removed",
++                                                             G_CALLBACK (device_removed_cb), manager);
++        manager->priv->device_manager = device_manager;
++}
++
++static void
+ gsd_mouse_manager_init (GsdMouseManager *manager)
+ {
+         manager->priv = GSD_MOUSE_MANAGER_GET_PRIVATE (manager);
++        manager->priv->blacklist = g_hash_table_new (g_direct_hash, g_direct_equal);
+ }
+ 
+ static gboolean
+ gsd_mouse_manager_idle_cb (GsdMouseManager *manager)
+ {
++        GList *devices, *l;
++
+         gnome_settings_profile_start (NULL);
+ 
++        set_devicepresence_handler (manager);
++
+         manager->priv->gsd_mouse_settings = g_settings_new (GSD_SETTINGS_MOUSE_SCHEMA);
+         g_signal_connect (manager->priv->gsd_mouse_settings, "changed",
+                           G_CALLBACK (mouse_callback), manager);
+@@ -176,17 +1372,39 @@ gsd_mouse_manager_idle_cb (GsdMouseManag
+         manager->priv->mouse_a11y_settings = g_settings_new ("org.gnome.desktop.a11y.mouse");
+         g_signal_connect (manager->priv->mouse_a11y_settings, "changed",
+                           G_CALLBACK (mouse_callback), manager);
+-#if 0
++
+         manager->priv->mouse_settings = g_settings_new (GSETTINGS_MOUSE_SCHEMA);
+         g_signal_connect (manager->priv->mouse_settings, "changed",
+                           G_CALLBACK (mouse_callback), manager);
+-#endif
++
++        manager->priv->touchpad_settings = g_settings_new (GSETTINGS_TOUCHPAD_SCHEMA);
++        g_signal_connect (manager->priv->touchpad_settings, "changed",
++                          G_CALLBACK (touchpad_callback), manager);
++
++        manager->priv->trackball_settings = g_settings_new (GSETTINGS_TRACKBALL_SCHEMA);
++        g_signal_connect (manager->priv->trackball_settings, "changed",
++                          G_CALLBACK (trackball_callback), manager);
++
++        manager->priv->syndaemon_spawned = FALSE;
+ 
+         set_locate_pointer (manager, g_settings_get_boolean (manager->priv->gsd_mouse_settings, KEY_LOCATE_POINTER));
+         set_mousetweaks_daemon (manager,
+                                 g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_DWELL_CLICK_ENABLED),
+                                 g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_SECONDARY_CLICK_ENABLED));
+ 
++        devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE);
++        for (l = devices; l != NULL; l = l->next) {
++                GdkDevice *device = l->data;
++
++                if (device_is_ignored (manager, device))
++                        continue;
++
++                set_mouse_settings (manager, device);
++        }
++        g_list_free (devices);
++
++        ensure_touchpad_active (manager);
++
+         gnome_settings_profile_end (NULL);
+ 
+         manager->priv->start_idle_id = 0;
+@@ -202,6 +1420,11 @@ gsd_mouse_manager_start (GsdMouseManager
+ 
+         migrate_mouse_settings ();
+ 
++        if (!supports_xinput_devices ()) {
++                g_debug ("XInput is not supported, not applying any settings");
++                return TRUE;
++        }
++
+         if (gnome_settings_is_wayland ())
+                 return TRUE;
+ 
+@@ -225,9 +1448,16 @@ gsd_mouse_manager_stop (GsdMouseManager
+                 manager->priv->start_idle_id = 0;
+         }
+ 
++        if (p->device_manager != NULL) {
++                g_signal_handler_disconnect (p->device_manager, p->device_added_id);
++                g_signal_handler_disconnect (p->device_manager, p->device_removed_id);
++                p->device_manager = NULL;
++        }
++
+         g_clear_object (&p->mouse_a11y_settings);
+         g_clear_object (&p->mouse_settings);
+         g_clear_object (&p->touchpad_settings);
++        g_clear_object (&p->trackball_settings);
+         g_clear_object (&p->gsd_mouse_settings);
+ 
+         set_locate_pointer (manager, FALSE);
+@@ -247,6 +1477,9 @@ gsd_mouse_manager_finalize (GObject *obj
+ 
+         gsd_mouse_manager_stop (mouse_manager);
+ 
++        if (mouse_manager->priv->blacklist != NULL)
++                g_hash_table_destroy (mouse_manager->priv->blacklist);
++
+         G_OBJECT_CLASS (gsd_mouse_manager_parent_class)->finalize (object);
+ }
+ 
Index: debian/patches/series
===================================================================
--- debian/patches/series	(révision 49289)
+++ debian/patches/series	(copie de travail)
@@ -1 +1,3 @@
 04_superP.patch
+Revert-mouse-Remove-support-for-non-libinput-mouse-c.patch
+Revert-common-Remove-unused-functions.patch
Index: debian/changelog
===================================================================
--- debian/changelog	(révision 49289)
+++ debian/changelog	(copie de travail)
@@ -1,3 +1,10 @@
+gnome-control-center (1:3.20.1-3) UNRELEASED; urgency=medium
+
+  * Re-enable possibility to configure synaptics-managed touchpads. We have to
+    revert some upstream changes to achieve this.
+
+ -- Raphaël Hertzog <hertzog@debian.org>  Mon, 11 Jul 2016 23:34:43 +0200
+
 gnome-control-center (1:3.20.1-2) unstable; urgency=medium
 
   * debian/control.in: Switch system-config-printer recommends to
Index: debian/patches/Revert-mouse-Drop-unused-synaptics-capabilities-chec.patch
===================================================================
--- debian/patches/Revert-mouse-Drop-unused-synaptics-capabilities-chec.patch	(nonexistent)
+++ debian/patches/Revert-mouse-Drop-unused-synaptics-capabilities-chec.patch	(copie de travail)
@@ -0,0 +1,88 @@
+From a1add71896354ff234cab35720651d26ea5e6395 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hertzog@debian.org>
+Date: Mon, 11 Jul 2016 23:26:55 +0200
+Subject: [PATCH] Revert "mouse: Drop unused synaptics capabilities check"
+
+This reverts commit 796e3fba9ed206e6570d3b38e3b81cf096851568 and also a
+part of ce48b5c6594ad450bbfee526683fe19efffe9ef3.
+
+We just re-enable the possibility to configure synaptics managed
+touchpads.
+---
+ panels/mouse/cc-mouse-caps-helper.c   | 26 ++++++++++++++++++++++++--
+ panels/mouse/gnome-mouse-properties.c |  8 ++------
+ 2 files changed, 26 insertions(+), 8 deletions(-)
+
+diff --git a/panels/mouse/cc-mouse-caps-helper.c b/panels/mouse/cc-mouse-caps-helper.c
+index 3b912ce..a6525d0 100644
+--- a/panels/mouse/cc-mouse-caps-helper.c
++++ b/panels/mouse/cc-mouse-caps-helper.c
+@@ -31,15 +31,16 @@ touchpad_check_capabilities_x11 (gboolean *have_two_finger_scrolling,
+ {
+         Display *display;
+ 	GList *devicelist, *l;
+-	Atom realtype, prop_scroll_methods, prop_tapping_enabled;
++	Atom realtype, prop_capabilities, prop_scroll_methods, prop_tapping_enabled;
+ 	int realformat;
+ 	unsigned long nitems, bytes_after;
+ 	unsigned char *data;
+ 
+         display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
++	prop_capabilities = XInternAtom (display, "Synaptics Capabilities", False);
+ 	prop_scroll_methods = XInternAtom (display, "libinput Scroll Methods Available", False);
+ 	prop_tapping_enabled = XInternAtom (display, "libinput Tapping Enabled", False);
+-	if (!prop_scroll_methods || !prop_tapping_enabled)
++	if (!prop_capabilities || !prop_scroll_methods || !prop_tapping_enabled)
+ 		return FALSE;
+ 
+ 	*have_two_finger_scrolling = FALSE;
+@@ -55,6 +56,27 @@ touchpad_check_capabilities_x11 (gboolean *have_two_finger_scrolling,
+                 if (gdk_device_get_source (device) != GDK_SOURCE_TOUCHPAD)
+ 			continue;
+ 
++		/* xorg-x11-drv-synaptics */
++		if ((XIGetProperty (display, gdk_x11_device_get_id (device), prop_capabilities,
++				    0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems,
++				    &bytes_after, &data) == Success) && (realtype != None)) {
++			/* Property data is booleans for has_left, has_middle, has_right, has_double, has_triple.
++			 * Newer drivers (X.org/kerrnel) will also include has_pressure and has_width. */
++
++			/* Set tap_to_click_toggle sensitive only if the device has hardware buttons */
++			if (data[0])
++				*have_tap_to_click = TRUE;
++
++			/* Set two_finger_scroll_toggle sensitive if the hardware supports double touch */
++			if (data[3])
++				*have_two_finger_scrolling = TRUE;
++
++			/* Edge scrolling should be supported for all synaptics touchpads */
++			*have_edge_scrolling = TRUE;
++
++			XFree (data);
++		}
++
+ 		/* xorg-x11-drv-libinput */
+ 		if ((XIGetProperty (display, gdk_x11_device_get_id (device), prop_scroll_methods,
+                                     0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems,
+diff --git a/panels/mouse/gnome-mouse-properties.c b/panels/mouse/gnome-mouse-properties.c
+index a648b9d..6fee407 100644
+--- a/panels/mouse/gnome-mouse-properties.c
++++ b/panels/mouse/gnome-mouse-properties.c
+@@ -80,12 +80,8 @@ setup_touchpad_options (CcMousePropertiesPrivate *d)
+ 	gboolean have_edge_scrolling;
+ 	gboolean have_tap_to_click;
+ 
+-	gtk_widget_set_visible (WID ("touchpad-frame"), !d->have_synaptics);
+-	if (d->have_synaptics)
+-		return;
+-
+-	gtk_widget_set_visible (WID ("touchpad-frame"), d->have_touchpad);
+-	if (!d->have_touchpad)
++	gtk_widget_set_visible (WID ("touchpad-frame"), d->have_touchpad || d->have_synaptics);
++	if (!d->have_touchpad && !d->have_synaptics)
+ 		return;
+ 
+ 	cc_touchpad_check_capabilities (&have_two_finger_scrolling, &have_edge_scrolling, &have_tap_to_click);
+-- 
+2.8.1
+
Index: debian/patches/series
===================================================================
--- debian/patches/series	(révision 49289)
+++ debian/patches/series	(copie de travail)
@@ -1,3 +1,4 @@
 01_menu_category.patch
 06_handle_passwd_with_ldap.patch
 07_polkit_wheel_sudo_group.patch
+Revert-mouse-Drop-unused-synaptics-capabilities-chec.patch

Reply to: