core: Add a MetaTabletActionMapper as parent of the MetaPadActionMapper
This is prep work for using the same functionality for tablet tools as well. The new MetaTabletActionMapper takes care of the event bubbling via the device-added/removed and input-event signals and provides the helper functions to cycle outputs and/or emulate keybindings. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3649>
This commit is contained in:
parent
94e497f630
commit
6c77af1493
6 changed files with 682 additions and 323 deletions
|
@ -235,6 +235,7 @@ meta_display_handle_event (MetaDisplay *display,
|
|||
ClutterEventSequence *sequence;
|
||||
ClutterEventType event_type;
|
||||
gboolean has_grab;
|
||||
MetaTabletActionMapper *mapper;
|
||||
#ifdef HAVE_WAYLAND
|
||||
MetaWaylandCompositor *wayland_compositor;
|
||||
MetaWaylandTextInput *wayland_text_input = NULL;
|
||||
|
@ -318,17 +319,23 @@ meta_display_handle_event (MetaDisplay *display,
|
|||
}
|
||||
|
||||
handle_pad_event = !display->current_pad_osd || is_mode_switch;
|
||||
mapper = META_TABLET_ACTION_MAPPER (display->pad_action_mapper);
|
||||
|
||||
if (handle_pad_event &&
|
||||
meta_pad_action_mapper_handle_event (display->pad_action_mapper, event))
|
||||
meta_tablet_action_mapper_handle_event (mapper, event))
|
||||
return CLUTTER_EVENT_STOP;
|
||||
}
|
||||
|
||||
if (event_type != CLUTTER_DEVICE_ADDED &&
|
||||
event_type != CLUTTER_DEVICE_REMOVED)
|
||||
handle_idletime_for_event (display, event);
|
||||
{
|
||||
handle_idletime_for_event (display, event);
|
||||
}
|
||||
else
|
||||
meta_pad_action_mapper_handle_event (display->pad_action_mapper, event);
|
||||
{
|
||||
mapper = META_TABLET_ACTION_MAPPER (display->pad_action_mapper);
|
||||
meta_tablet_action_mapper_handle_event (mapper, event);
|
||||
}
|
||||
|
||||
if (event_type == CLUTTER_MOTION)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2020 Red Hat
|
||||
* Copyright (C) 2014-2024 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
|
||||
|
@ -38,7 +38,6 @@ typedef struct _PadMappingInfo PadMappingInfo;
|
|||
struct _PadMappingInfo
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
GSettings *settings;
|
||||
guint *group_modes;
|
||||
};
|
||||
|
||||
|
@ -47,9 +46,6 @@ struct _MetaPadActionMapper
|
|||
GObject parent_class;
|
||||
|
||||
GHashTable *pads;
|
||||
ClutterSeat *seat;
|
||||
ClutterVirtualInputDevice *virtual_pad_keyboard;
|
||||
MetaMonitorManager *monitor_manager;
|
||||
|
||||
/* Pad ring/strip emission */
|
||||
struct {
|
||||
|
@ -60,17 +56,17 @@ struct _MetaPadActionMapper
|
|||
} last_pad_action_info;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaPadActionMapper, meta_pad_action_mapper, G_TYPE_OBJECT)
|
||||
G_DEFINE_TYPE (MetaPadActionMapper, meta_pad_action_mapper, META_TYPE_TABLET_ACTION_MAPPER);
|
||||
|
||||
static MetaDisplay *
|
||||
display_from_mapper (MetaPadActionMapper *mapper)
|
||||
{
|
||||
MetaBackend *backend =
|
||||
meta_monitor_manager_get_backend (mapper->monitor_manager);
|
||||
MetaContext *context = meta_backend_get_context (backend);
|
||||
|
||||
return meta_context_get_display (context);
|
||||
}
|
||||
static gboolean
|
||||
meta_pad_action_mapper_handle_event (MetaTabletActionMapper *mapper,
|
||||
const ClutterEvent *event);
|
||||
static void
|
||||
device_added (MetaTabletActionMapper *mapper,
|
||||
ClutterInputDevice *device);
|
||||
static void
|
||||
device_removed (MetaTabletActionMapper *mapper,
|
||||
ClutterInputDevice *device);
|
||||
|
||||
static void
|
||||
meta_pad_action_mapper_finalize (GObject *object)
|
||||
|
@ -78,8 +74,6 @@ 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);
|
||||
}
|
||||
|
@ -92,25 +86,6 @@ meta_pad_action_mapper_class_init (MetaPadActionMapperClass *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)
|
||||
{
|
||||
|
@ -118,7 +93,6 @@ pad_mapping_info_new (ClutterInputDevice *pad)
|
|||
|
||||
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));
|
||||
|
||||
|
@ -128,15 +102,15 @@ pad_mapping_info_new (ClutterInputDevice *pad)
|
|||
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 (MetaPadActionMapper *mapper,
|
||||
ClutterInputDevice *device)
|
||||
device_added (MetaTabletActionMapper *tablet_mapper,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaPadActionMapper *mapper = META_PAD_ACTION_MAPPER (tablet_mapper);
|
||||
PadMappingInfo *info;
|
||||
|
||||
if ((clutter_input_device_get_capabilities (device) &
|
||||
|
@ -148,26 +122,23 @@ device_added (MetaPadActionMapper *mapper,
|
|||
}
|
||||
|
||||
static void
|
||||
device_removed (MetaPadActionMapper *mapper,
|
||||
ClutterInputDevice *device)
|
||||
device_removed (MetaTabletActionMapper *tablet_mapper,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaPadActionMapper *mapper = META_PAD_ACTION_MAPPER (tablet_mapper);
|
||||
|
||||
g_hash_table_remove (mapper->pads, device);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_pad_action_mapper_init (MetaPadActionMapper *mapper)
|
||||
{
|
||||
g_autoptr (GList) devices = NULL;
|
||||
GList *l;
|
||||
g_signal_connect (mapper, "device-added", G_CALLBACK (device_added), NULL);
|
||||
g_signal_connect (mapper, "device-removed", G_CALLBACK (device_removed), NULL);
|
||||
g_signal_connect (mapper, "input-event", G_CALLBACK (meta_pad_action_mapper_handle_event), NULL);
|
||||
|
||||
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 ());
|
||||
devices = clutter_seat_list_devices (mapper->seat);
|
||||
|
||||
for (l = devices; l; l = l->next)
|
||||
device_added (mapper, l->data);
|
||||
}
|
||||
|
||||
MetaPadActionMapper *
|
||||
|
@ -175,8 +146,9 @@ 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);
|
||||
action_mapper = g_object_new (META_TYPE_PAD_ACTION_MAPPER,
|
||||
"monitor_manager", monitor_manager,
|
||||
NULL);
|
||||
|
||||
return action_mapper;
|
||||
}
|
||||
|
@ -268,187 +240,6 @@ meta_pad_action_mapper_get_button_action (MetaPadActionMapper *mapper,
|
|||
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_capabilities (device) &
|
||||
(CLUTTER_INPUT_CAPABILITY_TABLET_TOOL |
|
||||
CLUTTER_INPUT_CAPABILITY_TABLET_PAD)) != 0);
|
||||
|
||||
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;
|
||||
const char *vendor;
|
||||
const char *product;
|
||||
const char *serial;
|
||||
|
||||
/* Pick an arbitrary monitor in the logical monitor to represent it. */
|
||||
monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
|
||||
vendor = meta_monitor_get_vendor (monitor);
|
||||
product = meta_monitor_get_product (monitor);
|
||||
serial = meta_monitor_get_serial (monitor);
|
||||
edid[0] = vendor ? vendor : "";
|
||||
edid[1] = product ? product : "";
|
||||
edid[2] = serial ? serial : "";
|
||||
}
|
||||
else
|
||||
{
|
||||
edid[0] = "";
|
||||
edid[1] = "";
|
||||
edid[2] = "";
|
||||
}
|
||||
|
||||
g_settings_set_strv (info->settings, "output", edid);
|
||||
meta_display_show_tablet_mapping_notification (display_from_mapper (mapper),
|
||||
device, pretty_name);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper,
|
||||
ClutterInputDevice *pad,
|
||||
|
@ -463,86 +254,20 @@ meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper,
|
|||
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_Alt_L },
|
||||
{ CLUTTER_META_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;
|
||||
MetaKeyCombo combo = { 0 };
|
||||
|
||||
if (!accel || !*accel)
|
||||
return;
|
||||
|
||||
if (!meta_parse_accelerator (accel, &combo))
|
||||
{
|
||||
g_warning ("\"%s\" is not a valid accelerator", accel);
|
||||
return;
|
||||
}
|
||||
|
||||
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, combo.modifiers, state);
|
||||
|
||||
clutter_virtual_input_device_notify_keyval (mapper->virtual_pad_keyboard,
|
||||
clutter_get_current_event_time (),
|
||||
combo.keysym, state);
|
||||
if (!is_press)
|
||||
emulate_modifiers (mapper->virtual_pad_keyboard, combo.modifiers, state);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_pad_action_mapper_handle_button (MetaPadActionMapper *mapper,
|
||||
ClutterInputDevice *pad,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaTabletActionMapper *tablet_mapper = META_TABLET_ACTION_MAPPER (mapper);
|
||||
MetaTabletActionMapperClass *tablet_klass = META_TABLET_ACTION_MAPPER_GET_CLASS (mapper);
|
||||
GDesktopPadButtonAction action;
|
||||
int group, n_modes = 0;
|
||||
gboolean is_press;
|
||||
GSettings *settings;
|
||||
char *accel;
|
||||
uint32_t button, mode;
|
||||
MetaDisplay *display;
|
||||
|
||||
g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), FALSE);
|
||||
g_return_val_if_fail (clutter_event_type (event) == CLUTTER_PAD_BUTTON_PRESS ||
|
||||
|
@ -551,6 +276,7 @@ meta_pad_action_mapper_handle_button (MetaPadActionMapper *mapper,
|
|||
clutter_event_get_pad_details (event, &button, &mode, NULL, NULL);
|
||||
group = clutter_input_device_get_mode_switch_button_group (pad, button);
|
||||
is_press = clutter_event_type (event) == CLUTTER_PAD_BUTTON_PRESS;
|
||||
display = tablet_klass->get_display (tablet_mapper);
|
||||
|
||||
if (group >= 0)
|
||||
n_modes = clutter_input_device_get_group_n_modes (pad, group);
|
||||
|
@ -571,7 +297,7 @@ meta_pad_action_mapper_handle_button (MetaPadActionMapper *mapper,
|
|||
if (wacom_device)
|
||||
pretty_name = libwacom_get_name (wacom_device);
|
||||
#endif
|
||||
meta_display_notify_pad_group_switch (display_from_mapper (mapper), pad,
|
||||
meta_display_notify_pad_group_switch (display, pad,
|
||||
pretty_name, group, mode, n_modes);
|
||||
info->group_modes[group] = mode;
|
||||
}
|
||||
|
@ -582,16 +308,16 @@ meta_pad_action_mapper_handle_button (MetaPadActionMapper *mapper,
|
|||
{
|
||||
case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
|
||||
if (is_press)
|
||||
meta_pad_action_mapper_cycle_tablet_output (mapper, pad);
|
||||
tablet_klass->cycle_tablet_output (tablet_mapper, pad);
|
||||
return TRUE;
|
||||
case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
|
||||
if (is_press)
|
||||
meta_display_request_pad_osd (display_from_mapper (mapper), pad, FALSE);
|
||||
meta_display_request_pad_osd (display, pad, FALSE);
|
||||
return TRUE;
|
||||
case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
|
||||
settings = lookup_pad_button_settings (pad, button);
|
||||
accel = g_settings_get_string (settings, "keybinding");
|
||||
meta_pad_action_mapper_emulate_keybinding (mapper, accel, is_press);
|
||||
tablet_klass->emulate_keybinding (tablet_mapper, accel, is_press);
|
||||
g_object_unref (settings);
|
||||
g_free (accel);
|
||||
return TRUE;
|
||||
|
@ -708,18 +434,21 @@ meta_pad_action_mapper_handle_action (MetaPadActionMapper *mapper,
|
|||
|
||||
if (accel && *accel)
|
||||
{
|
||||
meta_pad_action_mapper_emulate_keybinding (mapper, accel, TRUE);
|
||||
meta_pad_action_mapper_emulate_keybinding (mapper, accel, FALSE);
|
||||
MetaTabletActionMapper *parent = META_TABLET_ACTION_MAPPER (mapper);
|
||||
MetaTabletActionMapperClass *klass = META_TABLET_ACTION_MAPPER_GET_CLASS (parent);
|
||||
klass->emulate_keybinding (parent, accel, TRUE);
|
||||
klass->emulate_keybinding (parent, accel, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper,
|
||||
const ClutterEvent *event)
|
||||
static gboolean
|
||||
meta_pad_action_mapper_handle_event (MetaTabletActionMapper *tablet_mapper,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaPadActionMapper *mapper = META_PAD_ACTION_MAPPER (tablet_mapper);
|
||||
ClutterInputDevice *pad;
|
||||
uint32_t number, mode;
|
||||
|
||||
|
@ -740,12 +469,6 @@ meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper,
|
|||
return meta_pad_action_mapper_handle_action (mapper, pad, event,
|
||||
META_PAD_FEATURE_STRIP,
|
||||
number, mode);
|
||||
case CLUTTER_DEVICE_ADDED:
|
||||
device_added (mapper, clutter_event_get_source_device (event));
|
||||
break;
|
||||
case CLUTTER_DEVICE_REMOVED:
|
||||
device_removed (mapper, clutter_event_get_source_device (event));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -23,18 +23,17 @@
|
|||
#include "clutter/clutter.h"
|
||||
#include "meta/display.h"
|
||||
#include "meta/meta-monitor-manager.h"
|
||||
#include "core/meta-tablet-action-mapper.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)
|
||||
META, PAD_ACTION_MAPPER, MetaTabletActionMapper)
|
||||
|
||||
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);
|
||||
|
||||
char * meta_pad_action_mapper_get_button_label (MetaPadActionMapper *mapper,
|
||||
ClutterInputDevice *pad,
|
||||
|
|
578
src/core/meta-tablet-action-mapper.c
Normal file
578
src/core/meta-tablet-action-mapper.c
Normal file
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2024 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 "core/meta-tablet-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 _TabletMappingInfo TabletMappingInfo;
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_MONITOR_MANAGER = 1,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
|
||||
|
||||
enum
|
||||
{
|
||||
DEVICE_ADDED,
|
||||
DEVICE_REMOVED,
|
||||
INPUT_EVENT,
|
||||
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
struct _TabletMappingInfo
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
GSettings *settings;
|
||||
};
|
||||
|
||||
struct _MetaTabletActionMapperPrivate
|
||||
{
|
||||
GObject parent_class;
|
||||
|
||||
GHashTable *tablets;
|
||||
ClutterSeat *seat;
|
||||
ClutterVirtualInputDevice *virtual_tablet_keyboard;
|
||||
MetaMonitorManager *monitor_manager;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaTabletActionMapper, meta_tablet_action_mapper, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_constructed (GObject *object);
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_cycle_tablet_output (MetaTabletActionMapper *mapper,
|
||||
ClutterInputDevice *device);
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_emulate_keybinding (MetaTabletActionMapper *mapper,
|
||||
const char *accel,
|
||||
gboolean is_press);
|
||||
|
||||
static MetaDisplay *
|
||||
meta_tablet_action_mapper_get_display (MetaTabletActionMapper *mapper)
|
||||
{
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
MetaBackend *backend =
|
||||
meta_monitor_manager_get_backend (priv->monitor_manager);
|
||||
MetaContext *context = meta_backend_get_context (backend);
|
||||
|
||||
return meta_context_get_display (context);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_finalize (GObject *object)
|
||||
{
|
||||
MetaTabletActionMapper *mapper = META_TABLET_ACTION_MAPPER (object);
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
|
||||
g_hash_table_unref (priv->tablets);
|
||||
g_object_unref (priv->monitor_manager);
|
||||
g_clear_object (&priv->virtual_tablet_keyboard);
|
||||
|
||||
G_OBJECT_CLASS (meta_tablet_action_mapper_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaTabletActionMapper *mapper = META_TABLET_ACTION_MAPPER (object);
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_MONITOR_MANAGER:
|
||||
g_value_set_object (value, priv->monitor_manager);
|
||||
break;
|
||||
default:
|
||||
/* We don't have any other property... */
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaTabletActionMapper *mapper = META_TABLET_ACTION_MAPPER (object);
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_MONITOR_MANAGER:
|
||||
if (priv->monitor_manager)
|
||||
g_object_unref (priv->monitor_manager);
|
||||
priv->monitor_manager = g_object_ref (g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* We don't have any other property... */
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_class_init (MetaTabletActionMapperClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = meta_tablet_action_mapper_get_property;
|
||||
object_class->set_property = meta_tablet_action_mapper_set_property;
|
||||
object_class->constructed = meta_tablet_action_mapper_constructed;
|
||||
object_class->finalize = meta_tablet_action_mapper_finalize;
|
||||
|
||||
klass->get_display = meta_tablet_action_mapper_get_display;
|
||||
klass->emulate_keybinding = meta_tablet_action_mapper_emulate_keybinding;
|
||||
klass->cycle_tablet_output = meta_tablet_action_mapper_cycle_tablet_output;
|
||||
|
||||
signals[DEVICE_ADDED] = g_signal_new ("device-added",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_INPUT_DEVICE);
|
||||
signals[DEVICE_REMOVED] = g_signal_new ("device-removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_INPUT_DEVICE);
|
||||
|
||||
signals[INPUT_EVENT] = g_signal_new ("input-event",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
CLUTTER_TYPE_EVENT);
|
||||
|
||||
obj_properties[PROP_MONITOR_MANAGER] =
|
||||
g_param_spec_object ("monitor-manager", NULL, NULL,
|
||||
META_TYPE_MONITOR_MANAGER,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (object_class,
|
||||
N_PROPERTIES,
|
||||
obj_properties);
|
||||
}
|
||||
|
||||
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 TabletMappingInfo *
|
||||
tablet_mapping_info_new (ClutterInputDevice *tablet)
|
||||
{
|
||||
TabletMappingInfo *info;
|
||||
|
||||
info = g_new0 (TabletMappingInfo, 1);
|
||||
info->device = tablet;
|
||||
info->settings = lookup_device_settings (tablet);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
tablet_mapping_info_free (TabletMappingInfo *info)
|
||||
{
|
||||
g_object_unref (info->settings);
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
static void
|
||||
device_added (MetaTabletActionMapper *mapper,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
TabletMappingInfo *info;
|
||||
|
||||
if ((clutter_input_device_get_capabilities (device) &
|
||||
CLUTTER_INPUT_CAPABILITY_TABLET_TOOL) != 0)
|
||||
{
|
||||
info = tablet_mapping_info_new (device);
|
||||
g_hash_table_insert (priv->tablets, device, info);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_removed (MetaTabletActionMapper *mapper,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
|
||||
g_hash_table_remove (priv->tablets, device);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_init (MetaTabletActionMapper *mapper)
|
||||
{
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
|
||||
g_signal_connect (mapper, "device-added", G_CALLBACK (device_added), NULL);
|
||||
g_signal_connect (mapper, "device-removed", G_CALLBACK (device_removed), NULL);
|
||||
|
||||
priv->tablets = g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) tablet_mapping_info_free);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_tablet_action_mapper_constructed (GObject *object)
|
||||
{
|
||||
MetaTabletActionMapper *mapper = META_TABLET_ACTION_MAPPER (object);
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
g_autoptr (GList) devices = NULL;
|
||||
GList *l;
|
||||
|
||||
priv->seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
|
||||
devices = clutter_seat_list_devices (priv->seat);
|
||||
|
||||
/* FIXME: is this call correct?? */
|
||||
for (l = devices; l; l = l->next)
|
||||
g_signal_emit (mapper, signals[DEVICE_ADDED], 0, l->data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cycle_logical_monitors (MetaTabletActionMapperPrivate *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_tablet_action_mapper_find_monitor (MetaTabletActionMapperPrivate *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_tablet_action_mapper_cycle_tablet_output (MetaTabletActionMapper *mapper,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
TabletMappingInfo *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_TABLET_ACTION_MAPPER (mapper));
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
g_return_if_fail ((clutter_input_device_get_capabilities (device) &
|
||||
(CLUTTER_INPUT_CAPABILITY_TABLET_TOOL |
|
||||
CLUTTER_INPUT_CAPABILITY_TABLET_PAD)) != 0);
|
||||
|
||||
info = g_hash_table_lookup (priv->tablets, 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_tablet_action_mapper_find_monitor (priv, info->settings, device,
|
||||
NULL, &logical_monitor);
|
||||
|
||||
if (!cycle_logical_monitors (priv,
|
||||
is_integrated_device,
|
||||
logical_monitor,
|
||||
&logical_monitor))
|
||||
return;
|
||||
|
||||
if (logical_monitor)
|
||||
{
|
||||
MetaMonitor *monitor;
|
||||
const char *vendor;
|
||||
const char *product;
|
||||
const char *serial;
|
||||
|
||||
/* Pick an arbitrary monitor in the logical monitor to represent it. */
|
||||
monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
|
||||
vendor = meta_monitor_get_vendor (monitor);
|
||||
product = meta_monitor_get_product (monitor);
|
||||
serial = meta_monitor_get_serial (monitor);
|
||||
edid[0] = vendor ? vendor : "";
|
||||
edid[1] = product ? product : "";
|
||||
edid[2] = serial ? serial : "";
|
||||
}
|
||||
else
|
||||
{
|
||||
edid[0] = "";
|
||||
edid[1] = "";
|
||||
edid[2] = "";
|
||||
}
|
||||
|
||||
g_settings_set_strv (info->settings, "output", edid);
|
||||
meta_display_show_tablet_mapping_notification (meta_tablet_action_mapper_get_display (mapper),
|
||||
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_Alt_L },
|
||||
{ CLUTTER_META_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_tablet_action_mapper_emulate_keybinding (MetaTabletActionMapper *mapper,
|
||||
const char *accel,
|
||||
gboolean is_press)
|
||||
{
|
||||
MetaTabletActionMapperPrivate *priv =
|
||||
meta_tablet_action_mapper_get_instance_private (mapper);
|
||||
ClutterKeyState state;
|
||||
MetaKeyCombo combo = { 0 };
|
||||
|
||||
if (!accel || !*accel)
|
||||
return;
|
||||
|
||||
if (!meta_parse_accelerator (accel, &combo))
|
||||
{
|
||||
g_warning ("\"%s\" is not a valid accelerator", accel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!priv->virtual_tablet_keyboard)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
ClutterSeat *seat;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
seat = clutter_backend_get_default_seat (backend);
|
||||
|
||||
priv->virtual_tablet_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_tablet_keyboard, combo.modifiers, state);
|
||||
|
||||
clutter_virtual_input_device_notify_keyval (priv->virtual_tablet_keyboard,
|
||||
clutter_get_current_event_time (),
|
||||
combo.keysym, state);
|
||||
if (!is_press)
|
||||
emulate_modifiers (priv->virtual_tablet_keyboard, combo.modifiers, state);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_tablet_action_mapper_handle_event (MetaTabletActionMapper *mapper,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
gboolean propagate = CLUTTER_EVENT_PROPAGATE;
|
||||
|
||||
switch (clutter_event_type (event))
|
||||
{
|
||||
case CLUTTER_DEVICE_ADDED:
|
||||
device = clutter_event_get_source_device (event);
|
||||
g_signal_emit (mapper, signals[DEVICE_ADDED], 0, device);
|
||||
break;
|
||||
case CLUTTER_DEVICE_REMOVED:
|
||||
device = clutter_event_get_source_device (event);
|
||||
g_signal_emit (mapper, signals[DEVICE_REMOVED], 0, device);
|
||||
break;
|
||||
default:
|
||||
g_signal_emit (mapper, signals[INPUT_EVENT], 0, event, &propagate);
|
||||
break;
|
||||
}
|
||||
|
||||
return propagate;
|
||||
}
|
51
src/core/meta-tablet-action-mapper.h
Normal file
51
src/core/meta-tablet-action-mapper.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2024 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Written by:
|
||||
* Carlos Garnacho <carlosg@gnome.org>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
#include "meta/display.h"
|
||||
#include "meta/meta-monitor-manager.h"
|
||||
|
||||
#define META_TYPE_TABLET_ACTION_MAPPER (meta_tablet_action_mapper_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaTabletActionMapper, meta_tablet_action_mapper,
|
||||
META, TABLET_ACTION_MAPPER, GObject)
|
||||
|
||||
typedef struct _MetaTabletActionMapperPrivate MetaTabletActionMapperPrivate;
|
||||
|
||||
/**
|
||||
* MetaTabletActionMapperClass:
|
||||
*/
|
||||
struct _MetaTabletActionMapperClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
MetaDisplay * (* get_display) (MetaTabletActionMapper *mapper);
|
||||
void (* emulate_keybinding) (MetaTabletActionMapper *mapper,
|
||||
const char *accel,
|
||||
gboolean is_press);
|
||||
void (*cycle_tablet_output) (MetaTabletActionMapper *mapper,
|
||||
ClutterInputDevice *device);
|
||||
};
|
||||
|
||||
gboolean meta_tablet_action_mapper_handle_event (MetaTabletActionMapper *mapper,
|
||||
const ClutterEvent *event);
|
|
@ -378,6 +378,7 @@ mutter_sources = [
|
|||
'core/meta-selection-source.c',
|
||||
'core/meta-selection-source-memory.c',
|
||||
'core/meta-sound-player.c',
|
||||
'core/meta-tablet-action-mapper.c',
|
||||
'core/meta-workspace-manager.c',
|
||||
'core/meta-workspace-manager-private.h',
|
||||
'core/place.c',
|
||||
|
|
Loading…
Add table
Reference in a new issue