You have declared an actor using JSON, and want to add handlers for signals emitted by it.
Add a signals property to the actor's
      JSON definition.
Here's how to connect a ClutterStage's
      destroy signal to the
      clutter_main_quit() function:
{
  "id" : "stage",
  "type" : "ClutterStage",
  "width" : 300,
  "height" : 300,
  "signals" : [
    { "name" : "destroy", "handler" : "clutter_main_quit" }
  ]
}The highlighted part of the code is where the signal is connected. In this case, a Clutter function is used as the handler; in most cases, you'll want to define your own handlers, rather than using functions from other libraries, as follows:
{
  "id" : "rectangle",
  "type" : "ClutterRectangle",
  "width" : 200,
  "height" : 200,
  "reactive" : true,
  "signals" : [
    { "name" : "motion-event", "handler" : "foo_pointer_motion_cb" }
  ]
}This signal handler definition sets
      foo_pointer_motion_cb()
      as the handler for the motion-event
      signal on the rectangle. (NB the rectangle has
      reactive set to true, otherwise it
      can't emit this signal.)
As per standard event handling in Clutter, you define the handler function next. For example:
/* handler which just prints the position of the pointer at each motion event */
gboolean
foo_pointer_motion_cb (ClutterActor *actor,
                       ClutterEvent *event,
                       gpointer      user_data)
{
  gfloat x, y;
  clutter_event_get_coords (event, &x, &y);
  g_print ("Pointer movement at %.0f,%.0f\n", x, y);
  return TRUE;
}See the Discussion section for more about writing handler functions.
To make the signal connections active in your code,
      call the clutter_script_connect_signals()
      function after loading the JSON:
GError *error = NULL; /* load JSON from a file */ ClutterScript *ui = clutter_script_new (); clutter_script_load_from_file (ui, filename, &error); /* ...handle errors etc... */ /* connect the signals defined in the JSON file * * the first argument is the script into which the JSON * definition was loaded * * the second argument is passed as user_data to all * handlers: in this case, we pass the script as user_data * to all handlers, so that all the objects in the UI * are available to callback functions */ clutter_script_connect_signals (ui, ui);
Every connection between a signal and handler requires
        a JSON object with name and
        handler keys. The name
        is the name of the signal you're connecting a handler to; the
        handler is the name of the function which
        will handle the signal.
You can also specify these optional keys for a handler object:
"after" : true configures the handler
            to run after the default handler for the signal. (Default is
            "after" : false).
"swapped" : true specifies that
            the instance and the user data passed to the
            handler function are swapped around; i.e. the instance emitting
            the signal is passed in as the user data argument (usually the
            last argument), and any user data is passed in as the first
            argument. (Default is "swapped" : false).
While the connections to signals were specified in JSON
          above, it is still possible to connect handlers to signals in
          code (e.g. if you need to conditionally connect a handler). Just
          retrieve the object from the ClutterScript and
          connect to its signals with
          g_signal_connect().
The handler function has the usual signature required for the signal. However, the function cannot be static, otherwise the function is invisible to GModule (the mechanism used by ClutterScript to look up functions named in the JSON definition). Consequently, callback functions should be namespaced in such a way that they won't clash with function definitions in other parts of your code or in libraries you link to.
You should also ensure that you use the
        -export-dynamic flag when you compile your
        application: either by passing it on the command line (if you're
        calling gcc directly); or by adding
        it to the appropriate LDFLAGS variable in
        your Makefile (if you're using
        make); or by whatever other mechanism is
        appropriate for your build environment.
In a typical Clutter application, handler functions require access to objects other than the one which emitted a signal. For example, a button may move another actor when clicked. Typically, you would pass any required objects to the handler function as user data, like this:
g_signal_connect (button,
                  "clicked",
                  G_CALLBACK (_button_clicked_cb),
                  actor_to_move);Note how actor_to_move is passed
        as user data to the handler.
However, the JSON definition doesn't allow you to specify that different user data be passed to different handlers. So, to get at all required objects in the handler, a simple solution is to pass the ClutterScript to every handler function; then inside each handler function, retrieve the required objects from the script.
This was done in the code example above, by passing
        the ClutterScript instance as two arguments to
        clutter_script_connect_signals():
        the first argument specifies the script which defines the
        signal handlers; the second specifies the user data passed to every
        handler function. This ensures that each handler has access
        to all of the elements defined in the JSON file.
Alternatively, you could create some other structure to hold the objects you need and pass it to all handler functions. But this would effectively be a reimplementation of some aspects of ClutterScript.
Example 8.3. ClutterScript JSON with signal handler definitions
[
  {
    "id" : "stage",
    "type" : "ClutterStage",
    "width" : 300,
    "height" : 300,
    "color" : "#335",
    "signals" : [
      { "name" : "destroy", "handler" : "clutter_main_quit" }
    ],
    "children" : [ "rectangle" ]
  },
  {
    "id" : "rectangle",
    "type" : "ClutterRectangle",
    "width" : 200,
    "height" : 200,
    "x" : 50,
    "y" : 50,
    "color" : "#a90",
    "rotation-center-z-gravity" : "center",
    "reactive" : true,
    "signals" : [
      { "name" : "motion-event", "handler" : "foo_pointer_motion_cb" }
    ],
    "actions" : [
      {
        "type" : "ClutterClickAction",
        "signals" : [
          { "name" : "clicked", "handler" : "foo_button_clicked_cb" }
        ]
      }
    ]
  }
]
Example 8.4. Loading a JSON file into a ClutterScript and connecting signal handlers
#include <stdlib.h>
#include <clutter/clutter.h>
/* callbacks cannot be declared static as they
 * are looked up dynamically by ClutterScript
 */
gboolean
foo_pointer_motion_cb (ClutterActor *actor,
                       ClutterEvent *event,
                       gpointer      user_data)
{
  gfloat x, y;
  clutter_event_get_coords (event, &x, &y);
  g_print ("Pointer movement at %.0f,%.0f\n", x, y);
  return TRUE;
}
void
foo_button_clicked_cb (ClutterClickAction *action,
                       ClutterActor       *actor,
                       gpointer            user_data)
{
  gfloat z_angle;
  /* get the UI definition passed to the handler */
  ClutterScript *ui = CLUTTER_SCRIPT (user_data);
  /* get the rectangle defined in the JSON */
  ClutterActor *rectangle;
  clutter_script_get_objects (ui,
                              "rectangle", &rectangle,
                              NULL);
  /* do nothing if the actor is already animating */
  if (clutter_actor_get_animation (rectangle) != NULL)
    return;
  /* get the current rotation and increment it */
  z_angle = clutter_actor_get_rotation (rectangle,
                                        CLUTTER_Z_AXIS,
                                        NULL, NULL, NULL);
  if (clutter_click_action_get_button (action) == 1)
    z_angle += 90.0;
  else
    z_angle -= 90.0;
  /* animate to new rotation angle */
  clutter_actor_animate (rectangle,
                         CLUTTER_EASE_OUT_CUBIC,
                         1000,
                         "rotation-angle-z", z_angle,
                         NULL);
}
int
main (int argc, char *argv[])
{
  ClutterActor *stage;
  ClutterScript *ui;
  gchar *filename = "script-signals.json";
  GError *error = NULL;
  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
    return 1;
  ui = clutter_script_new ();
  clutter_script_load_from_file (ui, filename, &error);
  if (error != NULL)
    {
      g_critical ("Error loading ClutterScript file %s\n%s", filename, error->message);
      g_error_free (error);
      exit (EXIT_FAILURE);
    }
  clutter_script_get_objects (ui,
                              "stage", &stage,
                              NULL);
  /* make the objects in the script available to all signals
   * by passing the script as the second argument
   * to clutter_script_connect_signals()
   */
  clutter_script_connect_signals (ui, ui);
  clutter_actor_show (stage);
  clutter_main ();
  g_object_unref (ui);
  return EXIT_SUCCESS;
}