hi everyone;

in the past weeks the work on Clutter trunk has somewhat stabilised, and
we feel it's time to start freezing the API and start releasing a series
of unstable versions leading to the next 0.6 cycle.

for this reason, I'm going to write up a list of the API
changes/breaks/additions and a round up of the features that went in
trunk in the past four months. to the people tracking SVN trunk this
write up will be old news, but it's still a way to get a 10000 ft view
of the "state of the clutter".

in these emails I'll also expose some high level API that is based on
Clutter core; let's call it "Tidy".

let's start with the big changes, so here's the first: event handling.

+++

Clutter started with a very simple event handling: every event was
directly translated from the native type into a Clutter event and a
signal was emitted on the stage (0.2); then, from the backend an event
was injected in the event queue and the queue was consumed by the main
loop (0.4); with 0.6, the basics are the same (the backend translates
the native event and pushes it into a queue) but the event processing is
mostly done by the backend-independent core. this way, the synthetic
events, like the multiple button clicks or the crossing events are dealt
with on a higher level than the actual backend/platform, increasing the
portability and making the implementation more future-proof.

with the event code re-factorisation came the improvement in the
"picking" operation - that is, the way Clutter identifies the actor at
any given position on the stage given its coordinates; the picking code
became quite fast in 0.4 and this led to the ability to deliver the
events to the correct actor, and not to the stage. to avoid performance
issues, though, only the actors that have been explicitly flagged as
"reactive" will emit events. in other words, if an actor is not set as
reactive, it will be completely transparent to the events.

the biggest and more visible change in the event handling in 0.6,
though, is the W3C DOM-like event handling.

when an event is propagated from the backend to Clutter core, it will
start a chain of signal emissions which will go in two directions:
starting from the actor which received the event, the parents hierarchy
will be walked backwards until the ClutterStage is reached. for every
actor, the ClutterActor::captured-event signal will be emitted in this
phase. the ::captured-event is generic, so it will receive every event
(button, key, crossing, etc.). this phase is called "event capture".

once the stage has been reached, the parent hierarchy will be walked
again, starting from the stage until the actor is reached; for each
actor, the generic ClutterActor::event signal will be emitted, and if
the event has a specific signal (button-press-event, key-press-event,
enter-event, etc.), that signal will be emitted as well. this phase is
called "event bubbling".

each signal handler attached to the ::captured-event or any of ::event
signals emitted in the bubbling phase can block the emission chain by
simply returning TRUE - meaning that the handler fully consumed the
event.

one practical example of the chain interruption is a typical "button"
actor: it will need to override the button-press-event and
button-release-event signal class handlers inside its class
initialisation function, and return TRUE there:

  static void
  tidy_button_class_init (TidyButtonClass *klass)
  {
    ...
    ClutterActorClass *actor_lass = CLUTTER_ACTOR_CLASS (klass);
    ...
    actor_class->button_press_event = tidy_button_press;
    actor_class->button_release_event = tidy_button_release;
    actor_class->leave_event = tidy_button_leave;
    ...
  }

  static gboolean
  tidy_button_press (ClutterActor       *actor,
                     ClutterButtonEvent *event)
  {
    TidyButton *button = TIDY_BUTTON (actor);

    if (event->button == 1)
      {
        TidyButtonClass *klass;

        button->is_pressed = TRUE;

        klass = TIDY_BUTTON_GET_CLASS (button);
        klass->pressed (button);

        clutter_grab_pointer (actor);

        return TRUE;
      }

    return FALSE;
  }

  static gboolean
  tidy_button_release (ClutterActor       *actor,
                       ClutterButtonEvent *event)
  {
    TidtButton *button = TIDY_BUTTON (actor);
 
    if (event->button == 1 && button->is_pressed)
      {
        TidyButtonClass *klass;

        clutter_ungrab_pointer ();

        button->is_pressed = FALSE;

        klass = TIDY_BUTTON_GET_CLASS (button);
        klass->released (button);

        g_signal_emit (button, signals[CLICKED], 0);

        return TRUE;
      }

    return FALSE;
  }

  static gboolean
  tidy_button_leave (ClutterActor *actor,
                     ClutterCrossingEvent *event)
  {
    TidyButton *button = TIDY_BUTTON (actor);

    if (button->is_pressed)
      {
        TidyButtonClass *klass;

        clutter_ungrab_pointer ();

        button->is_pressed = FALSE;

        klass = TIDY_BUTTON_GET_CLASS (button);
        klass->released (button);

        return TRUE;
      }

    return FALSE;
  }

an example of the usage of the ::captured-event signal is a
pointer-based navigation, for instance a finger scrollable list actor on
a touchscreen. without the event capture phase (for instance, using a
toolkit like GTK+) it is necessary to overlay the actual widget with
something that intercepts all the motion events to avoid the widget
itself being activated by those events, and it also needs that the same
something intercepting the events re-injects into the queue the
important events, like presses and releases. the capture phase avoids
all this by simply interrupting the motion event propagation right
before those events reach the actor's reactive children, while letting
everything else through undisturbed.

another important addition to the event handling in Clutter is the
ability to make actors "grab" the events (for pointer and keyboard
events), preventing other actors from receiving them. for instance, in
the example above, the actor grabs all the pointer events when receiving
the button press, and releases the grab on button release and when the
pointer leaves the actor.

finally, the last event-related change, is the addition of a simple key
focus model. focus handling in Clutter is always explicit: the actor
that requests the key focus always receives it. if no actor requests key
focus the stage will automatically acquire it. for the kind of
interfaces Clutter aims at implementing it's not necessary to provide a
more complicated focus handling; in any case, it's always possible to
implement it on top of Clutter itself, for instance by having a
container actor that captures every key press and then changes the key
focus based on an internal list if a special key is pressed.

ciao,
 Emmanuele.

-- 
Emmanuele Bassi, OpenedHand Ltd.
Unit R, Homesdale Business Centre
216-218 Homesdale Rd., Bromley - BR12QZ
http://www.o-hand.com

-- 
To unsubscribe send a mail to [EMAIL PROTECTED]

Reply via email to