<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">

<chapter id="events" xmlns:xi="http://www.w3.org/2003/XInclude">
  <title>Events</title>

  <epigraph>
    <attribution>The Tenth Doctor (David Tennant)</attribution>
    <para>Crossing into established events is strictly forbidden. Except for
    cheap tricks.</para>
  </epigraph>

  <section id="events-introduction">
    <title>Introduction</title>
    <para>Once you have set up a scene on the stage, in order to respond
    to user interaction you will have to handle events coming from the
    underlying platform.</para>

    <para>Events are relayed to actors by Clutter in form of
    <emphasis>signals</emphasis>; signals are a facility provided by the
    GObject framework to call functions depending on a unique name. A signal
    can be thought as a message that an object instance broadcasts to various
    listener functions.</para>

    <para>There are various events that Clutter will handle: mostly, they
    deal with input devices, like a mouse pointer or a keyboard; but they can
    also come from the windowing system, like the
    <emphasis>delete-event</emphasis> signal that is emitted when the user
    closes the window of the stage.</para>

    <para>Each event has a particular <emphasis>source</emphasis>, that is
    the actor that received the event. The event handling sequence is divided
    in two phases:</para>

    <orderedlist>
      <listitem><para>the <emphasis>capture</emphasis> phase, which consists
      in an emission of the <emphasis>captured-event</emphasis> signal
      starting from the stage to, following the parent-child relationship,
      the source of the event;</para></listitem>
      <listitem><para>the <emphasis>bubble</emphasis> phase, which consists
      in an emission of the <emphasis>event</emphasis> signal starting from
      the source of the event to, following the parent-child
      relationship, the stage.</para></listitem>
    </orderedlist>

    <para>At any point during the event emission sequence a handler of either
    the captured-event or the event signals can stop it, by returning a boolean
    value of <emphasis>true</emphasis>, which means that the event has been
    handled. If an event hasn't  been handled, a boolean value of
    <emphasis>false</emphasis> should be returned instead.</para>

    <note><para>Clutter provides two useful macros to avoid remembering which
    boolean value should be used in an event signal handler:
    CLUTTER_EVENT_PROPAGATE, equivalent to FALSE; and CLUTTER_EVENT_STOP,
    equivalent to TRUE.</para></note>
  </section>

  <section id="events-handling-key-events">
    <title>Handling key events</title>

    <section>
      <title>Problem</title>
      <para>You want to respond to key presses on an actor.</para>
    </section>

    <section>
      <title>Solutions</title>

      <para>There are two possible solutions:</para>

      <orderedlist>
        <listitem>
          <para><emphasis>Solution 1:</emphasis> Connect a callback to the
          actor; inside the callback, manually analyse which key and
          modifier(s) were pressed and react accordingly.</para>
        </listitem>
        <listitem>
          <para><emphasis>Solution 2:</emphasis> Use an actor's
          <type>ClutterBindingPool</type> to declaratively assign
          actions to specific key and modifier combinations.</para>
        </listitem>
      </orderedlist>

      <para>Each solution is covered below.</para>

      <section>
        <title>Solution 1</title>

        <para>Connect the <emphasis>key-press-event</emphasis>
        signal for an actor to a callback; then examine the event
        in the callback to determine which key and modifiers were
        pressed.</para>

        <para>First, connect an actor's
        <emphasis>key-press-event</emphasis> signal to a callback:</para>

        <informalexample>
          <programlisting>
g_signal_connect (actor, "key-press-event", G_CALLBACK (_key_press_cb), NULL);
          </programlisting>
        </informalexample>

        <para>Then, in the callback, check which key was pressed and which
        modifiers were down at the same time. For example, this callback
        checks for a press on the up arrow key and whether
        the <keycap>Shift</keycap> and/or <keycap>Ctrl</keycap>
        key were down:</para>

        <informalexample>
          <programlisting>
<![CDATA[
static gboolean
_key_press_cb (ClutterActor *actor,
               ClutterEvent *event,
               gpointer      user_data)
{
  guint keyval = clutter_event_get_key_symbol (event);

  ClutterModifierType state = clutter_event_get_state (event);
  gboolean shift_pressed = (state & CLUTTER_SHIFT_MASK ? TRUE : FALSE);
  gboolean ctrl_pressed = (state & CLUTTER_CONTROL_MASK ? TRUE : FALSE);

  if (CLUTTER_KEY_Up == keyval)
    {
      if (shift_pressed & ctrl_pressed)
        g_debug ("Up and shift and control pressed");
      else if (shift_pressed)
        g_debug ("Up and shift pressed");
      else
        g_debug ("Up pressed");

      /* The event was handled, and the emission should stop */
      return CLUTTER_EVENT_STOP;
    }

  /* The event was not handled, and the emission should continue */
  return CLUTTER_EVENT_PROPAGATE;
}
]]>
          </programlisting>
        </informalexample>

        <note>
          <para>Clutter provides a range of key value definitions
          (like <constant>CLUTTER_KEY_Up</constant>, used above). These are
          generated from the list in the
          <ulink url="http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h">X.Org source code</ulink>
          (replace "XK" with "CLUTTER_KEY" in the definitions there to get the
          Clutter equivalents; alternatively, look at the
          <filename>clutter-keysyms.h</filename> header file for the
          list).</para>

          <para><constant>CLUTTER_SHIFT_MASK</constant>,
          <constant>CLUTTER_CONTROL_MASK</constant> and other modifiers are
          defined in the <type>ClutterModifierType</type> enum.</para>
        </note>

      </section>

      <section>
        <title>Solution 2</title>

        <para>Assign actions to an actor's <type>ClutterBindingPool</type>.
        A binding pool stores mappings from a key press (either a single key
        or a key plus modifiers) to actions; an action is simply a callback
        function with a specific signature.</para>

        <para>While this approach is trickier to implement, it is more
        flexible and removes the drudgery of writing branching code to
        handle different key presses. See the
        <link linkend="events-handling-key-events-discussion">Discussion</link>
        section for more details.</para>

        <para>To use this approach with an actor which will receive key press
        events, first get that actor's binding pool. In the example below,
        we're using the binding pool for the default
        <type>ClutterStage</type>:</para>

        <informalexample>
          <programlisting>
