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