From ff9753688fcba7eacc49ba2420bf42c0af22dc59 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 31 Oct 2016 18:01:25 +0100 Subject: [PATCH] backends/x11: Implement tablet settings based on the Wacom driver This is a stopgap solution until libinput is the fallback driver handling tablets and pads. https://bugzilla.gnome.org/show_bug.cgi?id=773779 --- src/backends/x11/meta-input-settings-x11.c | 214 ++++++++++++++++++++- 1 file changed, 207 insertions(+), 7 deletions(-) diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c index 332997b47..d7d468da4 100644 --- a/src/backends/x11/meta-input-settings-x11.c +++ b/src/backends/x11/meta-input-settings-x11.c @@ -188,10 +188,20 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { - guchar value = (enabled) ? 1 : 0; + guchar value; - change_property (device, "libinput Left Handed Enabled", - XA_INTEGER, 8, &value, 1); + if (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE) + { + value = enabled ? 3 : 0; + change_property (device, "Wacom Rotation", + XA_INTEGER, 8, &value, 1); + } + else + { + value = enabled ? 1 : 0; + change_property (device, "libinput Left Handed Enabled", + XA_INTEGER, 8, &value, 1); + } } static void @@ -467,14 +477,76 @@ meta_input_settings_x11_set_tablet_mapping (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopTabletMapping mapping) { + MetaDisplay *display = meta_get_display (); + MetaBackend *backend = meta_get_backend (); + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + int device_id = clutter_input_device_get_device_id (device); + XDevice *xdev; + + if (!display) + return; + + /* Grab the puke bucket! */ + meta_error_trap_push (display); + xdev = XOpenDevice (xdisplay, device_id); + if (xdev) + { + XSetDeviceMode (xdisplay, xdev, + mapping == G_DESKTOP_TABLET_MAPPING_ABSOLUTE ? + Absolute : Relative); + XCloseDevice (xdisplay, xdev); + } + + if (meta_error_trap_pop_with_return (display)) + { + g_warning ("Could not set tablet mapping for %s", + clutter_input_device_get_device_name (device)); + } +} + +static gboolean +device_query_area (ClutterInputDevice *device, + gint *width, + gint *height) +{ + MetaBackend *backend = meta_get_backend (); + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + gint device_id, n_devices, i; + XIDeviceInfo *info; + Atom abs_x, abs_y; + + *width = *height = 0; + device_id = clutter_input_device_get_device_id (device); + info = XIQueryDevice (xdisplay, device_id, &n_devices); + if (n_devices == 0) + return FALSE; + + abs_x = XInternAtom (xdisplay, "Abs X", True); + abs_y = XInternAtom (xdisplay, "Abs Y", True); + + for (i = 0; i < info->num_classes; i++) + { + XIValuatorClassInfo *valuator = (XIValuatorClassInfo *) info->classes[i]; + + if (valuator->type != XIValuatorClass) + continue; + if (valuator->label == abs_x) + *width = valuator->max - valuator->min; + else if (valuator->label == abs_y) + *height = valuator->max - valuator->min; + } + + XIFreeDeviceInfo (info); + return TRUE; } static void -meta_input_settings_x11_set_tablet_keep_aspect (MetaInputSettings *settings, - ClutterInputDevice *device, - MetaOutput *output, - gboolean keep_aspect) +update_tablet_area (MetaInputSettings *settings, + ClutterInputDevice *device, + gint32 *area) { + change_property (device, "Wacom Tablet Area", + XA_INTEGER, 32, area, 4); } static void @@ -485,6 +557,61 @@ meta_input_settings_x11_set_tablet_area (MetaInputSettings *settings, gdouble padding_top, gdouble padding_bottom) { + gint32 width, height, area[4] = { 0 }; + + if (!device_query_area (device, &width, &height)) + return; + + area[0] = width * padding_left; + area[1] = height * padding_top; + area[2] = width - (width * padding_right); + area[2] = height - (height * padding_bottom); + update_tablet_area (settings, device, area); +} + +static void +meta_input_settings_x11_set_tablet_keep_aspect (MetaInputSettings *settings, + ClutterInputDevice *device, + MetaOutput *output, + gboolean keep_aspect) +{ + gint32 width, height, dev_width, dev_height, area[4] = { 0 }; + + if (!device_query_area (device, &dev_width, &dev_height)) + return; + + if (keep_aspect) + { + gdouble output_aspect, dev_aspect; + + if (output && output->crtc) + { + width = output->crtc->rect.width; + height = output->crtc->rect.height; + } + else + { + MetaMonitorManager *monitor_manager; + MetaBackend *backend; + + backend = meta_get_backend (); + monitor_manager = meta_backend_get_monitor_manager (backend); + meta_monitor_manager_get_screen_limits (monitor_manager, + &width, &height); + } + + output_aspect = (gdouble) width / height; + dev_aspect = (gdouble) dev_width / dev_height; + + if (dev_aspect > output_aspect) + dev_width = dev_height * output_aspect; + else if (dev_aspect < output_aspect) + dev_height = dev_width / output_aspect; + } + + area[2] = dev_width; + area[3] = dev_height; + update_tablet_area (settings, device, area); } static void @@ -501,6 +628,76 @@ meta_input_settings_x11_dispose (GObject *object) G_OBJECT_CLASS (meta_input_settings_x11_parent_class)->dispose (object); } +static guint +action_to_button (GDesktopStylusButtonAction action, + guint button) +{ + switch (action) + { + case G_DESKTOP_STYLUS_BUTTON_ACTION_MIDDLE: + return CLUTTER_BUTTON_MIDDLE; + case G_DESKTOP_STYLUS_BUTTON_ACTION_RIGHT: + return CLUTTER_BUTTON_SECONDARY; + case G_DESKTOP_STYLUS_BUTTON_ACTION_BACK: + return 8; + case G_DESKTOP_STYLUS_BUTTON_ACTION_FORWARD: + return 9; + case G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT: + default: + return button; + } +} + +static void +meta_input_settings_x11_set_stylus_button_map (MetaInputSettings *settings, + ClutterInputDevice *device, + ClutterInputDeviceTool *tool, + GDesktopStylusButtonAction primary, + GDesktopStylusButtonAction secondary) +{ + MetaDisplay *display = meta_get_display (); + MetaBackend *backend = meta_get_backend (); + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + int device_id = clutter_input_device_get_device_id (device); + XDevice *xdev; + + if (!display) + return; + + /* Grab the puke bucket! */ + meta_error_trap_push (display); + xdev = XOpenDevice (xdisplay, device_id); + if (xdev) + { + guchar map[3] = { + CLUTTER_BUTTON_PRIMARY, + action_to_button (primary, CLUTTER_BUTTON_MIDDLE), + action_to_button (secondary, CLUTTER_BUTTON_SECONDARY), + }; + + XSetDeviceButtonMapping (xdisplay, xdev, map, G_N_ELEMENTS (map)); + XCloseDevice (xdisplay, xdev); + } + + if (meta_error_trap_pop_with_return (display)) + { + g_warning ("Could not set stylus button map for %s", + clutter_input_device_get_device_name (device)); + } +} + +static void +meta_input_settings_x11_set_stylus_pressure (MetaInputSettings *settings, + ClutterInputDevice *device, + ClutterInputDeviceTool *tool, + const gint32 pressure[4]) +{ + guchar values[4] = { pressure[0], pressure[1], pressure[2], pressure[3] }; + + change_property (device, "Wacom Pressurecurve", XA_INTEGER, 8, + &values, G_N_ELEMENTS (values)); +} + static void meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass) { @@ -527,6 +724,9 @@ meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass) 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; + + input_settings_class->set_stylus_pressure = meta_input_settings_x11_set_stylus_pressure; + input_settings_class->set_stylus_button_map = meta_input_settings_x11_set_stylus_button_map; } static void