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