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