clutter/stage: Add input-only grabs
An input only grab is a ClutterGrab on the stage that doesn't have an explicit actor associated with it. This is useful for cases where event should be captured as if focus was stolen to some mysterious place that doesn't have anything in the scene graph that represents it. Internally, it's implemented using a 0x0 sized actor attached directly to the stage, and a clutter action that consumes the events. An input-only grab takes a handler, user data and a destroy function for the user data. These are handed to the ClutterAction, which handles the actual event handling. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2628>
This commit is contained in:

committed by
Carlos Garnacho

parent
a79f35612b
commit
e917b7de43
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "tests/clutter-test-utils.h"
|
||||
#include "clutter/clutter-event-private.h"
|
||||
#include "clutter/clutter-stage-private.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -50,17 +51,30 @@ event_cb (ClutterActor *actor,
|
||||
gpointer user_data)
|
||||
{
|
||||
GArray *events = user_data;
|
||||
EventLog entry;
|
||||
|
||||
if ((event->type == CLUTTER_ENTER ||
|
||||
event->type == CLUTTER_LEAVE) &&
|
||||
(event->any.flags & CLUTTER_EVENT_FLAG_GRAB_NOTIFY) != 0)
|
||||
switch (event->type)
|
||||
{
|
||||
EventLog entry = { clutter_actor_get_name (actor), event->type };
|
||||
case CLUTTER_ENTER:
|
||||
case CLUTTER_LEAVE:
|
||||
if ((event->any.flags & CLUTTER_EVENT_FLAG_GRAB_NOTIFY) != 0)
|
||||
{
|
||||
entry = (EventLog) { clutter_actor_get_name (actor), event->type };
|
||||
|
||||
g_debug ("Event '%s' on actor '%s'",
|
||||
clutter_event_get_name (event),
|
||||
entry.name);
|
||||
g_array_append_val (events, entry);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
entry = (EventLog) { clutter_actor_get_name (actor), event->type };
|
||||
g_debug ("Event '%s' on actor '%s'",
|
||||
clutter_event_get_name (event),
|
||||
entry.name);
|
||||
g_array_append_val (events, entry);
|
||||
break;
|
||||
}
|
||||
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
@@ -541,6 +555,107 @@ grab_key_focus_outside_grab (void)
|
||||
test_data_shutdown (&data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_input_only_event (const ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
GArray *events = user_data;
|
||||
EventLog entry = { "input-only grab", event->type };
|
||||
|
||||
g_debug ("Input only grab event '%s'", clutter_event_get_name (event));
|
||||
g_array_append_val (events, entry);
|
||||
|
||||
return CLUTTER_EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
last_event_is (GArray *events,
|
||||
ClutterEventType event_type)
|
||||
{
|
||||
EventLog *entry;
|
||||
|
||||
if (events->len == 0)
|
||||
return FALSE;
|
||||
|
||||
entry = &g_array_index (events, EventLog, events->len - 1);
|
||||
return entry->type == event_type;
|
||||
}
|
||||
|
||||
static void
|
||||
grab_input_only (void)
|
||||
{
|
||||
TestData data;
|
||||
ClutterGrab *grab;
|
||||
EventLog grab1_log[] = {
|
||||
{ "b", CLUTTER_LEAVE },
|
||||
{ "a", CLUTTER_LEAVE },
|
||||
{ "stage", CLUTTER_LEAVE },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
EventLog grab2_log[] = {
|
||||
{ "input-only grab", CLUTTER_BUTTON_PRESS },
|
||||
{ "input-only grab", CLUTTER_BUTTON_RELEASE },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
EventLog grab3_log[] = {
|
||||
{ "b", CLUTTER_ENTER },
|
||||
{ "a", CLUTTER_ENTER },
|
||||
{ "stage", CLUTTER_ENTER },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
EventLog grab4_log[] = {
|
||||
{ "b", CLUTTER_BUTTON_PRESS },
|
||||
{ "a", CLUTTER_BUTTON_PRESS },
|
||||
{ "stage", CLUTTER_BUTTON_PRESS },
|
||||
{ "b", CLUTTER_BUTTON_RELEASE },
|
||||
{ "a", CLUTTER_BUTTON_RELEASE },
|
||||
{ "stage", CLUTTER_BUTTON_RELEASE },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
ClutterSeat *seat;
|
||||
g_autoptr (ClutterVirtualInputDevice) pointer = NULL;
|
||||
|
||||
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
|
||||
pointer = clutter_seat_create_virtual_device (seat, CLUTTER_POINTER_DEVICE);
|
||||
|
||||
test_data_init (&data);
|
||||
|
||||
grab = clutter_stage_grab_input_only (CLUTTER_STAGE (data.stage),
|
||||
handle_input_only_event,
|
||||
data.events, NULL);
|
||||
event_log_compare ((EventLog *) &grab1_log, data.events);
|
||||
|
||||
clutter_virtual_input_device_notify_button (pointer,
|
||||
0,
|
||||
CLUTTER_BUTTON_PRIMARY,
|
||||
CLUTTER_BUTTON_STATE_PRESSED);
|
||||
clutter_virtual_input_device_notify_button (pointer,
|
||||
0,
|
||||
CLUTTER_BUTTON_PRIMARY,
|
||||
CLUTTER_BUTTON_STATE_RELEASED);
|
||||
|
||||
while (!last_event_is (data.events, CLUTTER_BUTTON_RELEASE))
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
event_log_compare ((EventLog *) &grab2_log, data.events);
|
||||
|
||||
clutter_grab_unref (grab);
|
||||
event_log_compare ((EventLog *) &grab3_log, data.events);
|
||||
|
||||
clutter_virtual_input_device_notify_button (pointer,
|
||||
0,
|
||||
CLUTTER_BUTTON_SECONDARY,
|
||||
CLUTTER_BUTTON_STATE_PRESSED);
|
||||
clutter_virtual_input_device_notify_button (pointer,
|
||||
0,
|
||||
CLUTTER_BUTTON_SECONDARY,
|
||||
CLUTTER_BUTTON_STATE_RELEASED);
|
||||
while (!last_event_is (data.events, CLUTTER_BUTTON_RELEASE))
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
event_log_compare ((EventLog *) &grab4_log, data.events);
|
||||
|
||||
test_data_shutdown (&data);
|
||||
}
|
||||
|
||||
CLUTTER_TEST_SUITE (
|
||||
CLUTTER_TEST_UNIT ("/grab/grab-under-pointer", grab_under_pointer)
|
||||
CLUTTER_TEST_UNIT ("/grab/grab-under-pointers-parent", grab_under_pointers_parent)
|
||||
@@ -552,4 +667,5 @@ CLUTTER_TEST_SUITE (
|
||||
CLUTTER_TEST_UNIT ("/grab/grab-unordered-ungrab-2", grab_unordered_ungrab_2)
|
||||
CLUTTER_TEST_UNIT ("/grab/key-focus-in-grab", grab_key_focus_in_grab);
|
||||
CLUTTER_TEST_UNIT ("/grab/key-focus-outside-grab", grab_key_focus_outside_grab);
|
||||
CLUTTER_TEST_UNIT ("/grab/input-only", grab_input_only);
|
||||
)
|
||||
|
Reference in New Issue
Block a user