]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
Make GTK+ device grabs take precedence over GTK+ grabs
[~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 (gint                 *argc,
825                     gchar              ***argv,
826                     const gchar          *parameter_string,
827                     const GOptionEntry   *entries,
828                     const gchar          *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   /* check whether there is a (device) grab in effect...
1470    */
1471   if (device)
1472     grab_widget = gtk_window_group_get_current_device_grab (window_group, device);
1473
1474   if (!grab_widget && window_group->grabs)
1475     grab_widget = window_group->grabs->data;
1476
1477   /* If the grab widget is an ancestor of the event widget
1478    *  then we send the event to the original event widget.
1479    *  This is the key to implementing modality.
1480    */
1481   if (!grab_widget ||
1482       (gtk_widget_is_sensitive (event_widget) &&
1483        gtk_widget_is_ancestor (event_widget, grab_widget)))
1484     grab_widget = event_widget;
1485
1486   /* If the widget receiving events is actually blocked by another device GTK+ grab */
1487   if (device &&
1488       _gtk_window_group_widget_is_blocked_for_device (window_group, grab_widget, device))
1489     {
1490       if (rewritten_event)
1491         gdk_event_free (rewritten_event);
1492
1493       return;
1494     }
1495
1496   /* Push the event onto a stack of current events for
1497    * gtk_current_event_get().
1498    */
1499   current_events = g_list_prepend (current_events, event);
1500
1501   /* Not all events get sent to the grabbing widget.
1502    * The delete, destroy, expose, focus change and resize
1503    *  events still get sent to the event widget because
1504    *  1) these events have no meaning for the grabbing widget
1505    *  and 2) redirecting these events to the grabbing widget
1506    *  could cause the display to be messed up.
1507    * 
1508    * Drag events are also not redirected, since it isn't
1509    *  clear what the semantics of that would be.
1510    */
1511   switch (event->type)
1512     {
1513     case GDK_NOTHING:
1514       break;
1515       
1516     case GDK_DELETE:
1517       g_object_ref (event_widget);
1518       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1519           !gtk_widget_event (event_widget, event))
1520         gtk_widget_destroy (event_widget);
1521       g_object_unref (event_widget);
1522       break;
1523       
1524     case GDK_DESTROY:
1525       /* Unexpected GDK_DESTROY from the outside, ignore for
1526        * child windows, handle like a GDK_DELETE for toplevels
1527        */
1528       if (!event_widget->parent)
1529         {
1530           g_object_ref (event_widget);
1531           if (!gtk_widget_event (event_widget, event) &&
1532               gtk_widget_get_realized (event_widget))
1533             gtk_widget_destroy (event_widget);
1534           g_object_unref (event_widget);
1535         }
1536       break;
1537       
1538     case GDK_EXPOSE:
1539       if (event->any.window && gtk_widget_get_double_buffered (event_widget))
1540         {
1541           gdk_window_begin_paint_region (event->any.window, event->expose.region);
1542           gtk_widget_send_expose (event_widget, event);
1543           gdk_window_end_paint (event->any.window);
1544         }
1545       else
1546         {
1547           /* The app may paint with a previously allocated cairo_t,
1548              which will draw directly to the window. We can't catch cairo
1549              drap operatoins to automatically flush the window, thus we
1550              need to explicitly flush any outstanding moves or double
1551              buffering */
1552           gdk_window_flush (event->any.window);
1553           gtk_widget_send_expose (event_widget, event);
1554         }
1555       break;
1556
1557     case GDK_PROPERTY_NOTIFY:
1558     case GDK_NO_EXPOSE:
1559     case GDK_FOCUS_CHANGE:
1560     case GDK_CONFIGURE:
1561     case GDK_MAP:
1562     case GDK_UNMAP:
1563     case GDK_SELECTION_CLEAR:
1564     case GDK_SELECTION_REQUEST:
1565     case GDK_SELECTION_NOTIFY:
1566     case GDK_CLIENT_EVENT:
1567     case GDK_VISIBILITY_NOTIFY:
1568     case GDK_WINDOW_STATE:
1569     case GDK_GRAB_BROKEN:
1570     case GDK_DAMAGE:
1571       gtk_widget_event (event_widget, event);
1572       break;
1573
1574     case GDK_SCROLL:
1575     case GDK_BUTTON_PRESS:
1576     case GDK_2BUTTON_PRESS:
1577     case GDK_3BUTTON_PRESS:
1578       gtk_propagate_event (grab_widget, event);
1579       break;
1580
1581     case GDK_KEY_PRESS:
1582     case GDK_KEY_RELEASE:
1583       if (key_snoopers)
1584         {
1585           if (gtk_invoke_key_snoopers (grab_widget, event))
1586             break;
1587         }
1588       /* Catch alt press to enable auto-mnemonics;
1589        * menus are handled elsewhere
1590        */
1591       if ((event->key.keyval == GDK_Alt_L || event->key.keyval == GDK_Alt_R) &&
1592           !GTK_IS_MENU_SHELL (grab_widget))
1593         {
1594           gboolean auto_mnemonics;
1595
1596           g_object_get (gtk_widget_get_settings (grab_widget),
1597                         "gtk-auto-mnemonics", &auto_mnemonics, NULL);
1598
1599           if (auto_mnemonics)
1600             {
1601               gboolean mnemonics_visible;
1602               GtkWidget *window;
1603
1604               mnemonics_visible = (event->type == GDK_KEY_PRESS);
1605
1606               window = gtk_widget_get_toplevel (grab_widget);
1607
1608               if (GTK_IS_WINDOW (window))
1609                 gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
1610             }
1611         }
1612       /* else fall through */
1613     case GDK_MOTION_NOTIFY:
1614     case GDK_BUTTON_RELEASE:
1615     case GDK_PROXIMITY_IN:
1616     case GDK_PROXIMITY_OUT:
1617       gtk_propagate_event (grab_widget, event);
1618       break;
1619       
1620     case GDK_ENTER_NOTIFY:
1621       _gtk_widget_set_device_window (event_widget,
1622                                      gdk_event_get_device (event),
1623                                      event->any.window);
1624       if (gtk_widget_is_sensitive (grab_widget))
1625         gtk_widget_event (grab_widget, event);
1626       break;
1627       
1628     case GDK_LEAVE_NOTIFY:
1629       _gtk_widget_set_device_window (event_widget,
1630                                      gdk_event_get_device (event),
1631                                      NULL);
1632       if (gtk_widget_is_sensitive (grab_widget))
1633         gtk_widget_event (grab_widget, event);
1634       break;
1635       
1636     case GDK_DRAG_STATUS:
1637     case GDK_DROP_FINISHED:
1638       _gtk_drag_source_handle_event (event_widget, event);
1639       break;
1640     case GDK_DRAG_ENTER:
1641     case GDK_DRAG_LEAVE:
1642     case GDK_DRAG_MOTION:
1643     case GDK_DROP_START:
1644       _gtk_drag_dest_handle_event (event_widget, event);
1645       break;
1646     default:
1647       g_assert_not_reached ();
1648       break;
1649     }
1650
1651   if (event->type == GDK_ENTER_NOTIFY
1652       || event->type == GDK_LEAVE_NOTIFY
1653       || event->type == GDK_BUTTON_PRESS
1654       || event->type == GDK_2BUTTON_PRESS
1655       || event->type == GDK_3BUTTON_PRESS
1656       || event->type == GDK_KEY_PRESS
1657       || event->type == GDK_DRAG_ENTER
1658       || event->type == GDK_GRAB_BROKEN
1659       || event->type == GDK_MOTION_NOTIFY
1660       || event->type == GDK_SCROLL)
1661     {
1662       _gtk_tooltip_handle_event (event);
1663     }
1664   
1665   tmp_list = current_events;
1666   current_events = g_list_remove_link (current_events, tmp_list);
1667   g_list_free_1 (tmp_list);
1668
1669   if (rewritten_event)
1670     gdk_event_free (rewritten_event);
1671 }
1672
1673 gboolean
1674 gtk_true (void)
1675 {
1676   return TRUE;
1677 }
1678
1679 gboolean
1680 gtk_false (void)
1681 {
1682   return FALSE;
1683 }
1684
1685 static GtkWindowGroup *
1686 gtk_main_get_window_group (GtkWidget   *widget)
1687 {
1688   GtkWidget *toplevel = NULL;
1689
1690   if (widget)
1691     toplevel = gtk_widget_get_toplevel (widget);
1692
1693   if (GTK_IS_WINDOW (toplevel))
1694     return gtk_window_get_group (GTK_WINDOW (toplevel));
1695   else
1696     return gtk_window_get_group (NULL);
1697 }
1698
1699 typedef struct
1700 {
1701   GtkWidget *old_grab_widget;
1702   GtkWidget *new_grab_widget;
1703   gboolean   was_grabbed;
1704   gboolean   is_grabbed;
1705   gboolean   from_grab;
1706   GList     *notified_windows;
1707   GdkDevice *device;
1708 } GrabNotifyInfo;
1709
1710 static void
1711 synth_crossing_for_grab_notify (GtkWidget       *from,
1712                                 GtkWidget       *to,
1713                                 GrabNotifyInfo  *info,
1714                                 GList           *devices,
1715                                 GdkCrossingMode  mode)
1716 {
1717   while (devices)
1718     {
1719       GdkDevice *device = devices->data;
1720       GdkWindow *from_window, *to_window;
1721
1722       /* Do not propagate events more than once to
1723        * the same windows if non-multidevice aware.
1724        */
1725       if (!from)
1726         from_window = NULL;
1727       else
1728         {
1729           from_window = _gtk_widget_get_device_window (from, device);
1730
1731           if (from_window &&
1732               !gdk_window_get_support_multidevice (from_window) &&
1733               g_list_find (info->notified_windows, from_window))
1734             from_window = NULL;
1735         }
1736
1737       if (!to)
1738         to_window = NULL;
1739       else
1740         {
1741           to_window = _gtk_widget_get_device_window (to, device);
1742
1743           if (to_window &&
1744               !gdk_window_get_support_multidevice (to_window) &&
1745               g_list_find (info->notified_windows, to_window))
1746             to_window = NULL;
1747         }
1748
1749       if (from_window || to_window)
1750         {
1751           _gtk_widget_synthesize_crossing ((from_window) ? from : NULL,
1752                                            (to_window) ? to : NULL,
1753                                            device, mode);
1754
1755           if (from_window)
1756             info->notified_windows = g_list_prepend (info->notified_windows, from_window);
1757
1758           if (to_window)
1759             info->notified_windows = g_list_prepend (info->notified_windows, to_window);
1760         }
1761
1762       devices = devices->next;
1763     }
1764 }
1765
1766 static void
1767 gtk_grab_notify_foreach (GtkWidget *child,
1768                          gpointer   data)
1769 {
1770   GrabNotifyInfo *info = data;
1771   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1772   GList *devices;
1773
1774   was_grabbed = info->was_grabbed;
1775   is_grabbed = info->is_grabbed;
1776
1777   info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1778   info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1779
1780   was_shadowed = info->old_grab_widget && !info->was_grabbed;
1781   is_shadowed = info->new_grab_widget && !info->is_grabbed;
1782
1783   g_object_ref (child);
1784
1785   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1786     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1787
1788   if (info->device &&
1789       _gtk_widget_get_device_window (child, info->device))
1790     {
1791       /* Device specified and is on widget */
1792       devices = g_list_prepend (NULL, info->device);
1793     }
1794   else
1795     devices = _gtk_widget_list_devices (child);
1796
1797   if (is_shadowed)
1798     {
1799       GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
1800       if (!was_shadowed && devices &&
1801           gtk_widget_is_sensitive (child))
1802         synth_crossing_for_grab_notify (child, info->new_grab_widget,
1803                                         info, devices,
1804                                         GDK_CROSSING_GTK_GRAB);
1805     }
1806   else
1807     {
1808       GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
1809       if (was_shadowed && devices &&
1810           gtk_widget_is_sensitive (child))
1811         synth_crossing_for_grab_notify (info->old_grab_widget, child,
1812                                         info, devices,
1813                                         info->from_grab ? GDK_CROSSING_GTK_GRAB :
1814                                         GDK_CROSSING_GTK_UNGRAB);
1815     }
1816
1817   if (was_shadowed != is_shadowed)
1818     _gtk_widget_grab_notify (child, was_shadowed);
1819
1820   g_object_unref (child);
1821   g_list_free (devices);
1822
1823   info->was_grabbed = was_grabbed;
1824   info->is_grabbed = is_grabbed;
1825 }
1826
1827 static void
1828 gtk_grab_notify (GtkWindowGroup *group,
1829                  GdkDevice      *device,
1830                  GtkWidget      *old_grab_widget,
1831                  GtkWidget      *new_grab_widget,
1832                  gboolean        from_grab)
1833 {
1834   GList *toplevels;
1835   GrabNotifyInfo info = { 0 };
1836
1837   if (old_grab_widget == new_grab_widget)
1838     return;
1839
1840   info.old_grab_widget = old_grab_widget;
1841   info.new_grab_widget = new_grab_widget;
1842   info.from_grab = from_grab;
1843   info.device = device;
1844
1845   g_object_ref (group);
1846
1847   toplevels = gtk_window_list_toplevels ();
1848   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1849
1850   while (toplevels)
1851     {
1852       GtkWindow *toplevel = toplevels->data;
1853       toplevels = g_list_delete_link (toplevels, toplevels);
1854
1855       info.was_grabbed = FALSE;
1856       info.is_grabbed = FALSE;
1857
1858       if (group == gtk_window_get_group (toplevel))
1859         gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1860       g_object_unref (toplevel);
1861     }
1862
1863   g_list_free (info.notified_windows);
1864   g_object_unref (group);
1865 }
1866
1867 void
1868 gtk_grab_add (GtkWidget *widget)
1869 {
1870   GtkWindowGroup *group;
1871   GtkWidget *old_grab_widget;
1872   
1873   g_return_if_fail (widget != NULL);
1874   
1875   if (!gtk_widget_has_grab (widget) && gtk_widget_is_sensitive (widget))
1876     {
1877       _gtk_widget_set_has_grab (widget, TRUE);
1878       
1879       group = gtk_main_get_window_group (widget);
1880
1881       if (group->grabs)
1882         old_grab_widget = (GtkWidget *)group->grabs->data;
1883       else
1884         old_grab_widget = NULL;
1885
1886       g_object_ref (widget);
1887       group->grabs = g_slist_prepend (group->grabs, widget);
1888
1889       gtk_grab_notify (group, NULL, old_grab_widget, widget, TRUE);
1890     }
1891 }
1892
1893 GtkWidget*
1894 gtk_grab_get_current (void)
1895 {
1896   GtkWindowGroup *group;
1897
1898   group = gtk_main_get_window_group (NULL);
1899
1900   if (group->grabs)
1901     return GTK_WIDGET (group->grabs->data);
1902   return NULL;
1903 }
1904
1905 void
1906 gtk_grab_remove (GtkWidget *widget)
1907 {
1908   GtkWindowGroup *group;
1909   GtkWidget *new_grab_widget;
1910   
1911   g_return_if_fail (widget != NULL);
1912   
1913   if (gtk_widget_has_grab (widget))
1914     {
1915       _gtk_widget_set_has_grab (widget, FALSE);
1916
1917       group = gtk_main_get_window_group (widget);
1918       group->grabs = g_slist_remove (group->grabs, widget);
1919       
1920       if (group->grabs)
1921         new_grab_widget = (GtkWidget *)group->grabs->data;
1922       else
1923         new_grab_widget = NULL;
1924
1925       gtk_grab_notify (group, NULL, widget, new_grab_widget, FALSE);
1926       
1927       g_object_unref (widget);
1928     }
1929 }
1930
1931 /**
1932  * gtk_device_grab_add:
1933  * @widget: a #GtkWidget
1934  * @device: a #GtkDevice to grab on.
1935  * @block_others: %TRUE to prevent other devices to interact with @widget.
1936  *
1937  * Adds a GTK+ grab on @device, so all the events on @device and its
1938  * associated pointer or keyboard (if any) are delivered to @widget.
1939  * If the @block_others parameter is %TRUE, any other devices will be
1940  * unable to interact with @widget during the grab.
1941  *
1942  * Since: 3.0
1943  **/
1944 void
1945 gtk_device_grab_add (GtkWidget        *widget,
1946                      GdkDevice        *device,
1947                      gboolean          block_others)
1948 {
1949   GtkWindowGroup *group;
1950   GtkWidget *old_grab_widget;
1951
1952   g_return_if_fail (GTK_IS_WIDGET (widget));
1953   g_return_if_fail (GDK_IS_DEVICE (device));
1954
1955   group = gtk_main_get_window_group (widget);
1956   old_grab_widget = gtk_window_group_get_current_device_grab (group, device);
1957
1958   if (old_grab_widget != widget)
1959     _gtk_window_group_add_device_grab (group, widget, device, block_others);
1960
1961   gtk_grab_notify (group, device, old_grab_widget, widget, TRUE);
1962 }
1963
1964 /**
1965  * gtk_device_grab_remove:
1966  * @widget: a #GtkWidget
1967  * @device: a #GdkDevice
1968  *
1969  * Removes a device grab from the given widget. You have to pair calls
1970  * to gtk_device_grab_add() and gtk_device_grab_remove().
1971  *
1972  * Since: 3.0
1973  **/
1974 void
1975 gtk_device_grab_remove (GtkWidget *widget,
1976                         GdkDevice *device)
1977 {
1978   GtkWindowGroup *group;
1979   GtkWidget *new_grab_widget;
1980
1981   g_return_if_fail (GTK_IS_WIDGET (widget));
1982   g_return_if_fail (GDK_IS_DEVICE (device));
1983
1984   group = gtk_main_get_window_group (widget);
1985   _gtk_window_group_remove_device_grab (group, widget, device);
1986   new_grab_widget = gtk_window_group_get_current_device_grab (group, device);
1987
1988   gtk_grab_notify (group, device, widget, new_grab_widget, FALSE);
1989 }
1990
1991 void
1992 gtk_init_add (GtkFunction function,
1993               gpointer    data)
1994 {
1995   GtkInitFunction *init;
1996   
1997   init = g_new (GtkInitFunction, 1);
1998   init->function = function;
1999   init->data = data;
2000   
2001   init_functions = g_list_prepend (init_functions, init);
2002 }
2003
2004 guint
2005 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
2006                          gpointer        func_data)
2007 {
2008   GtkKeySnooperData *data;
2009   static guint snooper_id = 1;
2010
2011   g_return_val_if_fail (snooper != NULL, 0);
2012
2013   data = g_new (GtkKeySnooperData, 1);
2014   data->func = snooper;
2015   data->func_data = func_data;
2016   data->id = snooper_id++;
2017   key_snoopers = g_slist_prepend (key_snoopers, data);
2018
2019   return data->id;
2020 }
2021
2022 void
2023 gtk_key_snooper_remove (guint snooper_id)
2024 {
2025   GtkKeySnooperData *data = NULL;
2026   GSList *slist;
2027
2028   slist = key_snoopers;
2029   while (slist)
2030     {
2031       data = slist->data;
2032       if (data->id == snooper_id)
2033         break;
2034
2035       slist = slist->next;
2036       data = NULL;
2037     }
2038   if (data)
2039     {
2040       key_snoopers = g_slist_remove (key_snoopers, data);
2041       g_free (data);
2042     }
2043 }
2044
2045 static gint
2046 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
2047                          GdkEvent  *event)
2048 {
2049   GSList *slist;
2050   gint return_val = FALSE;
2051
2052   slist = key_snoopers;
2053   while (slist && !return_val)
2054     {
2055       GtkKeySnooperData *data;
2056
2057       data = slist->data;
2058       slist = slist->next;
2059       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
2060     }
2061
2062   return return_val;
2063 }
2064
2065 guint
2066 gtk_quit_add_full (guint                main_level,
2067                    GtkFunction          function,
2068                    GtkCallbackMarshal   marshal,
2069                    gpointer             data,
2070                    GDestroyNotify       destroy)
2071 {
2072   static guint quit_id = 1;
2073   GtkQuitFunction *quitf;
2074   
2075   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
2076
2077   quitf = g_slice_new (GtkQuitFunction);
2078   
2079   quitf->id = quit_id++;
2080   quitf->main_level = main_level;
2081   quitf->function = function;
2082   quitf->marshal = marshal;
2083   quitf->data = data;
2084   quitf->destroy = destroy;
2085
2086   quit_functions = g_list_prepend (quit_functions, quitf);
2087   
2088   return quitf->id;
2089 }
2090
2091 static void
2092 gtk_quit_destroy (GtkQuitFunction *quitf)
2093 {
2094   if (quitf->destroy)
2095     quitf->destroy (quitf->data);
2096   g_slice_free (GtkQuitFunction, quitf);
2097 }
2098
2099 static gint
2100 gtk_quit_destructor (GtkObject **object_p)
2101 {
2102   if (*object_p)
2103     gtk_object_destroy (*object_p);
2104   g_free (object_p);
2105
2106   return FALSE;
2107 }
2108
2109 void
2110 gtk_quit_add_destroy (guint              main_level,
2111                       GtkObject         *object)
2112 {
2113   GtkObject **object_p;
2114
2115   g_return_if_fail (main_level > 0);
2116   g_return_if_fail (GTK_IS_OBJECT (object));
2117
2118   object_p = g_new (GtkObject*, 1);
2119   *object_p = object;
2120   g_signal_connect (object,
2121                     "destroy",
2122                     G_CALLBACK (gtk_widget_destroyed),
2123                     object_p);
2124   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
2125 }
2126
2127 guint
2128 gtk_quit_add (guint       main_level,
2129               GtkFunction function,
2130               gpointer    data)
2131 {
2132   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
2133 }
2134
2135 void
2136 gtk_quit_remove (guint id)
2137 {
2138   GtkQuitFunction *quitf;
2139   GList *tmp_list;
2140   
2141   tmp_list = quit_functions;
2142   while (tmp_list)
2143     {
2144       quitf = tmp_list->data;
2145       
2146       if (quitf->id == id)
2147         {
2148           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2149           g_list_free (tmp_list);
2150           gtk_quit_destroy (quitf);
2151           
2152           return;
2153         }
2154       
2155       tmp_list = tmp_list->next;
2156     }
2157 }
2158
2159 void
2160 gtk_quit_remove_by_data (gpointer data)
2161 {
2162   GtkQuitFunction *quitf;
2163   GList *tmp_list;
2164   
2165   tmp_list = quit_functions;
2166   while (tmp_list)
2167     {
2168       quitf = tmp_list->data;
2169       
2170       if (quitf->data == data)
2171         {
2172           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2173           g_list_free (tmp_list);
2174           gtk_quit_destroy (quitf);
2175
2176           return;
2177         }
2178       
2179       tmp_list = tmp_list->next;
2180     }
2181 }
2182
2183 /**
2184  * gtk_get_current_event:
2185  * 
2186  * Obtains a copy of the event currently being processed by GTK+.  For
2187  * example, if you get a "clicked" signal from #GtkButton, the current
2188  * event will be the #GdkEventButton that triggered the "clicked"
2189  * signal. The returned event must be freed with gdk_event_free().
2190  * If there is no current event, the function returns %NULL.
2191  * 
2192  * Return value: a copy of the current event, or %NULL if no current event.
2193  **/
2194 GdkEvent*
2195 gtk_get_current_event (void)
2196 {
2197   if (current_events)
2198     return gdk_event_copy (current_events->data);
2199   else
2200     return NULL;
2201 }
2202
2203 /**
2204  * gtk_get_current_event_time:
2205  * 
2206  * If there is a current event and it has a timestamp, return that
2207  * timestamp, otherwise return %GDK_CURRENT_TIME.
2208  * 
2209  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2210  **/
2211 guint32
2212 gtk_get_current_event_time (void)
2213 {
2214   if (current_events)
2215     return gdk_event_get_time (current_events->data);
2216   else
2217     return GDK_CURRENT_TIME;
2218 }
2219
2220 /**
2221  * gtk_get_current_event_state:
2222  * @state: a location to store the state of the current event
2223  * 
2224  * If there is a current event and it has a state field, place
2225  * that state field in @state and return %TRUE, otherwise return
2226  * %FALSE.
2227  * 
2228  * Return value: %TRUE if there was a current event and it had a state field
2229  **/
2230 gboolean
2231 gtk_get_current_event_state (GdkModifierType *state)
2232 {
2233   g_return_val_if_fail (state != NULL, FALSE);
2234   
2235   if (current_events)
2236     return gdk_event_get_state (current_events->data, state);
2237   else
2238     {
2239       *state = 0;
2240       return FALSE;
2241     }
2242 }
2243
2244 /**
2245  * gtk_get_current_event_device:
2246  *
2247  * If there is a current event and it has a device, return that
2248  * device, otherwise return %NULL.
2249  *
2250  * Returns: a #GdkDevice, or %NULL
2251  **/
2252 GdkDevice *
2253 gtk_get_current_event_device (void)
2254 {
2255   if (current_events)
2256     return gdk_event_get_device (current_events->data);
2257   else
2258     return NULL;
2259 }
2260
2261 /**
2262  * gtk_get_event_widget:
2263  * @event: a #GdkEvent
2264  *
2265  * If @event is %NULL or the event was not associated with any widget,
2266  * returns %NULL, otherwise returns the widget that received the event
2267  * originally.
2268  * 
2269  * Return value: the widget that originally received @event, or %NULL
2270  **/
2271 GtkWidget*
2272 gtk_get_event_widget (GdkEvent *event)
2273 {
2274   GtkWidget *widget;
2275   gpointer widget_ptr;
2276
2277   widget = NULL;
2278   if (event && event->any.window && 
2279       (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
2280     {
2281       gdk_window_get_user_data (event->any.window, &widget_ptr);
2282       widget = widget_ptr;
2283     }
2284   
2285   return widget;
2286 }
2287
2288 static gint
2289 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2290 {
2291   if (!quitf->marshal)
2292     return quitf->function (quitf->data);
2293   else
2294     {
2295       GtkArg args[1];
2296       gint ret_val = FALSE;
2297
2298       args[0].name = NULL;
2299       args[0].type = G_TYPE_BOOLEAN;
2300       args[0].d.pointer_data = &ret_val;
2301       ((GtkCallbackMarshal) quitf->marshal) (NULL,
2302                                              quitf->data,
2303                                              0, args);
2304       return ret_val;
2305     }
2306 }
2307
2308 /**
2309  * gtk_propagate_event:
2310  * @widget: a #GtkWidget
2311  * @event: an event
2312  *
2313  * Sends an event to a widget, propagating the event to parent widgets
2314  * if the event remains unhandled. Events received by GTK+ from GDK
2315  * normally begin in gtk_main_do_event(). Depending on the type of
2316  * event, existence of modal dialogs, grabs, etc., the event may be
2317  * propagated; if so, this function is used. gtk_propagate_event()
2318  * calls gtk_widget_event() on each widget it decides to send the
2319  * event to.  So gtk_widget_event() is the lowest-level function; it
2320  * simply emits the "event" and possibly an event-specific signal on a
2321  * widget.  gtk_propagate_event() is a bit higher-level, and
2322  * gtk_main_do_event() is the highest level.
2323  *
2324  * All that said, you most likely don't want to use any of these
2325  * functions; synthesizing events is rarely needed. Consider asking on
2326  * the mailing list for better ways to achieve your goals. For
2327  * example, use gdk_window_invalidate_rect() or
2328  * gtk_widget_queue_draw() instead of making up expose events.
2329  * 
2330  **/
2331 void
2332 gtk_propagate_event (GtkWidget *widget,
2333                      GdkEvent  *event)
2334 {
2335   gint handled_event;
2336   
2337   g_return_if_fail (GTK_IS_WIDGET (widget));
2338   g_return_if_fail (event != NULL);
2339   
2340   handled_event = FALSE;
2341
2342   g_object_ref (widget);
2343       
2344   if ((event->type == GDK_KEY_PRESS) ||
2345       (event->type == GDK_KEY_RELEASE))
2346     {
2347       /* Only send key events within Window widgets to the Window
2348        *  The Window widget will in turn pass the
2349        *  key event on to the currently focused widget
2350        *  for that window.
2351        */
2352       GtkWidget *window;
2353
2354       window = gtk_widget_get_toplevel (widget);
2355       if (GTK_IS_WINDOW (window))
2356         {
2357           /* If there is a grab within the window, give the grab widget
2358            * a first crack at the key event
2359            */
2360           if (widget != window && gtk_widget_has_grab (widget))
2361             handled_event = gtk_widget_event (widget, event);
2362           
2363           if (!handled_event)
2364             {
2365               window = gtk_widget_get_toplevel (widget);
2366               if (GTK_IS_WINDOW (window))
2367                 {
2368                   if (gtk_widget_is_sensitive (window))
2369                     gtk_widget_event (window, event);
2370                 }
2371             }
2372                   
2373           handled_event = TRUE; /* don't send to widget */
2374         }
2375     }
2376   
2377   /* Other events get propagated up the widget tree
2378    *  so that parents can see the button and motion
2379    *  events of the children.
2380    */
2381   if (!handled_event)
2382     {
2383       while (TRUE)
2384         {
2385           GtkWidget *tmp;
2386
2387           /* Scroll events are special cased here because it
2388            * feels wrong when scrolling a GtkViewport, say,
2389            * to have children of the viewport eat the scroll
2390            * event
2391            */
2392           if (!gtk_widget_is_sensitive (widget))
2393             handled_event = event->type != GDK_SCROLL;
2394           else
2395             handled_event = gtk_widget_event (widget, event);
2396               
2397           tmp = widget->parent;
2398           g_object_unref (widget);
2399
2400           widget = tmp;
2401           
2402           if (!handled_event && widget)
2403             g_object_ref (widget);
2404           else
2405             break;
2406         }
2407     }
2408   else
2409     g_object_unref (widget);
2410 }
2411
2412 gboolean
2413 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2414                                   GValue                *return_accu,
2415                                   const GValue          *handler_return,
2416                                   gpointer               dummy)
2417 {
2418   gboolean continue_emission;
2419   gboolean signal_handled;
2420   
2421   signal_handled = g_value_get_boolean (handler_return);
2422   g_value_set_boolean (return_accu, signal_handled);
2423   continue_emission = !signal_handled;
2424   
2425   return continue_emission;
2426 }
2427
2428 #define __GTK_MAIN_C__
2429 #include "gtkaliasdef.c"