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