]> git.tdb.fi Git - ext/sigc++-2.0.git/blob - docs/manual/libsigc_manual.xml
Import libsigc++ 2.10.8 sources
[ext/sigc++-2.0.git] / docs / manual / libsigc_manual.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <book xmlns="http://docbook.org/ns/docbook"
3       xmlns:xlink="http://www.w3.org/1999/xlink"
4       version="5.0" xml:id="index" xml:lang="en">
5
6 <info>
7   <title>libsigc++</title>
8   <author><personname>
9     <firstname>Ainsley</firstname>
10     <surname>Pereira</surname>
11   </personname></author>
12   <date>September 2002</date>
13   <pubdate>September 2002. Updated January 2004 by Murray Cumming</pubdate>
14   <abstract>
15     <para>libsigc++ is a C++ template library implementing typesafe callbacks. This is an intro to libsigc++.</para>
16   </abstract>
17 </info>
18
19 <chapter xml:id="chapter-introduction">
20 <info><title>Introduction</title></info>
21
22 <section xml:id="sect-motivation">
23 <info><title>Motivation</title></info>
24
25         <para>There are many situations in which it is desirable to decouple code that
26         detects an event, and the code that deals with it. This is especially common in
27         GUI programming, where a toolkit might provide user interface elements such as
28         clickable buttons but, being a generic toolkit, doesn't know how an individual
29         application using that toolkit should handle the user clicking on it.</para>
30
31         <para>In C the callbacks are generally handled by the application calling a
32         'register' function and passing a pointer to a function and a <literal remap="tt">void*</literal>
33         argument, eg.</para>
34
35 <programlisting>
36 void clicked(void* data);
37
38 button* okbutton = create_button("ok");
39 static char somedata[] = "This is some data I want the clicked() function to have";
40
41 register_click_handler(okbutton, clicked, somedata);
42 </programlisting>
43
44         <para>When clicked, the toolkit will call <literal remap="tt">clicked()</literal> with the data pointer passed
45         to the <literal remap="tt">register_click_handler()</literal> function.</para>
46
47         <para>This works in C, but is not typesafe. There is no compile-time way of
48         ensuring that <literal remap="tt">clicked()</literal> isn't expecting a struct of some sort instead of a
49         <literal remap="tt">char*</literal>.</para>
50
51         <para>As C++ programmers, we want type safety. We also want to be able to use
52         things other than free-standing functions as callbacks.</para>
53
54         <para>libsigc++ provides the concept of a slot, which holds a reference to one of
55         the things that can be used as a callback:
56         <itemizedlist>
57             <listitem><para>A free-standing function as in the example</para></listitem>
58             <listitem><para>A functor object that defines operator() (a lambda expression
59                 is such an object)</para></listitem>
60             <listitem><para>A pointer-to-a-member-function and an instance of an object on which to invoke it (the
61                 object should inherit from <literal remap="tt">sigc::trackable</literal>)</para></listitem>
62         </itemizedlist></para>
63
64         <para>All of which can take different numbers and types of arguments.</para>
65
66         <para>To make it easier to construct these, libsigc++ provides the sigc::ptr_fun() and sigc::mem_fun() functions, for creating slots from static functions and member functions, respectively. They return
67         a generic <literal remap="tt">signal::slot</literal> type that can be invoked with <literal remap="tt">emit()</literal> or <literal remap="tt">operator()</literal>.</para>
68
69         <para>For the other side of the fence, libsigc++ provides <literal remap="tt">signal</literal>s, to which the
70         client can attach <literal remap="tt">slot</literal>s. When the <literal remap="tt">signal</literal> is emitted, all the connected
71         <literal remap="tt">slot</literal>s are called.</para>
72 </section>
73 </chapter>
74
75 <chapter xml:id="chapter-connecting">
76 <info><title>Connecting your code to signals</title></info>
77
78 <section xml:id="sect-simple-ex">
79 <info><title>A simple example</title></info>
80
81         <para>So to get some experience, lets look at a simple example...</para>
82
83         <para>Lets say you and I are writing an application which informs the user when
84         aliens land in the car park. To keep the design nice and clean, and allow for
85         maximum portability to different interfaces, we decide to use libsigc++ to
86         split the project in two parts.</para>
87
88         <para>I will write the <literal remap="tt">AlienDetector</literal> class, and you will write the code to inform
89         the user. (Well, OK, I'll write both, but we're pretending, remember?)</para>
90
91         <para>Here's my class:</para>
92
93 <programlisting>
94 class AlienDetector
95 {
96 public:
97     AlienDetector();
98
99     void run();
100
101     sigc::signal&lt;void()&gt; signal_detected;
102 };
103 </programlisting>
104
105                 <para>(I'll explain the type of signal_detected later.)</para>
106
107                 <para>Here's your code that uses it:</para>
108
109 <programlisting>
110 void warn_people()
111 {
112     std::cout &lt;&lt; "There are aliens in the carpark!" &lt;&lt; std::endl;
113 }
114
115 int main()
116 {
117     AlienDetector mydetector;
118     mydetector.signal_detected.connect( sigc::ptr_fun(warn_people) );
119
120     mydetector.run();
121
122     return 0;
123 }
124 </programlisting>
125
126   <para>You can use a lambda expression instead of sigc::ptr_fun().</para>
127 <programlisting>
128     mydetector.signal_detected.connect( [](){ warn_people(); } );
129 </programlisting>
130
131         <para>Pretty simple really - you call the <literal remap="tt">connect()</literal> method on the signal to
132         connect your function. <literal remap="tt">connect()</literal> takes a <literal remap="tt">slot</literal> parameter (remember slots
133         are capable of holding any type of callback), so you convert your
134         <literal remap="tt">warn_people()</literal> function to a slot using the <literal remap="tt">slot()</literal> function.</para>
135
136         <para>To compile this example, use:</para>
137         <programlisting>g++ example1.cc -o example1 `pkg-config --cflags --libs sigc++-2.0`</programlisting>
138         <para>Note that those `` characters are backticks, not single quotes. Run it with</para>
139         <programlisting>./example1</programlisting>
140         <para>(Try not to panic when the aliens land!)</para>
141
142 </section>
143
144 <section xml:id="sect-using-mem-func">
145 <info><title>Using a member function</title></info>
146
147         <para>Suppose you found a more sophisticated alien alerter class on the web,
148         such as this:</para>
149
150 <programlisting>
151 class AlienAlerter : public sigc::trackable
152 {
153 public:
154     AlienAlerter(char const* servername);
155     void alert();
156 private:
157     // ...
158 };
159 </programlisting>
160
161         <para>(Handily it derives from <literal remap="tt">sigc::trackable</literal> already. This isn't quite so
162         unlikely as you might think; all appropriate bits of the popular gtkmm library do so,
163         for example.)</para>
164
165         <para>You could rewrite your code as follows:</para>
166
167 <programlisting>
168 int main()
169 {
170     AlienDetector mydetector;
171     AlienAlerter  myalerter("localhost");       // added
172     mydetector.signal_detected.connect( sigc::mem_fun(myalerter, &amp;AlienAlerter::alert) ); // changed
173
174     mydetector.run();
175
176     return 0;
177 }
178 </programlisting>
179
180         <para>Note that only 2 lines are different - one to create an instance of the
181         class, and the line to connect the method to the signal.</para>
182
183         <para>This code is in example2.cc, which can be compiled in the same way as
184         example1.cc</para>
185
186         <para>It's possible to use a lambda expression instead of sigc::mem_fun(),
187         but it's not recommended, if the class derives from <literal remap="tt">sigc::trackable</literal>.
188         With a lambda expression you would lose the automatic disconnection that the
189         combination of <literal remap="tt">sigc::trackable</literal> and sigc::mem_fun()
190         offers.</para>
191 </section>
192
193 <section xml:id="sect-signals-with-pars">
194 <info><title>Signals with parameters</title></info>
195
196         <para>Functions taking no parameters and returning void are quite useful,
197         especially when they're members of classes that can store unlimited amounts of
198         safely typed data, but they're not sufficient for everything.</para>
199
200         <para>What if aliens don't land in the carpark, but somewhere else? Let's modify
201         the example so that the callback function takes a <literal remap="tt">std::string</literal> with the location
202         in which aliens were detected.</para>
203
204         <para>I change my class to:</para>
205
206 <programlisting>
207 class AlienDetector
208 {
209 public:
210     AlienDetector();
211
212     void run();
213
214     sigc::signal&lt;void(std::string)&gt; signal_detected;      // changed
215 };
216 </programlisting>
217
218         <para>The only line I had to change was the signal line (in <literal remap="tt">run()</literal> I need to change
219         my code to supply the argument when I emit the signal too, but that's not shown
220         here).</para>
221
222         <para>The name of the type is '<literal remap="tt">sigc::signal</literal>'.
223         The template parameters are the return type, then the argument types in parentheses.
224         (libsigc++2 also accepts a different syntax, with a comma between the return type
225         and the parameter types. That syntax is deprecated, though.)</para>
226
227         <para>The types in the function signature are in the same order as the template
228         parameters, eg:</para>
229
230 <programlisting>
231 sigc::signal&lt;void(std::string)&gt;
232     void function(std::string foo);
233 </programlisting>
234
235                 <para>So now you can update your alerter (for simplicity, lets go back to the
236                 free-standing function version):</para>
237
238 <programlisting>
239 void warn_people(std::string where)
240 {
241     std::cout &lt;&lt; "There are aliens in " &lt;&lt; where &lt;&lt; "!" &lt;&lt; std::endl;
242 }
243
244 int main()
245 {
246     AlienDetector mydetector;
247     mydetector.signal_detected.connect( sigc::ptr_fun(warn_people) );
248
249     mydetector.run();
250
251     return 0;
252 }
253 </programlisting>
254
255         <para>Easy.</para>
256 </section>
257
258 <section xml:id="sect-disconnecting">
259 <info><title>Disconnecting</title></info>
260
261         <para>If you decide you no longer want your code to be called whenever a signal is
262         emitted, you must remember the return value of <literal remap="tt">connect()</literal>, which we've been
263         ignoring until now.</para>
264
265         <para><literal remap="tt">connect()</literal> returns a <literal remap="tt">sigc::connection</literal> object, which has a <literal remap="tt">disconnect()</literal> member method. This does just what you think it does.</para>
266
267 </section>
268 </chapter>
269
270 <chapter xml:id="chapter-writing">
271 <info><title>Writing your own signals</title></info>
272
273 <section xml:id="sect-quick-recap">
274 <info><title>Quick recap</title></info>
275
276         <para>If all you want to do is use gtkmm, and connect your functionality to its
277         signals, you can probably stop reading here.</para>
278
279         <para>You might benefit from reading on anyway though, as this section is going to
280         be quite simple, and the 'Rebinding' technique from the next section is
281         occasionally useful.</para>
282
283         <para>We've already covered the way the types of signals are made up, but lets
284         recap:</para>
285
286         <para>A signal is an instance of a template, named <literal remap="tt">sigc::signal</literal>.
287         The template arguments are the types,
288         in the order they appear in the function signature that can be connected to that
289         signal; that is the return type, then the argument types in parentheses.</para>
290
291         <para>To provide a signal for people to connect to, you must make available an
292         instance of that <literal remap="tt">sigc::signal</literal>. In <literal remap="tt">AlienDetector</literal> this was done
293         with a public data member. That's not considered good practice usually, so you
294         might want to consider making a member function that returns the signal by
295         reference. (This is what gtkmm does.)</para>
296
297         <para>Once you've done this, all you have to do is emit the signal when you're
298         ready. Look at the code for <literal remap="tt">AlienDetector::run()</literal>:</para>
299
300 <programlisting>
301 void AlienDetector::run()
302 {
303     sleep(3); // wait for aliens
304     signal_detected.emit(); // panic!
305 }
306 </programlisting>
307
308         <para>As a shortcut, <literal remap="tt">sigc::signal</literal> defines <literal remap="tt">operator()</literal> as a synonym for
309         <literal remap="tt">emit()</literal>, so you could just write <literal remap="tt">signal_detected();</literal> as in the second
310         example version:</para>
311
312 <programlisting>
313 void AlienDetector::run()
314 {
315     sleep(3);                // wait for aliens
316     signal_detected("the carpark"); // this is the std::string version, looks like
317                              // they landed in the carpark after all.
318 }
319 </programlisting>
320 </section>
321
322 <section xml:id="sect-return-values">
323 <info><title>What about return values?</title></info>
324
325         <para>If you only ever have one slot connected to a signal, or if you only care
326         about the return value of the last registered one, it's quite straightforward:</para>
327
328 <programlisting>
329 sigc::signal&lt;int()&gt; somesignal;
330 int a_return_value;
331
332 a_return_value = somesignal.emit();
333 </programlisting>
334 </section>
335 </chapter>
336
337 <chapter xml:id="chapter-advanced">
338 <info><title>Advanced topics</title></info>
339
340 <section xml:id="sect-rebinding">
341 <info><title>Rebinding</title></info>
342
343         <para>Suppose you already have a function that you want to be called when a
344         signal is emitted, but it takes the wrong argument types. For example, lets try
345         to attach the <literal remap="tt">warn_people(std::string)</literal> function to the detected signal
346         from the first example, which didn't supply a location string.</para>
347
348         <para>Just trying to connect it with:</para>
349
350 <programlisting>
351 myaliendetector.signal_detected.connect(sigc::ptr_fun(warn_people));
352 </programlisting>
353
354         <para>results in a compile-time error, because the types don't match. This is good!
355         This is typesafety at work. In the C way of doing things, this would have just
356         died at runtime after trying to print a random bit of memory as the location -
357         ick!</para>
358
359         <para>We have to make up a location string, and bind it to the function, so that
360         when signal_detected is emitted with no arguments, something adds it in before
361         <literal remap="tt">warn_people</literal> is actually called.</para>
362         <para>We could write it ourselves - it's not hard:</para>
363
364 <programlisting>
365 void warn_people_wrapper() // note this is the signature that 'signal_detected' expects
366 {
367     warn_people("the carpark");
368 }
369 </programlisting>
370
371         <para>but after our first million or so we might start looking for a better way. As
372         it happens, libsigc++ has one.</para>
373
374 <programlisting>
375 sigc::bind(slot, arg);
376 </programlisting>
377
378         <para>binds arg as the argument to slot, and returns a new slot of the same return
379         type, but with one fewer arguments.</para>
380
381         <para>Now we can write:</para>
382 <programlisting>
383 myaliendetector.signal_detected.connect(sigc::bind( sigc::ptr_fun(warn_people), "the carpark" ) );
384 </programlisting>
385
386         <para>If the input slot has multiple args, the rightmost one is bound.</para>
387
388         <para>The return type can also be bound with <literal remap="tt">sigc::bind_return(slot, returnvalue);</literal> though
389         this is not so commonly useful.</para>
390
391         <para>So if we can attach the new <literal remap="tt">warn_people()</literal> to the old detector, can we attach
392         the old <literal remap="tt">warn_people</literal> (the one that didn't take an argument) to the new detector?</para>
393
394         <para>Of course, we just need to hide the extra argument. This can be done with
395         <literal remap="tt">sigc::hide</literal>, eg.</para>
396
397 <programlisting>
398 myaliendetector.signal_detected.connect( sigc::hide&lt;std::string&gt;( sigc::ptr_fun(warn_people) ) );
399 </programlisting>
400
401         <para>The template arguments are the types to hide (from the right only - you can't
402         hide the first argument of 3, for example, only the last).</para>
403
404         <para><literal remap="tt">sigc::hide_return</literal> effectively makes the return type void.</para>
405 </section>
406
407 <section xml:id="sect-retyping">
408 <info><title>Retyping</title></info>
409
410         <para>A similar topic is retyping. Perhaps you have a signal that takes an <literal remap="tt">int</literal>, but
411         you want to connect a function that takes a <literal remap="tt">double</literal>.</para>
412
413         <para>This can be achieved with the <literal remap="tt">sigc::retype()</literal> template.
414         It takes a <literal remap="tt">sigc::slot</literal>, and returns a <literal remap="tt">sigc::slot</literal>. eg.</para>
415
416 <programlisting>
417 void dostuff(double foo)
418 {
419 }
420
421 sigc::signal&lt;void(int)&gt; asignal;
422
423 asignal.connect( sigc::retype( sigc::ptr_fun(&amp;dostuff) ) );
424 </programlisting>
425
426         <para>If you only want to change the return type, you can use <literal remap="tt">sigc::retype_return()</literal>.
427         <literal remap="tt">retype_return()</literal> needs one template argument, the new return type.</para>
428 </section>
429 </chapter>
430
431 <chapter xml:id="chapter-reference">
432 <info><title>Reference</title></info>
433
434         <para>See the reference documentation <link xlink:href="http://library.gnome.org/devel/libsigc++/2.10/">online</link></para>
435 </chapter>
436 </book>