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