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