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