ClutterBindingPool *binding_pool;
GObjectClass *stage_class;

stage_class = CLUTTER_STAGE_GET_CLASS (stage);
binding_pool = clutter_binding_pool_get_for_class (stage_class);
          </programlisting>
        </informalexample>

        <para>Next, install actions into the binding pool. For example, to
        install an action bound to the up arrow key, which calls the
        <function>_move_up()</function> function when that key is pressed,
        you would do:</para>

        <informalexample>
          <programlisting>
clutter_binding_pool_install_action (binding_pool,
                                     "move-up",      /* identifier */
                                     CLUTTER_KEY_Up, /* up arrow pressed */
                                     0,              /* no modifiers pressed */
                                     G_CALLBACK (_move_up),
                                     NULL,           /* no user data passed */
                                     NULL);
          </programlisting>
        </informalexample>

        <para>Another example, binding up arrow +
        <keycap>Shift</keycap> + <keycap>Ctrl</keycap> to an action
        which calls <function>_move_up_shift_control()</function> when
        activated:</para>

        <informalexample>
          <programlisting>
clutter_binding_pool_install_action (binding_pool,
                                     "move-up-shift-control",
                                     CLUTTER_KEY_Up,
                                     CLUTTER_SHIFT_MASK + CLUTTER_CONTROL_MASK,
                                     G_CALLBACK (_move_up_shift_control),
                                     NULL,
                                     NULL);
          </programlisting>
        </informalexample>

        <para>The function called when an action is activated looks
        like this (for <function>_move_up()</function>):</para>

        <informalexample>
          <programlisting>
static void
_move_up (GObject             *instance,
          const gchar         *action_name,
          guint                key_val,
          ClutterModifierType  modifiers,
          gpointer             user_data)
{
  g_debug ("Up pressed");
}
          </programlisting>
        </informalexample>

        <para>Then bind the <emphasis>key-press-event</emphasis> signal
        for the actor (in our case, the stage) to a callback:</para>

        <informalexample>
          <programlisting>
g_signal_connect (stage,
                  "key-press-event",
                  G_CALLBACK (_key_press_cb),
                  NULL);
          </programlisting>
        </informalexample>

        <para>Finally, inside the callback, pass control to the actor's
        binding pool rather than dissecting the key press event
        yourself:</para>

        <informalexample>
          <programlisting>
static gboolean
_key_press_cb (ClutterActor *actor,
             ClutterEvent *event,
             gpointer      user_data)
{
  ClutterBindingPool *pool;

  pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));

  return clutter_binding_pool_activate (pool,
                                        clutter_event_get_key_symbol (event),
                                        clutter_event_get_state (event),
                                        G_OBJECT (actor));
}
          </programlisting>
        </informalexample>

        <para>Now, when a key + modifiers that have been bound to an action
        are pressed on the actor, the appropriate action is activated.</para>

      </section>
    </section>

    <section id="events-handling-key-events-discussion">
      <title>Discussion</title>

      <section>
        <title>Pros and cons of Solution 1 and Solution 2</title>

        <para>Solution 1 is the simplest (in terms of the amount of code you
        have to write for simple cases), but could quickly turn into a mess if
        you need many conditions or want to capture many key combinations.
        Also, if multiple actors need to respond to key press events, you'll
        need similar event dissection code in each callback.</para>

        <para>Solution 2 is more complicated to implement, but scales better
        if you have many different key combinations on multiple actors.
        The binding pool protects you from the minutiae of detecting which
        keys were pressed, leaving you to concentrate on the
        triggered actions instead. This could simplify your control
        logic.</para>

        <para>In addition, Solution 2 lets you write a single callback to
        handle all key press events for all actors. This callback could then
        use <function>clutter_binding_pool_find()</function>
        (as in the example code) to determine which binding pool to
        activate (depending on which actor received the key press
        event).</para>

        <para>Finally, a binding pool allows you to block and unblock actions.
        This means you can make the response to a key press event conditional
        on application state. For example, let's say you wanted the up arrow
        key to move an actor, but only when the actor is at the bottom
        of the stage. To implement this, you could disable the up arrow key
        action in the binding pool initially; then, once the actor reaches the
        bottom of the stage, enable the up arrow key action again. While this
        is possible with Solution 1, you would have to implement more of the
        state management code yourself.</para>
      </section>

      <section>
        <title>Other useful things to know about key press events</title>

        <itemizedlist>
          <listitem>
            <para>A <type>ClutterKeyEvent</type> contains only a
            <emphasis>single</emphasis> key value, plus possibly one
            or more modifier keys (like <keycap>Shift</keycap>,
            <keycap>Ctrl</keycap>, <keycap>Alt</keycap> etc.).
            There are no functions in the Clutter API which return
            events for tracking near-simultaneous presses on multiple
            keys.</para>
          </listitem>

          <listitem>
            <para>By default, the stage receives all key events.
            To make another actor receive key events, use
            <function>clutter_stage_set_key_focus()</function>:</para>

            <informalexample>
              <programlisting>
