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:
Emmanuele Bassi 2009-11-24 16:33:03 +00:00
parent 75f05646fa
commit 687c70dffa
4 changed files with 105 additions and 174 deletions

View File

@ -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);
} }

View File

@ -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;

View File

@ -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 */

View File

@ -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;