[mutter] settings: Support mouse and trackball accel profile



commit 23c4ac6c7fecdd4eb70d64a8fbb6e4b25f5d03f0
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Apr 7 15:44:28 2016 +0800

    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 +++++++++-
 src/backends/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 8548d89..ae18984 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 c814d69..6e5f97b 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 c718ae3..5c1972b 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 b762941..01cd4e7 100644
--- a/src/backends/native/meta-input-settings-native.c
+++ b/src/backends/native/meta-input-settings-native.c
@@ -276,6 +276,112 @@ meta_input_settings_native_set_keyboard_repeat (MetaInputSettings *settings,
 }
 
 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,
                                                GDesktopTabletMapping  mapping)
@@ -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 8645570..f595d42 100644
--- a/src/backends/x11/meta-input-settings-x11.c
+++ b/src/backends/x11/meta-input-settings-x11.c
@@ -31,10 +31,21 @@
 #include <X11/Xatom.h>
 #include <X11/extensions/XInput2.h>
 #include <X11/XKBlib.h>
+#ifdef HAVE_LIBGUDEV
+#include <gudev/gudev.h>
+#endif
 
 #include <meta/errors.h>
 
-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,
@@ -386,10 +526,27 @@ 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
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]