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 }