/*
 * stage is a ClutterStage instance;
 * actor is the ClutterActor instance which should receive key events
 */
clutter_stage_set_key_focus (stage, actor);
              </programlisting>
            </informalexample>
          </listitem>
        </itemizedlist>

      </section>

    </section>

  </section>

  <section id="events-mouse-scroll">
    <title>Detecting mouse scrolling on an actor</title>

    <section>
      <title>Problem</title>

      <para>You want to detect when the mouse is scrolled on an
      actor (e.g. the pointer is over an actor when a mouse
      wheel is scrolled).</para>
    </section>

    <section>
      <title>Solution</title>

      <para>Connect a callback handler to the <code>scroll-event</code>
      signal of an actor.</para>

      <para>First, ensure that the actor is reactive (i.e. will
      respond to events):</para>

      <informalexample>
        <programlisting>
<![CDATA[
clutter_actor_set_reactive (actor, TRUE);
]]>
        </programlisting>
      </informalexample>

      <para>Next, create a callback handler to examine the scroll
      event and respond to it:</para>

      <informalexample>
        <programlisting>
<![CDATA[
static gboolean
_scroll_event_cb (ClutterActor *actor,
                  ClutterEvent *event,
                  gpointer      user_data)
{
  /* determine the direction the mouse was scrolled */
  ClutterScrollDirection direction;
  direction = clutter_event_get_scroll_direction (event);

  /* replace these stubs with real code to move the actor etc. */
  switch (direction)
    {
    case CLUTTER_SCROLL_UP:
      g_debug ("Scrolled up");
      break;
    case CLUTTER_SCROLL_DOWN:
      g_debug ("Scrolled down");
      break;
    case CLUTTER_SCROLL_RIGHT:
      g_debug ("Scrolled right");
      break;
    case CLUTTER_SCROLL_LEFT:
      g_debug ("Scrolled left");
      break;
    }

  return CLUTTER_EVENT_STOP; /* event has been handled */
}
]]>
        </programlisting>
      </informalexample>

      <para>Finally, connect the callback handler to the
      <code>scroll-event</code> signal of the actor:</para>

      <informalexample>
        <programlisting>
<![CDATA[
g_signal_connect (actor,
                  "scroll-event",
                  G_CALLBACK (_scroll_event_cb),
                  NULL);
]]>
        </programlisting>
      </informalexample>

    </section>

    <section>
      <title>Discussion</title>

      <para>A standard mouse wheel will only return up and
      down movements; but in cases where the mouse has left and
      right scrolling (e.g. a trackball mouse or trackpad), left and
      right scroll events may also be emitted.</para>

      <section>
        <title>Creating a scrolling viewport for an actor</title>

        <para>While the simple outline above explains the basics
        of how to connect to scroll events, it doesn't do much to
        help with <emphasis>really</emphasis> implementing scrolling
        over an actor. That's what we'll do in this section.</para>

        <note>
          <para>The full code for the example we'll walk through here is
          available in <link linkend="events-mouse-scroll-example">this later
          section</link>.</para>
        </note>

        <para>Scrolling over an actor actually requires coordination
        between two components:</para>

        <orderedlist>
          <listitem>
            <formalpara>
              <title>Scrollable actor</title>
              <para>An actor which is too large to fit on the stage
              or inside the area of the UI assigned to it (otherwise
              there's no need to scroll over it...).</para>
            </formalpara>
          </listitem>
          <listitem>
            <formalpara>
              <title>Viewport</title>
              <para>This displays a cropped view of part of the scrollable
              actor, revealing different parts of it as scroll events
              occur.</para>
            </formalpara>
          </listitem>
        </orderedlist>

        <para>Here are the steps required to set up the two actors:</para>

        <orderedlist>
          <listitem>
            <para>Create the scrollable actor; it should be larger
            than the viewport. This example uses a <type>ClutterTexture</type>,
            but any <type>ClutterActor</type> will work:</para>
            <informalexample>
              <programlisting>
/* get image file path, set up stage etc. */

ClutterActor *texture;
texture = clutter_texture_new ();
clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture),
                                       TRUE);

/*
 * set the texture's height so it's as tall as the stage
 * (STAGE_HEIGHT is define'd at the top of the file)
 */
clutter_actor_set_request_mode (texture, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT);
clutter_actor_set_height (texture, STAGE_HEIGHT);

/*
 * load the image file;
 * see <link linkend="textures-aspect-ratio">this recipe</link> for more about loading images into textures
 */
