diff --git a/ChangeLog b/ChangeLog index cb4b428da..dee8698b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-11-15 Øyvind Kolås + + * clutter/clutter-main.[ch]: added clutter_grab_keyboard, + clutter_ungrab_keyboard and clutter_get_keyboard_grab, in + clutter_do_event deliver keyboard related events only to the + actor with the keyboard grab if a grab exists. + * clutter/clutter-private.h: added keyboard_grab_actor to context. + * tests/test-grab.c: added testing for testing the keyboard grab. + 2007-11-15 Emmanuele Bassi * clutter/clutter-texture.c: diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index d63b59c15..e9f0db614 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -1285,7 +1285,6 @@ clutter_do_event (ClutterEvent *event) clutter_actor_event (context->pointer_grab_actor, event, FALSE); return; } - deliver_event (event); break; case CLUTTER_DESTROY_NOTIFY: @@ -1304,6 +1303,11 @@ clutter_do_event (ClutterEvent *event) g_return_if_fail (actor != NULL); + if (context->keyboard_grab_actor != NULL) + { + clutter_actor_event (context->keyboard_grab_actor, event, FALSE); + return; + } deliver_event (event); } break; @@ -1355,7 +1359,6 @@ clutter_do_event (ClutterEvent *event) event, FALSE); return; } - deliver_event (event); } break; @@ -1557,3 +1560,88 @@ clutter_get_pointer_grab (void) return context->pointer_grab_actor; } + + +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 + * + * Grabs keyboard events, after the grab is done keyboard events ("key-press-event" + * and "key-release-event") are delivered to this actor directly. The source + * set in the event will be the actor that would have received the event if the + * keyboard grab was not in effect. + * + * Since: 0.6 + */ +void +clutter_grab_keyboard (ClutterActor *actor) +{ + ClutterMainContext *context; + + g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); + + context = clutter_context_get_default (); + + if (context->keyboard_grab_actor == actor) + return; + + if (context->keyboard_grab_actor) + { + g_object_weak_unref (G_OBJECT (context->keyboard_grab_actor), + on_keyboard_grab_weak_notify, + NULL); + context->keyboard_grab_actor = NULL; + } + + if (actor) + { + context->keyboard_grab_actor = actor; + + g_object_weak_ref (G_OBJECT (actor), + on_keyboard_grab_weak_notify, + NULL); + } +} + +/** + * clutter_ungrab_keyboard: + * + * Removes an existing grab of the keyboard. + * + * Since: 0.6 + */ +void +clutter_ungrab_keyboard (void) +{ + clutter_grab_keyboard (NULL); +} + +/** + * clutter_get_keyboard_grab: + * + * Queries the current keyboard grab of clutter. + * + * Return value: the actor currently holding the keyboard grab, or NULL if there is no grab. + * + * Since: 0.6 + */ +ClutterActor * +clutter_get_keyboard_grab (void) +{ + ClutterMainContext *context; + context = clutter_context_get_default (); + + return context->keyboard_grab_actor; +} diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h index abb70d9bb..a62044163 100644 --- a/clutter/clutter-main.h +++ b/clutter/clutter-main.h @@ -111,6 +111,10 @@ void clutter_grab_pointer (ClutterActor *actor); void clutter_ungrab_pointer (void); ClutterActor * clutter_get_pointer_grab (void); +void clutter_grab_keyboard (ClutterActor *actor); +void clutter_ungrab_keyboard (void); +ClutterActor * clutter_get_keyboard_grab (void); + G_END_DECLS #endif /* _HAVE_CLUTTER_MAIN_H */ diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index d69208a2f..16048da2a 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -89,6 +89,9 @@ struct _ClutterMainContext ClutterActor *pointer_grab_actor; /* The actor having the pointer grab (or NULL if there is no pointer grab) */ + ClutterActor *keyboard_grab_actor; /* The actor having the pointer grab + (or NULL if there is no pointer grab) + */ }; #define CLUTTER_CONTEXT() (clutter_context_get_default ()) diff --git a/tests/test-grab.c b/tests/test-grab.c index 9c5210ec5..924df0b33 100644 --- a/tests/test-grab.c +++ b/tests/test-grab.c @@ -47,10 +47,6 @@ debug_event_cb (ClutterActor *actor, break; case CLUTTER_BUTTON_RELEASE: printf("[%s] BUTTON RELEASE", source); - if (clutter_event_get_source (event) == CLUTTER_ACTOR (stage)) - clutter_stage_set_key_focus (stage, NULL); - else if (clutter_event_get_source (event) == actor) - clutter_stage_set_key_focus (stage, actor); break; case CLUTTER_SCROLL: printf("[%s] BUTTON SCROLL", source); @@ -133,6 +129,19 @@ toggle_grab_pointer_cb (ClutterActor *actor, return FALSE; } +static gboolean +cyan_press_cb (ClutterActor *actor, + ClutterEvent *event, + gpointer data) +{ + if (clutter_get_keyboard_grab () != NULL) + clutter_ungrab_keyboard (); + else + clutter_grab_keyboard (actor); + return FALSE; +} + + int main (int argc, char *argv[]) @@ -141,6 +150,7 @@ main (int argc, char *argv[]) ClutterColor rcol = { 0xff, 0, 0, 0xff}, bcol = { 0, 0, 0xff, 0xff }, gcol = { 0, 0xff, 0, 0xff }, + ccol = { 0, 0xff, 0xff, 0xff }, ycol = { 0xff, 0xff, 0, 0xff }, ncol = { 0, 0, 0, 0xff }; @@ -150,6 +160,7 @@ main (int argc, char *argv[]) g_print ("Blue box: aquire grab on press, destroys the blue box actor on release\n"); g_print ("Yellow box: aquire grab on press, releases grab on next press on yellow box\n"); g_print ("Green box: toggle per actor motion events.\n\n"); + g_print ("Cyan box: toggle grab (from cyan box) for keyboard events.\n\n"); stage = clutter_stage_get_default (); g_signal_connect (stage, "event", G_CALLBACK (debug_event_cb), "stage"); @@ -205,6 +216,17 @@ main (int argc, char *argv[]) g_signal_connect (actor, "button-press-event", G_CALLBACK (green_press_cb), NULL); + + actor = clutter_rectangle_new_with_color (&ccol); + clutter_actor_set_size (actor, 100, 100); + clutter_actor_set_position (actor, 500, 100); + clutter_actor_set_reactive (actor); + clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); + g_signal_connect (actor, "event", + G_CALLBACK (debug_event_cb), "cyan box"); + g_signal_connect (actor, "button-press-event", + G_CALLBACK (cyan_press_cb), NULL); + clutter_actor_show_all (CLUTTER_ACTOR (stage)); clutter_main();