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