mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 04:22:05 +00:00
cookbook: Added recipe for signal handling in ClutterScript
Added a recipe explaining how to connect signals to handlers in the JSON definition used by ClutterScript; also shows how to connect the signals in code once the JSON has been loaded. Includes guidelines on writing handlers (i.e. need to use -export-dynamic and non-static functions) and example which connects a handler for motion events on a rectangle.
This commit is contained in:
parent
a67111a17c
commit
6c40b10083
@ -461,4 +461,270 @@ ClutterStage *stage = CLUTTER_STAGE (clutter_script_get_object (script, "stage))
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="script-signals">
|
||||||
|
<title>Connecting to signals in <type>ClutterScript</type></title>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Problem</title>
|
||||||
|
|
||||||
|
<para>You have declared an actor using JSON, and want to add
|
||||||
|
handlers for signals emitted by it.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Solution</title>
|
||||||
|
|
||||||
|
<para>Add a <varname>signals</varname> property to the actor's
|
||||||
|
JSON definition.</para>
|
||||||
|
|
||||||
|
<para>Here's how to connect a <type>ClutterStage's</type>
|
||||||
|
<code>destroy</code> signal to the
|
||||||
|
<function>clutter_main_quit()</function> function:</para>
|
||||||
|
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
{
|
||||||
|
"id" : "stage",
|
||||||
|
"type" : "ClutterStage",
|
||||||
|
"width" : 300,
|
||||||
|
"height" : 300,
|
||||||
|
|
||||||
|
<emphasis>"signals" : [
|
||||||
|
{ "name" : "destroy", "handler" : "clutter_main_quit" }
|
||||||
|
]</emphasis>
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
|
||||||
|
<para>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:</para>
|
||||||
|
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
{
|
||||||
|
"id" : "rectangle",
|
||||||
|
"type" : "ClutterRectangle",
|
||||||
|
"width" : 200,
|
||||||
|
"height" : 200,
|
||||||
|
"reactive" : true,
|
||||||
|
|
||||||
|
<emphasis>"signals" : [
|
||||||
|
{ "name" : "motion-event", "handler" : "foo_pointer_motion_cb" }
|
||||||
|
]</emphasis>
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
|
||||||
|
<para>This signal handler definition sets
|
||||||
|
<function>foo_pointer_motion_cb()</function>
|
||||||
|
as the handler for the <code>motion-event</code>
|
||||||
|
signal on the rectangle. (NB the rectangle has
|
||||||
|
<varname>reactive</varname> set to true, otherwise it
|
||||||
|
can't emit this signal.)</para>
|
||||||
|
|
||||||
|
<para>As per standard event handling in Clutter,
|
||||||
|
you define the handler function next. For example:</para>
|
||||||
|
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
<![CDATA[
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>See the
|
||||||
|
<link linkend="script-signals-discussion-writing-handlers">Discussion</link>
|
||||||
|
section for more about writing handler functions.</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<para>To make the signal connections active in your code,
|
||||||
|
call the <function>clutter_script_connect_signals()</function>
|
||||||
|
function after loading the JSON:</para>
|
||||||
|
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
<![CDATA[
|
||||||
|
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);
|
||||||
|
]]>
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="script-signals-discussion">
|
||||||
|
<title>Discussion</title>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Options for connecting signals to handlers</title>
|
||||||
|
|
||||||
|
<para>Every connection between a signal and handler requires
|
||||||
|
a JSON object with <varname>name</varname> and
|
||||||
|
<varname>handler</varname> keys. The <varname>name</varname>
|
||||||
|
is the name of the signal you're connecting a handler to; the
|
||||||
|
<varname>handler</varname> is the name of the function which
|
||||||
|
will handle the signal.</para>
|
||||||
|
|
||||||
|
<para>You can also specify these optional keys for a handler
|
||||||
|
object:</para>
|
||||||
|
|
||||||
|
<orderedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><code>"after" : true</code> configures the handler
|
||||||
|
to run after the default handler for the signal. (Default is
|
||||||
|
<code>"after" : false</code>).</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><varname>"swapped" : true</varname> 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 <code>"swapped" : false</code>).</para>
|
||||||
|
</listitem>
|
||||||
|
</orderedlist>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>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 <type>ClutterScript</type> and
|
||||||
|
connect to its signals with
|
||||||
|
<function>g_signal_connect()</function>.</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="script-signals-discussion-writing-handlers">
|
||||||
|
<title>Writing handler functions</title>
|
||||||
|
|
||||||
|
<para>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
|
||||||
|
<type>ClutterScript</type> 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.</para>
|
||||||
|
|
||||||
|
<para>You should also ensure that you use the
|
||||||
|
<option>-export-dynamic</option> flag when you compile your
|
||||||
|
application: either by passing it on the command line (if you're
|
||||||
|
calling <command>gcc</command> directly); or by adding
|
||||||
|
it to the appropriate <varname>LDFLAGS</varname> variable in
|
||||||
|
your <filename>Makefile</filename> (if you're using
|
||||||
|
<command>make</command>); or by whatever other mechanism is
|
||||||
|
appropriate for your build environment.</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Passing objects to handler functions</title>
|
||||||
|
|
||||||
|
<para>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:</para>
|
||||||
|
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
g_signal_connect (button,
|
||||||
|
"clicked",
|
||||||
|
G_CALLBACK (_button_clicked_cb),
|
||||||
|
actor_to_move);
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
|
||||||
|
<para>Note how <varname>actor_to_move</varname> is passed
|
||||||
|
as user data to the handler.</para>
|
||||||
|
|
||||||
|
<para>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 <type>ClutterScript</type> to
|
||||||
|
<emphasis>every</emphasis> handler function; then inside
|
||||||
|
<emphasis>each</emphasis> handler function, retrieve
|
||||||
|
the required objects from the script.</para>
|
||||||
|
|
||||||
|
<para>This was done in the code example above, by passing
|
||||||
|
the <type>ClutterScript</type> instance as two arguments to
|
||||||
|
<function>clutter_script_connect_signals()</function>:
|
||||||
|
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.</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>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 <type>ClutterScript</type>.</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Full examples</title>
|
||||||
|
|
||||||
|
<example id="script-signals-examples-1">
|
||||||
|
<title><type>ClutterScript</type> JSON with signal handler
|
||||||
|
definitions</title>
|
||||||
|
<programlisting>
|
||||||
|
<xi:include href="examples/script-signals.json" parse="text">
|
||||||
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||||||
|
</xi:include>
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<example id="script-signals-examples-2">
|
||||||
|
<title>Loading a JSON file into a <type>ClutterScript</type>
|
||||||
|
and connecting signal handlers</title>
|
||||||
|
<programlisting>
|
||||||
|
<xi:include href="examples/script-signals.c" parse="text">
|
||||||
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||||||
|
</xi:include>
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
Loading…
Reference in New Issue
Block a user