From b6dd306998e626cbc86051dc1237894d515aa3dd Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 10 Oct 2011 16:45:20 +0100 Subject: [PATCH] Clean up grab implementation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The grab API is a relic of Clutter 0.6, and hasn't been through proper vetting in a *long* time — mostly due to the fact that we don't really like grabs, and point to the ::captured-event as a way to implement "soft grabs" in toolkits and applications. The implementation of full and device grabs uses weak references on actors instead of using the ::destroy signal, which is meant exactly for the case of releasing pointers to actors when they are disposed. The API naming scheme is also fairly broken, especially for device-related grabs. Finally, keyboard device grabs are just not implemented. We can, in one go, clean up this mess and deprecate a bunch of badly named API by introducing generic device grab/ungrab methods on ClutterInputDevice, and re-implement the current API on top of them. --- clutter/clutter-device-manager-private.h | 1 + clutter/clutter-input-device.h | 5 + clutter/clutter-main.c | 268 +++++++++++++++++++++++-------- clutter/clutter-main.h | 10 +- 4 files changed, 215 insertions(+), 69 deletions(-) diff --git a/clutter/clutter-device-manager-private.h b/clutter/clutter-device-manager-private.h index 223cdde..4ae5940 100644 --- a/clutter/clutter-device-manager-private.h +++ b/clutter/clutter-device-manager-private.h @@ -75,6 +75,7 @@ struct _ClutterInputDevice /* the actor that has a grab in place for the device */ ClutterActor *pointer_grab_actor; + ClutterActor *keyboard_grab_actor; /* the current click count */ gint click_count; diff --git a/clutter/clutter-input-device.h b/clutter/clutter-input-device.h index 7b3a75b..0128920 100644 --- a/clutter/clutter-input-device.h +++ b/clutter/clutter-input-device.h @@ -167,6 +167,11 @@ void clutter_input_device_update_from_event (ClutterInputDev ClutterEvent *event, gboolean update_stage); +void clutter_input_device_grab (ClutterInputDevice *device, + ClutterActor *actor); +void clutter_input_device_ungrab (ClutterInputDevice *device); +ClutterActor * clutter_input_device_get_grabbed_actor (ClutterInputDevice *device); + G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_H__ */ diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 7ef9edb..f6f5806 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -2007,14 +2007,27 @@ emit_pointer_event (ClutterEvent *event, } static inline void -emit_keyboard_event (ClutterEvent *event) +emit_keyboard_event (ClutterEvent *event, + ClutterInputDevice *device) { ClutterMainContext *context = _clutter_context_get_default (); - if (context->keyboard_grab_actor == NULL) - emit_event (event, TRUE); + if (context->keyboard_grab_actor == NULL && + (device == NULL || device->keyboard_grab_actor == NULL)) + { + emit_event (event, FALSE); + } else - clutter_actor_event (context->keyboard_grab_actor, event, FALSE); + { + if (context->keyboard_grab_actor != NULL) + { + clutter_actor_event (context->keyboard_grab_actor, event, FALSE); + } + else if (device != NULL && device->keyboard_grab_actor != NULL) + { + clutter_actor_event (context->keyboard_grab_actor, event, FALSE); + } + } } static gboolean @@ -2102,7 +2115,7 @@ _clutter_process_event_details (ClutterActor *stage, } } - emit_keyboard_event (event); + emit_keyboard_event (event, device); } break; @@ -2411,23 +2424,34 @@ clutter_set_default_frame_rate (guint frames_per_sec) static void -on_pointer_grab_weak_notify (gpointer data, - GObject *where_the_object_was) +on_grab_actor_destroy (ClutterActor *actor, + ClutterInputDevice *device) { - ClutterInputDevice *dev = (ClutterInputDevice *)data; - ClutterMainContext *context; + if (device == NULL) + { + ClutterMainContext *context = _clutter_context_get_default (); - context = _clutter_context_get_default (); + if (context->pointer_grab_actor == actor) + clutter_ungrab_pointer (); - if (dev) - { - dev->pointer_grab_actor = NULL; - clutter_ungrab_pointer_for_device (dev->id); + if (context->keyboard_grab_actor == actor) + clutter_ungrab_keyboard (); + + return; } - else + + switch (device->device_type) { - context->pointer_grab_actor = NULL; - clutter_ungrab_pointer (); + case CLUTTER_POINTER_DEVICE: + device->pointer_grab_actor = NULL; + break; + + case CLUTTER_KEYBOARD_DEVICE: + device->keyboard_grab_actor = NULL; + break; + + default: + g_assert_not_reached (); } } @@ -2446,8 +2470,10 @@ on_pointer_grab_weak_notify (gpointer data, * using the #ClutterActor::captured-event signal should always be the * preferred way to intercept event delivery to reactive actors. * - * If you wish to grab all the pointer events for a specific input device, - * you should use clutter_grab_pointer_for_device(). + * This function should rarely be used. + * + * If a grab is required, you are strongly encouraged to use a specific + * input device by calling clutter_input_device_grab(). * * Since: 0.6 */ @@ -2463,22 +2489,150 @@ clutter_grab_pointer (ClutterActor *actor) if (context->pointer_grab_actor == actor) return; - if (context->pointer_grab_actor) + if (context->pointer_grab_actor != NULL) { - g_object_weak_unref (G_OBJECT (context->pointer_grab_actor), - on_pointer_grab_weak_notify, - NULL); + g_signal_handlers_disconnect_by_func (context->pointer_grab_actor, + G_CALLBACK (on_grab_actor_destroy), + NULL); context->pointer_grab_actor = NULL; } - if (actor) + if (actor != NULL) { context->pointer_grab_actor = actor; - g_object_weak_ref (G_OBJECT (actor), - on_pointer_grab_weak_notify, - NULL); + g_signal_connect (context->pointer_grab_actor, "destroy", + G_CALLBACK (on_grab_actor_destroy), + NULL); + } +} + +/** + * clutter_input_device_grab: + * @device: a #ClutterInputDevice + * @actor: a #ClutterActor + * + * Acquires a grab on @actor for the given @device. + * + * Any event coming from @device will be delivered to @actor, bypassing + * the usual event delivery mechanism, until the grab is released by + * calling clutter_input_device_ungrab(). + * + * The grab is client-side: even if the windowing system used by the Clutter + * backend has the concept of "device grabs", Clutter will not use them. + * + * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE and + * %CLUTTER_KEYBOARD_DEVICE can hold a grab. + * + * Since: 1.10 + */ +void +clutter_input_device_grab (ClutterInputDevice *device, + ClutterActor *actor) +{ + ClutterActor **grab_actor; + + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + + switch (device->device_type) + { + case CLUTTER_POINTER_DEVICE: + grab_actor = &(device->pointer_grab_actor); + break; + + case CLUTTER_KEYBOARD_DEVICE: + grab_actor = &(device->keyboard_grab_actor); + break; + + default: + g_critical ("Only pointer and keyboard devices can grab an actor"); + return; + } + + if (*grab_actor != NULL) + { + g_signal_handlers_disconnect_by_func (*grab_actor, + G_CALLBACK (on_grab_actor_destroy), + device); + } + + *grab_actor = actor; + + g_signal_connect (*grab_actor, + "destroy", + G_CALLBACK (on_grab_actor_destroy), + device); +} + +/** + * clutter_input_device_ungrab: + * @device: a #ClutterInputDevice + * + * Releases the grab on the @device, if one is in place. + * + * Since: 1.10 + */ +void +clutter_input_device_ungrab (ClutterInputDevice *device) +{ + ClutterActor **grab_actor; + + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + + switch (device->device_type) + { + case CLUTTER_POINTER_DEVICE: + grab_actor = &(device->pointer_grab_actor); + break; + + case CLUTTER_KEYBOARD_DEVICE: + grab_actor = &(device->keyboard_grab_actor); + break; + + default: + return; + } + + if (*grab_actor == NULL) + return; + + g_signal_handlers_disconnect_by_func (*grab_actor, + G_CALLBACK (on_grab_actor_destroy), + device); + + *grab_actor = NULL; +} + +/** + * clutter_input_device_get_grabbed_actor: + * @device: a #ClutterInputDevice + * + * Retrieves a pointer to the #ClutterActor currently grabbing all + * the events coming from @device. + * + * Return value: (transfer none): a #ClutterActor, or %NULL + * + * Since: 1.10 + */ +ClutterActor * +clutter_input_device_get_grabbed_actor (ClutterInputDevice *device) +{ + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); + + switch (device->device_type) + { + case CLUTTER_POINTER_DEVICE: + return device->pointer_grab_actor; + + case CLUTTER_KEYBOARD_DEVICE: + return device->keyboard_grab_actor; + + default: + g_critical ("Only pointer and keyboard devices can grab an actor"); } + + return NULL; } /** @@ -2491,6 +2645,8 @@ clutter_grab_pointer (ClutterActor *actor) * If @id is -1 then this function is equivalent to clutter_grab_pointer(). * * Since: 0.8 + * + * Deprecated: 1.10: Use clutter_input_device_grab() instead. */ void clutter_grab_pointer_for_device (ClutterActor *actor, @@ -2503,7 +2659,11 @@ clutter_grab_pointer_for_device (ClutterActor *actor, /* essentially a global grab */ if (id_ == -1) { - clutter_grab_pointer (actor); + if (actor == NULL) + clutter_ungrab_pointer (); + else + clutter_grab_pointer (actor); + return; } @@ -2511,25 +2671,13 @@ clutter_grab_pointer_for_device (ClutterActor *actor, if (dev == NULL) return; - if (dev->pointer_grab_actor == actor) + if (dev->device_type != CLUTTER_POINTER_DEVICE) return; - if (dev->pointer_grab_actor) - { - g_object_weak_unref (G_OBJECT (dev->pointer_grab_actor), - on_pointer_grab_weak_notify, - dev); - dev->pointer_grab_actor = NULL; - } - - if (actor) - { - dev->pointer_grab_actor = actor; - - g_object_weak_ref (G_OBJECT (actor), - on_pointer_grab_weak_notify, - dev); - } + if (actor == NULL) + clutter_input_device_ungrab (dev); + else + clutter_input_device_grab (dev, actor); } @@ -2553,6 +2701,8 @@ clutter_ungrab_pointer (void) * Removes an existing grab of the pointer events for device @id_. * * Since: 0.8 + * + * Deprecated: 1.10: Use clutter_input_device_ungrab() instead. */ void clutter_ungrab_pointer_for_device (gint id_) @@ -2580,18 +2730,6 @@ clutter_get_pointer_grab (void) } -static void -on_keyboard_grab_weak_notify (gpointer data, - GObject *where_the_object_was) -{ - ClutterMainContext *context; - - context = _clutter_context_get_default (); - context->keyboard_grab_actor = NULL; - - clutter_ungrab_keyboard (); -} - /** * clutter_grab_keyboard: * @actor: a #ClutterActor @@ -2622,21 +2760,21 @@ clutter_grab_keyboard (ClutterActor *actor) if (context->keyboard_grab_actor == actor) return; - if (context->keyboard_grab_actor) + if (context->keyboard_grab_actor != NULL) { - g_object_weak_unref (G_OBJECT (context->keyboard_grab_actor), - on_keyboard_grab_weak_notify, - NULL); + g_signal_handlers_disconnect_by_func (context->keyboard_grab_actor, + G_CALLBACK (on_grab_actor_destroy), + NULL); context->keyboard_grab_actor = NULL; } - if (actor) + if (actor != NULL) { context->keyboard_grab_actor = actor; - g_object_weak_ref (G_OBJECT (actor), - on_keyboard_grab_weak_notify, - NULL); + g_signal_connect (context->keyboard_grab_actor, "destroy", + G_CALLBACK (on_grab_actor_destroy), + NULL); } } diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h index 3ddc263..34328e8 100644 --- a/clutter/clutter-main.h +++ b/clutter/clutter-main.h @@ -96,7 +96,7 @@ void clutter_main (void); void clutter_main_quit (void); gint clutter_main_level (void); -#ifndef CLUTTER_DISABLE_DEPRECATED +#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION) void clutter_redraw (ClutterStage *stage) G_GNUC_DEPRECATED_FOR (clutter_stage_ensure_redraw); #endif @@ -110,7 +110,7 @@ gulong clutter_get_timestamp (void); gboolean clutter_get_accessibility_enabled (void); /* Threading functions */ -#ifndef CLUTTER_DISABLE_DEPRECATED +#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION) void clutter_threads_init (void); #endif @@ -133,7 +133,7 @@ guint clutter_threads_add_timeout_full (gint priority, gpointer data, GDestroyNotify notify); -#ifndef CLUTTER_DISABLE_DEPRECATED +#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION) guint clutter_threads_add_frame_source (guint fps, GSourceFunc func, gpointer data); @@ -149,7 +149,7 @@ guint clutter_threads_add_repaint_func (GSourceFunc func, GDestroyNotify notify); void clutter_threads_remove_repaint_func (guint handle_id); -#ifndef CLUTTER_DISABLE_DEPRECATED +#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION) void clutter_set_motion_events_enabled (gboolean enable); gboolean clutter_get_motion_events_enabled (void); #endif /* CLUTTER_DISABLE_DEPRECATED */ @@ -171,9 +171,11 @@ ClutterFontFlags clutter_get_font_flags (void); ClutterInputDevice *clutter_get_input_device_for_id (gint id_); +#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION) void clutter_grab_pointer_for_device (ClutterActor *actor, gint id_); void clutter_ungrab_pointer_for_device (gint id_); +#endif PangoFontMap * clutter_get_font_map (void); -- 2.7.4