2016 lines
72 KiB
Diff
2016 lines
72 KiB
Diff
|
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;
|
||
|
|
||
|
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 tablet's 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
|
||
|
@@ -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] <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
|
||
|
|