diff --git a/src/core/display-private.h b/src/core/display-private.h
index b22e1f772..eaa9d1fb6 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -32,6 +32,7 @@
#include "core/keybindings-private.h"
#include "core/meta-gesture-tracker-private.h"
#include "core/meta-pad-action-mapper.h"
+#include "core/meta-tool-action-mapper.h"
#include "core/stack-tracker.h"
#include "core/startup-notification-private.h"
#include "meta/barrier.h"
@@ -141,6 +142,7 @@ struct _MetaDisplay
ClutterActor *current_pad_osd;
MetaPadActionMapper *pad_action_mapper;
+ MetaToolActionMapper *tool_action_mapper;
MetaStartupNotification *startup_notification;
diff --git a/src/core/display.c b/src/core/display.c
index bd09082ed..8c0364621 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -996,6 +996,7 @@ meta_display_new (MetaContext *context,
display, G_CONNECT_SWAPPED);
display->pad_action_mapper = meta_pad_action_mapper_new (monitor_manager);
+ display->tool_action_mapper = meta_tool_action_mapper_new (backend);
input_capture = meta_backend_get_input_capture (backend);
meta_input_capture_set_event_router (input_capture,
diff --git a/src/core/events.c b/src/core/events.c
index 26f0c1295..fb4c7574c 100644
--- a/src/core/events.c
+++ b/src/core/events.c
@@ -328,7 +328,10 @@ meta_display_handle_event (MetaDisplay *display,
else if (event_type == CLUTTER_BUTTON_PRESS ||
event_type == CLUTTER_BUTTON_RELEASE)
{
- if (clutter_event_get_button (event) == 0)
+ mapper = META_TABLET_ACTION_MAPPER (display->tool_action_mapper);
+ if (((clutter_input_device_get_capabilities (device) & CLUTTER_INPUT_CAPABILITY_TABLET_TOOL) &&
+ meta_tablet_action_mapper_handle_event (mapper, event)) ||
+ clutter_event_get_button (event) == 0)
return CLUTTER_EVENT_STOP;
}
diff --git a/src/core/meta-tool-action-mapper.c b/src/core/meta-tool-action-mapper.c
new file mode 100644
index 000000000..b707f309b
--- /dev/null
+++ b/src/core/meta-tool-action-mapper.c
@@ -0,0 +1,149 @@
+/*
+ * 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, see .
+ *
+ */
+
+#include "config.h"
+
+#include
+#include
+
+#ifdef HAVE_LIBWACOM
+#include
+#endif
+
+#include "core/meta-tool-action-mapper.h"
+#include "backends/meta-input-device-private.h"
+#include "core/display-private.h"
+
+struct _MetaToolActionMapper
+{
+ GObject parent_class;
+ MetaInputSettings *input_settings;
+};
+
+G_DEFINE_TYPE (MetaToolActionMapper, meta_tool_action_mapper, META_TYPE_TABLET_ACTION_MAPPER);
+
+static gboolean
+meta_tool_action_mapper_handle_event (MetaTabletActionMapper *mapper,
+ const ClutterEvent *event);
+
+static void
+meta_tool_action_mapper_finalize (GObject *object)
+{
+ MetaToolActionMapper *mapper = META_TOOL_ACTION_MAPPER (object);
+
+ g_clear_object (&mapper->input_settings);
+
+ G_OBJECT_CLASS (meta_tool_action_mapper_parent_class)->finalize (object);
+}
+
+static void
+meta_tool_action_mapper_class_init (MetaToolActionMapperClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = meta_tool_action_mapper_finalize;
+}
+
+static void
+meta_tool_action_mapper_init (MetaToolActionMapper *mapper)
+{
+ g_signal_connect (mapper, "input-event", G_CALLBACK (meta_tool_action_mapper_handle_event), NULL);
+}
+
+MetaToolActionMapper *
+meta_tool_action_mapper_new (MetaBackend *backend)
+{
+ MetaToolActionMapper *action_mapper;
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+
+ action_mapper = g_object_new (META_TYPE_TOOL_ACTION_MAPPER,
+ "monitor-manager", monitor_manager,
+ NULL);
+ action_mapper->input_settings = g_object_ref (meta_backend_get_input_settings (backend));
+
+ return action_mapper;
+}
+
+static gboolean
+meta_tool_action_mapper_handle_button (MetaToolActionMapper *mapper,
+ ClutterInputDevice *device,
+ const ClutterEvent *event)
+{
+ MetaTabletActionMapper *tablet_mapper = META_TABLET_ACTION_MAPPER (mapper);
+ MetaTabletActionMapperClass *tablet_klass = META_TABLET_ACTION_MAPPER_GET_CLASS (mapper);
+ GDesktopStylusButtonAction action;
+ gboolean is_press;
+ g_autofree char *accel = NULL;
+ uint32_t button, evcode;
+ ClutterInputDeviceTool *tool;
+
+ g_return_val_if_fail (clutter_event_type (event) == CLUTTER_BUTTON_PRESS ||
+ clutter_event_type (event) == CLUTTER_BUTTON_RELEASE, FALSE);
+
+ if ((clutter_input_device_get_capabilities (device) & CLUTTER_INPUT_CAPABILITY_TABLET_TOOL) == 0)
+ return FALSE;
+
+ tool = clutter_event_get_device_tool (event);
+ evcode = clutter_event_get_event_code (event);
+ button = meta_evdev_tool_button_to_clutter (evcode);
+ is_press = clutter_event_type (event) == CLUTTER_BUTTON_PRESS;
+
+ action = meta_input_settings_get_tool_button_action (mapper->input_settings,
+ device, tool, button, &accel);
+ switch (action)
+ {
+ case G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT:
+ case G_DESKTOP_STYLUS_BUTTON_ACTION_MIDDLE:
+ case G_DESKTOP_STYLUS_BUTTON_ACTION_RIGHT:
+ case G_DESKTOP_STYLUS_BUTTON_ACTION_BACK:
+ case G_DESKTOP_STYLUS_BUTTON_ACTION_FORWARD:
+ /* These are handled as normal button events, nothing to do here */
+ return FALSE;
+ case G_DESKTOP_STYLUS_BUTTON_ACTION_SWITCH_MONITOR:
+ if (is_press)
+ tablet_klass->cycle_tablet_output (tablet_mapper, device);
+ return TRUE;
+ case G_DESKTOP_STYLUS_BUTTON_ACTION_KEYBINDING:
+ if (accel)
+ tablet_klass->emulate_keybinding (tablet_mapper, accel, is_press);
+ return TRUE;
+ default:
+ g_warn_if_reached ();
+ return FALSE;
+ }
+}
+
+gboolean
+meta_tool_action_mapper_handle_event (MetaTabletActionMapper *tablet_mapper,
+ const ClutterEvent *event)
+{
+ MetaToolActionMapper *mapper = META_TOOL_ACTION_MAPPER (tablet_mapper);
+ ClutterInputDevice *tool;
+
+ tool = clutter_event_get_source_device ((ClutterEvent *) event);
+
+ switch (clutter_event_type (event))
+ {
+ case CLUTTER_BUTTON_PRESS:
+ case CLUTTER_BUTTON_RELEASE:
+ return meta_tool_action_mapper_handle_button (mapper, tool, event);
+ default:
+ break;
+ }
+
+ return CLUTTER_EVENT_PROPAGATE;
+}
diff --git a/src/core/meta-tool-action-mapper.h b/src/core/meta-tool-action-mapper.h
new file mode 100644
index 000000000..6136a662a
--- /dev/null
+++ b/src/core/meta-tool-action-mapper.h
@@ -0,0 +1,30 @@
+/*
+ * 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, see .
+ *
+ */
+
+#pragma once
+
+#include "clutter/clutter.h"
+#include "meta/display.h"
+#include "meta/meta-monitor-manager.h"
+#include "core/meta-tablet-action-mapper.h"
+
+#define META_TYPE_TOOL_ACTION_MAPPER (meta_tool_action_mapper_get_type ())
+G_DECLARE_FINAL_TYPE (MetaToolActionMapper, meta_tool_action_mapper,
+ META, TOOL_ACTION_MAPPER, MetaTabletActionMapper)
+
+MetaToolActionMapper *meta_tool_action_mapper_new (MetaBackend * backend);
diff --git a/src/meson.build b/src/meson.build
index b74fe37fe..c5dffd587 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -379,6 +379,7 @@ mutter_sources = [
'core/meta-selection-source-memory.c',
'core/meta-sound-player.c',
'core/meta-tablet-action-mapper.c',
+ 'core/meta-tool-action-mapper.c',
'core/meta-workspace-manager.c',
'core/meta-workspace-manager-private.h',
'core/place.c',