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