Clean up crossing event synthesis code

Clutter should just require that the windowing system used by a backend
adds a device to the stage when the device enters, and removes it from
the stage when the device leaves; with this information, we can
synthesize every crossing event and update the device state without
other intervention from the backend-specific code.

The generation of additional crossing events for actors that are
covering the stage at the coordinates of the crossing event should be
delegated to the event processing code.

The x11 and win32 backends need to be modified to relay the enter and
leave events from the windowing system.
This commit is contained in:
Emmanuele Bassi 2011-01-27 17:26:16 +00:00
parent b3784bd2b4
commit 82d1e5a6ee
10 changed files with 238 additions and 157 deletions

View File

@ -136,8 +136,10 @@ void _clutter_input_device_set_time (ClutterInputDev
void _clutter_input_device_set_stage (ClutterInputDevice *device, void _clutter_input_device_set_stage (ClutterInputDevice *device,
ClutterStage *stage); ClutterStage *stage);
void _clutter_input_device_set_actor (ClutterInputDevice *device, void _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterActor *actor); ClutterActor *actor,
ClutterActor * _clutter_input_device_update (ClutterInputDevice *device); gboolean emit_crossing);
ClutterActor * _clutter_input_device_update (ClutterInputDevice *device,
gboolean emit_crossing);
void _clutter_input_device_set_n_keys (ClutterInputDevice *device, void _clutter_input_device_set_n_keys (ClutterInputDevice *device,
guint n_keys); guint n_keys);
guint _clutter_input_device_add_axis (ClutterInputDevice *device, guint _clutter_input_device_add_axis (ClutterInputDevice *device,

View File

@ -423,7 +423,7 @@ _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager)
if (device->stage == NULL) if (device->stage == NULL)
continue; continue;
_clutter_input_device_update (device); _clutter_input_device_update (device, TRUE);
} }
} }

View File

