From 9506510d1cf794ef530f6c4db45103efb60cca63 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 8 Jan 2010 17:51:00 +0000 Subject: [PATCH] Move all picking-related operations inside InputDevice The InputDevice objects stores pointer coordinates, state, stage and the actor under the cursor, so if the current backend provides us with one attached to the Event structure then we want the InputDevice itself to update its state and give us the ClutterActor underneath the pointer's cursor. --- clutter/clutter-device-manager.c | 24 +++++++++ clutter/clutter-event.c | 36 ------------- clutter/clutter-input-device.c | 91 ++++++++++++++++++++++++++++++-- clutter/clutter-input-device.h | 7 ++- clutter/clutter-main.c | 60 ++++++++++++--------- clutter/clutter-master-clock.c | 7 ++- clutter/clutter-private.h | 36 ++++++++----- clutter/clutter-stage.c | 28 ++++++++-- clutter/x11/clutter-event-x11.c | 36 ++++++++----- 9 files changed, 225 insertions(+), 100 deletions(-) diff --git a/clutter/clutter-device-manager.c b/clutter/clutter-device-manager.c index bfed42fb8..8b4a5b8a5 100644 --- a/clutter/clutter-device-manager.c +++ b/clutter/clutter-device-manager.c @@ -144,3 +144,27 @@ _clutter_device_manager_remove_device (ClutterDeviceManager *device_manager, device_manager->devices = g_slist_remove (device_manager->devices, device); } + +void +_clutter_device_manager_update_devices (ClutterDeviceManager *device_manager) +{ + GSList *d; + + /* perform a pick() on the stage at the coordinates of every + * input device, and store the actor currently under the pointer + */ + for (d = device_manager->devices; d != NULL; d = d->next) + { + ClutterInputDevice *device = d->data; + ClutterInputDeviceType device_type; + + device_type = clutter_input_device_get_device_type (device); + if (device_type != CLUTTER_POINTER_DEVICE) + continue; + + if (device->stage == NULL) + continue; + + _clutter_input_device_update (device); + } +} diff --git a/clutter/clutter-event.c b/clutter/clutter-event.c index 2f9cf178a..2492a25a3 100644 --- a/clutter/clutter-event.c +++ b/clutter/clutter-event.c @@ -787,39 +787,3 @@ clutter_get_current_event (void) return context->current_event; } - -/** - * clutter_input_device_get_device_type: - * @device: a #ClutterInputDevice - * - * Retrieves the type of @device - * - * Return value: the type of the device - * - * Since: 1.0 - */ -ClutterInputDeviceType -clutter_input_device_get_device_type (ClutterInputDevice *device) -{ - g_return_val_if_fail (device != NULL, CLUTTER_POINTER_DEVICE); - - return device->device_type; -} - -/** - * clutter_input_device_get_device_id: - * @device: a #ClutterInputDevice - * - * Retrieves the unique identifier of @device - * - * Return value: the identifier of the device - * - * Since: 1.0 - */ -gint -clutter_input_device_get_device_id (ClutterInputDevice *device) -{ - g_return_val_if_fail (device != NULL, -1); - - return device->id; -} diff --git a/clutter/clutter-input-device.c b/clutter/clutter-input-device.c index dae5e92e2..d2a298394 100644 --- a/clutter/clutter-input-device.c +++ b/clutter/clutter-input-device.c @@ -110,13 +110,13 @@ clutter_input_device_init (ClutterInputDevice *self) void _clutter_input_device_set_coords (ClutterInputDevice *device, - gfloat x, - gfloat y) + gint x, + gint y) { g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - device->previous_x = floorf (x) + 0.5; - device->previous_y = floorf (y) + 0.5; + device->previous_x = x; + device->previous_y = y; } void @@ -137,6 +137,45 @@ _clutter_input_device_set_time (ClutterInputDevice *device, device->previous_time = time_; } +void +_clutter_input_device_set_stage (ClutterInputDevice *device, + ClutterStage *stage) +{ + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + + device->stage = stage; +} + +static void +cursor_weak_unref (gpointer user_data, + GObject *object_pointer) +{ + ClutterInputDevice *device = user_data; + + device->cursor_actor = NULL; +} + +void +_clutter_input_device_set_actor (ClutterInputDevice *device, + ClutterActor *actor) +{ + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + + if (device->cursor_actor != NULL) + { + _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 = actor; + g_object_weak_ref (G_OBJECT (device->cursor_actor), + cursor_weak_unref, + device); + _clutter_actor_set_has_pointer (device->cursor_actor, TRUE); +} + /** * clutter_input_device_get_device_type: * @device: a #ClutterInputDevice @@ -173,3 +212,47 @@ clutter_input_device_get_device_id (ClutterInputDevice *device) return device->id; } + +void +clutter_input_device_get_device_coords (ClutterInputDevice *device, + gint *x, + gint *y) +{ + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + + if (x) + *x = device->previous_x; + + if (y) + *y = device->previous_y; +} + +ClutterActor * +_clutter_input_device_update (ClutterInputDevice *device) +{ + ClutterStage *stage; + ClutterActor *new_cursor_actor; + ClutterActor *old_cursor_actor; + gint x, y; + + clutter_input_device_get_device_coords (device, &x, &y); + + stage = device->stage; + old_cursor_actor = device->cursor_actor; + new_cursor_actor = _clutter_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE); + + if (new_cursor_actor == NULL) + new_cursor_actor = CLUTTER_ACTOR (stage); + + CLUTTER_NOTE (EVENT, + "Actor under cursor (device %d, at %d, %d): %s", + clutter_input_device_get_device_id (device), + x, y, + clutter_actor_get_name (new_cursor_actor) != NULL + ? clutter_actor_get_name (new_cursor_actor) + : G_OBJECT_TYPE_NAME (new_cursor_actor)); + + _clutter_input_device_set_actor (device, new_cursor_actor); + + return device->cursor_actor; +} diff --git a/clutter/clutter-input-device.h b/clutter/clutter-input-device.h index 1d36278bc..3d372bcf6 100644 --- a/clutter/clutter-input-device.h +++ b/clutter/clutter-input-device.h @@ -56,8 +56,11 @@ struct _ClutterInputDeviceClass GType clutter_input_device_get_type (void) G_GNUC_CONST; -ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device); -gint clutter_input_device_get_device_id (ClutterInputDevice *device); +ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device); +gint clutter_input_device_get_device_id (ClutterInputDevice *device); +void clutter_input_device_get_device_coords (ClutterInputDevice *device, + gint *x, + gint *y); G_END_DECLS diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index d0438bbf2..c177d3a0d 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -2118,7 +2118,7 @@ emit_event (ClutterEvent *event, ClutterActor *actor; gint i = 0; - if (!event->any.source) + if (event->any.source == NULL) { CLUTTER_NOTE (EVENT, "No source set, discarding event"); return; @@ -2445,6 +2445,24 @@ _clutter_process_event_details (ClutterActor *stage, 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 * (as it could be in a synthetic event) */ @@ -2467,13 +2485,24 @@ _clutter_process_event_details (ClutterActor *stage, break; } - /* Map the event to a reactive actor */ - actor = _clutter_do_pick (CLUTTER_STAGE (stage), - x, y, - CLUTTER_PICK_REACTIVE); + /* if the backend provides a device then we should + * already have everything we need to update it and + * get the actor underneath + */ + if (device == NULL) + { + CLUTTER_NOTE (EVENT, "No device found: picking"); + + /* Map the event to a reactive actor */ + actor = _clutter_do_pick (CLUTTER_STAGE (stage), + x, y, + CLUTTER_PICK_REACTIVE); + } + else + actor = _clutter_input_device_update (device); event->any.source = actor; - if (!actor) + if (actor == NULL) break; } else @@ -2482,7 +2511,6 @@ _clutter_process_event_details (ClutterActor *stage, 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. @@ -2502,24 +2530,6 @@ _clutter_process_event_details (ClutterActor *stage, event_click_count_generate (event); } - 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; - } - } - emit_pointer_event (event, device); break; } diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index b61ad436c..2f59dbff3 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -288,14 +288,13 @@ clutter_clock_dispatch (GSource *source, * event handling */ stages = clutter_stage_manager_list_stages (stage_manager); - g_slist_foreach (stages, (GFunc)g_object_ref, NULL); + g_slist_foreach (stages, (GFunc) g_object_ref, NULL); CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process); master_clock->updated_stages = FALSE; - /* Process queued events - */ + /* Process queued events */ for (l = stages; l != NULL; l = l->next) _clutter_stage_process_queued_events (l->data); @@ -311,7 +310,7 @@ clutter_clock_dispatch (GSource *source, for (l = stages; l != NULL; l = l->next) master_clock->updated_stages |= _clutter_stage_do_update (l->data); - g_slist_foreach (stages, (GFunc)g_object_unref, NULL); + g_slist_foreach (stages, (GFunc) g_object_unref, NULL); g_slist_free (stages); master_clock->prev_tick = master_clock->cur_tick; diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 2a4b4eb3c..dbbc96f83 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -91,13 +91,16 @@ struct _ClutterInputDevice ClutterInputDeviceType device_type; + ClutterActor *cursor_actor; + ClutterActor *pointer_grab_actor; ClutterActor *motion_last_actor; gint click_count; - gfloat previous_x; - gfloat previous_y; + ClutterStage *stage; + gint previous_x; + gint previous_y; guint32 previous_time; gint previous_button_number; ClutterModifierType previous_state; @@ -189,19 +192,25 @@ PangoContext *_clutter_context_get_pango_context (ClutterMainContext *self); #define I_(str) (g_intern_static_string ((str))) /* device manager */ -void _clutter_device_manager_add_device (ClutterDeviceManager *device_manager, - ClutterInputDevice *device); -void _clutter_device_manager_remove_device (ClutterDeviceManager *device_manager, - ClutterInputDevice *device); +void _clutter_device_manager_add_device (ClutterDeviceManager *device_manager, + ClutterInputDevice *device); +void _clutter_device_manager_remove_device (ClutterDeviceManager *device_manager, + ClutterInputDevice *device); +void _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager); /* input device */ -void _clutter_input_device_set_coords (ClutterInputDevice *device, - gfloat x, - gfloat y); -void _clutter_input_device_set_state (ClutterInputDevice *device, - ClutterModifierType state); -void _clutter_input_device_set_time (ClutterInputDevice *device, - guint32 time_); +void _clutter_input_device_set_coords (ClutterInputDevice *device, + gint x, + gint y); +void _clutter_input_device_set_state (ClutterInputDevice *device, + ClutterModifierType state); +void _clutter_input_device_set_time (ClutterInputDevice *device, + guint32 time_); +void _clutter_input_device_set_stage (ClutterInputDevice *device, + ClutterStage *stage); +void _clutter_input_device_set_actor (ClutterInputDevice *device, + ClutterActor *actor); +ClutterActor *_clutter_input_device_update (ClutterInputDevice *device); /* stage manager */ void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager, @@ -223,6 +232,7 @@ void _clutter_stage_queue_event (ClutterStage *stage, ClutterEvent *event); gboolean _clutter_stage_has_queued_events (ClutterStage *stage); void _clutter_stage_process_queued_events (ClutterStage *stage); +void _clutter_stage_update_input_devices (ClutterStage *stage); /* vfuncs implemented by backend */ GType _clutter_backend_impl_get_type (void); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 518d181c7..4d3d13774 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -69,6 +69,7 @@ #include "clutter-id-pool.h" #include "clutter-container.h" #include "clutter-profile.h" +#include "clutter-input-device.h" #include "cogl/cogl.h" @@ -454,6 +455,7 @@ _clutter_stage_queue_event (ClutterStage *stage, { ClutterStagePrivate *priv; gboolean first_event; + ClutterInputDevice *device; g_return_if_fail (CLUTTER_IS_STAGE (stage)); @@ -461,14 +463,32 @@ _clutter_stage_queue_event (ClutterStage *stage, first_event = priv->event_queue->length == 0; - g_queue_push_tail (priv->event_queue, - clutter_event_copy (event)); + g_queue_push_tail (priv->event_queue, clutter_event_copy (event)); if (first_event) { ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_start_running (master_clock); } + + /* if needed, update the state of the input device of the event. + * we do it here to avoid calling the same code from every backend + * event processing function + */ + device = clutter_event_get_device (event); + if (device != NULL) + { + ClutterModifierType event_state = clutter_event_get_state (event); + guint32 event_time = clutter_event_get_time (event); + gfloat event_x, event_y; + + clutter_event_get_coords (event, &event_x, &event_y); + + _clutter_input_device_set_coords (device, event_x, event_y); + _clutter_input_device_set_state (device, event_state); + _clutter_input_device_set_time (device, event_time); + _clutter_input_device_set_stage (device, stage); + } } gboolean @@ -487,7 +507,7 @@ void _clutter_stage_process_queued_events (ClutterStage *stage) { ClutterStagePrivate *priv; - GList *events, *l;; + GList *events, *l; g_return_if_fail (CLUTTER_IS_STAGE (stage)); @@ -506,7 +526,7 @@ _clutter_stage_process_queued_events (ClutterStage *stage) priv->event_queue->tail = NULL; priv->event_queue->length = 0; - for (l = events; l; l = l->next) + for (l = events; l != NULL; l = l->next) { ClutterEvent *event; ClutterEvent *next_event; diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index af85238d7..a87a6313d 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -624,9 +624,10 @@ event_translate (ClutterBackend *backend, case KeyPress: event->key.type = event->type = CLUTTER_KEY_PRESS; + translate_key_event (backend, event, xevent); + /* default key device if no XInput support is defined */ event->key.device = clutter_device_manager_get_device (manager, 1); - translate_key_event (backend, event, xevent); set_user_time (backend_x11, &xwindow, xevent->xkey.time); break; @@ -659,9 +660,10 @@ event_translate (ClutterBackend *backend, } event->key.type = event->type = CLUTTER_KEY_RELEASE; + translate_key_event (backend, event, xevent); + /* default key device if no XInput support is defined */ event->key.device = clutter_device_manager_get_device (manager, 1); - translate_key_event (backend, event, xevent); break; default: @@ -763,6 +765,10 @@ event_translate (ClutterBackend *backend, event->motion.modifier_state = xevent->xcrossing.state; event->motion.device = clutter_device_manager_get_device (manager, 0); + + /* we know that we are entering the stage here */ + _clutter_input_device_set_stage (event->motion.device, stage); + CLUTTER_NOTE (EVENT, "Entering the stage"); break; case LeaveNotify: @@ -770,8 +776,12 @@ event_translate (ClutterBackend *backend, event->crossing.time = xevent->xcrossing.time; event->crossing.x = xevent->xcrossing.x; event->crossing.y = xevent->xcrossing.y; - event->motion.device = + event->crossing.device = clutter_device_manager_get_device (manager, 0); + + /* we know that we are leaving the stage here */ + _clutter_input_device_set_stage (event->crossing.device, NULL); + CLUTTER_NOTE (EVENT, "Leaving the stage"); break; default: @@ -784,10 +794,16 @@ event_translate (ClutterBackend *backend, { /* XInput fun.. Needs clean up. */ #ifdef HAVE_XINPUT int *ev_types = backend_x11->event_types; + int button_press, button_release; + int motion_notify; + + button_press = ev_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT]; + button_release = ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT]; + motion_notify = ev_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT]; CLUTTER_NOTE (EVENT, "XInput event type: %d", xevent->type); - if (xevent->type == ev_types [CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT]) + if (xevent->type == button_press) { XDeviceButtonEvent *xbev = (XDeviceButtonEvent *) xevent; @@ -833,8 +849,7 @@ event_translate (ClutterBackend *backend, set_user_time (backend_x11, &xwindow, xbev->time); } - else if (xevent->type - == ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT]) + else if (xevent->type == button_release) { XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent; @@ -860,8 +875,7 @@ event_translate (ClutterBackend *backend, event->button.button = xbev->button; event->button.device = _clutter_x11_get_device_for_xid (xbev->deviceid); } - else if (xevent->type - == ev_types [CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT]) + else if (xevent->type == motion_notify) { XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent; @@ -883,8 +897,7 @@ event_translate (ClutterBackend *backend, * not generate events even when the window has focus */ - else if (xevent->type - == ev_types [CLUTTER_X11_XINPUT_KEY_PRESS_EVENT]) + else if (xevent->type == ev_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT]) { XEvent xevent_converted; XDeviceKeyEvent *xkev = (XDeviceKeyEvent *)xevent; @@ -896,8 +909,7 @@ event_translate (ClutterBackend *backend, set_user_time (backend_x11, &xwindow, xkev->time); } - else if (xevent->type - == ev_types [CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT]) + else if (xevent->type == ev_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT]) { XEvent xevent_converted; XDeviceKeyEvent *xkev = (XDeviceKeyEvent *)xevent;