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