clutter_texture_set_from_file (CLUTTER_TEXTURE (texture),
                               image_file_path,
                               NULL);
              </programlisting>
            </informalexample>
          </listitem>

          <listitem>

            <para>Create the viewport. The simplest way to do
            this is with a <type>ClutterGroup</type>:</para>

            <informalexample>
              <programlisting>
<![CDATA[
ClutterActor *viewport;
viewport = clutter_group_new ();

/* viewport is _shorter_ than the stage (and the texture) */
clutter_actor_set_size (viewport, STAGE_WIDTH, STAGE_HEIGHT * 0.5);

/* align the viewport to the center of the stage's y axis */
clutter_actor_add_constraint (viewport,
                              clutter_align_constraint_new (stage, CLUTTER_BIND_Y, 0.5));

/* viewport needs to respond to scroll events */
clutter_actor_set_reactive (viewport, TRUE);

/* clip all actors inside the viewport to that group's allocation */
clutter_actor_set_clip_to_allocation (viewport, TRUE);
]]>
                </programlisting>
              </informalexample>

              <para>The key here is calling
              <code>clutter_actor_set_clip_to_allocation (viewport, TRUE)</code>.
              This configures the <varname>viewport</varname> group so
              that any of its children are clipped: i.e. only parts of
              its children which fit inside its allocation are visible. This
              in turn requires setting an explicit size on the group,
              rather than allowing it to size itself to fit its
              children (the latter is the default).</para>

          </listitem>

          <listitem>
            <para>Put the scrollable actor into the viewport; and
            the viewport into its container (in this case,
            the default stage):</para>

            <informalexample>
              <programlisting>
clutter_actor_add_child (viewport, texture);

clutter_actor_add_child (stage, viewport);
              </programlisting>
            </informalexample>

          </listitem>

          <listitem>
            <para>Create a callback handler for <code>scroll-event</code>
            signals emitted by the viewport:</para>

            <informalexample>
              <programlisting>
