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