]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
Set translation domain for parameter_string in gtk_init_with_args
[~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 const guint gtk_major_version = GTK_MAJOR_VERSION;
183 const guint gtk_minor_version = GTK_MINOR_VERSION;
184 const guint gtk_micro_version = GTK_MICRO_VERSION;
185 const guint gtk_binary_age = GTK_BINARY_AGE;
186 const guint gtk_interface_age = GTK_INTERFACE_AGE;
187
188 static guint gtk_main_loop_level = 0;
189 static gint pre_initialized = FALSE;
190 static gint gtk_initialized = FALSE;
191 static GList *current_events = NULL;
192
193 static GSList *main_loops = NULL;      /* stack of currently executing main loops */
194
195 static GList *init_functions = NULL;       /* A list of init functions.
196                                             */
197 static GList *quit_functions = NULL;       /* A list of quit functions.
198                                             */
199 static GSList *key_snoopers = NULL;
200
201 guint gtk_debug_flags = 0;                 /* Global GTK debug flag */
202
203 #ifdef G_ENABLE_DEBUG
204 static const GDebugKey gtk_debug_keys[] = {
205   {"misc", GTK_DEBUG_MISC},
206   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
207   {"text", GTK_DEBUG_TEXT},
208   {"tree", GTK_DEBUG_TREE},
209   {"updates", GTK_DEBUG_UPDATES},
210   {"keybindings", GTK_DEBUG_KEYBINDINGS},
211   {"multihead", GTK_DEBUG_MULTIHEAD},
212   {"modules", GTK_DEBUG_MODULES},
213   {"geometry", GTK_DEBUG_GEOMETRY},
214   {"icontheme", GTK_DEBUG_ICONTHEME},
215   {"printing", GTK_DEBUG_PRINTING},
216   {"builder", GTK_DEBUG_BUILDER},
217   {"size-request", GTK_DEBUG_SIZE_REQUEST},
218 };
219 #endif /* G_ENABLE_DEBUG */
220
221 /**
222  * gtk_check_version:
223  * @required_major: the required major version.
224  * @required_minor: the required minor version.
225  * @required_micro: the required micro version.
226  * 
227  * Checks that the GTK+ library in use is compatible with the
228  * given version. Generally you would pass in the constants
229  * #GTK_MAJOR_VERSION, #GTK_MINOR_VERSION, #GTK_MICRO_VERSION
230  * as the three arguments to this function; that produces
231  * a check that the library in use is compatible with
232  * the version of GTK+ the application or module was compiled
233  * against.
234  *
235  * Compatibility is defined by two things: first the version
236  * of the running library is newer than the version
237  * @required_major.required_minor.@required_micro. Second
238  * the running library must be binary compatible with the
239  * version @required_major.required_minor.@required_micro
240  * (same major version.)
241  *
242  * This function is primarily for GTK+ modules; the module
243  * can call this function to check that it wasn't loaded
244  * into an incompatible version of GTK+. However, such a
245  * a check isn't completely reliable, since the module may be
246  * linked against an old version of GTK+ and calling the
247  * old version of gtk_check_version(), but still get loaded
248  * into an application using a newer version of GTK+.
249  *
250  * Return value: %NULL if the GTK+ library is compatible with the
251  *   given version, or a string describing the version mismatch.
252  *   The returned string is owned by GTK+ and should not be modified
253  *   or freed.
254  **/
255 const gchar*
256 gtk_check_version (guint required_major,
257                    guint required_minor,
258                    guint required_micro)
259 {
260   gint gtk_effective_micro = 100 * GTK_MINOR_VERSION + GTK_MICRO_VERSION;
261   gint required_effective_micro = 100 * required_minor + required_micro;
262
263   if (required_major > GTK_MAJOR_VERSION)
264     return "Gtk+ version too old (major mismatch)";
265   if (required_major < GTK_MAJOR_VERSION)
266     return "Gtk+ version too new (major mismatch)";
267   if (required_effective_micro < gtk_effective_micro - GTK_BINARY_AGE)
268     return "Gtk+ version too new (micro mismatch)";
269   if (required_effective_micro > gtk_effective_micro)
270     return "Gtk+ version too old (micro mismatch)";
271   return NULL;
272 }
273
274 /* This checks to see if the process is running suid or sgid
275  * at the current time. If so, we don't allow GTK+ to be initialized.
276  * This is meant to be a mild check - we only error out if we
277  * can prove the programmer is doing something wrong, not if
278  * they could be doing something wrong. For this reason, we
279  * don't use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
280  */
281 static gboolean
282 check_setugid (void)
283 {
284 /* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
285 #ifndef G_OS_WIN32
286   uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
287   gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
288   
289 #ifdef HAVE_GETRESUID
290   /* These aren't in the header files, so we prototype them here.
291    */
292   int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
293   int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
294
295   if (getresuid (&ruid, &euid, &suid) != 0 ||
296       getresgid (&rgid, &egid, &sgid) != 0)
297 #endif /* HAVE_GETRESUID */
298     {
299       suid = ruid = getuid ();
300       sgid = rgid = getgid ();
301       euid = geteuid ();
302       egid = getegid ();
303     }
304
305   if (ruid != euid || ruid != suid ||
306       rgid != egid || rgid != sgid)
307     {
308       g_warning ("This process is currently running setuid or setgid.\n"
309                  "This is not a supported use of GTK+. You must create a helper\n"
310                  "program instead. For further details, see:\n\n"
311                  "    http://www.gtk.org/setuid.html\n\n"
312                  "Refusing to initialize GTK+.");
313       exit (1);
314     }
315 #endif
316   return TRUE;
317 }
318
319 #ifdef G_OS_WIN32
320
321 const gchar *
322 _gtk_get_datadir (void)
323 {
324   static char *gtk_datadir = NULL;
325   if (gtk_datadir == NULL)
326     {
327       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
328       gtk_datadir = g_build_filename (root, "share", NULL);
329       g_free (root);
330     }
331
332   return gtk_datadir;
333 }
334
335 const gchar *
336 _gtk_get_sysconfdir (void)
337 {
338   static char *gtk_sysconfdir = NULL;
339   if (gtk_sysconfdir == NULL)
340     {
341       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
342       gtk_sysconfdir = g_build_filename (root, "etc", NULL);
343       g_free (root);
344     }
345
346   return gtk_sysconfdir;
347 }
348
349 const gchar *
350 _gtk_get_data_prefix (void)
351 {
352   static char *gtk_data_prefix = NULL;
353   if (gtk_data_prefix == NULL)
354     gtk_data_prefix = g_win32_get_package_installation_directory_of_module (gtk_dll);
355
356   return gtk_data_prefix;
357 }
358
359 #endif /* G_OS_WIN32 */
360
361 static gboolean do_setlocale = TRUE;
362
363 /**
364  * gtk_disable_setlocale:
365  * 
366  * Prevents gtk_init(), gtk_init_check(), gtk_init_with_args() and
367  * gtk_parse_args() from automatically
368  * calling <literal>setlocale (LC_ALL, "")</literal>. You would 
369  * want to use this function if you wanted to set the locale for 
370  * your program to something other than the user's locale, or if 
371  * you wanted to set different values for different locale categories.
372  *
373  * Most programs should not need to call this function.
374  **/
375 void
376 gtk_disable_setlocale (void)
377 {
378   if (pre_initialized)
379     g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
380     
381   do_setlocale = FALSE;
382 }
383
384 #ifdef G_PLATFORM_WIN32
385 #undef gtk_init_check
386 #endif
387
388 static GString *gtk_modules_string = NULL;
389 static gboolean g_fatal_warnings = FALSE;
390
391 #ifdef G_ENABLE_DEBUG
392 static gboolean
393 gtk_arg_debug_cb (const char *key, const char *value, gpointer user_data)
394 {
395   gtk_debug_flags |= g_parse_debug_string (value,
396                                            gtk_debug_keys,
397                                            G_N_ELEMENTS (gtk_debug_keys));
398
399   return TRUE;
400 }
401
402 static gboolean
403 gtk_arg_no_debug_cb (const char *key, const char *value, gpointer user_data)
404 {
405   gtk_debug_flags &= ~g_parse_debug_string (value,
406                                             gtk_debug_keys,
407                                             G_N_ELEMENTS (gtk_debug_keys));
408
409   return TRUE;
410 }
411 #endif /* G_ENABLE_DEBUG */
412
413 static gboolean
414 gtk_arg_module_cb (const char *key, const char *value, gpointer user_data)
415 {
416   if (value && *value)
417     {
418       if (gtk_modules_string)
419         g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
420       else
421         gtk_modules_string = g_string_new (NULL);
422       
423       g_string_append (gtk_modules_string, value);
424     }
425
426   return TRUE;
427 }
428
429 static const GOptionEntry gtk_args[] = {
430   { "gtk-module",       0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_module_cb,   
431     /* Description of --gtk-module=MODULES in --help output */ N_("Load additional GTK+ modules"), 
432     /* Placeholder in --gtk-module=MODULES in --help output */ N_("MODULES") },
433   { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, 
434     /* Description of --g-fatal-warnings in --help output */   N_("Make all warnings fatal"), NULL },
435 #ifdef G_ENABLE_DEBUG
436   { "gtk-debug",        0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_debug_cb,    
437     /* Description of --gtk-debug=FLAGS in --help output */    N_("GTK+ debugging flags to set"), 
438     /* Placeholder in --gtk-debug=FLAGS in --help output */    N_("FLAGS") },
439   { "gtk-no-debug",     0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_no_debug_cb, 
440     /* Description of --gtk-no-debug=FLAGS in --help output */ N_("GTK+ debugging flags to unset"), 
441     /* Placeholder in --gtk-no-debug=FLAGS in --help output */ N_("FLAGS") },
442 #endif 
443   { NULL }
444 };
445
446 #ifdef G_OS_WIN32
447
448 static char *iso639_to_check = NULL;
449 static char *iso3166_to_check = NULL;
450 static char *script_to_check = NULL;
451 static gboolean setlocale_called = FALSE;
452
453 static BOOL CALLBACK
454 enum_locale_proc (LPTSTR locale)
455 {
456   LCID lcid;
457   char iso639[10];
458   char iso3166[10];
459   char *endptr;
460
461
462   lcid = strtoul (locale, &endptr, 16);
463   if (*endptr == '\0' &&
464       GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) &&
465       GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
466     {
467       if (strcmp (iso639, iso639_to_check) == 0 &&
468           ((iso3166_to_check != NULL &&
469             strcmp (iso3166, iso3166_to_check) == 0) ||
470            (iso3166_to_check == NULL &&
471             SUBLANGID (LANGIDFROMLCID (lcid)) == SUBLANG_DEFAULT)))
472         {
473           char language[100], country[100];
474           char locale[300];
475
476           if (script_to_check != NULL)
477             {
478               /* If lcid is the "other" script for this language,
479                * return TRUE, i.e. continue looking.
480                */
481               if (strcmp (script_to_check, "Latn") == 0)
482                 {
483                   switch (LANGIDFROMLCID (lcid))
484                     {
485                     case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_CYRILLIC):
486                       return TRUE;
487                     case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC):
488                       return TRUE;
489                     case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC):
490                       return TRUE;
491                     case MAKELANGID (LANG_SERBIAN, 0x07):
492                       /* Serbian in Bosnia and Herzegovina, Cyrillic */
493                       return TRUE;
494                     }
495                 }
496               else if (strcmp (script_to_check, "Cyrl") == 0)
497                 {
498                   switch (LANGIDFROMLCID (lcid))
499                     {
500                     case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_LATIN):
501                       return TRUE;
502                     case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_LATIN):
503                       return TRUE;
504                     case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_LATIN):
505                       return TRUE;
506                     case MAKELANGID (LANG_SERBIAN, 0x06):
507                       /* Serbian in Bosnia and Herzegovina, Latin */
508                       return TRUE;
509                     }
510                 }
511             }
512
513           SetThreadLocale (lcid);
514
515           if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, language, sizeof (language)) &&
516               GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, country, sizeof (country)))
517             {
518               strcpy (locale, language);
519               strcat (locale, "_");
520               strcat (locale, country);
521
522               if (setlocale (LC_ALL, locale) != NULL)
523                 setlocale_called = TRUE;
524             }
525
526           return FALSE;
527         }
528     }
529
530   return TRUE;
531 }
532   
533 #endif
534
535 static void
536 setlocale_initialization (void)
537 {
538   static gboolean initialized = FALSE;
539
540   if (initialized)
541     return;
542   initialized = TRUE;
543
544   if (do_setlocale)
545     {
546 #ifdef G_OS_WIN32
547       /* If some of the POSIXish environment variables are set, set
548        * the Win32 thread locale correspondingly.
549        */ 
550       char *p = getenv ("LC_ALL");
551       if (p == NULL)
552         p = getenv ("LANG");
553
554       if (p != NULL)
555         {
556           p = g_strdup (p);
557           if (strcmp (p, "C") == 0)
558             SetThreadLocale (LOCALE_SYSTEM_DEFAULT);
559           else
560             {
561               /* Check if one of the supported locales match the
562                * environment variable. If so, use that locale.
563                */
564               iso639_to_check = p;
565               iso3166_to_check = strchr (iso639_to_check, '_');
566               if (iso3166_to_check != NULL)
567                 {
568                   *iso3166_to_check++ = '\0';
569
570                   script_to_check = strchr (iso3166_to_check, '@');
571                   if (script_to_check != NULL)
572                     *script_to_check++ = '\0';
573
574                   /* Handle special cases. */
575                   
576                   /* The standard code for Serbia and Montenegro was
577                    * "CS", but MSFT uses for some reason "SP". By now
578                    * (October 2006), SP has split into two, "RS" and
579                    * "ME", but don't bother trying to handle those
580                    * yet. Do handle the even older "YU", though.
581                    */
582                   if (strcmp (iso3166_to_check, "CS") == 0 ||
583                       strcmp (iso3166_to_check, "YU") == 0)
584                     iso3166_to_check = "SP";
585                 }
586               else
587                 {
588                   script_to_check = strchr (iso639_to_check, '@');
589                   if (script_to_check != NULL)
590                     *script_to_check++ = '\0';
591                   /* LANG_SERBIAN == LANG_CROATIAN, recognize just "sr" */
592                   if (strcmp (iso639_to_check, "sr") == 0)
593                     iso3166_to_check = "SP";
594                 }
595
596               EnumSystemLocales (enum_locale_proc, LCID_SUPPORTED);
597             }
598           g_free (p);
599         }
600       if (!setlocale_called)
601         setlocale (LC_ALL, "");
602 #else
603       if (!setlocale (LC_ALL, ""))
604         g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
605 #endif
606     }
607 }
608
609 static void
610 check_mixed_deps (void)
611 {
612   GModule *module;
613   gpointer func;
614
615   module = g_module_open (NULL, 0);
616
617   if (g_module_symbol (module, "gtk_progress_get_type", &func))
618     {
619       g_error ("GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported");
620     }
621
622   g_module_close (module);
623 }
624
625 static void
626 do_pre_parse_initialization (int    *argc,
627                              char ***argv)
628 {
629   const gchar *env_string;
630   
631   if (pre_initialized)
632     return;
633
634   pre_initialized = TRUE;
635
636   check_mixed_deps ();
637
638   gdk_pre_parse_libgtk_only ();
639   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
640   
641 #ifdef G_ENABLE_DEBUG
642   env_string = g_getenv ("GTK_DEBUG");
643   if (env_string != NULL)
644     {
645       gtk_debug_flags = g_parse_debug_string (env_string,
646                                               gtk_debug_keys,
647                                               G_N_ELEMENTS (gtk_debug_keys));
648       env_string = NULL;
649     }
650 #endif  /* G_ENABLE_DEBUG */
651
652   env_string = g_getenv ("GTK_MODULES");
653   if (env_string)
654     gtk_modules_string = g_string_new (env_string);
655 }
656
657 static void
658 gettext_initialization (void)
659 {
660   setlocale_initialization ();
661
662 #ifdef ENABLE_NLS
663   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
664   bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
665 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
666   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
667   bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", "UTF-8");
668 #    endif
669 #endif  
670 }
671
672 static void
673 do_post_parse_initialization (int    *argc,
674                               char ***argv)
675 {
676   if (gtk_initialized)
677     return;
678
679   gettext_initialization ();
680
681 #ifdef SIGPIPE
682   signal (SIGPIPE, SIG_IGN);
683 #endif
684
685   if (g_fatal_warnings)
686     {
687       GLogLevelFlags fatal_mask;
688
689       fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
690       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
691       g_log_set_always_fatal (fatal_mask);
692     }
693
694   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
695     gdk_window_set_debug_updates (TRUE);
696
697   {
698   /* Translate to default:RTL if you want your widgets
699    * to be RTL, otherwise translate to default:LTR.
700    * Do *not* translate it to "predefinito:LTR", if it
701    * it isn't default:LTR or default:RTL it will not work 
702    */
703     char *e = _("default:LTR");
704     if (strcmp (e, "default:RTL")==0) 
705       gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
706     else if (strcmp (e, "default:LTR"))
707       g_warning ("Whoever translated default:LTR did so wrongly.\n");
708   }
709
710   /* do what the call to gtk_type_init() used to do */
711   g_type_init ();
712
713   _gtk_accel_map_init ();
714   _gtk_rc_init ();
715
716   /* Set the 'initialized' flag.
717    */
718   gtk_initialized = TRUE;
719
720   /* load gtk modules */
721   if (gtk_modules_string)
722     {
723       _gtk_modules_init (argc, argv, gtk_modules_string->str);
724       g_string_free (gtk_modules_string, TRUE);
725     }
726   else
727     {
728       _gtk_modules_init (argc, argv, NULL);
729     }
730 }
731
732
733 typedef struct
734 {
735   gboolean open_default_display;
736 } OptionGroupInfo;
737
738 static gboolean
739 pre_parse_hook (GOptionContext *context,
740                 GOptionGroup   *group,
741                 gpointer        data,
742                 GError        **error)
743 {
744   do_pre_parse_initialization (NULL, NULL);
745   
746   return TRUE;
747 }
748
749 static gboolean
750 post_parse_hook (GOptionContext *context,
751                  GOptionGroup   *group,
752                  gpointer       data,
753                  GError        **error)
754 {
755   OptionGroupInfo *info = data;
756
757   
758   do_post_parse_initialization (NULL, NULL);
759   
760   if (info->open_default_display)
761     {
762       if (gdk_display_open_default_libgtk_only () == NULL)
763         {
764           const char *display_name = gdk_get_display_arg_name ();
765           g_set_error (error, 
766                        G_OPTION_ERROR, 
767                        G_OPTION_ERROR_FAILED,
768                        _("Cannot open display: %s"),
769                        display_name ? display_name : "" );
770           
771           return FALSE;
772         }
773     }
774
775   return TRUE;
776 }
777
778
779 /**
780  * gtk_get_option_group:
781  * @open_default_display: whether to open the default display 
782  *    when parsing the commandline arguments
783  * 
784  * Returns a #GOptionGroup for the commandline arguments recognized
785  * by GTK+ and GDK. You should add this group to your #GOptionContext 
786  * with g_option_context_add_group(), if you are using 
787  * g_option_context_parse() to parse your commandline arguments.
788  *
789  * Returns: a #GOptionGroup for the commandline arguments recognized
790  *   by GTK+
791  *
792  * Since: 2.6
793  */
794 GOptionGroup *
795 gtk_get_option_group (gboolean open_default_display)
796 {
797   GOptionGroup *group;
798   OptionGroupInfo *info;
799
800   gettext_initialization ();
801
802   info = g_new0 (OptionGroupInfo, 1);
803   info->open_default_display = open_default_display;
804   
805   group = g_option_group_new ("gtk", _("GTK+ Options"), _("Show GTK+ Options"), info, g_free);
806   g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
807
808   gdk_add_option_entries_libgtk_only (group);
809   g_option_group_add_entries (group, gtk_args);
810   g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
811   
812   return group;
813 }
814
815 /**
816  * gtk_init_with_args:
817  * @argc: a pointer to the number of command line arguments.
818  * @argv: a pointer to the array of command line arguments.
819  * @parameter_string: a string which is displayed in
820  *    the first line of <option>--help</option> output, after
821  *    <literal><replaceable>programname</replaceable> [OPTION...]</literal>
822  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
823  *    describing the options of your program
824  * @translation_domain: a translation domain to use for translating
825  *    the <option>--help</option> output for the options in @entries
826  *    and the @parameter_string with gettext(), or %NULL
827  * @error: a return location for errors
828  *
829  * This function does the same work as gtk_init_check().
830  * Additionally, it allows you to add your own commandline options,
831  * and it automatically generates nicely formatted
832  * <option>--help</option> output. Note that your program will
833  * be terminated after writing out the help output.
834  *
835  * Returns: %TRUE if the GUI has been successfully initialized,
836  *               %FALSE otherwise.
837  *
838  * Since: 2.6
839  */
840 gboolean
841 gtk_init_with_args (gint                 *argc,
842                     gchar              ***argv,
843                     const gchar          *parameter_string,
844                     const GOptionEntry   *entries,
845                     const gchar          *translation_domain,
846                     GError              **error)
847 {
848   GOptionContext *context;
849   GOptionGroup *gtk_group;
850   gboolean retval;
851
852   if (gtk_initialized)
853     return gdk_display_open_default_libgtk_only () != NULL;
854
855   gettext_initialization ();
856
857   if (!check_setugid ())
858     return FALSE;
859
860   gtk_group = gtk_get_option_group (TRUE);
861
862   context = g_option_context_new (parameter_string);
863   g_option_context_add_group (context, gtk_group);
864   g_option_context_set_translation_domain (context, translation_domain);
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 }