<![CDATA[
static gboolean
_scroll_event_cb (ClutterActor *viewport,
                  ClutterEvent *event,
                  gpointer      user_data)
{
  ClutterActor *scrollable = CLUTTER_ACTOR (user_data);

  gfloat viewport_height = clutter_actor_get_height (viewport);
  gfloat scrollable_height = clutter_actor_get_height (scrollable);

  /* no need to scroll if the scrollable is shorter than the viewport */
  if (scrollable_height < viewport_height)
    return CLUTTER_EVENT_STOP;

  gfloat y = clutter_actor_get_y (scrollable);

  ClutterScrollDirection direction;
  direction = clutter_event_get_scroll_direction (event);

  switch (direction)
    {
    case CLUTTER_SCROLL_UP:
      y -= SCROLL_AMOUNT;
      break;
    case CLUTTER_SCROLL_DOWN:
      y += SCROLL_AMOUNT;
      break;

    /* we're only interested in up and down */
    case CLUTTER_SCROLL_LEFT:
    case CLUTTER_SCROLL_RIGHT:
      break;
    }

  /*
   * the CLAMP macro returns a value for the first argument
   * that falls within the range specified by the second and
   * third arguments
   *
   * we allow the scrollable's y position to be decremented to the point
   * where its base is aligned with the base of the viewport
   */
  y = CLAMP (y,
             viewport_height - scrollable_height,
             0.0);

  /* animate the change to the scrollable's y coordinate */
  clutter_actor_animate (scrollable,
                         CLUTTER_EASE_OUT_CUBIC,
                         300,
                         "y", y,
                         NULL);

  return CLUTTER_EVENT_STOP;
}
]]>
              </programlisting>
            </informalexample>

            <para>The approach taken here is to move the scrollable
            actor up, relative to the viewport. Initially, the
            scrollable will have a <code>y</code> coordinate value
            of <code>0.0</code> (aligned to the top of the viewport).
            Scrolling up decrements the
            <code>y</code> coordinate (down to a minumum of
            <code>viewport_height - scrollable_height</code>). This moves
            the top of the scrollable actor "outside" the clip area of the
            viewport; simultaneously, more of the bottom part of the
            scrollable moves into the clip area, becoming visible.</para>

            <para>Scrolling down increments the <code>y</code> coordinate
            (but only up to a maximum value of <code>0.0</code>).</para>

            <para>To see how this works in practice, look at
            <link linkend="events-mouse-scroll-example">the code
            sample</link>. There, the height of the scrollable actor is
            set to <code>300</code> and the height of the viewport to
            <code>150</code>. This means that the <code>y</code>
            coordinate value for the scrollable actor will vary between
            <code>-150.0</code>: <code>150</code> (the viewport's height)
            <code>- 300</code> (the scrollable actor's height), making
            its base visible and clipping its top; and
            <code>0.0</code>, where its top is visible and its base
            clipped.</para>
          </listitem>

          <listitem>
            <para>Connect the callback handler to the signal; note
            that we pass the scrollable actor (the texture) to the callback,
            as we're moving the texture relative to the viewport to
            create the scrolling effect:</para>

            <informalexample>
              <programlisting>
g_signal_connect (viewport,
                  "scroll-event",
                  G_CALLBACK (_scroll_event_cb),
                  texture);
              </programlisting>
            </informalexample>
          </listitem>

        </orderedlist>

        <para>Here's a video of the result:</para>

        <inlinemediaobject>
          <videoobject>
            <videodata fileref="videos/events-mouse-scroll.ogv"/>
          </videoobject>
          <alt>
            <para>Video showing a scrollable actor</para>
          </alt>
        </inlinemediaobject>

      </section>
    </section>

    <section>
      <title>Full example</title>

      <example id="events-mouse-scroll-example">
        <title>Mouse scrolling over a <type>ClutterActor</type></title>
        <programlisting>
<xi:include href="examples/events-mouse-scroll.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>
    </section>

  </section>

  <section id="events-pointer-motion">
    <title>Detecting pointer movements on an actor</title>

    <section id="events-pointer-motion-problem">
      <title>Problem</title>

      <para>You want to be able to tell when the pointer (e.g. associated
      with a mouse or touches on a screen) enters, leaves, or moves over
      an actor.</para>

      <para>Example use cases include:</para>

      <itemizedlist>
        <listitem>
          <para>Adding a tooltip or hover effect to an actor when
          a pointer moves onto it.</para>
        </listitem>
        <listitem>
          <para>Tracing the path of the pointer over an actor (e.g.
          in a drawing application).</para>
        </listitem>
      </itemizedlist>

    </section>

    <section id="events-pointer-motion-solution">
      <title>Solution</title>

      <para>Connect to the pointer motion signals emitted by the actor.</para>

      <section>
        <title>Responding to crossing events</title>

        <para>To detect the pointer crossing the boundary of an actor
        (entering or leaving), connect to the <code>enter-event</code>
        and/or <code>leave-event</code> signals. For example:</para>

        <informalexample>
          <programlisting>
ClutterActor *actor = clutter_texture_new ();

/* ...set size, color, image etc., depending on the actor... */

/* make the actor reactive: see <link linkend="events-pointer-motion-discussion">Discussion</link> for more details */
clutter_actor_set_reactive (actor, TRUE);

/* connect to the signals */
g_signal_connect (actor,
                  "enter-event",
                  G_CALLBACK (_pointer_enter_cb),
                  NULL);

g_signal_connect (actor,
                  "leave-event",
                  G_CALLBACK (_pointer_leave_cb),
                  NULL);
          </programlisting>
        </informalexample>

        <para>The signature for callbacks connected to each of these
        signals is:</para>

        <informalexample>
          <programlisting>
gboolean
_on_crossing (ClutterActor *actor,
              ClutterEvent *event,
              gpointer      user_data)
          </programlisting>
        </informalexample>

        <para>In the callback, you can examine the event to get the
        coordinates where the pointer entered or left the actor. For
        example, <function>_pointer_enter_cb()</function> could
        follow this template:</para>

        <informalexample id="events-pointer-motion-callback-example">
          <programlisting>
<![CDATA[
/* the event passed to the callback is of type ClutterCrossingEvent */
static gboolean
_pointer_enter_cb (ClutterActor *actor,
                   ClutterEvent *event,
                   gpointer      user_data)
{
  /* get the coordinates where the pointer crossed into the actor */
  gfloat stage_x, stage_y;
  clutter_event_get_coords (event, &stage_x, &stage_y);

  /*
   * as the coordinates are relative to the stage, rather than
   * the actor which emitted the signal, it can be useful to
   * transform them to actor-relative coordinates
   */
  gfloat actor_x, actor_y;
  clutter_actor_transform_stage_point (actor,
                                       stage_x, stage_y,
                                       &actor_x, &actor_y);

  g_debug ("pointer at stage x %.0f, y %.0f; actor x %.0f, y %.0f",
           stage_x, stage_y,
           actor_x, actor_y);

  return CLUTTER_EVENT_STOP;
}
]]>
          </programlisting>
        </informalexample>

        <para>See <link linkend="events-pointer-motion-example-1">the
        code example in the appendix</link> for an example of how
        you can implement a hover effect on a "button" (rectangle
        with text overlay) using this approach.</para>

      </section>

      <section>
        <title>Responding to motion events</title>

        <para>Motion events occur when a pointer moves over an actor;
        the actor emits a <code>motion-event</code> signal when this
        happens. To respond to motion events, connect to this signal:</para>

        <informalexample>
          <programlisting>
/* set up the actor, make reactive etc., as above */

/* connect to motion-event signal */
g_signal_connect (actor,
                  "motion-event",
                  G_CALLBACK (_pointer_motion_cb),
                  transitions);
          </programlisting>
        </informalexample>

        <para>The signature of the callback is the same as for
        the <code>enter-event/leave-event</code> signals, so you can use
        <link linkend="events-pointer-motion-callback-example">code
        similar to the above</link> to handle it. However, the
        type of the event is a <type>ClutterMotionEvent</type>
        (rather than a <type>ClutterCrossingEvent</type>).</para>

      </section>

    </section>

    <section id="events-pointer-motion-discussion">
      <title>Discussion</title>

      <para>A few more useful things to know about pointer motion
      events:</para>

      <itemizedlist>

        <listitem>
          <para>Each crossing event is accompanied by a motion event at
          the same coordinates.</para>
        </listitem>

        <listitem>
          <para>Before an actor will emit signals for pointer events,
          it needs to be made reactive with:</para>

          <informalexample>
            <programlisting>
clutter_actor_set_reactive (actor, TRUE);
            </programlisting>
          </informalexample>
        </listitem>

        <listitem>
          <para>A pointer event structure includes other data. Some
          examples:</para>

          <informalexample>
            <programlisting>
/* keys and mouse buttons pressed down when the pointer moved */
ClutterModifierType modifiers = clutter_event_get_state (event);

/* time (since the epoch) when the event occurred */
guint32 event_time = clutter_event_get_time (event);

/* actor where the event originated */
ClutterActor *actor = clutter_event_get_actor (event);

/* stage where the event originated */
ClutterStage *stage = clutter_event_get_stage (event);
            </programlisting>
          </informalexample>

          <para>There's no need to cast the event to use these
          functions: they will work on any <type>ClutterEvent</type>.</para>
        </listitem>

        <listitem>
          <para>The coordinates of an event (as returned by
          <function>clutter_event_get_coords()</function>) are relative
          to the stage where they originated, rather than the actor. Unless
          the actor is the same size as the stage, you'll typically want
          the actor-relative coordinates instead. To get those, use
          <function>clutter_actor_transform_stage_point()</function>.</para>
        </listitem>

      </itemizedlist>

      <para>The <link linkend="events-pointer-motion-example-4">simple
      scribble application</link> gives a more
      thorough example of how to integrate pointer events into a
      Clutter application (in this case, for drawing on a
      <type>ClutterTexture</type>).</para>

      <para>The effect of actor depth on pointer motion events is
      worth slightly deeper discussion, and is covered next.</para>

      <section>
        <title>Pointer events on actors at different depths</title>

        <para>If you have actors stacked on top of each other, the
        reactive actor nearest the "top" is the one
        which emits the signal (when the pointer crosses into or moves
        over it). "Top" here means either at the top of
        the depth ordering (if all actors are at the same depth)
        or the closest to the view point (if actors have different
        depths in the <code>z</code> axis).</para>

        <para>Here's an example of three rectangles overlapping each
        other:</para>

        <screenshot>
          <mediaobject>
            <imageobject>
              <imagedata format="PNG"
                         fileref="images/events-pointer-motion-stacking.png" />
            </imageobject>
            <alt>
              <para>Pointer events in actors with different depth ordering</para>
            </alt>
          </mediaobject>
        </screenshot>

        <para>The rectangles are all at the same point on the
        <code>z</code> axis but stacked (different positions in the depth
        order). They have the following properties:</para>

        <itemizedlist>
          <listitem>
            <para>The <emphasis>red</emphasis> rectangle is lowest down
            the depth ordering and reactive. Pointer motion signals are
            emitted by this actor when the pointer crosses or moves on the
            area of the rectangle <emphasis>not</emphasis> overlapped by the
            green rectangle.</para>
          </listitem>
          <listitem>
            <para>The <emphasis>green</emphasis> rectangle is in the
            middle of the depth ordering and reactive. This actor emits
            events over its whole surface, even though it is overlapped
            by the blue rectangle (as the blue rectangle is not
            reactive).</para>
            <para>Even if the blue rectangle were fully opaque, a pointer
            crossing into or moving on the green rectangle's area (even if
            obscured by the blue rectangle) would still cause a signal
            to be emitted.</para>
          </listitem>
          <listitem>
            <para>The <emphasis>blue</emphasis> rectangle is at the top
            of the depth ordering and <emphasis>not</emphasis> reactive.
            This actor doesn't emit any pointer motion signals and doesn't
            block events from occurring on any other actor.</para>
          </listitem>
        </itemizedlist>

        <para>See <link linkend="events-pointer-motion-example-3">the
        sample code in the appendix</link> for more details.</para>

      </section>

    </section>

    <section>
      <title>Full examples</title>

      <example id="events-pointer-motion-example-1">
        <title>Simple button with a hover animation (change in opacity
        as the pointer enters and leaves it)</title>
        <programlisting>
<xi:include href="examples/events-pointer-motion-crossing.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="events-pointer-motion-example-2">
        <title>Detecting pointer motion on a <type>ClutterRectangle</type></title>
        <programlisting>
<xi:include href="examples/events-pointer-motion.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="events-pointer-motion-example-3">
        <title>How actors influence pointer events on each other</title>
        <programlisting>
<xi:include href="examples/events-pointer-motion-stacked.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="events-pointer-motion-example-4">
        <title>Scribbling on a <type>ClutterTexture</type> in response
        to pointer events</title>
        <programlisting>
<xi:include href="examples/events-pointer-motion-scribbler.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

    </section>

  </section>

  <section id="events-buttons">
    <title>Making an actor respond to button events</title>

    <section>
      <title>Problem</title>

      <para>You want an actor to respond to button events. These might
      be buttons on an input device like a mouse;
      or input events caused by other means, like touches on a screen.</para>

      <para>Some examples of where this is useful:</para>

      <itemizedlist>
        <listitem>
          <para>For implementing button widgets which respond to
          button clicks.</para>
        </listitem>
        <listitem>
          <para>To make actor selections by mouse click (e.g.
          as part of a drawing application).</para>
        </listitem>
        <listitem>
          <para>To recognise a button press followed by pointer
          motion and button release (e.g. to implement drag
          and drop or kinetic animations).</para>
        </listitem>
      </itemizedlist>

    </section>

    <section>
      <title>Solution</title>

      <para>Connect a handler to the <emphasis>button-press-event</emphasis>
      and/or <emphasis>button-release-event</emphasis> signals of an
      actor.</para>

      <note>
        <para>The <emphasis>button-press-event</emphasis> is emitted
        when a button is pressed (not necessarily released) on a reactive
        actor; the <emphasis>button-release-event</emphasis> when a
        button is released on a reactive actor (even if the button was
        pressed down somewhere else).</para>
      </note>

      <para>First, ensure the actor is reactive:</para>

      <informalexample>
        <programlisting>
clutter_actor_set_reactive (actor, TRUE);
        </programlisting>
      </informalexample>

      <para>Next, create a function to handle the signal(s) you are
      interested in. The function signature is the same for both the
      press and release signals:</para>

      <informalexample>
        <programlisting>
gboolean
callback_function (ClutterActor *actor,
                   ClutterEvent *event,
                   gpointer      user_data);
        </programlisting>
      </informalexample>

      <para>You can use a single function as the
      callback for both signals (or write a different one for each signal).
      Here's an example function which can be used as a callback
      for both press and release signals, as it simply pulls data
      out of the event and displays it:</para>

      <informalexample>
        <programlisting>
/* <varname>event</varname> is a <type>ClutterButtonEvent</type>
 * for both the press and the release signal; it contains
 * data about where the event occurred
 */
static gboolean
button_event_cb (ClutterActor *actor,
                 ClutterEvent *event,
                 gpointer      user_data)
{
  gfloat x, y;
  gchar *event_type;
  guint button_pressed;
  ClutterModifierType state;
  gchar *ctrl_pressed;
  guint32 click_count;

  /* where the pointer was (relative to the stage)
   * when the button event occurred; use
   * <function>clutter_actor_transform_stage_point()</function>
   * to transform to actor-relative coordinates
   */
  clutter_event_get_coords (event, &amp;x, &amp;y);

  /* check whether it was a press or release event */
  event_type = "released";
  if (clutter_event_type (event) == CLUTTER_BUTTON_PRESS)
    event_type = "pressed";

  /* which button triggered the event */
  button_pressed = clutter_event_get_button (event);

  /* keys down when the event occurred;
   * this is a bit mask composed of the bits for each key held down
   * when the button was pressed or released; see the
   * <type>ClutterModifierType</type> enum in the Clutter API docs
   * for a list of the available modifiers
   */
  state = clutter_event_get_state (event);

  ctrl_pressed = "ctrl not pressed";
  if (state &amp; CLUTTER_CONTROL_MASK)
    ctrl_pressed = "ctrl pressed";

  /* click count */
  click_count = clutter_event_get_click_count (event);

  g_debug ("button %d was %s at %.0f,%.0f; %s; click count %d",
           button_pressed,
           event_type,
           x,
           y,
           ctrl_pressed,
           click_count);

  return CLUTTER_EVENT_STOP;
}
        </programlisting>
      </informalexample>

      <para>Finally, connect the signals to the function(s):</para>

      <informalexample>
        <programlisting>
/* connect the press event */
g_signal_connect (actor,
                  "button-press-event",
                  G_CALLBACK (button_event_cb),
                  NULL);

/* connect the release event */
g_signal_connect (actor,
                  "button-release-event",
                  G_CALLBACK (button_event_cb),
                  NULL);
        </programlisting>
      </informalexample>

      <para>Pressing or releasing a button on the actor will now
      trigger a call to the <function>button_event_cb()</function>
      function. See <link linkend="events-buttons-example-1">the full
      example</link> for more details.</para>

    </section>

    <section>
      <title>Discussion</title>

      <para>Properties of the <type>ClutterButtonEvent</type>
      emitted by both signals should be examined using the
      <function>clutter_event_*</function> functions (rather than struct
      members directly), as in the example above. While most of these
      functions are self-explanatory, a couple require more explanation:
      see the sections below.</para>

      <para>Also covered below is an alternative approach to handling a
      button press followed by a release on a single actor: by adding
      a <type>ClutterClickAction</type> to an actor. See
      <link linkend="events-buttons-clutterclickaction">this section</link>
      for details.</para>

      <para>Finally, a <link linkend="events-buttons-example-3">longer
      example</link> is included, showing how to make use of button press,
      button release and pointer events in a simple drawing application.</para>

      <section>
        <title>Click count</title>

        <para>The click count records the number of times a press/release
        pair occurred in sequence. You can retrieve it via the
        <function>clutter_event_get_click_count()</function> function.</para>

        <note>
          <para>A press/release pair is effectively a click, so this term
          will be used from now on throughout this section,
          to make the explanation simpler. However, the click count has
          nothing to do with <type>ClutterClickActions</type>, described
          <link linkend="events-buttons-clutterclickaction">later</link>.
          </para>
        </note>

        <para>For clicks to be considered part of the same sequence (for
        the purposes of counting), all the clicks after the first one
        must occur within the global <varname>double_click_distance</varname>
        (pixels) of the first click; and the time between click
        <code>n</code> and click <code>n+1</code> must be <code>&lt;=</code>
        the global <varname>double_click_time</varname> (milliseconds).</para>

        <para>The clicks <emphasis>do not</emphasis> have to occur on
        the same actor: providing they occur within the double click
        distance and time, they are counted as part of the same click
        sequence. Also note that the clicks don't even have to happen
        on a reactive actor: providing they happen somewhere on the
        stage, they will still increment the click count.</para>

        <para>The default double click time and distance are
        stored in the <type>ClutterSettings</type> associated
        with an application. You can get/set their values like this:</para>

        <informalexample>
          <programlisting>
gint double_click_distance;
gint double_click_time;

ClutterSettings *settings = clutter_settings_get_default ();

/* get double click settings */
g_object_get (settings,
              "double-click-distance", &amp;double_click_distance,
              "double-click-time", &amp;double_click_time,
              NULL);

/* set */
g_object_set (settings,
              "double-click-distance", 50,
              "double-click-time", 1000,
              NULL);
          </programlisting>
        </informalexample>

      </section>

      <section>
        <title>Button numbering</title>

        <para><function>clutter_event_get_button()</function> returns
        an integer representing the pressed or released button.</para>

        <para>In the case of a standard scroll mouse, the numbers
        returned are reliable across different hardware models:</para>

        <itemizedlist>
          <listitem>
            <para>1 = left mouse button in a right-handed configuration,
            or the right mouse button in a left-handed configuration</para>
          </listitem>
          <listitem>
            <para>2 = scroll wheel button</para>
          </listitem>
          <listitem>
            <para>3 = right mouse button in a right-handed configuration,
            or the left mouse button in a left-handed configuration</para>
          </listitem>
        </itemizedlist>

        <note><para>Clutter provides symbolic names for the three buttons
        above: CLUTTER_BUTTON_PRIMARY, CLUTTER_BUTTON_MIDDLE, and
        CLUTTER_BUTTON_SECONDARY.</para></note>

        <para>For mice with more buttons, or other types of
        input devices, the mappings may not be so
        straightforward: you may have to experiment to see
        which button returns which value.</para>

      </section>

      <section id="events-buttons-clutterclickaction">
        <title><type>ClutterClickAction</type></title>

        <para><type>ClutterActions</type> add flexible event handling
        to <type>ClutterActors</type>. They recognise and abstract
        common sequences of low-level events into a single, more easily
        managed high-level event. In the case of a
        <type>ClutterClickAction</type>, the abstraction is over
        a press followed by a release on a single actor. This is
        achieved by "synthesising" the press and release signals on
        the actor: in other words, the action captures those
        two signals when emitted by a single actor; and, once captured, the
        action emits a single <emphasis>clicked</emphasis> signal
        <emphasis>instead</emphasis> of the two signals being
        emitted by the actor.</para>

        <para>The pointer can move off the actor between the press and
        release, but the press and release must both occur on the same
        actor, with no intervening presses or releases on other
        actors. In addition, there are no maximum distance or time
        constraints on the press and release.</para>

        <para>If a press occurs and you want to force it to be released
        (e.g. to break a pointer grab after a certain length of
        time has elapsed), use
        <function>clutter_click_action_release()</function>.</para>

        <para>On the down side, the <emphasis>clicked</emphasis> signal
        doesn't present the same detailed <type>ClutterButtonEvent</type>
        to the handler. So, for example, you can't get a click count from a
        <type>ClutterClickAction</type> (though you could count
        the clicks yourself, of course); and you don't have access
        to the coordinates where the press or release occurred.</para>

        <para>To add a click action to a <type>ClutterActor</type>:</para>

        <informalexample>
          <programlisting>
ClutterAction *action = clutter_click_action_new ();
clutter_actor_add_action (actor, action);
          </programlisting>
        </informalexample>

        <note>
          <para>An actor must still be set to reactive so that its
          signals can be routed to a click action.</para>
        </note>

        <para>Create a handler function (note the function
        signature is different from the one for the press or
        releas signal handler):</para>

        <informalexample>
          <programlisting>
void
clicked_cb (ClutterClickAction *action,
            ClutterActor       *actor,
            gpointer            user_data)
{
  /* display the number of the clicked button (equivalent
   * to the number returned by clutter_event_get_button())
   */
  g_debug ("Button %d clicked", clutter_click_action_get_button (action));
}
          </programlisting>
        </informalexample>

        <para>Connect the signal to the handler:</para>

        <informalexample>
          <programlisting>
g_signal_connect (action,
                  "clicked",
                  G_CALLBACK (clicked_cb),
                  NULL);
          </programlisting>
        </informalexample>

        <para>The <link linkend="events-buttons-example-2">example
        code</link> gives a bit more detail about how to use click
        actions.</para>

      </section>

    </section>

    <section>
      <title>Full examples</title>

      <example id="events-buttons-example-1">
        <title>Examining properties of a <type>ClutterButtonEvent</type></title>
        <programlisting>
<xi:include href="examples/events-buttons.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="events-buttons-example-2">
        <title>Using <type>ClutterClickAction</type> to capture
        button events on an actor</title>
        <programlisting>
<xi:include href="examples/events-buttons-click.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="events-buttons-example-3">
        <title>Using button and pointer events for drawing</title>
        <para>This code was inspired by
        <ulink url="http://git.clutter-project.org/cluttersmith/">ClutterSmith</ulink>
        </para>
        <programlisting>
<xi:include href="examples/events-buttons-lasso.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

    </section>

  </section>

</chapter>
