]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
Don't skip internal children when emitting grab-notify. (#343425, Markku
[~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 const 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   gboolean   was_grabbed;
1500   gboolean   is_grabbed;
1501 } GrabNotifyInfo;
1502
1503 static void
1504 gtk_grab_notify_foreach (GtkWidget *child,
1505                          gpointer   data)
1506                         
1507 {
1508   GrabNotifyInfo *info = data;
1509  
1510   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1511
1512   was_grabbed = info->was_grabbed;
1513   is_grabbed = info->is_grabbed;
1514
1515   info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1516   info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1517
1518   was_shadowed = info->old_grab_widget && !info->was_grabbed;
1519   is_shadowed = info->new_grab_widget && !info->is_grabbed;
1520
1521   g_object_ref (child);
1522   
1523   if (was_shadowed != is_shadowed)
1524     _gtk_widget_grab_notify (child, was_shadowed);
1525   
1526   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1527     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1528       
1529   g_object_unref (child);
1530   
1531   info->was_grabbed = was_grabbed;
1532   info->is_grabbed = is_grabbed;
1533 }
1534
1535 static void
1536 gtk_grab_notify (GtkWindowGroup *group,
1537                  GtkWidget      *old_grab_widget,
1538                  GtkWidget      *new_grab_widget)
1539 {
1540   GList *toplevels;
1541   GrabNotifyInfo info;
1542
1543   if (old_grab_widget == new_grab_widget)
1544     return;
1545
1546   info.old_grab_widget = old_grab_widget;
1547   info.new_grab_widget = new_grab_widget;
1548
1549   g_object_ref (group);
1550
1551   toplevels = gtk_window_list_toplevels ();
1552   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1553                             
1554   while (toplevels)
1555     {
1556       GtkWindow *toplevel = toplevels->data;
1557       toplevels = g_list_delete_link (toplevels, toplevels);
1558
1559       info.was_grabbed = FALSE;
1560       info.is_grabbed = FALSE;
1561
1562       if (group == gtk_window_get_group (toplevel))
1563         gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1564       g_object_unref (toplevel);
1565     }
1566
1567   g_object_unref (group);
1568 }
1569
1570 void
1571 gtk_grab_add (GtkWidget *widget)
1572 {
1573   GtkWindowGroup *group;
1574   GtkWidget *old_grab_widget;
1575   
1576   g_return_if_fail (widget != NULL);
1577   
1578   if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
1579     {
1580       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
1581       
1582       group = gtk_main_get_window_group (widget);
1583
1584       if (group->grabs)
1585         old_grab_widget = (GtkWidget *)group->grabs->data;
1586       else
1587         old_grab_widget = NULL;
1588
1589       g_object_ref (widget);
1590       group->grabs = g_slist_prepend (group->grabs, widget);
1591
1592       gtk_grab_notify (group, old_grab_widget, widget);
1593     }
1594 }
1595
1596 GtkWidget*
1597 gtk_grab_get_current (void)
1598 {
1599   GtkWindowGroup *group;
1600
1601   group = gtk_main_get_window_group (NULL);
1602
1603   if (group->grabs)
1604     return GTK_WIDGET (group->grabs->data);
1605   return NULL;
1606 }
1607
1608 void
1609 gtk_grab_remove (GtkWidget *widget)
1610 {
1611   GtkWindowGroup *group;
1612   GtkWidget *new_grab_widget;
1613   
1614   g_return_if_fail (widget != NULL);
1615   
1616   if (GTK_WIDGET_HAS_GRAB (widget))
1617     {
1618       GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
1619
1620       group = gtk_main_get_window_group (widget);
1621       group->grabs = g_slist_remove (group->grabs, widget);
1622       
1623       if (group->grabs)
1624         new_grab_widget = (GtkWidget *)group->grabs->data;
1625       else
1626         new_grab_widget = NULL;
1627
1628       gtk_grab_notify (group, widget, new_grab_widget);
1629       
1630       g_object_unref (widget);
1631     }
1632 }
1633
1634 void
1635 gtk_init_add (GtkFunction function,
1636               gpointer    data)
1637 {
1638   GtkInitFunction *init;
1639   
1640   init = g_new (GtkInitFunction, 1);
1641   init->function = function;
1642   init->data = data;
1643   
1644   init_functions = g_list_prepend (init_functions, init);
1645 }
1646
1647 guint
1648 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
1649                          gpointer        func_data)
1650 {
1651   GtkKeySnooperData *data;
1652   static guint snooper_id = 1;
1653
1654   g_return_val_if_fail (snooper != NULL, 0);
1655
1656   data = g_new (GtkKeySnooperData, 1);
1657   data->func = snooper;
1658   data->func_data = func_data;
1659   data->id = snooper_id++;
1660   key_snoopers = g_slist_prepend (key_snoopers, data);
1661
1662   return data->id;
1663 }
1664
1665 void
1666 gtk_key_snooper_remove (guint snooper_id)
1667 {
1668   GtkKeySnooperData *data = NULL;
1669   GSList *slist;
1670
1671   slist = key_snoopers;
1672   while (slist)
1673     {
1674       data = slist->data;
1675       if (data->id == snooper_id)
1676         break;
1677
1678       slist = slist->next;
1679       data = NULL;
1680     }
1681   if (data)
1682     {
1683       key_snoopers = g_slist_remove (key_snoopers, data);
1684       g_free (data);
1685     }
1686 }
1687
1688 static gint
1689 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
1690                          GdkEvent  *event)
1691 {
1692   GSList *slist;
1693   gint return_val = FALSE;
1694
1695   slist = key_snoopers;
1696   while (slist && !return_val)
1697     {
1698       GtkKeySnooperData *data;
1699
1700       data = slist->data;
1701       slist = slist->next;
1702       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
1703     }
1704
1705   return return_val;
1706 }
1707
1708 guint
1709 gtk_quit_add_full (guint                main_level,
1710                    GtkFunction          function,
1711                    GtkCallbackMarshal   marshal,
1712                    gpointer             data,
1713                    GtkDestroyNotify     destroy)
1714 {
1715   static guint quit_id = 1;
1716   GtkQuitFunction *quitf;
1717   
1718   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
1719
1720   quitf = g_slice_new (GtkQuitFunction);
1721   
1722   quitf->id = quit_id++;
1723   quitf->main_level = main_level;
1724   quitf->function = function;
1725   quitf->marshal = marshal;
1726   quitf->data = data;
1727   quitf->destroy = destroy;
1728
1729   quit_functions = g_list_prepend (quit_functions, quitf);
1730   
1731   return quitf->id;
1732 }
1733
1734 static void
1735 gtk_quit_destroy (GtkQuitFunction *quitf)
1736 {
1737   if (quitf->destroy)
1738     quitf->destroy (quitf->data);
1739   g_slice_free (GtkQuitFunction, quitf);
1740 }
1741
1742 static gint
1743 gtk_quit_destructor (GtkObject **object_p)
1744 {
1745   if (*object_p)
1746     gtk_object_destroy (*object_p);
1747   g_free (object_p);
1748
1749   return FALSE;
1750 }
1751
1752 void
1753 gtk_quit_add_destroy (guint              main_level,
1754                       GtkObject         *object)
1755 {
1756   GtkObject **object_p;
1757
1758   g_return_if_fail (main_level > 0);
1759   g_return_if_fail (GTK_IS_OBJECT (object));
1760
1761   object_p = g_new (GtkObject*, 1);
1762   *object_p = object;
1763   g_signal_connect (object,
1764                     "destroy",
1765                     G_CALLBACK (gtk_widget_destroyed),
1766                     object_p);
1767   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1768 }
1769
1770 guint
1771 gtk_quit_add (guint       main_level,
1772               GtkFunction function,
1773               gpointer    data)
1774 {
1775   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
1776 }
1777
1778 void
1779 gtk_quit_remove (guint id)
1780 {
1781   GtkQuitFunction *quitf;
1782   GList *tmp_list;
1783   
1784   tmp_list = quit_functions;
1785   while (tmp_list)
1786     {
1787       quitf = tmp_list->data;
1788       
1789       if (quitf->id == id)
1790         {
1791           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1792           g_list_free (tmp_list);
1793           gtk_quit_destroy (quitf);
1794           
1795           return;
1796         }
1797       
1798       tmp_list = tmp_list->next;
1799     }
1800 }
1801
1802 void
1803 gtk_quit_remove_by_data (gpointer data)
1804 {
1805   GtkQuitFunction *quitf;
1806   GList *tmp_list;
1807   
1808   tmp_list = quit_functions;
1809   while (tmp_list)
1810     {
1811       quitf = tmp_list->data;
1812       
1813       if (quitf->data == data)
1814         {
1815           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1816           g_list_free (tmp_list);
1817           gtk_quit_destroy (quitf);
1818
1819           return;
1820         }
1821       
1822       tmp_list = tmp_list->next;
1823     }
1824 }
1825
1826 guint
1827 gtk_timeout_add_full (guint32            interval,
1828                       GtkFunction        function,
1829                       GtkCallbackMarshal marshal,
1830                       gpointer           data,
1831                       GtkDestroyNotify   destroy)
1832 {
1833   if (marshal)
1834     {
1835       GtkClosure *closure;
1836
1837       closure = g_new (GtkClosure, 1);
1838       closure->marshal = marshal;
1839       closure->data = data;
1840       closure->destroy = destroy;
1841
1842       return g_timeout_add_full (0, interval, 
1843                                  gtk_invoke_idle_timeout,
1844                                  closure,
1845                                  gtk_destroy_closure);
1846     }
1847   else
1848     return g_timeout_add_full (0, interval, function, data, destroy);
1849 }
1850
1851 guint
1852 gtk_timeout_add (guint32     interval,
1853                  GtkFunction function,
1854                  gpointer    data)
1855 {
1856   return g_timeout_add_full (0, interval, function, data, NULL);
1857 }
1858
1859 void
1860 gtk_timeout_remove (guint tag)
1861 {
1862   g_source_remove (tag);
1863 }
1864
1865 guint
1866 gtk_idle_add_full (gint                 priority,
1867                    GtkFunction          function,
1868                    GtkCallbackMarshal   marshal,
1869                    gpointer             data,
1870                    GtkDestroyNotify     destroy)
1871 {
1872   if (marshal)
1873     {
1874       GtkClosure *closure;
1875
1876       closure = g_new (GtkClosure, 1);
1877       closure->marshal = marshal;
1878       closure->data = data;
1879       closure->destroy = destroy;
1880
1881       return g_idle_add_full (priority,
1882                               gtk_invoke_idle_timeout,
1883                               closure,
1884                               gtk_destroy_closure);
1885     }
1886   else
1887     return g_idle_add_full (priority, function, data, destroy);
1888 }
1889
1890 guint
1891 gtk_idle_add (GtkFunction function,
1892               gpointer    data)
1893 {
1894   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
1895 }
1896
1897 guint       
1898 gtk_idle_add_priority (gint        priority,
1899                        GtkFunction function,
1900                        gpointer    data)
1901 {
1902   return g_idle_add_full (priority, function, data, NULL);
1903 }
1904
1905 void
1906 gtk_idle_remove (guint tag)
1907 {
1908   g_source_remove (tag);
1909 }
1910
1911 void
1912 gtk_idle_remove_by_data (gpointer data)
1913 {
1914   if (!g_idle_remove_by_data (data))
1915     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
1916 }
1917
1918 guint
1919 gtk_input_add_full (gint                source,
1920                     GdkInputCondition   condition,
1921                     GdkInputFunction    function,
1922                     GtkCallbackMarshal  marshal,
1923                     gpointer            data,
1924                     GtkDestroyNotify    destroy)
1925 {
1926   if (marshal)
1927     {
1928       GtkClosure *closure;
1929
1930       closure = g_new (GtkClosure, 1);
1931       closure->marshal = marshal;
1932       closure->data = data;
1933       closure->destroy = destroy;
1934
1935       return gdk_input_add_full (source,
1936                                  condition,
1937                                  (GdkInputFunction) gtk_invoke_input,
1938                                  closure,
1939                                  (GdkDestroyNotify) gtk_destroy_closure);
1940     }
1941   else
1942     return gdk_input_add_full (source, condition, function, data, destroy);
1943 }
1944
1945 void
1946 gtk_input_remove (guint tag)
1947 {
1948   g_source_remove (tag);
1949 }
1950
1951 static void
1952 gtk_destroy_closure (gpointer data)
1953 {
1954   GtkClosure *closure = data;
1955
1956   if (closure->destroy)
1957     (closure->destroy) (closure->data);
1958   g_free (closure);
1959 }
1960
1961 static gboolean
1962 gtk_invoke_idle_timeout (gpointer data)
1963 {
1964   GtkClosure *closure = data;
1965
1966   GtkArg args[1];
1967   gint ret_val = FALSE;
1968   args[0].name = NULL;
1969   args[0].type = G_TYPE_BOOLEAN;
1970   args[0].d.pointer_data = &ret_val;
1971   closure->marshal (NULL, closure->data,  0, args);
1972   return ret_val;
1973 }
1974
1975 static void
1976 gtk_invoke_input (gpointer          data,
1977                   gint              source,
1978                   GdkInputCondition condition)
1979 {
1980   GtkClosure *closure = data;
1981
1982   GtkArg args[3];
1983   args[0].type = G_TYPE_INT;
1984   args[0].name = NULL;
1985   GTK_VALUE_INT (args[0]) = source;
1986   args[1].type = GDK_TYPE_INPUT_CONDITION;
1987   args[1].name = NULL;
1988   GTK_VALUE_FLAGS (args[1]) = condition;
1989   args[2].type = G_TYPE_NONE;
1990   args[2].name = NULL;
1991
1992   closure->marshal (NULL, closure->data, 2, args);
1993 }
1994
1995 /**
1996  * gtk_get_current_event:
1997  * 
1998  * Obtains a copy of the event currently being processed by GTK+.  For
1999  * example, if you get a "clicked" signal from #GtkButton, the current
2000  * event will be the #GdkEventButton that triggered the "clicked"
2001  * signal. The returned event must be freed with gdk_event_free().
2002  * If there is no current event, the function returns %NULL.
2003  * 
2004  * Return value: a copy of the current event, or %NULL if no current event.
2005  **/
2006 GdkEvent*
2007 gtk_get_current_event (void)
2008 {
2009   if (current_events)
2010     return gdk_event_copy (current_events->data);
2011   else
2012     return NULL;
2013 }
2014
2015 /**
2016  * gtk_get_current_event_time:
2017  * 
2018  * If there is a current event and it has a timestamp, return that
2019  * timestamp, otherwise return %GDK_CURRENT_TIME.
2020  * 
2021  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2022  **/
2023 guint32
2024 gtk_get_current_event_time (void)
2025 {
2026   if (current_events)
2027     return gdk_event_get_time (current_events->data);
2028   else
2029     return GDK_CURRENT_TIME;
2030 }
2031
2032 /**
2033  * gtk_get_current_event_state:
2034  * @state: a location to store the state of the current event
2035  * 
2036  * If there is a current event and it has a state field, place
2037  * that state field in @state and return %TRUE, otherwise return
2038  * %FALSE.
2039  * 
2040  * Return value: %TRUE if there was a current event and it had a state field
2041  **/
2042 gboolean
2043 gtk_get_current_event_state (GdkModifierType *state)
2044 {
2045   g_return_val_if_fail (state != NULL, FALSE);
2046   
2047   if (current_events)
2048     return gdk_event_get_state (current_events->data, state);
2049   else
2050     {
2051       *state = 0;
2052       return FALSE;
2053     }
2054 }
2055
2056 /**
2057  * gtk_get_event_widget:
2058  * @event: a #GdkEvent
2059  *
2060  * If @event is %NULL or the event was not associated with any widget,
2061  * returns %NULL, otherwise returns the widget that received the event
2062  * originally.
2063  * 
2064  * Return value: the widget that originally received @event, or %NULL
2065  **/
2066 GtkWidget*
2067 gtk_get_event_widget (GdkEvent *event)
2068 {
2069   GtkWidget *widget;
2070
2071   widget = NULL;
2072   if (event && event->any.window && 
2073       (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
2074     gdk_window_get_user_data (event->any.window, (void**) &widget);
2075   
2076   return widget;
2077 }
2078
2079 static gint
2080 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2081 {
2082   if (!quitf->marshal)
2083     return quitf->function (quitf->data);
2084   else
2085     {
2086       GtkArg args[1];
2087       gint ret_val = FALSE;
2088
2089       args[0].name = NULL;
2090       args[0].type = G_TYPE_BOOLEAN;
2091       args[0].d.pointer_data = &ret_val;
2092       ((GtkCallbackMarshal) quitf->marshal) (NULL,
2093                                              quitf->data,
2094                                              0, args);
2095       return ret_val;
2096     }
2097 }
2098
2099 /**
2100  * gtk_propagate_event:
2101  * @widget: a #GtkWidget
2102  * @event: an event
2103  *
2104  * Sends an event to a widget, propagating the event to parent widgets
2105  * if the event remains unhandled. Events received by GTK+ from GDK
2106  * normally begin in gtk_main_do_event(). Depending on the type of
2107  * event, existence of modal dialogs, grabs, etc., the event may be
2108  * propagated; if so, this function is used. gtk_propagate_event()
2109  * calls gtk_widget_event() on each widget it decides to send the
2110  * event to.  So gtk_widget_event() is the lowest-level function; it
2111  * simply emits the "event" and possibly an event-specific signal on a
2112  * widget.  gtk_propagate_event() is a bit higher-level, and
2113  * gtk_main_do_event() is the highest level.
2114  *
2115  * All that said, you most likely don't want to use any of these
2116  * functions; synthesizing events is rarely needed. Consider asking on
2117  * the mailing list for better ways to achieve your goals. For
2118  * example, use gdk_window_invalidate_rect() or
2119  * gtk_widget_queue_draw() instead of making up expose events.
2120  * 
2121  **/
2122 void
2123 gtk_propagate_event (GtkWidget *widget,
2124                      GdkEvent  *event)
2125 {
2126   gint handled_event;
2127   
2128   g_return_if_fail (GTK_IS_WIDGET (widget));
2129   g_return_if_fail (event != NULL);
2130   
2131   handled_event = FALSE;
2132
2133   g_object_ref (widget);
2134       
2135   if ((event->type == GDK_KEY_PRESS) ||
2136       (event->type == GDK_KEY_RELEASE))
2137     {
2138       /* Only send key events within Window widgets to the Window
2139        *  The Window widget will in turn pass the
2140        *  key event on to the currently focused widget
2141        *  for that window.
2142        */
2143       GtkWidget *window;
2144
2145       window = gtk_widget_get_toplevel (widget);
2146       if (window && GTK_IS_WINDOW (window))
2147         {
2148           /* If there is a grab within the window, give the grab widget
2149            * a first crack at the key event
2150            */
2151           if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
2152             handled_event = gtk_widget_event (widget, event);
2153           
2154           if (!handled_event)
2155             {
2156               window = gtk_widget_get_toplevel (widget);
2157               if (window && GTK_IS_WINDOW (window))
2158                 {
2159                   if (GTK_WIDGET_IS_SENSITIVE (window))
2160                     gtk_widget_event (window, event);
2161                 }
2162             }
2163                   
2164           handled_event = TRUE; /* don't send to widget */
2165         }
2166     }
2167   
2168   /* Other events get propagated up the widget tree
2169    *  so that parents can see the button and motion
2170    *  events of the children.
2171    */
2172   if (!handled_event)
2173     {
2174       while (TRUE)
2175         {
2176           GtkWidget *tmp;
2177
2178           /* Scroll events are special cased here because it
2179            * feels wrong when scrolling a GtkViewport, say,
2180            * to have children of the viewport eat the scroll
2181            * event
2182            */
2183           if (!GTK_WIDGET_IS_SENSITIVE (widget))
2184             handled_event = event->type != GDK_SCROLL;
2185           else
2186             handled_event = gtk_widget_event (widget, event);
2187               
2188           tmp = widget->parent;
2189           g_object_unref (widget);
2190
2191           widget = tmp;
2192           
2193           if (!handled_event && widget)
2194             g_object_ref (widget);
2195           else
2196             break;
2197         }
2198     }
2199   else
2200     g_object_unref (widget);
2201 }
2202
2203 #if 0
2204 static void
2205 gtk_error (gchar *str)
2206 {
2207   gtk_print (str);
2208 }
2209
2210 static void
2211 gtk_warning (gchar *str)
2212 {
2213   gtk_print (str);
2214 }
2215
2216 static void
2217 gtk_message (gchar *str)
2218 {
2219   gtk_print (str);
2220 }
2221
2222 static void
2223 gtk_print (gchar *str)
2224 {
2225   static GtkWidget *window = NULL;
2226   static GtkWidget *text;
2227   static int level = 0;
2228   GtkWidget *box1;
2229   GtkWidget *box2;
2230   GtkWidget *table;
2231   GtkWidget *hscrollbar;
2232   GtkWidget *vscrollbar;
2233   GtkWidget *separator;
2234   GtkWidget *button;
2235   
2236   if (level > 0)
2237     {
2238       fputs (str, stdout);
2239       fflush (stdout);
2240       return;
2241     }
2242   
2243   if (!window)
2244     {
2245       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2246       
2247       gtk_signal_connect (GTK_OBJECT (window), "destroy",
2248                           (GtkSignalFunc) gtk_widget_destroyed,
2249                           &window);
2250       
2251       gtk_window_set_title (GTK_WINDOW (window), "Messages");
2252       
2253       box1 = gtk_vbox_new (FALSE, 0);
2254       gtk_container_add (GTK_CONTAINER (window), box1);
2255       gtk_widget_show (box1);
2256       
2257       
2258       box2 = gtk_vbox_new (FALSE, 10);
2259       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2260       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2261       gtk_widget_show (box2);
2262       
2263       
2264       table = gtk_table_new (2, 2, FALSE);
2265       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
2266       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
2267       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
2268       gtk_widget_show (table);
2269       
2270       text = gtk_text_new (NULL, NULL);
2271       gtk_text_set_editable (GTK_TEXT (text), FALSE);
2272       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
2273       gtk_widget_show (text);
2274       gtk_widget_realize (text);
2275       
2276       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
2277       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
2278                         GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
2279       gtk_widget_show (hscrollbar);
2280       
2281       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
2282       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
2283                         GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2284       gtk_widget_show (vscrollbar);
2285       
2286       separator = gtk_hseparator_new ();
2287       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2288       gtk_widget_show (separator);
2289       
2290       
2291       box2 = gtk_vbox_new (FALSE, 10);
2292       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2293       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2294       gtk_widget_show (box2);
2295       
2296       
2297       button = gtk_button_new_with_label ("close");
2298       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2299                                  (GtkSignalFunc) gtk_widget_hide,
2300                                  GTK_OBJECT (window));
2301       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2302       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2303       gtk_widget_grab_default (button);
2304       gtk_widget_show (button);
2305     }
2306   
2307   level += 1;
2308   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
2309   level -= 1;
2310   
2311   if (!GTK_WIDGET_VISIBLE (window))
2312     gtk_widget_show (window);
2313 }
2314 #endif
2315
2316 gboolean
2317 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2318                                   GValue                *return_accu,
2319                                   const GValue          *handler_return,
2320                                   gpointer               dummy)
2321 {
2322   gboolean continue_emission;
2323   gboolean signal_handled;
2324   
2325   signal_handled = g_value_get_boolean (handler_return);
2326   g_value_set_boolean (return_accu, signal_handled);
2327   continue_emission = !signal_handled;
2328   
2329   return continue_emission;
2330 }
2331
2332 #define __GTK_MAIN_C__
2333 #include "gtkaliasdef.c"