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