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 <hert...@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?= <hert...@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?= <hert...@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. + +[hert...@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 <hert...@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?= <hert...@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