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

@ -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 */

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 *
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)
{

View File

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

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
}