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:
parent
a79f35612b
commit
e917b7de43
97
clutter/clutter/clutter-input-only-action.c
Normal file
97
clutter/clutter/clutter-input-only-action.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2022 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/>.
|
||||
*/
|
||||
|
||||
#include "clutter-build-config.h"
|
||||
|
||||
#include "clutter/clutter-input-only-action.h"
|
||||
|
||||
#include "clutter/clutter-action-private.h"
|
||||
#include "clutter/clutter.h"
|
||||
|
||||
struct _ClutterInputOnlyAction
|
||||
{
|
||||
ClutterAction parent;
|
||||
|
||||
ClutterInputOnlyHandleEvent handle_event;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_data_destroy;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ClutterInputOnlyAction, clutter_input_only_action,
|
||||
CLUTTER_TYPE_ACTION)
|
||||
|
||||
static void
|
||||
clutter_input_only_action_dispose (GObject *object)
|
||||
{
|
||||
ClutterInputOnlyAction *input_only_action =
|
||||
CLUTTER_INPUT_ONLY_ACTION (object);
|
||||
|
||||
if (input_only_action->user_data_destroy)
|
||||
{
|
||||
g_clear_pointer (&input_only_action->user_data,
|
||||
input_only_action->user_data_destroy);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (clutter_input_only_action_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_input_only_action_handle_event (ClutterAction *action,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
ClutterInputOnlyAction *input_only_action =
|
||||
CLUTTER_INPUT_ONLY_ACTION (action);
|
||||
|
||||
return input_only_action->handle_event (event, input_only_action->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_only_action_class_init (ClutterInputOnlyActionClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActionClass *action_class = CLUTTER_ACTION_CLASS (klass);
|
||||
|
||||
object_class->finalize = clutter_input_only_action_dispose;
|
||||
|
||||
action_class->handle_event = clutter_input_only_action_handle_event;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_only_action_init (ClutterInputOnlyAction *input_only_action)
|
||||
{
|
||||
}
|
||||
|
||||
ClutterInputOnlyAction *
|
||||
clutter_input_only_action_new (ClutterInputOnlyHandleEvent handle_event,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy)
|
||||
{
|
||||
ClutterInputOnlyAction *input_only_action;
|
||||
|
||||
input_only_action = g_object_new (CLUTTER_TYPE_INPUT_ONLY_ACTION, NULL);
|
||||
input_only_action->handle_event = handle_event;
|
||||
input_only_action->user_data = user_data;
|
||||
input_only_action->user_data_destroy = user_data_destroy;
|
||||
clutter_action_set_phase (CLUTTER_ACTION (input_only_action),
|
||||
CLUTTER_PHASE_CAPTURE);
|
||||
|
||||
return input_only_action;
|
||||
}
|
38
clutter/clutter/clutter-input-only-action.h
Normal file
38
clutter/clutter/clutter-input-only-action.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2022 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/>.
|
||||
*/
|
||||
|
||||
#ifndef CLUTTER_INPUT_ONLY_ACTION_H
|
||||
#define CLUTTER_INPUT_ONLY_ACTION_H
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
|
||||
typedef gboolean (* ClutterInputOnlyHandleEvent) (const ClutterEvent *event,
|
||||
gpointer user_data);
|
||||
|
||||
#define CLUTTER_TYPE_INPUT_ONLY_ACTION (clutter_input_only_action_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (ClutterInputOnlyAction, clutter_input_only_action,
|
||||
CLUTTER, INPUT_ONLY_ACTION, ClutterAction)
|
||||
|
||||
ClutterInputOnlyAction * clutter_input_only_action_new (ClutterInputOnlyHandleEvent handle_event,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy);
|
||||
|
||||
#endif /* CLUTTER_INPUT_ONLY_ACTION_H */
|
60
clutter/clutter/clutter-input-only-actor.c
Normal file
60
clutter/clutter/clutter-input-only-actor.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2022 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/>.
|
||||
*/
|
||||
|
||||
#include "clutter-build-config.h"
|
||||
|
||||
#include "clutter-input-only-actor.h"
|
||||
|
||||
#include "clutter-input-only-action.h"
|
||||
|
||||
struct _ClutterInputOnlyActor
|
||||
{
|
||||
ClutterActor parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ClutterInputOnlyActor, clutter_input_only_actor,
|
||||
CLUTTER_TYPE_ACTOR)
|
||||
|
||||
static void
|
||||
clutter_input_only_actor_class_init (ClutterInputOnlyActorClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_only_actor_init (ClutterInputOnlyActor *input_only_actor)
|
||||
{
|
||||
}
|
||||
|
||||
ClutterInputOnlyActor *
|
||||
clutter_input_only_actor_new (ClutterInputOnlyHandleEvent handle_event,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy)
|
||||
{
|
||||
ClutterInputOnlyAction *input_only_action;
|
||||
|
||||
input_only_action = clutter_input_only_action_new (handle_event,
|
||||
user_data,
|
||||
user_data_destroy);
|
||||
return g_object_new (CLUTTER_TYPE_INPUT_ONLY_ACTOR,
|
||||
"reactive", TRUE,
|
||||
"actions", input_only_action,
|
||||
NULL);
|
||||
}
|
36
clutter/clutter/clutter-input-only-actor.h
Normal file
36
clutter/clutter/clutter-input-only-actor.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2022 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/>.
|
||||
*/
|
||||
|
||||
#ifndef CLUTTER_INPUT_ONLY_ACTOR_H
|
||||
#define CLUTTER_INPUT_ONLY_ACTOR_H
|
||||
|
||||
#include "clutter/clutter.h"
|
||||
#include "clutter/clutter-stage-private.h"
|
||||
|
||||
#define CLUTTER_TYPE_INPUT_ONLY_ACTOR (clutter_input_only_actor_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (ClutterInputOnlyActor, clutter_input_only_actor,
|
||||
CLUTTER, INPUT_ONLY_ACTOR, ClutterActor)
|
||||
|
||||
ClutterInputOnlyActor * clutter_input_only_actor_new (ClutterEventHandler event_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy);
|
||||
|
||||
#endif /* CLUTTER_INPUT_ONLY_ACTOR_H */
|
@ -32,6 +32,8 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef gboolean (* ClutterEventHandler) (const ClutterEvent *event,
|
||||
gpointer user_data);
|
||||
typedef enum
|
||||
{
|
||||
CLUTTER_DEVICE_UPDATE_NONE = 0,
|
||||
@ -163,6 +165,12 @@ void clutter_stage_notify_action_implicit_grab (ClutterStage *self,
|
||||
void clutter_stage_add_to_redraw_clip (ClutterStage *self,
|
||||
ClutterPaintVolume *clip);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterGrab * clutter_stage_grab_input_only (ClutterStage *self,
|
||||
ClutterEventHandler handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "clutter-frame.h"
|
||||
#include "clutter-grab.h"
|
||||
#include "clutter-input-device-private.h"
|
||||
#include "clutter-input-only-actor.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-marshal.h"
|
||||
#include "clutter-mutter.h"
|
||||
@ -148,7 +149,10 @@ struct _ClutterGrab
|
||||
{
|
||||
grefcount ref_count;
|
||||
ClutterStage *stage;
|
||||
|
||||
ClutterActor *actor;
|
||||
gboolean owns_actor;
|
||||
|
||||
ClutterGrab *prev;
|
||||
ClutterGrab *next;
|
||||
};
|
||||
@ -3866,20 +3870,28 @@ clutter_grab_unref (ClutterGrab *grab)
|
||||
G_DEFINE_BOXED_TYPE (ClutterGrab, clutter_grab,
|
||||
clutter_grab_ref, clutter_grab_unref)
|
||||
|
||||
/**
|
||||
* clutter_stage_grab:
|
||||
* @stage: The #ClutterStage
|
||||
* @actor: The actor grabbing input
|
||||
*
|
||||
* Grabs input onto a certain actor. Events will be propagated as
|
||||
* usual inside its hierarchy.
|
||||
*
|
||||
* Returns: (transfer full): an opaque #ClutterGrab handle, drop
|
||||
* with [method@Grab.dismiss]
|
||||
**/
|
||||
ClutterGrab *
|
||||
clutter_stage_grab (ClutterStage *stage,
|
||||
ClutterActor *actor)
|
||||
static ClutterGrab *
|
||||
clutter_grab_new (ClutterStage *stage,
|
||||
ClutterActor *actor,
|
||||
gboolean owns_actor)
|
||||
{
|
||||
ClutterGrab *grab;
|
||||
|
||||
grab = g_new0 (ClutterGrab, 1);
|
||||
g_ref_count_init (&grab->ref_count);
|
||||
grab->stage = stage;
|
||||
|
||||
grab->actor = actor;
|
||||
if (owns_actor)
|
||||
grab->owns_actor = TRUE;
|
||||
|
||||
return grab;
|
||||
}
|
||||
|
||||
static ClutterGrab *
|
||||
clutter_stage_grab_full (ClutterStage *stage,
|
||||
ClutterActor *actor,
|
||||
gboolean owns_actor)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
ClutterGrab *grab;
|
||||
@ -3904,10 +3916,8 @@ clutter_stage_grab (ClutterStage *stage,
|
||||
clutter_seat_grab (seat, clutter_get_current_event_time ());
|
||||
}
|
||||
|
||||
grab = g_new0 (ClutterGrab, 1);
|
||||
g_ref_count_init (&grab->ref_count);
|
||||
grab->stage = stage;
|
||||
grab->actor = actor;
|
||||
grab = clutter_grab_new (stage, actor, owns_actor);
|
||||
|
||||
grab->prev = NULL;
|
||||
grab->next = priv->topmost_grab;
|
||||
|
||||
@ -3935,6 +3945,43 @@ clutter_stage_grab (ClutterStage *stage,
|
||||
return grab;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_grab:
|
||||
* @stage: The #ClutterStage
|
||||
* @actor: The actor grabbing input
|
||||
*
|
||||
* Grabs input onto a certain actor. Events will be propagated as
|
||||
* usual inside its hierarchy.
|
||||
*
|
||||
* Returns: (transfer full): an opaque #ClutterGrab handle, drop
|
||||
* with [method@Grab.dismiss]
|
||||
**/
|
||||
ClutterGrab *
|
||||
clutter_stage_grab (ClutterStage *stage,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
return clutter_stage_grab_full (stage, actor, FALSE);
|
||||
}
|
||||
|
||||
ClutterGrab *
|
||||
clutter_stage_grab_input_only (ClutterStage *stage,
|
||||
ClutterEventHandler handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy)
|
||||
{
|
||||
ClutterInputOnlyActor *input_only_actor;
|
||||
ClutterActor *actor;
|
||||
|
||||
input_only_actor = clutter_input_only_actor_new (handler, user_data,
|
||||
user_data_destroy);
|
||||
actor = CLUTTER_ACTOR (input_only_actor);
|
||||
clutter_actor_set_name (actor, "input only grab actor");
|
||||
|
||||
clutter_actor_insert_child_at_index (CLUTTER_ACTOR (stage), actor, 0);
|
||||
|
||||
return clutter_stage_grab_full (stage, actor, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_unlink_grab (ClutterStage *stage,
|
||||
ClutterGrab *grab)
|
||||
@ -3991,6 +4038,9 @@ clutter_stage_unlink_grab (ClutterStage *stage,
|
||||
|
||||
grab->next = NULL;
|
||||
grab->prev = NULL;
|
||||
|
||||
if (grab->owns_actor)
|
||||
g_clear_pointer (&grab->actor, clutter_actor_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,6 +140,8 @@ clutter_sources = [
|
||||
'clutter-input-focus.c',
|
||||
'clutter-input-method.c',
|
||||
'clutter-input-pointer-a11y.c',
|
||||
'clutter-input-only-action.c',
|
||||
'clutter-input-only-actor.c',
|
||||
'clutter-virtual-input-device.c',
|
||||
'clutter-interval.c',
|
||||
'clutter-keyframe-transition.c',
|
||||
@ -208,6 +210,8 @@ clutter_private_headers = [
|
||||
'clutter-input-focus-private.h',
|
||||
'clutter-input-method-private.h',
|
||||
'clutter-input-pointer-a11y-private.h',
|
||||
'clutter-input-only-action.h',
|
||||
'clutter-input-only-actor.h',
|
||||
'clutter-keymap-private.h',
|
||||
'clutter-offscreen-effect-private.h',
|
||||
'clutter-paint-context-private.h',
|
||||
|
@ -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);
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user