doc/reference/libpurple/tut_signals.xml

branch
gtkdoc-conversion
changeset 35389
884a5385bb2c
child 35427
d8b39c2329dd
child 37033
ce8b96a22ebe
equal deleted inserted replaced
35388:9b0f74b6b3d9 35389:884a5385bb2c
1 <?xml version='1.0' encoding="ISO-8859-1"?>
2 <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
3 "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
4 ]>
5 <chapter id="chapter-tut-signals">
6 <title>Signals tutorial</title>
7
8 <sect2 id="tut-signals-introduction">
9 <title>Introduction</title>
10 <para>
11 The libpurple signals interface is used for general event notification, such
12 as plugins being loaded or unloaded, allowing the GUI frontend to respond
13 appropriately to changing internal data. Unfortunately, its use is not at all
14 obvious from the information in the header files. This document uses code
15 snippets from the Pidgin/libpurple plugin systems to illustrate the proper
16 use of signals.
17 </para>
18 </sect2>
19
20 <sect2 id="tut-signals-overview">
21 <title>Overview of Purple-signals</title>
22 <para>
23 Signals in libpurple are very similar to those in GTK+. When certain events
24 happen, a named signal is "emitted" from a certain object. Emitting the
25 signal triggers a series of callbacks that have been "connected" to that
26 signal for that object. These callbacks take appropriate action in response
27 to the signal.
28 </para>
29 </sect2>
30
31 <sect2 id="tut-signals-registering">
32 <title>Registering a Signal</title>
33 <para>
34 The first step of using a signal is registering it with libpurple so that
35 callbacks may be connected to it. This is done using
36 <link linkend="purple-signal-register"><function>purple_signal_register()</function></link>.
37 Here is a slightly modified example from
38 <link linkend="purple-plugins-init"><function>purple_plugins_init</function></link>
39 in <literal>plugin.c</literal>:
40
41 <programlisting>
42 purple_signal_register(purple_plugins_get_handle(), /* Instance */
43 "plugin-load", /* Signal name */
44 purple_marshal_VOID__POINTER,/* Marshal function */
45 G_TYPE_NONE, /* Callback return type */
46 1, /* Number of callback arguments (not including void *data) */
47 PURPLE_TYPE_PLUGIN /* Type of first callback argument */
48 );
49 </programlisting>
50 </para>
51
52 <sect3>
53 <title>Instance</title>
54 <para>
55 A reference to the object from which this signal is emitted, and to which
56 potential callbacks should be connected. In this case, it will be the entire
57 plugin module emitting the signal.
58 </para>
59 </sect3>
60
61 <sect3>
62 <title>Signal Name</title>
63 <para>
64 Unique identifier for the signal itself.
65 </para>
66 </sect3>
67
68 <sect3>
69 <title>Callback function definition</title>
70 <para>
71 The rest of the arguments specify the form of the callback function.
72
73 <itemizedlist>
74 <listitem><para><emphasis>Marshal function</emphasis></para><para>
75 <literal>purple_marshal_VOID__POINTER</literal> represents the callback
76 function prototype, not including a "data" argument, explained later. The form
77 is <literal>purple_marshal_RETURNVALUETYPE__ARG1TYPE_ARG2TYPE_ETC</literal>.
78 See <link linkend="libpurple-signals">signals.h</link> for more possible types.
79 </para>
80
81 <para>
82 In this case, the callback will have the form
83 <programlisting>
84 void cb(void *arg1, void *data)
85 </programlisting>
86 </para>
87
88 <para>
89 If <literal>purple_marshal_BOOLEAN__POINTER_POINTER_POINTER</literal> were
90 specified, it would be:
91 <programlisting>
92 gboolean cb(void *arg1, void *arg2, void *arg3, void *data)
93 </programlisting>
94
95 The <literal>void *data</literal> argument at the end of each callback function
96 provides the data argument given to
97 <link linkend="purple-signal-connect"><function>purple_signal_connect()</function></link>.
98 </para></listitem>
99
100 <listitem><para><emphasis>Callback return type</emphasis></para><para>
101 In our case, this is G_TYPE_NONE, meaning "returns void".
102 <!-- TODO This could be described better. -->
103 </para></listitem>
104
105 <listitem><para><emphasis>Number of callback arguments</emphasis></para><para>
106 The number of arguments (not including <literal>data</literal>) that the callback function
107 will take.
108 </para></listitem>
109
110 <listitem><para><emphasis>Type of argument</emphasis></para><para>
111 <literal>PURPLE_TYPE_PLUGIN</literal> specifies that the first argument given to the callback
112 will be a <literal>PurplePlugin*</literal>. You will need as many "type of argument"
113 arguments to
114 <link linkend="purple-signal-register"><function>purple_signal_register</function></link>
115 as you specified in
116 "Number of arguments" above.
117
118 <!-- TODO Describe this more. -->
119 </para></listitem>
120 </itemizedlist>
121 </para>
122 </sect3>
123 </sect2>
124
125 <sect2 id="tut-signals-connect">
126 <title>Connecting to the signal</title>
127 <para>
128 Once the signal is registered, you can connect callbacks to it. First, you
129 must define a callback function, such as this one from gtkplugin.c :
130 <programlisting>
131 static void plugin_load_cb(PurplePlugin *plugin, gpointer data)
132 {
133 GtkTreeView *view = (GtkTreeView *)data;
134 plugin_loading_common(plugin, view, TRUE);
135 }
136 </programlisting>
137 Note that the callback function prototype matches that specified in the call
138 to <link linkend="purple-signal-register"><function>purple_signal_register()</function></link>
139 above.
140 </para>
141
142 <para>
143 Once the callback function is defined, you can connect it to the signal.
144 Again from gtkplugin.c , in <function>pidgin_plugin_dialog_show()</function>:
145 <programlisting>
146 purple_signal_connect(purple_plugins_get_handle(), "plugin-load", /* What to connect to */
147 plugin_dialog, /* Object receiving the signal */
148 PURPLE_CALLBACK(plugin_load_cb), /* Callback function */
149 event_view, /* Data to pass to the callback function
150 );
151 </programlisting>
152 </para>
153
154 <para>
155 The first two arguments ("What to connect to") specify the object emitting
156 the signal (the plugin module) and what signal to listen for ("plugin-load").
157 </para>
158
159 <para>
160 The object receiving the signal is <literal>plugin_dialog</literal> , the Pidgin plugins
161 dialog. When <literal>plugin_dialog</literal> is deleted, then
162 <literal>purple_signals_disconnect_by_handle(plugin_dialog)</literal> should be called to
163 remove all signal connections it is associated with.
164 </para>
165
166 <para>
167 The callback function is given using a helper macro, and finally the
168 <literal>data</literal> argument to be passed to
169 <literal>plugin_load_cb</literal> is given as <literal>event_view</literal>,
170 a pointer to the GTK widget that <literal>plugin_load_cb</literal> needs to update.
171 </para>
172 </sect2>
173
174 <sect2 id="tut-signals-emit-signal">
175 <title>Emitting a signal</title>
176 <para>
177 Connecting callbacks to signals is all well and good, but how do you "fire"
178 the signal and trigger the callback? At some point, you must "emit" the
179 signal, which immediately calls all connected callbacks.
180 </para>
181
182 <para>
183 As seen in <link linkend="purple-plugin-load"><function>purple_plugin_load</function></link>
184 in plugin.c:
185 <programlisting>
186 purple_signal_emit(purple_plugins_get_handle(), "plugin-load", plugin);
187 </programlisting>
188 This causes the signal "plugin-load" to be emitted from the plugin module
189 (given by
190 <link linkend="purple-plugins-get-handle"><function>purple_plugins_get_handle</function></link>),
191 with the newly loaded plugin as
192 the argument to pass to any registered callback functions.
193 </para>
194
195 <para>
196 In our example, <literal>plugin_load_cb</literal> is called immediately as
197 <programlisting>
198 plugin_load_cb(plugin, event_view);
199 </programlisting>
200 and does whatever it does.
201 </para>
202 </sect2>
203 </chapter>

mercurial