summaryrefslogtreecommitdiff
path: root/doc/ivy-c.sgml
blob: 7365746be2db6a49f1d84156ce56f77d2f0c7ccd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
<!--
	The Ivy C guide

	Copyright (c) 1999-2000
	Centre d'Etudes de la Navigation Aerienne

	SGML source file

	Authors: Stéphane Chatty <chatty@cena.dgac.fr>

	$Id$

	Please refer to file version.h for the
	copyright notice regarding this software
-->


<?xml version='1.0' ?>
<!doctype article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">

<article>
<artheader>

<title>The Ivy C library guide</title>

<authorgroup>
<author>
<firstname>Francois-Régis</firstname><surname>Colin</surname>
<affiliation><address><email>fcolin@cena.fr</email></address></affiliation>
</author>
<author>
<firstname>Stéphane</firstname><surname>Chatty</surname>
<affiliation><address><email>chatty@cena.fr</email></address></affiliation>
</author>
<author>
<firstname>Yannick</firstname><surname>Jestin</surname>
<affiliation><address><email>jestin@cena.fr</email></address></affiliation>
</author>
</authorgroup>
<date>December 11, 2002</date>

<copyright>
<year>1998-2002</year>
<holder>Centre d'Études de la Navigation Aérienne</holder>
</copyright>

<abstract>
<para>
This document is a programmer's guide that describes how to use the Ivy C
library to connect applications to an Ivy bus. This guide describes version 3.2
of the library.
</para>
</abstract>
</artheader>

<sect1>
<title>Foreword</title>

<para>
This document was written in SGML according to the DocBook DTD, so as to be able to
generate PDF and html output. However, the authors have not yet mastered the
intricacies of SGML, the DocBook DTD, the DocBook Stylesheets and the related
tools, which have achieved the glorious feat of being far more complex than
LaTeX and Microsoft Word combined together. This explains why this document, in addition
to being incomplete, is so ugly. We'll try and improve it.
</para>
</sect1>


<sect1>
<title>What is Ivy?</title>

<para>
Ivy is a software bus designed at CENA (France). A software bus is a system 
that allows software applications to exchange information with the illusion of
broadcasting that information, selection being performed by the receiving
applications. Using a software bus is very similar to dealing with events in a
graphical toolkit: on one side, messages are emitted without caring about who
will handle them, and on the other side, one decide to handle the messages that
have a certain type or follow a certain pattern. Software buses are mainly aimed 
at facilitating the rapid development of new agents, and at managing a dynamic
collection of agents on the bus: agents show up, emit messages and receive some, 
then leave the bus without blocking the others.
</para>

<para>
Ivy is implemented as a collection of libaries for several languages and
platforms. If you want to read more about the principles Ivy before reading this guide of the C 
library, please refer to <citetitle>The Ivy sofware bus: a white
paper</citetitle>. If you want more details about the internals of Ivy, have a
look at <citetitle>The Ivy architecture and protocol</citetitle>. And finally,
if you are more interested in other languages, refer to other guides such as
<citetitle>The Ivy Perl library guide</citetitle>. All those documents should be 
available from the Ivy Web site at <ulink URL="http://www.tls.cena.fr/products/ivy/">http://www.tls.cena.fr/products/ivy/</ulink>.
</para>
</sect1>

<sect1>
<title>The Ivy C library</title>
<sect2>
<title>What is it?</title>
<para>
The Ivy C library (aka Ivy-C or ivy-c) is a C library that allows you to connect 
applications to an Ivy bus. You can use it to write applications in C or any
other language that supports C extensions. You can also use it to integrate an
application that already has a main loop (such as a GUI application) within an
Ivy bus. This guide is here to help you do that.
</para>

<para>
The Ivy C library is known to compile and work in WindowsNT and Linux
environments. It should be easy to use on most Posix environments. 
</para>

<para>
The Ivy C library was originally developed by François-Régis Colin at CENA. It
is maintained by a group at CENA (Toulouse, France)
</para>
</sect2>

<sect2>
<title>Getting and installing the Ivy C library</title>

