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
This commit is contained in:
Jonas Ådahl 2016-04-07 15:44:28 +08:00
parent cfe5d7429a
commit 23c4ac6c7f
5 changed files with 375 additions and 5 deletions

View File

@ -116,6 +116,11 @@ AC_ARG_WITH(libwacom,
[disable the use of libwacom for advanced tablet management]),, [disable the use of libwacom for advanced tablet management]),,
with_libwacom=auto) 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], AC_ARG_WITH([xwayland-path],
[AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])], [AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])],
[XWAYLAND_PATH="$withval"], [XWAYLAND_PATH="$withval"],
@ -195,6 +200,24 @@ else
fi fi
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 INTROSPECTION_VERSION=0.9.5
GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_VERSION]) GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_VERSION])
@ -449,6 +472,7 @@ mutter-$VERSION
Startup notification: ${have_startup_notification} Startup notification: ${have_startup_notification}
libcanberra: ${have_libcanberra} libcanberra: ${have_libcanberra}
libwacom: ${have_libwacom} libwacom: ${have_libwacom}
gudev ${have_gudev}
Introspection: ${found_introspection} Introspection: ${found_introspection}
Session management: ${found_sm} Session management: ${found_sm}
Wayland: ${have_wayland} Wayland: ${have_wayland}

View File

@ -100,6 +100,13 @@ struct _MetaInputSettingsClass
gdouble padding_right, gdouble padding_right,
gdouble padding_top, gdouble padding_top,
gdouble padding_bottom); 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; 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); ClutterInputDevice *device);
#endif #endif
gboolean meta_input_device_is_trackball (ClutterInputDevice *device);
#endif /* META_INPUT_SETTINGS_PRIVATE_H */ #endif /* META_INPUT_SETTINGS_PRIVATE_H */

View File

@ -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 * static GSettings *
get_settings_for_device_type (MetaInputSettings *input_settings, get_settings_for_device_type (MetaInputSettings *input_settings,
ClutterInputDeviceType type) ClutterInputDeviceType type)
@ -539,8 +596,8 @@ update_touchpad_send_events (MetaInputSettings *input_settings,
} }
} }
static gboolean gboolean
device_is_trackball (ClutterInputDevice *device) meta_input_device_is_trackball (ClutterInputDevice *device)
{ {
gboolean is_trackball; gboolean is_trackball;
char *name; char *name;
@ -563,7 +620,7 @@ update_trackball_scroll_button (MetaInputSettings *input_settings,
MetaInputSettingsPrivate *priv; MetaInputSettingsPrivate *priv;
guint button; guint button;
if (device && !device_is_trackball (device)) if (device && !meta_input_device_is_trackball (device))
return; return;
priv = meta_input_settings_get_instance_private (input_settings); priv = meta_input_settings_get_instance_private (input_settings);
@ -586,7 +643,7 @@ update_trackball_scroll_button (MetaInputSettings *input_settings,
{ {
device = devices->data; 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); input_settings_class->set_scroll_button (input_settings, device, button);
devices = devices->next; devices = devices->next;
@ -852,6 +909,8 @@ meta_input_settings_changed_cb (GSettings *settings,
update_device_speed (input_settings, NULL); update_device_speed (input_settings, NULL);
else if (strcmp (key, "natural-scroll") == 0) else if (strcmp (key, "natural-scroll") == 0)
update_device_natural_scroll (input_settings, NULL); 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) 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) if (strcmp (key, "scroll-wheel-emulation-button") == 0)
update_trackball_scroll_button (input_settings, NULL); 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) else if (settings == priv->keyboard_settings)
{ {

View File

@ -275,6 +275,112 @@ meta_input_settings_native_set_keyboard_repeat (MetaInputSettings *settings,
clutter_evdev_set_keyboard_repeat (manager, enabled, delay, interval); 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 static void
meta_input_settings_native_set_tablet_mapping (MetaInputSettings *settings, meta_input_settings_native_set_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device, 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_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_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_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 static void

View File

@ -31,10 +31,21 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#ifdef HAVE_LIBGUDEV
#include <gudev/gudev.h>
#endif
#include <meta/errors.h> #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 { enum {
SCROLL_METHOD_FIELD_2FG, 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 static void
meta_input_settings_x11_set_tablet_mapping (MetaInputSettings *settings, meta_input_settings_x11_set_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device, 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 static void
meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass) meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaInputSettingsClass *input_settings_class = META_INPUT_SETTINGS_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_send_events = meta_input_settings_x11_set_send_events;
input_settings_class->set_matrix = meta_input_settings_x11_set_matrix; input_settings_class->set_matrix = meta_input_settings_x11_set_matrix;
input_settings_class->set_speed = meta_input_settings_x11_set_speed; 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_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_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_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 static void
meta_input_settings_x11_init (MetaInputSettingsX11 *settings) 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
} }