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