]> Pileus Git - ~andy/gtk/blob - docs/reference/gtk/other_software.sgml
half-finished docs on merging GTK with existing hunks of code (event loop
[~andy/gtk] / docs / reference / gtk / other_software.sgml
1 <refentry id="gtk-other-software" revision="5 Sept 2001">
2 <refmeta>
3 <refentrytitle>Mixing GTK+ with other software</refentrytitle>
4 <manvolnum>3</manvolnum>
5 <refmiscinfo>Mixing GTK+ with other software</refmiscinfo>
6 </refmeta>
7
8 <refnamediv>
9 <refname>Mixing GTK+ with other software</refname>
10 <refpurpose>
11 How to combine GTK+ with other code and event loops
12 </refpurpose>
13 </refnamediv>
14
15 <refsect1>
16 <title>Overview</title>
17
18 <para>
19 Often people want to use GTK+ in combination with another library or existing 
20 body of code that is not GTK+-aware. The general problem people encounter 
21 is that the control flow of the other code does not return to GTK+, so 
22 widgets do not repaint, mouse and keyboard events are ignored, and so forth.
23 </para>
24
25 <para>
26 This section describes some approaches to solving this problem. The most
27 suitable approach depends on the code that's involved, the platforms you're
28 targetting, and your own familiarity with each approach.
29 </para>
30
31 </refsect1>
32
33 <refsect1>
34 <title>Periodically yield to GTK+ main loop</title>
35
36 <para>
37 This is the simplest method, but requires you to modify the non-GTK+ code.
38 Say you have a function that does some kind of lengthy task:
39 <informalexample>
40 <programlisting>
41   void
42   do_lengthy_task (void)
43   {
44      int i;
45      for (i = 0; i &lt; BIG_NUMBER; ++i)
46        {
47          do_small_part_of_task ();
48        }
49   }
50 </programlisting>
51 </informalexample>
52 You simply insert code into this function that processes pending main loop tasks, if any:
53 <informalexample>
54 <programlisting>
55   void
56   do_lengthy_task (void)
57   {
58      int i;
59      for (i = 0; i &lt; BIG_NUMBER; ++i)
60        {
61          do_small_part_of_task ();
62
63          /* allow main loop to process pending events; NULL 
64           * means the default context. 
65           */
66          while (g_main_context_pending (NULL))
67            g_main_context_iteration (NULL, FALSE);
68        }
69   }
70 </programlisting>
71 </informalexample>
72 </para>
73
74 <para>
75 The primary disadvantage of this approach is that you have to trade off UI
76 responsiveness and the performance of the task. That is, if
77 do_small_part_of_task() does very little of the task, you'll spend lots of CPU
78 time on <link
79 linkend="g-main-context-iteration">g_main_context_iteration()</link>. While if
80 do_small_part_of_task() does a lot of work, the GUI will seem noticeably
81 "chunky" to the user.
82 </para>
83
84 <para>
85 Another disadvantage to this approach is that you can't have more than one
86 lengthy task at the same time, unless you manually integrate them.
87 </para>
88
89 <para>
90 The big advantage of this approach is that it's simple and straightforward, and
91 works fine for simple applications such as tossing up a progress bar during the
92 lengthy task.
93 </para>
94
95 </refsect1>
96
97 <refsect1>
98 <title>Run the other code as a slave of the GTK+ main loop</title>
99
100 <para>
101 As a slightly cleaner solution, you can ask the main loop to run a small part of your 
102 task whenever it isn't busy &mdash; that is, when it's <firstterm>idle</firstterm>.
103 GLib provides a function <link linkend="g-idle-add">g_idle_add()</link> that's useful 
104 for this. An "idle handler" added with <link linkend="g-idle-add">g_idle_add()</link>
105 will be run continuously as long as it returns <literal>TRUE</literal>. However, 
106 the main loop gives higher priority to GUI-related tasks, so will run those instead
107 when appropriate.
108 </para>
109
110 <para>
111 Here's a simple example:
112 <informalexample>
113 <programlisting>
114   gboolean
115   my_idle_handler (gpointer user_data)
116   {
117     do_small_part_of_task ();
118   
119     if (task_complete)
120       return FALSE; /* removes the idle handler */
121     else
122       return TRUE;  /* runs the idle handler again */
123   }
124
125   g_idle_add (my_idle_handler, NULL);
126 </programlisting>
127 </informalexample>
128 </para>
129
130 <para>
131 If your task involves reading data from the network, you should instead use
132 <link linkend="g-input-add">g_input_add()</link>; this will allow the 
133 main loop to sleep until data is available on a file descriptor, then 
134 wake up to read that data.
135 </para>
136
137 <para>
138 <link linkend="g-idle-add">g_idle_add()</link> returns a main loop source ID you can 
139 use to remove the idle handler with <link linkend="g-source-remove">g_source_remove()</link>.
140 This is useful for cancelling a task, for example. Another approach is to keep a flag 
141 variable and have the idle handler itself return <literal>FALSE</literal> when appropriate.
142 </para>
143
144 </refsect1>
145
146 <refsect1>
147 <title>Use multiple processes</title>
148
149 <para>
150 If you can't break a task into small chunks &mdash; the
151 "do_small_part_of_task()" function in the above examples &mdash; you'll have to
152 separate your program into two parts, by spawning a child thread or process.
153 A process does not share the same address space (variables and data) with its parent.
154 A thread does share the same address space, so a change made to a variable in 
155 one thread will be visible to other threads as well.
156 </para>
157
158 <para>
159 This manual can't go into full detail on processes, threads, and other UNIX
160 programming topics.  You may wish to get a book or two &mdash; two I'm familiar
161 with are Beginning Linux Programming (WROX Press) and Advanced Programming in
162 the UNIX Environment (by Richard Stevens.
163 </para>
164
165 <para>
166 Those books also cover the central issue you'll need to address in order to have
167 a multi-process application: how to communicate between the processes. The
168 simplest solution is to use pipes; <link
169 linkend="g-input-add">g_input_add()</link> in combination with <link
170 linkend="g-spawn-async-with-pipes">g_spawn_async_with_pipes()</link> should make
171 this reasonably convenient. There are other possibilities, of course, such as
172 sockets, shared memory, and X Window System client message events, depending on
173 your needs.
174 </para>
175
176 </refsect1>
177
178
179 <refsect1>
180 <title>Use multiple threads</title>
181
182 <para>
183
184 </para>
185
186 </refsect1>
187
188 <refsect1>
189 <title>Integrate the GTK+ main loop with another main loop</title>
190
191 <para>
192 </para>
193
194 </refsect1>
195
196
197 <refsect1>
198 <title>Things that won't work</title>
199
200 <para>
201 signals
202 </para>
203
204 </refsect1>
205
206
207 </refentry>