mirror of
https://github.com/brl/mutter.git
synced 2025-04-13 05:39:38 +00:00
wayland: Introduce MetaWaylandInput/MetaWaylandEventInterface
MetaWaylandInput is an object that will become in charge of handling input events on their way to the Wayland socket. It keeps a stack of event handlers, and propagates events and changes across them in order to have them emit Wayland events, or change focus. Each of these event handlers has a MetaWaylandEventInterface, this is a vtable meant to replace MetaWaylandPointerGrabInterface and MetaWaylandKeyboardGrabInterface in an unified manner, with the following methods: - get_focus_surface: to return the focus surface for a device/sequence. Since several handlers will want to delegate logic on previous handlers, it is optional to chain up with meta_wayland_event_handler_chain_up_get_focus_surface(). - focus: To trigger a focus change for a device/sequence, since event handlers are daisy chained by default, it is mandatory to chain up with meta_wayland_event_handler_chain_up_focus(), either with the given surface, or passing NULL to let later handlers unset their state. - press/motion/release: Unified handlers for pointer/touch/stylus input, they chain up like event handlers do. - key: Key event handler, propagates like event handlers do. - other: Fallthrough for other events (pad, scroll, ...), propagates like event handlers do. Since there is a variety of expected behaviors, and the possibility of stacking for some of the existing Wayland "grabs", this provides the mechanism for that to happen. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3420>
This commit is contained in:
parent
77ec0d1e41
commit
a2c11f0e87
@ -625,6 +625,8 @@ if have_wayland
|
|||||||
'wayland/meta-wayland-inhibit-shortcuts-dialog.c',
|
'wayland/meta-wayland-inhibit-shortcuts-dialog.c',
|
||||||
'wayland/meta-wayland-inhibit-shortcuts-dialog.h',
|
'wayland/meta-wayland-inhibit-shortcuts-dialog.h',
|
||||||
'wayland/meta-wayland-inhibit-shortcuts.h',
|
'wayland/meta-wayland-inhibit-shortcuts.h',
|
||||||
|
'wayland/meta-wayland-input.c',
|
||||||
|
'wayland/meta-wayland-input.h',
|
||||||
'wayland/meta-wayland-input-device.c',
|
'wayland/meta-wayland-input-device.c',
|
||||||
'wayland/meta-wayland-input-device.h',
|
'wayland/meta-wayland-input-device.h',
|
||||||
'wayland/meta-wayland-keyboard.c',
|
'wayland/meta-wayland-keyboard.c',
|
||||||
|
326
src/wayland/meta-wayland-input.c
Normal file
326
src/wayland/meta-wayland-input.c
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* Interface for Wayland events
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
|
||||||
|
#include "wayland/meta-wayland-input.h"
|
||||||
|
|
||||||
|
#include "wayland/meta-wayland-seat.h"
|
||||||
|
#include "wayland/meta-wayland-tablet-seat.h"
|
||||||
|
|
||||||
|
struct _MetaWaylandEventHandler
|
||||||
|
{
|
||||||
|
const MetaWaylandEventInterface *iface;
|
||||||
|
MetaWaylandInput *input;
|
||||||
|
gpointer user_data;
|
||||||
|
struct wl_list link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _MetaWaylandInput
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
|
||||||
|
MetaWaylandSeat *seat;
|
||||||
|
struct wl_list event_handler_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE (MetaWaylandInput, meta_wayland_input, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_input_init (MetaWaylandInput *input)
|
||||||
|
{
|
||||||
|
wl_list_init (&input->event_handler_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_input_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MetaWaylandInput *input = META_WAYLAND_INPUT (object);
|
||||||
|
MetaWaylandEventHandler *handler, *next;
|
||||||
|
|
||||||
|
wl_list_for_each_safe (handler, next, &input->event_handler_list, link)
|
||||||
|
meta_wayland_input_detach_event_handler (input, handler);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_wayland_input_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_input_class_init (MetaWaylandInputClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = meta_wayland_input_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaWaylandInput *
|
||||||
|
meta_wayland_input_new (MetaWaylandSeat *seat)
|
||||||
|
{
|
||||||
|
MetaWaylandInput *input;
|
||||||
|
|
||||||
|
input = g_object_new (META_TYPE_WAYLAND_INPUT, NULL);
|
||||||
|
input->seat = seat;
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_event_handler_invalidate_focus (MetaWaylandEventHandler *handler,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface = NULL;
|
||||||
|
|
||||||
|
if (!handler->iface->focus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Only the first handler can focus other than a NULL surface */
|
||||||
|
if (meta_wayland_input_is_current_handler (handler->input, handler) &&
|
||||||
|
handler->iface->get_focus_surface)
|
||||||
|
{
|
||||||
|
surface = handler->iface->get_focus_surface (handler,
|
||||||
|
device, sequence,
|
||||||
|
handler->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->iface->focus (handler,
|
||||||
|
device, sequence, surface,
|
||||||
|
handler->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_event_handler_invalidate_all_focus (MetaWaylandEventHandler *handler)
|
||||||
|
{
|
||||||
|
MetaWaylandSeat *seat = handler->input->seat;
|
||||||
|
ClutterSeat *clutter_seat =
|
||||||
|
clutter_backend_get_default_seat (clutter_get_default_backend ());
|
||||||
|
ClutterInputDevice *device;
|
||||||
|
GHashTableIter iter;
|
||||||
|
|
||||||
|
/* Trigger sync of all known devices */
|
||||||
|
if (meta_wayland_seat_has_pointer (seat))
|
||||||
|
{
|
||||||
|
device = clutter_seat_get_pointer (clutter_seat);
|
||||||
|
meta_wayland_event_handler_invalidate_focus (handler, device, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta_wayland_seat_has_keyboard (seat))
|
||||||
|
{
|
||||||
|
device = clutter_seat_get_keyboard (clutter_seat);
|
||||||
|
meta_wayland_event_handler_invalidate_focus (handler, device, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta_wayland_seat_has_touch (seat))
|
||||||
|
meta_wayland_touch_cancel (seat->touch);
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, seat->tablet_seat->tablets);
|
||||||
|
while (g_hash_table_iter_next (&iter, (gpointer*) &device, NULL))
|
||||||
|
meta_wayland_event_handler_invalidate_focus (handler, device, NULL);
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, seat->tablet_seat->pads);
|
||||||
|
while (g_hash_table_iter_next (&iter, (gpointer*) &device, NULL))
|
||||||
|
meta_wayland_event_handler_invalidate_focus (handler, device, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_wayland_event_handler_handle_event (MetaWaylandEventHandler *handler,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
ClutterEventType event_type = clutter_event_type (event);
|
||||||
|
|
||||||
|
switch (event_type)
|
||||||
|
{
|
||||||
|
case CLUTTER_ENTER:
|
||||||
|
case CLUTTER_LEAVE:
|
||||||
|
{
|
||||||
|
ClutterInputDevice *device;
|
||||||
|
ClutterEventSequence *sequence;
|
||||||
|
|
||||||
|
device = clutter_event_get_device (event);
|
||||||
|
sequence = clutter_event_get_event_sequence (event);
|
||||||
|
meta_wayland_event_handler_invalidate_focus (handler,
|
||||||
|
device, sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
case CLUTTER_TOUCH_BEGIN:
|
||||||
|
case CLUTTER_BUTTON_PRESS:
|
||||||
|
if (!handler->iface->press)
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
return handler->iface->press (handler, event, handler->user_data);
|
||||||
|
|
||||||
|
case CLUTTER_TOUCH_UPDATE:
|
||||||
|
case CLUTTER_MOTION:
|
||||||
|
if (!handler->iface->motion)
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
return handler->iface->motion (handler, event, handler->user_data);
|
||||||
|
|
||||||
|
case CLUTTER_TOUCH_END:
|
||||||
|
case CLUTTER_BUTTON_RELEASE:
|
||||||
|
if (!handler->iface->release)
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
return handler->iface->release (handler, event, handler->user_data);
|
||||||
|
|
||||||
|
case CLUTTER_KEY_PRESS:
|
||||||
|
case CLUTTER_KEY_RELEASE:
|
||||||
|
if (!handler->iface->key)
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
return handler->iface->key (handler, event, handler->user_data);
|
||||||
|
|
||||||
|
case CLUTTER_TOUCH_CANCEL:
|
||||||
|
case CLUTTER_SCROLL:
|
||||||
|
case CLUTTER_PROXIMITY_IN:
|
||||||
|
case CLUTTER_PROXIMITY_OUT:
|
||||||
|
case CLUTTER_TOUCHPAD_PINCH:
|
||||||
|
case CLUTTER_TOUCHPAD_SWIPE:
|
||||||
|
case CLUTTER_TOUCHPAD_HOLD:
|
||||||
|
case CLUTTER_PAD_BUTTON_PRESS:
|
||||||
|
case CLUTTER_PAD_BUTTON_RELEASE:
|
||||||
|
case CLUTTER_PAD_STRIP:
|
||||||
|
case CLUTTER_PAD_RING:
|
||||||
|
case CLUTTER_IM_COMMIT:
|
||||||
|
case CLUTTER_IM_DELETE:
|
||||||
|
case CLUTTER_IM_PREEDIT:
|
||||||
|
case CLUTTER_DEVICE_ADDED:
|
||||||
|
case CLUTTER_DEVICE_REMOVED:
|
||||||
|
case CLUTTER_NOTHING:
|
||||||
|
case CLUTTER_EVENT_LAST:
|
||||||
|
if (!handler->iface->other)
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
return handler->iface->other (handler, event, handler->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaWaylandEventHandler *
|
||||||
|
meta_wayland_input_attach_event_handler (MetaWaylandInput *input,
|
||||||
|
const MetaWaylandEventInterface *iface,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaWaylandEventHandler *handler;
|
||||||
|
|
||||||
|
handler = g_new0 (MetaWaylandEventHandler, 1);
|
||||||
|
handler->iface = iface;
|
||||||
|
handler->input = input;
|
||||||
|
handler->user_data = user_data;
|
||||||
|
wl_list_init (&handler->link);
|
||||||
|
wl_list_insert (&input->event_handler_list, &handler->link);
|
||||||
|
|
||||||
|
meta_wayland_event_handler_invalidate_all_focus (handler);
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_input_detach_event_handler (MetaWaylandInput *input,
|
||||||
|
MetaWaylandEventHandler *handler)
|
||||||
|
{
|
||||||
|
gboolean handler_change = FALSE;
|
||||||
|
|
||||||
|
handler_change = meta_wayland_input_is_current_handler (input, handler);
|
||||||
|
wl_list_remove (&handler->link);
|
||||||
|
|
||||||
|
if (handler_change && !wl_list_empty (&input->event_handler_list))
|
||||||
|
{
|
||||||
|
MetaWaylandEventHandler *head =
|
||||||
|
wl_container_of (input->event_handler_list.next,
|
||||||
|
head, link);
|
||||||
|
|
||||||
|
meta_wayland_event_handler_invalidate_all_focus (head);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_input_is_current_handler (MetaWaylandInput *input,
|
||||||
|
MetaWaylandEventHandler *handler)
|
||||||
|
{
|
||||||
|
return input->event_handler_list.next == &handler->link;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_input_handle_event (MetaWaylandInput *input,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWaylandEventHandler *handler, *next;
|
||||||
|
gboolean retval = CLUTTER_EVENT_PROPAGATE;
|
||||||
|
ClutterEventType event_type = clutter_event_type (event);
|
||||||
|
|
||||||
|
wl_list_for_each_safe (handler, next, &input->event_handler_list, link)
|
||||||
|
{
|
||||||
|
retval = meta_wayland_event_handler_handle_event (handler, event);
|
||||||
|
if (retval == CLUTTER_EVENT_STOP)
|
||||||
|
break;
|
||||||
|
/* Event handlers propagate focus themselves */
|
||||||
|
if (event_type == CLUTTER_ENTER ||
|
||||||
|
event_type == CLUTTER_LEAVE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_input_invalidate_focus (MetaWaylandInput *input,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence)
|
||||||
|
{
|
||||||
|
if (!wl_list_empty (&input->event_handler_list))
|
||||||
|
{
|
||||||
|
MetaWaylandEventHandler *head =
|
||||||
|
wl_container_of (input->event_handler_list.next,
|
||||||
|
head, link);
|
||||||
|
|
||||||
|
meta_wayland_event_handler_invalidate_focus (head, device, sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaWaylandSurface *
|
||||||
|
meta_wayland_event_handler_chain_up_get_focus_surface (MetaWaylandEventHandler *handler,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence)
|
||||||
|
{
|
||||||
|
MetaWaylandEventHandler *next;
|
||||||
|
|
||||||
|
g_assert (!wl_list_empty (&handler->link));
|
||||||
|
|
||||||
|
next = wl_container_of (handler->link.next, next, link);
|
||||||
|
|
||||||
|
return next->iface->get_focus_surface (next, device, sequence, next->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_event_handler_chain_up_focus (MetaWaylandEventHandler *handler,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence,
|
||||||
|
MetaWaylandSurface *surface)
|
||||||
|
{
|
||||||
|
MetaWaylandEventHandler *next;
|
||||||
|
|
||||||
|
g_assert (!wl_list_empty (&handler->link));
|
||||||
|
|
||||||
|
next = wl_container_of (handler->link.next, next, link);
|
||||||
|
|
||||||
|
return next->iface->focus (next, device, sequence, surface, next->user_data);
|
||||||
|
}
|
102
src/wayland/meta-wayland-input.h
Normal file
102
src/wayland/meta-wayland-input.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Interface for Wayland events
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include "clutter/clutter.h"
|
||||||
|
#include "wayland/meta-wayland-types.h"
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_INPUT (meta_wayland_input_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandInput,
|
||||||
|
meta_wayland_input,
|
||||||
|
META, WAYLAND_INPUT,
|
||||||
|
GObject);
|
||||||
|
|
||||||
|
typedef struct _MetaWaylandEventHandler MetaWaylandEventHandler;
|
||||||
|
|
||||||
|
typedef struct _MetaWaylandEventInterface MetaWaylandEventInterface;
|
||||||
|
|
||||||
|
struct _MetaWaylandEventInterface
|
||||||
|
{
|
||||||
|
MetaWaylandSurface * (*get_focus_surface) (MetaWaylandEventHandler *handler,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
/* Pointer/stylus/touch */
|
||||||
|
void (*focus) (MetaWaylandEventHandler *handler,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence,
|
||||||
|
MetaWaylandSurface *surface,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean (*motion) (MetaWaylandEventHandler *handler,
|
||||||
|
const ClutterEvent *event,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean (*press) (MetaWaylandEventHandler *handler,
|
||||||
|
const ClutterEvent *event,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean (*release) (MetaWaylandEventHandler *handler,
|
||||||
|
const ClutterEvent *event,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
/* Key */
|
||||||
|
gboolean (*key) (MetaWaylandEventHandler *handler,
|
||||||
|
const ClutterEvent *event,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
/* Other (Pads/IM/...) */
|
||||||
|
gboolean (*other) (MetaWaylandEventHandler *handler,
|
||||||
|
const ClutterEvent *event,
|
||||||
|
gpointer user_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
MetaWaylandInput * meta_wayland_input_new (MetaWaylandSeat *seat);
|
||||||
|
|
||||||
|
MetaWaylandEventHandler * meta_wayland_input_attach_event_handler (MetaWaylandInput *input,
|
||||||
|
const MetaWaylandEventInterface *iface,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean meta_wayland_input_is_current_handler (MetaWaylandInput *input,
|
||||||
|
MetaWaylandEventHandler *handler);
|
||||||
|
|
||||||
|
void meta_wayland_input_detach_event_handler (MetaWaylandInput *input,
|
||||||
|
MetaWaylandEventHandler *handler);
|
||||||
|
|
||||||
|
gboolean meta_wayland_input_handle_event (MetaWaylandInput *input,
|
||||||
|
const ClutterEvent *event);
|
||||||
|
|
||||||
|
void meta_wayland_input_invalidate_focus (MetaWaylandInput *input,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence);
|
||||||
|
|
||||||
|
MetaWaylandSurface * meta_wayland_event_handler_chain_up_get_focus_surface (MetaWaylandEventHandler *handler,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence);
|
||||||
|
|
||||||
|
void meta_wayland_event_handler_chain_up_focus (MetaWaylandEventHandler *handler,
|
||||||
|
ClutterInputDevice *device,
|
||||||
|
ClutterEventSequence *sequence,
|
||||||
|
MetaWaylandSurface *surface);
|
Loading…
x
Reference in New Issue
Block a user