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