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