1
0
Fork 0
mutter-performance-source/src/backends/native/meta-seat-native.c
Jonas Dreßler 301198a9b8 Revert "backends: Use also a native cursor renderer for tablets"
With commit c985753442 the support for
multiple hardware cursors broke, but those were never properly supported
anyway as we usually assume there's only one hardware cursor around.

With the introduction of the KMS thread in the future, we'll only have
one KMS cursor that gets updated directly from the input thread. So
apart from the fact that it never really makes sense to have two cursors
visible, in this new model having multiple cursors won't work anyway.

So make the cursor we show for stylii a software cursor again.
Eventually the plan is to make the input device that's driving the KMS
cursor interchangeable, so that we can always use hardware cursors.

This reverts commit 165b7369c8.

Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1645

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1758>
2021-03-08 13:13:22 +00:00

606 lines
18 KiB
C

/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corp.
* Copyright (C) 2014 Jonas Ådahl
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Damien Lespiau <damien.lespiau@intel.com>
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include "backends/native/meta-seat-native.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-keymap-utils.h"
#include "backends/native/meta-barrier-native.h"
#include "backends/native/meta-input-thread.h"
#include "backends/native/meta-keymap-native.h"
#include "backends/native/meta-virtual-input-device-native.h"
#include "clutter/clutter-mutter.h"
#include "core/bell.h"
enum
{
PROP_0,
PROP_SEAT_ID,
N_PROPS,
/* This property is overridden */
PROP_TOUCH_MODE,
};
static GParamSpec *props[N_PROPS] = { NULL };
G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT)
static gboolean
meta_seat_native_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
ClutterInputDevice *device = clutter_event_get_source_device (event);
ClutterEventType event_type = event->type;
if (event_type == CLUTTER_PROXIMITY_IN)
{
MetaCursorRenderer *cursor_renderer;
if (!seat_native->tablet_cursors)
{
seat_native->tablet_cursors = g_hash_table_new_full (NULL, NULL, NULL,
g_object_unref);
}
cursor_renderer = meta_cursor_renderer_new (meta_get_backend (), device);
g_hash_table_insert (seat_native->tablet_cursors,
device, cursor_renderer);
return TRUE;
}
else if (event_type == CLUTTER_PROXIMITY_OUT)
{
if (seat_native->tablet_cursors)
g_hash_table_remove (seat_native->tablet_cursors, device);
return TRUE;
}
else if (event_type == CLUTTER_DEVICE_ADDED)
{
if (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL)
seat_native->devices = g_list_prepend (seat_native->devices, g_object_ref (device));
}
else if (event_type == CLUTTER_DEVICE_REMOVED)
{
GList *l = g_list_find (seat_native->devices, device);
if (l)
{
seat_native->devices = g_list_delete_link (seat_native->devices, l);
g_object_unref (device);
}
}
return FALSE;
}
static void
proxy_kbd_a11y_flags_changed (MetaSeatImpl *seat_impl,
MetaKeyboardA11yFlags new_flags,
MetaKeyboardA11yFlags what_changed,
MetaSeatNative *seat_native)
{
g_signal_emit_by_name (seat_native,
"kbd-a11y-flags-changed",
new_flags, what_changed);
}
static void
proxy_kbd_a11y_mods_state_changed (MetaSeatImpl *seat_impl,
xkb_mod_mask_t new_latched_mods,
xkb_mod_mask_t new_locked_mods,
MetaSeatNative *seat_native)
{
g_signal_emit_by_name (seat_native,
"kbd-a11y-mods-state-changed",
new_latched_mods,
new_locked_mods);
}
static void
proxy_touch_mode_changed (MetaSeatImpl *seat_impl,
gboolean enabled,
MetaSeatNative *seat_native)
{
seat_native->touch_mode = enabled;
g_object_notify (G_OBJECT (seat_native), "touch-mode");
}
static void
proxy_bell (MetaSeatImpl *seat_impl,
MetaSeatNative *seat_native)
{
clutter_seat_bell_notify (CLUTTER_SEAT (seat_native));
}
static void
proxy_mods_state_changed (MetaSeatImpl *seat_impl,
ClutterSeat *seat)
{
ClutterKeymap *keymap;
keymap = clutter_seat_get_keymap (seat);
g_signal_emit_by_name (keymap, "state-changed");
}
static void
meta_seat_native_constructed (GObject *object)
{
MetaSeatNative *seat = META_SEAT_NATIVE (object);
seat->impl = meta_seat_impl_new (seat, seat->seat_id);
g_signal_connect (seat->impl, "kbd-a11y-flags-changed",
G_CALLBACK (proxy_kbd_a11y_flags_changed), seat);
g_signal_connect (seat->impl, "kbd-a11y-mods-state-changed",
G_CALLBACK (proxy_kbd_a11y_mods_state_changed), seat);
g_signal_connect (seat->impl, "touch-mode",
G_CALLBACK (proxy_touch_mode_changed), seat);
g_signal_connect (seat->impl, "bell",
G_CALLBACK (proxy_bell), seat);
g_signal_connect (seat->impl, "mods-state-changed",
G_CALLBACK (proxy_mods_state_changed), seat);
seat->core_pointer = meta_seat_impl_get_pointer (seat->impl);
seat->core_keyboard = meta_seat_impl_get_keyboard (seat->impl);
meta_seat_native_set_keyboard_map (seat, "us", "", "");
if (G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed)
G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed (object);
}
static void
meta_seat_native_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (object);
switch (prop_id)
{
case PROP_SEAT_ID:
seat_native->seat_id = g_value_dup_string (value);
break;
case PROP_TOUCH_MODE:
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_seat_native_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (object);
switch (prop_id)
{
case PROP_SEAT_ID:
g_value_set_string (value, seat_native->seat_id);
break;
case PROP_TOUCH_MODE:
g_value_set_boolean (value, seat_native->touch_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_seat_native_finalize (GObject *object)
{
MetaSeatNative *seat = META_SEAT_NATIVE (object);
GList *iter;
if (seat->xkb_keymap)
xkb_keymap_unref (seat->xkb_keymap);
g_clear_object (&seat->core_pointer);
g_clear_object (&seat->core_keyboard);
g_clear_pointer (&seat->impl, meta_seat_impl_destroy);
for (iter = seat->devices; iter; iter = g_list_next (iter))
{
ClutterInputDevice *device = iter->data;
g_object_unref (device);
}
g_list_free (seat->devices);
g_hash_table_destroy (seat->reserved_virtual_slots);
g_clear_pointer (&seat->tablet_cursors, g_hash_table_unref);
g_object_unref (seat->cursor_renderer);
g_free (seat->seat_id);
G_OBJECT_CLASS (meta_seat_native_parent_class)->finalize (object);
}
static ClutterInputDevice *
meta_seat_native_get_pointer (ClutterSeat *seat)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
return seat_native->core_pointer;
}
static ClutterInputDevice *
meta_seat_native_get_keyboard (ClutterSeat *seat)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
return seat_native->core_keyboard;
}
static const GList *
meta_seat_native_peek_devices (ClutterSeat *seat)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
return (const GList *) seat_native->devices;
}
static void
meta_seat_native_bell_notify (ClutterSeat *seat)
{
MetaDisplay *display = meta_get_display ();
meta_bell_notify (display, NULL);
}
static ClutterKeymap *
meta_seat_native_get_keymap (ClutterSeat *seat)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
if (!seat_native->keymap)
seat_native->keymap = meta_seat_impl_get_keymap (seat_native->impl);
return CLUTTER_KEYMAP (seat_native->keymap);
}
static guint
bump_virtual_touch_slot_base (MetaSeatNative *seat_native)
{
while (TRUE)
{
if (seat_native->virtual_touch_slot_base < 0x100)
seat_native->virtual_touch_slot_base = 0x100;
seat_native->virtual_touch_slot_base +=
CLUTTER_VIRTUAL_INPUT_DEVICE_MAX_TOUCH_SLOTS;
if (!g_hash_table_lookup (seat_native->reserved_virtual_slots,
GUINT_TO_POINTER (seat_native->virtual_touch_slot_base)))
break;
}
return seat_native->virtual_touch_slot_base;
}
static ClutterVirtualInputDevice *
meta_seat_native_create_virtual_device (ClutterSeat *seat,
ClutterInputDeviceType device_type)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
guint slot_base;
slot_base = bump_virtual_touch_slot_base (seat_native);
g_hash_table_add (seat_native->reserved_virtual_slots,
GUINT_TO_POINTER (slot_base));
return g_object_new (META_TYPE_VIRTUAL_INPUT_DEVICE_NATIVE,
"seat", seat,
"slot-base", slot_base,
"device-type", device_type,
NULL);
}
void
meta_seat_native_release_touch_slots (MetaSeatNative *seat,
guint base_slot)
{
g_hash_table_remove (seat->reserved_virtual_slots,
GUINT_TO_POINTER (base_slot));
}
static ClutterVirtualDeviceType
meta_seat_native_get_supported_virtual_device_types (ClutterSeat *seat)
{
return (CLUTTER_VIRTUAL_DEVICE_TYPE_KEYBOARD |
CLUTTER_VIRTUAL_DEVICE_TYPE_POINTER |
CLUTTER_VIRTUAL_DEVICE_TYPE_TOUCHSCREEN);
}
static void
meta_seat_native_warp_pointer (ClutterSeat *seat,
int x,
int y)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
meta_seat_impl_warp_pointer (seat_native->impl, x, y);
}
static gboolean
meta_seat_native_query_state (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers)
{
MetaSeatNative *seat_native = META_SEAT_NATIVE (seat);
return meta_seat_impl_query_state (seat_native->impl, device, sequence,
coords, modifiers);
}
static void
meta_seat_native_class_init (MetaSeatNativeClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterSeatClass *seat_class = CLUTTER_SEAT_CLASS (klass);
object_class->constructed = meta_seat_native_constructed;
object_class->set_property = meta_seat_native_set_property;
object_class->get_property = meta_seat_native_get_property;
object_class->finalize = meta_seat_native_finalize;
seat_class->get_pointer = meta_seat_native_get_pointer;
seat_class->get_keyboard = meta_seat_native_get_keyboard;
seat_class->peek_devices = meta_seat_native_peek_devices;
seat_class->bell_notify = meta_seat_native_bell_notify;
seat_class->get_keymap = meta_seat_native_get_keymap;
seat_class->create_virtual_device = meta_seat_native_create_virtual_device;
seat_class->get_supported_virtual_device_types = meta_seat_native_get_supported_virtual_device_types;
seat_class->warp_pointer = meta_seat_native_warp_pointer;
seat_class->handle_event_post = meta_seat_native_handle_event_post;
seat_class->query_state = meta_seat_native_query_state;
props[PROP_SEAT_ID] =
g_param_spec_string ("seat-id",
"Seat ID",
"Seat ID",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, props);
g_object_class_override_property (object_class, PROP_TOUCH_MODE,
"touch-mode");
}
static void
meta_seat_native_init (MetaSeatNative *seat)
{
seat->reserved_virtual_slots = g_hash_table_new (NULL, NULL);
}
/**
* meta_seat_native_release_devices:
*
* Releases all the evdev devices that Clutter is currently managing. This api
* is typically used when switching away from the Clutter application when
* switching tty. The devices can be reclaimed later with a call to
* meta_seat_native_reclaim_devices().
*
* This function should only be called after clutter has been initialized.
*/
void
meta_seat_native_release_devices (MetaSeatNative *seat)
{
g_return_if_fail (META_IS_SEAT_NATIVE (seat));
if (seat->released)
{
g_warning ("meta_seat_native_release_devices() shouldn't be called "
"multiple times without a corresponding call to "
"meta_seat_native_reclaim_devices() first");
return;
}
meta_seat_impl_release_devices (seat->impl);
seat->released = TRUE;
}
/**
* meta_seat_native_reclaim_devices:
*
* This causes Clutter to re-probe for evdev devices. This is must only be
* called after a corresponding call to meta_seat_native_release_devices()
* was previously used to release all evdev devices. This API is typically
* used when a clutter application using evdev has regained focus due to
* switching ttys.
*
* This function should only be called after clutter has been initialized.
*/
void
meta_seat_native_reclaim_devices (MetaSeatNative *seat)
{
if (!seat->released)
{
g_warning ("Spurious call to meta_seat_native_reclaim_devices() without "
"previous call to meta_seat_native_release_devices");
return;
}
meta_seat_impl_reclaim_devices (seat->impl);
seat->released = FALSE;
}
static struct xkb_keymap *
create_keymap (const char *layouts,
const char *variants,
const char *options)
{
struct xkb_rule_names names;
struct xkb_keymap *keymap;
struct xkb_context *context;
names.rules = DEFAULT_XKB_RULES_FILE;
names.model = DEFAULT_XKB_MODEL;
names.layout = layouts;
names.variant = variants;
names.options = options;
context = meta_create_xkb_context ();
keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref (context);
return keymap;
}
/**
* meta_seat_native_set_keyboard_map: (skip)
* @seat: the #ClutterSeat created by the evdev backend
* @keymap: the new keymap
*
* Instructs @evdev to use the specified keyboard map. This will cause
* the backend to drop the state and create a new one with the new
* map. To avoid state being lost, callers should ensure that no key
* is pressed when calling this function.
*/
void
meta_seat_native_set_keyboard_map (MetaSeatNative *seat,
const char *layouts,
const char *variants,
const char *options)
{
struct xkb_keymap *keymap, *impl_keymap;
keymap = create_keymap (layouts, variants, options);
impl_keymap = create_keymap (layouts, variants, options);
if (keymap == NULL)
{
g_warning ("Unable to load configured keymap: rules=%s, model=%s, layout=%s, variant=%s, options=%s",
DEFAULT_XKB_RULES_FILE, DEFAULT_XKB_MODEL, layouts,
variants, options);
return;
}
if (seat->xkb_keymap)
xkb_keymap_unref (seat->xkb_keymap);
seat->xkb_keymap = keymap;
meta_seat_impl_set_keyboard_map (seat->impl, impl_keymap);
xkb_keymap_unref (impl_keymap);
}
/**
* meta_seat_native_get_keyboard_map: (skip)
* @seat: the #ClutterSeat created by the evdev backend
*
* Retrieves the #xkb_keymap in use by the evdev backend.
*
* Return value: the #xkb_keymap.
*/
struct xkb_keymap *
meta_seat_native_get_keyboard_map (MetaSeatNative *seat)
{
g_return_val_if_fail (META_IS_SEAT_NATIVE (seat), NULL);
return seat->xkb_keymap;
}
/**
* meta_seat_native_set_keyboard_layout_index: (skip)
* @seat: the #ClutterSeat created by the evdev backend
* @idx: the xkb layout index to set
*
* Sets the xkb layout index on the backend's #xkb_state .
*/
void
meta_seat_native_set_keyboard_layout_index (MetaSeatNative *seat,
xkb_layout_index_t idx)
{
g_return_if_fail (META_IS_SEAT_NATIVE (seat));
seat->xkb_layout_index = idx;
meta_seat_impl_set_keyboard_layout_index (seat->impl, idx);
}
/**
* meta_seat_native_get_keyboard_layout_index: (skip)
*/
xkb_layout_index_t
meta_seat_native_get_keyboard_layout_index (MetaSeatNative *seat)
{
return seat->xkb_layout_index;
}
MetaBarrierManagerNative *
meta_seat_native_get_barrier_manager (MetaSeatNative *seat)
{
return meta_seat_impl_get_barrier_manager (seat->impl);
}
void
meta_seat_native_set_pointer_constraint (MetaSeatNative *seat,
MetaPointerConstraintImpl *constraint_impl)
{
meta_seat_impl_set_pointer_constraint (seat->impl, constraint_impl);
}
MetaCursorRenderer *
meta_seat_native_maybe_ensure_cursor_renderer (MetaSeatNative *seat_native,
ClutterInputDevice *device)
{
if (device == seat_native->core_pointer)
{
if (!seat_native->cursor_renderer)
{
MetaCursorRendererNative *cursor_renderer_native;
cursor_renderer_native =
meta_cursor_renderer_native_new (meta_get_backend (),
seat_native->core_pointer);
seat_native->cursor_renderer =
META_CURSOR_RENDERER (cursor_renderer_native);
}
return seat_native->cursor_renderer;
}
if (seat_native->tablet_cursors &&
clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE)
return g_hash_table_lookup (seat_native->tablet_cursors, device);
return NULL;
}
void
meta_seat_native_set_viewports (MetaSeatNative *seat,
MetaViewportInfo *viewports)
{
meta_seat_impl_set_viewports (seat->impl, viewports);
}