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