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