<para>
You can get the latest versions of the Ivy C library from CENA
(<ulink URL="http://www.tls.cena.fr/products/ivy/">http://www.tls.cena.fr/products/ivy/</ulink>). Depending on whether you
use a supported binary distribution, you can retrieve binary RPM or
Debian packages for Linux (do not forget to get the development package as well as the
run-time package), or retrieve the source files and compile them.
</para>
</sect2>

</sect1>

<sect1>
<title>Your first Ivy application</title>
<para>
We are going to write a "Hello world translater" for an Ivy bus. The application 
will subscribe to all messages starting with "Hello", and re-emit them after
translating "Hello" into "Bonjour". In addition, the application will quit when
it receives any message containing exactly "Bye".
</para>

<sect2>
<title>The code</title>
<para>
Here is the code of "hellotranslater.c":


<programlisting>
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;getopt.h&gt;
#include &lt;ivy.h&gt;
#include &lt;ivyloop.h&gt;

/* callback associated to "Hello" messages */
void HelloCallback (IvyClientPtr app, void *data, int argc, char **argv)
{
	const char* arg = (argc &lt; 1) ? "" : argv[0];
	IvySendMsg ("Bonjour%s", arg);
}

/* callback associated to "Bye" messages */
void ByeCallback (IvyClientPtr app, void *data, int argc, char **argv)
{
	IvyStop ();
}

main (int argc, char**argv)
{
	/* handling of -b option */
	const char* bus = 0;
	char c;
	while (c = getopt (argc, argv, "b:") != EOF) {
		switch (c) {
		case 'b':
			bus = optarg;
			break;
		}
	}

	/* handling of environment variable */
	if (!bus)
		bus = getenv ("IVYBUS");

	/* initializations */
	IvyInit ("IvyTranslater", "Hello le monde", 0, 0, 0, 0);
	IvyStart (bus);

	/* binding of HelloCallback to messages starting with 'Hello' */
	IvyBindMsg (HelloCallback, 0, "^Hello(.*)");

	/* binding of ByeCallback to 'Bye' */
	IvyBindMsg (ByeCallback, 0, "^Bye$");

	/* main loop */
	IvyMainLoop (0);
}

</programlisting>
</para>

</sect2>

<sect2>
<title>Compiling it</title>
<para>
On a Unix computer, you should be able to compile the application with the
following command:
<screen>
$ <userinput>cc -o ivytranslater ivytranslater.c -livy</userinput>
$
</screen>
</para>
</sect2>


<sect2>
<title>Testing</title>
<para>
We are going to test our application with <command>ivyprobe</command>. In a
terminal window, launch <command>ivytranslater</command>.
<screen>
$ <userinput>ivytranslater</userinput>

</screen>
Then in another
terminal window, launch <command>ivyprobe '(.*)'</command>. You are then ready
to start. Type "Hello Paul", and you should get "Bonjour Paul". Type "Bye", and
your application should quit:
<screen>
$ <userinput>ivyprobe '(.*)'</userinput>
IvyTranslater connected from localhost
IvyTranslater subscribes to 'Hello (.*)'
IvyTranslater subscribes to 'Bye'
<userinput>Hello Paul</userinput>
IvyTranslater sent 'Bonjour Paul'
<userinput>Bye</userinput>
IvyTranslater disconnected from localhost
<userinput>&lt;Ctrl-D&gt;</userinput>
$
</screen>

</para>
</sect2>
</sect1>

<sect1>
<title>Basic functions</title>

<sect2>
<title>Initialization and main loop</title>
<para>
Initializing an Ivy agent with the Ivy C library is a two step process. First of 
all, you should initialize the library by calling function <function>IvyInit</function>. Once
the library is initialized you can create timers and add subscriptions, but your 
agent is still not connected to any bus. In order to connect, you should call
function <function>IvyStart</function>. In theory, initialization is then over. However in
practice, as for any asynchronous communication or interaction library, nothing
happens until your application has reached the main loop.
</para>
<para>
The Ivy C library provides its own main loop: <function>IvyMainLoop</function>. You should use
it unless you already use a toolkit that provides its own main loop and you want 
to use that one. If it is the case, please refer to section XX. Otherwise, just
call <function>IvyMainLoop</function>. From within the main loop, you can call <function>IvyStop</function> to
exit the loop.
</para>
<para>
Here are more details on those functions:

<programlisting>
void IvyInit (const char* agentname,
			const char* ready_msg,
			IvyApplicationCallback app_cb,
			void *app_data,
			IvyDieCallback die_cb,
			void *die_data);
</programlisting>
initializes the library.
<parameter>agentname</parameter> is the name of your application on the Ivy
bus. It will be transmitted to other applications and possibly used by them, as
does <command>ivyprobe</command>.
<parameter>ready_msg</parameter> is the first message that is going to be sent
to peer applications, bypassing the normal broadcasting scheme of Ivy (see
<citetitle>The Ivy architecture and protocol</citetitle> for more details). If a zero
value is passed, no message will be sent.
<parameter>app_cb</parameter> is a callback that will be called every time a new
peer is detected. If a zero value is passed, no callback is called.
<parameter>app_data</parameter> is a pointer that will be passed to the
application-connection callback.
<parameter>die_cb</parameter> is a callback that will be called every time a
peer disconnects. If a zero value is passed, no callback is called.
<parameter>die_data</parameter> is a pointer that will be passed to the
application-disconnection callback.

<programlisting>
void IvyStart (const char* bus);
</programlisting>
connects your application to the bus specified in
<parameter>bus</parameter>. The string provided should follow the convention
described in section XX. Example:
<parameter>"10.192.33,10.192.34:2345"</parameter>. If a null value is passed,
the library will use the value of the environment variable
<parameter>IVYBUS</parameter>, which should have the same syntax. If the
environment variable is not defined, the default value
<parameter>"127:2010"</parameter> is used.

<programlisting>
void IvyMainLoop (void (*hook) (void));
</programlisting>
makes your application enter the main loop in which it will handle asynchronous
communications and signals. This is the default Ivy main loop, based on the
<function>select</function> POSIX system call.
If non-null, <parameter>hook</parameter> is called every time the main loop is
about to enter <function>select</function>, and can be used (with care!) to
extend the main loop.

<programlisting>
void IvyStop ();
</programlisting>
makes your application exit the main loop.

</para>
</sect2>

<sect2>
<title>Emitting messages</title>
<para>
Emitting a message on an Ivy bus is much like printing a message on the standard 
output. However, do not forget that your message will not be emitted if Ivy has
not been properly initialized and if you do not have a main loop of some sort
running. To emit a message, use <function>IvySendMsg</function>, which works like <function>printf</function>:

<programlisting>
void IvySendMsg (const char* format, ...);
</programlisting>
sends a message on the bus. This function has exactly the same behaviour as
<function>printf</function>, <function>sprintf</function> or <function>fprintf</function>.

</para>
</sect2>

<sect2>
<title>Subscribing to messages</title>
<para>
Subscribing to messages consists in binding a callback function to a message
pattern. Patterns are described by regular expressions with captures. When a
message matching the regular expression is detected on the bus, the callback
function is called. The captures (ie the bits of the message that match the
parts of regular expression delimited by brackets) are passed to the callback
function much like options are passed to <function>main</function>. Use function <function>IvyBindMsg</function> 
to bind a callback to a pattern, and function <function>IvyUnbindMsg</function> to delete the
binding.


<programlisting>
MsgRcvPtr IvyBindMsg (MsgCallback cb,
		void* data,
		const char* regex_format, ...);
</programlisting>
binds callback function <function>cb</function> to the regular expression specified by
<parameter>regex_format</parameter> and the optional following arguments. <parameter>regex_format</parameter> and
the following arguments are handled as in <function>printf</function>. The return
value is an identifier that can be used later for cancelling the subscription.

<programlisting>
void IvyUnbindMsg (MsgRcvPtr id);
</programlisting>
deletes the binding specified by <parameter>id</parameter>.
</para>

<para>
In what precedes, <type>MsgRcvPtr</type> is an opaque type used to identify bindings,
<parameter>data</parameter> is a user pointer passed to the callback whenever it is called, and
<parameter>MsgCallback</parameter> is defined as follows:
<programlisting>
typedef void (*MsgCallback)(IvyClientPtr app, void *data, int argc, char **argv);
</programlisting>

</para>
</sect2>
</sect1>


<sect1>
<title>Advanced functions</title>

<sect2>
<title>Utilities</title>
<para>
[to be written]
</para>
</sect2>

<sect2>
<title>Direct messages</title>
<para>
[to be written]
</para>
</sect2>

<sect2>
<title>Managing timers and other channels</title>
<para>

In your applications, you may need to manage other input/output channels than an
Ivy bus: a serial driver, the channels defined by a graphical toolkit, or simply 
stdin and stdout. The same applies for timers. You can either manage those
channels or timers from the Ivy main loop, or instead use the main loop provided by
another library.
</para>

<sect3>
<title>Channels</title>
<para>
You can get a channel to be managed from the Ivy main loop by using functions
<function>IvyChannelSetUp</function> and <function>IvyChannelClose</function>.
<programlisting>
Channel IvyChannelSetUp (HANDLE fd,
			void* data,
			ChannelHandleDelete handle_delete,
			ChannelHandleRead handle_read);
</programlisting>
ensures that function <function>handle_read</function> is called whenever data is read on file
descriptor <parameter>fd</parameter>, and function <parameter>handle_delete</parameter> whenever <parameter>fd</parameter> is
closed, and

<programlisting>
void IvyChannelClose (Channel ch);
</programlisting>
terminates the management of channel <parameter>ch</parameter>.
</para>

<para>
In what precedes, <type>Channel</type> is an opaque type defined by the Ivy C
library, <parameter>data</parameter> is a pointer that will be passed to
functions <function>handle_read</function> and
<function>handle_delete</function>. It can be defined at will by users.  The
types <type>HANDLE</type>, <type>ChannelHandleDelete</type> and
<type>ChannelHandleRead</type> are as follows:

<programlisting>
typedef int HANDLE; (for Unix)
typedef SOCKET HANDLE; (for Windows)
typedef void (*ChannelHandleDelete)(void *data);
typedef void (*ChannelHandleRead)(Channel ch, HANDLE fd, void* data);
</programlisting>
</para>
</sect3>

<sect3>
<title>Adding timers</title>
<para>
You can get a function to be repeatedly called by using function
<function>TimerRepeatAfter</function>:

<programlisting>
TimerId TimerRepeatAfter (int nbticks, long delay, TimerCb handle_timer, void* data);
</programlisting>
ensures that function <parameter>handle_timer</parameter> is called <parameter>nbticks</parameter> times at
intervals of <parameter>delay</parameter> seconds, thus creating a timer.

<programlisting>
void TimerModify (TimerId id, long delay);
</programlisting>
changes the delay used for timer <parameter>id</parameter>.

<programlisting>
void TimerRemove (TimerId id);
</programlisting>
deletes timer <parameter>id</parameter>, thus stopping it.
</para>

<para>
In what precedes, <parameter>data</parameter> is passed to <parameter>handle_timer</parameter> every time it is
called. <parameter>delay</parameter> is expressed in milliseconds.
If <parameter>nbticks</parameter> is set to <parameter>TIMER_LOOP</parameter>, then <parameter>handle_timer</parameter> will
be called forever. <type>TimerCb</type> is as follows:
<programlisting>
typedef void (*TimerCb)(TimerId id, void *data, unsigned long delta);
</programlisting>

</para>
</sect3>
</sect2>
</sect1>

<sect1>
<title>Conventions for writing applications</title>
<para>
In addition to the Ivy protocol, Ivy applications
should respect two conventions when used in a Posix environment:

<itemizedlist>
<listitem><para>They should accept the option <option>-b</option> or
<option>-bus</option> to specify the Ivy bus on which they will connect. The Ivy
C library provides no support for that.
</para>


<listitem><para>They should refer to the environment variable
<parameter>IVYBUS</parameter> when the above option is not used. With the Ivy C
library, this is obtained by passing a null value to <function>IvyStart</function></para>
</itemizedlist>
</para>
</sect1>

<sect1>
<title>Using Ivy with another main loop</title>
<para>
The ivyprobe source code holds examples of use of Ivy within other main loops,
namely Xt and Gtk.
</para>

<sect2>

<title>Using Ivy with the X Toolkit</title>
<para>The basics for using the Ivy withing the XtAppMainLoop() are the
following ones:
</para>

<itemizedlist>
<listitem><para>include the ivy.h and ivyxtloop.h</para>
<listitem><para>link with libxtivy.o ( add the <option>-lxtivy</option> ld flag and NOT the <option>-livy</option> )</para>
<listitem><para>create the ivy bus</para>
  <itemizedlist>
  <listitem><para>IvyXtChannelAppContect(app_context) with an existing Xt
  context</para>
  <listitem><para>You can add channels to be handled by Ivy, for instance,
  stdin, with the IvyXtChannelSetUp function
  <listitem><para>IvyInit(char *name,char *readyMessage,IvyApplicationCallback
  cb,void *cbUserData,IvyDieCallback dieCb,void *dieCbUserdata)</para>
  <listitem><para>IvyBindMsg() for the behavior</para>
  <listitem><para>IvyStart(char *domain)</para>
  </itemizedlist>
<listitem><para>run the Xt main loop with XtAppMainLoop(app_context)</para>
</itemizedlist>

<para>Here is an example, motifButtonIvy.c. You can compile it with the
following command line:
<programlisting>
cc -o motifButtonIvy motifButtonIvy.c -lxtivy
</programlisting>
The result is a simple single-buttoned application emitting a message on the
bus. The message defaults to "foo", but can be updated via an Ivy Button
text=bar message.

<programlisting>
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;strings.h&gt;
#include &lt;Xm/PushB.h&gt;
#include &lt;ivy.h&gt;
#include &lt;ivyxtloop.h&gt;

void myMotifCallback(Widget w,XtPointer client_d,XtPointer call_d){
  IvySendMsg (*((char**)client_d));
}
void textCallback(IvyClientPtr app, void *user_data, int argc, char *argv[]){
  *((char **)user_data)=argv[0];
}
void DieCallback (IvyClientPtr app, void *data, int id){
  exit(0);
}
int main(int argc,char *argv[]){
  Widget toplevel,pushb;
  XtAppContext app_context;
  Arg myargs[10];
  char *bus=getenv("IVYBUS");
  char *tosend="foo";
  toplevel=XtAppInitialize(&amp;app_context,"Ivy Button",NULL,0,&amp;argc,argv,NULL,myargs,0);
  pushb=XmCreatePushButton(toplevel,"send message",myargs,1);
  XtManageChild(pushb);
  XtAddCallback(pushb,XmNactivateCallback,myMotifCallback,&amp;tosend);
  XtRealizeWidget(toplevel);
  IvyXtChannelAppContext(app_context);
  IvyInit("IvyMotif","IvyMotif connected",NULL,NULL,DieCallback,NULL);
  IvyBindMsg(textCallback,&amp;tosend,"^Ivy Button text=(.*)");
  IvyStart(bus);
  XtAppMainLoop(app_context);
}
</programlisting>
</para>
</sect2>

<sect2>
<title>Using Ivy with Tcl/Tk</title>
<para>Just load the libtclivy.so package, and use the following commands
<programlisting>
#!/usr/bin/tclsh
Ivy::init $name $hellomessge connectproc dieproc
Ivy::start $domain
Ivy::bind $regexp ballback
Ivy::applist
Ivy::send $message
Ivy::applist
mainloop
</programlisting>
A full example in Tcl/Tk is provided here:
<programlisting>
#!/usr/bin/wish
load libtclivy.so.3.4
proc connect {args} { }
proc send { } {
  global tosend
  Ivy::send $tosend
}
proc dotext {text} {
  global tosend
  set tosend $text
}
Ivy::init "IvyTCLTK" "IvyTCLTK READY" connect echo
Ivy::start 127.255.255.255:2010
Ivy::bind "^Ivy Button text=(.*)" dotext
set tosend foo
button .send -command send -text "send msg"
pack .send
</programlisting>
</para>
</sect2>

<sect2>
<title>Using Ivy with Gtk</title>
<para>There is little to do to make your gtk applications Ivy aware: just add
the following lines into your code:
<programlisting>
#include &lt;ivy.h&gt;
#include &lt;ivygtkloop.h&gt;
...
IvyInit ("IvyGtkButton", "IvyGtkButton READY",NULL,NULL,NULL,NULL);
IvyBindMsg(textCallback,&amp;tosend,"^Ivy Button text=(.*)");
IvyStart (bus);
</programlisting>
</para>

<para>A full example: gtkIvyButton.c  is provided below, compile it with the
-lgtkivy flag. The other flags depend on your system installation ( replace
pkg-config with gtk-config for older gnome1 libs)
<programlisting>
#include &lt;gtk/gtk.h&gt;
#include &lt;ivy.h&gt;
#include &lt;ivygtkloop.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

void hello( GtkWidget *widget, gpointer   data ) {
  fprintf(stderr,"%s\n",*((char**)data));
  IvySendMsg(*((char**)data));
}

void textCallback(IvyClientPtr app, void *user_data, int argc, char *argv[]){
  *((char **)user_data)=argv[0];
}

int main( int   argc, char *argv[] ) {
    GtkWidget *window;
    GtkWidget *button;
    char *bus=getenv("IVYBUS");
    char *tosend="foo";
    gtk_init (&amp;argc, &amp;argv);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
    button = gtk_button_new_with_label ("send message");
    g_signal_connect (G_OBJECT(button),"clicked",G_CALLBACK(hello),&amp;tosend); 
    gtk_container_add (GTK_CONTAINER(window),button);
    gtk_widget_show (button);
    gtk_widget_show (window);
    IvyInit ("IvyGtkButton", "IvyGtkButton READY",NULL,NULL,NULL,NULL);
    IvyBindMsg(textCallback,&amp;tosend,"^Ivy Button text=(.*)");
    IvyStart (bus);
    gtk_main ();
    return 0;
}
</programlisting>
</sect2>

<sect2>
<title>Adding Ivy to another main loop</title>

<sect3>
<title>Functions to be provided</title>
<para>
You can decide to use the main loop from another toolkit than the X Toolkit
or the Tk toolkit. If you do that, you'll have to define three functions that
Ivy will use to get its own channels managed by the other toolkit. The three
following global variables should be defined:
<programlisting>
ChannelInit channel_init;
ChannelSetUp channel_setup;
ChannelClose channel_close;
</programlisting>

They should point to functions that respectively:
<itemizedlist>
<listitem><para> make the necessary global initializations before entering the main loop</para>
<listitem><para> initialize a channel and ensure that it is managed by the main loop</para>
<listitem><para> close a channel</para>
</itemizedlist>
</para>
<para>
The types <type>ChannelInit</type>, <type>ChannelSetUp</type> and <type>ChannelClose</type> are defined
as follows:

<programlisting>
typedef void (*ChannelInit)(void);
typedef Channel (*ChannelSetUp)(
        HANDLE fd,
        void *data,
        ChannelHandleDelete handle_delete,
        ChannelHandleRead handle_read);
typedef void (*ChannelClose)( Channel channel );
</programlisting>
</para>
</sect3>

<sect3>
<title>Type to be defined</title>
<para>
In order to implement the three previous functions, you will need to define the
hidden type <type>struct _channel</type> (the type <type>Channel</type> is
defined as <type>struct _channel*</type>). Use it to store the data provided by
the other toolkit.
</para>
</sect3>
</sect2>
</sect1>

<sect1>
<title>Contacting the authors</title>
<para>
The Ivy C library was mainly written by Francois-Régis Colin, with support
from Stéphane Chatty. For bug reports or comments on the library itself or
about this document, please send them an email: fcolin@cena.fr and
chatty@cena.fr. For comments and ideas about Ivy itself (protocol,
applications, etc), please use the Ivy mailing list: ivy@tls.cena.fr. 
</para>
</sect1>

</article>