Emit CLUTTER_LEAVE events when the pointer leaves the stage
Bug 1178 - No enter / leave events on actors when pointer leaves the stage window The patch is mostly thanks to Johan Bilien with small modifications based on suggestions by Owen Taylor. The X11 backend now listens for enter and leave notifications. Leave notifications get translated directly to a CLUTTER_LEAVE event. Clutter can detect these special events because the source actor is NULL in which case it sets the source actor to the last known actor and then sets the last known actor to NULL. Enter notifications just get translated to CLUTTER_MOTION events which will cause Clutter to generate an enter event through the usual code path.
This commit is contained in:
parent
0c7e4172ab
commit
5d6a11e1bf
4 changed files with 70 additions and 20 deletions
|
@ -1853,6 +1853,37 @@ clutter_event_get_device (ClutterEvent *event)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_motion_last_actor (ClutterActor *motion_current_actor,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
ClutterMainContext *context = ClutterCntx;
|
||||
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)
|
||||
{
|
||||
|
@ -1905,25 +1936,7 @@ generate_enter_leave_events (ClutterEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
set_motion_last_actor (motion_current_actor, event->motion.device);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1965,8 +1978,23 @@ clutter_do_event (ClutterEvent *event)
|
|||
event->any.source = stage;
|
||||
break;
|
||||
|
||||
case CLUTTER_ENTER:
|
||||
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:
|
||||
emit_pointer_event (event, event->crossing.device);
|
||||
break;
|
||||
|
||||
|
|
|
@ -185,6 +185,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
|
|||
StructureNotifyMask |
|
||||
FocusChangeMask |
|
||||
ExposureMask |
|
||||
EnterWindowMask | LeaveWindowMask |
|
||||
PropertyChangeMask);
|
||||
#ifdef USE_XINPUT
|
||||
_clutter_x11_select_events (stage_x11->xwin);
|
||||
|
@ -198,6 +199,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
|
|||
PointerMotionMask |
|
||||
KeyPressMask | KeyReleaseMask |
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
EnterWindowMask | LeaveWindowMask |
|
||||
PropertyChangeMask);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
|||
FocusChangeMask |
|
||||
ExposureMask |
|
||||
KeyPressMask | KeyReleaseMask |
|
||||
EnterWindowMask | LeaveWindowMask |
|
||||
PropertyChangeMask);
|
||||
#ifdef USE_XINPUT
|
||||
_clutter_x11_select_events (stage_x11->xwin);
|
||||
|
@ -202,6 +203,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
|||
PointerMotionMask |
|
||||
KeyPressMask | KeyReleaseMask |
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
EnterWindowMask | LeaveWindowMask |
|
||||
PropertyChangeMask);
|
||||
}
|
||||
|
||||
|
|
|
@ -666,6 +666,24 @@ event_translate (ClutterBackend *backend,
|
|||
event->motion.y = xevent->xmotion.y;
|
||||
event->motion.modifier_state = xevent->xmotion.state;
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
/* 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;
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
event->crossing.type = event->type = CLUTTER_LEAVE;
|
||||
event->crossing.time = xevent->xcrossing.time;
|
||||
event->crossing.x = xevent->xcrossing.x;
|
||||
event->crossing.y = xevent->xcrossing.y;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore every other event */
|
||||
res = FALSE;
|
||||
|
|
Loading…
Reference in a new issue