diff --git a/gnome-settings-daemon-3.18.2.tar.xz b/gnome-settings-daemon-3.18.2.tar.xz
deleted file mode 100644
index 16a21b6..0000000
--- a/gnome-settings-daemon-3.18.2.tar.xz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3071c7258f22684f7f64b7f735821e4cb25f59fc4665eb08e8d86b560e72fc6f
-size 1626400
diff --git a/gnome-settings-daemon-3.20.0.tar.xz b/gnome-settings-daemon-3.20.0.tar.xz
new file mode 100644
index 0000000..fb9ee40
--- /dev/null
+++ b/gnome-settings-daemon-3.20.0.tar.xz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bb2e40b3566f9014315765fc4d40f749ccf284727277294cdfb7707ced162c6c
+size 1648780
diff --git a/gnome-settings-daemon-bnc462640-mute-action.patch b/gnome-settings-daemon-bnc462640-mute-action.patch
deleted file mode 100644
index a2338ab..0000000
--- a/gnome-settings-daemon-bnc462640-mute-action.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-Index: plugins/media-keys/gsd-media-keys-manager.c
-===================================================================
---- plugins/media-keys/gsd-media-keys-manager.c.orig
-+++ plugins/media-keys/gsd-media-keys-manager.c
-@@ -1211,6 +1211,7 @@ do_sound_action (GsdMediaKeysManager *ma
- {
- GvcMixerStream *stream;
- gboolean old_muted, new_muted;
-+ gboolean toggle_mute;
- guint old_vol, new_vol, norm_vol_step;
- gboolean sound_changed;
-
-@@ -1239,7 +1240,11 @@ do_sound_action (GsdMediaKeysManager *ma
-
- switch (type) {
- case MUTE_KEY:
-- new_muted = !old_muted;
-+ toggle_mute = g_settings_get_boolean (manager->priv->settings, "toggle-mute");
-+ if (toggle_mute)
-+ new_muted = !old_muted;
-+ else
-+ new_muted = TRUE;
- break;
- case VOLUME_DOWN_KEY:
- if (old_vol <= norm_vol_step) {
-Index: data/gnome-settings-daemon.convert
-===================================================================
---- data/gnome-settings-daemon.convert.orig
-+++ data/gnome-settings-daemon.convert
-@@ -57,6 +57,7 @@ volume-down = /apps/gnome_settings_daemo
- volume-mute = /apps/gnome_settings_daemon/keybindings/volume_mute
- volume-up = /apps/gnome_settings_daemon/keybindings/volume_up
- www = /apps/gnome_settings_daemon/keybindings/www
-+toggle-mute = /apps/gnome_settings_daemon/toggle_mute
-
- [org.gnome.settings-daemon.plugins.mouse]
- active = /apps/gnome_settings_daemon/plugins/mouse/active
-Index: data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in.in
-===================================================================
---- data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in.in.orig
-+++ data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in.in
-@@ -185,6 +185,11 @@
- Maximum length of screen recordings
- The maximum length of single screen cast recordings in seconds or 0 for unlimited
-
-+
-+ true
-+ <_summary>Toggle Mute
-+ <_description>Toggle the sound mixer's mute status when then mute button is pressed.
-+
-
-
-
diff --git a/gnome-settings-daemon-bnc873545-hide-warnings.patch b/gnome-settings-daemon-bnc873545-hide-warnings.patch
new file mode 100644
index 0000000..dc32170
--- /dev/null
+++ b/gnome-settings-daemon-bnc873545-hide-warnings.patch
@@ -0,0 +1,41 @@
+From fd0df3003ba7c0ae4d04a8314358db7f82dd2ab1 Mon Sep 17 00:00:00 2001
+From: Felix Zhang
+Date: Tue, 6 May 2014 16:13:04 +0800
+Subject: [PATCH] hide warnings
+
+---
+ plugins/color/gsd-color-profiles.c | 2 ++
+ plugins/color/gsd-color-state.c | 2 ++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/plugins/color/gsd-color-profiles.c b/plugins/color/gsd-color-profiles.c
+index 2b01faa..05a728a 100644
+--- a/plugins/color/gsd-color-profiles.c
++++ b/plugins/color/gsd-color-profiles.c
+@@ -71,7 +71,9 @@ gcm_session_client_connect_cb (GObject *source_object,
+ /* is there an available colord instance? */
+ ret = cd_client_get_has_server (profiles->priv->client);
+ if (!ret) {
++ /* hide this warning for SLES
+ g_warning ("There is no colord server available");
++ */
+ return;
+ }
+
+diff --git a/plugins/color/gsd-color-state.c b/plugins/color/gsd-color-state.c
+index 04823e4..20e8a2b 100644
+--- a/plugins/color/gsd-color-state.c
++++ b/plugins/color/gsd-color-state.c
+@@ -1297,7 +1297,9 @@ gcm_session_client_connect_cb (GObject *source_object,
+ /* is there an available colord instance? */
+ ret = cd_client_get_has_server (state->priv->client);
+ if (!ret) {
++ /* hide this warning for SLES
+ g_warning ("There is no colord server available");
++ */
+ goto out;
+ }
+
+--
+1.7.12.4
+
diff --git a/gnome-settings-daemon-dont-override-xim-presets.patch b/gnome-settings-daemon-dont-override-xim-presets.patch
deleted file mode 100644
index 41cdb98..0000000
--- a/gnome-settings-daemon-dont-override-xim-presets.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From: Takashi Iwai
-Subject: Don't override preset xim setups
-References: boo#947576
-
-When $QT_IM_MODULE or $XMODIFIERS has been already set beforehand,
-we should honor it and not override brutally. This makes GNOME as
-a good citizen coping with other IMs more smoothly.
-
-Signed-off-by: Takashi Iwai
-
----
- gnome-settings-daemon/gnome-settings-daemon-localeexec.in | 4 ++--
- gnome-settings-daemon/main.c | 11 +++++++++--
- 2 files changed, 11 insertions(+), 4 deletions(-)
-
---- a/gnome-settings-daemon/gnome-settings-daemon-localeexec.in
-+++ b/gnome-settings-daemon/gnome-settings-daemon-localeexec.in
-@@ -13,8 +13,8 @@ if [ -n "$REGION" ]; then
- fi
-
- if [ -x @prefix@/bin/ibus-daemon ]; then
-- export QT_IM_MODULE=ibus
-- export XMODIFIERS=@im=ibus
-+ test -z "$QT_IM_MODULE" && export QT_IM_MODULE=ibus
-+ test -z "$XMODIFIERS" && export XMODIFIERS=@im=ibus
- fi
-
- exec @libexecdir@/gnome-settings-daemon
---- a/gnome-settings-daemon/main.c
-+++ b/gnome-settings-daemon/main.c
-@@ -255,9 +255,16 @@ is_program_in_path (const char *binary)
- static void
- set_legacy_ibus_env_vars (GDBusProxy *proxy)
- {
-+ const char *p;
- if (is_program_in_path ("ibus-daemon")) {
-- set_session_env (proxy, "QT_IM_MODULE", "ibus");
-- set_session_env (proxy, "XMODIFIERS", "@im=ibus");
-+ p = getenv ("QT_IM_MODULE");
-+ if (!p || !*p)
-+ p = "ibus";
-+ set_session_env (proxy, "QT_IM_MODULE", p);
-+ p = getenv ("XMODIFIERS");
-+ if (!p || !*p)
-+ p = "@im=ibus";
-+ set_session_env (proxy, "XMODIFIERS", p);
- }
- }
-
diff --git a/gnome-settings-daemon-revert-libinput-mandatory.patch b/gnome-settings-daemon-revert-libinput-mandatory.patch
new file mode 100644
index 0000000..8d1d65e
--- /dev/null
+++ b/gnome-settings-daemon-revert-libinput-mandatory.patch
@@ -0,0 +1,2015 @@
+From f5aa66f135c9e7e9c57363c8933e6a87d0900112 Mon Sep 17 00:00:00 2001
+From: Frederic Crozat
+Date: Fri, 4 Mar 2016 15:47:30 +0100
+Subject: [PATCH 1/3] Revert "mouse: Remove support for non-libinput mouse
+ configurations"
+
+This reverts commit 66c211ff24bec6a938d6a6a0dd8730f4689ef383.
+---
+ plugins/mouse/gsd-mouse-manager.c | 1255 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 1252 insertions(+), 3 deletions(-)
+
+diff --git a/plugins/mouse/gsd-mouse-manager.c b/plugins/mouse/gsd-mouse-manager.c
+index cf2c28c..da7b378 100644
+--- a/plugins/mouse/gsd-mouse-manager.c
++++ b/plugins/mouse/gsd-mouse-manager.c
+@@ -19,17 +19,39 @@
+
+ #include "config.h"
+
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#ifdef __linux
++#include
++#endif
++
+ #include
+
+ #include
+ #include
+ #include
++#include
++#include
++#include
++#include
++#include
++#include
+
+ #include
+
++#include
++#include
++
+ #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 (GsdMouseManagerClass *klass)
+ 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,418 @@ set_mousetweaks_daemon (GsdMouseManager *manager,
+ 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) {
++ if (run_custom_command (device, COMMAND_DEVICE_ADDED) == FALSE) {
++ set_mouse_settings (manager, device);
++ } else {
++ int id;
++ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++ g_hash_table_insert (manager->priv->blacklist,
++ GINT_TO_POINTER (id), GINT_TO_POINTER (1));
++ }
++
++ 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) {
++ run_custom_command (device, COMMAND_DEVICE_REMOVED);
++
++ 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 +1381,46 @@ gsd_mouse_manager_idle_cb (GsdMouseManager *manager)
+ 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;
++
++ if (run_custom_command (device, COMMAND_DEVICE_PRESENT) == FALSE) {
++ set_mouse_settings (manager, device);
++ } else {
++ int id;
++ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
++ g_hash_table_insert (manager->priv->blacklist,
++ GINT_TO_POINTER (id), GINT_TO_POINTER (1));
++ }
++ }
++ g_list_free (devices);
++
++ ensure_touchpad_active (manager);
++
+ gnome_settings_profile_end (NULL);
+
+ manager->priv->start_idle_id = 0;
+@@ -202,6 +1436,11 @@ gsd_mouse_manager_start (GsdMouseManager *manager,
+
+ 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 +1464,16 @@ gsd_mouse_manager_stop (GsdMouseManager *manager)
+ 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 +1493,9 @@ gsd_mouse_manager_finalize (GObject *object)
+
+ 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);
+ }
+
+--
+2.6.2
+
+
+From 4b1ed6c7aec9dea2b70fe19c0156fed72899eba6 Mon Sep 17 00:00:00 2001
+From: Frederic Crozat
+Date: Fri, 4 Mar 2016 15:49:20 +0100
+Subject: [PATCH 2/3] Revert "common: Remove unused functions"
+
+This reverts commit 9287ef9ac5b119abdcbbabd920c19f353e577f90.
+---
+ plugins/common/gsd-input-helper.c | 279 +++++++++++++++++++++++++++++++++++++
+ plugins/common/gsd-input-helper.h | 15 ++
+ plugins/common/test-input-helper.c | 5 +-
+ 3 files changed, 298 insertions(+), 1 deletion(-)
+
+diff --git a/plugins/common/gsd-input-helper.c b/plugins/common/gsd-input-helper.c
+index 077ff1c..4dca795 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,172 @@ 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;
++}
++
++static const char *
++custom_command_to_string (CustomCommand command)
++{
++ switch (command) {
++ case COMMAND_DEVICE_ADDED:
++ return "added";
++ case COMMAND_DEVICE_REMOVED:
++ return "removed";
++ case COMMAND_DEVICE_PRESENT:
++ return "present";
++ default:
++ g_assert_not_reached ();
++ }
++}
++
++/* Run a custom command on device presence events. Parameters passed into
++ * the custom command are:
++ * command -t [added|removed|present] -i
++ * Type 'added' and 'removed' signal 'device added' and 'device removed',
++ * respectively. Type 'present' signals 'device present at
++ * gnome-settings-daemon init'.
++ *
++ * The script is expected to run synchronously, and an exit value
++ * of "1" means that no other settings will be applied to this
++ * particular device.
++ *
++ * More options may be added in the future.
++ *
++ * This function returns TRUE if we should not apply any more settings
++ * to the device.
++ */
++gboolean
++run_custom_command (GdkDevice *device,
++ CustomCommand command)
++{
++ GSettings *settings;
++ GError *error = NULL;
++ char *cmd;
++ char *argv[7];
++ int exit_status;
++ gboolean rc;
++ int id;
++ char *out;
++
++ settings = g_settings_new (INPUT_DEVICES_SCHEMA);
++ cmd = g_settings_get_string (settings, KEY_HOTPLUG_COMMAND);
++ g_object_unref (settings);
++
++ if (!cmd || cmd[0] == '\0') {
++ g_free (cmd);
++ return FALSE;
++ }
++
++ /* Easter egg! */
++ g_object_get (device, "device-id", &id, NULL);
++
++ argv[0] = cmd;
++ argv[1] = "-t";
++ argv[2] = (char *) custom_command_to_string (command);
++ argv[3] = "-i";
++ argv[4] = g_strdup_printf ("%d", id);
++ argv[5] = (char*) gdk_device_get_name (device);
++ argv[6] = NULL;
++
++ out = g_strjoinv (" ", argv);
++ g_debug ("About to launch command: %s", out);
++ g_free (out);
++
++ rc = g_spawn_sync (g_get_home_dir (), argv, NULL, G_SPAWN_SEARCH_PATH,
++ NULL, NULL, NULL, NULL, &exit_status, &error);
++
++ if (rc == FALSE) {
++ g_warning ("Couldn't execute command '%s', verify that this is a valid command: %s", cmd, error->message);
++ g_clear_error (&error);
++ }
++
++ g_free (argv[0]);
++ g_free (argv[4]);
++
++ if (!g_spawn_check_exit_status (exit_status, &error)) {
++ if (g_error_matches (error, G_SPAWN_EXIT_ERROR, 1)) {
++ g_clear_error (&error);
++ return TRUE;
++ }
++ g_clear_error (&error);
++ }
++
++ return FALSE;
++}
++
++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 +680,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..85e6d07 100644
+--- a/plugins/common/gsd-input-helper.h
++++ b/plugins/common/gsd-input-helper.h
+@@ -44,20 +44,32 @@ 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);
+
++gboolean run_custom_command (GdkDevice *device,
++ CustomCommand command);
++
++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 +79,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.6.2
+
+
+From 2e27aeec3c5bcb9fe398bd3835226f261b60baf1 Mon Sep 17 00:00:00 2001
+From: Frederic Crozat
+Date: Fri, 4 Mar 2016 15:51:23 +0100
+Subject: [PATCH 3/3] Revert "common: Remove "hotplug-command" helper"
+
+This reverts commit c50ceb880e928506d987747f9e554079ad3d9826.
+---
+ ...e.settings-daemon.peripherals.gschema.xml.in.in | 8 +++
+ plugins/common/Makefile.am | 3 +
+ plugins/common/gsd-input-helper.c | 3 +
+ plugins/common/gsd-input-helper.h | 6 ++
+ plugins/common/input-device-example.sh | 69 ++++++++++++++++++++++
+ plugins/keyboard/gsd-keyboard-manager.c | 18 ++++++
+ 6 files changed, 107 insertions(+)
+ create mode 100644 plugins/common/input-device-example.sh
+
+diff --git a/data/org.gnome.settings-daemon.peripherals.gschema.xml.in.in b/data/org.gnome.settings-daemon.peripherals.gschema.xml.in.in
+index f4120e9..6a65f08 100644
+--- a/data/org.gnome.settings-daemon.peripherals.gschema.xml.in.in
++++ b/data/org.gnome.settings-daemon.peripherals.gschema.xml.in.in
+@@ -4,6 +4,7 @@
+
+
+
++
+
+
+
+@@ -67,6 +68,13 @@
+ <_summary>Whether the tablet's orientation is locked, or rotated automatically.
+
+
++
++
++ ''
++ <_summary>Device hotplug custom command
++ <_description>Command to be run when a device is added or removed. An exit value of 1 means that the device will not be handled further by gnome-settings-daemon.
++
++
+
+
+
+diff --git a/plugins/common/Makefile.am b/plugins/common/Makefile.am
+index 0331226..0f85351 100644
+--- a/plugins/common/Makefile.am
++++ b/plugins/common/Makefile.am
+@@ -82,6 +82,9 @@ test_egg_key_parsing_SOURCES = test-egg-key-parsing.c
+ test_egg_key_parsing_LDADD = libcommon.la $(COMMON_LIBS)
+ test_egg_key_parsing_CFLAGS = $(libcommon_la_CFLAGS)
+
++scriptsdir = $(datadir)/gnome-settings-daemon-@GSD_API_VERSION@
++scripts_DATA = input-device-example.sh
++
+ EXTRA_DIST = $(scripts_DATA) test-plugin.h
+
+ CLEANFILES = \
+diff --git a/plugins/common/gsd-input-helper.c b/plugins/common/gsd-input-helper.c
+index 4dca795..e3fe2d8 100644
+--- a/plugins/common/gsd-input-helper.c
++++ b/plugins/common/gsd-input-helper.c
+@@ -31,6 +31,9 @@
+ #include "gsd-input-helper.h"
+ #include "gsd-device-manager.h"
+
++#define INPUT_DEVICES_SCHEMA "org.gnome.settings-daemon.peripherals.input-devices"
++#define KEY_HOTPLUG_COMMAND "hotplug-command"
++
+ #define ABS_MT_X "Abs MT Position X"
+ #define ABS_MT_Y "Abs MT Position Y"
+ #define ABS_X "Abs X"
+diff --git a/plugins/common/gsd-input-helper.h b/plugins/common/gsd-input-helper.h
+index 85e6d07..aadd790 100644
+--- a/plugins/common/gsd-input-helper.h
++++ b/plugins/common/gsd-input-helper.h
+@@ -28,6 +28,12 @@ G_BEGIN_DECLS
+
+ #define WACOM_SERIAL_IDS_PROP "Wacom Serial IDs"
+
++typedef enum {
++ COMMAND_DEVICE_ADDED,
++ COMMAND_DEVICE_REMOVED,
++ COMMAND_DEVICE_PRESENT
++} CustomCommand;
++
+ /* Generic property setting code. Fill up the struct property with the property
+ * data and pass it into device_set_property together with the device to be
+ * changed. Note: doesn't cater for non-zero offsets yet, but we don't have
+diff --git a/plugins/common/input-device-example.sh b/plugins/common/input-device-example.sh
+new file mode 100644
+index 0000000..235cdc4
+--- /dev/null
++++ b/plugins/common/input-device-example.sh
+@@ -0,0 +1,69 @@
++#!/bin/sh
++#
++# This script is an example hotplug script for use with the various
++# input devices plugins.
++#
++# The script is called with the arguments:
++# -t [added|present|removed]
++# added ... device was just plugged in
++# present.. device was present at gnome-settings-daemon startup
++# removed.. device was just removed
++# -i
++# device ID being the XInput device ID
++# The name of the device
++#
++# The script should return 1 if the device is to be
++# ignored from future configuration.
++#
++# Set the script to be used with:
++# gsettings set org.gnome.settings-daemon.peripherals.input-devices hotplug-command /path/to/script/input-devices.sh
++#
++
++args=`getopt "t:i:" $*`
++
++set -- $args
++
++while [ $# -gt 0 ]
++do
++ case $1 in
++ -t)
++ shift;
++ type="$1"
++ ;;
++ -i)
++ shift;
++ id="$1"
++ ;;
++ --)
++ shift;
++ device="$@"
++ break;
++ ;;
++ *)
++ echo "Unknown option $1";
++ exit 1
++ ;;
++ esac
++ shift
++done
++
++retval=0
++
++case $type in
++ added)
++ echo "Device '$device' (ID=$id) was added"
++ ;;
++ present)
++ echo "Device '$device' (ID=$id) was already present at startup"
++ ;;
++ removed)
++ echo "Device '$device' (ID=$id) was removed"
++ ;;
++ *)
++ echo "Unknown operation"
++ retval=1
++ ;;
++esac
++
++# All further processing will be disabled if $retval == 1
++exit $retval
+diff --git a/plugins/keyboard/gsd-keyboard-manager.c b/plugins/keyboard/gsd-keyboard-manager.c
+index ddeeee6..eb75c92 100644
+--- a/plugins/keyboard/gsd-keyboard-manager.c
++++ b/plugins/keyboard/gsd-keyboard-manager.c
+@@ -90,6 +90,7 @@ struct GsdKeyboardManagerPrivate
+ GsdNumLockState old_state;
+ GdkDeviceManager *device_manager;
+ guint device_added_id;
++ guint device_removed_id;
+ };
+
+ static void gsd_keyboard_manager_class_init (GsdKeyboardManagerClass *klass);
+@@ -363,6 +364,20 @@ device_added_cb (GdkDeviceManager *device_manager,
+ if (source == GDK_SOURCE_KEYBOARD) {
+ g_debug ("New keyboard plugged in, applying all settings");
+ apply_numlock (manager);
++ run_custom_command (device, COMMAND_DEVICE_ADDED);
++ }
++}
++
++static void
++device_removed_cb (GdkDeviceManager *device_manager,
++ GdkDevice *device,
++ GsdKeyboardManager *manager)
++{
++ GdkInputSource source;
++
++ source = gdk_device_get_source (device);
++ if (source == GDK_SOURCE_KEYBOARD) {
++ run_custom_command (device, COMMAND_DEVICE_REMOVED);
+ }
+ }
+
+@@ -378,6 +393,8 @@ set_devicepresence_handler (GsdKeyboardManager *manager)
+
+ 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;
+ }
+
+@@ -758,6 +775,7 @@ gsd_keyboard_manager_stop (GsdKeyboardManager *manager)
+
+ 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;
+ }
+
+--
+2.6.2
+
diff --git a/gnome-settings-daemon.changes b/gnome-settings-daemon.changes
index f5d0429..174236d 100644
--- a/gnome-settings-daemon.changes
+++ b/gnome-settings-daemon.changes
@@ -1,3 +1,121 @@
+-------------------------------------------------------------------
+Mon Mar 21 15:09:07 UTC 2016 - dimstar@opensuse.org
+
+- Update to version 3.20.0:
+ + Fix cancellation handling and possible crashes in all plugins.
+
+-------------------------------------------------------------------
+Fri Mar 18 17:53:18 UTC 2016 - fezhang@suse.com
+
+- Add gnome-settings-daemon-bnc873545-hide-warnings.patch: Hide the
+ warnings when failed to find a colord instance on SLES
+ (bnc873545).
+
+-------------------------------------------------------------------
+Thu Mar 17 09:53:38 UTC 2016 - dimstar@opensuse.org
+
+- Update to version 3.19.92:
+ + XSettings: Export Gtk/KeynavUseCaret accessibility setting.
+ + Remote display: Remove Spice special-casing now that it can do
+ accelerated rendering.
+
+-------------------------------------------------------------------
+Fri Mar 4 12:57:15 UTC 2016 - fcrozat@suse.com
+
+- Add gnome-settings-daemon-revert-libinput-mandatory.patch: do not
+ force libinput driver on SLE.
+- Re-add "hotplug-command" helper when building for SLE.
+
+-------------------------------------------------------------------
+Thu Mar 3 21:57:28 UTC 2016 - zaitor@opensuse.org
+
+- Update to version 3.19.91:
+ + Media keys:
+ - Fix a typo in the "Airplane" string.
+ - Fix a number of possible crashers when plugging in audio
+ devices on some machines.
+ - Add debug output to a number of custom shortcuts related
+ functions.
+ + Housekeeping: Don't remove X11 sockets, breaking sandboxed X11
+ applications.
+ + Updated translations.
+
+-------------------------------------------------------------------
+Wed Mar 2 14:33:56 UTC 2016 - fcrozat@suse.com
+
+- Add BuildRequires pkgconfig(alsa) and --enable-alsa to configure
+ to ensure audio device selection feature is properly enabled.
+
+-------------------------------------------------------------------
+Tue Feb 16 20:35:11 UTC 2016 - zaitor@opensuse.org
+
+- Update to version 3.19.90:
+ + Fixed a few leaks, crashes and endless loops.
+ + Media keys:
+ - Fix orientation keybindings/keys not working.
+ - Added support to ask users which kind of headset was plugged
+ in.
+ + Updated translations.
+
+-------------------------------------------------------------------
+Sun Feb 14 23:05:02 UTC 2016 - zaitor@opensuse.org
+
+- Add xf86-input-libinput Recommends and apply conditionally on
+ openSUSE: gnome-settings-daemon only support configuration of
+ libinput based pointer drivers since version 3.19.5.
+
+-------------------------------------------------------------------
+Fri Feb 12 15:07:00 UTC 2016 - zaitor@opensuse.org
+
+- Change gnome-settings-daemon-notify-idle-resumed.patch to
+ PATCH-FEATURE-SLE, and only apply it and run autoreconf when
+ building for SLE. It is not needed in openSUSE.
+- Drop gnome-settings-daemon-bnc462640-mute-action.patch: People
+ expect mute to always toogle now, so drop this patch.
+- No longer obsolete resapplet, not been in use since before 2008.
+
+-------------------------------------------------------------------
+Wed Jan 20 15:13:46 UTC 2016 - dimstar@opensuse.org
+
+- Update to version 3.19.5:
+ + Remove "hotplug-command" helper
+ + Media keys:
+ - Add support for Killswitch media keys
+ - Add labels for the rfkill OSD
+ + Mouse: Remove support for non-libinput mouse configurations.
+ + Power: Don't try to automatically set brightness on inactive
+ sessions.
+ + Rfkill: Fix a problem when the system has a platform rfkill
+ device for Bluetooth and the Bluetooth adapter's rfkill support
+ somehow got blocked.
+ + Sharing: Port to the new libnm NetworkManager library; required
+ NM version bumped to 1.0.
+ + Updated translations.
+- Replace pkgconfig(libnm-glib) and pkgconfig(libnm-util)
+ BuildRequires with pkgconfig(libnm): following upstreams changes.
+
+-------------------------------------------------------------------
+Sun Dec 20 12:04:15 UTC 2015 - zaitor@opensuse.org
+
+- Update to version 3.19.4:
+ + Mouse:
+ - Force 2-finger scroll by default if available.
+ - Migrate scroll-method key to new edge-scrolling-enabled key.
+- Changes from version 3.19.3:
+ + Export the cursor theme through XSettings.
+ + Use the convenience Geoclue library for the automatic timezone
+ setting.
+ + Don't overwrite existing XIM configurations.
+ + Fix application of left-handed mode, keep-aspect and area
+ settings for Wacom tablets.
+ + Change default font hinting to slight (see git log for
+ details).
+ + Re-add a way to configure the power button for desktops and
+ laptops (tablets and VMs have hard-coded defaults).
+ + Always expand power notifications.
+- Drop gnome-settings-daemon-dont-override-xim-presets.patch: Fixed
+ upstream.
+
-------------------------------------------------------------------
Tue Nov 10 16:00:08 UTC 2015 - zaitor@opensuse.org
diff --git a/gnome-settings-daemon.spec b/gnome-settings-daemon.spec
index 6f8d55b..5354fd4 100644
--- a/gnome-settings-daemon.spec
+++ b/gnome-settings-daemon.spec
@@ -1,7 +1,7 @@
#
# spec file for package gnome-settings-daemon
#
-# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -30,30 +30,33 @@
%endif
Name: gnome-settings-daemon
-Version: 3.18.2
+Version: 3.20.0
Release: 0
Summary: Settings daemon for the GNOME desktop
License: GPL-2.0+
Group: System/GUI/GNOME
Url: http://www.gnome.org
-Source: http://download.gnome.org/sources/gnome-settings-daemon/3.18/%{name}-%{version}.tar.xz
-# PATCH-FEATURE-UPSTREAM gnome-settings-daemon-bnc462640-mute-action.patch bnc462640 bgo572365 vuntz@novell.com -- Mute button should always mute sound instead of toggling mute status
-Patch10: gnome-settings-daemon-bnc462640-mute-action.patch
-# PATCH-FEATURE-UPSTREAM gnome-settings-daemon-notify-idle-resumed.patch bnc#439018 bnc#708182 bgo#575467 hpj@suse.com -- notify user about auto suspend when returning from sleep
-Patch19: gnome-settings-daemon-notify-idle-resumed.patch
-# PATCH-FIX-UPSTREAM gnome-settings-daemon-dont-override-xim-presets.patch boo#947576 bgo#757013 tiwai@suse.com -- Don't overwrite XIM presets
-Patch20: gnome-settings-daemon-dont-override-xim-presets.patch
+Source: http://download.gnome.org/sources/gnome-settings-daemon/3.20/%{name}-%{version}.tar.xz
+# PATCH-FEATURE-SLE gnome-settings-daemon-revert-libinput-mandatory.patch fcrozat@suse.com -- ensure libinput is not mandatory
+Patch20: gnome-settings-daemon-revert-libinput-mandatory.patch
+# PATCH-FEATURE-SLE gnome-settings-daemon-notify-idle-resumed.patch bnc#439018 bnc#708182 bgo#575467 hpj@suse.com -- notify user about auto suspend when returning from sleep
+Patch21: gnome-settings-daemon-notify-idle-resumed.patch
+# PATCH-FIX-SLE gnome-settings-daemon-bnc873545-hide-warnings.patch bnc#873545 fezhang@suse.com -- hide the warnings when g-s-d cannot find colord running, which is expected on SLES
+Patch22: gnome-settings-daemon-bnc873545-hide-warnings.patch
BuildRequires: cups-devel
BuildRequires: fdupes
BuildRequires: gnome-common
-# Disabled because of the non-rebased patches
+%if !0%{?is_opensuse}
+# Disabled because of the non-rebased patch
#BuildRequires: gnome-patch-translation
-BuildRequires: intltool
BuildRequires: translation-update-upstream
+%endif
+BuildRequires: intltool
BuildRequires: update-desktop-files
BuildRequires: xsltproc
# For directory ownership; it's fine to BuildRequire it since it's also a Requires
BuildRequires: polkit
+BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(colord) >= 1.0.2
BuildRequires: pkgconfig(fontconfig)
BuildRequires: pkgconfig(gconf-2.0) >= 2.6.1
@@ -61,15 +64,14 @@ BuildRequires: pkgconfig(geoclue-2.0) >= 2.1.2
BuildRequires: pkgconfig(geocode-glib-1.0) >= 3.10.0
BuildRequires: pkgconfig(glib-2.0) >= 2.37.7
BuildRequires: pkgconfig(gnome-desktop-3.0) >= 3.11.1
-BuildRequires: pkgconfig(gsettings-desktop-schemas) >= 3.15.4
-BuildRequires: pkgconfig(gtk+-3.0) >= 3.15.1
+BuildRequires: pkgconfig(gsettings-desktop-schemas) >= 3.19.3
+BuildRequires: pkgconfig(gtk+-3.0) >= 3.15.3
BuildRequires: pkgconfig(gudev-1.0)
BuildRequires: pkgconfig(gweather-3.0) >= 3.9.5
BuildRequires: pkgconfig(kbproto)
BuildRequires: pkgconfig(lcms2)
BuildRequires: pkgconfig(libcanberra-gtk3)
-BuildRequires: pkgconfig(libnm-glib) >= 0.9.9.1
-BuildRequires: pkgconfig(libnm-util) >= 0.9.9.1
+BuildRequires: pkgconfig(libnm) >= 1.0
BuildRequires: pkgconfig(libnotify) >= 0.7.3
BuildRequires: pkgconfig(libpulse) >= 2.0
BuildRequires: pkgconfig(libpulse-mainloop-glib) >= 2.0
@@ -96,7 +98,10 @@ Requires: polkit
Recommends: %{name}-lang
# For housekeeping plugin, that uses the nautilus dbus service
Recommends: nautilus
-Obsoletes: resapplet
+%if 0%{?is_opensuse}
+# g-s-d only support configurtion of libinput based pointer drivers now.
+Recommends: xf86-input-libinput
+%endif
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%glib2_gsettings_schema_requires
@@ -126,21 +131,28 @@ contact the settings daemon via its DBus interface.
%lang_package
%prep
%setup -q
+%if !0%{?is_opensuse}
translation-update-upstream
-# Disabled because of the non-rebased patches
+# Disabled because of the non-rebased patch
#gnome-patch-translation-prepare
-%patch10 -p0
-%patch19 -p1
%patch20 -p1
+%patch21 -p1
+%endif
+%if 0%{?sles_version} > 0
+%patch22 -p1
+%endif
%build
+%if !0%{?is_opensuse}
autoreconf -f -i
+%endif
%configure\
%if %{with wayland}
--enable-wayland \
%else
--disable-wayland \
%endif
+ --enable-alsa \
--disable-static \
--libexecdir=%{_libexecdir}/gnome-settings-daemon-3.0 \
%{nil}
@@ -170,7 +182,9 @@ rm -rf %{buildroot}
%defattr(-,root,root)
%doc AUTHORS COPYING ChangeLog NEWS
%{_datadir}/gnome-settings-daemon/
+%if !0%{?is_opensuse}
%{_datadir}/gnome-settings-daemon-3.0/
+%endif
%dir %{_libexecdir}/gnome-settings-daemon-3.0/
%{_libexecdir}/gnome-settings-daemon-3.0/gnome-settings-daemon
%{_libexecdir}/gnome-settings-daemon-3.0/gnome-settings-daemon-localeexec