@ -543,6 +543,7 @@ clutter_event_set_device (ClutterEvent *event,
ClutterInputDevice *device) ClutterInputDevice *device)
{ {
g_return_if_fail (event != NULL); g_return_if_fail (event != NULL);
g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
if (is_event_allocated (event)) if (is_event_allocated (event))
{ {

View File

@ -445,49 +445,23 @@ void
_clutter_input_device_set_stage (ClutterInputDevice *device, _clutter_input_device_set_stage (ClutterInputDevice *device,
ClutterStage *stage) ClutterStage *stage)
{ {
ClutterStage *old_stage; if (device->stage == stage)
return;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
old_stage = device->stage;
device->stage = stage; device->stage = stage;
/* if we left the stage then we also need to unset the /* we leave the ->cursor_actor in place in order to check
* cursor actor (and update its :has-pointer property) * if we left the stage without crossing it again; this way
* we can emit a leave event on the cursor actor right before
* we emit the leave event on the stage.
*/ */
if (device->stage == NULL &&
device->cursor_actor != NULL &&
device->cursor_actor != CLUTTER_ACTOR (old_stage))
{
ClutterEvent cev;
cev.crossing.type = CLUTTER_LEAVE;
cev.crossing.time = device->current_time;
cev.crossing.flags = 0;
cev.crossing.stage = old_stage;
cev.crossing.source = device->cursor_actor;
cev.crossing.x = device->current_x;
cev.crossing.y = device->current_y;
cev.crossing.device = device;
cev.crossing.related = device->stage != NULL
? CLUTTER_ACTOR (device->stage)
: CLUTTER_ACTOR (old_stage);
_clutter_stage_queue_event (old_stage, &cev);
_clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
g_object_weak_unref (G_OBJECT (device->cursor_actor),
cursor_weak_unref,
device);
}
device->cursor_actor = NULL;
} }
/*< private > /*< private >
* clutter_input_device_set_actor: * clutter_input_device_set_actor:
* @device: a #ClutterInputDevice * @device: a #ClutterInputDevice
* @actor: a #ClutterActor * @actor: a #ClutterActor
* @emit_crossing: %TRUE to emit crossing events
* *
* Sets the actor under the pointer coordinates of @device * Sets the actor under the pointer coordinates of @device
* *
@ -504,34 +478,41 @@ _clutter_input_device_set_stage (ClutterInputDevice *device,
*/ */
void void
_clutter_input_device_set_actor (ClutterInputDevice *device, _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterActor *actor) ClutterActor *actor,
gboolean emit_crossing)
{ {
ClutterActor *old_actor; ClutterActor *old_actor;
ClutterEvent cev;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); if (device->cursor_actor == actor)
if (actor == device->cursor_actor)
return; return;
old_actor = device->cursor_actor; old_actor = device->cursor_actor;
if (old_actor != NULL) if (old_actor != NULL)
{ {
cev.crossing.type = CLUTTER_LEAVE; if (emit_crossing)
cev.crossing.time = device->current_time; {
cev.crossing.flags = 0; ClutterEvent *event;
cev.crossing.stage = device->stage;
cev.crossing.source = device->cursor_actor;
cev.crossing.x = device->current_x;
cev.crossing.y = device->current_y;
cev.crossing.device = device;
cev.crossing.related = actor;
/* we need to make sure that this event is processed before event = clutter_event_new (CLUTTER_LEAVE);
* any other event we might have queued up until now, so we event->crossing.time = device->current_time;
* go on and synthesize the event emission event->crossing.flags = 0;
event->crossing.stage = device->stage;
event->crossing.source = device->cursor_actor;
event->crossing.x = device->current_x;
event->crossing.y = device->current_y;
event->crossing.related = actor;
clutter_event_set_device (event, device);
/* 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
* ourselves
*/ */
_clutter_process_event (&cev); _clutter_process_event (event);
clutter_event_free (event);
}
/* processing the event might have destroyed the actor */ /* processing the event might have destroyed the actor */
if (device->cursor_actor != NULL) if (device->cursor_actor != NULL)
@ -547,54 +528,28 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
if (actor != NULL) if (actor != NULL)
{ {
cev.crossing.type = CLUTTER_ENTER; if (emit_crossing)
cev.crossing.time = device->current_time;
cev.crossing.flags = 0;
cev.crossing.stage = device->stage;
cev.crossing.x = device->current_x;
cev.crossing.y = device->current_y;
cev.crossing.device = device;
CLUTTER_NOTE (EVENT, "Device '%s' entering '%s' at %d, %d",
device->device_name,
clutter_actor_get_name (actor) != NULL
? clutter_actor_get_name (actor)
: G_OBJECT_TYPE_NAME (actor),
device->current_x,
device->current_y);
/* if there is an actor overlapping the Stage boundary and we
* don't do this check then we'll emit an ENTER event only on
* the actor instead of emitting it on the Stage *and* the
* actor
*/
if (old_actor == NULL && actor != CLUTTER_ACTOR (device->stage))
{ {
cev.crossing.source = CLUTTER_ACTOR (device->stage); ClutterEvent *event;
cev.crossing.related = NULL;
CLUTTER_NOTE (EVENT, "Adding Crossing[Enter] event for Stage"); event = clutter_event_new (CLUTTER_ENTER);
event->crossing.time = device->current_time;
event->crossing.flags = 0;
event->crossing.stage = device->stage;
event->crossing.x = device->current_x;
event->crossing.y = device->current_y;
event->crossing.source = actor;
event->crossing.related = old_actor;
clutter_event_set_device (event, device);
_clutter_process_event (&cev); /* see above */
_clutter_process_event (event);
cev.crossing.source = actor; clutter_event_free (event);
cev.crossing.related = CLUTTER_ACTOR (device->stage);
} }
else
{
cev.crossing.source = actor;
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) if (device->cursor_actor != NULL)
{ {
g_object_weak_ref (G_OBJECT (device->cursor_actor), g_object_weak_ref (G_OBJECT (device->cursor_actor),
@ -730,7 +685,8 @@ clutter_input_device_get_device_coords (ClutterInputDevice *device,
* Since: 1.2 * Since: 1.2
*/ */
ClutterActor * ClutterActor *
_clutter_input_device_update (ClutterInputDevice *device) _clutter_input_device_update (ClutterInputDevice *device,
gboolean emit_crossing)
{ {
ClutterStage *stage; ClutterStage *stage;
ClutterActor *new_cursor_actor; ClutterActor *new_cursor_actor;
@ -773,7 +729,7 @@ _clutter_input_device_update (ClutterInputDevice *device)
if (new_cursor_actor == old_cursor_actor) if (new_cursor_actor == old_cursor_actor)
return 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, emit_crossing);
return device->cursor_actor; return device->cursor_actor;
} }

View File

@ -2154,7 +2154,7 @@ emit_event (ClutterEvent *event,
/* reentrancy check */ /* reentrancy check */
if (lock != FALSE) if (lock != FALSE)
{ {
g_warning ("Tried emitting event during event delivery, bailing out.n"); g_warning ("Tried emitting event during event delivery, bailing out.");
return; return;
} }
@ -2248,10 +2248,14 @@ is_off_stage (ClutterActor *stage,
gfloat x, gfloat x,
gfloat y) gfloat y)
{ {
gfloat width, height;
clutter_actor_get_size (stage, &width, &height);
return (x < 0 || return (x < 0 ||
y < 0 || y < 0 ||
x >= clutter_actor_get_width (stage) || x >= width ||
y >= clutter_actor_get_height (stage)); y >= height);
} }
/** /**
@ -2293,18 +2297,6 @@ _clutter_process_event_details (ClutterActor *stage,
event->any.source = stage; event->any.source = stage;
break; break;
case CLUTTER_LEAVE:
case CLUTTER_ENTER:
emit_pointer_event (event, device);
break;
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_DELETE:
event->any.source = stage;
/* the stage did not handle the event, so we just quit */
clutter_stage_event (CLUTTER_STAGE (stage), event);
break;
case CLUTTER_KEY_PRESS: case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE: case CLUTTER_KEY_RELEASE:
{ {
@ -2326,6 +2318,65 @@ _clutter_process_event_details (ClutterActor *stage,
} }
break; break;
case CLUTTER_ENTER:
/* if we're entering from outside the stage we need
* to check whether the pointer is actually on another
* actor, and emit an additional pointer event
*/
if (event->any.source == stage &&
event->crossing.related == NULL)
{
ClutterActor *actor = NULL;
emit_pointer_event (event, device);
actor = _clutter_input_device_update (device, FALSE);
if (actor != stage)
{
ClutterEvent *crossing;
/* we emit the exact same event on the actor */
crossing = clutter_event_copy (event);
crossing->crossing.related = stage;
crossing->crossing.source = actor;
emit_pointer_event (crossing, device);
clutter_event_free (crossing);
}
}
else
emit_pointer_event (event, device);
break;
case CLUTTER_LEAVE:
/* same as CLUTTER_ENTER above: when leaving the stage
* we need to also emit a CLUTTER_LEAVE event on the
* actor currently underneath the device, unless it's the
* stage
*/
if (event->any.source == stage &&
event->crossing.related == NULL &&
device->cursor_actor != stage)
{
ClutterEvent *crossing;
crossing = clutter_event_copy (event);
crossing->crossing.related = stage;
crossing->crossing.source = device->cursor_actor;
emit_pointer_event (crossing, device);
clutter_event_free (crossing);
}
emit_pointer_event (event, device);
break;
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_DELETE:
event->any.source = stage;
/* the stage did not handle the event, so we just quit */
clutter_stage_event (CLUTTER_STAGE (stage), event);
break;
case CLUTTER_MOTION: case CLUTTER_MOTION:
/* 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.
@ -2413,7 +2464,7 @@ _clutter_process_event_details (ClutterActor *stage,
* get the actor underneath * get the actor underneath
*/ */
if (device != NULL) if (device != NULL)
actor = _clutter_input_device_update (device); actor = _clutter_input_device_update (device, TRUE);
else else
{ {
CLUTTER_NOTE (EVENT, "No device found: picking"); CLUTTER_NOTE (EVENT, "No device found: picking");
@ -2434,11 +2485,6 @@ _clutter_process_event_details (ClutterActor *stage,
actor = event->any.source; actor = event->any.source;
} }
/* FIXME: for an optimisation should check if there are
* actually any reactive actors and avoid the pick all together
* (signalling just the stage). Should be big help for gles.
*/
CLUTTER_NOTE (EVENT, CLUTTER_NOTE (EVENT,
"Reactive event received at %.2f, %.2f - actor: %p", "Reactive event received at %.2f, %.2f - actor: %p",
x, y, x, y,
@ -2507,7 +2553,7 @@ _clutter_process_event (ClutterEvent *event)
* *
* Since: 0.6 * Since: 0.6
*/ */
ClutterActor* ClutterActor *
clutter_get_actor_by_gid (guint32 id) clutter_get_actor_by_gid (guint32 id)
{ {
ClutterMainContext *context; ClutterMainContext *context;

View File

@ -24,6 +24,7 @@
#include <clutter/clutter-stage-window.h> #include <clutter/clutter-stage-window.h>
#include <clutter/clutter-stage.h> #include <clutter/clutter-stage.h>
#include <clutter/clutter-input-device.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -82,6 +83,13 @@ ClutterStageQueueRedrawEntry *_clutter_stage_queue_actor_redraw (Clut
ClutterPaintVolume *clip); ClutterPaintVolume *clip);
void _clutter_stage_queue_redraw_entry_invalidate (ClutterStageQueueRedrawEntry *entry); void _clutter_stage_queue_redraw_entry_invalidate (ClutterStageQueueRedrawEntry *entry);
void _clutter_stage_add_device (ClutterStage *stage,
ClutterInputDevice *device);
void _clutter_stage_remove_device (ClutterStage *stage,
ClutterInputDevice *device);
gboolean _clutter_stage_has_device (ClutterStage *stage,
ClutterInputDevice *device);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */ #endif /* __CLUTTER_STAGE_PRIVATE_H__ */

View File

@ -135,6 +135,8 @@ struct _ClutterStagePrivate
ClutterPickMode pick_buffer_mode; ClutterPickMode pick_buffer_mode;
GHashTable *devices;
guint relayout_pending : 1; guint relayout_pending : 1;
guint redraw_pending : 1; guint redraw_pending : 1;
guint is_fullscreen : 1; guint is_fullscreen : 1;
@ -1202,10 +1204,13 @@ clutter_stage_finalize (GObject *object)
g_queue_foreach (priv->event_queue, (GFunc)clutter_event_free, NULL); g_queue_foreach (priv->event_queue, (GFunc)clutter_event_free, NULL);
g_queue_free (priv->event_queue); g_queue_free (priv->event_queue);
g_free (stage->priv->title); g_free (priv->title);
g_array_free (priv->paint_volume_stack, TRUE); g_array_free (priv->paint_volume_stack, TRUE);
if (priv->devices != NULL)
g_hash_table_destroy (priv->devices);
G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object); G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
} }
@ -3375,3 +3380,44 @@ clutter_stage_get_accept_focus (ClutterStage *stage)
return stage->priv->accept_focus; return stage->priv->accept_focus;
} }
void
_clutter_stage_add_device (ClutterStage *stage,
ClutterInputDevice *device)
{
ClutterStagePrivate *priv = stage->priv;
if (G_UNLIKELY (priv->devices == NULL))
priv->devices = g_hash_table_new (NULL, NULL);
if (g_hash_table_lookup (priv->devices, device) != NULL)
return;
g_hash_table_insert (priv->devices, device, GINT_TO_POINTER (1));
_clutter_input_device_set_stage (device, stage);
}
void
_clutter_stage_remove_device (ClutterStage *stage,
ClutterInputDevice *device)
{
ClutterStagePrivate *priv = stage->priv;
if (G_UNLIKELY (priv->devices == NULL))
return;
_clutter_input_device_set_stage (device, NULL);
g_hash_table_remove (priv->devices, device);
}
gboolean
_clutter_stage_has_device (ClutterStage *stage,
ClutterInputDevice *device)
{
ClutterStagePrivate *priv = stage->priv;
if (priv->devices == NULL)
return FALSE;
return g_hash_table_lookup (priv->devices, device) != NULL;
}

View File

@ -548,6 +548,7 @@ clutter_win32_handle_event (const MSG *msg)
we're not already */ we're not already */
if (!stage_win32->tracking_mouse) if (!stage_win32->tracking_mouse)
{ {
ClutterEvent *crossing = clutter_event_new (CLUTTER_ENTER);
TRACKMOUSEEVENT tmevent; TRACKMOUSEEVENT tmevent;
tmevent.cbSize = sizeof (tmevent); tmevent.cbSize = sizeof (tmevent);
@ -555,8 +556,18 @@ clutter_win32_handle_event (const MSG *msg)
tmevent.hwndTrack = stage_win32->hwnd; tmevent.hwndTrack = stage_win32->hwnd;
TrackMouseEvent (&tmevent); TrackMouseEvent (&tmevent);
event->crossing.time = msg->time;
event->crossing.x = event->motion.x;
event->crossing.y = event->motion.y;
event->crossing.device = event->motion.device;
event->crossing.stage = stage;
event->crossing.source = CLUTTER_ACTOR (stage);
event->crossing.related = NULL;
/* we entered the stage */ /* we entered the stage */
_clutter_input_device_set_stage (event->motion.device, stage); _clutter_stage_add_device (stage, event->crossing.device);
take_and_queue_event (crossing);
stage_win32->tracking_mouse = TRUE; stage_win32->tracking_mouse = TRUE;
} }
@ -573,10 +584,12 @@ clutter_win32_handle_event (const MSG *msg)
event->crossing.x = msg->pt.x; event->crossing.x = msg->pt.x;
event->crossing.y = msg->pt.y; event->crossing.y = msg->pt.y;
event->crossing.device = core_pointer; event->crossing.device = core_pointer;
event->any.stage = stage; event->crossing.stage = stage;
event->crossing.source = CLUTTER_ACTOR (stage);
event->crossing.related = NULL;
/* we left the stage */ /* we left the stage */
_clutter_input_device_set_stage (event->crossing.device, NULL); _clutter_stage_remove_device (stage, event->crossing.device);
/* When we get a leave message the mouse tracking is /* When we get a leave message the mouse tracking is
automatically cancelled so we'll need to start it again when automatically cancelled so we'll need to start it again when

View File

@ -220,7 +220,8 @@ translate_key_event (ClutterBackendX11 *backend_x11,
event->key.type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS event->key.type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS
: CLUTTER_KEY_RELEASE; : CLUTTER_KEY_RELEASE;
event->key.time = xevent->xkey.time; event->key.time = xevent->xkey.time;
event->key.device = manager_x11->core_keyboard;
clutter_event_set_device (event, manager_x11->core_keyboard);
/* KeyEvents have platform specific data associated to them */ /* KeyEvents have platform specific data associated to them */
event_x11 = _clutter_event_x11_new (); event_x11 = _clutter_event_x11_new ();
@ -406,7 +407,7 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator,
event->scroll.x = xevent->xbutton.x; event->scroll.x = xevent->xbutton.x;
event->scroll.y = xevent->xbutton.y; event->scroll.y = xevent->xbutton.y;
event->scroll.modifier_state = xevent->xbutton.state; event->scroll.modifier_state = xevent->xbutton.state;
event->scroll.device = manager_x11->core_pointer; event->scroll.axes = NULL;
break; break;
default: default:
@ -416,11 +417,12 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator,
event->button.y = xevent->xbutton.y; event->button.y = xevent->xbutton.y;
event->button.modifier_state = xevent->xbutton.state; event->button.modifier_state = xevent->xbutton.state;
event->button.button = xevent->xbutton.button; event->button.button = xevent->xbutton.button;
event->button.device = manager_x11->core_pointer;
event->button.axes = NULL; event->button.axes = NULL;
break; break;
} }
clutter_event_set_device (event, manager_x11->core_pointer);
_clutter_stage_x11_set_user_time (stage_x11, xevent->xbutton.time); _clutter_stage_x11_set_user_time (stage_x11, xevent->xbutton.time);
res = CLUTTER_TRANSLATE_QUEUE; res = CLUTTER_TRANSLATE_QUEUE;
break; break;
@ -450,7 +452,7 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator,
event->button.modifier_state = xevent->xbutton.state; event->button.modifier_state = xevent->xbutton.state;
event->button.button = xevent->xbutton.button; event->button.button = xevent->xbutton.button;
event->button.axes = NULL; event->button.axes = NULL;
event->button.device = manager_x11->core_pointer; clutter_event_set_device (event, manager_x11->core_pointer);
res = CLUTTER_TRANSLATE_QUEUE; res = CLUTTER_TRANSLATE_QUEUE;
break; break;
@ -466,25 +468,25 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator,
event->motion.x = xevent->xmotion.x; event->motion.x = xevent->xmotion.x;
event->motion.y = xevent->xmotion.y; event->motion.y = xevent->xmotion.y;
event->motion.modifier_state = xevent->xmotion.state; event->motion.modifier_state = xevent->xmotion.state;
event->motion.device = manager_x11->core_pointer;
event->motion.axes = NULL; event->motion.axes = NULL;
clutter_event_set_device (event, manager_x11->core_pointer);
res = CLUTTER_TRANSLATE_QUEUE; res = CLUTTER_TRANSLATE_QUEUE;
break; break;
case EnterNotify: case EnterNotify:
/* we know that we are entering the stage here */ CLUTTER_NOTE (EVENT, "Entering the stage (time:%u)",
_clutter_input_device_set_stage (manager_x11->core_pointer, stage); (unsigned int) xevent->xcrossing.time);
CLUTTER_NOTE (EVENT, "Entering the stage");
event->crossing.type = CLUTTER_ENTER;
event->crossing.time = xevent->xcrossing.time;
event->crossing.x = xevent->xcrossing.x;
event->crossing.y = xevent->xcrossing.y;
event->crossing.source = CLUTTER_ACTOR (stage);
event->crossing.related = NULL;
clutter_event_set_device (event, manager_x11->core_pointer);
_clutter_stage_add_device (stage, manager_x11->core_pointer);
/* Convert enter notifies to motion events because X
doesn't emit the corresponding motion notify */
event->motion.type = event->type = CLUTTER_MOTION;
event->motion.time = xevent->xcrossing.time;
event->motion.x = xevent->xcrossing.x;
event->motion.y = xevent->xcrossing.y;
event->motion.modifier_state = xevent->xcrossing.state;
event->motion.source = CLUTTER_ACTOR (stage);
event->motion.device = manager_x11->core_pointer;
res = CLUTTER_TRANSLATE_QUEUE; res = CLUTTER_TRANSLATE_QUEUE;
break; break;
@ -498,16 +500,19 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator,
} }
/* we know that we are leaving the stage here */ /* we know that we are leaving the stage here */
_clutter_input_device_set_stage (manager_x11->core_pointer, NULL);
CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)", CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)",
event->crossing.time); (unsigned int) xevent->xcrossing.time);
event->crossing.type = CLUTTER_LEAVE; event->crossing.type = CLUTTER_LEAVE;
event->crossing.time = xevent->xcrossing.time; event->crossing.time = xevent->xcrossing.time;
event->crossing.x = xevent->xcrossing.x; event->crossing.x = xevent->xcrossing.x;
event->crossing.y = xevent->xcrossing.y; event->crossing.y = xevent->xcrossing.y;
event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.source = CLUTTER_ACTOR (stage);
event->crossing.device = manager_x11->core_pointer; event->crossing.related = NULL;
clutter_event_set_device (event, manager_x11->core_pointer);
_clutter_stage_remove_device (stage, manager_x11->core_pointer);
res = CLUTTER_TRANSLATE_QUEUE; res = CLUTTER_TRANSLATE_QUEUE;
break; break;

View File

@ -847,22 +847,22 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
device = g_hash_table_lookup (manager_xi2->devices_by_id, device = g_hash_table_lookup (manager_xi2->devices_by_id,
GINT_TO_POINTER (xev->deviceid)); GINT_TO_POINTER (xev->deviceid));
source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
GINT_TO_POINTER (xev->sourceid));
if (xi_event->evtype == XI_Enter) if (xi_event->evtype == XI_Enter)
{ {
_clutter_input_device_set_stage (device, stage); event->crossing.type = event->type = CLUTTER_ENTER;
event->motion.type = event->type = CLUTTER_MOTION; event->crossing.stage = stage;
event->crossing.source = CLUTTER_ACTOR (stage);
event->crossing.related = NULL;
event->motion.stage = stage; event->crossing.time = xev->time;
event->motion.source = CLUTTER_ACTOR (stage); event->crossing.x = xev->event_x;
event->crossing.y = xev->event_y;
event->motion.time = xev->time; _clutter_stage_add_device (stage, device);
event->motion.x = xev->event_x;
event->motion.y = xev->event_y;
event->motion.device = device;
event->motion.modifier_state =
_clutter_input_device_xi2_translate_state (&xev->mods,
&xev->buttons);
} }
else else
{ {
@ -876,18 +876,22 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
break; break;
} }
_clutter_input_device_set_stage (device, NULL);
event->crossing.type = event->type = CLUTTER_LEAVE; event->crossing.type = event->type = CLUTTER_LEAVE;
event->crossing.stage = stage;
event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.source = CLUTTER_ACTOR (stage);
event->crossing.related = NULL;
event->crossing.time = xev->time; event->crossing.time = xev->time;
event->crossing.x = xev->event_x; event->crossing.x = xev->event_x;
event->crossing.y = xev->event_y; event->crossing.y = xev->event_y;
event->crossing.device = device;
_clutter_stage_remove_device (stage, device);
} }
clutter_event_set_device (event, device);
_clutter_event_set_source_device (event, source_device);
retval = CLUTTER_TRANSLATE_QUEUE; retval = CLUTTER_TRANSLATE_QUEUE;
} }
break; break;