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