]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
g_warning() if setting the local fails, like gdk_set_locale() did.
[~andy/gtk] / gtk / gtkmain.c
1 /* GTK - The GIMP Toolkit
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 "gdkconfig.h"
28
29 #include <locale.h>
30
31 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
32 #include <libintl.h>
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <gmodule.h>
39 #ifdef G_OS_UNIX
40 #include <unistd.h>
41 #include <sys/types.h>          /* For uid_t, gid_t */
42 #endif
43 #ifdef G_OS_WIN32
44 #define STRICT
45 #include <windows.h>
46 #undef STRICT
47 #endif
48
49 #include <pango/pango-utils.h>  /* For pango_split_file_list */
50
51 #include "gtkaccelmap.h"
52 #include "gtkdnd.h"
53 #include "gtkversion.h"
54 #include "gtkmain.h"
55 #include "gtkrc.h"
56 #include "gtkselection.h"
57 #include "gtksettings.h"
58 #include "gtksignal.h"
59 #include "gtkwidget.h"
60 #include "gtkwindow.h"
61 #include "gtkprivate.h"
62 #include "config.h"
63 #include "gtkdebug.h"
64 #include "gtkintl.h"
65
66 /* Private type definitions
67  */
68 typedef struct _GtkInitFunction          GtkInitFunction;
69 typedef struct _GtkQuitFunction          GtkQuitFunction;
70 typedef struct _GtkClosure               GtkClosure;
71 typedef struct _GtkKeySnooperData        GtkKeySnooperData;
72
73 struct _GtkInitFunction
74 {
75   GtkFunction function;
76   gpointer data;
77 };
78
79 struct _GtkQuitFunction
80 {
81   guint id;
82   guint main_level;
83   GtkCallbackMarshal marshal;
84   GtkFunction function;
85   gpointer data;
86   GtkDestroyNotify destroy;
87 };
88
89 struct _GtkClosure
90 {
91   GtkCallbackMarshal marshal;
92   gpointer data;
93   GtkDestroyNotify destroy;
94 };
95
96 struct _GtkKeySnooperData
97 {
98   GtkKeySnoopFunc func;
99   gpointer func_data;
100   guint id;
101 };
102
103 static gint  gtk_quit_invoke_function    (GtkQuitFunction    *quitf);
104 static void  gtk_quit_destroy            (GtkQuitFunction    *quitf);
105 static gint  gtk_invoke_key_snoopers     (GtkWidget          *grab_widget,
106                                           GdkEvent           *event);
107
108 static void     gtk_destroy_closure      (gpointer            data);
109 static gboolean gtk_invoke_idle_timeout  (gpointer            data);
110 static void     gtk_invoke_input         (gpointer            data,
111                                           gint                source,
112                                           GdkInputCondition   condition);
113
114 #if 0
115 static void  gtk_error                   (gchar              *str);
116 static void  gtk_warning                 (gchar              *str);
117 static void  gtk_message                 (gchar              *str);
118 static void  gtk_print                   (gchar              *str);
119 #endif
120
121 static GtkWindowGroup *gtk_main_get_window_group (GtkWidget   *widget);
122
123 const guint gtk_major_version = GTK_MAJOR_VERSION;
124 const guint gtk_minor_version = GTK_MINOR_VERSION;
125 const guint gtk_micro_version = GTK_MICRO_VERSION;
126 const guint gtk_binary_age = GTK_BINARY_AGE;
127 const guint gtk_interface_age = GTK_INTERFACE_AGE;
128
129 static guint gtk_main_loop_level = 0;
130 static gint gtk_initialized = FALSE;
131 static GList *current_events = NULL;
132
133 static GSList *main_loops = NULL;      /* stack of currently executing main loops */
134
135 static GList *init_functions = NULL;       /* A list of init functions.
136                                             */
137 static GList *quit_functions = NULL;       /* A list of quit functions.
138                                             */
139 static GMemChunk *quit_mem_chunk = NULL;
140
141 static GSList *key_snoopers = NULL;
142
143 static GdkVisual *gtk_visual;              /* The visual to be used in creating new
144                                             *  widgets.
145                                             */
146 static GdkColormap *gtk_colormap;          /* The colormap to be used in creating new
147                                             *  widgets.
148                                             */
149
150 guint gtk_debug_flags = 0;                 /* Global GTK debug flag */
151
152 #ifdef G_ENABLE_DEBUG
153 static const GDebugKey gtk_debug_keys[] = {
154   {"misc", GTK_DEBUG_MISC},
155   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
156   {"text", GTK_DEBUG_TEXT},
157   {"tree", GTK_DEBUG_TREE},
158   {"updates", GTK_DEBUG_UPDATES}
159 };
160
161 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
162
163 #endif /* G_ENABLE_DEBUG */
164
165 gchar*
166 gtk_check_version (guint required_major,
167                    guint required_minor,
168                    guint required_micro)
169 {
170   if (required_major > GTK_MAJOR_VERSION)
171     return "Gtk+ version too old (major mismatch)";
172   if (required_major < GTK_MAJOR_VERSION)
173     return "Gtk+ version too new (major mismatch)";
174   if (required_minor > GTK_MINOR_VERSION)
175     return "Gtk+ version too old (minor mismatch)";
176   if (required_minor < GTK_MINOR_VERSION)
177     return "Gtk+ version too new (minor mismatch)";
178   if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
179     return "Gtk+ version too new (micro mismatch)";
180   if (required_micro > GTK_MICRO_VERSION)
181     return "Gtk+ version too old (micro mismatch)";
182   return NULL;
183 }
184
185 #undef gtk_init_check
186
187 /* This checks to see if the process is running suid or sgid
188  * at the current time. If so, we don't allow GTK+ to be initialized.
189  * This is meant to be a mild check - we only error out if we
190  * can prove the programmer is doing something wrong, not if
191  * they could be doing something wrong. For this reason, we
192  * don't use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
193  */
194 static gboolean
195 check_setugid (void)
196 {
197 /* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
198 #ifndef G_OS_WIN32
199   uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
200   gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
201   
202 #ifdef HAVE_GETRESUID
203   /* These aren't in the header files, so we prototype them here.
204    */
205   int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
206   int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
207
208   if (getresuid (&ruid, &euid, &suid) != 0 ||
209       getresgid (&rgid, &egid, &sgid) != 0)
210 #endif /* HAVE_GETRESUID */
211     {
212       suid = ruid = getuid ();
213       sgid = rgid = getgid ();
214       euid = geteuid ();
215       egid = getegid ();
216     }
217
218   if (ruid != euid || ruid != suid ||
219       rgid != egid || rgid != sgid)
220     {
221       g_warning ("This process is currently running setuid or setgid.\n"
222                  "This is not a supported use of GTK+. You must create a helper\n"
223                  "program instead. For further details, see:\n\n"
224                  "    http://www.gtk.org/setuid.html\n\n"
225                  "Refusing to initialize GTK+.");
226       exit (1);
227     }
228 #endif
229   return TRUE;
230 }
231
232 #ifdef G_OS_WIN32
233
234 G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)
235
236 const gchar *
237 _gtk_get_libdir (void)
238 {
239   static char *gtk_libdir = NULL;
240   if (gtk_libdir == NULL)
241     gtk_libdir = g_win32_get_package_installation_subdirectory
242       (GETTEXT_PACKAGE, dll_name, "lib");
243
244   return gtk_libdir;
245 }
246
247 const gchar *
248 _gtk_get_localedir (void)
249 {
250   static char *gtk_localedir = NULL;
251   if (gtk_localedir == NULL)
252     gtk_localedir = g_win32_get_package_installation_subdirectory
253       (GETTEXT_PACKAGE, dll_name, "lib\\locale");
254
255   return gtk_localedir;
256 }
257
258 const gchar *
259 _gtk_get_sysconfdir (void)
260 {
261   static char *gtk_sysconfdir = NULL;
262   if (gtk_sysconfdir == NULL)
263     gtk_sysconfdir = g_win32_get_package_installation_subdirectory
264       (GETTEXT_PACKAGE, dll_name, "etc");
265
266   return gtk_sysconfdir;
267 }
268
269 const gchar *
270 _gtk_get_data_prefix (void)
271 {
272   static char *gtk_data_prefix = NULL;
273   if (gtk_data_prefix == NULL)
274     gtk_data_prefix = g_win32_get_package_installation_directory
275       (GETTEXT_PACKAGE, dll_name);
276
277   return gtk_data_prefix;
278 }
279
280 #endif /* G_OS_WIN32 */
281
282 static gchar **
283 get_module_path (void)
284 {
285   const gchar *module_path_env = g_getenv ("GTK_MODULE_PATH");
286   const gchar *exe_prefix = g_getenv ("GTK_EXE_PREFIX");
287   gchar **result;
288   gchar *module_path;
289   gchar *default_dir;
290
291   if (exe_prefix)
292     default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", "modules", NULL);
293   else
294     default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", "modules", NULL);
295
296   module_path = g_strconcat (module_path_env ? module_path_env : "",
297                              module_path_env ? G_SEARCHPATH_SEPARATOR_S : "",
298                              default_dir, NULL);
299
300   result = pango_split_file_list (module_path);
301
302   g_free (default_dir);
303   g_free (module_path);
304
305   return result;
306 }
307
308 static GModule *
309 find_module (gchar      **module_path,
310              const gchar *name)
311 {
312   GModule *module;
313   gchar *module_name;
314   gint i;
315
316   if (g_path_is_absolute (name))
317     return g_module_open (name, G_MODULE_BIND_LAZY);
318
319   for (i = 0; module_path[i]; i++)
320     {
321       gchar *version_directory;
322
323       version_directory = g_build_filename (module_path[i], GTK_BINARY_VERSION, NULL);
324       module_name = g_module_build_path (version_directory, name);
325       g_free (version_directory);
326       
327       if (g_file_test (module_name, G_FILE_TEST_EXISTS))
328         {
329           module = g_module_open (module_name, G_MODULE_BIND_LAZY);
330           g_free (module_name);
331           return module;
332         }
333       
334       g_free (module_name);
335
336       module_name = g_module_build_path (module_path[i], name);
337       
338       if (g_file_test (module_name, G_FILE_TEST_EXISTS))
339         {
340           module = g_module_open (module_name, G_MODULE_BIND_LAZY);
341           g_free (module_name);
342           return module;
343         }
344
345       g_free (module_name);
346     }
347
348   /* As last resort, try loading without an absolute path (using system
349    * library path)
350    */
351   module_name = g_module_build_path (NULL, name);
352   module = g_module_open (module_name, G_MODULE_BIND_LAZY);
353   g_free(module_name);
354
355   return module;
356 }
357
358 static GSList *
359 load_module (GSList      *gtk_modules,
360              gchar      **module_path,
361              const gchar *name)
362 {
363   GtkModuleInitFunc modinit_func = NULL;
364   GModule *module = NULL;
365   
366   if (g_module_supported ())
367     {
368       module = find_module (module_path, name);
369       if (module &&
370           g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
371           modinit_func)
372         {
373           if (!g_slist_find (gtk_modules, modinit_func))
374             {
375               g_module_make_resident (module);
376               gtk_modules = g_slist_prepend (gtk_modules, modinit_func);
377             }
378           else
379             {
380               g_module_close (module);
381               module = NULL;
382             }
383         }
384     }
385   if (!modinit_func)
386     {
387       g_message ("Failed to load module \"%s\": %s",
388                  module ? g_module_name (module) : name,
389                  g_module_error ());
390       if (module)
391         g_module_close (module);
392     }
393   
394   return gtk_modules;
395 }
396
397 static GSList *
398 load_modules (const char *module_str)
399 {
400   gchar **module_path = get_module_path ();
401   gchar **module_names = pango_split_file_list (module_str);
402   GSList *gtk_modules = NULL;
403   gint i;
404   
405   for (i = 0; module_names[i]; i++)
406     gtk_modules = load_module (gtk_modules, module_path, module_names[i]);
407   
408   gtk_modules = g_slist_reverse (gtk_modules);
409   
410   g_strfreev (module_names);
411   g_strfreev (module_path);
412
413   return gtk_modules;
414 }
415
416 static gboolean do_setlocale = TRUE;
417
418 /**
419  * gtk_disable_setlocale:
420  * 
421  * Prevents gtk_init() and gtk_init_check() from automatically
422  * calling <literal>setlocale (LC_ALL, "")</literal>. You would 
423  * want to use this function if you wanted to set the locale for 
424  * your program to something other than the user's locale, or if 
425  * you wanted to set different values for different locale categories.
426  *
427  * Most programs should not need to call this function.
428  **/
429 void
430 gtk_disable_setlocale (void)
431 {
432   if (gtk_initialized)
433     g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
434     
435   do_setlocale = FALSE;
436 }
437
438 gboolean
439 gtk_init_check (int      *argc,
440                 char   ***argv)
441 {
442   GString *gtk_modules_string = NULL;
443   GSList *gtk_modules = NULL;
444   GSList *slist;
445   const gchar *env_string;
446
447   if (gtk_initialized)
448     return TRUE;
449
450   if (!check_setugid ())
451     return FALSE;
452   
453 #if     0
454   g_set_error_handler (gtk_error);
455   g_set_warning_handler (gtk_warning);
456   g_set_message_handler (gtk_message);
457   g_set_print_handler (gtk_print);
458 #endif
459
460   if (do_setlocale)
461     {
462       if (!setlocale (LC_ALL, ""))
463         g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
464     }
465   
466   /* Initialize "gdk". We pass along the 'argc' and 'argv'
467    *  parameters as they contain information that GDK uses
468    */
469   if (!gdk_init_check (argc, argv))
470     return FALSE;
471
472   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
473   
474 #ifdef G_ENABLE_DEBUG
475   env_string = g_getenv ("GTK_DEBUG");
476   if (env_string != NULL)
477     {
478       gtk_debug_flags = g_parse_debug_string (env_string,
479                                               gtk_debug_keys,
480                                               gtk_ndebug_keys);
481       env_string = NULL;
482     }
483 #endif  /* G_ENABLE_DEBUG */
484
485   env_string = g_getenv ("GTK_MODULES");
486   if (env_string)
487     gtk_modules_string = g_string_new (env_string);
488
489   if (argc && argv)
490     {
491       gint i, j, k;
492       
493       for (i = 1; i < *argc;)
494         {
495           if (strcmp ("--gtk-module", (*argv)[i]) == 0 ||
496               strncmp ("--gtk-module=", (*argv)[i], 13) == 0)
497             {
498               gchar *module_name = (*argv)[i] + 12;
499               
500               if (*module_name == '=')
501                 module_name++;
502               else if (i + 1 < *argc)
503                 {
504                   (*argv)[i] = NULL;
505                   i += 1;
506                   module_name = (*argv)[i];
507                 }
508               (*argv)[i] = NULL;
509
510               if (module_name && *module_name)
511                 {
512                   if (gtk_modules_string)
513                     g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
514                   else
515                     gtk_modules_string = g_string_new (NULL);
516
517                   g_string_append (gtk_modules_string, module_name);
518                 }
519             }
520           else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0)
521             {
522               GLogLevelFlags fatal_mask;
523               
524               fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
525               fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
526               g_log_set_always_fatal (fatal_mask);
527               (*argv)[i] = NULL;
528             }
529 #ifdef G_ENABLE_DEBUG
530           else if ((strcmp ("--gtk-debug", (*argv)[i]) == 0) ||
531                    (strncmp ("--gtk-debug=", (*argv)[i], 12) == 0))
532             {
533               gchar *equal_pos = strchr ((*argv)[i], '=');
534               
535               if (equal_pos != NULL)
536                 {
537                   gtk_debug_flags |= g_parse_debug_string (equal_pos+1,
538                                                            gtk_debug_keys,
539                                                            gtk_ndebug_keys);
540                 }
541               else if ((i + 1) < *argc && (*argv)[i + 1])
542                 {
543                   gtk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
544                                                            gtk_debug_keys,
545                                                            gtk_ndebug_keys);
546                   (*argv)[i] = NULL;
547                   i += 1;
548                 }
549               (*argv)[i] = NULL;
550             }
551           else if ((strcmp ("--gtk-no-debug", (*argv)[i]) == 0) ||
552                    (strncmp ("--gtk-no-debug=", (*argv)[i], 15) == 0))
553             {
554               gchar *equal_pos = strchr ((*argv)[i], '=');
555               
556               if (equal_pos != NULL)
557                 {
558                   gtk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
559                                                             gtk_debug_keys,
560                                                             gtk_ndebug_keys);
561                 }
562               else if ((i + 1) < *argc && (*argv)[i + 1])
563                 {
564                   gtk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
565                                                             gtk_debug_keys,
566                                                             gtk_ndebug_keys);
567                   (*argv)[i] = NULL;
568                   i += 1;
569                 }
570               (*argv)[i] = NULL;
571             }
572 #endif /* G_ENABLE_DEBUG */
573           i += 1;
574         }
575       
576       for (i = 1; i < *argc; i++)
577         {
578           for (k = i; k < *argc; k++)
579             if ((*argv)[k] != NULL)
580               break;
581           
582           if (k > i)
583             {
584               k -= i;
585               for (j = i + k; j < *argc; j++)
586                 (*argv)[j-k] = (*argv)[j];
587               *argc -= k;
588             }
589         }
590     }
591
592   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
593     gdk_window_set_debug_updates (TRUE);
594
595   /* load gtk modules */
596   if (gtk_modules_string)
597     {
598       gtk_modules = load_modules (gtk_modules_string->str);
599       g_string_free (gtk_modules_string, TRUE);
600     }
601
602 #ifdef ENABLE_NLS
603   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
604 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
605   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
606 #    endif
607 #endif  
608
609   {
610   /* Translate to default:RTL if you want your widgets
611    * to be RTL, otherwise translate to default:LTR.
612    * Do *not* translate it to "predefinito:LTR", if it
613    * it isn't default:LTR or default:RTL it will not work 
614    */
615     char *e = _("default:LTR");
616     if (strcmp (e, "default:RTL")==0) {
617       gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
618     } else if (strcmp (e, "default:LTR")) {
619       g_warning ("Whoever translated default:LTR did so wrongly.\n");
620     }
621   }
622
623   /* Initialize the default visual and colormap to be
624    *  used in creating widgets. (We want to use the system
625    *  defaults so as to be nice to the colormap).
626    */
627   gtk_visual = gdk_visual_get_system ();
628   gtk_colormap = gdk_colormap_get_system ();
629
630   gtk_type_init (0);
631   _gtk_accel_map_init ();  
632   _gtk_rc_init ();
633   
634   /* Set the 'initialized' flag.
635    */
636   gtk_initialized = TRUE;
637
638   /* initialize gtk modules
639    */
640   for (slist = gtk_modules; slist; slist = slist->next)
641     {
642       if (slist->data)
643         {
644           GtkModuleInitFunc modinit;
645           
646           modinit = slist->data;
647           modinit (argc, argv);
648         }
649     }
650   g_slist_free (gtk_modules);
651   
652   return TRUE;
653 }
654
655 #undef gtk_init
656
657 void
658 gtk_init (int *argc, char ***argv)
659 {
660   if (!gtk_init_check (argc, argv))
661     {
662       g_warning ("cannot open display: %s", gdk_get_display ());
663       exit (1);
664     }
665 }
666
667 #ifdef G_OS_WIN32
668
669 static void
670 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
671 {
672   if (sizeof_GtkWindow != sizeof (GtkWindow))
673     g_error ("Incompatible build!\n"
674              "The code using GTK+ thinks GtkWindow is of different\n"
675              "size than it actually is in this build of GTK+.\n"
676              "On Windows, this probably means that you have compiled\n"
677              "your code with gcc without the -fnative-struct switch.");
678 }
679
680 /* These two functions might get more checks added later, thus pass
681  * in the number of extra args.
682  */
683 void
684 gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
685 {
686   check_sizeof_GtkWindow (sizeof_GtkWindow);
687   gtk_init (argc, argv);
688 }
689
690 gboolean
691 gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
692 {
693   check_sizeof_GtkWindow (sizeof_GtkWindow);
694   return gtk_init_check (argc, argv);
695 }
696
697 #endif
698
699 void
700 gtk_exit (gint errorcode)
701 {
702   /* Only if "gtk" has been initialized should we de-initialize.
703    */
704   gdk_exit (errorcode);
705 }
706
707
708 /**
709  * gtk_set_locale:
710  *
711  * Initializes internationalization support for GTK+. gtk_init()
712  * automatically does this, so there is typically no point
713  * in calling this function.
714  *
715  * If you are calling this function because you changed the locale
716  * after GTK+ is was initialized, then calling this function
717  * may help a bit. (Note, however, that changing the locale
718  * after GTK+ is initialized may produce inconsistent results and
719  * is not really supported.)
720  * 
721  * In detail - sets the current locale according to the
722  * program environment. This is the same as calling the C library function
723  * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the 
724  * locale specific setup of the windowing system used by GDK.
725  * 
726  * Return value: a string corresponding to the locale set, as with the
727  * C library function <function>setlocale()</function>.
728  **/
729 gchar*
730 gtk_set_locale (void)
731 {
732   return gdk_set_locale ();
733 }
734
735 /**
736  * gtk_get_default_language:
737  *
738  * Returns the ISO language code for the default language currently in
739  * effect. (Note that this can change over the life of an
740  * application.)  The default language is derived from the current
741  * locale. It determines, for example, whether GTK+ uses the
742  * right-to-left or left-to-right text direction.
743  * 
744  * Return value: the default language as an allocated string, must be freed
745  **/
746 PangoLanguage *
747 gtk_get_default_language (void)
748 {
749   gchar *lang;
750   PangoLanguage *result;
751   gchar *p;
752   
753   lang = g_strdup (setlocale (LC_CTYPE, NULL));
754   p = strchr (lang, '.');
755   if (p)
756     *p = '\0';
757   p = strchr (lang, '@');
758   if (p)
759     *p = '\0';
760
761   result = pango_language_from_string (lang);
762   g_free (lang);
763   
764   return result;
765 }
766
767 void
768 gtk_main (void)
769 {
770   GList *tmp_list;
771   GList *functions;
772   GtkInitFunction *init;
773   GMainLoop *loop;
774
775   gtk_main_loop_level++;
776   
777   loop = g_main_new (TRUE);
778   main_loops = g_slist_prepend (main_loops, loop);
779
780   tmp_list = functions = init_functions;
781   init_functions = NULL;
782   
783   while (tmp_list)
784     {
785       init = tmp_list->data;
786       tmp_list = tmp_list->next;
787       
788       (* init->function) (init->data);
789       g_free (init);
790     }
791   g_list_free (functions);
792
793   if (g_main_is_running (main_loops->data))
794     {
795       GDK_THREADS_LEAVE ();
796       g_main_run (loop);
797       GDK_THREADS_ENTER ();
798       gdk_flush ();
799     }
800
801   if (quit_functions)
802     {
803       GList *reinvoke_list = NULL;
804       GtkQuitFunction *quitf;
805
806       while (quit_functions)
807         {
808           quitf = quit_functions->data;
809
810           tmp_list = quit_functions;
811           quit_functions = g_list_remove_link (quit_functions, quit_functions);
812           g_list_free_1 (tmp_list);
813
814           if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
815               gtk_quit_invoke_function (quitf))
816             {
817               reinvoke_list = g_list_prepend (reinvoke_list, quitf);
818             }
819           else
820             {
821               gtk_quit_destroy (quitf);
822             }
823         }
824       if (reinvoke_list)
825         {
826           GList *work;
827           
828           work = g_list_last (reinvoke_list);
829           if (quit_functions)
830             quit_functions->prev = work;
831           work->next = quit_functions;
832           quit_functions = work;
833         }
834
835       gdk_flush ();
836     }
837               
838   main_loops = g_slist_remove (main_loops, loop);
839
840   g_main_destroy (loop);
841
842   gtk_main_loop_level--;
843 }
844
845 guint
846 gtk_main_level (void)
847 {
848   return gtk_main_loop_level;
849 }
850
851 void
852 gtk_main_quit (void)
853 {
854   g_return_if_fail (main_loops != NULL);
855
856   g_main_quit (main_loops->data);
857 }
858
859 gint
860 gtk_events_pending (void)
861 {
862   gboolean result;
863   
864   GDK_THREADS_LEAVE ();  
865   result = g_main_pending ();
866   GDK_THREADS_ENTER ();
867
868   return result;
869 }
870
871 gboolean
872 gtk_main_iteration (void)
873 {
874   GDK_THREADS_LEAVE ();
875   g_main_iteration (TRUE);
876   GDK_THREADS_ENTER ();
877
878   if (main_loops)
879     return !g_main_is_running (main_loops->data);
880   else
881     return TRUE;
882 }
883
884 gboolean
885 gtk_main_iteration_do (gboolean blocking)
886 {
887   GDK_THREADS_LEAVE ();
888   g_main_iteration (blocking);
889   GDK_THREADS_ENTER ();
890
891   if (main_loops)
892     return !g_main_is_running (main_loops->data);
893   else
894     return TRUE;
895 }
896
897 void 
898 gtk_main_do_event (GdkEvent *event)
899 {
900   GtkWidget *event_widget;
901   GtkWidget *grab_widget;
902   GtkWindowGroup *window_group;
903   GdkEvent *next_event;
904   GList *tmp_list;
905
906   /* If there are any events pending then get the next one.
907    */
908   next_event = gdk_event_peek ();
909   
910   /* Try to compress enter/leave notify events. These event
911    *  pairs occur when the mouse is dragged quickly across
912    *  a window with many buttons (or through a menu). Instead
913    *  of highlighting and de-highlighting each widget that
914    *  is crossed it is better to simply de-highlight the widget
915    *  which contained the mouse initially and highlight the
916    *  widget which ends up containing the mouse.
917    */
918   if (next_event)
919     if (((event->type == GDK_ENTER_NOTIFY) ||
920          (event->type == GDK_LEAVE_NOTIFY)) &&
921         ((next_event->type == GDK_ENTER_NOTIFY) ||
922          (next_event->type == GDK_LEAVE_NOTIFY)) &&
923         (next_event->type != event->type) &&
924         (next_event->any.window == event->any.window))
925       {
926         /* Throw both the peeked copy and the queued copy away 
927          */
928         gdk_event_free (next_event);
929         next_event = gdk_event_get ();
930         gdk_event_free (next_event);
931         
932         return;
933       }
934
935   if (next_event)
936     gdk_event_free (next_event);
937
938   /* Find the widget which got the event. We store the widget
939    *  in the user_data field of GdkWindow's.
940    *  Ignore the event if we don't have a widget for it, except
941    *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
942    *  Though this happens rarely, bogus events can occour
943    *  for e.g. destroyed GdkWindows. 
944    */
945   event_widget = gtk_get_event_widget (event);
946   if (!event_widget)
947     {
948       /* To handle selection INCR transactions, we select
949        * PropertyNotify events on the requestor window and create
950        * a corresponding (fake) GdkWindow so that events get
951        * here. There won't be a widget though, so we have to handle
952            * them specially
953            */
954       if (event->type == GDK_PROPERTY_NOTIFY)
955         gtk_selection_incr_event (event->any.window,
956                                   &event->property);
957       else if (event->type == GDK_SETTING)
958         _gtk_settings_handle_event (&event->setting);
959
960       return;
961     }
962   
963   /* Push the event onto a stack of current events for
964    * gtk_current_event_get().
965    */
966   current_events = g_list_prepend (current_events, event);
967
968   window_group = gtk_main_get_window_group (event_widget);
969   
970   /* If there is a grab in effect...
971    */
972   if (window_group->grabs)
973     {
974       grab_widget = window_group->grabs->data;
975       
976       /* If the grab widget is an ancestor of the event widget
977        *  then we send the event to the original event widget.
978        *  This is the key to implementing modality.
979        */
980       if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
981           gtk_widget_is_ancestor (event_widget, grab_widget))
982         grab_widget = event_widget;
983     }
984   else
985     {
986       grab_widget = event_widget;
987     }
988
989   /* Not all events get sent to the grabbing widget.
990    * The delete, destroy, expose, focus change and resize
991    *  events still get sent to the event widget because
992    *  1) these events have no meaning for the grabbing widget
993    *  and 2) redirecting these events to the grabbing widget
994    *  could cause the display to be messed up.
995    * 
996    * Drag events are also not redirected, since it isn't
997    *  clear what the semantics of that would be.
998    */
999   switch (event->type)
1000     {
1001     case GDK_NOTHING:
1002       break;
1003       
1004     case GDK_DELETE:
1005       gtk_widget_ref (event_widget);
1006       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1007           !gtk_widget_event (event_widget, event))
1008         gtk_widget_destroy (event_widget);
1009       gtk_widget_unref (event_widget);
1010       break;
1011       
1012     case GDK_DESTROY:
1013       /* Unexpected GDK_DESTROY from the outside, ignore for
1014        * child windows, handle like a GDK_DELETE for toplevels
1015        */
1016       if (!event_widget->parent)
1017         {
1018           gtk_widget_ref (event_widget);
1019           if (!gtk_widget_event (event_widget, event) &&
1020               GTK_WIDGET_REALIZED (event_widget))
1021             gtk_widget_destroy (event_widget);
1022           gtk_widget_unref (event_widget);
1023         }
1024       break;
1025       
1026     case GDK_EXPOSE:
1027       if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
1028         {
1029           gdk_window_begin_paint_region (event->any.window, event->expose.region);
1030           gtk_widget_send_expose (event_widget, event);
1031           gdk_window_end_paint (event->any.window);
1032         }
1033       else
1034         gtk_widget_send_expose (event_widget, event);
1035       break;
1036
1037     case GDK_PROPERTY_NOTIFY:
1038     case GDK_NO_EXPOSE:
1039     case GDK_FOCUS_CHANGE:
1040     case GDK_CONFIGURE:
1041     case GDK_MAP:
1042     case GDK_UNMAP:
1043     case GDK_SELECTION_CLEAR:
1044     case GDK_SELECTION_REQUEST:
1045     case GDK_SELECTION_NOTIFY:
1046     case GDK_CLIENT_EVENT:
1047     case GDK_VISIBILITY_NOTIFY:
1048     case GDK_WINDOW_STATE:
1049       gtk_widget_event (event_widget, event);
1050       break;
1051
1052     case GDK_SCROLL:
1053     case GDK_BUTTON_PRESS:
1054     case GDK_2BUTTON_PRESS:
1055     case GDK_3BUTTON_PRESS:
1056       gtk_propagate_event (grab_widget, event);
1057       break;
1058
1059     case GDK_KEY_PRESS:
1060     case GDK_KEY_RELEASE:
1061       if (key_snoopers)
1062         {
1063           if (gtk_invoke_key_snoopers (grab_widget, event))
1064             break;
1065         }
1066       /* else fall through */
1067     case GDK_MOTION_NOTIFY:
1068     case GDK_BUTTON_RELEASE:
1069     case GDK_PROXIMITY_IN:
1070     case GDK_PROXIMITY_OUT:
1071       gtk_propagate_event (grab_widget, event);
1072       break;
1073       
1074     case GDK_ENTER_NOTIFY:
1075       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1076         {
1077           g_object_ref (event_widget);
1078           
1079           gtk_widget_event (grab_widget, event);
1080           if (event_widget == grab_widget)
1081             GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
1082           
1083           g_object_unref (event_widget);
1084         }
1085       break;
1086       
1087     case GDK_LEAVE_NOTIFY:
1088       if (GTK_WIDGET_LEAVE_PENDING (event_widget))
1089         {
1090           GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
1091           gtk_widget_event (event_widget, event);
1092         }
1093       else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1094         gtk_widget_event (grab_widget, event);
1095       break;
1096       
1097     case GDK_DRAG_STATUS:
1098     case GDK_DROP_FINISHED:
1099       _gtk_drag_source_handle_event (event_widget, event);
1100       break;
1101     case GDK_DRAG_ENTER:
1102     case GDK_DRAG_LEAVE:
1103     case GDK_DRAG_MOTION:
1104     case GDK_DROP_START:
1105       _gtk_drag_dest_handle_event (event_widget, event);
1106       break;
1107     default:
1108       g_assert_not_reached ();
1109       break;
1110     }
1111   
1112   tmp_list = current_events;
1113   current_events = g_list_remove_link (current_events, tmp_list);
1114   g_list_free_1 (tmp_list);
1115 }
1116
1117 gboolean
1118 gtk_true (void)
1119 {
1120   return TRUE;
1121 }
1122
1123 gboolean
1124 gtk_false (void)
1125 {
1126   return FALSE;
1127 }
1128
1129 static GtkWindowGroup *
1130 gtk_main_get_window_group (GtkWidget   *widget)
1131 {
1132   GtkWidget *toplevel = NULL;
1133
1134   if (widget)
1135     toplevel = gtk_widget_get_toplevel (widget);
1136
1137   if (toplevel && GTK_IS_WINDOW (toplevel))
1138     return _gtk_window_get_group (GTK_WINDOW (toplevel));
1139   else
1140     return _gtk_window_get_group (NULL);
1141 }
1142
1143 typedef struct
1144 {
1145   GtkWidget *old_grab_widget;
1146   GtkWidget *new_grab_widget;
1147 } GrabNotifyInfo;
1148
1149 static gboolean
1150 check_is_grabbed (GtkWidget *widget,
1151                   GtkWidget *grab_widget)
1152 {
1153   if (grab_widget)
1154     return !(widget == grab_widget || gtk_widget_is_ancestor (widget, grab_widget));
1155   else
1156     return FALSE;
1157 }
1158
1159 static void
1160 gtk_grab_notify_foreach (GtkWidget *child,
1161                          gpointer   data)
1162                         
1163 {
1164   GrabNotifyInfo *info = data;
1165   gboolean was_grabbed = check_is_grabbed (child, info->old_grab_widget);
1166   gboolean is_grabbed = check_is_grabbed (child, info->new_grab_widget);
1167
1168   if (was_grabbed != is_grabbed)
1169     {
1170       g_object_ref (G_OBJECT (child));
1171       
1172       gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", was_grabbed);
1173       
1174       if (GTK_IS_CONTAINER (child))
1175         gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1176       
1177       g_object_unref (G_OBJECT (child));
1178     }
1179 }
1180
1181 static void
1182 gtk_grab_notify (GtkWindowGroup *group,
1183                  GtkWidget      *grab_widget,
1184                  gboolean        was_grabbed)
1185 {
1186   GList *toplevels;
1187   GrabNotifyInfo info;
1188
1189   if (was_grabbed)
1190     {
1191       info.old_grab_widget = grab_widget;
1192       info.new_grab_widget = group->grabs ? group->grabs->data : NULL;
1193     }
1194   else
1195     {
1196       info.old_grab_widget = (group->grabs && group->grabs->next) ? group->grabs->next->data : NULL;
1197       info.new_grab_widget = grab_widget;
1198     }
1199
1200   g_object_ref (group);
1201   g_object_ref (grab_widget);
1202
1203   toplevels = gtk_window_list_toplevels ();
1204   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1205                             
1206   while (toplevels)
1207     {
1208       GtkWindow *toplevel = toplevels->data;
1209       toplevels = g_list_delete_link (toplevels, toplevels);
1210
1211       if (group == _gtk_window_get_group (toplevel))
1212         gtk_container_foreach (GTK_CONTAINER (toplevel), gtk_grab_notify_foreach, &info);
1213       g_object_unref (toplevel);
1214     }
1215
1216   g_object_unref (group);
1217   g_object_unref (grab_widget);
1218 }
1219
1220 void
1221 gtk_grab_add (GtkWidget *widget)
1222 {
1223   GtkWindowGroup *group;
1224   gboolean was_grabbed;
1225   
1226   g_return_if_fail (widget != NULL);
1227   
1228   if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
1229     {
1230       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
1231       
1232       group = gtk_main_get_window_group (widget);
1233
1234       was_grabbed = (group->grabs != NULL);
1235       
1236       gtk_widget_ref (widget);
1237       group->grabs = g_slist_prepend (group->grabs, widget);
1238
1239       gtk_grab_notify (group, widget, FALSE);
1240     }
1241 }
1242
1243 GtkWidget*
1244 gtk_grab_get_current (void)
1245 {
1246   GtkWindowGroup *group;
1247
1248   group = gtk_main_get_window_group (NULL);
1249
1250   if (group->grabs)
1251     return GTK_WIDGET (group->grabs->data);
1252   return NULL;
1253 }
1254
1255 void
1256 gtk_grab_remove (GtkWidget *widget)
1257 {
1258   GtkWindowGroup *group;
1259   
1260   g_return_if_fail (widget != NULL);
1261   
1262   if (GTK_WIDGET_HAS_GRAB (widget))
1263     {
1264       GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
1265
1266       group = gtk_main_get_window_group (widget);
1267       group->grabs = g_slist_remove (group->grabs, widget);
1268       
1269       gtk_widget_unref (widget);
1270
1271       gtk_grab_notify (group, widget, TRUE);
1272     }
1273 }
1274
1275 void
1276 gtk_init_add (GtkFunction function,
1277               gpointer    data)
1278 {
1279   GtkInitFunction *init;
1280   
1281   init = g_new (GtkInitFunction, 1);
1282   init->function = function;
1283   init->data = data;
1284   
1285   init_functions = g_list_prepend (init_functions, init);
1286 }
1287
1288 guint
1289 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
1290                          gpointer        func_data)
1291 {
1292   GtkKeySnooperData *data;
1293   static guint snooper_id = 1;
1294
1295   g_return_val_if_fail (snooper != NULL, 0);
1296
1297   data = g_new (GtkKeySnooperData, 1);
1298   data->func = snooper;
1299   data->func_data = func_data;
1300   data->id = snooper_id++;
1301   key_snoopers = g_slist_prepend (key_snoopers, data);
1302
1303   return data->id;
1304 }
1305
1306 void
1307 gtk_key_snooper_remove (guint            snooper_id)
1308 {
1309   GtkKeySnooperData *data = NULL;
1310   GSList *slist;
1311
1312   slist = key_snoopers;
1313   while (slist)
1314     {
1315       data = slist->data;
1316       if (data->id == snooper_id)
1317         break;
1318
1319       slist = slist->next;
1320       data = NULL;
1321     }
1322   if (data)
1323     key_snoopers = g_slist_remove (key_snoopers, data);
1324 }
1325
1326 static gint
1327 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
1328                          GdkEvent  *event)
1329 {
1330   GSList *slist;
1331   gint return_val = FALSE;
1332
1333   slist = key_snoopers;
1334   while (slist && !return_val)
1335     {
1336       GtkKeySnooperData *data;
1337
1338       data = slist->data;
1339       slist = slist->next;
1340       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
1341     }
1342
1343   return return_val;
1344 }
1345
1346 guint
1347 gtk_quit_add_full (guint                main_level,
1348                    GtkFunction          function,
1349                    GtkCallbackMarshal   marshal,
1350                    gpointer             data,
1351                    GtkDestroyNotify     destroy)
1352 {
1353   static guint quit_id = 1;
1354   GtkQuitFunction *quitf;
1355   
1356   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
1357
1358   if (!quit_mem_chunk)
1359     quit_mem_chunk = g_mem_chunk_new ("quit mem chunk", sizeof (GtkQuitFunction),
1360                                       512, G_ALLOC_AND_FREE);
1361   
1362   quitf = g_chunk_new (GtkQuitFunction, quit_mem_chunk);
1363   
1364   quitf->id = quit_id++;
1365   quitf->main_level = main_level;
1366   quitf->function = function;
1367   quitf->marshal = marshal;
1368   quitf->data = data;
1369   quitf->destroy = destroy;
1370
1371   quit_functions = g_list_prepend (quit_functions, quitf);
1372   
1373   return quitf->id;
1374 }
1375
1376 static void
1377 gtk_quit_destroy (GtkQuitFunction *quitf)
1378 {
1379   if (quitf->destroy)
1380     quitf->destroy (quitf->data);
1381   g_mem_chunk_free (quit_mem_chunk, quitf);
1382 }
1383
1384 static gint
1385 gtk_quit_destructor (GtkObject **object_p)
1386 {
1387   if (*object_p)
1388     gtk_object_destroy (*object_p);
1389   g_free (object_p);
1390
1391   return FALSE;
1392 }
1393
1394 void
1395 gtk_quit_add_destroy (guint              main_level,
1396                       GtkObject         *object)
1397 {
1398   GtkObject **object_p;
1399
1400   g_return_if_fail (main_level > 0);
1401   g_return_if_fail (GTK_IS_OBJECT (object));
1402
1403   object_p = g_new (GtkObject*, 1);
1404   *object_p = object;
1405   gtk_signal_connect (object,
1406                       "destroy",
1407                       GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1408                       object_p);
1409   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1410 }
1411
1412 guint
1413 gtk_quit_add (guint       main_level,
1414               GtkFunction function,
1415               gpointer    data)
1416 {
1417   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
1418 }
1419
1420 void
1421 gtk_quit_remove (guint id)
1422 {
1423   GtkQuitFunction *quitf;
1424   GList *tmp_list;
1425   
1426   tmp_list = quit_functions;
1427   while (tmp_list)
1428     {
1429       quitf = tmp_list->data;
1430       
1431       if (quitf->id == id)
1432         {
1433           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1434           g_list_free (tmp_list);
1435           gtk_quit_destroy (quitf);
1436           
1437           return;
1438         }
1439       
1440       tmp_list = tmp_list->next;
1441     }
1442 }
1443
1444 void
1445 gtk_quit_remove_by_data (gpointer data)
1446 {
1447   GtkQuitFunction *quitf;
1448   GList *tmp_list;
1449   
1450   tmp_list = quit_functions;
1451   while (tmp_list)
1452     {
1453       quitf = tmp_list->data;
1454       
1455       if (quitf->data == data)
1456         {
1457           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1458           g_list_free (tmp_list);
1459           gtk_quit_destroy (quitf);
1460
1461           return;
1462         }
1463       
1464       tmp_list = tmp_list->next;
1465     }
1466 }
1467
1468 guint
1469 gtk_timeout_add_full (guint32            interval,
1470                       GtkFunction        function,
1471                       GtkCallbackMarshal marshal,
1472                       gpointer           data,
1473                       GtkDestroyNotify   destroy)
1474 {
1475   if (marshal)
1476     {
1477       GtkClosure *closure;
1478
1479       closure = g_new (GtkClosure, 1);
1480       closure->marshal = marshal;
1481       closure->data = data;
1482       closure->destroy = destroy;
1483
1484       return g_timeout_add_full (0, interval, 
1485                                  gtk_invoke_idle_timeout,
1486                                  closure,
1487                                  gtk_destroy_closure);
1488     }
1489   else
1490     return g_timeout_add_full (0, interval, function, data, destroy);
1491 }
1492
1493 guint
1494 gtk_timeout_add (guint32     interval,
1495                  GtkFunction function,
1496                  gpointer    data)
1497 {
1498   return g_timeout_add_full (0, interval, function, data, NULL);
1499 }
1500
1501 void
1502 gtk_timeout_remove (guint tag)
1503 {
1504   g_source_remove (tag);
1505 }
1506
1507 guint
1508 gtk_idle_add_full (gint                 priority,
1509                    GtkFunction          function,
1510                    GtkCallbackMarshal   marshal,
1511                    gpointer             data,
1512                    GtkDestroyNotify     destroy)
1513 {
1514   if (marshal)
1515     {
1516       GtkClosure *closure;
1517
1518       closure = g_new (GtkClosure, 1);
1519       closure->marshal = marshal;
1520       closure->data = data;
1521       closure->destroy = destroy;
1522
1523       return g_idle_add_full (priority,
1524                               gtk_invoke_idle_timeout,
1525                               closure,
1526                               gtk_destroy_closure);
1527     }
1528   else
1529     return g_idle_add_full (priority, function, data, destroy);
1530 }
1531
1532 guint
1533 gtk_idle_add (GtkFunction function,
1534               gpointer    data)
1535 {
1536   return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL);
1537 }
1538
1539 guint       
1540 gtk_idle_add_priority (gint        priority,
1541                        GtkFunction function,
1542                        gpointer    data)
1543 {
1544   return g_idle_add_full (priority, function, data, NULL);
1545 }
1546
1547 void
1548 gtk_idle_remove (guint tag)
1549 {
1550   g_source_remove (tag);
1551 }
1552
1553 void
1554 gtk_idle_remove_by_data (gpointer data)
1555 {
1556   if (!g_idle_remove_by_data (data))
1557     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
1558 }
1559
1560 guint
1561 gtk_input_add_full (gint                source,
1562                     GdkInputCondition   condition,
1563                     GdkInputFunction    function,
1564                     GtkCallbackMarshal  marshal,
1565                     gpointer            data,
1566                     GtkDestroyNotify    destroy)
1567 {
1568   if (marshal)
1569     {
1570       GtkClosure *closure;
1571
1572       closure = g_new (GtkClosure, 1);
1573       closure->marshal = marshal;
1574       closure->data = data;
1575       closure->destroy = destroy;
1576
1577       return gdk_input_add_full (source,
1578                                  condition,
1579                                  (GdkInputFunction) gtk_invoke_input,
1580                                  closure,
1581                                  (GdkDestroyNotify) gtk_destroy_closure);
1582     }
1583   else
1584     return gdk_input_add_full (source, condition, function, data, destroy);
1585 }
1586
1587 void
1588 gtk_input_remove (guint tag)
1589 {
1590   g_source_remove (tag);
1591 }
1592
1593 static void
1594 gtk_destroy_closure (gpointer data)
1595 {
1596   GtkClosure *closure = data;
1597
1598   if (closure->destroy)
1599     (closure->destroy) (closure->data);
1600   g_free (closure);
1601 }
1602
1603 static gboolean
1604 gtk_invoke_idle_timeout (gpointer data)
1605 {
1606   GtkClosure *closure = data;
1607
1608   GtkArg args[1];
1609   gint ret_val = FALSE;
1610   args[0].name = NULL;
1611   args[0].type = GTK_TYPE_BOOL;
1612   args[0].d.pointer_data = &ret_val;
1613   closure->marshal (NULL, closure->data,  0, args);
1614   return ret_val;
1615 }
1616
1617 static void
1618 gtk_invoke_input (gpointer          data,
1619                   gint              source,
1620                   GdkInputCondition condition)
1621 {
1622   GtkClosure *closure = data;
1623
1624   GtkArg args[3];
1625   args[0].type = GTK_TYPE_INT;
1626   args[0].name = NULL;
1627   GTK_VALUE_INT (args[0]) = source;
1628   args[1].type = GDK_TYPE_INPUT_CONDITION;
1629   args[1].name = NULL;
1630   GTK_VALUE_FLAGS (args[1]) = condition;
1631   args[2].type = GTK_TYPE_NONE;
1632   args[2].name = NULL;
1633
1634   closure->marshal (NULL, closure->data, 2, args);
1635 }
1636
1637 /**
1638  * gtk_get_current_event:
1639  * 
1640  * Obtains a copy of the event currently being processed by GTK+.  For
1641  * example, if you get a "clicked" signal from #GtkButton, the current
1642  * event will be the #GdkEventButton that triggered the "clicked"
1643  * signal. The returned event must be freed with gdk_event_free().
1644  * If there is no current event, the function returns %NULL.
1645  * 
1646  * Return value: a copy of the current event, or %NULL if no current event.
1647  **/
1648 GdkEvent*
1649 gtk_get_current_event (void)
1650 {
1651   if (current_events)
1652     return gdk_event_copy (current_events->data);
1653   else
1654     return NULL;
1655 }
1656
1657 /**
1658  * gtk_get_current_event_time:
1659  * 
1660  * If there is a current event and it has a timestamp, return that
1661  * timestamp, otherwise return %GDK_CURRENT_TIME.
1662  * 
1663  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
1664  **/
1665 guint32
1666 gtk_get_current_event_time (void)
1667 {
1668   if (current_events)
1669     return gdk_event_get_time (current_events->data);
1670   else
1671     return GDK_CURRENT_TIME;
1672 }
1673
1674 /**
1675  * gtk_get_current_event_state:
1676  * @state: a location to store the state of the current event
1677  * 
1678  * If there is a current event and it has a state field, place
1679  * that state field in @state and return %TRUE, otherwise return
1680  * %FALSE.
1681  * 
1682  * Return value: %TRUE if there was a current event and it had a state field
1683  **/
1684 gboolean
1685 gtk_get_current_event_state (GdkModifierType *state)
1686 {
1687   g_return_val_if_fail (state != NULL, FALSE);
1688   
1689   if (current_events)
1690     return gdk_event_get_state (current_events->data, state);
1691   else
1692     {
1693       *state = 0;
1694       return FALSE;
1695     }
1696 }
1697
1698 /**
1699  * gtk_get_event_widget:
1700  * @event: a #GdkEvent
1701  *
1702  * If @event is %NULL or the event was not associated with any widget,
1703  * returns %NULL, otherwise returns the widget that received the event
1704  * originally.
1705  * 
1706  * Return value: the widget that originally received @event, or %NULL
1707  **/
1708 GtkWidget*
1709 gtk_get_event_widget (GdkEvent *event)
1710 {
1711   GtkWidget *widget;
1712
1713   widget = NULL;
1714   if (event && event->any.window)
1715     gdk_window_get_user_data (event->any.window, (void**) &widget);
1716   
1717   return widget;
1718 }
1719
1720 static gint
1721 gtk_quit_invoke_function (GtkQuitFunction *quitf)
1722 {
1723   if (!quitf->marshal)
1724     return quitf->function (quitf->data);
1725   else
1726     {
1727       GtkArg args[1];
1728       gint ret_val = FALSE;
1729
1730       args[0].name = NULL;
1731       args[0].type = GTK_TYPE_BOOL;
1732       args[0].d.pointer_data = &ret_val;
1733       ((GtkCallbackMarshal) quitf->marshal) (NULL,
1734                                              quitf->data,
1735                                              0, args);
1736       return ret_val;
1737     }
1738 }
1739
1740 /**
1741  * gtk_propagate_event:
1742  * @widget: a #GtkWidget
1743  * @event: an event
1744  *
1745  * Sends an event to a widget, propagating the event to parent widgets
1746  * if the event remains unhandled. Events received by GTK+ from GDK
1747  * normally begin in gtk_main_do_event(). Depending on the type of
1748  * event, existence of modal dialogs, grabs, etc., the event may be
1749  * propagated; if so, this function is used. gtk_propagate_event()
1750  * calls gtk_widget_event() on each widget it decides to send the
1751  * event to.  So gtk_widget_event() is the lowest-level function; it
1752  * simply emits the "event" and possibly an event-specific signal on a
1753  * widget.  gtk_propagate_event() is a bit higher-level, and
1754  * gtk_main_do_event() is the highest level.
1755  *
1756  * All that said, you most likely don't want to use any of these
1757  * functions; synthesizing events is rarely needed. Consider asking on
1758  * the mailing list for better ways to achieve your goals. For
1759  * example, use gdk_window_invalidate_rect() or
1760  * gtk_widget_queue_draw() instead of making up expose events.
1761  * 
1762  **/
1763 void
1764 gtk_propagate_event (GtkWidget *widget,
1765                      GdkEvent  *event)
1766 {
1767   gint handled_event;
1768   
1769   g_return_if_fail (GTK_IS_WIDGET (widget));
1770   g_return_if_fail (event != NULL);
1771   
1772   handled_event = FALSE;
1773
1774   gtk_widget_ref (widget);
1775       
1776   if ((event->type == GDK_KEY_PRESS) ||
1777       (event->type == GDK_KEY_RELEASE))
1778     {
1779       /* Only send key events within Window widgets to the Window
1780        *  The Window widget will in turn pass the
1781        *  key event on to the currently focused widget
1782        *  for that window.
1783        */
1784       GtkWidget *window;
1785
1786       window = gtk_widget_get_toplevel (widget);
1787       if (window && GTK_IS_WINDOW (window))
1788         {
1789           /* If there is a grab within the window, give the grab widget
1790            * a first crack at the key event
1791            */
1792           if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
1793             handled_event = gtk_widget_event (widget, event);
1794           
1795           if (!handled_event)
1796             {
1797               window = gtk_widget_get_toplevel (widget);
1798               if (window && GTK_IS_WINDOW (window))
1799                 {
1800                   if (GTK_WIDGET_IS_SENSITIVE (window))
1801                     gtk_widget_event (window, event);
1802                 }
1803             }
1804                   
1805           handled_event = TRUE; /* don't send to widget */
1806         }
1807     }
1808   
1809   /* Other events get propagated up the widget tree
1810    *  so that parents can see the button and motion
1811    *  events of the children.
1812    */
1813   if (!handled_event)
1814     {
1815       while (TRUE)
1816         {
1817           GtkWidget *tmp;
1818           
1819           handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
1820           tmp = widget->parent;
1821           gtk_widget_unref (widget);
1822
1823           widget = tmp;
1824           
1825           if (!handled_event && widget)
1826             gtk_widget_ref (widget);
1827           else
1828             break;
1829         }
1830     }
1831   else
1832     gtk_widget_unref (widget);
1833 }
1834
1835 #if 0
1836 static void
1837 gtk_error (gchar *str)
1838 {
1839   gtk_print (str);
1840 }
1841
1842 static void
1843 gtk_warning (gchar *str)
1844 {
1845   gtk_print (str);
1846 }
1847
1848 static void
1849 gtk_message (gchar *str)
1850 {
1851   gtk_print (str);
1852 }
1853
1854 static void
1855 gtk_print (gchar *str)
1856 {
1857   static GtkWidget *window = NULL;
1858   static GtkWidget *text;
1859   static int level = 0;
1860   GtkWidget *box1;
1861   GtkWidget *box2;
1862   GtkWidget *table;
1863   GtkWidget *hscrollbar;
1864   GtkWidget *vscrollbar;
1865   GtkWidget *separator;
1866   GtkWidget *button;
1867   
1868   if (level > 0)
1869     {
1870       fputs (str, stdout);
1871       fflush (stdout);
1872       return;
1873     }
1874   
1875   if (!window)
1876     {
1877       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1878       
1879       gtk_signal_connect (GTK_OBJECT (window), "destroy",
1880                           (GtkSignalFunc) gtk_widget_destroyed,
1881                           &window);
1882       
1883       gtk_window_set_title (GTK_WINDOW (window), "Messages");
1884       
1885       box1 = gtk_vbox_new (FALSE, 0);
1886       gtk_container_add (GTK_CONTAINER (window), box1);
1887       gtk_widget_show (box1);
1888       
1889       
1890       box2 = gtk_vbox_new (FALSE, 10);
1891       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1892       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
1893       gtk_widget_show (box2);
1894       
1895       
1896       table = gtk_table_new (2, 2, FALSE);
1897       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
1898       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
1899       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
1900       gtk_widget_show (table);
1901       
1902       text = gtk_text_new (NULL, NULL);
1903       gtk_text_set_editable (GTK_TEXT (text), FALSE);
1904       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
1905       gtk_widget_show (text);
1906       gtk_widget_realize (text);
1907       
1908       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
1909       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
1910                         GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1911       gtk_widget_show (hscrollbar);
1912       
1913       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
1914       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
1915                         GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1916       gtk_widget_show (vscrollbar);
1917       
1918       separator = gtk_hseparator_new ();
1919       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
1920       gtk_widget_show (separator);
1921       
1922       
1923       box2 = gtk_vbox_new (FALSE, 10);
1924       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1925       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
1926       gtk_widget_show (box2);
1927       
1928       
1929       button = gtk_button_new_with_label ("close");
1930       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1931                                  (GtkSignalFunc) gtk_widget_hide,
1932                                  GTK_OBJECT (window));
1933       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1934       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1935       gtk_widget_grab_default (button);
1936       gtk_widget_show (button);
1937     }
1938   
1939   level += 1;
1940   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
1941   level -= 1;
1942   
1943   if (!GTK_WIDGET_VISIBLE (window))
1944     gtk_widget_show (window);
1945 }
1946 #endif
1947
1948 gboolean
1949 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
1950                                   GValue                *return_accu,
1951                                   const GValue          *handler_return,
1952                                   gpointer               dummy)
1953 {
1954   gboolean continue_emission;
1955   gboolean signal_handled;
1956   
1957   signal_handled = g_value_get_boolean (handler_return);
1958   g_value_set_boolean (return_accu, signal_handled);
1959   continue_emission = !signal_handled;
1960   
1961   return continue_emission;
1962 }