| |
1 /** @page signal-howto Signals HOWTO |
| |
2 |
| |
3 @section Introduction |
| |
4 The libpurple signals interface is used for general event notification, such |
| |
5 as plugins being loaded or unloaded, allowing the GUI frontend to respond |
| |
6 appropriately to changing internal data. Unfortunately, its use is not at all |
| |
7 obvious from the information in the header files. This document uses code |
| |
8 snippets from the Pidgin/libpurple plugin systems to illustrate the proper |
| |
9 use of signals. |
| |
10 |
| |
11 @section overview Overview of Signals |
| |
12 Signals in libpurple are very similar to those in GTK+. When certain events |
| |
13 happen, a named signal is "emitted" from a certain object. Emitting the |
| |
14 signal triggers a series of callbacks that have been "connected" to that |
| |
15 signal for that object. These callbacks take appropriate action in response |
| |
16 to the signal. |
| |
17 |
| |
18 @section registering_signal Registering a Signal |
| |
19 The first step of using a signal is registering it with libpurple so that |
| |
20 callbacks may be connected to it. This is done using purple_signal_register() |
| |
21 Here is a slightly modified example from @c purple_plugins_init in |
| |
22 @c libpurple/plugin.c : |
| |
23 |
| |
24 @code |
| |
25 purple_signal_register( purple_plugins_get_handle(), /* Instance */ |
| |
26 "plugin-load", /* Signal name */ |
| |
27 purple_marshal_VOID__POINTER,/* Marshal function */ |
| |
28 NULL, /* Callback return value type */ |
| |
29 1, /* Number of callback arguments (not including void *data) */ |
| |
30 purple_value_new(PURPLE_TYPE_SUBTYPE,PURPLE_SUBTYPE_PLUGIN) /* Type of first callback argument */ |
| |
31 ); |
| |
32 @endcode |
| |
33 |
| |
34 @subsection Instance |
| |
35 A reference to the object from which this signal is emitted, and to which |
| |
36 potential callbacks should be connected. In this case, it will be the entire |
| |
37 plugin module emitting the signal. |
| |
38 |
| |
39 @subsection signalname Signal Name |
| |
40 Unique identifier for the signal itself. |
| |
41 |
| |
42 @subsection therest Callback function definition |
| |
43 The rest of the arguments specify the form of the callback function. |
| |
44 |
| |
45 @subsubsection marshalfunc Marshal Function |
| |
46 @c purple_marshal_VOID__POINTER represents the callback function prototype, |
| |
47 not including a "data" argument, explained later. The form is |
| |
48 @c purple_marshal_RETURNVALUETYPE__ARG1TYPE_ARG2TYPE_ETC. See signals.h for |
| |
49 more possible types. |
| |
50 |
| |
51 In this case, the callback will have the form |
| |
52 @code |
| |
53 void cb(void *arg1, void *data) |
| |
54 @endcode |
| |
55 |
| |
56 If @c purple_marshal_BOOLEAN__POINTER_POINTER_POINTER were specified, it |
| |
57 would be: |
| |
58 @code |
| |
59 gboolean cb(void *arg1, void *arg2, void *arg3, void *data) |
| |
60 @endcode |
| |
61 |
| |
62 The @c void @c *data argument at the end of each callback function |
| |
63 provides the data argument given to purple_signal_connect() . |
| |
64 |
| |
65 @subsubsection cb_ret_type Callback return value type |
| |
66 In our case, this is NULL, meaning "returns void". |
| |
67 @todo This could be described better. |
| |
68 |
| |
69 @subsubsection num_args Number of arguments |
| |
70 The number of arguments (not including @c data ) that the callback function |
| |
71 will take. |
| |
72 |
| |
73 @subsubsection type_arg Type of argument |
| |
74 @c purple_value_new(PURPLE_TYPE_SUBTYPE,PURPLE_SUBTYPE_PLUGIN) specifies that |
| |
75 the first argument given to the callback will be a @c PurplePlugin* . You |
| |
76 will need as many "type of argument" arguments to purple_signal_register() as |
| |
77 you specified in "Number of arguments" above. |
| |
78 |
| |
79 @todo Describe this more. |
| |
80 |
| |
81 @See value.h |
| |
82 |
| |
83 @section connect Connecting to the signal |
| |
84 Once the signal is registered, you can connect callbacks to it. First, you |
| |
85 must define a callback function, such as this one from gtkplugin.c : |
| |
86 @code |
| |
87 static void plugin_load_cb(PurplePlugin *plugin, gpointer data) |
| |
88 { |
| |
89 GtkTreeView *view = (GtkTreeView *)data; |
| |
90 plugin_loading_common(plugin, view, TRUE); |
| |
91 } |
| |
92 @endcode |
| |
93 Note that the callback function prototype matches that specified in the call |
| |
94 to purple_signal_register() above. |
| |
95 |
| |
96 Once the callback function is defined, you can connect it to the signal. |
| |
97 Again from gtkplugin.c , in @c pidgin_plugin_dialog_show() : |
| |
98 @code |
| |
99 purple_signal_connect(purple_plugins_get_handle(), "plugin-load", /* What to connect to */ |
| |
100 plugin_dialog, /* Object receiving the signal */ |
| |
101 PURPLE_CALLBACK(plugin_load_cb), /* Callback function */ |
| |
102 event_view, /* Data to pass to the callback function |
| |
103 ); |
| |
104 @endcode |
| |
105 |
| |
106 The first two arguments ("What to connect to") specify the object emitting |
| |
107 the signal (the plugin module) and what signal to listen for ("plugin-load"). |
| |
108 |
| |
109 The object receiving the signal is @c plugin_dialog , the Pidgin plugins |
| |
110 dialog. When @c plugin_dialog is deleted, then |
| |
111 @c purple_signals_disconnect_by_handle(plugin_dialog) should be called to |
| |
112 remove all signal connections it is associated with. |
| |
113 |
| |
114 The callback function is given using a helper macro, and finally the |
| |
115 @c data argument to be passed to @c plugin_load_cb is given as @c event_view, |
| |
116 a pointer to the GTK widget that @c plugin_load_cb needs to update. |
| |
117 |
| |
118 @section emit-signal Emitting a signal |
| |
119 Connecting callbacks to signals is all well and good, but how do you "fire" |
| |
120 the signal and trigger the callback? At some point, you must "emit" the |
| |
121 signal, which immediately calls all connected callbacks. |
| |
122 |
| |
123 As seen in @c purple_plugin_load() in plugin.c : |
| |
124 @code |
| |
125 purple_signal_emit(purple_plugins_get_handle(), "plugin-load", plugin); |
| |
126 @endcode |
| |
127 This causes the signal "plugin-load" to be emitted from the plugin module |
| |
128 (given by @c purple_plugins_get_handle() ), with the newly loaded plugin as |
| |
129 the argument to pass to any registered callback functions. |
| |
130 |
| |
131 In our example, @c plugin_load_cb is called immediately as |
| |
132 @code |
| |
133 plugin_load_cb(plugin, event_view); |
| |
134 @endcode |
| |
135 and does whatever it does. |
| |
136 |
| |
137 */ |