]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
861ab0f44a2da55b8cbcf08b5474befc8d7dd342
[~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 "gtkmain.h"
30
31 #include <glib.h>
32 #include "gdkconfig.h"
33
34 #include <locale.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #include <sys/types.h>          /* For uid_t, gid_t */
43
44 #ifdef G_OS_WIN32
45 #define STRICT
46 #include <windows.h>
47 #undef STRICT
48 #endif
49
50 #include "gtkintl.h"
51
52 #include "gtkaccelmap.h"
53 #include "gtkbox.h"
54 #include "gtkclipboard.h"
55 #include "gtkdnd.h"
56 #include "gtkversion.h"
57 #include "gtkmodules.h"
58 #include "gtkrc.h"
59 #include "gtkrecentmanager.h"
60 #include "gtkselection.h"
61 #include "gtksettings.h"
62 #include "gtkwidgetprivate.h"
63 #include "gtkwindowprivate.h"
64 #include "gtktooltip.h"
65 #include "gtkdebug.h"
66 #include "gtkmenu.h"
67 #include "gdk/gdkkeysyms.h"
68
69 #ifdef G_OS_WIN32
70
71 static HMODULE gtk_dll;
72
73 BOOL WINAPI
74 DllMain (HINSTANCE hinstDLL,
75          DWORD     fdwReason,
76          LPVOID    lpvReserved)
77 {
78   switch (fdwReason)
79     {
80     case DLL_PROCESS_ATTACH:
81       gtk_dll = (HMODULE) hinstDLL;
82       break;
83     }
84
85   return TRUE;
86 }
87
88 /* These here before inclusion of gtkprivate.h so that the original
89  * GTK_LIBDIR and GTK_LOCALEDIR definitions are seen. Yeah, this is a
90  * bit sucky.
91  */
92 const gchar *
93 _gtk_get_libdir (void)
94 {
95   static char *gtk_libdir = NULL;
96   if (gtk_libdir == NULL)
97     {
98       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
99       gchar *slash = strrchr (root, '\\');
100       if (g_ascii_strcasecmp (slash + 1, ".libs") == 0)
101         gtk_libdir = GTK_LIBDIR;
102       else
103         gtk_libdir = g_build_filename (root, "lib", NULL);
104       g_free (root);
105     }
106
107   return gtk_libdir;
108 }
109
110 const gchar *
111 _gtk_get_localedir (void)
112 {
113   static char *gtk_localedir = NULL;
114   if (gtk_localedir == NULL)
115     {
116       const gchar *p;
117       gchar *root, *temp;
118       
119       /* GTK_LOCALEDIR ends in either /lib/locale or
120        * /share/locale. Scan for that slash.
121        */
122       p = GTK_LOCALEDIR + strlen (GTK_LOCALEDIR);
123       while (*--p != '/')
124         ;
125       while (*--p != '/')
126         ;
127
128       root = g_win32_get_package_installation_directory_of_module (gtk_dll);
129       temp = g_build_filename (root, p, NULL);
130       g_free (root);
131
132       /* gtk_localedir is passed to bindtextdomain() which isn't
133        * UTF-8-aware.
134        */
135       gtk_localedir = g_win32_locale_filename_from_utf8 (temp);
136       g_free (temp);
137     }
138   return gtk_localedir;
139 }
140
141 #endif
142
143 #include "gtkprivate.h"
144
145 /* Private type definitions
146  */
147 typedef struct _GtkQuitFunction          GtkQuitFunction;
148 typedef struct _GtkKeySnooperData        GtkKeySnooperData;
149
150 struct _GtkQuitFunction
151 {
152   guint id;
153   guint main_level;
154   GtkCallbackMarshal marshal;
155   GtkFunction function;
156   gpointer data;
157   GDestroyNotify destroy;
158 };
159
160 struct _GtkKeySnooperData
161 {
162   GtkKeySnoopFunc func;
163   gpointer func_data;
164   guint id;
165 };
166
167 static gint  gtk_quit_invoke_function    (GtkQuitFunction    *quitf);
168 static void  gtk_quit_destroy            (GtkQuitFunction    *quitf);
169 static gint  gtk_invoke_key_snoopers     (GtkWidget          *grab_widget,
170                                           GdkEvent           *event);
171
172 static GtkWindowGroup *gtk_main_get_window_group (GtkWidget   *widget);
173
174 static guint gtk_main_loop_level = 0;
175 static gint pre_initialized = FALSE;
176 static gint gtk_initialized = FALSE;
177 static GList *current_events = NULL;
178
179 static GSList *main_loops = NULL;      /* stack of currently executing main loops */
180
181 static GList *quit_functions = NULL;       /* A list of quit functions.
182                                             */
183 static GSList *key_snoopers = NULL;
184
185 static guint debug_flags = 0;              /* Global GTK debug flag */
186
187 #ifdef G_ENABLE_DEBUG
188 static const GDebugKey gtk_debug_keys[] = {
189   {"misc", GTK_DEBUG_MISC},
190   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
191   {"text", GTK_DEBUG_TEXT},
192   {"tree", GTK_DEBUG_TREE},
193   {"updates", GTK_DEBUG_UPDATES},
194   {"keybindings", GTK_DEBUG_KEYBINDINGS},
195   {"multihead", GTK_DEBUG_MULTIHEAD},
196   {"modules", GTK_DEBUG_MODULES},
197   {"geometry", GTK_DEBUG_GEOMETRY},
198   {"icontheme", GTK_DEBUG_ICONTHEME},
199   {"printing", GTK_DEBUG_PRINTING},
200   {"builder", GTK_DEBUG_BUILDER},
201   {"size-request", GTK_DEBUG_SIZE_REQUEST},
202 };
203 #endif /* G_ENABLE_DEBUG */
204
205 /**
206  * gtk_get_major_version:
207  *
208  * Returns the major version number of the GTK+ library.  (e.g. in GTK+ version
209  * 3.1.5 this is 3.) 
210  *
211  * This function is in the library, so it represents the GTK+ library
212  * your code is running against. Contrast with the #GTK_MAJOR_VERSION
213  * macro, which represents the major version of the GTK+ headers you
214  * have included when compiling your code.
215  *
216  * Returns: the major version number of the GTK+ library.
217  *
218  * Since: 3.0
219  */
220 guint
221 gtk_get_major_version (void)
222 {
223   return GTK_MAJOR_VERSION;
224 }
225
226 /**
227  * gtk_get_minor_version:
228  *
229  * Returns the minor version number of the GTK+ library.  (e.g. in GTK+ version
230  * 3.1.5 this is 1.) 
231  *
232  * This function is in the library, so it represents the GTK+ library
233  * your code is are running against. Contrast with the
234  * #GTK_MINOR_VERSION macro, which represents the minor version of the
235  * GTK+ headers you have included when compiling your code.
236  *
237  * Returns: the minor version number of the GTK+ library.
238  *
239  * Since: 3.0
240  */
241 guint
242 gtk_get_minor_version (void)
243 {
244   return GTK_MINOR_VERSION;
245 }
246
247 /**
248  * gtk_get_micro_version:
249  *
250  * Returns the micro version number of the GTK+ library.  (e.g. in GTK+ version
251  * 3.1.5 this is 5.) 
252  *
253  * This function is in the library, so it represents the GTK+ library
254  * your code is are running against. Contrast with the
255  * #GTK_MICRO_VERSION macro, which represents the micro version of the
256  * GTK+ headers you have included when compiling your code.
257  *
258  * Returns: the micro version number of the GTK+ library.
259  *
260  * Since: 3.0
261  */
262 guint
263 gtk_get_micro_version (void)
264 {
265   return GTK_MICRO_VERSION;
266 }
267
268 /**
269  * gtk_get_binary_age:
270  *
271  * Returns the binary age as passed to
272  * <application>libtool</application> when building the GTK+ library
273  * the process is running against. If
274  * <application>libtool</application> means nothing to you, don't
275  * worry about it.
276  *
277  * Returns: the binary age of the GTK+ library.
278  *
279  * Since: 3.0
280  */
281 guint
282 gtk_get_binary_age (void)
283 {
284   return GTK_BINARY_AGE;
285 }
286
287 /**
288  * gtk_get_interface_age:
289  *
290  * Returns the interface age as passed to
291  * <application>libtool</application> when building the GTK+ library
292  * the process is running against. If
293  * <application>libtool</application> means nothing to you, don't
294  * worry about it.
295  *
296  * Returns: the interface age of the GTK+ library.
297  *
298  * Since: 3.0
299  */
300 guint
301 gtk_get_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  * 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   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   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       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 (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
800   /* Set the 'initialized' flag.
801    */
802   gtk_initialized = TRUE;
803
804   /* load gtk modules */
805   if (gtk_modules_string)
806     {
807       _gtk_modules_init (argc, argv, gtk_modules_string->str);
808       g_string_free (gtk_modules_string, TRUE);
809     }
810   else
811     {
812       _gtk_modules_init (argc, argv, NULL);
813     }
814 }
815
816
817 typedef struct
818 {
819   gboolean open_default_display;
820 } OptionGroupInfo;
821
822 static gboolean
823 pre_parse_hook (GOptionContext *context,
824                 GOptionGroup   *group,
825                 gpointer        data,
826                 GError        **error)
827 {
828   do_pre_parse_initialization (NULL, NULL);
829   
830   return TRUE;
831 }
832
833 static gboolean
834 post_parse_hook (GOptionContext *context,
835                  GOptionGroup   *group,
836                  gpointer       data,
837                  GError        **error)
838 {
839   OptionGroupInfo *info = data;
840
841   
842   do_post_parse_initialization (NULL, NULL);
843   
844   if (info->open_default_display)
845     {
846       if (gdk_display_open_default_libgtk_only () == NULL)
847         {
848           const char *display_name = gdk_get_display_arg_name ();
849           g_set_error (error, 
850                        G_OPTION_ERROR, 
851                        G_OPTION_ERROR_FAILED,
852                        _("Cannot open display: %s"),
853                        display_name ? display_name : "" );
854           
855           return FALSE;
856         }
857     }
858
859   return TRUE;
860 }
861
862
863 /**
864  * gtk_get_debug_flags:
865  *
866  * Returns the GTK+ debug flags.
867  *
868  * This function is intended for GTK+ modules that want
869  * to adjust their debug output based on GTK+ debug flags.
870  *
871  * Returns: the GTK+ debug flags.
872  */
873 guint
874 gtk_get_debug_flags (void)
875 {
876   return debug_flags;
877 }
878
879 /**
880  * gtk_set_debug_flags:
881  *
882  * Sets the GTK+ debug flags.
883  */
884 void
885 gtk_set_debug_flags (guint flags)
886 {
887   debug_flags = flags;
888 }
889
890 /**
891  * gtk_get_option_group:
892  * @open_default_display: whether to open the default display 
893  *    when parsing the commandline arguments
894  * 
895  * Returns a #GOptionGroup for the commandline arguments recognized
896  * by GTK+ and GDK. You should add this group to your #GOptionContext 
897  * with g_option_context_add_group(), if you are using 
898  * g_option_context_parse() to parse your commandline arguments.
899  *
900  * Returns: a #GOptionGroup for the commandline arguments recognized
901  *   by GTK+
902  *
903  * Since: 2.6
904  */
905 GOptionGroup *
906 gtk_get_option_group (gboolean open_default_display)
907 {
908   GOptionGroup *group;
909   OptionGroupInfo *info;
910
911   gettext_initialization ();
912
913   info = g_new0 (OptionGroupInfo, 1);
914   info->open_default_display = open_default_display;
915   
916   group = g_option_group_new ("gtk", _("GTK+ Options"), _("Show GTK+ Options"), info, g_free);
917   g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
918
919   gdk_add_option_entries_libgtk_only (group);
920   g_option_group_add_entries (group, gtk_args);
921   g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
922   
923   return group;
924 }
925
926 /**
927  * gtk_init_with_args:
928  * @argc: a pointer to the number of command line arguments.
929  * @argv: a pointer to the array of command line arguments.
930  * @parameter_string: a string which is displayed in
931  *    the first line of <option>--help</option> output, after
932  *    <literal><replaceable>programname</replaceable> [OPTION...]</literal>
933  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
934  *    describing the options of your program
935  * @translation_domain: a translation domain to use for translating
936  *    the <option>--help</option> output for the options in @entries
937  *    and the @parameter_string with gettext(), or %NULL
938  * @error: a return location for errors
939  *
940  * This function does the same work as gtk_init_check().
941  * Additionally, it allows you to add your own commandline options,
942  * and it automatically generates nicely formatted
943  * <option>--help</option> output. Note that your program will
944  * be terminated after writing out the help output.
945  *
946  * Returns: %TRUE if the GUI has been successfully initialized,
947  *               %FALSE otherwise.
948  *
949  * Since: 2.6
950  */
951 gboolean
952 gtk_init_with_args (gint                 *argc,
953                     gchar              ***argv,
954                     const gchar          *parameter_string,
955                     const GOptionEntry   *entries,
956                     const gchar          *translation_domain,
957                     GError              **error)
958 {
959   GOptionContext *context;
960   GOptionGroup *gtk_group;
961   gboolean retval;
962
963   if (gtk_initialized)
964     return gdk_display_open_default_libgtk_only () != NULL;
965
966   gettext_initialization ();
967
968   if (!check_setugid ())
969     return FALSE;
970
971   gtk_group = gtk_get_option_group (TRUE);
972
973   context = g_option_context_new (parameter_string);
974   g_option_context_add_group (context, gtk_group);
975   g_option_context_set_translation_domain (context, translation_domain);
976
977   if (entries)
978     g_option_context_add_main_entries (context, entries, translation_domain);
979   retval = g_option_context_parse (context, argc, argv, error);
980
981   g_option_context_free (context);
982
983   return retval;
984 }
985
986
987 /**
988  * gtk_parse_args:
989  * @argc: (inout): a pointer to the number of command line arguments.
990  * @argv: (array) (inout): a pointer to the array of command line arguments.
991  *
992  * Parses command line arguments, and initializes global
993  * attributes of GTK+, but does not actually open a connection
994  * to a display. (See gdk_display_open(), gdk_get_display_arg_name())
995  *
996  * Any arguments used by GTK+ or GDK are removed from the array and
997  * @argc and @argv are updated accordingly.
998  *
999  * You shouldn't call this function explicitely if you are using
1000  * gtk_init(), or gtk_init_check().
1001  *
1002  * Return value: %TRUE if initialization succeeded, otherwise %FALSE.
1003  **/
1004 gboolean
1005 gtk_parse_args (int    *argc,
1006                 char ***argv)
1007 {
1008   GOptionContext *option_context;
1009   GOptionGroup *gtk_group;
1010   GError *error = NULL;
1011   
1012   if (gtk_initialized)
1013     return TRUE;
1014
1015   gettext_initialization ();
1016
1017   if (!check_setugid ())
1018     return FALSE;
1019
1020   option_context = g_option_context_new (NULL);
1021   g_option_context_set_ignore_unknown_options (option_context, TRUE);
1022   g_option_context_set_help_enabled (option_context, FALSE);
1023   gtk_group = gtk_get_option_group (FALSE);
1024   g_option_context_set_main_group (option_context, gtk_group);
1025   if (!g_option_context_parse (option_context, argc, argv, &error))
1026     {
1027       g_warning ("%s", error->message);
1028       g_error_free (error);
1029     }
1030
1031   g_option_context_free (option_context);
1032
1033   return TRUE;
1034 }
1035
1036 #ifdef G_PLATFORM_WIN32
1037 #undef gtk_init_check
1038 #endif
1039
1040 /**
1041  * gtk_init_check:
1042  * @argc: (inout): Address of the <parameter>argc</parameter> parameter of your
1043  *   main() function. Changed if any arguments were handled.
1044  * @argv: (array length=argc) (inout) (allow-none): Address of the <parameter>argv</parameter> parameter of main().
1045  *   Any parameters understood by gtk_init() are stripped before return.
1046  *
1047  * This function does the same work as gtk_init() with only
1048  * a single change: It does not terminate the program if the GUI can't be
1049  * initialized. Instead it returns %FALSE on failure.
1050  *
1051  * This way the application can fall back to some other means of communication 
1052  * with the user - for example a curses or command line interface.
1053  * 
1054  * Return value: %TRUE if the GUI has been successfully initialized, 
1055  *               %FALSE otherwise.
1056  **/
1057 gboolean
1058 gtk_init_check (int      *argc,
1059                 char   ***argv)
1060 {
1061   if (!gtk_parse_args (argc, argv))
1062     return FALSE;
1063
1064   return gdk_display_open_default_libgtk_only () != NULL;
1065 }
1066
1067 #ifdef G_PLATFORM_WIN32
1068 #undef gtk_init
1069 #endif
1070
1071 /**
1072  * gtk_init:
1073  * @argc: (inout): Address of the <parameter>argc</parameter> parameter of your
1074  *   main() function. Changed if any arguments were handled.
1075  * @argv: (array length=argc) (inout) (allow-none): Address of the <parameter>argv</parameter> parameter of main().
1076  *   Any parameters understood by gtk_init() are stripped before return.
1077  *
1078  * Call this function before using any other GTK+ functions in your GUI
1079  * applications.  It will initialize everything needed to operate the
1080  * toolkit and parses some standard command line options. @argc and 
1081  * @argv are adjusted accordingly so your own code will 
1082  * never see those standard arguments. 
1083  *
1084  * Note that there are some alternative ways to initialize GTK+: 
1085  * if you are calling gtk_parse_args(), gtk_init_check(), 
1086  * gtk_init_with_args() or g_option_context_parse() with 
1087  * the option group returned by gtk_get_option_group(), you 
1088  * <emphasis>don't</emphasis> have to call gtk_init().
1089  *
1090  * <note><para>
1091  * This function will terminate your program if it was unable to initialize 
1092  * the GUI for some reason. If you want your program to fall back to a 
1093  * textual interface you want to call gtk_init_check() instead.
1094  * </para></note>
1095  *
1096  * <note><para>
1097  * Since 2.18, GTK+ calls <literal>signal (SIGPIPE, SIG_IGN)</literal>
1098  * during initialization, to ignore SIGPIPE signals, since these are
1099  * almost never wanted in graphical applications. If you do need to
1100  * handle SIGPIPE for some reason, reset the handler after gtk_init(),
1101  * but notice that other libraries (e.g. libdbus or gvfs) might do
1102  * similar things.
1103  * </para></note>
1104  **/
1105 void
1106 gtk_init (int *argc, char ***argv)
1107 {
1108   if (!gtk_init_check (argc, argv))
1109     {
1110       const char *display_name_arg = gdk_get_display_arg_name ();
1111       if (display_name_arg == NULL)
1112         display_name_arg = getenv("DISPLAY");
1113       g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
1114       exit (1);
1115     }
1116 }
1117
1118 #ifdef G_PLATFORM_WIN32
1119
1120 static void
1121 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
1122 {
1123   if (sizeof_GtkWindow != sizeof (GtkWindow))
1124     g_error ("Incompatible build!\n"
1125              "The code using GTK+ thinks GtkWindow is of different\n"
1126              "size than it actually is in this build of GTK+.\n"
1127              "On Windows, this probably means that you have compiled\n"
1128              "your code with gcc without the -mms-bitfields switch,\n"
1129              "or that you are using an unsupported compiler.");
1130 }
1131
1132 /* In GTK+ 2.0 the GtkWindow struct actually is the same size in
1133  * gcc-compiled code on Win32 whether compiled with -fnative-struct or
1134  * not. Unfortunately this wan't noticed until after GTK+ 2.0.1. So,
1135  * from GTK+ 2.0.2 on, check some other struct, too, where the use of
1136  * -fnative-struct still matters. GtkBox is one such.
1137  */
1138 static void
1139 check_sizeof_GtkBox (size_t sizeof_GtkBox)
1140 {
1141   if (sizeof_GtkBox != sizeof (GtkBox))
1142     g_error ("Incompatible build!\n"
1143              "The code using GTK+ thinks GtkBox is of different\n"
1144              "size than it actually is in this build of GTK+.\n"
1145              "On Windows, this probably means that you have compiled\n"
1146              "your code with gcc without the -mms-bitfields switch,\n"
1147              "or that you are using an unsupported compiler.");
1148 }
1149
1150 /* These two functions might get more checks added later, thus pass
1151  * in the number of extra args.
1152  */
1153 void
1154 gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1155 {
1156   check_sizeof_GtkWindow (sizeof_GtkWindow);
1157   if (num_checks >= 2)
1158     check_sizeof_GtkBox (sizeof_GtkBox);
1159   gtk_init (argc, argv);
1160 }
1161
1162 gboolean
1163 gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1164 {
1165   check_sizeof_GtkWindow (sizeof_GtkWindow);
1166   if (num_checks >= 2)
1167     check_sizeof_GtkBox (sizeof_GtkBox);
1168   return gtk_init_check (argc, argv);
1169 }
1170
1171 #endif
1172
1173 /**
1174  * gtk_set_locale:
1175  *
1176  * Initializes internationalization support for GTK+. gtk_init()
1177  * automatically does this, so there is typically no point
1178  * in calling this function.
1179  *
1180  * If you are calling this function because you changed the locale
1181  * after GTK+ is was initialized, then calling this function
1182  * may help a bit. (Note, however, that changing the locale
1183  * after GTK+ is initialized may produce inconsistent results and
1184  * is not really supported.)
1185  * 
1186  * In detail - sets the current locale according to the
1187  * program environment. This is the same as calling the C library function
1188  * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the 
1189  * locale specific setup of the windowing system used by GDK.
1190  * 
1191  * Returns: a string corresponding to the locale set, typically in the
1192  * form lang_COUNTRY, where lang is an ISO-639 language code, and
1193  * COUNTRY is an ISO-3166 country code. On Unix, this form matches the
1194  * result of the setlocale(); it is also used on other machines, such as 
1195  * Windows, where the C library returns a different result. The string is 
1196  * owned by GTK+ and should not be modified or freed.
1197  **/
1198 gchar *
1199 gtk_set_locale (void)
1200 {
1201   return gdk_set_locale ();
1202 }
1203
1204 /**
1205  * _gtk_get_lc_ctype:
1206  *
1207  * Return the Unix-style locale string for the language currently in
1208  * effect. On Unix systems, this is the return value from
1209  * <literal>setlocale(LC_CTYPE, NULL)</literal>, and the user can
1210  * affect this through the environment variables LC_ALL, LC_CTYPE or
1211  * LANG (checked in that order). The locale strings typically is in
1212  * the form lang_COUNTRY, where lang is an ISO-639 language code, and
1213  * COUNTRY is an ISO-3166 country code. For instance, sv_FI for
1214  * Swedish as written in Finland or pt_BR for Portuguese as written in
1215  * Brazil.
1216  * 
1217  * On Windows, the C library doesn't use any such environment
1218  * variables, and setting them won't affect the behaviour of functions
1219  * like ctime(). The user sets the locale through the Regional Options 
1220  * in the Control Panel. The C library (in the setlocale() function) 
1221  * does not use country and language codes, but country and language 
1222  * names spelled out in English. 
1223  * However, this function does check the above environment
1224  * variables, and does return a Unix-style locale string based on
1225  * either said environment variables or the thread's current locale.
1226  *
1227  * Return value: a dynamically allocated string, free with g_free().
1228  */
1229
1230 gchar *
1231 _gtk_get_lc_ctype (void)
1232 {
1233 #ifdef G_OS_WIN32
1234   /* Somebody might try to set the locale for this process using the
1235    * LANG or LC_ environment variables. The Microsoft C library
1236    * doesn't know anything about them. You set the locale in the
1237    * Control Panel. Setting these env vars won't have any affect on
1238    * locale-dependent C library functions like ctime(). But just for
1239    * kicks, do obey LC_ALL, LC_CTYPE and LANG in GTK. (This also makes
1240    * it easier to test GTK and Pango in various default languages, you
1241    * don't have to clickety-click in the Control Panel, you can simply
1242    * start the program with LC_ALL=something on the command line.)
1243    */
1244   gchar *p;
1245
1246   p = getenv ("LC_ALL");
1247   if (p != NULL)
1248     return g_strdup (p);
1249
1250   p = getenv ("LC_CTYPE");
1251   if (p != NULL)
1252     return g_strdup (p);
1253
1254   p = getenv ("LANG");
1255   if (p != NULL)
1256     return g_strdup (p);
1257
1258   return g_win32_getlocale ();
1259 #else
1260   return g_strdup (setlocale (LC_CTYPE, NULL));
1261 #endif
1262 }
1263
1264 /**
1265  * gtk_get_default_language:
1266  *
1267  * Returns the #PangoLanguage for the default language currently in
1268  * effect. (Note that this can change over the life of an
1269  * application.)  The default language is derived from the current
1270  * locale. It determines, for example, whether GTK+ uses the
1271  * right-to-left or left-to-right text direction.
1272  *
1273  * This function is equivalent to pango_language_get_default().  See
1274  * that function for details.
1275  * 
1276  * Return value: the default language as a #PangoLanguage, must not be
1277  * freed
1278  **/
1279 PangoLanguage *
1280 gtk_get_default_language (void)
1281 {
1282   return pango_language_get_default ();
1283 }
1284
1285 void
1286 gtk_main (void)
1287 {
1288   GList *tmp_list;
1289   GMainLoop *loop;
1290
1291   gtk_main_loop_level++;
1292   
1293   loop = g_main_loop_new (NULL, TRUE);
1294   main_loops = g_slist_prepend (main_loops, loop);
1295
1296   if (g_main_loop_is_running (main_loops->data))
1297     {
1298       GDK_THREADS_LEAVE ();
1299       g_main_loop_run (loop);
1300       GDK_THREADS_ENTER ();
1301       gdk_flush ();
1302     }
1303
1304   if (quit_functions)
1305     {
1306       GList *reinvoke_list = NULL;
1307       GtkQuitFunction *quitf;
1308
1309       while (quit_functions)
1310         {
1311           quitf = quit_functions->data;
1312
1313           tmp_list = quit_functions;
1314           quit_functions = g_list_remove_link (quit_functions, quit_functions);
1315           g_list_free_1 (tmp_list);
1316
1317           if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
1318               gtk_quit_invoke_function (quitf))
1319             {
1320               reinvoke_list = g_list_prepend (reinvoke_list, quitf);
1321             }
1322           else
1323             {
1324               gtk_quit_destroy (quitf);
1325             }
1326         }
1327       if (reinvoke_list)
1328         {
1329           GList *work;
1330           
1331           work = g_list_last (reinvoke_list);
1332           if (quit_functions)
1333             quit_functions->prev = work;
1334           work->next = quit_functions;
1335           quit_functions = work;
1336         }
1337
1338       gdk_flush ();
1339     }
1340     
1341   main_loops = g_slist_remove (main_loops, loop);
1342
1343   g_main_loop_unref (loop);
1344
1345   gtk_main_loop_level--;
1346
1347   if (gtk_main_loop_level == 0)
1348     {
1349       /* Try storing all clipboard data we have */
1350       _gtk_clipboard_store_all ();
1351
1352       /* Synchronize the recent manager singleton */
1353       _gtk_recent_manager_sync ();
1354     }
1355 }
1356
1357 guint
1358 gtk_main_level (void)
1359 {
1360   return gtk_main_loop_level;
1361 }
1362
1363 void
1364 gtk_main_quit (void)
1365 {
1366   g_return_if_fail (main_loops != NULL);
1367
1368   g_main_loop_quit (main_loops->data);
1369 }
1370
1371 gboolean
1372 gtk_events_pending (void)
1373 {
1374   gboolean result;
1375   
1376   GDK_THREADS_LEAVE ();  
1377   result = g_main_context_pending (NULL);
1378   GDK_THREADS_ENTER ();
1379
1380   return result;
1381 }
1382
1383 gboolean
1384 gtk_main_iteration (void)
1385 {
1386   GDK_THREADS_LEAVE ();
1387   g_main_context_iteration (NULL, TRUE);
1388   GDK_THREADS_ENTER ();
1389
1390   if (main_loops)
1391     return !g_main_loop_is_running (main_loops->data);
1392   else
1393     return TRUE;
1394 }
1395
1396 gboolean
1397 gtk_main_iteration_do (gboolean blocking)
1398 {
1399   GDK_THREADS_LEAVE ();
1400   g_main_context_iteration (NULL, blocking);
1401   GDK_THREADS_ENTER ();
1402
1403   if (main_loops)
1404     return !g_main_loop_is_running (main_loops->data);
1405   else
1406     return TRUE;
1407 }
1408
1409 /* private libgtk to libgdk interfaces
1410  */
1411 gboolean gdk_device_grab_info_libgtk_only (GdkDisplay  *display,
1412                                            GdkDevice   *device,
1413                                            GdkWindow  **grab_window,
1414                                            gboolean    *owner_events);
1415
1416 static void
1417 rewrite_events_translate (GdkWindow *old_window,
1418                           GdkWindow *new_window,
1419                           gdouble   *x,
1420                           gdouble   *y)
1421 {
1422   gint old_origin_x, old_origin_y;
1423   gint new_origin_x, new_origin_y;
1424
1425   gdk_window_get_origin (old_window, &old_origin_x, &old_origin_y);
1426   gdk_window_get_origin (new_window, &new_origin_x, &new_origin_y);
1427
1428   *x += old_origin_x - new_origin_x;
1429   *y += old_origin_y - new_origin_y;
1430 }
1431
1432 static GdkEvent *
1433 rewrite_event_for_window (GdkEvent  *event,
1434                           GdkWindow *new_window)
1435 {
1436   event = gdk_event_copy (event);
1437
1438   switch (event->type)
1439     {
1440     case GDK_SCROLL:
1441       rewrite_events_translate (event->any.window,
1442                                 new_window,
1443                                 &event->scroll.x, &event->scroll.y);
1444       break;
1445     case GDK_BUTTON_PRESS:
1446     case GDK_2BUTTON_PRESS:
1447     case GDK_3BUTTON_PRESS:
1448     case GDK_BUTTON_RELEASE:
1449       rewrite_events_translate (event->any.window,
1450                                 new_window,
1451                                 &event->button.x, &event->button.y);
1452       break;
1453     case GDK_MOTION_NOTIFY:
1454       rewrite_events_translate (event->any.window,
1455                                 new_window,
1456                                 &event->motion.x, &event->motion.y);
1457       break;
1458     case GDK_KEY_PRESS:
1459     case GDK_KEY_RELEASE:
1460     case GDK_PROXIMITY_IN:
1461     case GDK_PROXIMITY_OUT:
1462       break;
1463
1464     default:
1465       return event;
1466     }
1467
1468   g_object_unref (event->any.window);
1469   event->any.window = g_object_ref (new_window);
1470
1471   return event;
1472 }
1473
1474 /* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
1475  * then what X11 does is deliver the event normally if it was going to this
1476  * client, otherwise, delivers it in terms of the grab window. This function
1477  * rewrites events to the effect that events going to the same window group
1478  * are delivered normally, otherwise, the event is delivered in terms of the
1479  * grab window.
1480  */
1481 static GdkEvent *
1482 rewrite_event_for_grabs (GdkEvent *event)
1483 {
1484   GdkWindow *grab_window;
1485   GtkWidget *event_widget, *grab_widget;
1486   gpointer grab_widget_ptr;
1487   gboolean owner_events;
1488   GdkDisplay *display;
1489   GdkDevice *device;
1490
1491   switch (event->type)
1492     {
1493     case GDK_SCROLL:
1494     case GDK_BUTTON_PRESS:
1495     case GDK_2BUTTON_PRESS:
1496     case GDK_3BUTTON_PRESS:
1497     case GDK_BUTTON_RELEASE:
1498     case GDK_MOTION_NOTIFY:
1499     case GDK_PROXIMITY_IN:
1500     case GDK_PROXIMITY_OUT:
1501     case GDK_KEY_PRESS:
1502     case GDK_KEY_RELEASE:
1503       display = gdk_window_get_display (event->any.window);
1504       device = gdk_event_get_device (event);
1505
1506       if (!gdk_device_grab_info_libgtk_only (display, device, &grab_window, &owner_events) ||
1507           !owner_events)
1508         return NULL;
1509       break;
1510     default:
1511       return NULL;
1512     }
1513
1514   event_widget = gtk_get_event_widget (event);
1515   gdk_window_get_user_data (grab_window, &grab_widget_ptr);
1516   grab_widget = grab_widget_ptr;
1517
1518   if (grab_widget &&
1519       gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
1520     return rewrite_event_for_window (event, grab_window);
1521   else
1522     return NULL;
1523 }
1524
1525 void 
1526 gtk_main_do_event (GdkEvent *event)
1527 {
1528   GtkWidget *event_widget;
1529   GtkWidget *grab_widget = NULL;
1530   GtkWindowGroup *window_group;
1531   GdkEvent *rewritten_event = NULL;
1532   GdkDevice *device;
1533   GList *tmp_list;
1534
1535   if (event->type == GDK_SETTING)
1536     {
1537       _gtk_settings_handle_event (&event->setting);
1538       return;
1539     }
1540
1541   if (event->type == GDK_OWNER_CHANGE)
1542     {
1543       _gtk_clipboard_handle_event (&event->owner_change);
1544       return;
1545     }
1546
1547   /* Find the widget which got the event. We store the widget
1548    *  in the user_data field of GdkWindow's.
1549    *  Ignore the event if we don't have a widget for it, except
1550    *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
1551    *  Though this happens rarely, bogus events can occour
1552    *  for e.g. destroyed GdkWindows. 
1553    */
1554   event_widget = gtk_get_event_widget (event);
1555   if (!event_widget)
1556     {
1557       /* To handle selection INCR transactions, we select
1558        * PropertyNotify events on the requestor window and create
1559        * a corresponding (fake) GdkWindow so that events get
1560        * here. There won't be a widget though, so we have to handle
1561            * them specially
1562            */
1563       if (event->type == GDK_PROPERTY_NOTIFY)
1564         _gtk_selection_incr_event (event->any.window,
1565                                    &event->property);
1566
1567       return;
1568     }
1569
1570   /* If pointer or keyboard grabs are in effect, munge the events
1571    * so that each window group looks like a separate app.
1572    */
1573   rewritten_event = rewrite_event_for_grabs (event);
1574   if (rewritten_event)
1575     {
1576       event = rewritten_event;
1577       event_widget = gtk_get_event_widget (event);
1578     }
1579
1580   window_group = gtk_main_get_window_group (event_widget);
1581   device = gdk_event_get_device (event);
1582
1583   /* check whether there is a (device) grab in effect...
1584    */
1585   if (device)
1586     grab_widget = gtk_window_group_get_current_device_grab (window_group, device);
1587
1588   if (!grab_widget)
1589     grab_widget = gtk_window_group_get_current_grab (window_group);
1590
1591   /* If the grab widget is an ancestor of the event widget
1592    *  then we send the event to the original event widget.
1593    *  This is the key to implementing modality.
1594    */
1595   if (!grab_widget ||
1596       (gtk_widget_is_sensitive (event_widget) &&
1597        gtk_widget_is_ancestor (event_widget, grab_widget)))
1598     grab_widget = event_widget;
1599
1600   /* If the widget receiving events is actually blocked by another device GTK+ grab */
1601   if (device &&
1602       _gtk_window_group_widget_is_blocked_for_device (window_group, grab_widget, device))
1603     {
1604       if (rewritten_event)
1605         gdk_event_free (rewritten_event);
1606
1607       return;
1608     }
1609
1610   /* Push the event onto a stack of current events for
1611    * gtk_current_event_get().
1612    */
1613   current_events = g_list_prepend (current_events, event);
1614
1615   /* Not all events get sent to the grabbing widget.
1616    * The delete, destroy, expose, focus change and resize
1617    *  events still get sent to the event widget because
1618    *  1) these events have no meaning for the grabbing widget
1619    *  and 2) redirecting these events to the grabbing widget
1620    *  could cause the display to be messed up.
1621    * 
1622    * Drag events are also not redirected, since it isn't
1623    *  clear what the semantics of that would be.
1624    */
1625   switch (event->type)
1626     {
1627     case GDK_NOTHING:
1628       break;
1629       
1630     case GDK_DELETE:
1631       g_object_ref (event_widget);
1632       if ((!gtk_window_group_get_current_grab (window_group) || gtk_widget_get_toplevel (gtk_window_group_get_current_grab (window_group)) == event_widget) &&
1633           !gtk_widget_event (event_widget, event))
1634         gtk_widget_destroy (event_widget);
1635       g_object_unref (event_widget);
1636       break;
1637       
1638     case GDK_DESTROY:
1639       /* Unexpected GDK_DESTROY from the outside, ignore for
1640        * child windows, handle like a GDK_DELETE for toplevels
1641        */
1642       if (!gtk_widget_get_parent (event_widget))
1643         {
1644           g_object_ref (event_widget);
1645           if (!gtk_widget_event (event_widget, event) &&
1646               gtk_widget_get_realized (event_widget))
1647             gtk_widget_destroy (event_widget);
1648           g_object_unref (event_widget);
1649         }
1650       break;
1651       
1652     case GDK_EXPOSE:
1653       if (event->any.window && gtk_widget_get_double_buffered (event_widget))
1654         {
1655           gdk_window_begin_paint_region (event->any.window, event->expose.region);
1656           gtk_widget_send_expose (event_widget, event);
1657           gdk_window_end_paint (event->any.window);
1658         }
1659       else
1660         {
1661           /* The app may paint with a previously allocated cairo_t,
1662              which will draw directly to the window. We can't catch cairo
1663              draw operations to automatically flush the window, thus we
1664              need to explicitly flush any outstanding moves or double
1665              buffering */
1666           gdk_window_flush (event->any.window);
1667           gtk_widget_send_expose (event_widget, event);
1668         }
1669       break;
1670
1671     case GDK_PROPERTY_NOTIFY:
1672     case GDK_FOCUS_CHANGE:
1673     case GDK_CONFIGURE:
1674     case GDK_MAP:
1675     case GDK_UNMAP:
1676     case GDK_SELECTION_CLEAR:
1677     case GDK_SELECTION_REQUEST:
1678     case GDK_SELECTION_NOTIFY:
1679     case GDK_CLIENT_EVENT:
1680     case GDK_VISIBILITY_NOTIFY:
1681     case GDK_WINDOW_STATE:
1682     case GDK_GRAB_BROKEN:
1683     case GDK_DAMAGE:
1684       gtk_widget_event (event_widget, event);
1685       break;
1686
1687     case GDK_SCROLL:
1688     case GDK_BUTTON_PRESS:
1689     case GDK_2BUTTON_PRESS:
1690     case GDK_3BUTTON_PRESS:
1691       gtk_propagate_event (grab_widget, event);
1692       break;
1693
1694     case GDK_KEY_PRESS:
1695     case GDK_KEY_RELEASE:
1696       if (key_snoopers)
1697         {
1698           if (gtk_invoke_key_snoopers (grab_widget, event))
1699             break;
1700         }
1701       /* Catch alt press to enable auto-mnemonics;
1702        * menus are handled elsewhere
1703        */
1704       if ((event->key.keyval == GDK_KEY_Alt_L || event->key.keyval == GDK_KEY_Alt_R) &&
1705           !GTK_IS_MENU_SHELL (grab_widget))
1706         {
1707           gboolean auto_mnemonics;
1708
1709           g_object_get (gtk_widget_get_settings (grab_widget),
1710                         "gtk-auto-mnemonics", &auto_mnemonics, NULL);
1711
1712           if (auto_mnemonics)
1713             {
1714               gboolean mnemonics_visible;
1715               GtkWidget *window;
1716
1717               mnemonics_visible = (event->type == GDK_KEY_PRESS);
1718
1719               window = gtk_widget_get_toplevel (grab_widget);
1720
1721               if (GTK_IS_WINDOW (window))
1722                 gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
1723             }
1724         }
1725       /* else fall through */
1726     case GDK_MOTION_NOTIFY:
1727     case GDK_BUTTON_RELEASE:
1728     case GDK_PROXIMITY_IN:
1729     case GDK_PROXIMITY_OUT:
1730       gtk_propagate_event (grab_widget, event);
1731       break;
1732       
1733     case GDK_ENTER_NOTIFY:
1734       _gtk_widget_set_device_window (event_widget,
1735                                      gdk_event_get_device (event),
1736                                      event->any.window);
1737       if (gtk_widget_is_sensitive (grab_widget))
1738         gtk_widget_event (grab_widget, event);
1739       break;
1740       
1741     case GDK_LEAVE_NOTIFY:
1742       _gtk_widget_set_device_window (event_widget,
1743                                      gdk_event_get_device (event),
1744                                      NULL);
1745       if (gtk_widget_is_sensitive (grab_widget))
1746         gtk_widget_event (grab_widget, event);
1747       break;
1748       
1749     case GDK_DRAG_STATUS:
1750     case GDK_DROP_FINISHED:
1751       _gtk_drag_source_handle_event (event_widget, event);
1752       break;
1753     case GDK_DRAG_ENTER:
1754     case GDK_DRAG_LEAVE:
1755     case GDK_DRAG_MOTION:
1756     case GDK_DROP_START:
1757       _gtk_drag_dest_handle_event (event_widget, event);
1758       break;
1759     default:
1760       g_assert_not_reached ();
1761       break;
1762     }
1763
1764   if (event->type == GDK_ENTER_NOTIFY
1765       || event->type == GDK_LEAVE_NOTIFY
1766       || event->type == GDK_BUTTON_PRESS
1767       || event->type == GDK_2BUTTON_PRESS
1768       || event->type == GDK_3BUTTON_PRESS
1769       || event->type == GDK_KEY_PRESS
1770       || event->type == GDK_DRAG_ENTER
1771       || event->type == GDK_GRAB_BROKEN
1772       || event->type == GDK_MOTION_NOTIFY
1773       || event->type == GDK_SCROLL)
1774     {
1775       _gtk_tooltip_handle_event (event);
1776     }
1777   
1778   tmp_list = current_events;
1779   current_events = g_list_remove_link (current_events, tmp_list);
1780   g_list_free_1 (tmp_list);
1781
1782   if (rewritten_event)
1783     gdk_event_free (rewritten_event);
1784 }
1785
1786 gboolean
1787 gtk_true (void)
1788 {
1789   return TRUE;
1790 }
1791
1792 gboolean
1793 gtk_false (void)
1794 {
1795   return FALSE;
1796 }
1797
1798 static GtkWindowGroup *
1799 gtk_main_get_window_group (GtkWidget   *widget)
1800 {
1801   GtkWidget *toplevel = NULL;
1802
1803   if (widget)
1804     toplevel = gtk_widget_get_toplevel (widget);
1805
1806   if (GTK_IS_WINDOW (toplevel))
1807     return gtk_window_get_group (GTK_WINDOW (toplevel));
1808   else
1809     return gtk_window_get_group (NULL);
1810 }
1811
1812 typedef struct
1813 {
1814   GtkWidget *old_grab_widget;
1815   GtkWidget *new_grab_widget;
1816   gboolean   was_grabbed;
1817   gboolean   is_grabbed;
1818   gboolean   from_grab;
1819   GList     *notified_windows;
1820   GdkDevice *device;
1821 } GrabNotifyInfo;
1822
1823 static void
1824 synth_crossing_for_grab_notify (GtkWidget       *from,
1825                                 GtkWidget       *to,
1826                                 GrabNotifyInfo  *info,
1827                                 GList           *devices,
1828                                 GdkCrossingMode  mode)
1829 {
1830   while (devices)
1831     {
1832       GdkDevice *device = devices->data;
1833       GdkWindow *from_window, *to_window;
1834
1835       /* Do not propagate events more than once to
1836        * the same windows if non-multidevice aware.
1837        */
1838       if (!from)
1839         from_window = NULL;
1840       else
1841         {
1842           from_window = _gtk_widget_get_device_window (from, device);
1843
1844           if (from_window &&
1845               !gdk_window_get_support_multidevice (from_window) &&
1846               g_list_find (info->notified_windows, from_window))
1847             from_window = NULL;
1848         }
1849
1850       if (!to)
1851         to_window = NULL;
1852       else
1853         {
1854           to_window = _gtk_widget_get_device_window (to, device);
1855
1856           if (to_window &&
1857               !gdk_window_get_support_multidevice (to_window) &&
1858               g_list_find (info->notified_windows, to_window))
1859             to_window = NULL;
1860         }
1861
1862       if (from_window || to_window)
1863         {
1864           _gtk_widget_synthesize_crossing ((from_window) ? from : NULL,
1865                                            (to_window) ? to : NULL,
1866                                            device, mode);
1867
1868           if (from_window)
1869             info->notified_windows = g_list_prepend (info->notified_windows, from_window);
1870
1871           if (to_window)
1872             info->notified_windows = g_list_prepend (info->notified_windows, to_window);
1873         }
1874
1875       devices = devices->next;
1876     }
1877 }
1878
1879 static void
1880 gtk_grab_notify_foreach (GtkWidget *child,
1881                          gpointer   data)
1882 {
1883   GrabNotifyInfo *info = data;
1884   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1885   GList *devices;
1886
1887   was_grabbed = info->was_grabbed;
1888   is_grabbed = info->is_grabbed;
1889
1890   info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1891   info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1892
1893   was_shadowed = info->old_grab_widget && !info->was_grabbed;
1894   is_shadowed = info->new_grab_widget && !info->is_grabbed;
1895
1896   g_object_ref (child);
1897
1898   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1899     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1900
1901   if (info->device &&
1902       _gtk_widget_get_device_window (child, info->device))
1903     {
1904       /* Device specified and is on widget */
1905       devices = g_list_prepend (NULL, info->device);
1906     }
1907   else
1908     devices = _gtk_widget_list_devices (child);
1909
1910   if (is_shadowed)
1911     {
1912       _gtk_widget_set_shadowed (child, TRUE);
1913       if (!was_shadowed && devices &&
1914           gtk_widget_is_sensitive (child))
1915         synth_crossing_for_grab_notify (child, info->new_grab_widget,
1916                                         info, devices,
1917                                         GDK_CROSSING_GTK_GRAB);
1918     }
1919   else
1920     {
1921       _gtk_widget_set_shadowed (child, FALSE);
1922       if (was_shadowed && devices &&
1923           gtk_widget_is_sensitive (child))
1924         synth_crossing_for_grab_notify (info->old_grab_widget, child,
1925                                         info, devices,
1926                                         info->from_grab ? GDK_CROSSING_GTK_GRAB :
1927                                         GDK_CROSSING_GTK_UNGRAB);
1928     }
1929
1930   if (was_shadowed != is_shadowed)
1931     _gtk_widget_grab_notify (child, was_shadowed);
1932
1933   g_object_unref (child);
1934   g_list_free (devices);
1935
1936   info->was_grabbed = was_grabbed;
1937   info->is_grabbed = is_grabbed;
1938 }
1939
1940 static void
1941 gtk_grab_notify (GtkWindowGroup *group,
1942                  GdkDevice      *device,
1943                  GtkWidget      *old_grab_widget,
1944                  GtkWidget      *new_grab_widget,
1945                  gboolean        from_grab)
1946 {
1947   GList *toplevels;
1948   GrabNotifyInfo info = { 0 };
1949
1950   if (old_grab_widget == new_grab_widget)
1951     return;
1952
1953   info.old_grab_widget = old_grab_widget;
1954   info.new_grab_widget = new_grab_widget;
1955   info.from_grab = from_grab;
1956   info.device = device;
1957
1958   g_object_ref (group);
1959
1960   toplevels = gtk_window_list_toplevels ();
1961   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1962
1963   while (toplevels)
1964     {
1965       GtkWindow *toplevel = toplevels->data;
1966       toplevels = g_list_delete_link (toplevels, toplevels);
1967
1968       info.was_grabbed = FALSE;
1969       info.is_grabbed = FALSE;
1970
1971       if (group == gtk_window_get_group (toplevel))
1972         gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1973       g_object_unref (toplevel);
1974     }
1975
1976   g_list_free (info.notified_windows);
1977   g_object_unref (group);
1978 }
1979
1980 void
1981 gtk_grab_add (GtkWidget *widget)
1982 {
1983   GtkWindowGroup *group;
1984   GtkWidget *old_grab_widget;
1985   
1986   g_return_if_fail (widget != NULL);
1987   
1988   if (!gtk_widget_has_grab (widget) && gtk_widget_is_sensitive (widget))
1989     {
1990       _gtk_widget_set_has_grab (widget, TRUE);
1991
1992       group = gtk_main_get_window_group (widget);
1993
1994       old_grab_widget = gtk_window_group_get_current_grab (group);
1995
1996       g_object_ref (widget);
1997       _gtk_window_group_add_grab (group, widget);
1998
1999       gtk_grab_notify (group, NULL, old_grab_widget, widget, TRUE);
2000     }
2001 }
2002
2003 /**
2004  * gtk_grab_get_current:
2005  *
2006  * Queries the current grab of the default window group.
2007  *
2008  * Return value: (transfer none): The widget which currently
2009  *     has the grab or %NULL if no grab is active
2010  */
2011 GtkWidget*
2012 gtk_grab_get_current (void)
2013 {
2014   GtkWindowGroup *group;
2015
2016   group = gtk_main_get_window_group (NULL);
2017
2018   return gtk_window_group_get_current_grab (group);
2019 }
2020
2021 void
2022 gtk_grab_remove (GtkWidget *widget)
2023 {
2024   GtkWindowGroup *group;
2025   GtkWidget *new_grab_widget;
2026   
2027   g_return_if_fail (widget != NULL);
2028   
2029   if (gtk_widget_has_grab (widget))
2030     {
2031       _gtk_widget_set_has_grab (widget, FALSE);
2032
2033       group = gtk_main_get_window_group (widget);
2034       _gtk_window_group_remove_grab (group, widget);
2035       new_grab_widget = gtk_window_group_get_current_grab (group);
2036
2037       gtk_grab_notify (group, NULL, widget, new_grab_widget, FALSE);
2038
2039       g_object_unref (widget);
2040     }
2041 }
2042
2043 /**
2044  * gtk_device_grab_add:
2045  * @widget: a #GtkWidget
2046  * @device: a #GtkDevice to grab on.
2047  * @block_others: %TRUE to prevent other devices to interact with @widget.
2048  *
2049  * Adds a GTK+ grab on @device, so all the events on @device and its
2050  * associated pointer or keyboard (if any) are delivered to @widget.
2051  * If the @block_others parameter is %TRUE, any other devices will be
2052  * unable to interact with @widget during the grab.
2053  *
2054  * Since: 3.0
2055  **/
2056 void
2057 gtk_device_grab_add (GtkWidget        *widget,
2058                      GdkDevice        *device,
2059                      gboolean          block_others)
2060 {
2061   GtkWindowGroup *group;
2062   GtkWidget *old_grab_widget;
2063
2064   g_return_if_fail (GTK_IS_WIDGET (widget));
2065   g_return_if_fail (GDK_IS_DEVICE (device));
2066
2067   group = gtk_main_get_window_group (widget);
2068   old_grab_widget = gtk_window_group_get_current_device_grab (group, device);
2069
2070   if (old_grab_widget != widget)
2071     _gtk_window_group_add_device_grab (group, widget, device, block_others);
2072
2073   gtk_grab_notify (group, device, old_grab_widget, widget, TRUE);
2074 }
2075
2076 /**
2077  * gtk_device_grab_remove:
2078  * @widget: a #GtkWidget
2079  * @device: a #GdkDevice
2080  *
2081  * Removes a device grab from the given widget. You have to pair calls
2082  * to gtk_device_grab_add() and gtk_device_grab_remove().
2083  *
2084  * Since: 3.0
2085  **/
2086 void
2087 gtk_device_grab_remove (GtkWidget *widget,
2088                         GdkDevice *device)
2089 {
2090   GtkWindowGroup *group;
2091   GtkWidget *new_grab_widget;
2092
2093   g_return_if_fail (GTK_IS_WIDGET (widget));
2094   g_return_if_fail (GDK_IS_DEVICE (device));
2095
2096   group = gtk_main_get_window_group (widget);
2097   _gtk_window_group_remove_device_grab (group, widget, device);
2098   new_grab_widget = gtk_window_group_get_current_device_grab (group, device);
2099
2100   gtk_grab_notify (group, device, widget, new_grab_widget, FALSE);
2101 }
2102
2103 guint
2104 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
2105                          gpointer        func_data)
2106 {
2107   GtkKeySnooperData *data;
2108   static guint snooper_id = 1;
2109
2110   g_return_val_if_fail (snooper != NULL, 0);
2111
2112   data = g_new (GtkKeySnooperData, 1);
2113   data->func = snooper;
2114   data->func_data = func_data;
2115   data->id = snooper_id++;
2116   key_snoopers = g_slist_prepend (key_snoopers, data);
2117
2118   return data->id;
2119 }
2120
2121 void
2122 gtk_key_snooper_remove (guint snooper_id)
2123 {
2124   GtkKeySnooperData *data = NULL;
2125   GSList *slist;
2126
2127   slist = key_snoopers;
2128   while (slist)
2129     {
2130       data = slist->data;
2131       if (data->id == snooper_id)
2132         break;
2133
2134       slist = slist->next;
2135       data = NULL;
2136     }
2137   if (data)
2138     {
2139       key_snoopers = g_slist_remove (key_snoopers, data);
2140       g_free (data);
2141     }
2142 }
2143
2144 static gint
2145 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
2146                          GdkEvent  *event)
2147 {
2148   GSList *slist;
2149   gint return_val = FALSE;
2150
2151   slist = key_snoopers;
2152   while (slist && !return_val)
2153     {
2154       GtkKeySnooperData *data;
2155
2156       data = slist->data;
2157       slist = slist->next;
2158       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
2159     }
2160
2161   return return_val;
2162 }
2163
2164 guint
2165 gtk_quit_add_full (guint                main_level,
2166                    GtkFunction          function,
2167                    GtkCallbackMarshal   marshal,
2168                    gpointer             data,
2169                    GDestroyNotify       destroy)
2170 {
2171   static guint quit_id = 1;
2172   GtkQuitFunction *quitf;
2173   
2174   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
2175
2176   quitf = g_slice_new (GtkQuitFunction);
2177   
2178   quitf->id = quit_id++;
2179   quitf->main_level = main_level;
2180   quitf->function = function;
2181   quitf->marshal = marshal;
2182   quitf->data = data;
2183   quitf->destroy = destroy;
2184
2185   quit_functions = g_list_prepend (quit_functions, quitf);
2186   
2187   return quitf->id;
2188 }
2189
2190 static void
2191 gtk_quit_destroy (GtkQuitFunction *quitf)
2192 {
2193   if (quitf->destroy)
2194     quitf->destroy (quitf->data);
2195   g_slice_free (GtkQuitFunction, quitf);
2196 }
2197
2198 static gint
2199 gtk_quit_destructor (GtkWidget **object_p)
2200 {
2201   if (*object_p)
2202     gtk_widget_destroy (*object_p);
2203   g_free (object_p);
2204
2205   return FALSE;
2206 }
2207
2208 void
2209 gtk_quit_add_destroy (guint      main_level,
2210                       GtkWidget *object)
2211 {
2212   GtkWidget **object_p;
2213
2214   g_return_if_fail (main_level > 0);
2215   g_return_if_fail (GTK_IS_WIDGET (object));
2216
2217   object_p = g_new (GtkWidget*, 1);
2218   *object_p = object;
2219   g_signal_connect (object,
2220                     "destroy",
2221                     G_CALLBACK (gtk_widget_destroyed),
2222                     object_p);
2223   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
2224 }
2225
2226 guint
2227 gtk_quit_add (guint       main_level,
2228               GtkFunction function,
2229               gpointer    data)
2230 {
2231   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
2232 }
2233
2234 void
2235 gtk_quit_remove (guint id)
2236 {
2237   GtkQuitFunction *quitf;
2238   GList *tmp_list;
2239   
2240   tmp_list = quit_functions;
2241   while (tmp_list)
2242     {
2243       quitf = tmp_list->data;
2244       
2245       if (quitf->id == id)
2246         {
2247           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2248           g_list_free (tmp_list);
2249           gtk_quit_destroy (quitf);
2250           
2251           return;
2252         }
2253       
2254       tmp_list = tmp_list->next;
2255     }
2256 }
2257
2258 void
2259 gtk_quit_remove_by_data (gpointer data)
2260 {
2261   GtkQuitFunction *quitf;
2262   GList *tmp_list;
2263   
2264   tmp_list = quit_functions;
2265   while (tmp_list)
2266     {
2267       quitf = tmp_list->data;
2268       
2269       if (quitf->data == data)
2270         {
2271           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2272           g_list_free (tmp_list);
2273           gtk_quit_destroy (quitf);
2274
2275           return;
2276         }
2277       
2278       tmp_list = tmp_list->next;
2279     }
2280 }
2281
2282 /**
2283  * gtk_get_current_event:
2284  * 
2285  * Obtains a copy of the event currently being processed by GTK+.  For
2286  * example, if you get a "clicked" signal from #GtkButton, the current
2287  * event will be the #GdkEventButton that triggered the "clicked"
2288  * signal. The returned event must be freed with gdk_event_free().
2289  * If there is no current event, the function returns %NULL.
2290  * 
2291  * Return value: a copy of the current event, or %NULL if no current event.
2292  **/
2293 GdkEvent*
2294 gtk_get_current_event (void)
2295 {
2296   if (current_events)
2297     return gdk_event_copy (current_events->data);
2298   else
2299     return NULL;
2300 }
2301
2302 /**
2303  * gtk_get_current_event_time:
2304  * 
2305  * If there is a current event and it has a timestamp, return that
2306  * timestamp, otherwise return %GDK_CURRENT_TIME.
2307  * 
2308  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2309  **/
2310 guint32
2311 gtk_get_current_event_time (void)
2312 {
2313   if (current_events)
2314     return gdk_event_get_time (current_events->data);
2315   else
2316     return GDK_CURRENT_TIME;
2317 }
2318
2319 /**
2320  * gtk_get_current_event_state:
2321  * @state: a location to store the state of the current event
2322  * 
2323  * If there is a current event and it has a state field, place
2324  * that state field in @state and return %TRUE, otherwise return
2325  * %FALSE.
2326  * 
2327  * Return value: %TRUE if there was a current event and it had a state field
2328  **/
2329 gboolean
2330 gtk_get_current_event_state (GdkModifierType *state)
2331 {
2332   g_return_val_if_fail (state != NULL, FALSE);
2333   
2334   if (current_events)
2335     return gdk_event_get_state (current_events->data, state);
2336   else
2337     {
2338       *state = 0;
2339       return FALSE;
2340     }
2341 }
2342
2343 /**
2344  * gtk_get_current_event_device:
2345  *
2346  * If there is a current event and it has a device, return that
2347  * device, otherwise return %NULL.
2348  *
2349  * Returns: (transfer none): a #GdkDevice, or %NULL
2350  **/
2351 GdkDevice *
2352 gtk_get_current_event_device (void)
2353 {
2354   if (current_events)
2355     return gdk_event_get_device (current_events->data);
2356   else
2357     return NULL;
2358 }
2359
2360 /**
2361  * gtk_get_event_widget:
2362  * @event: a #GdkEvent
2363  *
2364  * If @event is %NULL or the event was not associated with any widget,
2365  * returns %NULL, otherwise returns the widget that received the event
2366  * originally.
2367  * 
2368  * Return value: (transfer none): the widget that originally
2369  *     received @event, or %NULL
2370  **/
2371 GtkWidget*
2372 gtk_get_event_widget (GdkEvent *event)
2373 {
2374   GtkWidget *widget;
2375   gpointer widget_ptr;
2376
2377   widget = NULL;
2378   if (event && event->any.window && 
2379       (event->type == GDK_DESTROY || !gdk_window_is_destroyed (event->any.window)))
2380     {
2381       gdk_window_get_user_data (event->any.window, &widget_ptr);
2382       widget = widget_ptr;
2383     }
2384   
2385   return widget;
2386 }
2387
2388 static gint
2389 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2390 {
2391   if (!quitf->marshal)
2392     return quitf->function (quitf->data);
2393   else
2394     {
2395       GtkArg args[1];
2396       gint ret_val = FALSE;
2397
2398       args[0].name = NULL;
2399       args[0].type = G_TYPE_BOOLEAN;
2400       args[0].d.pointer_data = &ret_val;
2401       ((GtkCallbackMarshal) quitf->marshal) (NULL,
2402                                              quitf->data,
2403                                              0, args);
2404       return ret_val;
2405     }
2406 }
2407
2408 /**
2409  * gtk_propagate_event:
2410  * @widget: a #GtkWidget
2411  * @event: an event
2412  *
2413  * Sends an event to a widget, propagating the event to parent widgets
2414  * if the event remains unhandled. Events received by GTK+ from GDK
2415  * normally begin in gtk_main_do_event(). Depending on the type of
2416  * event, existence of modal dialogs, grabs, etc., the event may be
2417  * propagated; if so, this function is used. gtk_propagate_event()
2418  * calls gtk_widget_event() on each widget it decides to send the
2419  * event to.  So gtk_widget_event() is the lowest-level function; it
2420  * simply emits the "event" and possibly an event-specific signal on a
2421  * widget.  gtk_propagate_event() is a bit higher-level, and
2422  * gtk_main_do_event() is the highest level.
2423  *
2424  * All that said, you most likely don't want to use any of these
2425  * functions; synthesizing events is rarely needed. Consider asking on
2426  * the mailing list for better ways to achieve your goals. For
2427  * example, use gdk_window_invalidate_rect() or
2428  * gtk_widget_queue_draw() instead of making up expose events.
2429  * 
2430  **/
2431 void
2432 gtk_propagate_event (GtkWidget *widget,
2433                      GdkEvent  *event)
2434 {
2435   gint handled_event;
2436   
2437   g_return_if_fail (GTK_IS_WIDGET (widget));
2438   g_return_if_fail (event != NULL);
2439   
2440   handled_event = FALSE;
2441
2442   g_object_ref (widget);
2443       
2444   if ((event->type == GDK_KEY_PRESS) ||
2445       (event->type == GDK_KEY_RELEASE))
2446     {
2447       /* Only send key events within Window widgets to the Window
2448        *  The Window widget will in turn pass the
2449        *  key event on to the currently focused widget
2450        *  for that window.
2451        */
2452       GtkWidget *window;
2453
2454       window = gtk_widget_get_toplevel (widget);
2455       if (GTK_IS_WINDOW (window))
2456         {
2457           /* If there is a grab within the window, give the grab widget
2458            * a first crack at the key event
2459            */
2460           if (widget != window && gtk_widget_has_grab (widget))
2461             handled_event = gtk_widget_event (widget, event);
2462           
2463           if (!handled_event)
2464             {
2465               window = gtk_widget_get_toplevel (widget);
2466               if (GTK_IS_WINDOW (window))
2467                 {
2468                   if (gtk_widget_is_sensitive (window))
2469                     gtk_widget_event (window, event);
2470                 }
2471             }
2472                   
2473           handled_event = TRUE; /* don't send to widget */
2474         }
2475     }
2476   
2477   /* Other events get propagated up the widget tree
2478    *  so that parents can see the button and motion
2479    *  events of the children.
2480    */
2481   if (!handled_event)
2482     {
2483       while (TRUE)
2484         {
2485           GtkWidget *tmp;
2486
2487           /* Scroll events are special cased here because it
2488            * feels wrong when scrolling a GtkViewport, say,
2489            * to have children of the viewport eat the scroll
2490            * event
2491            */
2492           if (!gtk_widget_is_sensitive (widget))
2493             handled_event = event->type != GDK_SCROLL;
2494           else
2495             handled_event = gtk_widget_event (widget, event);
2496
2497           tmp = gtk_widget_get_parent (widget);
2498           g_object_unref (widget);
2499
2500           widget = tmp;
2501           
2502           if (!handled_event && widget)
2503             g_object_ref (widget);
2504           else
2505             break;
2506         }
2507     }
2508   else
2509     g_object_unref (widget);
2510 }
2511
2512 gboolean
2513 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2514                                   GValue                *return_accu,
2515                                   const GValue          *handler_return,
2516                                   gpointer               dummy)
2517 {
2518   gboolean continue_emission;
2519   gboolean signal_handled;
2520   
2521   signal_handled = g_value_get_boolean (handler_return);
2522   g_value_set_boolean (return_accu, signal_handled);
2523   continue_emission = !signal_handled;
2524   
2525   return continue_emission;
2526 }