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