From 23c4ac6c7fecdd4eb70d64a8fbb6e4b25f5d03f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 7 Apr 2016 15:44:28 +0800 Subject: [PATCH] settings: Support mouse and trackball accel profile Support changing the mouse and trackball acceleration profile. This makes it possible to for example disable pointer acceleration by choosing the 'flat' profile. This adds an optional dependency on gudev. Gudev is used by the X11 backend to detect whether a device is a mouse or not. Without gudev support, the accel profile settings has have effect for mouse devices. Trackball still uses the "strstr" approach, since udev doesn't support tagging devices as trackball devices yet. https://bugzilla.gnome.org/show_bug.cgi?id=769179 --- configure.ac | 24 +++ src/backends/meta-input-settings-private.h | 9 + src/backends/meta-input-settings.c | 69 ++++++- .../native/meta-input-settings-native.c | 109 +++++++++++ src/backends/x11/meta-input-settings-x11.c | 169 +++++++++++++++++- 5 files changed, 375 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 8548d89bc..ae189847d 100644 --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,11 @@ AC_ARG_WITH(libwacom, [disable the use of libwacom for advanced tablet management]),, with_libwacom=auto) +AC_ARG_WITH(gudev, + AC_HELP_STRING([--without-gudev], + [disable the use of gudev for device type detection]),, + with_gudev=auto) + AC_ARG_WITH([xwayland-path], [AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])], [XWAYLAND_PATH="$withval"], @@ -195,6 +200,24 @@ else fi fi +have_gudev=no +AC_MSG_CHECKING([gudev]) +if test x$with_gudev = xno ; then + AC_MSG_RESULT([disabled]) +else + if $PKG_CONFIG --exists gudev-1.0; then + have_gudev=yes + AC_MSG_RESULT(yes) + MUTTER_PC_MODULES="$MUTTER_PC_MODULES gudev-1.0" + AC_DEFINE([HAVE_LIBGUDEV], 1, [Building with gudev for device type detection]) + else + AC_MSG_RESULT(no) + if test x$with_gudev = xyes ; then + AC_MSG_ERROR([gudev forced but not found]) + fi + fi +fi + INTROSPECTION_VERSION=0.9.5 GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_VERSION]) @@ -449,6 +472,7 @@ mutter-$VERSION Startup notification: ${have_startup_notification} libcanberra: ${have_libcanberra} libwacom: ${have_libwacom} + gudev ${have_gudev} Introspection: ${found_introspection} Session management: ${found_sm} Wayland: ${have_wayland} diff --git a/src/backends/meta-input-settings-private.h b/src/backends/meta-input-settings-private.h index c814d69a2..6e5f97bd4 100644 --- a/src/backends/meta-input-settings-private.h +++ b/src/backends/meta-input-settings-private.h @@ -100,6 +100,13 @@ struct _MetaInputSettingsClass gdouble padding_right, gdouble padding_top, gdouble padding_bottom); + + void (* set_mouse_accel_profile) (MetaInputSettings *settings, + ClutterInputDevice *device, + GDesktopPointerAccelProfile profile); + void (* set_trackball_accel_profile) (MetaInputSettings *settings, + ClutterInputDevice *device, + GDesktopPointerAccelProfile profile); }; GType meta_input_settings_get_type (void) G_GNUC_CONST; @@ -140,4 +147,6 @@ WacomDevice * meta_input_settings_get_tablet_wacom_device (MetaInputSettings *se ClutterInputDevice *device); #endif +gboolean meta_input_device_is_trackball (ClutterInputDevice *device); + #endif /* META_INPUT_SETTINGS_PRIVATE_H */ diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c index c718ae319..5c1972bd4 100644 --- a/src/backends/meta-input-settings.c +++ b/src/backends/meta-input-settings.c @@ -310,6 +310,63 @@ update_mouse_left_handed (MetaInputSettings *input_settings, } } +static void +do_update_pointer_accel_profile (MetaInputSettings *input_settings, + GSettings *settings, + ClutterInputDevice *device, + GDesktopPointerAccelProfile profile) +{ + MetaInputSettingsPrivate *priv = + meta_input_settings_get_instance_private (input_settings); + MetaInputSettingsClass *input_settings_class = + META_INPUT_SETTINGS_GET_CLASS (input_settings); + + if (settings == priv->mouse_settings) + input_settings_class->set_mouse_accel_profile (input_settings, + device, + profile); + else if (settings == priv->trackball_settings) + input_settings_class->set_trackball_accel_profile (input_settings, + device, + profile); +} + +static void +update_pointer_accel_profile (MetaInputSettings *input_settings, + GSettings *settings, + ClutterInputDevice *device) +{ + GDesktopPointerAccelProfile profile; + + profile = g_settings_get_enum (settings, "accel-profile"); + + if (device) + { + do_update_pointer_accel_profile (input_settings, settings, + device, profile); + } + else + { + MetaInputSettingsPrivate *priv = + meta_input_settings_get_instance_private (input_settings); + const GSList *devices; + const GSList *l; + + devices = clutter_device_manager_peek_devices (priv->device_manager); + for (l = devices; l; l = l->next) + { + device = l->data; + + if (clutter_input_device_get_device_mode (device) == + CLUTTER_INPUT_MODE_MASTER) + continue; + + do_update_pointer_accel_profile (input_settings, settings, + device, profile); + } + } +} + static GSettings * get_settings_for_device_type (MetaInputSettings *input_settings, ClutterInputDeviceType type) @@ -539,8 +596,8 @@ update_touchpad_send_events (MetaInputSettings *input_settings, } } -static gboolean -device_is_trackball (ClutterInputDevice *device) +gboolean +meta_input_device_is_trackball (ClutterInputDevice *device) { gboolean is_trackball; char *name; @@ -563,7 +620,7 @@ update_trackball_scroll_button (MetaInputSettings *input_settings, MetaInputSettingsPrivate *priv; guint button; - if (device && !device_is_trackball (device)) + if (device && !meta_input_device_is_trackball (device)) return; priv = meta_input_settings_get_instance_private (input_settings); @@ -586,7 +643,7 @@ update_trackball_scroll_button (MetaInputSettings *input_settings, { device = devices->data; - if (device_is_trackball (device)) + if (meta_input_device_is_trackball (device)) input_settings_class->set_scroll_button (input_settings, device, button); devices = devices->next; @@ -852,6 +909,8 @@ meta_input_settings_changed_cb (GSettings *settings, update_device_speed (input_settings, NULL); else if (strcmp (key, "natural-scroll") == 0) update_device_natural_scroll (input_settings, NULL); + else if (strcmp (key, "accel-profile") == 0) + update_pointer_accel_profile (input_settings, settings, NULL); } else if (settings == priv->touchpad_settings) { @@ -876,6 +935,8 @@ meta_input_settings_changed_cb (GSettings *settings, { if (strcmp (key, "scroll-wheel-emulation-button") == 0) update_trackball_scroll_button (input_settings, NULL); + else if (strcmp (key, "accel-profile") == 0) + update_pointer_accel_profile (input_settings, settings, NULL); } else if (settings == priv->keyboard_settings) { diff --git a/src/backends/native/meta-input-settings-native.c b/src/backends/native/meta-input-settings-native.c index b762941c7..01cd4e73b 100644 --- a/src/backends/native/meta-input-settings-native.c +++ b/src/backends/native/meta-input-settings-native.c @@ -275,6 +275,112 @@ meta_input_settings_native_set_keyboard_repeat (MetaInputSettings *settings, clutter_evdev_set_keyboard_repeat (manager, enabled, delay, interval); } +static void +set_device_accel_profile (ClutterInputDevice *device, + GDesktopPointerAccelProfile profile) +{ + struct libinput_device *libinput_device; + enum libinput_config_accel_profile libinput_profile; + uint32_t profiles; + + libinput_device = clutter_evdev_input_device_get_libinput_device (device); + + switch (profile) + { + case G_DESKTOP_POINTER_ACCEL_PROFILE_FLAT: + libinput_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; + break; + case G_DESKTOP_POINTER_ACCEL_PROFILE_ADAPTIVE: + libinput_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; + break; + default: + g_warn_if_reached (); + case G_DESKTOP_POINTER_ACCEL_PROFILE_DEFAULT: + libinput_profile = + libinput_device_config_accel_get_default_profile (libinput_device); + } + + profiles = libinput_device_config_accel_get_profiles (libinput_device); + if ((profiles & libinput_profile) == 0) + { + libinput_profile = + libinput_device_config_accel_get_default_profile (libinput_device); + } + + libinput_device_config_accel_set_profile (libinput_device, + libinput_profile); +} + +static gboolean +has_udev_property (ClutterInputDevice *device, + const char *property) +{ + struct libinput_device *libinput_device; + struct udev_device *udev_device; + struct udev_device *parent_udev_device; + + libinput_device = clutter_evdev_input_device_get_libinput_device (device); + if (!libinput_device) + return FALSE; + + udev_device = libinput_device_get_udev_device (libinput_device); + + if (!udev_device) + return FALSE; + + if (NULL != udev_device_get_property_value (udev_device, property)) + { + udev_device_unref (udev_device); + return TRUE; + } + + parent_udev_device = udev_device_get_parent (udev_device); + udev_device_unref (udev_device); + + if (!parent_udev_device) + return FALSE; + + if (NULL != udev_device_get_property_value (parent_udev_device, property)) + return TRUE; + + return FALSE; +} + +static gboolean +is_mouse_device (ClutterInputDevice *device) +{ + return (has_udev_property (device, "ID_INPUT_MOUSE") && + !has_udev_property (device, "ID_INPUT_POINTINGSTICK")); +} + +static gboolean +is_trackball_device (ClutterInputDevice *device) +{ + return meta_input_device_is_trackball (device); +} + +static void +meta_input_settings_native_set_mouse_accel_profile (MetaInputSettings *settings, + ClutterInputDevice *device, + GDesktopPointerAccelProfile profile) +{ + if (!is_mouse_device (device)) + return; + + set_device_accel_profile (device, profile); +} + +static void +meta_input_settings_native_set_trackball_accel_profile (MetaInputSettings *settings, + ClutterInputDevice *device, + GDesktopPointerAccelProfile profile) +{ + if (!is_trackball_device (device)) + return; + + set_device_accel_profile (device, profile); +} + static void meta_input_settings_native_set_tablet_mapping (MetaInputSettings *settings, ClutterInputDevice *device, @@ -332,6 +438,9 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass) input_settings_class->set_tablet_mapping = meta_input_settings_native_set_tablet_mapping; input_settings_class->set_tablet_keep_aspect = meta_input_settings_native_set_tablet_keep_aspect; input_settings_class->set_tablet_area = meta_input_settings_native_set_tablet_area; + + input_settings_class->set_mouse_accel_profile = meta_input_settings_native_set_mouse_accel_profile; + input_settings_class->set_trackball_accel_profile = meta_input_settings_native_set_trackball_accel_profile; } static void diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c index 864557002..f595d4232 100644 --- a/src/backends/x11/meta-input-settings-x11.c +++ b/src/backends/x11/meta-input-settings-x11.c @@ -31,10 +31,21 @@ #include #include #include +#ifdef HAVE_LIBGUDEV +#include +#endif #include -G_DEFINE_TYPE (MetaInputSettingsX11, meta_input_settings_x11, META_TYPE_INPUT_SETTINGS) +typedef struct _MetaInputSettingsX11Private +{ +#ifdef HAVE_LIBGUDEV + GUdevClient *udev_client; +#endif +} MetaInputSettingsX11Private; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettingsX11, meta_input_settings_x11, + META_TYPE_INPUT_SETTINGS) enum { SCROLL_METHOD_FIELD_2FG, @@ -360,6 +371,135 @@ meta_input_settings_x11_set_keyboard_repeat (MetaInputSettings *settings, } } +static gboolean +has_udev_property (MetaInputSettings *settings, + ClutterInputDevice *device, + const char *property_name) +{ +#ifdef HAVE_LIBGUDEV + MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (settings); + MetaInputSettingsX11Private *priv = + meta_input_settings_x11_get_instance_private (settings_x11); + const char *device_node; + GUdevDevice *udev_device = NULL; + GUdevDevice *parent_udev_device = NULL; + + device_node = clutter_input_device_get_device_node (device); + if (!device_node) + return FALSE; + + udev_device = g_udev_client_query_by_device_file (priv->udev_client, + device_node); + if (!udev_device) + return FALSE; + + if (NULL != g_udev_device_get_property (udev_device, property_name)) + { + g_object_unref (udev_device); + return TRUE; + } + + parent_udev_device = g_udev_device_get_parent (udev_device); + g_object_unref (udev_device); + + if (!parent_udev_device) + return FALSE; + + if (NULL != g_udev_device_get_property (parent_udev_device, property_name)) + { + g_object_unref (parent_udev_device); + return TRUE; + } + + g_object_unref (parent_udev_device); + return FALSE; +#else + g_warning ("Failed to set acceleration profile: no udev support"); + return FALSE; +#endif +} + +static gboolean +is_mouse (MetaInputSettings *settings, + ClutterInputDevice *device) +{ + return (has_udev_property (settings, device, "ID_INPUT_MOUSE") && + !has_udev_property (settings, device, "ID_INPUT_POINTINGSTICK")); +} + +static gboolean +is_trackball (MetaInputSettings *settings, + ClutterInputDevice *device) +{ + return meta_input_device_is_trackball (device); +} + +static void +set_device_accel_profile (ClutterInputDevice *device, + GDesktopPointerAccelProfile profile) +{ + guchar *defaults, *available; + guchar values[2] = { 0 }; /* adaptive, flat */ + + defaults = get_property (device, "libinput Accel Profile Enabled Default", + XA_INTEGER, 8, 2); + if (!defaults) + return; + + available = get_property (device, "libinput Accel Profiles Available", + XA_INTEGER, 8, 2); + if (!available) + goto err_available; + + switch (profile) + { + case G_DESKTOP_POINTER_ACCEL_PROFILE_FLAT: + values[0] = 0; + values[1] = 1; + break; + case G_DESKTOP_POINTER_ACCEL_PROFILE_ADAPTIVE: + values[0] = 1; + values[1] = 0; + break; + default: + g_warn_if_reached (); + case G_DESKTOP_POINTER_ACCEL_PROFILE_DEFAULT: + values[0] = defaults[0]; + values[1] = defaults[1]; + break; + } + + change_property (device, "libinput Accel Profile Enabled", + XA_INTEGER, 8, &values, 2); + + meta_XFree (available); + +err_available: + meta_XFree (defaults); +} + +static void +meta_input_settings_x11_set_mouse_accel_profile (MetaInputSettings *settings, + ClutterInputDevice *device, + GDesktopPointerAccelProfile profile) +{ + if (!is_mouse (settings, device)) + return; + + set_device_accel_profile (device, profile); +} + +static void +meta_input_settings_x11_set_trackball_accel_profile (MetaInputSettings *settings, + ClutterInputDevice *device, + GDesktopPointerAccelProfile profile) +{ + if (!is_trackball (settings, device)) + return; + + set_device_accel_profile (device, profile); +} + static void meta_input_settings_x11_set_tablet_mapping (MetaInputSettings *settings, ClutterInputDevice *device, @@ -385,11 +525,28 @@ meta_input_settings_x11_set_tablet_area (MetaInputSettings *settings, { } +static void +meta_input_settings_x11_dispose (GObject *object) +{ +#ifdef HAVE_LIBGUDEV + MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (object); + MetaInputSettingsX11Private *priv = + meta_input_settings_x11_get_instance_private (settings_x11); + + g_clear_object (&priv->udev_client); +#endif + + G_OBJECT_CLASS (meta_input_settings_x11_parent_class)->dispose (object); +} + static void meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaInputSettingsClass *input_settings_class = META_INPUT_SETTINGS_CLASS (klass); + object_class->dispose = meta_input_settings_x11_dispose; + input_settings_class->set_send_events = meta_input_settings_x11_set_send_events; input_settings_class->set_matrix = meta_input_settings_x11_set_matrix; input_settings_class->set_speed = meta_input_settings_x11_set_speed; @@ -405,9 +562,19 @@ meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass) input_settings_class->set_tablet_mapping = meta_input_settings_x11_set_tablet_mapping; input_settings_class->set_tablet_keep_aspect = meta_input_settings_x11_set_tablet_keep_aspect; input_settings_class->set_tablet_area = meta_input_settings_x11_set_tablet_area; + + input_settings_class->set_mouse_accel_profile = meta_input_settings_x11_set_mouse_accel_profile; + input_settings_class->set_trackball_accel_profile = meta_input_settings_x11_set_trackball_accel_profile; } static void meta_input_settings_x11_init (MetaInputSettingsX11 *settings) { +#ifdef HAVE_LIBGUDEV + MetaInputSettingsX11Private *priv = + meta_input_settings_x11_get_instance_private (settings); + const char *subsystems[] = { NULL }; + + priv->udev_client = g_udev_client_new (subsystems); +#endif }