Threads
<!-- ##### SECTION Short_Description ##### -->
-
+Functions for using GDK in multi-threaded programs
<!-- ##### SECTION Long_Description ##### -->
<para>
+For thread safety, GDK relies on the thread primitives in GLib,
+and on the thread-safe GLib main loop.
+</para>
+<para>
+GLib is completely thread safe (all global data is automatically
+locked), but individual data structure instances are not automatically
+locked for performance reasons. So e.g. you must coordinate
+accesses to the same #GHashTable from multiple threads.
+</para>
+<para>
+GTK+ is "thread aware" but not thread safe — it provides a
+global lock controlled by gdk_threads_enter()/gdk_threads_leave()
+which protects all use of GTK+. That is, only one thread can use GTK+
+at any given time.
+</para>
+<para>
+Unfortunately the above holds with the X11 backend only. With the
+Win32 backend, GDK calls should not be attempted from multiple threads
+at all.
+</para>
+<para>
+You must call g_thread_init() and gdk_threads_init() before executing
+any other GTK+ or GDK functions in a threaded GTK+ program.
+</para>
+<para>
+Idles, timeouts, and input functions from GLib, such as g_idle_add(), are
+executed outside of the main GTK+ lock.
+So, if you need to call GTK+ inside of such a callback, you must surround
+the callback with a gdk_threads_enter()/gdk_threads_leave() pair or use
+gdk_threads_add_idle_full() which does this for you.
+However, event dispatching from the mainloop is still executed within
+the main GTK+ lock, so callback functions connected to event signals
+like GtkWidget::button-press-event, do not need thread protection.
+</para>
+<para>
+In particular, this means, if you are writing widgets that might
+be used in threaded programs, you <emphasis>must</emphasis> surround
+timeouts and idle functions in this matter.
+</para>
+<para>
+As always, you must also surround any calls to GTK+ not made within
+a signal handler with a gdk_threads_enter()/gdk_threads_leave() pair.
+</para>
+
+<para>
+Before calling gdk_threads_leave() from a thread other
+than your main thread, you probably want to call gdk_flush()
+to send all pending commands to the windowing system.
+(The reason you don't need to do this from the main thread
+is that GDK always automatically flushes pending commands
+when it runs out of incoming events to process and has
+to sleep while waiting for more events.)
+</para>
+
+<para>A minimal main program for a threaded GTK+ application
+looks like:</para>
+
+<informalexample>
+<programlisting role="C">
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ g_thread_init (NULL);
+ gdk_threads_init (<!-- -->);
+ gdk_threads_enter (<!-- -->);
+
+ gtk_init (&argc, &argv);
+
+ window = create_window (<!-- -->);
+ gtk_widget_show (window);
+
+ gtk_main (<!-- -->);
+ gdk_threads_leave (<!-- -->);
+
+ return 0;
+}
+</programlisting>
+</informalexample>
+
+<para>
+Callbacks require a bit of attention. Callbacks from GTK+ signals
+are made within the GTK+ lock. However callbacks from GLib (timeouts,
+IO callbacks, and idle functions) are made outside of the GTK+
+lock. So, within a signal handler you do not need to call
+gdk_threads_enter(), but within the other types of callbacks, you
+do.
</para>
+<para>Erik Mouw contributed the following code example to
+illustrate how to use threads within GTK+ programs.
+</para>
+
+<informalexample>
+<programlisting role="C">
+/*-------------------------------------------------------------------------
+ * Filename: gtk-thread.c
+ * Version: 0.99.1
+ * Copyright: Copyright (C) 1999, Erik Mouw
+ * Author: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
+ * Description: GTK threads example.
+ * Created at: Sun Oct 17 21:27:09 1999
+ * Modified by: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
+ * Modified at: Sun Oct 24 17:21:41 1999
+ *-----------------------------------------------------------------------*/
+/*
+ * Compile with:
+ *
+ * cc -o gtk-thread gtk-thread.c `gtk-config --cflags --libs gthread`
+ *
+ * Thanks to Sebastian Wilhelmi and Owen Taylor for pointing out some
+ * bugs.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <pthread.h>
+
+#define YES_IT_IS (1)
+#define NO_IT_IS_NOT (0)
+
+typedef struct
+{
+ GtkWidget *label;
+ int what;
+} yes_or_no_args;
+
+G_LOCK_DEFINE_STATIC (yes_or_no);
+static volatile int yes_or_no = YES_IT_IS;
+
+void destroy (GtkWidget *widget, gpointer data)
+{
+ gtk_main_quit (<!-- -->);
+}
+
+void *argument_thread (void *args)
+{
+ yes_or_no_args *data = (yes_or_no_args *)args;
+ gboolean say_something;
+
+ for (;;)
+ {
+ /* sleep a while */
+ sleep(rand(<!-- -->) / (RAND_MAX / 3) + 1);
+
+ /* lock the yes_or_no_variable */
+ G_LOCK(yes_or_no);
+
+ /* do we have to say something? */
+ say_something = (yes_or_no != data->what);
+
+ if(say_something)
+ {
+ /* set the variable */
+ yes_or_no = data->what;
+ }
+
+ /* Unlock the yes_or_no variable */
+ G_UNLOCK (yes_or_no);
+
+ if (say_something)
+ {
+ /* get GTK thread lock */
+ gdk_threads_enter (<!-- -->);
+
+ /* set label text */
+ if(data->what == YES_IT_IS)
+ gtk_label_set_text (GTK_LABEL (data->label), "O yes, it is!");
+ else
+ gtk_label_set_text (GTK_LABEL (data->label), "O no, it isn't!");
+
+ /* release GTK thread lock */
+ gdk_threads_leave (<!-- -->);
+ }
+ }
+
+ return NULL;
+}
+
+int main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *label;
+ yes_or_no_args yes_args, no_args;
+ pthread_t no_tid, yes_tid;
+
+ /* init threads */
+ g_thread_init (NULL);
+ gdk_threads_init (<!-- -->);
+ gdk_threads_enter (<!-- -->);
+
+ /* init gtk */
+ gtk_init(&argc, &argv);
+
+ /* init random number generator */
+ srand ((unsigned int) time (NULL));
+
+ /* create a window */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+ /* create a label */
+ label = gtk_label_new ("And now for something completely different ...");
+ gtk_container_add (GTK_CONTAINER (window), label);
+
+ /* show everything */
+ gtk_widget_show (label);
+ gtk_widget_show (window);
+
+ /* create the threads */
+ yes_args.label = label;
+ yes_args.what = YES_IT_IS;
+ pthread_create (&yes_tid, NULL, argument_thread, &yes_args);
+
+ no_args.label = label;
+ no_args.what = NO_IT_IS_NOT;
+ pthread_create (&no_tid, NULL, argument_thread, &no_args);
+
+ /* enter the GTK main loop */
+ gtk_main (<!-- -->);
+ gdk_threads_leave (<!-- -->);
+
+ return 0;
+}
+</programlisting>
+</informalexample>
+
<!-- ##### SECTION See_Also ##### -->
<para>
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
<!-- ##### MACRO GDK_THREADS_ENTER ##### -->
<para>
-
+This macro marks the beginning of a critical section in which GDK and
+GTK+ functions can be called safely and without causing race
+conditions. Only one thread at a time can be in such a critial
+section. The macro expands to a no-op if #G_THREADS_ENABLED has not
+been defined. Typically gdk_threads_enter() should be used instead of
+this macro.
</para>
<!-- ##### MACRO GDK_THREADS_LEAVE ##### -->
<para>
+This macro marks the end of a critical section
+begun with #GDK_THREADS_ENTER.
+</para>
+
+
+
+<!-- ##### FUNCTION gdk_threads_init ##### -->
+<para>
</para>
+@void:
<!-- ##### FUNCTION gdk_threads_enter ##### -->
<para>
-
+This macro marks the beginning of a critical section in which GDK and
+GTK+ functions can be called safely and without causing race
+conditions. Only one thread at a time can be in such a critial
+section.
</para>
+@void:
<!-- ##### FUNCTION gdk_threads_leave ##### -->
<para>
-
+Leaves a critical region begun with gdk_threads_enter().
</para>
+@void:
<!-- ##### VARIABLE gdk_threads_mutex ##### -->
<para>
+The #GMutex used to implement the critical region for
+gdk_threads_enter()/gdk_threads_leave().
+</para>
+
+
+<!-- ##### FUNCTION gdk_threads_set_lock_functions ##### -->
+<para>
+
+</para>
+
+@enter_fn:
+@leave_fn:
+
+
+<!-- ##### FUNCTION gdk_threads_add_idle ##### -->
+<para>
</para>
+@function:
+@data:
+@Returns:
+
+
+<!-- ##### FUNCTION gdk_threads_add_idle_full ##### -->
+<para>
+
+</para>
+
+@priority:
+@function:
+@data:
+@notify:
+@Returns:
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout ##### -->
+<para>
+
+</para>
+
+@interval:
+@function:
+@data:
+@Returns:
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout_full ##### -->
+<para>
+
+</para>
+
+@priority:
+@interval:
+@function:
+@data:
+@notify:
+@Returns:
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout_seconds ##### -->
+<para>
+
+</para>
+
+@interval:
+@function:
+@data:
+@Returns:
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout_seconds_full ##### -->
+<para>
+
+</para>
+
+@priority:
+@interval:
+@function:
+@data:
+@notify:
+@Returns:
+