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