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

@ -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,
@ -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
}