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