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