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