Rework the emission of LEAVE/ENTER event pairs
The LEAVE/ENTER event pairs should be queued during the InputDevice update process, when we change the actor under the device pointer. This commit cleans up the event emission code inside clutter-main.c and the logic of the event processing.
This commit is contained in:
parent
75f05646fa
commit
687c70dffa
@ -75,7 +75,7 @@ clutter_device_manager_class_init (ClutterDeviceManagerClass *klass)
|
|||||||
G_SIGNAL_RUN_LAST,
|
G_SIGNAL_RUN_LAST,
|
||||||
0,
|
0,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
clutter_marshal_VOID__POINTER,
|
clutter_marshal_VOID__OBJECT,
|
||||||
G_TYPE_NONE, 1,
|
G_TYPE_NONE, 1,
|
||||||
G_TYPE_POINTER);
|
G_TYPE_POINTER);
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ clutter_device_manager_class_init (ClutterDeviceManagerClass *klass)
|
|||||||
G_SIGNAL_RUN_LAST,
|
G_SIGNAL_RUN_LAST,
|
||||||
0,
|
0,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
clutter_marshal_VOID__POINTER,
|
clutter_marshal_VOID__OBJECT,
|
||||||
G_TYPE_NONE, 1,
|
G_TYPE_NONE, 1,
|
||||||
G_TYPE_POINTER);
|
G_TYPE_POINTER);
|
||||||
}
|
}
|
||||||
|
@ -242,25 +242,91 @@ cursor_weak_unref (gpointer user_data,
|
|||||||
device->cursor_actor = NULL;
|
device->cursor_actor = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _clutter_input_device_set_actor:
|
||||||
|
* @device: a #ClutterInputDevice
|
||||||
|
* @actor: a #ClutterActor
|
||||||
|
*
|
||||||
|
* Sets the actor under the pointer coordinates of @device
|
||||||
|
*
|
||||||
|
* This function is called by _clutter_input_device_update()
|
||||||
|
* and it will:
|
||||||
|
*
|
||||||
|
* - queue a %CLUTTER_LEAVE event on the previous pointer actor
|
||||||
|
* of @device, if any
|
||||||
|
* - set to %FALSE the :has-pointer property of the previous
|
||||||
|
* pointer actor of @device, if any
|
||||||
|
* - queue a %CLUTTER_ENTER event on the new pointer actor
|
||||||
|
* - set to %TRUE the :has-pointer property of the new pointer
|
||||||
|
* actor
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
_clutter_input_device_set_actor (ClutterInputDevice *device,
|
_clutter_input_device_set_actor (ClutterInputDevice *device,
|
||||||
ClutterActor *actor)
|
ClutterActor *actor)
|
||||||
{
|
{
|
||||||
|
ClutterActor *old_actor;
|
||||||
|
ClutterEvent cev;
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||||
|
|
||||||
if (device->cursor_actor != NULL)
|
if (actor == device->cursor_actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
old_actor = device->cursor_actor;
|
||||||
|
if (old_actor != NULL)
|
||||||
{
|
{
|
||||||
|
cev.crossing.type = CLUTTER_LEAVE;
|
||||||
|
cev.crossing.time = device->previous_time;
|
||||||
|
cev.crossing.flags = 0;
|
||||||
|
cev.crossing.stage = device->stage;
|
||||||
|
cev.crossing.source = device->cursor_actor;
|
||||||
|
cev.crossing.x = device->previous_x;
|
||||||
|
cev.crossing.y = device->previous_y;
|
||||||
|
cev.crossing.device = device;
|
||||||
|
cev.crossing.related = actor;
|
||||||
|
|
||||||
|
/* we need to make sure that this event is processed before
|
||||||
|
* any other event we might have queued up until now, so we
|
||||||
|
* go on and synthesize the event emission
|
||||||
|
*/
|
||||||
|
_clutter_process_event (&cev);
|
||||||
|
|
||||||
_clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
|
_clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
|
||||||
g_object_weak_unref (G_OBJECT (device->cursor_actor),
|
g_object_weak_unref (G_OBJECT (device->cursor_actor),
|
||||||
cursor_weak_unref,
|
cursor_weak_unref,
|
||||||
device);
|
device);
|
||||||
|
|
||||||
|
device->cursor_actor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor != NULL)
|
||||||
|
{
|
||||||
|
cev.crossing.type = CLUTTER_ENTER;
|
||||||
|
cev.crossing.time = device->current_time;
|
||||||
|
cev.crossing.flags = 0;
|
||||||
|
cev.crossing.stage = device->stage;
|
||||||
|
cev.crossing.source = actor;
|
||||||
|
cev.crossing.x = device->current_x;
|
||||||
|
cev.crossing.y = device->current_y;
|
||||||
|
cev.crossing.device = device;
|
||||||
|
cev.crossing.related = old_actor;
|
||||||
|
|
||||||
|
/* as above: we need to make sure that this event is processed
|
||||||
|
* before any other event we might have queued up until now, so
|
||||||
|
* we go on and synthesize the event emission
|
||||||
|
*/
|
||||||
|
_clutter_process_event (&cev);
|
||||||
}
|
}
|
||||||
|
|
||||||
device->cursor_actor = actor;
|
device->cursor_actor = actor;
|
||||||
|
|
||||||
|
if (device->cursor_actor != NULL)
|
||||||
|
{
|
||||||
g_object_weak_ref (G_OBJECT (device->cursor_actor),
|
g_object_weak_ref (G_OBJECT (device->cursor_actor),
|
||||||
cursor_weak_unref,
|
cursor_weak_unref,
|
||||||
device);
|
device);
|
||||||
_clutter_actor_set_has_pointer (device->cursor_actor, TRUE);
|
_clutter_actor_set_has_pointer (device->cursor_actor, TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -345,7 +411,7 @@ _clutter_input_device_update (ClutterInputDevice *device)
|
|||||||
* in which case this is the safest course of action anyway
|
* in which case this is the safest course of action anyway
|
||||||
*/
|
*/
|
||||||
if (new_cursor_actor == NULL)
|
if (new_cursor_actor == NULL)
|
||||||
new_cursor_actor = CLUTTER_ACTOR (stage);
|
return NULL;
|
||||||
|
|
||||||
CLUTTER_NOTE (EVENT,
|
CLUTTER_NOTE (EVENT,
|
||||||
"Actor under cursor (device %d, at %d, %d): %s",
|
"Actor under cursor (device %d, at %d, %d): %s",
|
||||||
@ -355,6 +421,9 @@ _clutter_input_device_update (ClutterInputDevice *device)
|
|||||||
? clutter_actor_get_name (new_cursor_actor)
|
? clutter_actor_get_name (new_cursor_actor)
|
||||||
: G_OBJECT_TYPE_NAME (new_cursor_actor));
|
: G_OBJECT_TYPE_NAME (new_cursor_actor));
|
||||||
|
|
||||||
|
if (new_cursor_actor == old_cursor_actor)
|
||||||
|
return old_cursor_actor;
|
||||||
|
|
||||||
_clutter_input_device_set_actor (device, new_cursor_actor);
|
_clutter_input_device_set_actor (device, new_cursor_actor);
|
||||||
|
|
||||||
return device->cursor_actor;
|
return device->cursor_actor;
|
||||||
|
@ -2182,27 +2182,26 @@ static inline void
|
|||||||
emit_pointer_event (ClutterEvent *event,
|
emit_pointer_event (ClutterEvent *event,
|
||||||
ClutterInputDevice *device)
|
ClutterInputDevice *device)
|
||||||
{
|
{
|
||||||
/* Using the global variable directly, since it has to be initialized
|
ClutterMainContext *context = _clutter_context_get_default ();
|
||||||
* at this point
|
|
||||||
*/
|
|
||||||
ClutterMainContext *context = ClutterCntx;
|
|
||||||
|
|
||||||
if (G_UNLIKELY (context->pointer_grab_actor != NULL &&
|
if (context->pointer_grab_actor == NULL &&
|
||||||
device == NULL))
|
(device == NULL || device->pointer_grab_actor == NULL))
|
||||||
|
{
|
||||||
|
/* no grab, time to capture and bubble */
|
||||||
|
emit_event (event, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (context->pointer_grab_actor != NULL)
|
||||||
{
|
{
|
||||||
/* global grab */
|
/* global grab */
|
||||||
clutter_actor_event (context->pointer_grab_actor, event, FALSE);
|
clutter_actor_event (context->pointer_grab_actor, event, FALSE);
|
||||||
}
|
}
|
||||||
else if (G_UNLIKELY (device != NULL &&
|
else if (device != NULL && device->pointer_grab_actor != NULL)
|
||||||
device->pointer_grab_actor != NULL))
|
|
||||||
{
|
{
|
||||||
/* per device grab */
|
/* per device grab */
|
||||||
clutter_actor_event (device->pointer_grab_actor, event, FALSE);
|
clutter_actor_event (device->pointer_grab_actor, event, FALSE);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* no grab, time to capture and bubble */
|
|
||||||
emit_event (event, FALSE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2211,107 +2210,10 @@ emit_keyboard_event (ClutterEvent *event)
|
|||||||
{
|
{
|
||||||
ClutterMainContext *context = _clutter_context_get_default ();
|
ClutterMainContext *context = _clutter_context_get_default ();
|
||||||
|
|
||||||
if (G_UNLIKELY (context->keyboard_grab_actor != NULL))
|
if (context->keyboard_grab_actor == NULL)
|
||||||
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
|
|
||||||
else
|
|
||||||
emit_event (event, TRUE);
|
emit_event (event, TRUE);
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
unset_motion_last_actor (ClutterActor *actor, ClutterInputDevice *dev)
|
|
||||||
{
|
|
||||||
ClutterMainContext *context = _clutter_context_get_default ();
|
|
||||||
|
|
||||||
if (dev == NULL)
|
|
||||||
context->motion_last_actor = NULL;
|
|
||||||
else
|
else
|
||||||
dev->motion_last_actor = NULL;
|
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_motion_last_actor (ClutterActor *motion_current_actor,
|
|
||||||
ClutterInputDevice *device)
|
|
||||||
{
|
|
||||||
ClutterMainContext *context = _clutter_context_get_default ();
|
|
||||||
ClutterActor *last_actor = context->motion_last_actor;
|
|
||||||
|
|
||||||
if (device != NULL)
|
|
||||||
last_actor = device->motion_last_actor;
|
|
||||||
|
|
||||||
if (last_actor && last_actor != motion_current_actor)
|
|
||||||
{
|
|
||||||
g_signal_handlers_disconnect_by_func
|
|
||||||
(last_actor,
|
|
||||||
G_CALLBACK (unset_motion_last_actor),
|
|
||||||
device);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motion_current_actor && last_actor != motion_current_actor)
|
|
||||||
{
|
|
||||||
g_signal_connect (motion_current_actor, "destroy",
|
|
||||||
G_CALLBACK (unset_motion_last_actor),
|
|
||||||
device);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device != NULL)
|
|
||||||
device->motion_last_actor = motion_current_actor;
|
|
||||||
else
|
|
||||||
context->motion_last_actor = motion_current_actor;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
generate_enter_leave_events (ClutterEvent *event)
|
|
||||||
{
|
|
||||||
ClutterMainContext *context = _clutter_context_get_default ();
|
|
||||||
ClutterActor *motion_current_actor = event->motion.source;
|
|
||||||
ClutterActor *last_actor = context->motion_last_actor;
|
|
||||||
ClutterInputDevice *device = clutter_event_get_device (event);
|
|
||||||
|
|
||||||
if (device != NULL)
|
|
||||||
last_actor = device->motion_last_actor;
|
|
||||||
|
|
||||||
if (last_actor != motion_current_actor)
|
|
||||||
{
|
|
||||||
if (motion_current_actor)
|
|
||||||
{
|
|
||||||
ClutterEvent cev;
|
|
||||||
gfloat x, y;
|
|
||||||
|
|
||||||
cev.crossing.device = device;
|
|
||||||
clutter_event_get_coords (event, &x, &y);
|
|
||||||
|
|
||||||
if (context->motion_last_actor)
|
|
||||||
{
|
|
||||||
cev.crossing.type = CLUTTER_LEAVE;
|
|
||||||
cev.crossing.time = event->any.time;
|
|
||||||
cev.crossing.flags = 0;
|
|
||||||
cev.crossing.x = x;
|
|
||||||
cev.crossing.y = y;
|
|
||||||
cev.crossing.source = last_actor;
|
|
||||||
cev.crossing.stage = event->any.stage;
|
|
||||||
cev.crossing.related = motion_current_actor;
|
|
||||||
|
|
||||||
emit_pointer_event (&cev, device);
|
|
||||||
}
|
|
||||||
|
|
||||||
cev.crossing.type = CLUTTER_ENTER;
|
|
||||||
cev.crossing.time = event->any.time;
|
|
||||||
cev.crossing.flags = 0;
|
|
||||||
cev.crossing.x = x;
|
|
||||||
cev.crossing.y = y;
|
|
||||||
cev.crossing.source = motion_current_actor;
|
|
||||||
cev.crossing.stage = event->any.stage;
|
|
||||||
|
|
||||||
if (context->motion_last_actor)
|
|
||||||
cev.crossing.related = last_actor;
|
|
||||||
else
|
|
||||||
cev.crossing.related = NULL;
|
|
||||||
|
|
||||||
emit_pointer_event (&cev, device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_motion_last_actor (motion_current_actor, device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2345,6 +2247,8 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
{
|
{
|
||||||
ClutterInputDevice *device = NULL;
|
ClutterInputDevice *device = NULL;
|
||||||
|
|
||||||
|
device = clutter_event_get_device (event);
|
||||||
|
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
case CLUTTER_NOTHING:
|
case CLUTTER_NOTHING:
|
||||||
@ -2352,23 +2256,8 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CLUTTER_LEAVE:
|
case CLUTTER_LEAVE:
|
||||||
/* The source is set for generated events, not for events
|
|
||||||
* resulting from the cursor leaving the stage
|
|
||||||
*/
|
|
||||||
if (event->any.source == NULL)
|
|
||||||
{
|
|
||||||
ClutterActor *last_actor = context->motion_last_actor;
|
|
||||||
|
|
||||||
if (event->crossing.device != NULL)
|
|
||||||
last_actor = event->crossing.device->motion_last_actor;
|
|
||||||
|
|
||||||
event->any.source = last_actor;
|
|
||||||
|
|
||||||
set_motion_last_actor (NULL, event->crossing.device);
|
|
||||||
}
|
|
||||||
/* flow through */
|
|
||||||
case CLUTTER_ENTER:
|
case CLUTTER_ENTER:
|
||||||
emit_pointer_event (event, event->crossing.device);
|
emit_pointer_event (event, device);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLUTTER_DESTROY_NOTIFY:
|
case CLUTTER_DESTROY_NOTIFY:
|
||||||
@ -2400,8 +2289,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CLUTTER_MOTION:
|
case CLUTTER_MOTION:
|
||||||
device = event->motion.device;
|
|
||||||
|
|
||||||
/* Only stage gets motion events if clutter_set_motion_events is TRUE,
|
/* Only stage gets motion events if clutter_set_motion_events is TRUE,
|
||||||
* and the event is not a synthetic event with source set.
|
* and the event is not a synthetic event with source set.
|
||||||
*/
|
*/
|
||||||
@ -2434,8 +2321,7 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough from motion */
|
||||||
|
|
||||||
case CLUTTER_BUTTON_PRESS:
|
case CLUTTER_BUTTON_PRESS:
|
||||||
case CLUTTER_BUTTON_RELEASE:
|
case CLUTTER_BUTTON_RELEASE:
|
||||||
case CLUTTER_SCROLL:
|
case CLUTTER_SCROLL:
|
||||||
@ -2445,24 +2331,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
|
|
||||||
clutter_event_get_coords (event, &x, &y);
|
clutter_event_get_coords (event, &x, &y);
|
||||||
|
|
||||||
if (device == NULL)
|
|
||||||
{
|
|
||||||
switch (event->type)
|
|
||||||
{
|
|
||||||
case CLUTTER_BUTTON_PRESS:
|
|
||||||
case CLUTTER_BUTTON_RELEASE:
|
|
||||||
device = event->button.device;
|
|
||||||
break;
|
|
||||||
case CLUTTER_SCROLL:
|
|
||||||
device = event->scroll.device;
|
|
||||||
break;
|
|
||||||
case CLUTTER_MOTION:
|
|
||||||
/* already handled in the MOTION case of the switch */
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only do a pick to find the source if source is not already set
|
/* Only do a pick to find the source if source is not already set
|
||||||
* (as it could be in a synthetic event)
|
* (as it could be in a synthetic event)
|
||||||
*/
|
*/
|
||||||
@ -2480,7 +2348,7 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
x, y);
|
x, y);
|
||||||
|
|
||||||
event->button.source = stage;
|
event->button.source = stage;
|
||||||
emit_pointer_event (event, event->button.device);
|
emit_pointer_event (event, device);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2489,20 +2357,19 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
* already have everything we need to update it and
|
* already have everything we need to update it and
|
||||||
* get the actor underneath
|
* get the actor underneath
|
||||||
*/
|
*/
|
||||||
if (device == NULL)
|
if (device != NULL)
|
||||||
|
actor = _clutter_input_device_update (device);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
CLUTTER_NOTE (EVENT, "No device found: picking");
|
CLUTTER_NOTE (EVENT, "No device found: picking");
|
||||||
|
|
||||||
/* Map the event to a reactive actor */
|
|
||||||
actor = _clutter_do_pick (CLUTTER_STAGE (stage),
|
actor = _clutter_do_pick (CLUTTER_STAGE (stage),
|
||||||
x, y,
|
x, y,
|
||||||
CLUTTER_PICK_REACTIVE);
|
CLUTTER_PICK_REACTIVE);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
actor = _clutter_input_device_update (device);
|
|
||||||
|
|
||||||
event->any.source = actor;
|
event->any.source = actor;
|
||||||
if (actor == NULL)
|
if (event->any.source == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2521,9 +2388,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
|||||||
x, y,
|
x, y,
|
||||||
actor);
|
actor);
|
||||||
|
|
||||||
/* Create, enter/leave events if needed */
|
|
||||||
generate_enter_leave_events (event);
|
|
||||||
|
|
||||||
if (event->type != CLUTTER_MOTION)
|
if (event->type != CLUTTER_MOTION)
|
||||||
{
|
{
|
||||||
/* Generate click count */
|
/* Generate click count */
|
||||||
|
@ -92,9 +92,7 @@ struct _ClutterInputDevice
|
|||||||
ClutterInputDeviceType device_type;
|
ClutterInputDeviceType device_type;
|
||||||
|
|
||||||
ClutterActor *cursor_actor;
|
ClutterActor *cursor_actor;
|
||||||
|
|
||||||
ClutterActor *pointer_grab_actor;
|
ClutterActor *pointer_grab_actor;
|
||||||
ClutterActor *motion_last_actor;
|
|
||||||
|
|
||||||
gint click_count;
|
gint click_count;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user