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