]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
Fix a trivial typo in a doc comment
[~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  * 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 && window_group->grabs)
1610     grab_widget = window_group->grabs->data;
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       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1654           !gtk_widget_event (event_widget, event))
1655         gtk_widget_destroy (event_widget);
1656       g_object_unref (event_widget);
1657       break;
1658       
1659     case GDK_DESTROY:
1660       /* Unexpected GDK_DESTROY from the outside, ignore for
1661        * child windows, handle like a GDK_DELETE for toplevels
1662        */
1663       if (!gtk_widget_get_parent (event_widget))
1664         {
1665           g_object_ref (event_widget);
1666           if (!gtk_widget_event (event_widget, event) &&
1667               gtk_widget_get_realized (event_widget))
1668             gtk_widget_destroy (event_widget);
1669           g_object_unref (event_widget);
1670         }
1671       break;
1672       
1673     case GDK_EXPOSE:
1674       if (event->any.window && gtk_widget_get_double_buffered (event_widget))
1675         {
1676           gdk_window_begin_paint_region (event->any.window, event->expose.region);
1677           gtk_widget_send_expose (event_widget, event);
1678           gdk_window_end_paint (event->any.window);
1679         }
1680       else
1681         {
1682           /* The app may paint with a previously allocated cairo_t,
1683              which will draw directly to the window. We can't catch cairo
1684              drap operatoins to automatically flush the window, thus we
1685              need to explicitly flush any outstanding moves or double
1686              buffering */
1687           gdk_window_flush (event->any.window);
1688           gtk_widget_send_expose (event_widget, event);
1689         }
1690       break;
1691
1692     case GDK_PROPERTY_NOTIFY:
1693     case GDK_NO_EXPOSE:
1694     case GDK_FOCUS_CHANGE:
1695     case GDK_CONFIGURE:
1696     case GDK_MAP:
1697     case GDK_UNMAP:
1698     case GDK_SELECTION_CLEAR:
1699     case GDK_SELECTION_REQUEST:
1700     case GDK_SELECTION_NOTIFY:
1701     case GDK_CLIENT_EVENT:
1702     case GDK_VISIBILITY_NOTIFY:
1703     case GDK_WINDOW_STATE:
1704     case GDK_GRAB_BROKEN:
1705     case GDK_DAMAGE:
1706       gtk_widget_event (event_widget, event);
1707       break;
1708
1709     case GDK_SCROLL:
1710     case GDK_BUTTON_PRESS:
1711     case GDK_2BUTTON_PRESS:
1712     case GDK_3BUTTON_PRESS:
1713       gtk_propagate_event (grab_widget, event);
1714       break;
1715
1716     case GDK_KEY_PRESS:
1717     case GDK_KEY_RELEASE:
1718       if (key_snoopers)
1719         {
1720           if (gtk_invoke_key_snoopers (grab_widget, event))
1721             break;
1722         }
1723       /* Catch alt press to enable auto-mnemonics;
1724        * menus are handled elsewhere
1725        */
1726       if ((event->key.keyval == GDK_KEY_Alt_L || event->key.keyval == GDK_KEY_Alt_R) &&
1727           !GTK_IS_MENU_SHELL (grab_widget))
1728         {
1729           gboolean auto_mnemonics;
1730
1731           g_object_get (gtk_widget_get_settings (grab_widget),
1732                         "gtk-auto-mnemonics", &auto_mnemonics, NULL);
1733
1734           if (auto_mnemonics)
1735             {
1736               gboolean mnemonics_visible;
1737               GtkWidget *window;
1738
1739               mnemonics_visible = (event->type == GDK_KEY_PRESS);
1740
1741               window = gtk_widget_get_toplevel (grab_widget);
1742
1743               if (GTK_IS_WINDOW (window))
1744                 gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
1745             }
1746         }
1747       /* else fall through */
1748     case GDK_MOTION_NOTIFY:
1749     case GDK_BUTTON_RELEASE:
1750     case GDK_PROXIMITY_IN:
1751     case GDK_PROXIMITY_OUT:
1752       gtk_propagate_event (grab_widget, event);
1753       break;
1754       
1755     case GDK_ENTER_NOTIFY:
1756       _gtk_widget_set_device_window (event_widget,
1757                                      gdk_event_get_device (event),
1758                                      event->any.window);
1759       if (gtk_widget_is_sensitive (grab_widget))
1760         gtk_widget_event (grab_widget, event);
1761       break;
1762       
1763     case GDK_LEAVE_NOTIFY:
1764       _gtk_widget_set_device_window (event_widget,
1765                                      gdk_event_get_device (event),
1766                                      NULL);
1767       if (gtk_widget_is_sensitive (grab_widget))
1768         gtk_widget_event (grab_widget, event);
1769       break;
1770       
1771     case GDK_DRAG_STATUS:
1772     case GDK_DROP_FINISHED:
1773       _gtk_drag_source_handle_event (event_widget, event);
1774       break;
1775     case GDK_DRAG_ENTER:
1776     case GDK_DRAG_LEAVE:
1777     case GDK_DRAG_MOTION:
1778     case GDK_DROP_START:
1779       _gtk_drag_dest_handle_event (event_widget, event);
1780       break;
1781     default:
1782       g_assert_not_reached ();
1783       break;
1784     }
1785
1786   if (event->type == GDK_ENTER_NOTIFY
1787       || event->type == GDK_LEAVE_NOTIFY
1788       || event->type == GDK_BUTTON_PRESS
1789       || event->type == GDK_2BUTTON_PRESS
1790       || event->type == GDK_3BUTTON_PRESS
1791       || event->type == GDK_KEY_PRESS
1792       || event->type == GDK_DRAG_ENTER
1793       || event->type == GDK_GRAB_BROKEN
1794       || event->type == GDK_MOTION_NOTIFY
1795       || event->type == GDK_SCROLL)
1796     {
1797       _gtk_tooltip_handle_event (event);
1798     }
1799   
1800   tmp_list = current_events;
1801   current_events = g_list_remove_link (current_events, tmp_list);
1802   g_list_free_1 (tmp_list);
1803
1804   if (rewritten_event)
1805     gdk_event_free (rewritten_event);
1806 }
1807
1808 gboolean
1809 gtk_true (void)
1810 {
1811   return TRUE;
1812 }
1813
1814 gboolean
1815 gtk_false (void)
1816 {
1817   return FALSE;
1818 }
1819
1820 static GtkWindowGroup *
1821 gtk_main_get_window_group (GtkWidget   *widget)
1822 {
1823   GtkWidget *toplevel = NULL;
1824
1825   if (widget)
1826     toplevel = gtk_widget_get_toplevel (widget);
1827
1828   if (GTK_IS_WINDOW (toplevel))
1829     return gtk_window_get_group (GTK_WINDOW (toplevel));
1830   else
1831     return gtk_window_get_group (NULL);
1832 }
1833
1834 typedef struct
1835 {
1836   GtkWidget *old_grab_widget;
1837   GtkWidget *new_grab_widget;
1838   gboolean   was_grabbed;
1839   gboolean   is_grabbed;
1840   gboolean   from_grab;
1841   GList     *notified_windows;
1842   GdkDevice *device;
1843 } GrabNotifyInfo;
1844
1845 static void
1846 synth_crossing_for_grab_notify (GtkWidget       *from,
1847                                 GtkWidget       *to,
1848                                 GrabNotifyInfo  *info,
1849                                 GList           *devices,
1850                                 GdkCrossingMode  mode)
1851 {
1852   while (devices)
1853     {
1854       GdkDevice *device = devices->data;
1855       GdkWindow *from_window, *to_window;
1856
1857       /* Do not propagate events more than once to
1858        * the same windows if non-multidevice aware.
1859        */
1860       if (!from)
1861         from_window = NULL;
1862       else
1863         {
1864           from_window = _gtk_widget_get_device_window (from, device);
1865
1866           if (from_window &&
1867               !gdk_window_get_support_multidevice (from_window) &&
1868               g_list_find (info->notified_windows, from_window))
1869             from_window = NULL;
1870         }
1871
1872       if (!to)
1873         to_window = NULL;
1874       else
1875         {
1876           to_window = _gtk_widget_get_device_window (to, device);
1877
1878           if (to_window &&
1879               !gdk_window_get_support_multidevice (to_window) &&
1880               g_list_find (info->notified_windows, to_window))
1881             to_window = NULL;
1882         }
1883
1884       if (from_window || to_window)
1885         {
1886           _gtk_widget_synthesize_crossing ((from_window) ? from : NULL,
1887                                            (to_window) ? to : NULL,
1888                                            device, mode);
1889
1890           if (from_window)
1891             info->notified_windows = g_list_prepend (info->notified_windows, from_window);
1892
1893           if (to_window)
1894             info->notified_windows = g_list_prepend (info->notified_windows, to_window);
1895         }
1896
1897       devices = devices->next;
1898     }
1899 }
1900
1901 static void
1902 gtk_grab_notify_foreach (GtkWidget *child,
1903                          gpointer   data)
1904 {
1905   GrabNotifyInfo *info = data;
1906   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1907   GList *devices;
1908
1909   was_grabbed = info->was_grabbed;
1910   is_grabbed = info->is_grabbed;
1911
1912   info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1913   info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1914
1915   was_shadowed = info->old_grab_widget && !info->was_grabbed;
1916   is_shadowed = info->new_grab_widget && !info->is_grabbed;
1917
1918   g_object_ref (child);
1919
1920   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1921     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1922
1923   if (info->device &&
1924       _gtk_widget_get_device_window (child, info->device))
1925     {
1926       /* Device specified and is on widget */
1927       devices = g_list_prepend (NULL, info->device);
1928     }
1929   else
1930     devices = _gtk_widget_list_devices (child);
1931
1932   if (is_shadowed)
1933     {
1934       GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
1935       if (!was_shadowed && devices &&
1936           gtk_widget_is_sensitive (child))
1937         synth_crossing_for_grab_notify (child, info->new_grab_widget,
1938                                         info, devices,
1939                                         GDK_CROSSING_GTK_GRAB);
1940     }
1941   else
1942     {
1943       GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
1944       if (was_shadowed && devices &&
1945           gtk_widget_is_sensitive (child))
1946         synth_crossing_for_grab_notify (info->old_grab_widget, child,
1947                                         info, devices,
1948                                         info->from_grab ? GDK_CROSSING_GTK_GRAB :
1949                                         GDK_CROSSING_GTK_UNGRAB);
1950     }
1951
1952   if (was_shadowed != is_shadowed)
1953     _gtk_widget_grab_notify (child, was_shadowed);
1954
1955   g_object_unref (child);
1956   g_list_free (devices);
1957
1958   info->was_grabbed = was_grabbed;
1959   info->is_grabbed = is_grabbed;
1960 }
1961
1962 static void
1963 gtk_grab_notify (GtkWindowGroup *group,
1964                  GdkDevice      *device,
1965                  GtkWidget      *old_grab_widget,
1966                  GtkWidget      *new_grab_widget,
1967                  gboolean        from_grab)
1968 {
1969   GList *toplevels;
1970   GrabNotifyInfo info = { 0 };
1971
1972   if (old_grab_widget == new_grab_widget)
1973     return;
1974
1975   info.old_grab_widget = old_grab_widget;
1976   info.new_grab_widget = new_grab_widget;
1977   info.from_grab = from_grab;
1978   info.device = device;
1979
1980   g_object_ref (group);
1981
1982   toplevels = gtk_window_list_toplevels ();
1983   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1984
1985   while (toplevels)
1986     {
1987       GtkWindow *toplevel = toplevels->data;
1988       toplevels = g_list_delete_link (toplevels, toplevels);
1989
1990       info.was_grabbed = FALSE;
1991       info.is_grabbed = FALSE;
1992
1993       if (group == gtk_window_get_group (toplevel))
1994         gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1995       g_object_unref (toplevel);
1996     }
1997
1998   g_list_free (info.notified_windows);
1999   g_object_unref (group);
2000 }
2001
2002 void
2003 gtk_grab_add (GtkWidget *widget)
2004 {
2005   GtkWindowGroup *group;
2006   GtkWidget *old_grab_widget;
2007   
2008   g_return_if_fail (widget != NULL);
2009   
2010   if (!gtk_widget_has_grab (widget) && gtk_widget_is_sensitive (widget))
2011     {
2012       _gtk_widget_set_has_grab (widget, TRUE);
2013       
2014       group = gtk_main_get_window_group (widget);
2015
2016       if (group->grabs)
2017         old_grab_widget = (GtkWidget *)group->grabs->data;
2018       else
2019         old_grab_widget = NULL;
2020
2021       g_object_ref (widget);
2022       group->grabs = g_slist_prepend (group->grabs, widget);
2023
2024       gtk_grab_notify (group, NULL, old_grab_widget, widget, TRUE);
2025     }
2026 }
2027
2028 GtkWidget*
2029 gtk_grab_get_current (void)
2030 {
2031   GtkWindowGroup *group;
2032
2033   group = gtk_main_get_window_group (NULL);
2034
2035   if (group->grabs)
2036     return GTK_WIDGET (group->grabs->data);
2037   return NULL;
2038 }
2039
2040 void
2041 gtk_grab_remove (GtkWidget *widget)
2042 {
2043   GtkWindowGroup *group;
2044   GtkWidget *new_grab_widget;
2045   
2046   g_return_if_fail (widget != NULL);
2047   
2048   if (gtk_widget_has_grab (widget))
2049     {
2050       _gtk_widget_set_has_grab (widget, FALSE);
2051
2052       group = gtk_main_get_window_group (widget);
2053       group->grabs = g_slist_remove (group->grabs, widget);
2054       
2055       if (group->grabs)
2056         new_grab_widget = (GtkWidget *)group->grabs->data;
2057       else
2058         new_grab_widget = NULL;
2059
2060       gtk_grab_notify (group, NULL, widget, new_grab_widget, FALSE);
2061       
2062       g_object_unref (widget);
2063     }
2064 }
2065
2066 /**
2067  * gtk_device_grab_add:
2068  * @widget: a #GtkWidget
2069  * @device: a #GtkDevice to grab on.
2070  * @block_others: %TRUE to prevent other devices to interact with @widget.
2071  *
2072  * Adds a GTK+ grab on @device, so all the events on @device and its
2073  * associated pointer or keyboard (if any) are delivered to @widget.
2074  * If the @block_others parameter is %TRUE, any other devices will be
2075  * unable to interact with @widget during the grab.
2076  *
2077  * Since: 3.0
2078  **/
2079 void
2080 gtk_device_grab_add (GtkWidget        *widget,
2081                      GdkDevice        *device,
2082                      gboolean          block_others)
2083 {
2084   GtkWindowGroup *group;
2085   GtkWidget *old_grab_widget;
2086
2087   g_return_if_fail (GTK_IS_WIDGET (widget));
2088   g_return_if_fail (GDK_IS_DEVICE (device));
2089
2090   group = gtk_main_get_window_group (widget);
2091   old_grab_widget = gtk_window_group_get_current_device_grab (group, device);
2092
2093   if (old_grab_widget != widget)
2094     _gtk_window_group_add_device_grab (group, widget, device, block_others);
2095
2096   gtk_grab_notify (group, device, old_grab_widget, widget, TRUE);
2097 }
2098
2099 /**
2100  * gtk_device_grab_remove:
2101  * @widget: a #GtkWidget
2102  * @device: a #GdkDevice
2103  *
2104  * Removes a device grab from the given widget. You have to pair calls
2105  * to gtk_device_grab_add() and gtk_device_grab_remove().
2106  *
2107  * Since: 3.0
2108  **/
2109 void
2110 gtk_device_grab_remove (GtkWidget *widget,
2111                         GdkDevice *device)
2112 {
2113   GtkWindowGroup *group;
2114   GtkWidget *new_grab_widget;
2115
2116   g_return_if_fail (GTK_IS_WIDGET (widget));
2117   g_return_if_fail (GDK_IS_DEVICE (device));
2118
2119   group = gtk_main_get_window_group (widget);
2120   _gtk_window_group_remove_device_grab (group, widget, device);
2121   new_grab_widget = gtk_window_group_get_current_device_grab (group, device);
2122
2123   gtk_grab_notify (group, device, widget, new_grab_widget, FALSE);
2124 }
2125
2126 void
2127 gtk_init_add (GtkFunction function,
2128               gpointer    data)
2129 {
2130   GtkInitFunction *init;
2131   
2132   init = g_new (GtkInitFunction, 1);
2133   init->function = function;
2134   init->data = data;
2135   
2136   init_functions = g_list_prepend (init_functions, init);
2137 }
2138
2139 guint
2140 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
2141                          gpointer        func_data)
2142 {
2143   GtkKeySnooperData *data;
2144   static guint snooper_id = 1;
2145
2146   g_return_val_if_fail (snooper != NULL, 0);
2147
2148   data = g_new (GtkKeySnooperData, 1);
2149   data->func = snooper;
2150   data->func_data = func_data;
2151   data->id = snooper_id++;
2152   key_snoopers = g_slist_prepend (key_snoopers, data);
2153
2154   return data->id;
2155 }
2156
2157 void
2158 gtk_key_snooper_remove (guint snooper_id)
2159 {
2160   GtkKeySnooperData *data = NULL;
2161   GSList *slist;
2162
2163   slist = key_snoopers;
2164   while (slist)
2165     {
2166       data = slist->data;
2167       if (data->id == snooper_id)
2168         break;
2169
2170       slist = slist->next;
2171       data = NULL;
2172     }
2173   if (data)
2174     {
2175       key_snoopers = g_slist_remove (key_snoopers, data);
2176       g_free (data);
2177     }
2178 }
2179
2180 static gint
2181 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
2182                          GdkEvent  *event)
2183 {
2184   GSList *slist;
2185   gint return_val = FALSE;
2186
2187   slist = key_snoopers;
2188   while (slist && !return_val)
2189     {
2190       GtkKeySnooperData *data;
2191
2192       data = slist->data;
2193       slist = slist->next;
2194       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
2195     }
2196
2197   return return_val;
2198 }
2199
2200 guint
2201 gtk_quit_add_full (guint                main_level,
2202                    GtkFunction          function,
2203                    GtkCallbackMarshal   marshal,
2204                    gpointer             data,
2205                    GDestroyNotify       destroy)
2206 {
2207   static guint quit_id = 1;
2208   GtkQuitFunction *quitf;
2209   
2210   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
2211
2212   quitf = g_slice_new (GtkQuitFunction);
2213   
2214   quitf->id = quit_id++;
2215   quitf->main_level = main_level;
2216   quitf->function = function;
2217   quitf->marshal = marshal;
2218   quitf->data = data;
2219   quitf->destroy = destroy;
2220
2221   quit_functions = g_list_prepend (quit_functions, quitf);
2222   
2223   return quitf->id;
2224 }
2225
2226 static void
2227 gtk_quit_destroy (GtkQuitFunction *quitf)
2228 {
2229   if (quitf->destroy)
2230     quitf->destroy (quitf->data);
2231   g_slice_free (GtkQuitFunction, quitf);
2232 }
2233
2234 static gint
2235 gtk_quit_destructor (GtkObject **object_p)
2236 {
2237   if (*object_p)
2238     gtk_object_destroy (*object_p);
2239   g_free (object_p);
2240
2241   return FALSE;
2242 }
2243
2244 void
2245 gtk_quit_add_destroy (guint              main_level,
2246                       GtkObject         *object)
2247 {
2248   GtkObject **object_p;
2249
2250   g_return_if_fail (main_level > 0);
2251   g_return_if_fail (GTK_IS_OBJECT (object));
2252
2253   object_p = g_new (GtkObject*, 1);
2254   *object_p = object;
2255   g_signal_connect (object,
2256                     "destroy",
2257                     G_CALLBACK (gtk_widget_destroyed),
2258                     object_p);
2259   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
2260 }
2261
2262 guint
2263 gtk_quit_add (guint       main_level,
2264               GtkFunction function,
2265               gpointer    data)
2266 {
2267   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
2268 }
2269
2270 void
2271 gtk_quit_remove (guint id)
2272 {
2273   GtkQuitFunction *quitf;
2274   GList *tmp_list;
2275   
2276   tmp_list = quit_functions;
2277   while (tmp_list)
2278     {
2279       quitf = tmp_list->data;
2280       
2281       if (quitf->id == id)
2282         {
2283           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2284           g_list_free (tmp_list);
2285           gtk_quit_destroy (quitf);
2286           
2287           return;
2288         }
2289       
2290       tmp_list = tmp_list->next;
2291     }
2292 }
2293
2294 void
2295 gtk_quit_remove_by_data (gpointer data)
2296 {
2297   GtkQuitFunction *quitf;
2298   GList *tmp_list;
2299   
2300   tmp_list = quit_functions;
2301   while (tmp_list)
2302     {
2303       quitf = tmp_list->data;
2304       
2305       if (quitf->data == data)
2306         {
2307           quit_functions = g_list_remove_link (quit_functions, tmp_list);
2308           g_list_free (tmp_list);
2309           gtk_quit_destroy (quitf);
2310
2311           return;
2312         }
2313       
2314       tmp_list = tmp_list->next;
2315     }
2316 }
2317
2318 /**
2319  * gtk_get_current_event:
2320  * 
2321  * Obtains a copy of the event currently being processed by GTK+.  For
2322  * example, if you get a "clicked" signal from #GtkButton, the current
2323  * event will be the #GdkEventButton that triggered the "clicked"
2324  * signal. The returned event must be freed with gdk_event_free().
2325  * If there is no current event, the function returns %NULL.
2326  * 
2327  * Return value: a copy of the current event, or %NULL if no current event.
2328  **/
2329 GdkEvent*
2330 gtk_get_current_event (void)
2331 {
2332   if (current_events)
2333     return gdk_event_copy (current_events->data);
2334   else
2335     return NULL;
2336 }
2337
2338 /**
2339  * gtk_get_current_event_time:
2340  * 
2341  * If there is a current event and it has a timestamp, return that
2342  * timestamp, otherwise return %GDK_CURRENT_TIME.
2343  * 
2344  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2345  **/
2346 guint32
2347 gtk_get_current_event_time (void)
2348 {
2349   if (current_events)
2350     return gdk_event_get_time (current_events->data);
2351   else
2352     return GDK_CURRENT_TIME;
2353 }
2354
2355 /**
2356  * gtk_get_current_event_state:
2357  * @state: a location to store the state of the current event
2358  * 
2359  * If there is a current event and it has a state field, place
2360  * that state field in @state and return %TRUE, otherwise return
2361  * %FALSE.
2362  * 
2363  * Return value: %TRUE if there was a current event and it had a state field
2364  **/
2365 gboolean
2366 gtk_get_current_event_state (GdkModifierType *state)
2367 {
2368   g_return_val_if_fail (state != NULL, FALSE);
2369   
2370   if (current_events)
2371     return gdk_event_get_state (current_events->data, state);
2372   else
2373     {
2374       *state = 0;
2375       return FALSE;
2376     }
2377 }
2378
2379 /**
2380  * gtk_get_current_event_device:
2381  *
2382  * If there is a current event and it has a device, return that
2383  * device, otherwise return %NULL.
2384  *
2385  * Returns: a #GdkDevice, or %NULL
2386  **/
2387 GdkDevice *
2388 gtk_get_current_event_device (void)
2389 {
2390   if (current_events)
2391     return gdk_event_get_device (current_events->data);
2392   else
2393     return NULL;
2394 }
2395
2396 /**
2397  * gtk_get_event_widget:
2398  * @event: a #GdkEvent
2399  *
2400  * If @event is %NULL or the event was not associated with any widget,
2401  * returns %NULL, otherwise returns the widget that received the event
2402  * originally.
2403  * 
2404  * Return value: the widget that originally received @event, or %NULL
2405  **/
2406 GtkWidget*
2407 gtk_get_event_widget (GdkEvent *event)
2408 {
2409   GtkWidget *widget;
2410   gpointer widget_ptr;
2411
2412   widget = NULL;
2413   if (event && event->any.window && 
2414       (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
2415     {
2416       gdk_window_get_user_data (event->any.window, &widget_ptr);
2417       widget = widget_ptr;
2418     }
2419   
2420   return widget;
2421 }
2422
2423 static gint
2424 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2425 {
2426   if (!quitf->marshal)
2427     return quitf->function (quitf->data);
2428   else
2429     {
2430       GtkArg args[1];
2431       gint ret_val = FALSE;
2432
2433       args[0].name = NULL;
2434       args[0].type = G_TYPE_BOOLEAN;
2435       args[0].d.pointer_data = &ret_val;
2436       ((GtkCallbackMarshal) quitf->marshal) (NULL,
2437                                              quitf->data,
2438                                              0, args);
2439       return ret_val;
2440     }
2441 }
2442
2443 /**
2444  * gtk_propagate_event:
2445  * @widget: a #GtkWidget
2446  * @event: an event
2447  *
2448  * Sends an event to a widget, propagating the event to parent widgets
2449  * if the event remains unhandled. Events received by GTK+ from GDK
2450  * normally begin in gtk_main_do_event(). Depending on the type of
2451  * event, existence of modal dialogs, grabs, etc., the event may be
2452  * propagated; if so, this function is used. gtk_propagate_event()
2453  * calls gtk_widget_event() on each widget it decides to send the
2454  * event to.  So gtk_widget_event() is the lowest-level function; it
2455  * simply emits the "event" and possibly an event-specific signal on a
2456  * widget.  gtk_propagate_event() is a bit higher-level, and
2457  * gtk_main_do_event() is the highest level.
2458  *
2459  * All that said, you most likely don't want to use any of these
2460  * functions; synthesizing events is rarely needed. Consider asking on
2461  * the mailing list for better ways to achieve your goals. For
2462  * example, use gdk_window_invalidate_rect() or
2463  * gtk_widget_queue_draw() instead of making up expose events.
2464  * 
2465  **/
2466 void
2467 gtk_propagate_event (GtkWidget *widget,
2468                      GdkEvent  *event)
2469 {
2470   gint handled_event;
2471   
2472   g_return_if_fail (GTK_IS_WIDGET (widget));
2473   g_return_if_fail (event != NULL);
2474   
2475   handled_event = FALSE;
2476
2477   g_object_ref (widget);
2478       
2479   if ((event->type == GDK_KEY_PRESS) ||
2480       (event->type == GDK_KEY_RELEASE))
2481     {
2482       /* Only send key events within Window widgets to the Window
2483        *  The Window widget will in turn pass the
2484        *  key event on to the currently focused widget
2485        *  for that window.
2486        */
2487       GtkWidget *window;
2488
2489       window = gtk_widget_get_toplevel (widget);
2490       if (GTK_IS_WINDOW (window))
2491         {
2492           /* If there is a grab within the window, give the grab widget
2493            * a first crack at the key event
2494            */
2495           if (widget != window && gtk_widget_has_grab (widget))
2496             handled_event = gtk_widget_event (widget, event);
2497           
2498           if (!handled_event)
2499             {
2500               window = gtk_widget_get_toplevel (widget);
2501               if (GTK_IS_WINDOW (window))
2502                 {
2503                   if (gtk_widget_is_sensitive (window))
2504                     gtk_widget_event (window, event);
2505                 }
2506             }
2507                   
2508           handled_event = TRUE; /* don't send to widget */
2509         }
2510     }
2511   
2512   /* Other events get propagated up the widget tree
2513    *  so that parents can see the button and motion
2514    *  events of the children.
2515    */
2516   if (!handled_event)
2517     {
2518       while (TRUE)
2519         {
2520           GtkWidget *tmp;
2521
2522           /* Scroll events are special cased here because it
2523            * feels wrong when scrolling a GtkViewport, say,
2524            * to have children of the viewport eat the scroll
2525            * event
2526            */
2527           if (!gtk_widget_is_sensitive (widget))
2528             handled_event = event->type != GDK_SCROLL;
2529           else
2530             handled_event = gtk_widget_event (widget, event);
2531
2532           tmp = gtk_widget_get_parent (widget);
2533           g_object_unref (widget);
2534
2535           widget = tmp;
2536           
2537           if (!handled_event && widget)
2538             g_object_ref (widget);
2539           else
2540             break;
2541         }
2542     }
2543   else
2544     g_object_unref (widget);
2545 }
2546
2547 gboolean
2548 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2549                                   GValue                *return_accu,
2550                                   const GValue          *handler_return,
2551                                   gpointer               dummy)
2552 {
2553   gboolean continue_emission;
2554   gboolean signal_handled;
2555   
2556   signal_handled = g_value_get_boolean (handler_return);
2557   g_value_set_boolean (return_accu, signal_handled);
2558   continue_emission = !signal_handled;
2559   
2560   return continue_emission;
2561 }