summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2014-10-26 14:27:16 +0100
committerBastien Nocera <hadess@hadess.net>2014-10-26 14:34:58 +0100
commit4f30831e0176a775f00b7af86bd19c664a68bc5c (patch)
treeee3d21b0f562e80ed48d1b2349815fc16bbcf087
parent6e22423362ffb36da0b576916b3bbcb0f26e3b74 (diff)
downloadgnome-settings-daemon-4f30831e0176a775f00b7af86bd19c664a68bc5c.tar.gz
mouse: Add scroll wheel emulation for trackballs
Some trackballs don't have a separate scroll wheel, so one of the buttons needs to be repurposed so pressing it will turn the main ball into a wheel. https://bugzilla.gnome.org/show_bug.cgi?id=645666
-rw-r--r--data/org.gnome.settings-daemon.peripherals.gschema.xml.in.in8
-rw-r--r--plugins/mouse/gsd-mouse-manager.c141
2 files changed, 149 insertions, 0 deletions
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 f1d16489..d2f70ed9 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="touchpad" schema="org.gnome.settings-daemon.peripherals.touchpad"/>
<child name="keyboard" schema="org.gnome.settings-daemon.peripherals.keyboard"/>
<child name="mouse" schema="org.gnome.settings-daemon.peripherals.mouse"/>
+ <child name="trackball" schema="org.gnome.settings-daemon.peripherals.trackball"/>
<child name="touchscreen" schema="org.gnome.settings-daemon.peripherals.touchscreen"/>
<child name="input-devices" schema="org.gnome.settings-daemon.peripherals.input-devices"/>
</schema>
@@ -149,6 +150,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.trackball" path="/org/gnome/settings-daemon/peripherals/trackball/">
+ <key name="scroll-wheel-emulation-button" type="i">
+ <default>0</default>
+ <range min="0" max="24"/>
+ <_summary>Mouse wheel emulation button. 0 to disable the feature.</_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>
diff --git a/plugins/mouse/gsd-mouse-manager.c b/plugins/mouse/gsd-mouse-manager.c
index 19698c60..60e77c25 100644
--- a/plugins/mouse/gsd-mouse-manager.c
+++ b/plugins/mouse/gsd-mouse-manager.c
@@ -55,6 +55,7 @@
#define SETTINGS_MOUSE_DIR "org.gnome.settings-daemon.peripherals.mouse"
#define SETTINGS_TOUCHPAD_DIR "org.gnome.settings-daemon.peripherals.touchpad"
+#define SETTINGS_TRACKBALL_DIR "org.gnome.settings-daemon.peripherals.trackball"
/* Keys for both touchpad and mouse */
#define KEY_LEFT_HANDED "left-handed" /* a boolean for mouse, an enum for touchpad */
@@ -75,12 +76,16 @@
#define KEY_SECONDARY_CLICK_ENABLED "secondary-click-enabled"
#define KEY_MIDDLE_BUTTON_EMULATION "middle-button-enabled"
+/* Trackball settings */
+#define KEY_SCROLL_WHEEL_BUTTON "scroll-wheel-emulation-button"
+
struct GsdMouseManagerPrivate
{
guint start_idle_id;
GSettings *touchpad_settings;
GSettings *mouse_settings;
GSettings *mouse_a11y_settings;
+ GSettings *trackball_settings;
GdkDeviceManager *device_manager;
guint device_added_id;
guint device_removed_id;
@@ -134,6 +139,38 @@ open_gdk_device (GdkDevice *device)
}
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)
{
@@ -988,6 +1025,83 @@ set_natural_scroll (GsdMouseManager *manager,
}
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;
+
+ 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;
+
+ gdk_error_trap_push ();
+ 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 void
set_mouse_settings (GsdMouseManager *manager,
GdkDevice *device)
{
@@ -1006,6 +1120,8 @@ set_mouse_settings (GsdMouseManager *manager,
set_natural_scroll (manager, device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_NATURAL_SCROLL_ENABLED));
if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED) == FALSE)
set_touchpad_disabled (device);
+
+ set_scroll_wheel_button (manager, device);
}
static void
@@ -1109,6 +1225,26 @@ touchpad_callback (GSettings *settings,
}
}
+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;
+
+ 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)
@@ -1202,6 +1338,10 @@ gsd_mouse_manager_idle_cb (GsdMouseManager *manager)
g_signal_connect (manager->priv->touchpad_settings, "changed",
G_CALLBACK (touchpad_callback), manager);
+ manager->priv->trackball_settings = g_settings_new (SETTINGS_TRACKBALL_DIR);
+ 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->mouse_settings, KEY_LOCATE_POINTER));
@@ -1288,6 +1428,7 @@ gsd_mouse_manager_stop (GsdMouseManager *manager)
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);
set_locate_pointer (manager, FALSE);
}