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