# HG changeset patch # User William Ehlhardt # Date 1184480888 0 # Node ID c3e80350c27095a573f8bac5769a0503605cf616 # Parent 264f00bc8f228fa917d95a505e927c0517ac388a - Added a lovely Doxygen signals tutorial diff -r 264f00bc8f22 -r c3e80350c270 doc/Makefile.am --- a/doc/Makefile.am Sat Jul 14 04:49:30 2007 +0000 +++ b/doc/Makefile.am Sun Jul 15 06:28:08 2007 +0000 @@ -3,6 +3,7 @@ EXTRA_DIST = \ C-HOWTO.dox \ PERL-HOWTO.dox \ + SIGNAL-HOWTO.dox \ TCL-HOWTO.dox \ TracFooter.html \ TracHeader.html \ diff -r 264f00bc8f22 -r c3e80350c270 doc/SIGNAL-HOWTO.dox --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/SIGNAL-HOWTO.dox Sun Jul 15 06:28:08 2007 +0000 @@ -0,0 +1,137 @@ +/** @page signal-howto Signals HOWTO + + @section Introduction + The libpurple signals interface is used for general event notification, such + as plugins being loaded or unloaded, allowing the GUI frontend to respond + appropriately to changing internal data. Unfortunately, its use is not at all + obvious from the information in the header files. This document uses code + snippets from the Pidgin/libpurple plugin systems to illustrate the proper + use of signals. + + @section overview Overview of Signals + Signals in libpurple are very similar to those in GTK+. When certain events + happen, a named signal is "emitted" from a certain object. Emitting the + signal triggers a series of callbacks that have been "connected" to that + signal for that object. These callbacks take appropriate action in response + to the signal. + + @section registering_signal Registering a Signal + The first step of using a signal is registering it with libpurple so that + callbacks may be connected to it. This is done using purple_signal_register() + Here is a slightly modified example from @c purple_plugins_init in + @c libpurple/plugin.c : + + @code + purple_signal_register( purple_plugins_get_handle(), /* Instance */ + "plugin-load", /* Signal name */ + purple_marshal_VOID__POINTER,/* Marshal function */ + NULL, /* Callback return value type */ + 1, /* Number of callback arguments (not including void *data) */ + purple_value_new(PURPLE_TYPE_SUBTYPE,PURPLE_SUBTYPE_PLUGIN) /* Type of first callback argument */ + ); + @endcode + + @subsection Instance + A reference to the object from which this signal is emitted, and to which + potential callbacks should be connected. In this case, it will be the entire + plugin module emitting the signal. + + @subsection signalname Signal Name + Unique identifier for the signal itself. + + @subsection therest Callback function definition + The rest of the arguments specify the form of the callback function. + + @subsubsection marshalfunc Marshal Function + @c purple_marshal_VOID__POINTER represents the callback function prototype, + not including a "data" argument, explained later. The form is + @c purple_marshal_RETURNVALUETYPE__ARG1TYPE_ARG2TYPE_ETC. See signals.h for + more possible types. + + In this case, the callback will have the form + @code + void cb(void *arg1, void *data) + @endcode + + If @c purple_marshal_BOOLEAN__POINTER_POINTER_POINTER were specified, it + would be: + @code + gboolean cb(void *arg1, void *arg2, void *arg3, void *data) + @endcode + + The @c void @c *data argument at the end of each callback function + provides the data argument given to purple_signal_connect() . + + @subsubsection cb_ret_type Callback return value type + In our case, this is NULL, meaning "returns void". + @todo This could be described better. + + @subsubsection num_args Number of arguments + The number of arguments (not including @c data ) that the callback function + will take. + + @subsubsection type_arg Type of argument + @c purple_value_new(PURPLE_TYPE_SUBTYPE,PURPLE_SUBTYPE_PLUGIN) specifies that + the first argument given to the callback will be a @c PurplePlugin* . You + will need as many "type of argument" arguments to purple_signal_register() as + you specified in "Number of arguments" above. + + @todo Describe this more. + + @See value.h + + @section connect Connecting to the signal + Once the signal is registered, you can connect callbacks to it. First, you + must define a callback function, such as this one from gtkplugin.c : + @code +static void plugin_load_cb(PurplePlugin *plugin, gpointer data) +{ + GtkTreeView *view = (GtkTreeView *)data; + plugin_loading_common(plugin, view, TRUE); +} + @endcode + Note that the callback function prototype matches that specified in the call + to purple_signal_register() above. + + Once the callback function is defined, you can connect it to the signal. + Again from gtkplugin.c , in @c pidgin_plugin_dialog_show() : + @code + purple_signal_connect(purple_plugins_get_handle(), "plugin-load", /* What to connect to */ + plugin_dialog, /* Object receiving the signal */ + PURPLE_CALLBACK(plugin_load_cb), /* Callback function */ + event_view, /* Data to pass to the callback function + ); + @endcode + + The first two arguments ("What to connect to") specify the object emitting + the signal (the plugin module) and what signal to listen for ("plugin-load"). + + The object receiving the signal is @c plugin_dialog , the Pidgin plugins + dialog. When @c plugin_dialog is deleted, then + @c purple_signals_disconnect_by_handle(plugin_dialog) should be called to + remove all signal connections it is associated with. + + The callback function is given using a helper macro, and finally the + @c data argument to be passed to @c plugin_load_cb is given as @c event_view, + a pointer to the GTK widget that @c plugin_load_cb needs to update. + + @section emit-signal Emitting a signal + Connecting callbacks to signals is all well and good, but how do you "fire" + the signal and trigger the callback? At some point, you must "emit" the + signal, which immediately calls all connected callbacks. + + As seen in @c purple_plugin_load() in plugin.c : + @code + purple_signal_emit(purple_plugins_get_handle(), "plugin-load", plugin); + @endcode + This causes the signal "plugin-load" to be emitted from the plugin module + (given by @c purple_plugins_get_handle() ), with the newly loaded plugin as + the argument to pass to any registered callback functions. + + In our example, @c plugin_load_cb is called immediately as + @code + plugin_load_cb(plugin, event_view); + @endcode + and does whatever it does. + + */