]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
Work toward turning GdkDisplayManager into a backend singleton
[~andy/gtk] / gdk / gdk.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include "gdkmain.h"
30
31 #include "gdkinternals.h"
32 #include "gdkintl.h"
33
34 #ifndef HAVE_XCONVERTCASE
35 #include "gdkkeysyms.h"
36 #endif
37
38 #include <string.h>
39 #include <stdlib.h>
40
41
42 /**
43  * SECTION:general
44  * @Short_description: Library initialization and miscellaneous functions
45  * @Title: General
46  *
47  * This section describes the GDK initialization functions and miscellaneous
48  * utility functions.
49  */
50
51
52 typedef struct _GdkPredicate  GdkPredicate;
53
54 struct _GdkPredicate
55 {
56   GdkEventFunc func;
57   gpointer data;
58 };
59
60 typedef struct _GdkThreadsDispatch GdkThreadsDispatch;
61
62 struct _GdkThreadsDispatch
63 {
64   GSourceFunc func;
65   gpointer data;
66   GDestroyNotify destroy;
67 };
68
69
70 /* Private variable declarations
71  */
72 static int gdk_initialized = 0;                     /* 1 if the library is initialized,
73                                                      * 0 otherwise.
74                                                      */
75
76 static gchar  *gdk_progclass = NULL;
77
78 static GMutex *gdk_threads_mutex = NULL;            /* Global GDK lock */
79
80 static GCallback gdk_threads_lock = NULL;
81 static GCallback gdk_threads_unlock = NULL;
82
83 #ifdef G_ENABLE_DEBUG
84 static const GDebugKey gdk_debug_keys[] = {
85   {"events",        GDK_DEBUG_EVENTS},
86   {"misc",          GDK_DEBUG_MISC},
87   {"dnd",           GDK_DEBUG_DND},
88   {"xim",           GDK_DEBUG_XIM},
89   {"nograbs",       GDK_DEBUG_NOGRABS},
90   {"colormap",      GDK_DEBUG_COLORMAP},
91   {"input",         GDK_DEBUG_INPUT},
92   {"cursor",        GDK_DEBUG_CURSOR},
93   {"multihead",     GDK_DEBUG_MULTIHEAD},
94   {"xinerama",      GDK_DEBUG_XINERAMA},
95   {"draw",          GDK_DEBUG_DRAW},
96   {"eventloop",     GDK_DEBUG_EVENTLOOP}
97 };
98
99 static const int gdk_ndebug_keys = G_N_ELEMENTS (gdk_debug_keys);
100
101 #endif /* G_ENABLE_DEBUG */
102
103 #ifdef G_ENABLE_DEBUG
104 static gboolean
105 gdk_arg_debug_cb (const char *key, const char *value, gpointer user_data, GError **error)
106 {
107   guint debug_value = g_parse_debug_string (value,
108                                             (GDebugKey *) gdk_debug_keys,
109                                             gdk_ndebug_keys);
110
111   if (debug_value == 0 && value != NULL && strcmp (value, "") != 0)
112     {
113       g_set_error (error, 
114                    G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
115                    _("Error parsing option --gdk-debug"));
116       return FALSE;
117     }
118
119   _gdk_debug_flags |= debug_value;
120
121   return TRUE;
122 }
123
124 static gboolean
125 gdk_arg_no_debug_cb (const char *key, const char *value, gpointer user_data, GError **error)
126 {
127   guint debug_value = g_parse_debug_string (value,
128                                             (GDebugKey *) gdk_debug_keys,
129                                             gdk_ndebug_keys);
130
131   if (debug_value == 0 && value != NULL && strcmp (value, "") != 0)
132     {
133       g_set_error (error, 
134                    G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
135                    _("Error parsing option --gdk-no-debug"));
136       return FALSE;
137     }
138
139   _gdk_debug_flags &= ~debug_value;
140
141   return TRUE;
142 }
143 #endif /* G_ENABLE_DEBUG */
144
145 static gboolean
146 gdk_arg_class_cb (const char *key, const char *value, gpointer user_data, GError **error)
147 {
148   gdk_set_program_class (value);
149
150   return TRUE;
151 }
152
153 static gboolean
154 gdk_arg_name_cb (const char *key, const char *value, gpointer user_data, GError **error)
155 {
156   g_set_prgname (value);
157
158   return TRUE;
159 }
160
161 static const GOptionEntry gdk_args[] = {
162   { "class",        0, 0,                     G_OPTION_ARG_CALLBACK, gdk_arg_class_cb,
163     /* Description of --class=CLASS in --help output */        N_("Program class as used by the window manager"),
164     /* Placeholder in --class=CLASS in --help output */        N_("CLASS") },
165   { "name",         0, 0,                     G_OPTION_ARG_CALLBACK, gdk_arg_name_cb,
166     /* Description of --name=NAME in --help output */          N_("Program name as used by the window manager"),
167     /* Placeholder in --name=NAME in --help output */          N_("NAME") },
168   { "display",      0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING,   &_gdk_display_name,
169     /* Description of --display=DISPLAY in --help output */    N_("X display to use"),
170     /* Placeholder in --display=DISPLAY in --help output */    N_("DISPLAY") },
171   { "screen",       0, 0, G_OPTION_ARG_INT,      &_gdk_screen_number,
172     /* Description of --screen=SCREEN in --help output */      N_("X screen to use"),
173     /* Placeholder in --screen=SCREEN in --help output */      N_("SCREEN") },
174 #ifdef G_ENABLE_DEBUG
175   { "gdk-debug",    0, 0, G_OPTION_ARG_CALLBACK, gdk_arg_debug_cb,  
176     /* Description of --gdk-debug=FLAGS in --help output */    N_("GDK debugging flags to set"),
177     /* Placeholder in --gdk-debug=FLAGS in --help output */    N_("FLAGS") },
178   { "gdk-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, gdk_arg_no_debug_cb, 
179     /* Description of --gdk-no-debug=FLAGS in --help output */ N_("GDK debugging flags to unset"),
180     /* Placeholder in --gdk-no-debug=FLAGS in --help output */ N_("FLAGS") },
181 #endif 
182   { NULL }
183 };
184
185 /**
186  * gdk_add_option_entries_libgtk_only:
187  * @group: An option group.
188  * 
189  * Appends gdk option entries to the passed in option group. This is
190  * not public API and must not be used by applications.
191  **/
192 void
193 gdk_add_option_entries_libgtk_only (GOptionGroup *group)
194 {
195   g_option_group_add_entries (group, gdk_args);
196   g_option_group_add_entries (group, _gdk_windowing_args);
197 }
198
199 void
200 gdk_pre_parse_libgtk_only (void)
201 {
202   gdk_initialized = TRUE;
203
204   /* We set the fallback program class here, rather than lazily in
205    * gdk_get_program_class, since we don't want -name to override it.
206    */
207   gdk_progclass = g_strdup (g_get_prgname ());
208   if (gdk_progclass && gdk_progclass[0])
209     gdk_progclass[0] = g_ascii_toupper (gdk_progclass[0]);
210   
211 #ifdef G_ENABLE_DEBUG
212   {
213     gchar *debug_string = getenv("GDK_DEBUG");
214     if (debug_string != NULL)
215       _gdk_debug_flags = g_parse_debug_string (debug_string,
216                                               (GDebugKey *) gdk_debug_keys,
217                                               gdk_ndebug_keys);
218   }
219 #endif  /* G_ENABLE_DEBUG */
220
221   if (getenv ("GDK_NATIVE_WINDOWS"))
222     {
223       _gdk_native_windows = TRUE;
224       /* Ensure that this is not propagated
225          to spawned applications */
226       g_unsetenv ("GDK_NATIVE_WINDOWS");
227     }
228
229   g_type_init ();
230
231   /* Do any setup particular to the windowing system */
232   gdk_display_manager_get ();
233 }
234
235   
236 /**
237  * gdk_parse_args:
238  * @argc: the number of command line arguments.
239  * @argv: the array of command line arguments.
240  * 
241  * Parse command line arguments, and store for future
242  * use by calls to gdk_display_open().
243  *
244  * Any arguments used by GDK are removed from the array and @argc and @argv are
245  * updated accordingly.
246  *
247  * You shouldn't call this function explicitely if you are using
248  * gtk_init(), gtk_init_check(), gdk_init(), or gdk_init_check().
249  *
250  * Since: 2.2
251  **/
252 void
253 gdk_parse_args (int    *argc,
254                 char ***argv)
255 {
256   GOptionContext *option_context;
257   GOptionGroup *option_group;
258   GError *error = NULL;
259
260   if (gdk_initialized)
261     return;
262
263   gdk_pre_parse_libgtk_only ();
264
265   option_context = g_option_context_new (NULL);
266   g_option_context_set_ignore_unknown_options (option_context, TRUE);
267   g_option_context_set_help_enabled (option_context, FALSE);
268   option_group = g_option_group_new (NULL, NULL, NULL, NULL, NULL);
269   g_option_context_set_main_group (option_context, option_group);
270
271   g_option_group_add_entries (option_group, gdk_args);
272   g_option_group_add_entries (option_group, _gdk_windowing_args);
273
274   if (!g_option_context_parse (option_context, argc, argv, &error))
275     {
276       g_warning ("%s", error->message);
277       g_error_free (error);
278     }
279   g_option_context_free (option_context);
280
281   GDK_NOTE (MISC, g_message ("progname: \"%s\"", g_get_prgname ()));
282 }
283
284 /**
285  * gdk_get_display_arg_name:
286  *
287  * Gets the display name specified in the command line arguments passed
288  * to gdk_init() or gdk_parse_args(), if any.
289  *
290  * Returns: the display name, if specified explicitely, otherwise %NULL
291  *   this string is owned by GTK+ and must not be modified or freed.
292  *
293  * Since: 2.2
294  */
295 G_CONST_RETURN gchar *
296 gdk_get_display_arg_name (void)
297 {
298   if (!_gdk_display_arg_name)
299     {
300       if (_gdk_screen_number >= 0)
301         _gdk_display_arg_name = _gdk_windowing_substitute_screen_number (_gdk_display_name, _gdk_screen_number);
302       else
303         _gdk_display_arg_name = g_strdup (_gdk_display_name);
304    }
305
306    return _gdk_display_arg_name;
307 }
308
309 /**
310  * gdk_display_open_default_libgtk_only:
311  *
312  * Opens the default display specified by command line arguments or
313  * environment variables, sets it as the default display, and returns
314  * it.  gdk_parse_args must have been called first. If the default
315  * display has previously been set, simply returns that. An internal
316  * function that should not be used by applications.
317  *
318  * Return value: (transfer none): the default display, if it could be
319  *   opened, otherwise %NULL.
320  **/
321 GdkDisplay *
322 gdk_display_open_default_libgtk_only (void)
323 {
324   GdkDisplay *display;
325
326   g_return_val_if_fail (gdk_initialized, NULL);
327
328   display = gdk_display_get_default ();
329   if (display)
330     return display;
331
332   display = gdk_display_open (gdk_get_display_arg_name ());
333
334   if (!display && _gdk_screen_number >= 0)
335     {
336       g_free (_gdk_display_arg_name);
337       _gdk_display_arg_name = g_strdup (_gdk_display_name);
338
339       display = gdk_display_open (_gdk_display_name);
340     }
341
342   return display;
343 }
344
345 /**
346  * gdk_init_check:
347  * @argc: (inout): the number of command line arguments.
348  * @argv: (array length=argc) (inout): the array of command line arguments.
349  *
350  * Initializes the GDK library and connects to the X server, returning %TRUE on
351  * success.
352  *
353  * Any arguments used by GDK are removed from the array and @argc and @argv are
354  * updated accordingly.
355  *
356  * GTK+ initializes GDK in gtk_init() and so this function is not usually needed
357  * by GTK+ applications.
358  *
359  * Returns: %TRUE if initialization succeeded.
360  */
361 gboolean
362 gdk_init_check (int    *argc,
363                 char ***argv)
364 {
365   gdk_parse_args (argc, argv);
366
367   return gdk_display_open_default_libgtk_only () != NULL;
368 }
369
370
371 /**
372  * gdk_init:
373  * @argc: (inout): the number of command line arguments.
374  * @argv: (array length=argc) (inout): the array of command line arguments.
375  *
376  * Initializes the GDK library and connects to the X server.
377  * If initialization fails, a warning message is output and the application
378  * terminates with a call to <literal>exit(1)</literal>.
379  *
380  * Any arguments used by GDK are removed from the array and @argc and @argv are
381  * updated accordingly.
382  *
383  * GTK+ initializes GDK in gtk_init() and so this function is not usually needed
384  * by GTK+ applications.
385  */
386 void
387 gdk_init (int *argc, char ***argv)
388 {
389   if (!gdk_init_check (argc, argv))
390     {
391       const char *display_name = gdk_get_display_arg_name ();
392       g_warning ("cannot open display: %s", display_name ? display_name : "");
393       exit(1);
394     }
395 }
396
397
398
399 /**
400  * SECTION:threads
401  * @Short_description: Functions for using GDK in multi-threaded programs
402  * @Title: Threads
403  *
404  * For thread safety, GDK relies on the thread primitives in GLib,
405  * and on the thread-safe GLib main loop.
406  *
407  * GLib is completely thread safe (all global data is automatically
408  * locked), but individual data structure instances are not automatically
409  * locked for performance reasons. So e.g. you must coordinate
410  * accesses to the same #GHashTable from multiple threads.
411  *
412  * GTK+ is "thread aware" but not thread safe &mdash; it provides a
413  * global lock controlled by gdk_threads_enter()/gdk_threads_leave()
414  * which protects all use of GTK+. That is, only one thread can use GTK+
415  * at any given time.
416  *
417  * Unfortunately the above holds with the X11 backend only. With the
418  * Win32 backend, GDK calls should not be attempted from multiple threads
419  * at all.
420  *
421  * You must call g_thread_init() and gdk_threads_init() before executing
422  * any other GTK+ or GDK functions in a threaded GTK+ program.
423  *
424  * Idles, timeouts, and input functions from GLib, such as g_idle_add(), are
425  * executed outside of the main GTK+ lock.
426  * So, if you need to call GTK+ inside of such a callback, you must surround
427  * the callback with a gdk_threads_enter()/gdk_threads_leave() pair or use
428  * gdk_threads_add_idle_full() which does this for you.
429  * However, event dispatching from the mainloop is still executed within
430  * the main GTK+ lock, so callback functions connected to event signals
431  * like #GtkWidget::button-press-event, do not need thread protection.
432  *
433  * In particular, this means, if you are writing widgets that might
434  * be used in threaded programs, you <emphasis>must</emphasis> surround
435  * timeouts and idle functions in this matter.
436  *
437  * As always, you must also surround any calls to GTK+ not made within
438  * a signal handler with a gdk_threads_enter()/gdk_threads_leave() pair.
439  *
440  * Before calling gdk_threads_leave() from a thread other
441  * than your main thread, you probably want to call gdk_flush()
442  * to send all pending commands to the windowing system.
443  * (The reason you don't need to do this from the main thread
444  * is that GDK always automatically flushes pending commands
445  * when it runs out of incoming events to process and has
446  * to sleep while waiting for more events.)
447  *
448  * A minimal main program for a threaded GTK+ application
449  * looks like:
450  * <informalexample>
451  * <programlisting role="C">
452  * int
453  * main (int argc, char *argv[])
454  * {
455  *   GtkWidget *window;
456  *
457  *   g_thread_init (NULL);
458  *   gdk_threads_init (<!-- -->);
459  *   gdk_threads_enter (<!-- -->);
460  *
461  *   gtk_init (&argc, &argv);
462  *
463  *   window = create_window (<!-- -->);
464  *   gtk_widget_show (window);
465  *
466  *   gtk_main (<!-- -->);
467  *   gdk_threads_leave (<!-- -->);
468  *
469  *   return 0;
470  * }
471  * </programlisting>
472  * </informalexample>
473  *
474  * Callbacks require a bit of attention. Callbacks from GTK+ signals
475  * are made within the GTK+ lock. However callbacks from GLib (timeouts,
476  * IO callbacks, and idle functions) are made outside of the GTK+
477  * lock. So, within a signal handler you do not need to call
478  * gdk_threads_enter(), but within the other types of callbacks, you
479  * do.
480  *
481  * Erik Mouw contributed the following code example to
482  * illustrate how to use threads within GTK+ programs.
483  * <informalexample>
484  * <programlisting role="C">
485  * /<!---->*-------------------------------------------------------------------------
486  *  * Filename:      gtk-thread.c
487  *  * Version:       0.99.1
488  *  * Copyright:     Copyright (C) 1999, Erik Mouw
489  *  * Author:        Erik Mouw &lt;J.A.K.Mouw@its.tudelft.nl&gt;
490  *  * Description:   GTK threads example.
491  *  * Created at:    Sun Oct 17 21:27:09 1999
492  *  * Modified by:   Erik Mouw &lt;J.A.K.Mouw@its.tudelft.nl&gt;
493  *  * Modified at:   Sun Oct 24 17:21:41 1999
494  *  *-----------------------------------------------------------------------*<!---->/
495  * /<!---->*
496  *  * Compile with:
497  *  *
498  *  * cc -o gtk-thread gtk-thread.c `gtk-config --cflags --libs gthread`
499  *  *
500  *  * Thanks to Sebastian Wilhelmi and Owen Taylor for pointing out some
501  *  * bugs.
502  *  *
503  *  *<!---->/
504  *
505  * #include <stdio.h>
506  * #include <stdlib.h>
507  * #include <unistd.h>
508  * #include <time.h>
509  * #include <gtk/gtk.h>
510  * #include <glib.h>
511  * #include <pthread.h>
512  *
513  * #define YES_IT_IS    (1)
514  * #define NO_IT_IS_NOT (0)
515  *
516  * typedef struct
517  * {
518  *   GtkWidget *label;
519  *   int what;
520  * } yes_or_no_args;
521  *
522  * G_LOCK_DEFINE_STATIC (yes_or_no);
523  * static volatile int yes_or_no = YES_IT_IS;
524  *
525  * void destroy (GtkWidget *widget, gpointer data)
526  * {
527  *   gtk_main_quit (<!-- -->);
528  * }
529  *
530  * void *argument_thread (void *args)
531  * {
532  *   yes_or_no_args *data = (yes_or_no_args *)args;
533  *   gboolean say_something;
534  *
535  *   for (;;)
536  *     {
537  *       /<!---->* sleep a while *<!---->/
538  *       sleep(rand(<!-- -->) / (RAND_MAX / 3) + 1);
539  *
540  *       /<!---->* lock the yes_or_no_variable *<!---->/
541  *       G_LOCK(yes_or_no);
542  *
543  *       /<!---->* do we have to say something? *<!---->/
544  *       say_something = (yes_or_no != data->what);
545  *
546  *       if(say_something)
547  *      {
548  *        /<!---->* set the variable *<!---->/
549  *        yes_or_no = data->what;
550  *      }
551  *
552  *       /<!---->* Unlock the yes_or_no variable *<!---->/
553  *       G_UNLOCK (yes_or_no);
554  *
555  *       if (say_something)
556  *      {
557  *        /<!---->* get GTK thread lock *<!---->/
558  *        gdk_threads_enter (<!-- -->);
559  *
560  *        /<!---->* set label text *<!---->/
561  *        if(data->what == YES_IT_IS)
562  *          gtk_label_set_text (GTK_LABEL (data->label), "O yes, it is!");
563  *        else
564  *          gtk_label_set_text (GTK_LABEL (data->label), "O no, it isn't!");
565  *
566  *        /<!---->* release GTK thread lock *<!---->/
567  *        gdk_threads_leave (<!-- -->);
568  *      }
569  *     }
570  *
571  *   return NULL;
572  * }
573  *
574  * int main (int argc, char *argv[])
575  * {
576  *   GtkWidget *window;
577  *   GtkWidget *label;
578  *   yes_or_no_args yes_args, no_args;
579  *   pthread_t no_tid, yes_tid;
580  *
581  *   /<!---->* init threads *<!---->/
582  *   g_thread_init (NULL);
583  *   gdk_threads_init (<!-- -->);
584  *   gdk_threads_enter (<!-- -->);
585  *
586  *   /<!---->* init gtk *<!---->/
587  *   gtk_init(&argc, &argv);
588  *
589  *   /<!---->* init random number generator *<!---->/
590  *   srand ((unsigned int) time (NULL));
591  *
592  *   /<!---->* create a window *<!---->/
593  *   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
594  *
595  *   g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
596  *
597  *   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
598  *
599  *   /<!---->* create a label *<!---->/
600  *   label = gtk_label_new ("And now for something completely different ...");
601  *   gtk_container_add (GTK_CONTAINER (window), label);
602  *
603  *   /<!---->* show everything *<!---->/
604  *   gtk_widget_show (label);
605  *   gtk_widget_show (window);
606  *
607  *   /<!---->* create the threads *<!---->/
608  *   yes_args.label = label;
609  *   yes_args.what = YES_IT_IS;
610  *   pthread_create (&yes_tid, NULL, argument_thread, &yes_args);
611  *
612  *   no_args.label = label;
613  *   no_args.what = NO_IT_IS_NOT;
614  *   pthread_create (&no_tid, NULL, argument_thread, &no_args);
615  *
616  *   /<!---->* enter the GTK main loop *<!---->/
617  *   gtk_main (<!-- -->);
618  *   gdk_threads_leave (<!-- -->);
619  *
620  *   return 0;
621  * }
622  * </programlisting>
623  * </informalexample>
624  */
625
626
627 /**
628  * gdk_threads_enter:
629  *
630  * This macro marks the beginning of a critical section in which GDK and
631  * GTK+ functions can be called safely and without causing race
632  * conditions.  Only one thread at a time can be in such a critial
633  * section.
634  */
635 void
636 gdk_threads_enter (void)
637 {
638   if (gdk_threads_lock)
639     (*gdk_threads_lock) ();
640 }
641
642 /**
643  * gdk_threads_leave:
644  *
645  * Leaves a critical region begun with gdk_threads_enter().
646  */
647 void
648 gdk_threads_leave (void)
649 {
650   if (gdk_threads_unlock)
651     (*gdk_threads_unlock) ();
652 }
653
654 static void
655 gdk_threads_impl_lock (void)
656 {
657   if (gdk_threads_mutex)
658     g_mutex_lock (gdk_threads_mutex);
659 }
660
661 static void
662 gdk_threads_impl_unlock (void)
663 {
664   if (gdk_threads_mutex)
665     g_mutex_unlock (gdk_threads_mutex);
666 }
667
668 /**
669  * gdk_threads_init:
670  *
671  * Initializes GDK so that it can be used from multiple threads
672  * in conjunction with gdk_threads_enter() and gdk_threads_leave().
673  * g_thread_init() must be called previous to this function.
674  *
675  * This call must be made before any use of the main loop from
676  * GTK+; to be safe, call it before gtk_init().
677  **/
678 void
679 gdk_threads_init (void)
680 {
681   if (!g_thread_supported ())
682     g_error ("g_thread_init() must be called before gdk_threads_init()");
683
684   gdk_threads_mutex = g_mutex_new ();
685   if (!gdk_threads_lock)
686     gdk_threads_lock = gdk_threads_impl_lock;
687   if (!gdk_threads_unlock)
688     gdk_threads_unlock = gdk_threads_impl_unlock;
689 }
690
691 /**
692  * gdk_threads_set_lock_functions:
693  * @enter_fn:   function called to guard GDK
694  * @leave_fn: function called to release the guard
695  *
696  * Allows the application to replace the standard method that
697  * GDK uses to protect its data structures. Normally, GDK
698  * creates a single #GMutex that is locked by gdk_threads_enter(),
699  * and released by gdk_threads_leave(); using this function an
700  * application provides, instead, a function @enter_fn that is
701  * called by gdk_threads_enter() and a function @leave_fn that is
702  * called by gdk_threads_leave().
703  *
704  * The functions must provide at least same locking functionality
705  * as the default implementation, but can also do extra application
706  * specific processing.
707  *
708  * As an example, consider an application that has its own recursive
709  * lock that when held, holds the GTK+ lock as well. When GTK+ unlocks
710  * the GTK+ lock when entering a recursive main loop, the application
711  * must temporarily release its lock as well.
712  *
713  * Most threaded GTK+ apps won't need to use this method.
714  *
715  * This method must be called before gdk_threads_init(), and cannot
716  * be called multiple times.
717  *
718  * Since: 2.4
719  **/
720 void
721 gdk_threads_set_lock_functions (GCallback enter_fn,
722                                 GCallback leave_fn)
723 {
724   g_return_if_fail (gdk_threads_lock == NULL &&
725                     gdk_threads_unlock == NULL);
726
727   gdk_threads_lock = enter_fn;
728   gdk_threads_unlock = leave_fn;
729 }
730
731 static gboolean
732 gdk_threads_dispatch (gpointer data)
733 {
734   GdkThreadsDispatch *dispatch = data;
735   gboolean ret = FALSE;
736
737   GDK_THREADS_ENTER ();
738
739   if (!g_source_is_destroyed (g_main_current_source ()))
740     ret = dispatch->func (dispatch->data);
741
742   GDK_THREADS_LEAVE ();
743
744   return ret;
745 }
746
747 static void
748 gdk_threads_dispatch_free (gpointer data)
749 {
750   GdkThreadsDispatch *dispatch = data;
751
752   if (dispatch->destroy && dispatch->data)
753     dispatch->destroy (dispatch->data);
754
755   g_slice_free (GdkThreadsDispatch, data);
756 }
757
758
759 /**
760  * gdk_threads_add_idle_full:
761  * @priority: the priority of the idle source. Typically this will be in the
762  *            range btweeen #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE
763  * @function: function to call
764  * @data:     data to pass to @function
765  * @notify: (allow-none):   function to call when the idle is removed, or %NULL
766  *
767  * Adds a function to be called whenever there are no higher priority
768  * events pending.  If the function returns %FALSE it is automatically
769  * removed from the list of event sources and will not be called again.
770  *
771  * This variant of g_idle_add_full() calls @function with the GDK lock
772  * held. It can be thought of a MT-safe version for GTK+ widgets for the 
773  * following use case, where you have to worry about idle_callback()
774  * running in thread A and accessing @self after it has been finalized
775  * in thread B:
776  *
777  * |[
778  * static gboolean
779  * idle_callback (gpointer data)
780  * {
781  *    /&ast; gdk_threads_enter(); would be needed for g_idle_add() &ast;/
782  *
783  *    SomeWidget *self = data;
784  *    /&ast; do stuff with self &ast;/
785  *
786  *    self->idle_id = 0;
787  *
788  *    /&ast; gdk_threads_leave(); would be needed for g_idle_add() &ast;/
789  *    return FALSE;
790  * }
791  *
792  * static void
793  * some_widget_do_stuff_later (SomeWidget *self)
794  * {
795  *    self->idle_id = gdk_threads_add_idle (idle_callback, self)
796  *    /&ast; using g_idle_add() here would require thread protection in the callback &ast;/
797  * }
798  *
799  * static void
800  * some_widget_finalize (GObject *object)
801  * {
802  *    SomeWidget *self = SOME_WIDGET (object);
803  *    if (self->idle_id)
804  *      g_source_remove (self->idle_id);
805  *    G_OBJECT_CLASS (parent_class)->finalize (object);
806  * }
807  * ]|
808  *
809  * Return value: the ID (greater than 0) of the event source.
810  *
811  * Since: 2.12
812  */
813 guint
814 gdk_threads_add_idle_full (gint           priority,
815                            GSourceFunc    function,
816                            gpointer       data,
817                            GDestroyNotify notify)
818 {
819   GdkThreadsDispatch *dispatch;
820
821   g_return_val_if_fail (function != NULL, 0);
822
823   dispatch = g_slice_new (GdkThreadsDispatch);
824   dispatch->func = function;
825   dispatch->data = data;
826   dispatch->destroy = notify;
827
828   return g_idle_add_full (priority,
829                           gdk_threads_dispatch,
830                           dispatch,
831                           gdk_threads_dispatch_free);
832 }
833
834 /**
835  * gdk_threads_add_idle:
836  * @function: function to call
837  * @data:     data to pass to @function
838  *
839  * A wrapper for the common usage of gdk_threads_add_idle_full() 
840  * assigning the default priority, #G_PRIORITY_DEFAULT_IDLE.
841  *
842  * See gdk_threads_add_idle_full().
843  *
844  * Return value: the ID (greater than 0) of the event source.
845  * 
846  * Since: 2.12
847  */
848 guint
849 gdk_threads_add_idle (GSourceFunc    function,
850                       gpointer       data)
851 {
852   return gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
853                                     function, data, NULL);
854 }
855
856
857 /**
858  * gdk_threads_add_timeout_full:
859  * @priority: the priority of the timeout source. Typically this will be in the
860  *            range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE.
861  * @interval: the time between calls to the function, in milliseconds
862  *             (1/1000ths of a second)
863  * @function: function to call
864  * @data:     data to pass to @function
865  * @notify: (allow-none):   function to call when the timeout is removed, or %NULL
866  *
867  * Sets a function to be called at regular intervals holding the GDK lock,
868  * with the given priority.  The function is called repeatedly until it 
869  * returns %FALSE, at which point the timeout is automatically destroyed 
870  * and the function will not be called again.  The @notify function is
871  * called when the timeout is destroyed.  The first call to the
872  * function will be at the end of the first @interval.
873  *
874  * Note that timeout functions may be delayed, due to the processing of other
875  * event sources. Thus they should not be relied on for precise timing.
876  * After each call to the timeout function, the time of the next
877  * timeout is recalculated based on the current time and the given interval
878  * (it does not try to 'catch up' time lost in delays).
879  *
880  * This variant of g_timeout_add_full() can be thought of a MT-safe version 
881  * for GTK+ widgets for the following use case:
882  *
883  * |[
884  * static gboolean timeout_callback (gpointer data)
885  * {
886  *    SomeWidget *self = data;
887  *    
888  *    /&ast; do stuff with self &ast;/
889  *    
890  *    self->timeout_id = 0;
891  *    
892  *    return FALSE;
893  * }
894  *  
895  * static void some_widget_do_stuff_later (SomeWidget *self)
896  * {
897  *    self->timeout_id = g_timeout_add (timeout_callback, self)
898  * }
899  *  
900  * static void some_widget_finalize (GObject *object)
901  * {
902  *    SomeWidget *self = SOME_WIDGET (object);
903  *    
904  *    if (self->timeout_id)
905  *      g_source_remove (self->timeout_id);
906  *    
907  *    G_OBJECT_CLASS (parent_class)->finalize (object);
908  * }
909  * ]|
910  *
911  * Return value: the ID (greater than 0) of the event source.
912  * 
913  * Since: 2.12
914  */
915 guint
916 gdk_threads_add_timeout_full (gint           priority,
917                               guint          interval,
918                               GSourceFunc    function,
919                               gpointer       data,
920                               GDestroyNotify notify)
921 {
922   GdkThreadsDispatch *dispatch;
923
924   g_return_val_if_fail (function != NULL, 0);
925
926   dispatch = g_slice_new (GdkThreadsDispatch);
927   dispatch->func = function;
928   dispatch->data = data;
929   dispatch->destroy = notify;
930
931   return g_timeout_add_full (priority, 
932                              interval,
933                              gdk_threads_dispatch, 
934                              dispatch, 
935                              gdk_threads_dispatch_free);
936 }
937
938 /**
939  * gdk_threads_add_timeout:
940  * @interval: the time between calls to the function, in milliseconds
941  *             (1/1000ths of a second)
942  * @function: function to call
943  * @data:     data to pass to @function
944  *
945  * A wrapper for the common usage of gdk_threads_add_timeout_full() 
946  * assigning the default priority, #G_PRIORITY_DEFAULT.
947  *
948  * See gdk_threads_add_timeout_full().
949  * 
950  * Return value: the ID (greater than 0) of the event source.
951  *
952  * Since: 2.12
953  */
954 guint
955 gdk_threads_add_timeout (guint       interval,
956                          GSourceFunc function,
957                          gpointer    data)
958 {
959   return gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
960                                        interval, function, data, NULL);
961 }
962
963
964 /**
965  * gdk_threads_add_timeout_seconds_full:
966  * @priority: the priority of the timeout source. Typically this will be in the
967  *            range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE.
968  * @interval: the time between calls to the function, in seconds
969  * @function: function to call
970  * @data:     data to pass to @function
971  * @notify: (allow-none):   function to call when the timeout is removed, or %NULL
972  *
973  * A variant of gdk_threads_add_timout_full() with second-granularity.
974  * See g_timeout_add_seconds_full() for a discussion of why it is
975  * a good idea to use this function if you don't need finer granularity.
976  *
977  *  Return value: the ID (greater than 0) of the event source.
978  * 
979  * Since: 2.14
980  */
981 guint
982 gdk_threads_add_timeout_seconds_full (gint           priority,
983                                       guint          interval,
984                                       GSourceFunc    function,
985                                       gpointer       data,
986                                       GDestroyNotify notify)
987 {
988   GdkThreadsDispatch *dispatch;
989
990   g_return_val_if_fail (function != NULL, 0);
991
992   dispatch = g_slice_new (GdkThreadsDispatch);
993   dispatch->func = function;
994   dispatch->data = data;
995   dispatch->destroy = notify;
996
997   return g_timeout_add_seconds_full (priority, 
998                                      interval,
999                                      gdk_threads_dispatch, 
1000                                      dispatch, 
1001                                      gdk_threads_dispatch_free);
1002 }
1003
1004 /**
1005  * gdk_threads_add_timeout_seconds:
1006  * @interval: the time between calls to the function, in seconds
1007  * @function: function to call
1008  * @data:     data to pass to @function
1009  *
1010  * A wrapper for the common usage of gdk_threads_add_timeout_seconds_full() 
1011  * assigning the default priority, #G_PRIORITY_DEFAULT.
1012  *
1013  * For details, see gdk_threads_add_timeout_full().
1014  * 
1015  * Return value: the ID (greater than 0) of the event source.
1016  *
1017  * Since: 2.14
1018  */
1019 guint
1020 gdk_threads_add_timeout_seconds (guint       interval,
1021                                  GSourceFunc function,
1022                                  gpointer    data)
1023 {
1024   return gdk_threads_add_timeout_seconds_full (G_PRIORITY_DEFAULT,
1025                                                interval, function, data, NULL);
1026 }
1027
1028 /**
1029  * gdk_get_program_class:
1030  *
1031  * Gets the program class. Unless the program class has explicitly
1032  * been set with gdk_set_program_class() or with the <option>--class</option>
1033  * commandline option, the default value is the program name (determined
1034  * with g_get_prgname()) with the first character converted to uppercase.
1035  *
1036  * Returns: the program class.
1037  */
1038 G_CONST_RETURN char *
1039 gdk_get_program_class (void)
1040 {
1041   return gdk_progclass;
1042 }
1043
1044 /**
1045  * gdk_set_program_class:
1046  * @program_class: a string.
1047  *
1048  * Sets the program class. The X11 backend uses the program class to set
1049  * the class name part of the <literal>WM_CLASS</literal> property on
1050  * toplevel windows; see the ICCCM.
1051  */
1052 void
1053 gdk_set_program_class (const char *program_class)
1054 {
1055   g_free (gdk_progclass);
1056
1057   gdk_progclass = g_strdup (program_class);
1058 }
1059
1060 /**
1061  * gdk_disable_multidevice:
1062  *
1063  * Disables multidevice support in GDK. This call must happen prior
1064  * to gdk_display_open(), gtk_init(), gtk_init_with_args() or
1065  * gtk_init_check() in order to take effect.
1066  *
1067  * Most common GTK+ applications won't ever need to call this. Only
1068  * applications that do mixed GDK/Xlib calls could want to disable
1069  * multidevice support if such Xlib code deals with input devices in
1070  * any way and doesn't observe the presence of XInput 2.
1071  *
1072  * Since: 3.0
1073  **/
1074 void
1075 gdk_disable_multidevice (void)
1076 {
1077   if (gdk_initialized)
1078     return;
1079
1080   _gdk_disable_multidevice = TRUE;
1081 }