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