]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
Add GtkSpinner::animation-duration style property
[~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   gtk_object_get_type ();
721
722   _gtk_accel_map_init ();
723   _gtk_rc_init ();
724
725   /* Set the 'initialized' flag.
726    */
727   gtk_initialized = TRUE;
728
729   /* load gtk modules */
730   if (gtk_modules_string)
731     {
732       _gtk_modules_init (argc, argv, gtk_modules_string->str);
733       g_string_free (gtk_modules_string, TRUE);
734     }
735   else
736     {
737       _gtk_modules_init (argc, argv, NULL);
738     }
739 }
740
741
742 typedef struct
743 {
744   gboolean open_default_display;
745 } OptionGroupInfo;
746
747 static gboolean
748 pre_parse_hook (GOptionContext *context,
749                 GOptionGroup   *group,
750                 gpointer        data,
751                 GError        **error)
752 {
753   do_pre_parse_initialization (NULL, NULL);
754   
755   return TRUE;
756 }
757
758 static gboolean
759 post_parse_hook (GOptionContext *context,
760                  GOptionGroup   *group,
761                  gpointer       data,
762                  GError        **error)
763 {
764   OptionGroupInfo *info = data;
765
766   
767   do_post_parse_initialization (NULL, NULL);
768   
769   if (info->open_default_display)
770     {
771       if (gdk_display_open_default_libgtk_only () == NULL)
772         {
773           const char *display_name = gdk_get_display_arg_name ();
774           g_set_error (error, 
775                        G_OPTION_ERROR, 
776                        G_OPTION_ERROR_FAILED,
777                        _("Cannot open display: %s"),
778                        display_name ? display_name : "" );
779           
780           return FALSE;
781         }
782     }
783
784   return TRUE;
785 }
786
787
788 /**
789  * gtk_get_option_group:
790  * @open_default_display: whether to open the default display 
791  *    when parsing the commandline arguments
792  * 
793  * Returns a #GOptionGroup for the commandline arguments recognized
794  * by GTK+ and GDK. You should add this group to your #GOptionContext 
795  * with g_option_context_add_group(), if you are using 
796  * g_option_context_parse() to parse your commandline arguments.
797  *
798  * Returns: a #GOptionGroup for the commandline arguments recognized
799  *   by GTK+
800  *
801  * Since: 2.6
802  */
803 GOptionGroup *
804 gtk_get_option_group (gboolean open_default_display)
805 {
806   GOptionGroup *group;
807   OptionGroupInfo *info;
808
809   gettext_initialization ();
810
811   info = g_new0 (OptionGroupInfo, 1);
812   info->open_default_display = open_default_display;
813   
814   group = g_option_group_new ("gtk", _("GTK+ Options"), _("Show GTK+ Options"), info, g_free);
815   g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
816
817   gdk_add_option_entries_libgtk_only (group);
818   g_option_group_add_entries (group, gtk_args);
819   g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
820   
821   return group;
822 }
823
824 /**
825  * gtk_init_with_args:
826  * @argc: a pointer to the number of command line arguments.
827  * @argv: a pointer to the array of command line arguments.
828  * @parameter_string: a string which is displayed in
829  *    the first line of <option>--help</option> output, after 
830  *    <literal><replaceable>programname</replaceable> [OPTION...]</literal>
831  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
832  *    describing the options of your program
833  * @translation_domain: a translation domain to use for translating
834  *    the <option>--help</option> output for the options in @entries
835  *    with gettext(), or %NULL
836  * @error: a return location for errors 
837  *
838  * This function does the same work as gtk_init_check(). 
839  * Additionally, it allows you to add your own commandline options, 
840  * and it automatically generates nicely formatted 
841  * <option>--help</option> output. Note that your program will
842  * be terminated after writing out the help output.
843  *
844  * Returns: %TRUE if the GUI has been successfully initialized, 
845  *               %FALSE otherwise.
846  * 
847  * Since: 2.6
848  */
849 gboolean
850 gtk_init_with_args (int            *argc,
851                     char         ***argv,
852                     char           *parameter_string,  
853                     GOptionEntry   *entries,
854                     char           *translation_domain,
855                     GError        **error)
856 {
857   GOptionContext *context;
858   GOptionGroup *gtk_group;
859   gboolean retval;
860
861   if (gtk_initialized)
862     return gdk_display_open_default_libgtk_only () != NULL;
863
864   gettext_initialization ();
865
866   if (!check_setugid ())
867     return FALSE;
868
869   gtk_group = gtk_get_option_group (TRUE);
870   
871   context = g_option_context_new (parameter_string);
872   g_option_context_add_group (context, gtk_group);
873   
874   if (entries)
875     g_option_context_add_main_entries (context, entries, translation_domain);
876   retval = g_option_context_parse (context, argc, argv, error);
877   
878   g_option_context_free (context);
879
880   return retval;
881 }
882
883
884 /**
885  * gtk_parse_args:
886  * @argc: a pointer to the number of command line arguments.
887  * @argv: a pointer to the array of command line arguments.
888  * 
889  * Parses command line arguments, and initializes global
890  * attributes of GTK+, but does not actually open a connection
891  * to a display. (See gdk_display_open(), gdk_get_display_arg_name())
892  *
893  * Any arguments used by GTK+ or GDK are removed from the array and
894  * @argc and @argv are updated accordingly.
895  *
896  * You shouldn't call this function explicitely if you are using
897  * gtk_init(), or gtk_init_check().
898  *
899  * Return value: %TRUE if initialization succeeded, otherwise %FALSE.
900  **/
901 gboolean
902 gtk_parse_args (int    *argc,
903                 char ***argv)
904 {
905   GOptionContext *option_context;
906   GOptionGroup *gtk_group;
907   GError *error = NULL;
908   
909   if (gtk_initialized)
910     return TRUE;
911
912   gettext_initialization ();
913
914   if (!check_setugid ())
915     return FALSE;
916
917   option_context = g_option_context_new (NULL);
918   g_option_context_set_ignore_unknown_options (option_context, TRUE);
919   g_option_context_set_help_enabled (option_context, FALSE);
920   gtk_group = gtk_get_option_group (FALSE);
921   g_option_context_set_main_group (option_context, gtk_group);
922   if (!g_option_context_parse (option_context, argc, argv, &error))
923     {
924       g_warning ("%s", error->message);
925       g_error_free (error);
926     }
927
928   g_option_context_free (option_context);
929
930   return TRUE;
931 }
932
933 #ifdef G_PLATFORM_WIN32
934 #undef gtk_init_check
935 #endif
936
937 /**
938  * gtk_init_check:
939  * @argc: Address of the <parameter>argc</parameter> parameter of your 
940  *   main() function. Changed if any arguments were handled.
941  * @argv: Address of the <parameter>argv</parameter> parameter of main(). 
942  *   Any parameters understood by gtk_init() are stripped before return.
943  * 
944  * This function does the same work as gtk_init() with only 
945  * a single change: It does not terminate the program if the GUI can't be 
946  * initialized. Instead it returns %FALSE on failure.
947  *
948  * This way the application can fall back to some other means of communication 
949  * with the user - for example a curses or command line interface.
950  * 
951  * Return value: %TRUE if the GUI has been successfully initialized, 
952  *               %FALSE otherwise.
953  **/
954 gboolean
955 gtk_init_check (int      *argc,
956                 char   ***argv)
957 {
958   if (!gtk_parse_args (argc, argv))
959     return FALSE;
960
961   return gdk_display_open_default_libgtk_only () != NULL;
962 }
963
964 #ifdef G_PLATFORM_WIN32
965 #undef gtk_init
966 #endif
967
968 /**
969  * gtk_init:
970  * @argc: Address of the <parameter>argc</parameter> parameter of your 
971  *   main() function. Changed if any arguments were handled.
972  * @argv: Address of the <parameter>argv</parameter> parameter of main(). 
973  *   Any parameters understood by gtk_init() are stripped before return.
974  * 
975  * Call this function before using any other GTK+ functions in your GUI
976  * applications.  It will initialize everything needed to operate the 
977  * toolkit and parses some standard command line options. @argc and 
978  * @argv are adjusted accordingly so your own code will 
979  * never see those standard arguments. 
980  *
981  * Note that there are some alternative ways to initialize GTK+: 
982  * if you are calling gtk_parse_args(), gtk_init_check(), 
983  * gtk_init_with_args() or g_option_context_parse() with 
984  * the option group returned by gtk_get_option_group(), you 
985  * <emphasis>don't</emphasis> have to call gtk_init().
986  *
987  * <note><para>
988  * This function will terminate your program if it was unable to initialize 
989  * the GUI for some reason. If you want your program to fall back to a 
990  * textual interface you want to call gtk_init_check() instead.
991  * </para></note>
992  *
993  * <note><para>
994  * Since 2.18, GTK+ calls <literal>signal (SIGPIPE, SIG_IGN)</literal>
995  * during initialization, to ignore SIGPIPE signals, since these are
996  * almost never wanted in graphical applications. If you do need to
997  * handle SIGPIPE for some reason, reset the handler after gtk_init(),
998  * but notice that other libraries (e.g. libdbus or gvfs) might do
999  * similar things.
1000  * </para></note>
1001  **/
1002 void
1003 gtk_init (int *argc, char ***argv)
1004 {
1005   if (!gtk_init_check (argc, argv))
1006     {
1007       const char *display_name_arg = gdk_get_display_arg_name ();
1008       if (display_name_arg == NULL)
1009         display_name_arg = getenv("DISPLAY");
1010       g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
1011       exit (1);
1012     }
1013 }
1014
1015 #ifdef G_PLATFORM_WIN32
1016
1017 static void
1018 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
1019 {
1020   if (sizeof_GtkWindow != sizeof (GtkWindow))
1021     g_error ("Incompatible build!\n"
1022              "The code using GTK+ thinks GtkWindow is of different\n"
1023              "size than it actually is in this build of GTK+.\n"
1024              "On Windows, this probably means that you have compiled\n"
1025              "your code with gcc without the -mms-bitfields switch,\n"
1026              "or that you are using an unsupported compiler.");
1027 }
1028
1029 /* In GTK+ 2.0 the GtkWindow struct actually is the same size in
1030  * gcc-compiled code on Win32 whether compiled with -fnative-struct or
1031  * not. Unfortunately this wan't noticed until after GTK+ 2.0.1. So,
1032  * from GTK+ 2.0.2 on, check some other struct, too, where the use of
1033  * -fnative-struct still matters. GtkBox is one such.
1034  */
1035 static void
1036 check_sizeof_GtkBox (size_t sizeof_GtkBox)
1037 {
1038   if (sizeof_GtkBox != sizeof (GtkBox))
1039     g_error ("Incompatible build!\n"
1040              "The code using GTK+ thinks GtkBox is of different\n"
1041              "size than it actually is in this build of GTK+.\n"
1042              "On Windows, this probably means that you have compiled\n"
1043              "your code with gcc without the -mms-bitfields switch,\n"
1044              "or that you are using an unsupported compiler.");
1045 }
1046
1047 /* These two functions might get more checks added later, thus pass
1048  * in the number of extra args.
1049  */
1050 void
1051 gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1052 {
1053   check_sizeof_GtkWindow (sizeof_GtkWindow);
1054   if (num_checks >= 2)
1055     check_sizeof_GtkBox (sizeof_GtkBox);
1056   gtk_init (argc, argv);
1057 }
1058
1059 gboolean
1060 gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1061 {
1062   check_sizeof_GtkWindow (sizeof_GtkWindow);
1063   if (num_checks >= 2)
1064     check_sizeof_GtkBox (sizeof_GtkBox);
1065   return gtk_init_check (argc, argv);
1066 }
1067
1068 #endif
1069
1070 void
1071 gtk_exit (gint errorcode)
1072 {
1073   exit (errorcode);
1074 }
1075
1076
1077 /**
1078  * gtk_set_locale:
1079  *
1080  * Initializes internationalization support for GTK+. gtk_init()
1081  * automatically does this, so there is typically no point
1082  * in calling this function.
1083  *
1084  * If you are calling this function because you changed the locale
1085  * after GTK+ is was initialized, then calling this function
1086  * may help a bit. (Note, however, that changing the locale
1087  * after GTK+ is initialized may produce inconsistent results and
1088  * is not really supported.)
1089  * 
1090  * In detail - sets the current locale according to the
1091  * program environment. This is the same as calling the C library function
1092  * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the 
1093  * locale specific setup of the windowing system used by GDK.
1094  * 
1095  * Returns: a string corresponding to the locale set, typically in the
1096  * form lang_COUNTRY, where lang is an ISO-639 language code, and
1097  * COUNTRY is an ISO-3166 country code. On Unix, this form matches the
1098  * result of the setlocale(); it is also used on other machines, such as 
1099  * Windows, where the C library returns a different result. The string is 
1100  * owned by GTK+ and should not be modified or freed.
1101  **/
1102 gchar *
1103 gtk_set_locale (void)
1104 {
1105   return gdk_set_locale ();
1106 }
1107
1108 /**
1109  * _gtk_get_lc_ctype:
1110  *
1111  * Return the Unix-style locale string for the language currently in
1112  * effect. On Unix systems, this is the return value from
1113  * <literal>setlocale(LC_CTYPE, NULL)</literal>, and the user can
1114  * affect this through the environment variables LC_ALL, LC_CTYPE or
1115  * LANG (checked in that order). The locale strings typically is in
1116  * the form lang_COUNTRY, where lang is an ISO-639 language code, and
1117  * COUNTRY is an ISO-3166 country code. For instance, sv_FI for
1118  * Swedish as written in Finland or pt_BR for Portuguese as written in
1119  * Brazil.
1120  * 
1121  * On Windows, the C library doesn't use any such environment
1122  * variables, and setting them won't affect the behaviour of functions
1123  * like ctime(). The user sets the locale through the Regional Options 
1124  * in the Control Panel. The C library (in the setlocale() function) 
1125  * does not use country and language codes, but country and language 
1126  * names spelled out in English. 
1127  * However, this function does check the above environment
1128  * variables, and does return a Unix-style locale string based on
1129  * either said environment variables or the thread's current locale.
1130  *
1131  * Return value: a dynamically allocated string, free with g_free().
1132  */
1133
1134 gchar *
1135 _gtk_get_lc_ctype (void)
1136 {
1137 #ifdef G_OS_WIN32
1138   /* Somebody might try to set the locale for this process using the
1139    * LANG or LC_ environment variables. The Microsoft C library
1140    * doesn't know anything about them. You set the locale in the
1141    * Control Panel. Setting these env vars won't have any affect on
1142    * locale-dependent C library functions like ctime(). But just for
1143    * kicks, do obey LC_ALL, LC_CTYPE and LANG in GTK. (This also makes
1144    * it easier to test GTK and Pango in various default languages, you
1145    * don't have to clickety-click in the Control Panel, you can simply
1146    * start the program with LC_ALL=something on the command line.)
1147    */
1148   gchar *p;
1149
1150   p = getenv ("LC_ALL");
1151   if (p != NULL)
1152     return g_strdup (p);
1153
1154   p = getenv ("LC_CTYPE");
1155   if (p != NULL)
1156     return g_strdup (p);
1157
1158   p = getenv ("LANG");
1159   if (p != NULL)
1160     return g_strdup (p);
1161
1162   return g_win32_getlocale ();
1163 #else
1164   return g_strdup (setlocale (LC_CTYPE, NULL));
1165 #endif
1166 }
1167
1168 /**
1169  * gtk_get_default_language:
1170  *
1171  * Returns the #PangoLanguage for the default language currently in
1172  * effect. (Note that this can change over the life of an
1173  * application.)  The default language is derived from the current
1174  * locale. It determines, for example, whether GTK+ uses the
1175  * right-to-left or left-to-right text direction.
1176  *
1177  * This function is equivalent to pango_language_get_default().  See
1178  * that function for details.
1179  * 
1180  * Return value: the default language as a #PangoLanguage, must not be
1181  * freed
1182  **/
1183 PangoLanguage *
1184 gtk_get_default_language (void)
1185 {
1186   return pango_language_get_default ();
1187 }
1188
1189 void
1190 gtk_main (void)
1191 {
1192   GList *tmp_list;
1193   GList *functions;
1194   GtkInitFunction *init;
1195   GMainLoop *loop;
1196
1197   gtk_main_loop_level++;
1198   
1199   loop = g_main_loop_new (NULL, TRUE);
1200   main_loops = g_slist_prepend (main_loops, loop);
1201
1202   tmp_list = functions = init_functions;
1203   init_functions = NULL;
1204   
1205   while (tmp_list)
1206     {
1207       init = tmp_list->data;
1208       tmp_list = tmp_list->next;
1209       
1210       (* init->function) (init->data);
1211       g_free (init);
1212     }
1213   g_list_free (functions);
1214
1215   if (g_main_loop_is_running (main_loops->data))
1216     {
1217       GDK_THREADS_LEAVE ();
1218       g_main_loop_run (loop);
1219       GDK_THREADS_ENTER ();
1220       gdk_flush ();
1221     }
1222
1223   if (quit_functions)
1224     {
1225       GList *reinvoke_list = NULL;
1226       GtkQuitFunction *quitf;
1227
1228       while (quit_functions)
1229         {
1230           quitf = quit_functions->data;
1231
1232           tmp_list = quit_functions;
1233           quit_functions = g_list_remove_link (quit_functions, quit_functions);
1234           g_list_free_1 (tmp_list);
1235
1236           if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
1237               gtk_quit_invoke_function (quitf))
1238             {
1239               reinvoke_list = g_list_prepend (reinvoke_list, quitf);
1240             }
1241           else
1242             {
1243               gtk_quit_destroy (quitf);
1244             }
1245         }
1246       if (reinvoke_list)
1247         {
1248           GList *work;
1249           
1250           work = g_list_last (reinvoke_list);
1251           if (quit_functions)
1252             quit_functions->prev = work;
1253           work->next = quit_functions;
1254           quit_functions = work;
1255         }
1256
1257       gdk_flush ();
1258     }
1259     
1260   main_loops = g_slist_remove (main_loops, loop);
1261
1262   g_main_loop_unref (loop);
1263
1264   gtk_main_loop_level--;
1265
1266   if (gtk_main_loop_level == 0)
1267     {
1268       /* Try storing all clipboard data we have */
1269       _gtk_clipboard_store_all ();
1270
1271       /* Synchronize the recent manager singleton */
1272       _gtk_recent_manager_sync ();
1273     }
1274 }
1275
1276 guint
1277 gtk_main_level (void)
1278 {
1279   return gtk_main_loop_level;
1280 }
1281
1282 void
1283 gtk_main_quit (void)
1284 {
1285   g_return_if_fail (main_loops != NULL);
1286
1287   g_main_loop_quit (main_loops->data);
1288 }
1289
1290 gboolean
1291 gtk_events_pending (void)
1292 {
1293   gboolean result;
1294   
1295   GDK_THREADS_LEAVE ();  
1296   result = g_main_context_pending (NULL);
1297   GDK_THREADS_ENTER ();
1298
1299   return result;
1300 }
1301
1302 gboolean
1303 gtk_main_iteration (void)
1304 {
1305   GDK_THREADS_LEAVE ();
1306   g_main_context_iteration (NULL, TRUE);
1307   GDK_THREADS_ENTER ();
1308
1309   if (main_loops)
1310     return !g_main_loop_is_running (main_loops->data);
1311   else
1312     return TRUE;
1313 }
1314
1315 gboolean
1316 gtk_main_iteration_do (gboolean blocking)
1317 {
1318   GDK_THREADS_LEAVE ();
1319   g_main_context_iteration (NULL, blocking);
1320   GDK_THREADS_ENTER ();
1321
1322   if (main_loops)
1323     return !g_main_loop_is_running (main_loops->data);
1324   else
1325     return TRUE;
1326 }
1327
1328 /* private libgtk to libgdk interfaces
1329  */
1330 gboolean gdk_pointer_grab_info_libgtk_only  (GdkDisplay *display,
1331                                              GdkWindow **grab_window,
1332                                              gboolean   *owner_events);
1333 gboolean gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
1334                                              GdkWindow **grab_window,
1335                                              gboolean   *owner_events);
1336
1337 static void
1338 rewrite_events_translate (GdkWindow *old_window,
1339                           GdkWindow *new_window,
1340                           gdouble   *x,
1341                           gdouble   *y)
1342 {
1343   gint old_origin_x, old_origin_y;
1344   gint new_origin_x, new_origin_y;
1345
1346   gdk_window_get_origin (old_window, &old_origin_x, &old_origin_y);
1347   gdk_window_get_origin (new_window, &new_origin_x, &new_origin_y);
1348
1349   *x += old_origin_x - new_origin_x;
1350   *y += old_origin_y - new_origin_y;
1351 }
1352
1353 static GdkEvent *
1354 rewrite_event_for_window (GdkEvent  *event,
1355                           GdkWindow *new_window)
1356 {
1357   event = gdk_event_copy (event);
1358
1359   switch (event->type)
1360     {
1361     case GDK_SCROLL:
1362       rewrite_events_translate (event->any.window,
1363                                 new_window,
1364                                 &event->scroll.x, &event->scroll.y);
1365       break;
1366     case GDK_BUTTON_PRESS:
1367     case GDK_2BUTTON_PRESS:
1368     case GDK_3BUTTON_PRESS:
1369     case GDK_BUTTON_RELEASE:
1370       rewrite_events_translate (event->any.window,
1371                                 new_window,
1372                                 &event->button.x, &event->button.y);
1373       break;
1374     case GDK_MOTION_NOTIFY:
1375       rewrite_events_translate (event->any.window,
1376                                 new_window,
1377                                 &event->motion.x, &event->motion.y);
1378       break;
1379     case GDK_KEY_PRESS:
1380     case GDK_KEY_RELEASE:
1381     case GDK_PROXIMITY_IN:
1382     case GDK_PROXIMITY_OUT:
1383       break;
1384
1385     default:
1386       return event;
1387     }
1388
1389   g_object_unref (event->any.window);
1390   event->any.window = g_object_ref (new_window);
1391
1392   return event;
1393 }
1394
1395 /* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
1396  * then what X11 does is deliver the event normally if it was going to this
1397  * client, otherwise, delivers it in terms of the grab window. This function
1398  * rewrites events to the effect that events going to the same window group
1399  * are delivered normally, otherwise, the event is delivered in terms of the
1400  * grab window.
1401  */
1402 static GdkEvent *
1403 rewrite_event_for_grabs (GdkEvent *event)
1404 {
1405   GdkWindow *grab_window;
1406   GtkWidget *event_widget, *grab_widget;
1407   gpointer grab_widget_ptr;
1408   gboolean owner_events;
1409   GdkDisplay *display;
1410
1411   switch (event->type)
1412     {
1413     case GDK_SCROLL:
1414     case GDK_BUTTON_PRESS:
1415     case GDK_2BUTTON_PRESS:
1416     case GDK_3BUTTON_PRESS:
1417     case GDK_BUTTON_RELEASE:
1418     case GDK_MOTION_NOTIFY:
1419     case GDK_PROXIMITY_IN:
1420     case GDK_PROXIMITY_OUT:
1421       display = gdk_drawable_get_display (event->proximity.window);
1422       if (!gdk_pointer_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
1423           !owner_events)
1424         return NULL;
1425       break;
1426
1427     case GDK_KEY_PRESS:
1428     case GDK_KEY_RELEASE:
1429       display = gdk_drawable_get_display (event->key.window);
1430       if (!gdk_keyboard_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
1431           !owner_events)
1432         return NULL;
1433       break;
1434
1435     default:
1436       return NULL;
1437     }
1438
1439   event_widget = gtk_get_event_widget (event);
1440   gdk_window_get_user_data (grab_window, &grab_widget_ptr);
1441   grab_widget = grab_widget_ptr;
1442
1443   if (grab_widget &&
1444       gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
1445     return rewrite_event_for_window (event, grab_window);
1446   else
1447     return NULL;
1448 }
1449
1450 void 
1451 gtk_main_do_event (GdkEvent *event)
1452 {
1453   GtkWidget *event_widget;
1454   GtkWidget *grab_widget;
1455   GtkWindowGroup *window_group;
1456   GdkEvent *rewritten_event = NULL;
1457   GList *tmp_list;
1458
1459   if (event->type == GDK_SETTING)
1460     {
1461       _gtk_settings_handle_event (&event->setting);
1462       return;
1463     }
1464
1465   if (event->type == GDK_OWNER_CHANGE)
1466     {
1467       _gtk_clipboard_handle_event (&event->owner_change);
1468       return;
1469     }
1470
1471   /* Find the widget which got the event. We store the widget
1472    *  in the user_data field of GdkWindow's.
1473    *  Ignore the event if we don't have a widget for it, except
1474    *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
1475    *  Though this happens rarely, bogus events can occour
1476    *  for e.g. destroyed GdkWindows. 
1477    */
1478   event_widget = gtk_get_event_widget (event);
1479   if (!event_widget)
1480     {
1481       /* To handle selection INCR transactions, we select
1482        * PropertyNotify events on the requestor window and create
1483        * a corresponding (fake) GdkWindow so that events get
1484        * here. There won't be a widget though, so we have to handle
1485            * them specially
1486            */
1487       if (event->type == GDK_PROPERTY_NOTIFY)
1488         _gtk_selection_incr_event (event->any.window,
1489                                    &event->property);
1490
1491       return;
1492     }
1493
1494   /* If pointer or keyboard grabs are in effect, munge the events
1495    * so that each window group looks like a separate app.
1496    */
1497   rewritten_event = rewrite_event_for_grabs (event);
1498   if (rewritten_event)
1499     {
1500       event = rewritten_event;
1501       event_widget = gtk_get_event_widget (event);
1502     }
1503   
1504   window_group = gtk_main_get_window_group (event_widget);
1505
1506   /* Push the event onto a stack of current events for
1507    * gtk_current_event_get().
1508    */
1509   current_events = g_list_prepend (current_events, event);
1510
1511   /* If there is a grab in effect...
1512    */
1513   if (window_group->grabs)
1514     {
1515       grab_widget = window_group->grabs->data;
1516       
1517       /* If the grab widget is an ancestor of the event widget
1518        *  then we send the event to the original event widget.
1519        *  This is the key to implementing modality.
1520        */
1521       if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
1522           gtk_widget_is_ancestor (event_widget, grab_widget))
1523         grab_widget = event_widget;
1524     }
1525   else
1526     {
1527       grab_widget = event_widget;
1528     }
1529
1530   /* Not all events get sent to the grabbing widget.
1531    * The delete, destroy, expose, focus change and resize
1532    *  events still get sent to the event widget because
1533    *  1) these events have no meaning for the grabbing widget
1534    *  and 2) redirecting these events to the grabbing widget
1535    *  could cause the display to be messed up.
1536    * 
1537    * Drag events are also not redirected, since it isn't
1538    *  clear what the semantics of that would be.
1539    */
1540   switch (event->type)
1541     {
1542     case GDK_NOTHING:
1543       break;
1544       
1545     case GDK_DELETE:
1546       g_object_ref (event_widget);
1547       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1548           !gtk_widget_event (event_widget, event))
1549         gtk_widget_destroy (event_widget);
1550       g_object_unref (event_widget);
1551       break;
1552       
1553     case GDK_DESTROY:
1554       /* Unexpected GDK_DESTROY from the outside, ignore for
1555        * child windows, handle like a GDK_DELETE for toplevels
1556        */
1557       if (!event_widget->parent)
1558         {
1559           g_object_ref (event_widget);
1560           if (!gtk_widget_event (event_widget, event) &&
1561               GTK_WIDGET_REALIZED (event_widget))
1562             gtk_widget_destroy (event_widget);
1563           g_object_unref (event_widget);
1564         }
1565       break;
1566       
1567     case GDK_EXPOSE:
1568       if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
1569         {
1570           gdk_window_begin_paint_region (event->any.window, event->expose.region);
1571           gtk_widget_send_expose (event_widget, event);
1572           gdk_window_end_paint (event->any.window);
1573         }
1574       else
1575         {
1576           /* The app may paint with a previously allocated cairo_t,
1577              which will draw directly to the window. We can't catch cairo
1578              drap operatoins to automatically flush the window, thus we
1579              need to explicitly flush any outstanding moves or double
1580              buffering */
1581           gdk_window_flush (event->any.window);
1582           gtk_widget_send_expose (event_widget, event);
1583         }
1584       break;
1585
1586     case GDK_PROPERTY_NOTIFY:
1587     case GDK_NO_EXPOSE:
1588     case GDK_FOCUS_CHANGE:
1589     case GDK_CONFIGURE:
1590     case GDK_MAP:
1591     case GDK_UNMAP:
1592     case GDK_SELECTION_CLEAR:
1593     case GDK_SELECTION_REQUEST:
1594     case GDK_SELECTION_NOTIFY:
1595     case GDK_CLIENT_EVENT:
1596     case GDK_VISIBILITY_NOTIFY:
1597     case GDK_WINDOW_STATE:
1598     case GDK_GRAB_BROKEN:
1599     case GDK_DAMAGE:
1600       gtk_widget_event (event_widget, event);
1601       break;
1602
1603     case GDK_SCROLL:
1604     case GDK_BUTTON_PRESS:
1605     case GDK_2BUTTON_PRESS:
1606     case GDK_3BUTTON_PRESS:
1607       gtk_propagate_event (grab_widget, event);
1608       break;
1609
1610     case GDK_KEY_PRESS:
1611     case GDK_KEY_RELEASE:
1612       if (key_snoopers)
1613         {
1614           if (gtk_invoke_key_snoopers (grab_widget, event))
1615             break;
1616         }
1617       /* else fall through */
1618     case GDK_MOTION_NOTIFY:
1619     case GDK_BUTTON_RELEASE:
1620     case GDK_PROXIMITY_IN:
1621     case GDK_PROXIMITY_OUT:
1622       gtk_propagate_event (grab_widget, event);
1623       break;
1624       
1625     case GDK_ENTER_NOTIFY:
1626       GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
1627       _gtk_widget_set_pointer_window (event_widget, event->any.window);
1628       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1629         gtk_widget_event (grab_widget, event);
1630       break;
1631       
1632     case GDK_LEAVE_NOTIFY:
1633       GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
1634       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1635         gtk_widget_event (grab_widget, event);
1636       break;
1637       
1638     case GDK_DRAG_STATUS:
1639     case GDK_DROP_FINISHED:
1640       _gtk_drag_source_handle_event (event_widget, event);
1641       break;
1642     case GDK_DRAG_ENTER:
1643     case GDK_DRAG_LEAVE:
1644     case GDK_DRAG_MOTION:
1645     case GDK_DROP_START:
1646       _gtk_drag_dest_handle_event (event_widget, event);
1647       break;
1648     default:
1649       g_assert_not_reached ();
1650       break;
1651     }
1652
1653   if (event->type == GDK_ENTER_NOTIFY
1654       || event->type == GDK_LEAVE_NOTIFY
1655       || event->type == GDK_BUTTON_PRESS
1656       || event->type == GDK_2BUTTON_PRESS
1657       || event->type == GDK_3BUTTON_PRESS
1658       || event->type == GDK_KEY_PRESS
1659       || event->type == GDK_DRAG_ENTER
1660       || event->type == GDK_GRAB_BROKEN
1661       || event->type == GDK_MOTION_NOTIFY
1662       || event->type == GDK_SCROLL)
1663     {
1664       _gtk_tooltip_handle_event (event);
1665     }
1666   
1667   tmp_list = current_events;
1668   current_events = g_list_remove_link (current_events, tmp_list);
1669   g_list_free_1 (tmp_list);
1670
1671   if (rewritten_event)
1672     gdk_event_free (rewritten_event);
1673 }
1674
1675 gboolean
1676 gtk_true (void)
1677 {
1678   return TRUE;
1679 }
1680
1681 gboolean
1682 gtk_false (void)
1683 {
1684   return FALSE;
1685 }
1686
1687 static GtkWindowGroup *
1688 gtk_main_get_window_group (GtkWidget   *widget)
1689 {
1690   GtkWidget *toplevel = NULL;
1691
1692   if (widget)
1693     toplevel = gtk_widget_get_toplevel (widget);
1694
1695   if (GTK_IS_WINDOW (toplevel))
1696     return gtk_window_get_group (GTK_WINDOW (toplevel));
1697   else
1698     return gtk_window_get_group (NULL);
1699 }
1700
1701 typedef struct
1702 {
1703   GtkWidget *old_grab_widget;
1704   GtkWidget *new_grab_widget;
1705   gboolean   was_grabbed;
1706   gboolean   is_grabbed;
1707   gboolean   from_grab;
1708 } GrabNotifyInfo;
1709
1710 static void
1711 gtk_grab_notify_foreach (GtkWidget *child,
1712                          gpointer   data)
1713                         
1714 {
1715   GrabNotifyInfo *info = data;
1716  
1717   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1718
1719   was_grabbed = info->was_grabbed;
1720   is_grabbed = info->is_grabbed;
1721
1722   info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1723   info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1724
1725   was_shadowed = info->old_grab_widget && !info->was_grabbed;
1726   is_shadowed = info->new_grab_widget && !info->is_grabbed;
1727
1728   g_object_ref (child);
1729
1730   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1731     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1732   
1733   if (is_shadowed)
1734     {
1735       GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
1736       if (!was_shadowed && GTK_WIDGET_HAS_POINTER (child)
1737           && GTK_WIDGET_IS_SENSITIVE (child))
1738         _gtk_widget_synthesize_crossing (child, info->new_grab_widget,
1739                                          GDK_CROSSING_GTK_GRAB);
1740     }
1741   else
1742     {
1743       GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
1744       if (was_shadowed && GTK_WIDGET_HAS_POINTER (child)
1745           && GTK_WIDGET_IS_SENSITIVE (child))
1746         _gtk_widget_synthesize_crossing (info->old_grab_widget, child,
1747                                          info->from_grab ? GDK_CROSSING_GTK_GRAB
1748                                          : GDK_CROSSING_GTK_UNGRAB);
1749     }
1750
1751   if (was_shadowed != is_shadowed)
1752     _gtk_widget_grab_notify (child, was_shadowed);
1753   
1754   g_object_unref (child);
1755   
1756   info->was_grabbed = was_grabbed;
1757   info->is_grabbed = is_grabbed;
1758 }
1759
1760 static void
1761 gtk_grab_notify (GtkWindowGroup *group,
1762                  GtkWidget      *old_grab_widget,
1763                  GtkWidget      *new_grab_widget,
1764                  gboolean        from_grab)
1765 {
1766   GList *toplevels;
1767   GrabNotifyInfo info;
1768
1769   if (old_grab_widget == new_grab_widget)
1770     return;
1771
1772   info.old_grab_widget = old_grab_widget;
1773   info.new_grab_widget = new_grab_widget;
1774   info.from_grab = from_grab;
1775
1776   g_object_ref (group);
1777
1778   toplevels = gtk_window_list_toplevels ();
1779   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1780                             
1781   while (toplevels)
1782     {
1783       GtkWindow *toplevel = toplevels->data;
1784       toplevels = g_list_delete_link (toplevels, toplevels);
1785
1786       info.was_grabbed = FALSE;
1787       info.is_grabbed = FALSE;
1788
1789       if (group == gtk_window_get_group (toplevel))
1790         gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1791       g_object_unref (toplevel);
1792     }
1793
1794   g_object_unref (group);
1795 }
1796
1797 void
1798 gtk_grab_add (GtkWidget *widget)
1799 {
1800   GtkWindowGroup *group;
1801   GtkWidget *old_grab_widget;
1802   
1803   g_return_if_fail (widget != NULL);
1804   
1805   if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
1806     {
1807       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
1808       
1809       group = gtk_main_get_window_group (widget);
1810
1811       if (group->grabs)
1812         old_grab_widget = (GtkWidget *)group->grabs->data;
1813       else
1814         old_grab_widget = NULL;
1815
1816       g_object_ref (widget);
1817       group->grabs = g_slist_prepend (group->grabs, widget);
1818
1819       gtk_grab_notify (group, old_grab_widget, widget, TRUE);
1820     }
1821 }
1822
1823 GtkWidget*
1824 gtk_grab_get_current (void)
1825 {
1826   GtkWindowGroup *group;
1827
1828   group = gtk_main_get_window_group (NULL);
1829
1830   if (group->grabs)
1831     return GTK_WIDGET (group->grabs->data);
1832   return NULL;
1833 }
1834
1835 void
1836 gtk_grab_remove (GtkWidget *widget)
1837 {
1838   GtkWindowGroup *group;
1839   GtkWidget *new_grab_widget;
1840   
1841   g_return_if_fail (widget != NULL);
1842   
1843   if (GTK_WIDGET_HAS_GRAB (widget))
1844     {
1845       GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
1846
1847       group = gtk_main_get_window_group (widget);
1848       group->grabs = g_slist_remove (group->grabs, widget);
1849       
1850       if (group->grabs)
1851         new_grab_widget = (GtkWidget *)group->grabs->data;
1852       else
1853         new_grab_widget = NULL;
1854
1855       gtk_grab_notify (group, widget, new_grab_widget, FALSE);
1856       
1857       g_object_unref (widget);
1858     }
1859 }
1860
1861 void
1862 gtk_init_add (GtkFunction function,
1863               gpointer    data)
1864 {
1865   GtkInitFunction *init;
1866   
1867   init = g_new (GtkInitFunction, 1);
1868   init->function = function;
1869   init->data = data;
1870   
1871   init_functions = g_list_prepend (init_functions, init);
1872 }
1873
1874 guint
1875 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
1876                          gpointer        func_data)
1877 {
1878   GtkKeySnooperData *data;
1879   static guint snooper_id = 1;
1880
1881   g_return_val_if_fail (snooper != NULL, 0);
1882
1883   data = g_new (GtkKeySnooperData, 1);
1884   data->func = snooper;
1885   data->func_data = func_data;
1886   data->id = snooper_id++;
1887   key_snoopers = g_slist_prepend (key_snoopers, data);
1888
1889   return data->id;
1890 }
1891
1892 void
1893 gtk_key_snooper_remove (guint snooper_id)
1894 {
1895   GtkKeySnooperData *data = NULL;
1896   GSList *slist;
1897
1898   slist = key_snoopers;
1899   while (slist)
1900     {
1901       data = slist->data;
1902       if (data->id == snooper_id)
1903         break;
1904
1905       slist = slist->next;
1906       data = NULL;
1907     }
1908   if (data)
1909     {
1910       key_snoopers = g_slist_remove (key_snoopers, data);
1911       g_free (data);
1912     }
1913 }
1914
1915 static gint
1916 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
1917                          GdkEvent  *event)
1918 {
1919   GSList *slist;
1920   gint return_val = FALSE;
1921
1922   slist = key_snoopers;
1923   while (slist && !return_val)
1924     {
1925       GtkKeySnooperData *data;
1926
1927       data = slist->data;
1928       slist = slist->next;
1929       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
1930     }
1931
1932   return return_val;
1933 }
1934
1935 guint
1936 gtk_quit_add_full (guint                main_level,
1937                    GtkFunction          function,
1938                    GtkCallbackMarshal   marshal,
1939                    gpointer             data,
1940                    GDestroyNotify       destroy)
1941 {
1942   static guint quit_id = 1;
1943   GtkQuitFunction *quitf;
1944   
1945   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
1946
1947   quitf = g_slice_new (GtkQuitFunction);
1948   
1949   quitf->id = quit_id++;
1950   quitf->main_level = main_level;
1951   quitf->function = function;
1952   quitf->marshal = marshal;
1953   quitf->data = data;
1954   quitf->destroy = destroy;
1955
1956   quit_functions = g_list_prepend (quit_functions, quitf);
1957   
1958   return quitf->id;
1959 }
1960
1961 static void
1962 gtk_quit_destroy (GtkQuitFunction *quitf)
1963 {
1964   if (quitf->destroy)
1965     quitf->destroy (quitf->data);
1966   g_slice_free (GtkQuitFunction, quitf);
1967 }
1968
1969 static gint
1970 gtk_quit_destructor (GtkObject **object_p)
1971 {
1972   if (*object_p)
1973     gtk_object_destroy (*object_p);
1974   g_free (object_p);
1975
1976   return FALSE;
1977 }
1978
1979 void
1980 gtk_quit_add_destroy (guint              main_level,
1981                       GtkObject         *object)
1982 {
1983   GtkObject **object_p;
1984
1985   g_return_if_fail (main_level > 0);
1986   g_return_if_fail (GTK_IS_OBJECT (object));
1987
1988   object_p = g_new (GtkObject*, 1);
1989   *object_p = object;
1990   g_signal_connect (object,
1991                     "destroy",
1992                     G_CALLBACK (gtk_widget_destroyed),
1993                     object_p);
1994   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1995 }
1996
1997 guint
1998 gtk_quit_add (guint       main_level,
1999               GtkFunction function,
2000               gpointer    data)
2001 {
2002   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
2003 }
2004
2005 void
2006 gtk_quit_remove (guint id)
2007 {
2008   GtkQuitFunction *quitf;
2009   GList *tmp_list;
2010   
2011   tmp_list = quit_functions;
2012   while (tmp_list)
2013     {
2014       quitf = tmp_list->data;
2015       
2016       if (quitf->id == id)
2017         {
2018           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2019           g_list_free (tmp_list);
2020           gtk_quit_destroy (quitf);
2021           
2022           return;
2023         }
2024       
2025       tmp_list = tmp_list->next;
2026     }
2027 }
2028
2029 void
2030 gtk_quit_remove_by_data (gpointer data)
2031 {
2032   GtkQuitFunction *quitf;
2033   GList *tmp_list;
2034   
2035   tmp_list = quit_functions;
2036   while (tmp_list)
2037     {
2038       quitf = tmp_list->data;
2039       
2040       if (quitf->data == data)
2041         {
2042           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2043           g_list_free (tmp_list);
2044           gtk_quit_destroy (quitf);
2045
2046           return;
2047         }
2048       
2049       tmp_list = tmp_list->next;
2050     }
2051 }
2052
2053 guint
2054 gtk_timeout_add_full (guint32            interval,
2055                       GtkFunction        function,
2056                       GtkCallbackMarshal marshal,
2057                       gpointer           data,
2058                       GDestroyNotify     destroy)
2059 {
2060   if (marshal)
2061     {
2062       GtkClosure *closure;
2063
2064       closure = g_new (GtkClosure, 1);
2065       closure->marshal = marshal;
2066       closure->data = data;
2067       closure->destroy = destroy;
2068
2069       return g_timeout_add_full (0, interval, 
2070                                  gtk_invoke_idle_timeout,
2071                                  closure,
2072                                  gtk_destroy_closure);
2073     }
2074   else
2075     return g_timeout_add_full (0, interval, function, data, destroy);
2076 }
2077
2078 guint
2079 gtk_timeout_add (guint32     interval,
2080                  GtkFunction function,
2081                  gpointer    data)
2082 {
2083   return g_timeout_add_full (0, interval, function, data, NULL);
2084 }
2085
2086 void
2087 gtk_timeout_remove (guint tag)
2088 {
2089   g_source_remove (tag);
2090 }
2091
2092 guint
2093 gtk_idle_add_full (gint                 priority,
2094                    GtkFunction          function,
2095                    GtkCallbackMarshal   marshal,
2096                    gpointer             data,
2097                    GDestroyNotify       destroy)
2098 {
2099   if (marshal)
2100     {
2101       GtkClosure *closure;
2102
2103       closure = g_new (GtkClosure, 1);
2104       closure->marshal = marshal;
2105       closure->data = data;
2106       closure->destroy = destroy;
2107
2108       return g_idle_add_full (priority,
2109                               gtk_invoke_idle_timeout,
2110                               closure,
2111                               gtk_destroy_closure);
2112     }
2113   else
2114     return g_idle_add_full (priority, function, data, destroy);
2115 }
2116
2117 guint
2118 gtk_idle_add (GtkFunction function,
2119               gpointer    data)
2120 {
2121   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
2122 }
2123
2124 guint       
2125 gtk_idle_add_priority (gint        priority,
2126                        GtkFunction function,
2127                        gpointer    data)
2128 {
2129   return g_idle_add_full (priority, function, data, NULL);
2130 }
2131
2132 void
2133 gtk_idle_remove (guint tag)
2134 {
2135   g_source_remove (tag);
2136 }
2137
2138 void
2139 gtk_idle_remove_by_data (gpointer data)
2140 {
2141   if (!g_idle_remove_by_data (data))
2142     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
2143 }
2144
2145 guint
2146 gtk_input_add_full (gint                source,
2147                     GdkInputCondition   condition,
2148                     GdkInputFunction    function,
2149                     GtkCallbackMarshal  marshal,
2150                     gpointer            data,
2151                     GDestroyNotify      destroy)
2152 {
2153   if (marshal)
2154     {
2155       GtkClosure *closure;
2156
2157       closure = g_new (GtkClosure, 1);
2158       closure->marshal = marshal;
2159       closure->data = data;
2160       closure->destroy = destroy;
2161
2162       return gdk_input_add_full (source,
2163                                  condition,
2164                                  (GdkInputFunction) gtk_invoke_input,
2165                                  closure,
2166                                  (GDestroyNotify) gtk_destroy_closure);
2167     }
2168   else
2169     return gdk_input_add_full (source, condition, function, data, destroy);
2170 }
2171
2172 void
2173 gtk_input_remove (guint tag)
2174 {
2175   g_source_remove (tag);
2176 }
2177
2178 static void
2179 gtk_destroy_closure (gpointer data)
2180 {
2181   GtkClosure *closure = data;
2182
2183   if (closure->destroy)
2184     (closure->destroy) (closure->data);
2185   g_free (closure);
2186 }
2187
2188 static gboolean
2189 gtk_invoke_idle_timeout (gpointer data)
2190 {
2191   GtkClosure *closure = data;
2192
2193   GtkArg args[1];
2194   gint ret_val = FALSE;
2195   args[0].name = NULL;
2196   args[0].type = G_TYPE_BOOLEAN;
2197   args[0].d.pointer_data = &ret_val;
2198   closure->marshal (NULL, closure->data,  0, args);
2199   return ret_val;
2200 }
2201
2202 static void
2203 gtk_invoke_input (gpointer          data,
2204                   gint              source,
2205                   GdkInputCondition condition)
2206 {
2207   GtkClosure *closure = data;
2208
2209   GtkArg args[3];
2210   args[0].type = G_TYPE_INT;
2211   args[0].name = NULL;
2212   GTK_VALUE_INT (args[0]) = source;
2213   args[1].type = GDK_TYPE_INPUT_CONDITION;
2214   args[1].name = NULL;
2215   GTK_VALUE_FLAGS (args[1]) = condition;
2216   args[2].type = G_TYPE_NONE;
2217   args[2].name = NULL;
2218
2219   closure->marshal (NULL, closure->data, 2, args);
2220 }
2221
2222 /**
2223  * gtk_get_current_event:
2224  * 
2225  * Obtains a copy of the event currently being processed by GTK+.  For
2226  * example, if you get a "clicked" signal from #GtkButton, the current
2227  * event will be the #GdkEventButton that triggered the "clicked"
2228  * signal. The returned event must be freed with gdk_event_free().
2229  * If there is no current event, the function returns %NULL.
2230  * 
2231  * Return value: a copy of the current event, or %NULL if no current event.
2232  **/
2233 GdkEvent*
2234 gtk_get_current_event (void)
2235 {
2236   if (current_events)
2237     return gdk_event_copy (current_events->data);
2238   else
2239     return NULL;
2240 }
2241
2242 /**
2243  * gtk_get_current_event_time:
2244  * 
2245  * If there is a current event and it has a timestamp, return that
2246  * timestamp, otherwise return %GDK_CURRENT_TIME.
2247  * 
2248  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2249  **/
2250 guint32
2251 gtk_get_current_event_time (void)
2252 {
2253   if (current_events)
2254     return gdk_event_get_time (current_events->data);
2255   else
2256     return GDK_CURRENT_TIME;
2257 }
2258
2259 /**
2260  * gtk_get_current_event_state:
2261  * @state: a location to store the state of the current event
2262  * 
2263  * If there is a current event and it has a state field, place
2264  * that state field in @state and return %TRUE, otherwise return
2265  * %FALSE.
2266  * 
2267  * Return value: %TRUE if there was a current event and it had a state field
2268  **/
2269 gboolean
2270 gtk_get_current_event_state (GdkModifierType *state)
2271 {
2272   g_return_val_if_fail (state != NULL, FALSE);
2273   
2274   if (current_events)
2275     return gdk_event_get_state (current_events->data, state);
2276   else
2277     {
2278       *state = 0;
2279       return FALSE;
2280     }
2281 }
2282
2283 /**
2284  * gtk_get_event_widget:
2285  * @event: a #GdkEvent
2286  *
2287  * If @event is %NULL or the event was not associated with any widget,
2288  * returns %NULL, otherwise returns the widget that received the event
2289  * originally.
2290  * 
2291  * Return value: the widget that originally received @event, or %NULL
2292  **/
2293 GtkWidget*
2294 gtk_get_event_widget (GdkEvent *event)
2295 {
2296   GtkWidget *widget;
2297   gpointer widget_ptr;
2298
2299   widget = NULL;
2300   if (event && event->any.window && 
2301       (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
2302     {
2303       gdk_window_get_user_data (event->any.window, &widget_ptr);
2304       widget = widget_ptr;
2305     }
2306   
2307   return widget;
2308 }
2309
2310 static gint
2311 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2312 {
2313   if (!quitf->marshal)
2314     return quitf->function (quitf->data);
2315   else
2316     {
2317       GtkArg args[1];
2318       gint ret_val = FALSE;
2319
2320       args[0].name = NULL;
2321       args[0].type = G_TYPE_BOOLEAN;
2322       args[0].d.pointer_data = &ret_val;
2323       ((GtkCallbackMarshal) quitf->marshal) (NULL,
2324                                              quitf->data,
2325                                              0, args);
2326       return ret_val;
2327     }
2328 }
2329
2330 /**
2331  * gtk_propagate_event:
2332  * @widget: a #GtkWidget
2333  * @event: an event
2334  *
2335  * Sends an event to a widget, propagating the event to parent widgets
2336  * if the event remains unhandled. Events received by GTK+ from GDK
2337  * normally begin in gtk_main_do_event(). Depending on the type of
2338  * event, existence of modal dialogs, grabs, etc., the event may be
2339  * propagated; if so, this function is used. gtk_propagate_event()
2340  * calls gtk_widget_event() on each widget it decides to send the
2341  * event to.  So gtk_widget_event() is the lowest-level function; it
2342  * simply emits the "event" and possibly an event-specific signal on a
2343  * widget.  gtk_propagate_event() is a bit higher-level, and
2344  * gtk_main_do_event() is the highest level.
2345  *
2346  * All that said, you most likely don't want to use any of these
2347  * functions; synthesizing events is rarely needed. Consider asking on
2348  * the mailing list for better ways to achieve your goals. For
2349  * example, use gdk_window_invalidate_rect() or
2350  * gtk_widget_queue_draw() instead of making up expose events.
2351  * 
2352  **/
2353 void
2354 gtk_propagate_event (GtkWidget *widget,
2355                      GdkEvent  *event)
2356 {
2357   gint handled_event;
2358   
2359   g_return_if_fail (GTK_IS_WIDGET (widget));
2360   g_return_if_fail (event != NULL);
2361   
2362   handled_event = FALSE;
2363
2364   g_object_ref (widget);
2365       
2366   if ((event->type == GDK_KEY_PRESS) ||
2367       (event->type == GDK_KEY_RELEASE))
2368     {
2369       /* Only send key events within Window widgets to the Window
2370        *  The Window widget will in turn pass the
2371        *  key event on to the currently focused widget
2372        *  for that window.
2373        */
2374       GtkWidget *window;
2375
2376       window = gtk_widget_get_toplevel (widget);
2377       if (GTK_IS_WINDOW (window))
2378         {
2379           /* If there is a grab within the window, give the grab widget
2380            * a first crack at the key event
2381            */
2382           if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
2383             handled_event = gtk_widget_event (widget, event);
2384           
2385           if (!handled_event)
2386             {
2387               window = gtk_widget_get_toplevel (widget);
2388               if (GTK_IS_WINDOW (window))
2389                 {
2390                   if (GTK_WIDGET_IS_SENSITIVE (window))
2391                     gtk_widget_event (window, event);
2392                 }
2393             }
2394                   
2395           handled_event = TRUE; /* don't send to widget */
2396         }
2397     }
2398   
2399   /* Other events get propagated up the widget tree
2400    *  so that parents can see the button and motion
2401    *  events of the children.
2402    */
2403   if (!handled_event)
2404     {
2405       while (TRUE)
2406         {
2407           GtkWidget *tmp;
2408
2409           /* Scroll events are special cased here because it
2410            * feels wrong when scrolling a GtkViewport, say,
2411            * to have children of the viewport eat the scroll
2412            * event
2413            */
2414           if (!GTK_WIDGET_IS_SENSITIVE (widget))
2415             handled_event = event->type != GDK_SCROLL;
2416           else
2417             handled_event = gtk_widget_event (widget, event);
2418               
2419           tmp = widget->parent;
2420           g_object_unref (widget);
2421
2422           widget = tmp;
2423           
2424           if (!handled_event && widget)
2425             g_object_ref (widget);
2426           else
2427             break;
2428         }
2429     }
2430   else
2431     g_object_unref (widget);
2432 }
2433
2434 #if 0
2435 static void
2436 gtk_error (gchar *str)
2437 {
2438   gtk_print (str);
2439 }
2440
2441 static void
2442 gtk_warning (gchar *str)
2443 {
2444   gtk_print (str);
2445 }
2446
2447 static void
2448 gtk_message (gchar *str)
2449 {
2450   gtk_print (str);
2451 }
2452
2453 static void
2454 gtk_print (gchar *str)
2455 {
2456   static GtkWidget *window = NULL;
2457   static GtkWidget *text;
2458   static int level = 0;
2459   GtkWidget *box1;
2460   GtkWidget *box2;
2461   GtkWidget *table;
2462   GtkWidget *hscrollbar;
2463   GtkWidget *vscrollbar;
2464   GtkWidget *separator;
2465   GtkWidget *button;
2466   
2467   if (level > 0)
2468     {
2469       fputs (str, stdout);
2470       fflush (stdout);
2471       return;
2472     }
2473   
2474   if (!window)
2475     {
2476       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2477       
2478       gtk_signal_connect (GTK_OBJECT (window), "destroy",
2479                           G_CALLBACK (gtk_widget_destroyed),
2480                           &window);
2481       
2482       gtk_window_set_title (GTK_WINDOW (window), "Messages");
2483       
2484       box1 = gtk_vbox_new (FALSE, 0);
2485       gtk_container_add (GTK_CONTAINER (window), box1);
2486       gtk_widget_show (box1);
2487       
2488       
2489       box2 = gtk_vbox_new (FALSE, 10);
2490       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2491       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2492       gtk_widget_show (box2);
2493       
2494       
2495       table = gtk_table_new (2, 2, FALSE);
2496       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
2497       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
2498       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
2499       gtk_widget_show (table);
2500       
2501       text = gtk_text_new (NULL, NULL);
2502       gtk_text_set_editable (GTK_TEXT (text), FALSE);
2503       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
2504       gtk_widget_show (text);
2505       gtk_widget_realize (text);
2506       
2507       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
2508       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
2509                         GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
2510       gtk_widget_show (hscrollbar);
2511       
2512       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
2513       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
2514                         GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2515       gtk_widget_show (vscrollbar);
2516       
2517       separator = gtk_hseparator_new ();
2518       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2519       gtk_widget_show (separator);
2520       
2521       
2522       box2 = gtk_vbox_new (FALSE, 10);
2523       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2524       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2525       gtk_widget_show (box2);
2526       
2527       
2528       button = gtk_button_new_with_label ("close");
2529       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2530                                  G_CALLBACK (gtk_widget_hide),
2531                                  GTK_OBJECT (window));
2532       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2533       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
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_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"