<?xml version='1.0' encoding="ISO-8859-1"?> <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ <chapter id="chapter-tut-signals"> <title>Signals
tutorial
</title> <sect2 id="tut-signals-introduction"> <title>Introduction
</title> 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
<sect2 id="tut-signals-overview"> <title>Overview
of
Purple-signals
</title> 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
<sect2 id="tut-signals-registering"> <title>Registering
a
Signal
</title> The
first
step
of
using
a
signal
is
registering
it
with
libpurple
so
that
callbacks
may
be
connected
to
it.
This
is
done
using
<link linkend="purple-signal-register"><function>purple_signal_register()
</function></link>.
Here
is
a
slightly
modified
example
from
<link linkend="purple-plugins-init"><function>purple_plugins_init()
</function></link> in
<literal>plugins.c
</literal>:
purple_signal_register(purple_plugins_get_handle(),
/*
Instance
*/
"plugin-load",
/*
Signal
name
*/
purple_marshal_VOID__POINTER,/*
Marshal
function
*/
G_TYPE_NONE,
/*
Callback
return
type
*/
1,
/*
Number
of
callback
arguments
(not
including
void
*data)
*/
PURPLE_TYPE_PLUGIN
/*
Type
of
first
callback
argument
*/
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.
<title>Signal
Name
</title> Unique
identifier
for
the
signal
itself.
<title>Callback
function
definition
</title> The
rest
of
the
arguments
specify
the
form
of
the
callback
function.
<listitem><para><emphasis>Marshal
function
</emphasis></para><para> <literal>purple_marshal_VOID__POINTER
</literal> represents
the
callback
function
prototype,
not
including
a
"data"
argument,
explained
later.
The
form
is
<literal>purple_marshal_RETURNVALUETYPE__ARG1TYPE_ARG2TYPE_ETC
</literal>.
See
<link linkend="libpurple-signals">signals.h
</link> for
more
possible
types.
In
this
case,
the
callback
will
have
the
form
void
cb(void
*arg1,
void
*data)
If
<literal>purple_marshal_BOOLEAN__POINTER_POINTER_POINTER
</literal> were
gboolean
cb(void
*arg1,
void
*arg2,
void
*arg3,
void
*data)
The
<literal>void
*data
</literal> argument
at
the
end
of
each
callback
function
provides
the
data
argument
given
to
<link linkend="purple-signal-connect"><function>purple_signal_connect()
</function></link>.
<listitem><para><emphasis>Callback
return
type
</emphasis></para><para> In
our
case,
this
is
G_TYPE_NONE,
meaning
"returns
void".
<!-- TODO This could be described better. --> <listitem><para><emphasis>Number
of
callback
arguments
</emphasis></para><para> The
number
of
arguments
(not
including
<literal>data
</literal>)
that
the
callback
function
<listitem><para><emphasis>Type
of
argument
</emphasis></para><para> <literal>PURPLE_TYPE_PLUGIN
</literal> specifies
that
the
first
argument
given
to
the
callback
will
be
a
<literal>PurplePlugin*
</literal>.
You
will
need
as
many
"type
of
argument"
<link linkend="purple-signal-register"><function>purple_signal_register()
</function></link> "Number
of
arguments"
above.
<!-- TODO Describe this more. --> <sect2 id="tut-signals-connect"> <title>Connecting
to
the
signal
</title> 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
:
static
void
plugin_load_cb(PurplePlugin
*plugin,
gpointer
data)
GtkTreeView
*view
=
(GtkTreeView
*)data;
plugin_loading_common(plugin,
view,
TRUE);
Note
that
the
callback
function
prototype
matches
that
specified
in
the
call
to
<link linkend="purple-signal-register"><function>purple_signal_register()
</function></link> Once
the
callback
function
is
defined,
you
can
connect
it
to
the
signal.
Again
from
gtkplugin.c
,
in
<function>pidgin_plugin_dialog_show()
</function>:
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
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
<literal>plugin_dialog
</literal> ,
the
Pidgin
plugins
dialog.
When
<literal>plugin_dialog
</literal> is
deleted,
then
<literal>purple_signals_disconnect_by_handle(plugin_dialog)
</literal> should
be
called
to
remove
all
signal
connections
it
is
associated
with.
The
callback
function
is
given
using
a
helper
macro,
and
finally
the
<literal>data
</literal> argument
to
be
passed
to
<literal>plugin_load_cb
</literal> is
given
as
<literal>event_view
</literal>,
a
pointer
to
the
GTK
widget
that
<literal>plugin_load_cb
</literal> needs
to
update.
<sect2 id="tut-signals-emit-signal"> <title>Emitting
a
signal
</title> 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
<link linkend="purple-plugin-load"><function>purple_plugin_load()
</function></link> purple_signal_emit(purple_plugins_get_handle(),
"plugin-load",
plugin);
This
causes
the
signal
"plugin-load"
to
be
emitted
from
the
plugin
module
<link linkend="purple-plugins-get-handle"><function>purple_plugins_get_handle()
</function></link>),
with
the
newly
loaded
plugin
as
the
argument
to
pass
to
any
registered
callback
functions.
In
our
example,
<literal>plugin_load_cb
</literal> is
called
immediately
as
plugin_load_cb(plugin,
event_view);
and
does
whatever
it
does.