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