]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
cbf393bf40587883d72782e9f293866c2af7fd86
[~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.
1093  *
1094  * This function is equivalent to pango_language_get_default().  See
1095  * that function for details.
1096  * 
1097  * Return value: the default language as a #PangoLanguage, must not be
1098  * freed
1099  **/
1100 PangoLanguage *
1101 gtk_get_default_language (void)
1102 {
1103   return pango_language_get_default ();
1104 }
1105
1106 void
1107 gtk_main (void)
1108 {
1109   GList *tmp_list;
1110   GList *functions;
1111   GtkInitFunction *init;
1112   GMainLoop *loop;
1113
1114   gtk_main_loop_level++;
1115   
1116   loop = g_main_loop_new (NULL, TRUE);
1117   main_loops = g_slist_prepend (main_loops, loop);
1118
1119   tmp_list = functions = init_functions;
1120   init_functions = NULL;
1121   
1122   while (tmp_list)
1123     {
1124       init = tmp_list->data;
1125       tmp_list = tmp_list->next;
1126       
1127       (* init->function) (init->data);
1128       g_free (init);
1129     }
1130   g_list_free (functions);
1131
1132   if (g_main_loop_is_running (main_loops->data))
1133     {
1134       GDK_THREADS_LEAVE ();
1135       g_main_loop_run (loop);
1136       GDK_THREADS_ENTER ();
1137       gdk_flush ();
1138     }
1139
1140   if (quit_functions)
1141     {
1142       GList *reinvoke_list = NULL;
1143       GtkQuitFunction *quitf;
1144
1145       while (quit_functions)
1146         {
1147           quitf = quit_functions->data;
1148
1149           tmp_list = quit_functions;
1150           quit_functions = g_list_remove_link (quit_functions, quit_functions);
1151           g_list_free_1 (tmp_list);
1152
1153           if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
1154               gtk_quit_invoke_function (quitf))
1155             {
1156               reinvoke_list = g_list_prepend (reinvoke_list, quitf);
1157             }
1158           else
1159             {
1160               gtk_quit_destroy (quitf);
1161             }
1162         }
1163       if (reinvoke_list)
1164         {
1165           GList *work;
1166           
1167           work = g_list_last (reinvoke_list);
1168           if (quit_functions)
1169             quit_functions->prev = work;
1170           work->next = quit_functions;
1171           quit_functions = work;
1172         }
1173
1174       gdk_flush ();
1175     }
1176     
1177   main_loops = g_slist_remove (main_loops, loop);
1178
1179   g_main_loop_unref (loop);
1180
1181   gtk_main_loop_level--;
1182
1183   /* Try storing all clipboard data we have */
1184   if (gtk_main_loop_level == 0)
1185     _gtk_clipboard_store_all ();
1186 }
1187
1188 guint
1189 gtk_main_level (void)
1190 {
1191   return gtk_main_loop_level;
1192 }
1193
1194 void
1195 gtk_main_quit (void)
1196 {
1197   g_return_if_fail (main_loops != NULL);
1198
1199   g_main_loop_quit (main_loops->data);
1200 }
1201
1202 gboolean
1203 gtk_events_pending (void)
1204 {
1205   gboolean result;
1206   
1207   GDK_THREADS_LEAVE ();  
1208   result = g_main_context_pending (NULL);
1209   GDK_THREADS_ENTER ();
1210
1211   return result;
1212 }
1213
1214 gboolean
1215 gtk_main_iteration (void)
1216 {
1217   GDK_THREADS_LEAVE ();
1218   g_main_context_iteration (NULL, TRUE);
1219   GDK_THREADS_ENTER ();
1220
1221   if (main_loops)
1222     return !g_main_loop_is_running (main_loops->data);
1223   else
1224     return TRUE;
1225 }
1226
1227 gboolean
1228 gtk_main_iteration_do (gboolean blocking)
1229 {
1230   GDK_THREADS_LEAVE ();
1231   g_main_context_iteration (NULL, blocking);
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 /* private libgtk to libgdk interfaces
1241  */
1242 gboolean gdk_pointer_grab_info_libgtk_only  (GdkDisplay *display,
1243                                              GdkWindow **grab_window,
1244                                              gboolean   *owner_events);
1245 gboolean gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
1246                                              GdkWindow **grab_window,
1247                                              gboolean   *owner_events);
1248
1249 static void
1250 rewrite_events_translate (GdkWindow *old_window,
1251                           GdkWindow *new_window,
1252                           gdouble   *x,
1253                           gdouble   *y)
1254 {
1255   gint old_origin_x, old_origin_y;
1256   gint new_origin_x, new_origin_y;
1257
1258   gdk_window_get_origin (old_window, &old_origin_x, &old_origin_y);
1259   gdk_window_get_origin (new_window, &new_origin_x, &new_origin_y);
1260
1261   *x += old_origin_x - new_origin_x;
1262   *y += old_origin_y - new_origin_y;
1263 }
1264
1265 static GdkEvent *
1266 rewrite_event_for_window (GdkEvent  *event,
1267                           GdkWindow *new_window)
1268 {
1269   event = gdk_event_copy (event);
1270
1271   switch (event->type)
1272     {
1273     case GDK_SCROLL:
1274       rewrite_events_translate (event->any.window,
1275                                 new_window,
1276                                 &event->scroll.x, &event->scroll.y);
1277       break;
1278     case GDK_BUTTON_PRESS:
1279     case GDK_2BUTTON_PRESS:
1280     case GDK_3BUTTON_PRESS:
1281     case GDK_BUTTON_RELEASE:
1282       rewrite_events_translate (event->any.window,
1283                                 new_window,
1284                                 &event->button.x, &event->button.y);
1285       break;
1286     case GDK_MOTION_NOTIFY:
1287       rewrite_events_translate (event->any.window,
1288                                 new_window,
1289                                 &event->motion.x, &event->motion.y);
1290       break;
1291     case GDK_KEY_PRESS:
1292     case GDK_KEY_RELEASE:
1293     case GDK_PROXIMITY_IN:
1294     case GDK_PROXIMITY_OUT:
1295       break;
1296
1297     default:
1298       return event;
1299     }
1300
1301   g_object_unref (event->any.window);
1302   event->any.window = g_object_ref (new_window);
1303
1304   return event;
1305 }
1306
1307 /* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
1308  * then what X11 does is deliver the event normally if it was going to this
1309  * client, otherwise, delivers it in terms of the grab window. This function
1310  * rewrites events to the effect that events going to the same window group
1311  * are delivered normally, otherwise, the event is delivered in terms of the
1312  * grab window.
1313  */
1314 static GdkEvent *
1315 rewrite_event_for_grabs (GdkEvent *event)
1316 {
1317   GdkWindow *grab_window;
1318   GtkWidget *event_widget, *grab_widget;
1319   gboolean owner_events;
1320   GdkDisplay *display;
1321
1322   switch (event->type)
1323     {
1324     case GDK_SCROLL:
1325     case GDK_BUTTON_PRESS:
1326     case GDK_2BUTTON_PRESS:
1327     case GDK_3BUTTON_PRESS:
1328     case GDK_BUTTON_RELEASE:
1329     case GDK_MOTION_NOTIFY:
1330     case GDK_PROXIMITY_IN:
1331     case GDK_PROXIMITY_OUT:
1332       display = gdk_drawable_get_display (event->proximity.window);
1333       if (!gdk_pointer_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
1334           !owner_events)
1335         return NULL;
1336       break;
1337
1338     case GDK_KEY_PRESS:
1339     case GDK_KEY_RELEASE:
1340       display = gdk_drawable_get_display (event->key.window);
1341       if (!gdk_keyboard_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
1342           !owner_events)
1343         return NULL;
1344       break;
1345
1346     default:
1347       return NULL;
1348     }
1349
1350   event_widget = gtk_get_event_widget (event);
1351   gdk_window_get_user_data (grab_window, (void**) &grab_widget);
1352
1353   if (grab_widget &&
1354       gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
1355     return rewrite_event_for_window (event, grab_window);
1356   else
1357     return NULL;
1358 }
1359
1360 void 
1361 gtk_main_do_event (GdkEvent *event)
1362 {
1363   GtkWidget *event_widget;
1364   GtkWidget *grab_widget;
1365   GtkWindowGroup *window_group;
1366   GdkEvent *next_event;
1367   GdkEvent *rewritten_event = NULL;
1368   GList *tmp_list;
1369
1370   /* If there are any events pending then get the next one.
1371    */
1372   next_event = gdk_event_peek ();
1373   
1374   /* Try to compress enter/leave notify events. These event
1375    *  pairs occur when the mouse is dragged quickly across
1376    *  a window with many buttons (or through a menu). Instead
1377    *  of highlighting and de-highlighting each widget that
1378    *  is crossed it is better to simply de-highlight the widget
1379    *  which contained the mouse initially and highlight the
1380    *  widget which ends up containing the mouse.
1381    */
1382   if (next_event)
1383     if (((event->type == GDK_ENTER_NOTIFY) ||
1384          (event->type == GDK_LEAVE_NOTIFY)) &&
1385         ((next_event->type == GDK_ENTER_NOTIFY) ||
1386          (next_event->type == GDK_LEAVE_NOTIFY)) &&
1387         (next_event->type != event->type) &&
1388         (next_event->any.window == event->any.window))
1389       {
1390         /* Throw both the peeked copy and the queued copy away 
1391          */
1392         gdk_event_free (next_event);
1393         next_event = gdk_event_get ();
1394         gdk_event_free (next_event);
1395         
1396         return;
1397       }
1398
1399   if (next_event)
1400     gdk_event_free (next_event);
1401
1402   if (event->type == GDK_SETTING)
1403     {
1404       _gtk_settings_handle_event (&event->setting);
1405       return;
1406     }
1407
1408   if (event->type == GDK_OWNER_CHANGE)
1409     {
1410       _gtk_clipboard_handle_event (&event->owner_change);
1411       return;
1412     }
1413
1414   /* Find the widget which got the event. We store the widget
1415    *  in the user_data field of GdkWindow's.
1416    *  Ignore the event if we don't have a widget for it, except
1417    *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
1418    *  Though this happens rarely, bogus events can occour
1419    *  for e.g. destroyed GdkWindows. 
1420    */
1421   event_widget = gtk_get_event_widget (event);
1422   if (!event_widget)
1423     {
1424       /* To handle selection INCR transactions, we select
1425        * PropertyNotify events on the requestor window and create
1426        * a corresponding (fake) GdkWindow so that events get
1427        * here. There won't be a widget though, so we have to handle
1428            * them specially
1429            */
1430       if (event->type == GDK_PROPERTY_NOTIFY)
1431         _gtk_selection_incr_event (event->any.window,
1432                                    &event->property);
1433
1434       return;
1435     }
1436
1437   /* If pointer or keyboard grabs are in effect, munge the events
1438    * so that each window group looks like a separate app.
1439    */
1440   rewritten_event = rewrite_event_for_grabs (event);
1441   if (rewritten_event)
1442     {
1443       event = rewritten_event;
1444       event_widget = gtk_get_event_widget (event);
1445     }
1446   
1447   window_group = gtk_main_get_window_group (event_widget);
1448
1449   /* Push the event onto a stack of current events for
1450    * gtk_current_event_get().
1451    */
1452   current_events = g_list_prepend (current_events, event);
1453
1454   /* If there is a grab in effect...
1455    */
1456   if (window_group->grabs)
1457     {
1458       grab_widget = window_group->grabs->data;
1459       
1460       /* If the grab widget is an ancestor of the event widget
1461        *  then we send the event to the original event widget.
1462        *  This is the key to implementing modality.
1463        */
1464       if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
1465           gtk_widget_is_ancestor (event_widget, grab_widget))
1466         grab_widget = event_widget;
1467     }
1468   else
1469     {
1470       grab_widget = event_widget;
1471     }
1472
1473   /* Not all events get sent to the grabbing widget.
1474    * The delete, destroy, expose, focus change and resize
1475    *  events still get sent to the event widget because
1476    *  1) these events have no meaning for the grabbing widget
1477    *  and 2) redirecting these events to the grabbing widget
1478    *  could cause the display to be messed up.
1479    * 
1480    * Drag events are also not redirected, since it isn't
1481    *  clear what the semantics of that would be.
1482    */
1483   switch (event->type)
1484     {
1485     case GDK_NOTHING:
1486       break;
1487       
1488     case GDK_DELETE:
1489       g_object_ref (event_widget);
1490       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1491           !gtk_widget_event (event_widget, event))
1492         gtk_widget_destroy (event_widget);
1493       g_object_unref (event_widget);
1494       break;
1495       
1496     case GDK_DESTROY:
1497       /* Unexpected GDK_DESTROY from the outside, ignore for
1498        * child windows, handle like a GDK_DELETE for toplevels
1499        */
1500       if (!event_widget->parent)
1501         {
1502           g_object_ref (event_widget);
1503           if (!gtk_widget_event (event_widget, event) &&
1504               GTK_WIDGET_REALIZED (event_widget))
1505             gtk_widget_destroy (event_widget);
1506           g_object_unref (event_widget);
1507         }
1508       break;
1509       
1510     case GDK_EXPOSE:
1511       if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
1512         {
1513           gdk_window_begin_paint_region (event->any.window, event->expose.region);
1514           gtk_widget_send_expose (event_widget, event);
1515           gdk_window_end_paint (event->any.window);
1516         }
1517       else
1518         gtk_widget_send_expose (event_widget, event);
1519       break;
1520
1521     case GDK_PROPERTY_NOTIFY:
1522     case GDK_NO_EXPOSE:
1523     case GDK_FOCUS_CHANGE:
1524     case GDK_CONFIGURE:
1525     case GDK_MAP:
1526     case GDK_UNMAP:
1527     case GDK_SELECTION_CLEAR:
1528     case GDK_SELECTION_REQUEST:
1529     case GDK_SELECTION_NOTIFY:
1530     case GDK_CLIENT_EVENT:
1531     case GDK_VISIBILITY_NOTIFY:
1532     case GDK_WINDOW_STATE:
1533     case GDK_GRAB_BROKEN:
1534       gtk_widget_event (event_widget, event);
1535       break;
1536
1537     case GDK_SCROLL:
1538     case GDK_BUTTON_PRESS:
1539     case GDK_2BUTTON_PRESS:
1540     case GDK_3BUTTON_PRESS:
1541       gtk_propagate_event (grab_widget, event);
1542       break;
1543
1544     case GDK_KEY_PRESS:
1545     case GDK_KEY_RELEASE:
1546       if (key_snoopers)
1547         {
1548           if (gtk_invoke_key_snoopers (grab_widget, event))
1549             break;
1550         }
1551       /* else fall through */
1552     case GDK_MOTION_NOTIFY:
1553     case GDK_BUTTON_RELEASE:
1554     case GDK_PROXIMITY_IN:
1555     case GDK_PROXIMITY_OUT:
1556       gtk_propagate_event (grab_widget, event);
1557       break;
1558       
1559     case GDK_ENTER_NOTIFY:
1560       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1561         {
1562           g_object_ref (event_widget);
1563           
1564           gtk_widget_event (grab_widget, event);
1565           if (event_widget == grab_widget)
1566             GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
1567           
1568           g_object_unref (event_widget);
1569         }
1570       break;
1571       
1572     case GDK_LEAVE_NOTIFY:
1573       if (GTK_WIDGET_LEAVE_PENDING (event_widget))
1574         {
1575           GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
1576           gtk_widget_event (event_widget, event);
1577         }
1578       else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1579         gtk_widget_event (grab_widget, event);
1580       break;
1581       
1582     case GDK_DRAG_STATUS:
1583     case GDK_DROP_FINISHED:
1584       _gtk_drag_source_handle_event (event_widget, event);
1585       break;
1586     case GDK_DRAG_ENTER:
1587     case GDK_DRAG_LEAVE:
1588     case GDK_DRAG_MOTION:
1589     case GDK_DROP_START:
1590       _gtk_drag_dest_handle_event (event_widget, event);
1591       break;
1592     default:
1593       g_assert_not_reached ();
1594       break;
1595     }
1596   
1597   tmp_list = current_events;
1598   current_events = g_list_remove_link (current_events, tmp_list);
1599   g_list_free_1 (tmp_list);
1600
1601   if (rewritten_event)
1602     gdk_event_free (rewritten_event);
1603 }
1604
1605 gboolean
1606 gtk_true (void)
1607 {
1608   return TRUE;
1609 }
1610
1611 gboolean
1612 gtk_false (void)
1613 {
1614   return FALSE;
1615 }
1616
1617 static GtkWindowGroup *
1618 gtk_main_get_window_group (GtkWidget   *widget)
1619 {
1620   GtkWidget *toplevel = NULL;
1621
1622   if (widget)
1623     toplevel = gtk_widget_get_toplevel (widget);
1624
1625   if (toplevel && GTK_IS_WINDOW (toplevel))
1626     return gtk_window_get_group (GTK_WINDOW (toplevel));
1627   else
1628     return gtk_window_get_group (NULL);
1629 }
1630
1631 typedef struct
1632 {
1633   GtkWidget *old_grab_widget;
1634   GtkWidget *new_grab_widget;
1635   gboolean   was_grabbed;
1636   gboolean   is_grabbed;
1637 } GrabNotifyInfo;
1638
1639 static void
1640 gtk_grab_notify_foreach (GtkWidget *child,
1641                          gpointer   data)
1642                         
1643 {
1644   GrabNotifyInfo *info = data;
1645  
1646   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1647
1648   was_grabbed = info->was_grabbed;
1649   is_grabbed = info->is_grabbed;
1650
1651   info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1652   info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1653
1654   was_shadowed = info->old_grab_widget && !info->was_grabbed;
1655   is_shadowed = info->new_grab_widget && !info->is_grabbed;
1656
1657   g_object_ref (child);
1658   
1659   if (was_shadowed != is_shadowed)
1660     _gtk_widget_grab_notify (child, was_shadowed);
1661   
1662   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1663     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1664       
1665   g_object_unref (child);
1666   
1667   info->was_grabbed = was_grabbed;
1668   info->is_grabbed = is_grabbed;
1669 }
1670
1671 static void
1672 gtk_grab_notify (GtkWindowGroup *group,
1673                  GtkWidget      *old_grab_widget,
1674                  GtkWidget      *new_grab_widget)
1675 {
1676   GList *toplevels;
1677   GrabNotifyInfo info;
1678
1679   if (old_grab_widget == new_grab_widget)
1680     return;
1681
1682   info.old_grab_widget = old_grab_widget;
1683   info.new_grab_widget = new_grab_widget;
1684
1685   g_object_ref (group);
1686
1687   toplevels = gtk_window_list_toplevels ();
1688   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1689                             
1690   while (toplevels)
1691     {
1692       GtkWindow *toplevel = toplevels->data;
1693       toplevels = g_list_delete_link (toplevels, toplevels);
1694
1695       info.was_grabbed = FALSE;
1696       info.is_grabbed = FALSE;
1697
1698       if (group == gtk_window_get_group (toplevel))
1699         gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1700       g_object_unref (toplevel);
1701     }
1702
1703   g_object_unref (group);
1704 }
1705
1706 void
1707 gtk_grab_add (GtkWidget *widget)
1708 {
1709   GtkWindowGroup *group;
1710   GtkWidget *old_grab_widget;
1711   
1712   g_return_if_fail (widget != NULL);
1713   
1714   if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
1715     {
1716       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
1717       
1718       group = gtk_main_get_window_group (widget);
1719
1720       if (group->grabs)
1721         old_grab_widget = (GtkWidget *)group->grabs->data;
1722       else
1723         old_grab_widget = NULL;
1724
1725       g_object_ref (widget);
1726       group->grabs = g_slist_prepend (group->grabs, widget);
1727
1728       gtk_grab_notify (group, old_grab_widget, widget);
1729     }
1730 }
1731
1732 GtkWidget*
1733 gtk_grab_get_current (void)
1734 {
1735   GtkWindowGroup *group;
1736
1737   group = gtk_main_get_window_group (NULL);
1738
1739   if (group->grabs)
1740     return GTK_WIDGET (group->grabs->data);
1741   return NULL;
1742 }
1743
1744 void
1745 gtk_grab_remove (GtkWidget *widget)
1746 {
1747   GtkWindowGroup *group;
1748   GtkWidget *new_grab_widget;
1749   
1750   g_return_if_fail (widget != NULL);
1751   
1752   if (GTK_WIDGET_HAS_GRAB (widget))
1753     {
1754       GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
1755
1756       group = gtk_main_get_window_group (widget);
1757       group->grabs = g_slist_remove (group->grabs, widget);
1758       
1759       if (group->grabs)
1760         new_grab_widget = (GtkWidget *)group->grabs->data;
1761       else
1762         new_grab_widget = NULL;
1763
1764       gtk_grab_notify (group, widget, new_grab_widget);
1765       
1766       g_object_unref (widget);
1767     }
1768 }
1769
1770 void
1771 gtk_init_add (GtkFunction function,
1772               gpointer    data)
1773 {
1774   GtkInitFunction *init;
1775   
1776   init = g_new (GtkInitFunction, 1);
1777   init->function = function;
1778   init->data = data;
1779   
1780   init_functions = g_list_prepend (init_functions, init);
1781 }
1782
1783 guint
1784 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
1785                          gpointer        func_data)
1786 {
1787   GtkKeySnooperData *data;
1788   static guint snooper_id = 1;
1789
1790   g_return_val_if_fail (snooper != NULL, 0);
1791
1792   data = g_new (GtkKeySnooperData, 1);
1793   data->func = snooper;
1794   data->func_data = func_data;
1795   data->id = snooper_id++;
1796   key_snoopers = g_slist_prepend (key_snoopers, data);
1797
1798   return data->id;
1799 }
1800
1801 void
1802 gtk_key_snooper_remove (guint snooper_id)
1803 {
1804   GtkKeySnooperData *data = NULL;
1805   GSList *slist;
1806
1807   slist = key_snoopers;
1808   while (slist)
1809     {
1810       data = slist->data;
1811       if (data->id == snooper_id)
1812         break;
1813
1814       slist = slist->next;
1815       data = NULL;
1816     }
1817   if (data)
1818     {
1819       key_snoopers = g_slist_remove (key_snoopers, data);
1820       g_free (data);
1821     }
1822 }
1823
1824 static gint
1825 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
1826                          GdkEvent  *event)
1827 {
1828   GSList *slist;
1829   gint return_val = FALSE;
1830
1831   slist = key_snoopers;
1832   while (slist && !return_val)
1833     {
1834       GtkKeySnooperData *data;
1835
1836       data = slist->data;
1837       slist = slist->next;
1838       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
1839     }
1840
1841   return return_val;
1842 }
1843
1844 guint
1845 gtk_quit_add_full (guint                main_level,
1846                    GtkFunction          function,
1847                    GtkCallbackMarshal   marshal,
1848                    gpointer             data,
1849                    GtkDestroyNotify     destroy)
1850 {
1851   static guint quit_id = 1;
1852   GtkQuitFunction *quitf;
1853   
1854   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
1855
1856   quitf = g_slice_new (GtkQuitFunction);
1857   
1858   quitf->id = quit_id++;
1859   quitf->main_level = main_level;
1860   quitf->function = function;
1861   quitf->marshal = marshal;
1862   quitf->data = data;
1863   quitf->destroy = destroy;
1864
1865   quit_functions = g_list_prepend (quit_functions, quitf);
1866   
1867   return quitf->id;
1868 }
1869
1870 static void
1871 gtk_quit_destroy (GtkQuitFunction *quitf)
1872 {
1873   if (quitf->destroy)
1874     quitf->destroy (quitf->data);
1875   g_slice_free (GtkQuitFunction, quitf);
1876 }
1877
1878 static gint
1879 gtk_quit_destructor (GtkObject **object_p)
1880 {
1881   if (*object_p)
1882     gtk_object_destroy (*object_p);
1883   g_free (object_p);
1884
1885   return FALSE;
1886 }
1887
1888 void
1889 gtk_quit_add_destroy (guint              main_level,
1890                       GtkObject         *object)
1891 {
1892   GtkObject **object_p;
1893
1894   g_return_if_fail (main_level > 0);
1895   g_return_if_fail (GTK_IS_OBJECT (object));
1896
1897   object_p = g_new (GtkObject*, 1);
1898   *object_p = object;
1899   g_signal_connect (object,
1900                     "destroy",
1901                     G_CALLBACK (gtk_widget_destroyed),
1902                     object_p);
1903   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1904 }
1905
1906 guint
1907 gtk_quit_add (guint       main_level,
1908               GtkFunction function,
1909               gpointer    data)
1910 {
1911   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
1912 }
1913
1914 void
1915 gtk_quit_remove (guint id)
1916 {
1917   GtkQuitFunction *quitf;
1918   GList *tmp_list;
1919   
1920   tmp_list = quit_functions;
1921   while (tmp_list)
1922     {
1923       quitf = tmp_list->data;
1924       
1925       if (quitf->id == id)
1926         {
1927           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1928           g_list_free (tmp_list);
1929           gtk_quit_destroy (quitf);
1930           
1931           return;
1932         }
1933       
1934       tmp_list = tmp_list->next;
1935     }
1936 }
1937
1938 void
1939 gtk_quit_remove_by_data (gpointer data)
1940 {
1941   GtkQuitFunction *quitf;
1942   GList *tmp_list;
1943   
1944   tmp_list = quit_functions;
1945   while (tmp_list)
1946     {
1947       quitf = tmp_list->data;
1948       
1949       if (quitf->data == data)
1950         {
1951           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1952           g_list_free (tmp_list);
1953           gtk_quit_destroy (quitf);
1954
1955           return;
1956         }
1957       
1958       tmp_list = tmp_list->next;
1959     }
1960 }
1961
1962 guint
1963 gtk_timeout_add_full (guint32            interval,
1964                       GtkFunction        function,
1965                       GtkCallbackMarshal marshal,
1966                       gpointer           data,
1967                       GtkDestroyNotify   destroy)
1968 {
1969   if (marshal)
1970     {
1971       GtkClosure *closure;
1972
1973       closure = g_new (GtkClosure, 1);
1974       closure->marshal = marshal;
1975       closure->data = data;
1976       closure->destroy = destroy;
1977
1978       return g_timeout_add_full (0, interval, 
1979                                  gtk_invoke_idle_timeout,
1980                                  closure,
1981                                  gtk_destroy_closure);
1982     }
1983   else
1984     return g_timeout_add_full (0, interval, function, data, destroy);
1985 }
1986
1987 guint
1988 gtk_timeout_add (guint32     interval,
1989                  GtkFunction function,
1990                  gpointer    data)
1991 {
1992   return g_timeout_add_full (0, interval, function, data, NULL);
1993 }
1994
1995 void
1996 gtk_timeout_remove (guint tag)
1997 {
1998   g_source_remove (tag);
1999 }
2000
2001 guint
2002 gtk_idle_add_full (gint                 priority,
2003                    GtkFunction          function,
2004                    GtkCallbackMarshal   marshal,
2005                    gpointer             data,
2006                    GtkDestroyNotify     destroy)
2007 {
2008   if (marshal)
2009     {
2010       GtkClosure *closure;
2011
2012       closure = g_new (GtkClosure, 1);
2013       closure->marshal = marshal;
2014       closure->data = data;
2015       closure->destroy = destroy;
2016
2017       return g_idle_add_full (priority,
2018                               gtk_invoke_idle_timeout,
2019                               closure,
2020                               gtk_destroy_closure);
2021     }
2022   else
2023     return g_idle_add_full (priority, function, data, destroy);
2024 }
2025
2026 guint
2027 gtk_idle_add (GtkFunction function,
2028               gpointer    data)
2029 {
2030   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
2031 }
2032
2033 guint       
2034 gtk_idle_add_priority (gint        priority,
2035                        GtkFunction function,
2036                        gpointer    data)
2037 {
2038   return g_idle_add_full (priority, function, data, NULL);
2039 }
2040
2041 void
2042 gtk_idle_remove (guint tag)
2043 {
2044   g_source_remove (tag);
2045 }
2046
2047 void
2048 gtk_idle_remove_by_data (gpointer data)
2049 {
2050   if (!g_idle_remove_by_data (data))
2051     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
2052 }
2053
2054 guint
2055 gtk_input_add_full (gint                source,
2056                     GdkInputCondition   condition,
2057                     GdkInputFunction    function,
2058                     GtkCallbackMarshal  marshal,
2059                     gpointer            data,
2060                     GtkDestroyNotify    destroy)
2061 {
2062   if (marshal)
2063     {
2064       GtkClosure *closure;
2065
2066       closure = g_new (GtkClosure, 1);
2067       closure->marshal = marshal;
2068       closure->data = data;
2069       closure->destroy = destroy;
2070
2071       return gdk_input_add_full (source,
2072                                  condition,
2073                                  (GdkInputFunction) gtk_invoke_input,
2074                                  closure,
2075                                  (GdkDestroyNotify) gtk_destroy_closure);
2076     }
2077   else
2078     return gdk_input_add_full (source, condition, function, data, destroy);
2079 }
2080
2081 void
2082 gtk_input_remove (guint tag)
2083 {
2084   g_source_remove (tag);
2085 }
2086
2087 static void
2088 gtk_destroy_closure (gpointer data)
2089 {
2090   GtkClosure *closure = data;
2091
2092   if (closure->destroy)
2093     (closure->destroy) (closure->data);
2094   g_free (closure);
2095 }
2096
2097 static gboolean
2098 gtk_invoke_idle_timeout (gpointer data)
2099 {
2100   GtkClosure *closure = data;
2101
2102   GtkArg args[1];
2103   gint ret_val = FALSE;
2104   args[0].name = NULL;
2105   args[0].type = G_TYPE_BOOLEAN;
2106   args[0].d.pointer_data = &ret_val;
2107   closure->marshal (NULL, closure->data,  0, args);
2108   return ret_val;
2109 }
2110
2111 static void
2112 gtk_invoke_input (gpointer          data,
2113                   gint              source,
2114                   GdkInputCondition condition)
2115 {
2116   GtkClosure *closure = data;
2117
2118   GtkArg args[3];
2119   args[0].type = G_TYPE_INT;
2120   args[0].name = NULL;
2121   GTK_VALUE_INT (args[0]) = source;
2122   args[1].type = GDK_TYPE_INPUT_CONDITION;
2123   args[1].name = NULL;
2124   GTK_VALUE_FLAGS (args[1]) = condition;
2125   args[2].type = G_TYPE_NONE;
2126   args[2].name = NULL;
2127
2128   closure->marshal (NULL, closure->data, 2, args);
2129 }
2130
2131 /**
2132  * gtk_get_current_event:
2133  * 
2134  * Obtains a copy of the event currently being processed by GTK+.  For
2135  * example, if you get a "clicked" signal from #GtkButton, the current
2136  * event will be the #GdkEventButton that triggered the "clicked"
2137  * signal. The returned event must be freed with gdk_event_free().
2138  * If there is no current event, the function returns %NULL.
2139  * 
2140  * Return value: a copy of the current event, or %NULL if no current event.
2141  **/
2142 GdkEvent*
2143 gtk_get_current_event (void)
2144 {
2145   if (current_events)
2146     return gdk_event_copy (current_events->data);
2147   else
2148     return NULL;
2149 }
2150
2151 /**
2152  * gtk_get_current_event_time:
2153  * 
2154  * If there is a current event and it has a timestamp, return that
2155  * timestamp, otherwise return %GDK_CURRENT_TIME.
2156  * 
2157  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2158  **/
2159 guint32
2160 gtk_get_current_event_time (void)
2161 {
2162   if (current_events)
2163     return gdk_event_get_time (current_events->data);
2164   else
2165     return GDK_CURRENT_TIME;
2166 }
2167
2168 /**
2169  * gtk_get_current_event_state:
2170  * @state: a location to store the state of the current event
2171  * 
2172  * If there is a current event and it has a state field, place
2173  * that state field in @state and return %TRUE, otherwise return
2174  * %FALSE.
2175  * 
2176  * Return value: %TRUE if there was a current event and it had a state field
2177  **/
2178 gboolean
2179 gtk_get_current_event_state (GdkModifierType *state)
2180 {
2181   g_return_val_if_fail (state != NULL, FALSE);
2182   
2183   if (current_events)
2184     return gdk_event_get_state (current_events->data, state);
2185   else
2186     {
2187       *state = 0;
2188       return FALSE;
2189     }
2190 }
2191
2192 /**
2193  * gtk_get_event_widget:
2194  * @event: a #GdkEvent
2195  *
2196  * If @event is %NULL or the event was not associated with any widget,
2197  * returns %NULL, otherwise returns the widget that received the event
2198  * originally.
2199  * 
2200  * Return value: the widget that originally received @event, or %NULL
2201  **/
2202 GtkWidget*
2203 gtk_get_event_widget (GdkEvent *event)
2204 {
2205   GtkWidget *widget;
2206
2207   widget = NULL;
2208   if (event && event->any.window && 
2209       (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
2210     gdk_window_get_user_data (event->any.window, (void**) &widget);
2211   
2212   return widget;
2213 }
2214
2215 static gint
2216 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2217 {
2218   if (!quitf->marshal)
2219     return quitf->function (quitf->data);
2220   else
2221     {
2222       GtkArg args[1];
2223       gint ret_val = FALSE;
2224
2225       args[0].name = NULL;
2226       args[0].type = G_TYPE_BOOLEAN;
2227       args[0].d.pointer_data = &ret_val;
2228       ((GtkCallbackMarshal) quitf->marshal) (NULL,
2229                                              quitf->data,
2230                                              0, args);
2231       return ret_val;
2232     }
2233 }
2234
2235 /**
2236  * gtk_propagate_event:
2237  * @widget: a #GtkWidget
2238  * @event: an event
2239  *
2240  * Sends an event to a widget, propagating the event to parent widgets
2241  * if the event remains unhandled. Events received by GTK+ from GDK
2242  * normally begin in gtk_main_do_event(). Depending on the type of
2243  * event, existence of modal dialogs, grabs, etc., the event may be
2244  * propagated; if so, this function is used. gtk_propagate_event()
2245  * calls gtk_widget_event() on each widget it decides to send the
2246  * event to.  So gtk_widget_event() is the lowest-level function; it
2247  * simply emits the "event" and possibly an event-specific signal on a
2248  * widget.  gtk_propagate_event() is a bit higher-level, and
2249  * gtk_main_do_event() is the highest level.
2250  *
2251  * All that said, you most likely don't want to use any of these
2252  * functions; synthesizing events is rarely needed. Consider asking on
2253  * the mailing list for better ways to achieve your goals. For
2254  * example, use gdk_window_invalidate_rect() or
2255  * gtk_widget_queue_draw() instead of making up expose events.
2256  * 
2257  **/
2258 void
2259 gtk_propagate_event (GtkWidget *widget,
2260                      GdkEvent  *event)
2261 {
2262   gint handled_event;
2263   
2264   g_return_if_fail (GTK_IS_WIDGET (widget));
2265   g_return_if_fail (event != NULL);
2266   
2267   handled_event = FALSE;
2268
2269   g_object_ref (widget);
2270       
2271   if ((event->type == GDK_KEY_PRESS) ||
2272       (event->type == GDK_KEY_RELEASE))
2273     {
2274       /* Only send key events within Window widgets to the Window
2275        *  The Window widget will in turn pass the
2276        *  key event on to the currently focused widget
2277        *  for that window.
2278        */
2279       GtkWidget *window;
2280
2281       window = gtk_widget_get_toplevel (widget);
2282       if (window && GTK_IS_WINDOW (window))
2283         {
2284           /* If there is a grab within the window, give the grab widget
2285            * a first crack at the key event
2286            */
2287           if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
2288             handled_event = gtk_widget_event (widget, event);
2289           
2290           if (!handled_event)
2291             {
2292               window = gtk_widget_get_toplevel (widget);
2293               if (window && GTK_IS_WINDOW (window))
2294                 {
2295                   if (GTK_WIDGET_IS_SENSITIVE (window))
2296                     gtk_widget_event (window, event);
2297                 }
2298             }
2299                   
2300           handled_event = TRUE; /* don't send to widget */
2301         }
2302     }
2303   
2304   /* Other events get propagated up the widget tree
2305    *  so that parents can see the button and motion
2306    *  events of the children.
2307    */
2308   if (!handled_event)
2309     {
2310       while (TRUE)
2311         {
2312           GtkWidget *tmp;
2313
2314           /* Scroll events are special cased here because it
2315            * feels wrong when scrolling a GtkViewport, say,
2316            * to have children of the viewport eat the scroll
2317            * event
2318            */
2319           if (!GTK_WIDGET_IS_SENSITIVE (widget))
2320             handled_event = event->type != GDK_SCROLL;
2321           else
2322             handled_event = gtk_widget_event (widget, event);
2323               
2324           tmp = widget->parent;
2325           g_object_unref (widget);
2326
2327           widget = tmp;
2328           
2329           if (!handled_event && widget)
2330             g_object_ref (widget);
2331           else
2332             break;
2333         }
2334     }
2335   else
2336     g_object_unref (widget);
2337 }
2338
2339 #if 0
2340 static void
2341 gtk_error (gchar *str)
2342 {
2343   gtk_print (str);
2344 }
2345
2346 static void
2347 gtk_warning (gchar *str)
2348 {
2349   gtk_print (str);
2350 }
2351
2352 static void
2353 gtk_message (gchar *str)
2354 {
2355   gtk_print (str);
2356 }
2357
2358 static void
2359 gtk_print (gchar *str)
2360 {
2361   static GtkWidget *window = NULL;
2362   static GtkWidget *text;
2363   static int level = 0;
2364   GtkWidget *box1;
2365   GtkWidget *box2;
2366   GtkWidget *table;
2367   GtkWidget *hscrollbar;
2368   GtkWidget *vscrollbar;
2369   GtkWidget *separator;
2370   GtkWidget *button;
2371   
2372   if (level > 0)
2373     {
2374       fputs (str, stdout);
2375       fflush (stdout);
2376       return;
2377     }
2378   
2379   if (!window)
2380     {
2381       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2382       
2383       gtk_signal_connect (GTK_OBJECT (window), "destroy",
2384                           (GtkSignalFunc) gtk_widget_destroyed,
2385                           &window);
2386       
2387       gtk_window_set_title (GTK_WINDOW (window), "Messages");
2388       
2389       box1 = gtk_vbox_new (FALSE, 0);
2390       gtk_container_add (GTK_CONTAINER (window), box1);
2391       gtk_widget_show (box1);
2392       
2393       
2394       box2 = gtk_vbox_new (FALSE, 10);
2395       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2396       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2397       gtk_widget_show (box2);
2398       
2399       
2400       table = gtk_table_new (2, 2, FALSE);
2401       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
2402       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
2403       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
2404       gtk_widget_show (table);
2405       
2406       text = gtk_text_new (NULL, NULL);
2407       gtk_text_set_editable (GTK_TEXT (text), FALSE);
2408       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
2409       gtk_widget_show (text);
2410       gtk_widget_realize (text);
2411       
2412       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
2413       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
2414                         GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
2415       gtk_widget_show (hscrollbar);
2416       
2417       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
2418       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
2419                         GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2420       gtk_widget_show (vscrollbar);
2421       
2422       separator = gtk_hseparator_new ();
2423       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2424       gtk_widget_show (separator);
2425       
2426       
2427       box2 = gtk_vbox_new (FALSE, 10);
2428       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2429       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2430       gtk_widget_show (box2);
2431       
2432       
2433       button = gtk_button_new_with_label ("close");
2434       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2435                                  (GtkSignalFunc) gtk_widget_hide,
2436                                  GTK_OBJECT (window));
2437       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2438       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2439       gtk_widget_grab_default (button);
2440       gtk_widget_show (button);
2441     }
2442   
2443   level += 1;
2444   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
2445   level -= 1;
2446   
2447   if (!GTK_WIDGET_VISIBLE (window))
2448     gtk_widget_show (window);
2449 }
2450 #endif
2451
2452 gboolean
2453 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2454                                   GValue                *return_accu,
2455                                   const GValue          *handler_return,
2456                                   gpointer               dummy)
2457 {
2458   gboolean continue_emission;
2459   gboolean signal_handled;
2460   
2461   signal_handled = g_value_get_boolean (handler_return);
2462   g_value_set_boolean (return_accu, signal_handled);
2463   continue_emission = !signal_handled;
2464   
2465   return continue_emission;
2466 }
2467
2468 #define __GTK_MAIN_C__
2469 #include "gtkaliasdef.c"