[mutter/wip/carlosg/input-thread: 57/91] backends: Split pad action mapping to a separate object
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/carlosg/input-thread: 57/91] backends: Split pad action mapping to a separate object
- Date: Tue, 6 Oct 2020 21:13:47 +0000 (UTC)
commit 7664afd3f150fc08f1d0dbd225b63d528cae7e75
Author: Carlos Garnacho <carlosg gnome org>
Date: Wed Jul 15 22:38:00 2020 +0200
backends: Split pad action mapping to a separate object
This now lives in the core, and will get updated from events in the
UI thread.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
src/backends/meta-input-settings-private.h | 11 -
src/backends/meta-input-settings.c | 638 ---------------------
src/core/display-private.h | 2 +
src/core/display.c | 9 +-
src/core/events.c | 3 +-
src/core/meta-pad-action-mapper.c | 858 +++++++++++++++++++++++++++++
src/core/meta-pad-action-mapper.h | 47 ++
src/meson.build | 1 +
src/wayland/meta-wayland-tablet-pad.c | 17 +-
9 files changed, 923 insertions(+), 663 deletions(-)
---
diff --git a/src/backends/meta-input-settings-private.h b/src/backends/meta-input-settings-private.h
index 675a3837b6..6647d19c22 100644
--- a/src/backends/meta-input-settings-private.h
+++ b/src/backends/meta-input-settings-private.h
@@ -142,17 +142,6 @@ GSettings * meta_input_settings_get_tablet_settings (MetaInputSettings
MetaLogicalMonitor * meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings,
ClutterInputDevice *device);
-gboolean meta_input_settings_is_pad_button_grabbed (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- guint button);
-
-gboolean meta_input_settings_handle_pad_event (MetaInputSettings
*input_settings,
- const ClutterEvent *event);
-gchar * meta_input_settings_get_pad_action_label (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- MetaPadActionType action,
- guint number);
-
void meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings);
void meta_input_settings_maybe_restore_numlock_state (MetaInputSettings *input_settings);
diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c
index 69c99ba407..2a4c4219ea 100644
--- a/src/backends/meta-input-settings.c
+++ b/src/backends/meta-input-settings.c
@@ -81,18 +81,8 @@ struct _MetaInputSettingsPrivate
GHashTable *current_tools;
- ClutterVirtualInputDevice *virtual_pad_keyboard;
-
GHashTable *two_finger_devices;
- /* Pad ring/strip emission */
- struct {
- ClutterInputDevice *pad;
- MetaPadActionType action;
- guint number;
- gdouble value;
- } last_pad_action_info;
-
/* For absolute devices with no mapping in settings */
MetaInputMapper *input_mapper;
};
@@ -111,15 +101,6 @@ typedef void (*ConfigUintFunc) (MetaInputSettings *input_settings,
ClutterInputDevice *device,
guint value);
-typedef enum
-{
- META_PAD_DIRECTION_NONE = -1,
- META_PAD_DIRECTION_UP = 0,
- META_PAD_DIRECTION_DOWN,
- META_PAD_DIRECTION_CW,
- META_PAD_DIRECTION_CCW,
-} MetaPadDirection;
-
G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettings, meta_input_settings, G_TYPE_OBJECT)
static GSList *
@@ -155,8 +136,6 @@ meta_input_settings_dispose (GObject *object)
g_signal_handlers_disconnect_by_data (priv->seat, settings);
- g_clear_object (&priv->virtual_pad_keyboard);
-
g_clear_object (&priv->mouse_settings);
g_clear_object (&priv->touchpad_settings);
g_clear_object (&priv->trackball_settings);
@@ -1584,63 +1563,6 @@ lookup_tool_settings (ClutterInputDeviceTool *tool,
return tool_settings;
}
-static GSettings *
-lookup_pad_action_settings (ClutterInputDevice *device,
- MetaPadActionType action,
- guint number,
- MetaPadDirection direction,
- gint mode)
-{
- const gchar *vendor, *product, *action_type, *detail_type = NULL;
- GSettings *settings;
- GString *path;
- gchar action_label;
-
- vendor = clutter_input_device_get_vendor_id (device);
- product = clutter_input_device_get_product_id (device);
-
- action_label = 'A' + number;
-
- switch (action)
- {
- case META_PAD_ACTION_BUTTON:
- action_type = "button";
- break;
- case META_PAD_ACTION_RING:
- g_assert (direction == META_PAD_DIRECTION_CW ||
- direction == META_PAD_DIRECTION_CCW);
- action_type = "ring";
- detail_type = (direction == META_PAD_DIRECTION_CW) ? "cw" : "ccw";
- break;
- case META_PAD_ACTION_STRIP:
- g_assert (direction == META_PAD_DIRECTION_UP ||
- direction == META_PAD_DIRECTION_DOWN);
- action_type = "strip";
- detail_type = (direction == META_PAD_DIRECTION_UP) ? "up" : "down";
- break;
- default:
- return NULL;
- }
-
- path = g_string_new (NULL);
- g_string_append_printf (path, "/org/gnome/desktop/peripherals/tablets/%s:%s/%s%c",
- vendor, product, action_type, action_label);
-
- if (detail_type)
- g_string_append_printf (path, "-%s", detail_type);
-
- if (mode >= 0)
- g_string_append_printf (path, "-mode-%d", mode);
-
- g_string_append_c (path, '/');
-
- settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.pad-button",
- path->str);
- g_string_free (path, TRUE);
-
- return settings;
-}
-
static void
monitors_changed_cb (MetaMonitorManager *monitor_manager,
MetaInputSettings *input_settings)
@@ -2193,566 +2115,6 @@ meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings,
return logical_monitor;
}
-static GDesktopPadButtonAction
-meta_input_settings_get_pad_button_action (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- guint button)
-{
- GDesktopPadButtonAction action;
- GSettings *settings;
-
- g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings),
- G_DESKTOP_PAD_BUTTON_ACTION_NONE);
- g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad),
- G_DESKTOP_PAD_BUTTON_ACTION_NONE);
-
- settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
- button, META_PAD_DIRECTION_NONE, -1);
- action = g_settings_get_enum (settings, "action");
- g_object_unref (settings);
-
- return action;
-}
-
-static gboolean
-cycle_logical_monitors (MetaInputSettings *settings,
- gboolean skip_all_monitors,
- MetaLogicalMonitor *current_logical_monitor,
- MetaLogicalMonitor **next_logical_monitor)
-{
- MetaInputSettingsPrivate *priv =
- meta_input_settings_get_instance_private (settings);
- MetaMonitorManager *monitor_manager = priv->monitor_manager;
- GList *logical_monitors;
-
- /* We cycle between:
- * - the span of all monitors (current_logical_monitor = NULL), only for
- * non-integrated devices.
- * - each monitor individually.
- */
-
- logical_monitors =
- meta_monitor_manager_get_logical_monitors (monitor_manager);
-
- if (!current_logical_monitor)
- {
- *next_logical_monitor = logical_monitors->data;
- }
- else
- {
- GList *l;
-
- l = g_list_find (logical_monitors, current_logical_monitor);
- if (l->next)
- *next_logical_monitor = l->next->data;
- else if (skip_all_monitors)
- *next_logical_monitor = logical_monitors->data;
- else
- *next_logical_monitor = NULL;
- }
-
- return TRUE;
-}
-
-static void
-meta_input_settings_cycle_tablet_output (MetaInputSettings *input_settings,
- ClutterInputDevice *device)
-{
- MetaInputSettingsPrivate *priv;
- DeviceMappingInfo *info;
- MetaLogicalMonitor *logical_monitor = NULL;
- const gchar *edid[4] = { 0 }, *pretty_name = NULL;
- gboolean is_integrated_device = FALSE;
-#ifdef HAVE_LIBWACOM
- WacomDevice *wacom_device;
-#endif
-
- g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings));
- g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
- g_return_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE ||
- clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE);
-
- priv = meta_input_settings_get_instance_private (input_settings);
- info = g_hash_table_lookup (priv->mappable_devices, device);
- g_return_if_fail (info != NULL);
-
-#ifdef HAVE_LIBWACOM
- wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
-
- if (wacom_device)
- {
- pretty_name = libwacom_get_name (wacom_device);
- is_integrated_device =
- libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE;
- }
-#endif
-
- meta_input_settings_find_monitor (input_settings, info->settings, device,
- NULL, &logical_monitor);
-
- if (!cycle_logical_monitors (input_settings,
- is_integrated_device,
- logical_monitor,
- &logical_monitor))
- return;
-
- if (logical_monitor)
- {
- MetaMonitor *monitor;
-
- /* Pick an arbitrary monitor in the logical monitor to represent it. */
- monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
- edid[0] = meta_monitor_get_vendor (monitor);
- edid[1] = meta_monitor_get_product (monitor);
- edid[2] = meta_monitor_get_serial (monitor);
- }
- else
- {
- edid[0] = "";
- edid[1] = "";
- edid[2] = "";
- }
- g_settings_set_strv (info->settings, "output", edid);
-
- meta_display_show_tablet_mapping_notification (meta_get_display (),
- device, pretty_name);
-}
-
-static void
-emulate_modifiers (ClutterVirtualInputDevice *device,
- ClutterModifierType mods,
- ClutterKeyState state)
-{
- guint i;
- struct {
- ClutterModifierType mod;
- guint keyval;
- } mod_map[] = {
- { CLUTTER_SHIFT_MASK, CLUTTER_KEY_Shift_L },
- { CLUTTER_CONTROL_MASK, CLUTTER_KEY_Control_L },
- { CLUTTER_MOD1_MASK, CLUTTER_KEY_Meta_L }
- };
-
- for (i = 0; i < G_N_ELEMENTS (mod_map); i++)
- {
- if ((mods & mod_map[i].mod) == 0)
- continue;
-
- clutter_virtual_input_device_notify_keyval (device,
- clutter_get_current_event_time (),
- mod_map[i].keyval, state);
- }
-}
-
-static void
-meta_input_settings_emulate_keybinding (MetaInputSettings *input_settings,
- const gchar *accel,
- gboolean is_press)
-{
- MetaInputSettingsPrivate *priv;
- ClutterKeyState state;
- guint key, mods;
-
- if (!accel || !*accel)
- return;
-
- priv = meta_input_settings_get_instance_private (input_settings);
-
- /* FIXME: This is appalling */
- gtk_accelerator_parse (accel, &key, &mods);
-
- if (!priv->virtual_pad_keyboard)
- {
- ClutterBackend *backend;
- ClutterSeat *seat;
-
- backend = clutter_get_default_backend ();
- seat = clutter_backend_get_default_seat (backend);
-
- priv->virtual_pad_keyboard =
- clutter_seat_create_virtual_device (seat,
- CLUTTER_KEYBOARD_DEVICE);
- }
-
- state = is_press ? CLUTTER_KEY_STATE_PRESSED : CLUTTER_KEY_STATE_RELEASED;
-
- if (is_press)
- emulate_modifiers (priv->virtual_pad_keyboard, mods, state);
-
- clutter_virtual_input_device_notify_keyval (priv->virtual_pad_keyboard,
- clutter_get_current_event_time (),
- key, state);
- if (!is_press)
- emulate_modifiers (priv->virtual_pad_keyboard, mods, state);
-}
-
-gboolean
-meta_input_settings_is_pad_button_grabbed (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- guint button)
-{
- g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), FALSE);
- g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), FALSE);
- g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
- CLUTTER_PAD_DEVICE, FALSE);
-
- return (meta_input_settings_get_pad_button_action (input_settings, pad, button) !=
- G_DESKTOP_PAD_BUTTON_ACTION_NONE);
-}
-
-static gboolean
-meta_input_settings_handle_pad_button (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- const ClutterPadButtonEvent *event)
-{
- GDesktopPadButtonAction action;
- gint button, group, mode;
- gboolean is_press;
- GSettings *settings;
- gchar *accel;
-
- g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), FALSE);
- g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS ||
- event->type == CLUTTER_PAD_BUTTON_RELEASE, FALSE);
-
- button = event->button;
- mode = event->mode;
- group = clutter_input_device_get_mode_switch_button_group (pad, button);
- is_press = event->type == CLUTTER_PAD_BUTTON_PRESS;
-
- if (is_press && group >= 0)
- {
- guint n_modes = clutter_input_device_get_group_n_modes (pad, group);
- const gchar *pretty_name = NULL;
- MetaInputSettingsPrivate *priv;
- DeviceMappingInfo *info;
-#ifdef HAVE_LIBWACOM
- WacomDevice *wacom_device;
-#endif
-
- priv = meta_input_settings_get_instance_private (input_settings);
- info = g_hash_table_lookup (priv->mappable_devices, pad);
-
-#ifdef HAVE_LIBWACOM
- wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (pad));
-
- if (wacom_device)
- pretty_name = libwacom_get_name (wacom_device);
-#endif
- meta_display_notify_pad_group_switch (meta_get_display (), pad,
- pretty_name, group, mode, n_modes);
- info->group_modes[group] = mode;
- }
-
- action = meta_input_settings_get_pad_button_action (input_settings, pad, button);
-
- switch (action)
- {
- case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
- if (is_press)
- meta_input_settings_cycle_tablet_output (input_settings, pad);
- return TRUE;
- case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
- if (is_press)
- meta_display_request_pad_osd (meta_get_display (), pad, FALSE);
- return TRUE;
- case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
- settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
- button, META_PAD_DIRECTION_NONE, -1);
- accel = g_settings_get_string (settings, "keybinding");
- meta_input_settings_emulate_keybinding (input_settings, accel, is_press);
- g_object_unref (settings);
- g_free (accel);
- return TRUE;
- case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
- default:
- return FALSE;
- }
-}
-
-static gboolean
-meta_input_settings_handle_pad_action (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- MetaPadActionType action,
- guint number,
- MetaPadDirection direction,
- guint mode)
-{
- GSettings *settings;
- gboolean handled = FALSE;
- gchar *accel;
-
- settings = lookup_pad_action_settings (pad, action, number, direction, mode);
- accel = g_settings_get_string (settings, "keybinding");
-
- if (accel && *accel)
- {
- meta_input_settings_emulate_keybinding (input_settings, accel, TRUE);
- meta_input_settings_emulate_keybinding (input_settings, accel, FALSE);
- handled = TRUE;
- }
-
- g_object_unref (settings);
- g_free (accel);
-
- return handled;
-}
-
-static gboolean
-meta_input_settings_get_pad_action_direction (MetaInputSettings *input_settings,
- const ClutterEvent *event,
- MetaPadDirection *direction)
-{
- MetaInputSettingsPrivate *priv;
- ClutterInputDevice *pad = clutter_event_get_device (event);
- MetaPadActionType pad_action;
- gboolean has_direction = FALSE;
- MetaPadDirection inc_dir, dec_dir;
- guint number;
- gdouble value;
-
- priv = meta_input_settings_get_instance_private (input_settings);
- *direction = META_PAD_DIRECTION_NONE;
-
- switch (event->type)
- {
- case CLUTTER_PAD_RING:
- pad_action = META_PAD_ACTION_RING;
- number = event->pad_ring.ring_number;
- value = event->pad_ring.angle;
- inc_dir = META_PAD_DIRECTION_CW;
- dec_dir = META_PAD_DIRECTION_CCW;
- break;
- case CLUTTER_PAD_STRIP:
- pad_action = META_PAD_ACTION_STRIP;
- number = event->pad_strip.strip_number;
- value = event->pad_strip.value;
- inc_dir = META_PAD_DIRECTION_DOWN;
- dec_dir = META_PAD_DIRECTION_UP;
- break;
- default:
- return FALSE;
- }
-
- if (priv->last_pad_action_info.pad == pad &&
- priv->last_pad_action_info.action == pad_action &&
- priv->last_pad_action_info.number == number &&
- value >= 0 && priv->last_pad_action_info.value >= 0)
- {
- *direction = (value - priv->last_pad_action_info.value) > 0 ?
- inc_dir : dec_dir;
- has_direction = TRUE;
- }
-
- priv->last_pad_action_info.pad = pad;
- priv->last_pad_action_info.action = pad_action;
- priv->last_pad_action_info.number = number;
- priv->last_pad_action_info.value = value;
- return has_direction;
-}
-
-gboolean
-meta_input_settings_handle_pad_event (MetaInputSettings *input_settings,
- const ClutterEvent *event)
-{
- ClutterInputDevice *pad;
- MetaPadDirection direction = META_PAD_DIRECTION_NONE;
-
- pad = clutter_event_get_source_device ((ClutterEvent *) event);
-
- switch (event->type)
- {
- case CLUTTER_PAD_BUTTON_PRESS:
- case CLUTTER_PAD_BUTTON_RELEASE:
- return meta_input_settings_handle_pad_button (input_settings, pad,
- &event->pad_button);
- case CLUTTER_PAD_RING:
- if (!meta_input_settings_get_pad_action_direction (input_settings,
- event, &direction))
- return FALSE;
- return meta_input_settings_handle_pad_action (input_settings, pad,
- META_PAD_ACTION_RING,
- event->pad_ring.ring_number,
- direction,
- event->pad_ring.mode);
- case CLUTTER_PAD_STRIP:
- if (!meta_input_settings_get_pad_action_direction (input_settings,
- event, &direction))
- return FALSE;
- return meta_input_settings_handle_pad_action (input_settings, pad,
- META_PAD_ACTION_STRIP,
- event->pad_strip.strip_number,
- direction,
- event->pad_strip.mode);
- default:
- return FALSE;
- }
-}
-
-static gchar *
-compose_directional_action_label (GSettings *direction1,
- GSettings *direction2)
-{
- gchar *accel1, *accel2, *str = NULL;
-
- accel1 = g_settings_get_string (direction1, "keybinding");
- accel2 = g_settings_get_string (direction2, "keybinding");
-
- if (accel1 && *accel1 && accel2 && *accel2)
- str = g_strdup_printf ("%s / %s", accel1, accel2);
-
- g_free (accel1);
- g_free (accel2);
-
- return str;
-}
-
-static gchar *
-meta_input_settings_get_ring_label (MetaInputSettings *settings,
- ClutterInputDevice *pad,
- guint number,
- guint mode)
-{
- GSettings *settings1, *settings2;
- gchar *label;
-
- /* We only allow keybinding actions with those */
- settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number,
- META_PAD_DIRECTION_CW, mode);
- settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number,
- META_PAD_DIRECTION_CCW, mode);
- label = compose_directional_action_label (settings1, settings2);
- g_object_unref (settings1);
- g_object_unref (settings2);
-
- return label;
-}
-
-static gchar *
-meta_input_settings_get_strip_label (MetaInputSettings *settings,
- ClutterInputDevice *pad,
- guint number,
- guint mode)
-{
- GSettings *settings1, *settings2;
- gchar *label;
-
- /* We only allow keybinding actions with those */
- settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number,
- META_PAD_DIRECTION_UP, mode);
- settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number,
- META_PAD_DIRECTION_DOWN, mode);
- label = compose_directional_action_label (settings1, settings2);
- g_object_unref (settings1);
- g_object_unref (settings2);
-
- return label;
-}
-
-static gchar *
-meta_input_settings_get_button_label (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- guint button)
-{
- GDesktopPadButtonAction action;
- gint group;
-
- g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), NULL);
- g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), NULL);
- g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
- CLUTTER_PAD_DEVICE, NULL);
-
- group = clutter_input_device_get_mode_switch_button_group (pad, button);
-
- if (group >= 0)
- {
- /* TRANSLATORS: This string refers to a button that switches between
- * different modes.
- */
- return g_strdup_printf (_("Mode Switch (Group %d)"), group);
- }
-
- action = meta_input_settings_get_pad_button_action (input_settings, pad, button);
-
- switch (action)
- {
- case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
- {
- GSettings *settings;
- gchar *accel;
-
- settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
- button, META_PAD_DIRECTION_NONE, -1);
- accel = g_settings_get_string (settings, "keybinding");
- g_object_unref (settings);
-
- return accel;
- }
- case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
- /* TRANSLATORS: This string refers to an action, cycles drawing tablets'
- * mapping through the available outputs.
- */
- return g_strdup (_("Switch monitor"));
- case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
- return g_strdup (_("Show on-screen help"));
- case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
- default:
- return NULL;
- }
-}
-
-static guint
-get_current_pad_mode (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- MetaPadActionType action_type,
- guint number)
-{
- MetaInputSettingsPrivate *priv;
- DeviceMappingInfo *info;
- guint group = 0, n_groups;
-
- priv = meta_input_settings_get_instance_private (input_settings);
- info = g_hash_table_lookup (priv->mappable_devices, pad);
- n_groups = clutter_input_device_get_n_mode_groups (pad);
-
- if (!info->group_modes || n_groups == 0)
- return 0;
-
- if (action_type == META_PAD_ACTION_RING ||
- action_type == META_PAD_ACTION_STRIP)
- {
- /* Assume features are evenly distributed in groups */
- group = number % n_groups;
- }
-
- return info->group_modes[group];
-}
-
-gchar *
-meta_input_settings_get_pad_action_label (MetaInputSettings *input_settings,
- ClutterInputDevice *pad,
- MetaPadActionType action_type,
- guint number)
-{
- guint mode;
-
- switch (action_type)
- {
- case META_PAD_ACTION_BUTTON:
- return meta_input_settings_get_button_label (input_settings, pad, number);
- case META_PAD_ACTION_RING:
- mode = get_current_pad_mode (input_settings, pad, action_type, number);
- return meta_input_settings_get_ring_label (input_settings, pad,
- number, mode);
- case META_PAD_ACTION_STRIP:
- mode = get_current_pad_mode (input_settings, pad, action_type, number);
- return meta_input_settings_get_strip_label (input_settings, pad,
- number, mode);
- }
-
- return NULL;
-}
-
void
meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings)
{
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 994bc45dcd..32187a929c 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -38,6 +38,7 @@
#include "clutter/clutter.h"
#include "core/keybindings-private.h"
#include "core/meta-gesture-tracker-private.h"
+#include "core/meta-pad-action-mapper.h"
#include "core/stack-tracker.h"
#include "core/startup-notification-private.h"
#include "meta/barrier.h"
@@ -211,6 +212,7 @@ struct _MetaDisplay
ClutterEventSequence *pointer_emulating_sequence;
ClutterActor *current_pad_osd;
+ MetaPadActionMapper *pad_action_mapper;
MetaStartupNotification *startup_notification;
diff --git a/src/core/display.c b/src/core/display.c
index 81410b18e6..a665de40c3 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -854,6 +854,8 @@ meta_display_open (void)
g_signal_connect (monitor_manager, "monitors-changed-internal",
G_CALLBACK (on_monitors_changed_internal), display);
+ display->pad_action_mapper = meta_pad_action_mapper_new (monitor_manager);
+
settings = meta_backend_get_settings (backend);
g_signal_connect (settings, "ui-scaling-factor-changed",
G_CALLBACK (on_ui_scaling_factor_changed), display);
@@ -1119,6 +1121,7 @@ meta_display_close (MetaDisplay *display,
meta_clipboard_manager_shutdown (display);
g_clear_object (&display->selection);
+ g_clear_object (&display->pad_action_mapper);
g_object_unref (display);
the_display = NULL;
@@ -2961,12 +2964,12 @@ meta_display_get_pad_action_label (MetaDisplay *display,
MetaPadActionType action_type,
guint action_number)
{
- MetaInputSettings *settings;
gchar *label;
/* First, lookup the action, as imposed by settings */
- settings = meta_backend_get_input_settings (meta_get_backend ());
- label = meta_input_settings_get_pad_action_label (settings, pad, action_type, action_number);
+ label = meta_pad_action_mapper_get_action_label (display->pad_action_mapper,
+ pad, action_type,
+ action_number);
if (label)
return label;
diff --git a/src/core/events.c b/src/core/events.c
index 288ba499f4..8ba3dc82f3 100644
--- a/src/core/events.c
+++ b/src/core/events.c
@@ -262,8 +262,7 @@ meta_display_handle_event (MetaDisplay *display,
handle_pad_event = !display->current_pad_osd || is_mode_switch;
if (handle_pad_event &&
- meta_input_settings_handle_pad_event (meta_backend_get_input_settings (backend),
- event))
+ meta_pad_action_mapper_handle_event (display->pad_action_mapper, event))
{
bypass_wayland = bypass_clutter = TRUE;
goto out;
diff --git a/src/core/meta-pad-action-mapper.c b/src/core/meta-pad-action-mapper.c
new file mode 100644
index 0000000000..4368782109
--- /dev/null
+++ b/src/core/meta-pad-action-mapper.c
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2014-2020 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ * Carlos Garnacho <carlosg gnome org>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gsettings-desktop-schemas/gdesktop-enums.h>
+
+#ifdef HAVE_LIBWACOM
+#include <libwacom/libwacom.h>
+#endif
+
+#include "meta-pad-action-mapper.h"
+#include "backends/meta-input-device-private.h"
+#include "backends/meta-logical-monitor.h"
+#include "backends/meta-monitor.h"
+#include "core/display-private.h"
+
+typedef struct _PadMappingInfo PadMappingInfo;
+
+struct _PadMappingInfo
+{
+ ClutterInputDevice *device;
+ GSettings *settings;
+ guint *group_modes;
+};
+
+typedef enum
+{
+ META_PAD_DIRECTION_NONE = -1,
+ META_PAD_DIRECTION_UP = 0,
+ META_PAD_DIRECTION_DOWN,
+ META_PAD_DIRECTION_CW,
+ META_PAD_DIRECTION_CCW,
+} MetaPadDirection;
+
+struct _MetaPadActionMapper
+{
+ GObject parent_class;
+
+ GHashTable *pads;
+ ClutterSeat *seat;
+ ClutterVirtualInputDevice *virtual_pad_keyboard;
+ MetaMonitorManager *monitor_manager;
+
+ /* Pad ring/strip emission */
+ struct {
+ ClutterInputDevice *pad;
+ MetaPadActionType action;
+ guint number;
+ double value;
+ } last_pad_action_info;
+};
+
+G_DEFINE_TYPE (MetaPadActionMapper, meta_pad_action_mapper, G_TYPE_OBJECT)
+
+static void
+meta_pad_action_mapper_finalize (GObject *object)
+{
+ MetaPadActionMapper *mapper = META_PAD_ACTION_MAPPER (object);
+
+ g_hash_table_unref (mapper->pads);
+ g_object_unref (mapper->monitor_manager);
+ g_clear_object (&mapper->virtual_pad_keyboard);
+
+ G_OBJECT_CLASS (meta_pad_action_mapper_parent_class)->finalize (object);
+}
+
+static void
+meta_pad_action_mapper_class_init (MetaPadActionMapperClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = meta_pad_action_mapper_finalize;
+}
+
+static GSettings *
+lookup_device_settings (ClutterInputDevice *device)
+{
+ const char *vendor, *product;
+ GSettings *settings;
+ char *path;
+
+ vendor = clutter_input_device_get_vendor_id (device);
+ product = clutter_input_device_get_product_id (device);
+ path = g_strdup_printf ("/org/gnome/desktop/peripherals/tablets/%s:%s/",
+ vendor, product);
+
+ settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet",
+ path);
+ g_free (path);
+
+ return settings;
+}
+
+static PadMappingInfo *
+pad_mapping_info_new (ClutterInputDevice *pad)
+{
+ PadMappingInfo *info;
+
+ info = g_new0 (PadMappingInfo, 1);
+ info->device = pad;
+ info->settings = lookup_device_settings (pad);
+ info->group_modes =
+ g_new0 (guint, clutter_input_device_get_n_mode_groups (pad));
+
+ return info;
+}
+
+static void
+pad_mapping_info_free (PadMappingInfo *info)
+{
+ g_object_unref (info->settings);
+ g_free (info->group_modes);
+ g_free (info);
+}
+
+static void
+device_added (ClutterSeat *seat,
+ ClutterInputDevice *device,
+ MetaPadActionMapper *mapper)
+{
+ PadMappingInfo *info;
+
+ if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE)
+ {
+ info = pad_mapping_info_new (device);
+ g_hash_table_insert (mapper->pads, device, info);
+ }
+}
+
+static void
+device_removed (ClutterSeat *seat,
+ ClutterInputDevice *device,
+ MetaPadActionMapper *mapper)
+{
+ g_hash_table_remove (mapper->pads, device);
+}
+
+static void
+meta_pad_action_mapper_init (MetaPadActionMapper *mapper)
+{
+ mapper->pads = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) pad_mapping_info_free);
+
+ mapper->seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
+ g_signal_connect (mapper->seat, "device-added",
+ G_CALLBACK (device_added), mapper);
+ g_signal_connect (mapper->seat, "device-removed",
+ G_CALLBACK (device_removed), mapper);
+}
+
+MetaPadActionMapper *
+meta_pad_action_mapper_new (MetaMonitorManager *monitor_manager)
+{
+ MetaPadActionMapper *action_mapper;
+
+ action_mapper = g_object_new (META_TYPE_PAD_ACTION_MAPPER, NULL);
+ g_set_object (&action_mapper->monitor_manager, monitor_manager);
+
+ return action_mapper;
+}
+
+static GSettings *
+lookup_pad_action_settings (ClutterInputDevice *device,
+ MetaPadActionType action,
+ guint number,
+ MetaPadDirection direction,
+ int mode)
+{
+ const char *vendor, *product, *action_type, *detail_type = NULL;
+ GSettings *settings;
+ GString *path;
+ char action_label;
+
+ vendor = clutter_input_device_get_vendor_id (device);
+ product = clutter_input_device_get_product_id (device);
+
+ action_label = 'A' + number;
+
+ switch (action)
+ {
+ case META_PAD_ACTION_BUTTON:
+ action_type = "button";
+ break;
+ case META_PAD_ACTION_RING:
+ g_assert (direction == META_PAD_DIRECTION_CW ||
+ direction == META_PAD_DIRECTION_CCW);
+ action_type = "ring";
+ detail_type = (direction == META_PAD_DIRECTION_CW) ? "cw" : "ccw";
+ break;
+ case META_PAD_ACTION_STRIP:
+ g_assert (direction == META_PAD_DIRECTION_UP ||
+ direction == META_PAD_DIRECTION_DOWN);
+ action_type = "strip";
+ detail_type = (direction == META_PAD_DIRECTION_UP) ? "up" : "down";
+ break;
+ default:
+ return NULL;
+ }
+
+ path = g_string_new (NULL);
+ g_string_append_printf (path, "/org/gnome/desktop/peripherals/tablets/%s:%s/%s%c",
+ vendor, product, action_type, action_label);
+
+ if (detail_type)
+ g_string_append_printf (path, "-%s", detail_type);
+
+ if (mode >= 0)
+ g_string_append_printf (path, "-mode-%d", mode);
+
+ g_string_append_c (path, '/');
+
+ settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.pad-button",
+ path->str);
+ g_string_free (path, TRUE);
+
+ return settings;
+}
+
+static GDesktopPadButtonAction
+meta_pad_action_mapper_get_button_action (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ guint button)
+{
+ GDesktopPadButtonAction action;
+ GSettings *settings;
+
+ g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper),
+ G_DESKTOP_PAD_BUTTON_ACTION_NONE);
+ g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad),
+ G_DESKTOP_PAD_BUTTON_ACTION_NONE);
+
+ settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
+ button, META_PAD_DIRECTION_NONE, -1);
+ action = g_settings_get_enum (settings, "action");
+ g_object_unref (settings);
+
+ return action;
+}
+
+static gboolean
+cycle_logical_monitors (MetaPadActionMapper *mapper,
+ gboolean skip_all_monitors,
+ MetaLogicalMonitor *current_logical_monitor,
+ MetaLogicalMonitor **next_logical_monitor)
+{
+ MetaMonitorManager *monitor_manager = mapper->monitor_manager;
+ GList *logical_monitors;
+
+ /* We cycle between:
+ * - the span of all monitors (current_output = NULL), only for
+ * non-integrated devices.
+ * - each monitor individually.
+ */
+
+ logical_monitors =
+ meta_monitor_manager_get_logical_monitors (monitor_manager);
+
+ if (!current_logical_monitor)
+ {
+ *next_logical_monitor = logical_monitors->data;
+ }
+ else
+ {
+ GList *l;
+
+ l = g_list_find (logical_monitors, current_logical_monitor);
+ if (l->next)
+ *next_logical_monitor = l->next->data;
+ else if (skip_all_monitors)
+ *next_logical_monitor = logical_monitors->data;
+ else
+ *next_logical_monitor = NULL;
+ }
+
+ return TRUE;
+}
+
+static MetaMonitor *
+logical_monitor_find_monitor (MetaLogicalMonitor *logical_monitor,
+ const char *vendor,
+ const char *product,
+ const char *serial)
+{
+ GList *monitors;
+ GList *l;
+
+ monitors = meta_logical_monitor_get_monitors (logical_monitor);
+ for (l = monitors; l; l = l->next)
+ {
+ MetaMonitor *monitor = l->data;
+
+ if (g_strcmp0 (meta_monitor_get_vendor (monitor), vendor) == 0 &&
+ g_strcmp0 (meta_monitor_get_product (monitor), product) == 0 &&
+ g_strcmp0 (meta_monitor_get_serial (monitor), serial) == 0)
+ return monitor;
+ }
+
+ return NULL;
+}
+
+static void
+meta_pad_action_mapper_find_monitor (MetaPadActionMapper *mapper,
+ GSettings *settings,
+ ClutterInputDevice *device,
+ MetaMonitor **out_monitor,
+ MetaLogicalMonitor **out_logical_monitor)
+{
+ MetaMonitorManager *monitor_manager;
+ MetaMonitor *monitor;
+ guint n_values;
+ GList *logical_monitors;
+ GList *l;
+ char **edid;
+
+ edid = g_settings_get_strv (settings, "output");
+ n_values = g_strv_length (edid);
+
+ if (n_values != 3)
+ {
+ g_warning ("EDID configuration for device '%s' "
+ "is incorrect, must have 3 values",
+ clutter_input_device_get_device_name (device));
+ goto out;
+ }
+
+ if (!*edid[0] && !*edid[1] && !*edid[2])
+ goto out;
+
+ monitor_manager = mapper->monitor_manager;
+ logical_monitors =
+ meta_monitor_manager_get_logical_monitors (monitor_manager);
+ for (l = logical_monitors; l; l = l->next)
+ {
+ MetaLogicalMonitor *logical_monitor = l->data;
+
+ monitor = logical_monitor_find_monitor (logical_monitor,
+ edid[0], edid[1], edid[2]);
+ if (monitor)
+ {
+ if (out_monitor)
+ *out_monitor = monitor;
+ if (out_logical_monitor)
+ *out_logical_monitor = logical_monitor;
+ break;
+ }
+ }
+
+out:
+ g_strfreev (edid);
+}
+
+static void
+meta_pad_action_mapper_cycle_tablet_output (MetaPadActionMapper *mapper,
+ ClutterInputDevice *device)
+{
+ PadMappingInfo *info;
+ MetaLogicalMonitor *logical_monitor = NULL;
+ const char *edid[4] = { 0 }, *pretty_name = NULL;
+ gboolean is_integrated_device = FALSE;
+#ifdef HAVE_LIBWACOM
+ WacomDevice *wacom_device;
+#endif
+
+ g_return_if_fail (META_IS_PAD_ACTION_MAPPER (mapper));
+ g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
+ g_return_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE ||
+ clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE);
+
+ info = g_hash_table_lookup (mapper->pads, device);
+ g_return_if_fail (info != NULL);
+
+#ifdef HAVE_LIBWACOM
+ wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
+
+ if (wacom_device)
+ {
+ pretty_name = libwacom_get_name (wacom_device);
+ is_integrated_device =
+ libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE;
+ }
+#endif
+
+ meta_pad_action_mapper_find_monitor (mapper, info->settings, device,
+ NULL, &logical_monitor);
+
+ if (!cycle_logical_monitors (mapper,
+ is_integrated_device,
+ logical_monitor,
+ &logical_monitor))
+ return;
+
+ if (logical_monitor)
+ {
+ MetaMonitor *monitor;
+
+ /* Pick an arbitrary monitor in the logical monitor to represent it. */
+ monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
+ edid[0] = meta_monitor_get_vendor (monitor);
+ edid[1] = meta_monitor_get_product (monitor);
+ edid[2] = meta_monitor_get_serial (monitor);
+ }
+ else
+ {
+ edid[0] = "";
+ edid[1] = "";
+ edid[2] = "";
+ }
+
+ g_settings_set_strv (info->settings, "output", edid);
+ meta_display_show_tablet_mapping_notification (meta_get_display (),
+ device, pretty_name);
+}
+
+gboolean
+meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ guint button)
+{
+ g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), FALSE);
+ g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), FALSE);
+ g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
+ CLUTTER_PAD_DEVICE, FALSE);
+
+ return (meta_pad_action_mapper_get_button_action (mapper, pad, button) !=
+ G_DESKTOP_PAD_BUTTON_ACTION_NONE);
+}
+
+static void
+emulate_modifiers (ClutterVirtualInputDevice *device,
+ ClutterModifierType mods,
+ ClutterKeyState state)
+{
+ guint i;
+ struct {
+ ClutterModifierType mod;
+ guint keyval;
+ } mod_map[] = {
+ { CLUTTER_SHIFT_MASK, CLUTTER_KEY_Shift_L },
+ { CLUTTER_CONTROL_MASK, CLUTTER_KEY_Control_L },
+ { CLUTTER_MOD1_MASK, CLUTTER_KEY_Meta_L }
+ };
+
+ for (i = 0; i < G_N_ELEMENTS (mod_map); i++)
+ {
+ if ((mods & mod_map[i].mod) == 0)
+ continue;
+
+ clutter_virtual_input_device_notify_keyval (device,
+ clutter_get_current_event_time (),
+ mod_map[i].keyval, state);
+ }
+}
+
+static void
+meta_pad_action_mapper_emulate_keybinding (MetaPadActionMapper *mapper,
+ const char *accel,
+ gboolean is_press)
+{
+ ClutterKeyState state;
+ guint key, mods;
+
+ if (!accel || !*accel)
+ return;
+
+ /* FIXME: This is appalling */
+ gtk_accelerator_parse (accel, &key, &mods);
+
+ if (!mapper->virtual_pad_keyboard)
+ {
+ ClutterBackend *backend;
+ ClutterSeat *seat;
+
+ backend = clutter_get_default_backend ();
+ seat = clutter_backend_get_default_seat (backend);
+
+ mapper->virtual_pad_keyboard =
+ clutter_seat_create_virtual_device (seat,
+ CLUTTER_KEYBOARD_DEVICE);
+ }
+
+ state = is_press ? CLUTTER_KEY_STATE_PRESSED : CLUTTER_KEY_STATE_RELEASED;
+
+ if (is_press)
+ emulate_modifiers (mapper->virtual_pad_keyboard, mods, state);
+
+ clutter_virtual_input_device_notify_keyval (mapper->virtual_pad_keyboard,
+ clutter_get_current_event_time (),
+ key, state);
+ if (!is_press)
+ emulate_modifiers (mapper->virtual_pad_keyboard, mods, state);
+}
+
+static gboolean
+meta_pad_action_mapper_handle_button (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ const ClutterPadButtonEvent *event)
+{
+ GDesktopPadButtonAction action;
+ int button, group, mode;
+ gboolean is_press;
+ GSettings *settings;
+ char *accel;
+
+ g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), FALSE);
+ g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS ||
+ event->type == CLUTTER_PAD_BUTTON_RELEASE, FALSE);
+
+ button = event->button;
+ mode = event->mode;
+ group = clutter_input_device_get_mode_switch_button_group (pad, button);
+ is_press = event->type == CLUTTER_PAD_BUTTON_PRESS;
+
+ if (is_press && group >= 0)
+ {
+ guint n_modes = clutter_input_device_get_group_n_modes (pad, group);
+ const char *pretty_name = NULL;
+ PadMappingInfo *info;
+#ifdef HAVE_LIBWACOM
+ WacomDevice *wacom_device;
+#endif
+
+ info = g_hash_table_lookup (mapper->pads, pad);
+
+#ifdef HAVE_LIBWACOM
+ wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (pad));
+
+ if (wacom_device)
+ pretty_name = libwacom_get_name (wacom_device);
+#endif
+ meta_display_notify_pad_group_switch (meta_get_display (), pad,
+ pretty_name, group, mode, n_modes);
+ info->group_modes[group] = mode;
+ }
+
+ action = meta_pad_action_mapper_get_button_action (mapper, pad, button);
+
+ switch (action)
+ {
+ case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
+ if (is_press)
+ meta_pad_action_mapper_cycle_tablet_output (mapper, pad);
+ return TRUE;
+ case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
+ if (is_press)
+ meta_display_request_pad_osd (meta_get_display (), pad, FALSE);
+ return TRUE;
+ case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
+ settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
+ button, META_PAD_DIRECTION_NONE, -1);
+ accel = g_settings_get_string (settings, "keybinding");
+ meta_pad_action_mapper_emulate_keybinding (mapper, accel, is_press);
+ g_object_unref (settings);
+ g_free (accel);
+ return TRUE;
+ case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
+ default:
+ return FALSE;
+ }
+}
+
+static gboolean
+meta_pad_action_mapper_handle_action (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ MetaPadActionType action,
+ guint number,
+ MetaPadDirection direction,
+ guint mode)
+{
+ GSettings *settings;
+ gboolean handled = FALSE;
+ char *accel;
+
+ settings = lookup_pad_action_settings (pad, action, number, direction, mode);
+ accel = g_settings_get_string (settings, "keybinding");
+
+ if (accel && *accel)
+ {
+ meta_pad_action_mapper_emulate_keybinding (mapper, accel, TRUE);
+ meta_pad_action_mapper_emulate_keybinding (mapper, accel, FALSE);
+ handled = TRUE;
+ }
+
+ g_object_unref (settings);
+ g_free (accel);
+
+ return handled;
+}
+
+static gboolean
+meta_pad_action_mapper_get_action_direction (MetaPadActionMapper *mapper,
+ const ClutterEvent *event,
+ MetaPadDirection *direction)
+{
+ ClutterInputDevice *pad = clutter_event_get_device (event);
+ MetaPadActionType pad_action;
+ gboolean has_direction = FALSE;
+ MetaPadDirection inc_dir, dec_dir;
+ guint number;
+ double value;
+
+ *direction = META_PAD_DIRECTION_NONE;
+
+ switch (event->type)
+ {
+ case CLUTTER_PAD_RING:
+ pad_action = META_PAD_ACTION_RING;
+ number = event->pad_ring.ring_number;
+ value = event->pad_ring.angle;
+ inc_dir = META_PAD_DIRECTION_CW;
+ dec_dir = META_PAD_DIRECTION_CCW;
+ break;
+ case CLUTTER_PAD_STRIP:
+ pad_action = META_PAD_ACTION_STRIP;
+ number = event->pad_strip.strip_number;
+ value = event->pad_strip.value;
+ inc_dir = META_PAD_DIRECTION_DOWN;
+ dec_dir = META_PAD_DIRECTION_UP;
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (mapper->last_pad_action_info.pad == pad &&
+ mapper->last_pad_action_info.action == pad_action &&
+ mapper->last_pad_action_info.number == number &&
+ value >= 0 && mapper->last_pad_action_info.value >= 0)
+ {
+ *direction = (value - mapper->last_pad_action_info.value) > 0 ?
+ inc_dir : dec_dir;
+ has_direction = TRUE;
+ }
+
+ mapper->last_pad_action_info.pad = pad;
+ mapper->last_pad_action_info.action = pad_action;
+ mapper->last_pad_action_info.number = number;
+ mapper->last_pad_action_info.value = value;
+ return has_direction;
+}
+
+gboolean
+meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper,
+ const ClutterEvent *event)
+{
+ ClutterInputDevice *pad;
+ MetaPadDirection direction = META_PAD_DIRECTION_NONE;
+
+ pad = clutter_event_get_source_device ((ClutterEvent *) event);
+
+ switch (event->type)
+ {
+ case CLUTTER_PAD_BUTTON_PRESS:
+ case CLUTTER_PAD_BUTTON_RELEASE:
+ return meta_pad_action_mapper_handle_button (mapper, pad,
+ &event->pad_button);
+ case CLUTTER_PAD_RING:
+ if (!meta_pad_action_mapper_get_action_direction (mapper,
+ event, &direction))
+ return FALSE;
+ return meta_pad_action_mapper_handle_action (mapper, pad,
+ META_PAD_ACTION_RING,
+ event->pad_ring.ring_number,
+ direction,
+ event->pad_ring.mode);
+ case CLUTTER_PAD_STRIP:
+ if (!meta_pad_action_mapper_get_action_direction (mapper,
+ event, &direction))
+ return FALSE;
+ return meta_pad_action_mapper_handle_action (mapper, pad,
+ META_PAD_ACTION_STRIP,
+ event->pad_strip.strip_number,
+ direction,
+ event->pad_strip.mode);
+ default:
+ return FALSE;
+ }
+}
+
+
+static char *
+compose_directional_action_label (GSettings *direction1,
+ GSettings *direction2)
+{
+ char *accel1, *accel2, *str = NULL;
+
+ accel1 = g_settings_get_string (direction1, "keybinding");
+ accel2 = g_settings_get_string (direction2, "keybinding");
+
+ if (accel1 && *accel1 && accel2 && *accel2)
+ str = g_strdup_printf ("%s / %s", accel1, accel2);
+
+ g_free (accel1);
+ g_free (accel2);
+
+ return str;
+}
+
+static char *
+meta_pad_action_mapper_get_ring_label (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ guint number,
+ guint mode)
+{
+ GSettings *settings1, *settings2;
+ char *label;
+
+ /* We only allow keybinding actions with those */
+ settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number,
+ META_PAD_DIRECTION_CW, mode);
+ settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number,
+ META_PAD_DIRECTION_CCW, mode);
+ label = compose_directional_action_label (settings1, settings2);
+ g_object_unref (settings1);
+ g_object_unref (settings2);
+
+ return label;
+}
+
+static char *
+meta_pad_action_mapper_get_strip_label (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ guint number,
+ guint mode)
+{
+ GSettings *settings1, *settings2;
+ char *label;
+
+ /* We only allow keybinding actions with those */
+ settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number,
+ META_PAD_DIRECTION_UP, mode);
+ settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number,
+ META_PAD_DIRECTION_DOWN, mode);
+ label = compose_directional_action_label (settings1, settings2);
+ g_object_unref (settings1);
+ g_object_unref (settings2);
+
+ return label;
+}
+
+static char *
+meta_pad_action_mapper_get_button_label (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ guint button)
+{
+ GDesktopPadButtonAction action;
+ int group;
+
+ g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), NULL);
+ g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), NULL);
+ g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
+ CLUTTER_PAD_DEVICE, NULL);
+
+ group = clutter_input_device_get_mode_switch_button_group (pad, button);
+
+ if (group >= 0)
+ {
+ /* TRANSLATORS: This string refers to a button that switches between
+ * different modes.
+ */
+ return g_strdup_printf (_("Mode Switch (Group %d)"), group);
+ }
+
+ action = meta_pad_action_mapper_get_button_action (mapper, pad, button);
+
+ switch (action)
+ {
+ case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
+ {
+ GSettings *settings;
+ char *accel;
+
+ settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
+ button, META_PAD_DIRECTION_NONE, -1);
+ accel = g_settings_get_string (settings, "keybinding");
+ g_object_unref (settings);
+
+ return accel;
+ }
+ case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
+ /* TRANSLATORS: This string refers to an action, cycles drawing tablets'
+ * mapping through the available outputs.
+ */
+ return g_strdup (_("Switch monitor"));
+ case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
+ return g_strdup (_("Show on-screen help"));
+ case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
+ default:
+ return NULL;
+ }
+}
+
+static guint
+get_current_pad_mode (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ MetaPadActionType action_type,
+ guint number)
+{
+ PadMappingInfo *info;
+ guint group = 0, n_groups;
+
+ info = g_hash_table_lookup (mapper->pads, pad);
+ n_groups = clutter_input_device_get_n_mode_groups (pad);
+
+ if (!info->group_modes || n_groups == 0)
+ return 0;
+
+ if (action_type == META_PAD_ACTION_RING ||
+ action_type == META_PAD_ACTION_STRIP)
+ {
+ /* Assume features are evenly distributed in groups */
+ group = number % n_groups;
+ }
+
+ return info->group_modes[group];
+}
+
+char *
+meta_pad_action_mapper_get_action_label (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ MetaPadActionType action_type,
+ guint number)
+{
+ guint mode;
+
+ switch (action_type)
+ {
+ case META_PAD_ACTION_BUTTON:
+ return meta_pad_action_mapper_get_button_label (mapper, pad, number);
+ case META_PAD_ACTION_RING:
+ mode = get_current_pad_mode (mapper, pad, action_type, number);
+ return meta_pad_action_mapper_get_ring_label (mapper, pad, number, mode);
+ case META_PAD_ACTION_STRIP:
+ mode = get_current_pad_mode (mapper, pad, action_type, number);
+ return meta_pad_action_mapper_get_strip_label (mapper, pad, number, mode);
+ }
+
+ return NULL;
+}
diff --git a/src/core/meta-pad-action-mapper.h b/src/core/meta-pad-action-mapper.h
new file mode 100644
index 0000000000..c1a7776d8b
--- /dev/null
+++ b/src/core/meta-pad-action-mapper.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ * Carlos Garnacho <carlosg gnome org>
+ */
+
+#ifndef META_PAD_ACTION_MAPPER_H
+#define META_PAD_ACTION_MAPPER_H
+
+#include <clutter/clutter.h>
+
+#include "meta/display.h"
+#include "meta/meta-monitor-manager.h"
+
+#define META_TYPE_PAD_ACTION_MAPPER (meta_pad_action_mapper_get_type ())
+G_DECLARE_FINAL_TYPE (MetaPadActionMapper, meta_pad_action_mapper,
+ META, PAD_ACTION_MAPPER, GObject)
+
+MetaPadActionMapper * meta_pad_action_mapper_new (MetaMonitorManager *monitor_manager);
+
+gboolean meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ guint button);
+gboolean meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper,
+ const ClutterEvent *event);
+gchar * meta_pad_action_mapper_get_action_label (MetaPadActionMapper *mapper,
+ ClutterInputDevice *pad,
+ MetaPadActionType action,
+ guint number);
+
+#endif /* META_PAD_ACTION_MAPPER_H */
diff --git a/src/meson.build b/src/meson.build
index 3da557f55e..1b40c168e0 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -374,6 +374,7 @@ mutter_sources = [
'core/meta-inhibit-shortcuts-dialog-default.c',
'core/meta-inhibit-shortcuts-dialog-default-private.h',
'core/meta-launch-context.c',
+ 'core/meta-pad-action-mapper.c',
'core/meta-selection.c',
'core/meta-selection-source.c',
'core/meta-selection-source-memory.c',
diff --git a/src/wayland/meta-wayland-tablet-pad.c b/src/wayland/meta-wayland-tablet-pad.c
index 167d45948f..d96bdfed45 100644
--- a/src/wayland/meta-wayland-tablet-pad.c
+++ b/src/wayland/meta-wayland-tablet-pad.c
@@ -28,6 +28,7 @@
#include <wayland-server.h>
#include "backends/meta-input-settings-private.h"
+#include "core/display-private.h"
#include "compositor/meta-surface-actor-wayland.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-tablet-pad-group.h"
@@ -244,15 +245,14 @@ tablet_pad_set_feedback (struct wl_client *client,
{
MetaWaylandTabletPad *pad = wl_resource_get_user_data (resource);
MetaWaylandTabletPadGroup *group = tablet_pad_lookup_button_group (pad, button);
- MetaInputSettings *input_settings;
+ MetaPadActionMapper *mapper;
if (!group || group->mode_switch_serial != serial)
return;
- input_settings = meta_backend_get_input_settings (meta_get_backend ());
+ mapper = meta_get_display ()->pad_action_mapper;
- if (input_settings &&
- meta_input_settings_is_pad_button_grabbed (input_settings, pad->device, button))
+ if (meta_pad_action_mapper_is_button_grabbed (mapper, pad->device, button))
return;
if (meta_wayland_tablet_pad_group_is_mode_switch_button (group, button))
@@ -367,15 +367,14 @@ static gboolean
meta_wayland_tablet_pad_handle_event_action (MetaWaylandTabletPad *pad,
const ClutterEvent *event)
{
- MetaInputSettings *input_settings;
+ MetaPadActionMapper *mapper;
ClutterInputDevice *device;
device = clutter_event_get_source_device (event);
- input_settings = meta_backend_get_input_settings (meta_get_backend ());
+ mapper = meta_get_display ()->pad_action_mapper;
- if (input_settings &&
- meta_input_settings_is_pad_button_grabbed (input_settings, device,
- event->pad_button.button))
+ if (meta_pad_action_mapper_is_button_grabbed (mapper, device,
+ event->pad_button.button))
return TRUE;
return FALSE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]