1
0
gnome-settings-daemon/gnome-settings-daemon-revert-libinput-mandatory.patch
Dominique Leuenberger 8748e8fe2a Accepting request 510030 from home:zhangxiaofei:branches:GNOME:Factory
- Update SLE patches:
  + gnome-settings-daemon-bnc873545-hide-warnings.patch
  + gnome-settings-daemon-bring-back-updates-plugin.patch
  + gnome-settings-daemon-revert-libinput-mandatory.patch
-  Cleanup specfile.

OBS-URL: https://build.opensuse.org/request/show/510030
OBS-URL: https://build.opensuse.org/package/show/GNOME:Factory/gnome-settings-daemon?expand=0&rev=287
2017-07-13 08:57:22 +00:00

2017 lines
72 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From f5aa66f135c9e7e9c57363c8933e6a87d0900112 Mon Sep 17 00:00:00 2001
From: Frederic Crozat <fcrozat@suse.com>
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 <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 (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 <fcrozat@suse.com>
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 <device ID> <device name>
+ * 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;
gboolean has_mouse;
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 <fcrozat@suse.com>
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 @@
<child name="keyboard" schema="org.gnome.settings-daemon.peripherals.keyboard"/>
<child name="mouse" schema="org.gnome.settings-daemon.peripherals.mouse"/>
<child name="touchscreen" schema="org.gnome.settings-daemon.peripherals.touchscreen"/>
+ <child name="input-devices" schema="org.gnome.settings-daemon.peripherals.input-devices"/>
</schema>
<schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.peripherals.smartcard" path="/org/gnome/settings-daemon/peripherals/smartcard/">
<key name="removal-action" enum="org.gnome.settings-daemon.GsdSmartcardRemovalAction">
@@ -67,6 +68,13 @@
<_summary>Whether the tablets orientation is locked, or rotated automatically.</_summary>
</key>
</schema>
+ <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.peripherals.input-devices" path="/org/gnome/settings-daemon/peripherals/input-devices/">
+ <key name="hotplug-command" type="s">
+ <default>''</default>
+ <_summary>Device hotplug custom command</_summary>
+ <_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.</_description>
+ </key>
+ </schema>
<!-- Deprecated schemas/keys -->
<schema id="org.gnome.settings-daemon.peripherals.mouse.deprecated">
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
@@ -64,6 +64,9 @@ gsd_test_input_helper_SOURCES = test-input-helper.c
gsd_test_input_helper_LDADD = libcommon.la
gsd_test_input_helper_CFLAGS = $(libcommon_la_CFLAGS)
+scriptsdir = $(datadir)/gnome-settings-daemon-@GSD_API_VERSION@
+scripts_DATA = input-device-example.sh
+
EXTRA_DIST = $(scripts_DATA) daemon-skeleton.h daemon-skeleton-gtk.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] <device name>
+# added ... device was just plugged in
+# present.. device was present at gnome-settings-daemon startup
+# removed.. device was just removed
+# -i <device ID>
+# device ID being the XInput device ID
+# <device name> 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