]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
Fixes for uninstalled operation with module suffixes other than .so and in
[~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 /* Like g_module_path, but use .la as the suffix
381  */
382 static gchar*
383 module_build_la_path (const gchar *directory,
384                       const gchar *module_name)
385 {
386         gchar *filename;
387         gchar *result;
388         
389         if (strncmp (module_name, "lib", 3) == 0)
390                 filename = (gchar *)module_name;
391         else
392                 filename =  g_strconcat ("lib", module_name, ".la", NULL);
393
394         if (directory && *directory)
395                 result = g_build_filename (directory, filename, NULL);
396         else
397                 result = g_strdup (filename);
398
399         if (filename != module_name)
400                 g_free (filename);
401
402         return result;
403 }
404
405 /**
406  * _gtk_find_module:
407  * @name: the name of the module
408  * @type: the type of the module, for instance 'modules', 'engines', immodules'
409  * 
410  * Looks for a dynamically module named @name of type @type in the standard GTK+
411  *  module search path.
412  * 
413  * Return value: the pathname to the found module, or %NULL if it wasn't found.
414  *  Free with g_free().
415  **/
416 gchar *
417 _gtk_find_module (const gchar *name,
418                   const gchar *type)
419 {
420   gchar **paths;
421   gchar **path;
422   gchar *module_name = NULL;
423
424   if (g_path_is_absolute (name))
425     return g_strdup (name);
426
427   paths = _gtk_get_module_path (type);
428   for (path = paths; *path; path++)
429     {
430       gchar *tmp_name;
431
432       tmp_name = g_module_build_path (*path, name);
433       if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
434         {
435           module_name = tmp_name;
436           goto found;
437         }
438       g_free(tmp_name);
439
440       tmp_name = module_build_la_path (*path, name);
441       if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
442         {
443           module_name = tmp_name;
444           goto found;
445         }
446       g_free(tmp_name);
447     }
448
449   g_strfreev (paths);
450
451  found:
452   return module_name;
453 }
454
455 static GModule *
456 find_module (gchar      **module_path,
457              const gchar *name)
458 {
459   GModule *module;
460   gchar *module_name;
461
462   module_name = _gtk_find_module (name, "modules");
463   if (!module_name)
464     {
465       /* As last resort, try loading without an absolute path (using system
466        * library path)
467        */
468       module_name = g_module_build_path (NULL, name);
469     }
470   
471   module = g_module_open (module_name, G_MODULE_BIND_LAZY);
472   g_free(module_name);
473
474   return module;
475 }
476
477 static GSList *
478 load_module (GSList      *gtk_modules,
479              gchar      **module_path,
480              const gchar *name)
481 {
482   GtkModuleInitFunc modinit_func = NULL;
483   GModule *module = NULL;
484   
485   if (g_module_supported ())
486     {
487       module = find_module (module_path, name);
488       if (module &&
489           g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
490           modinit_func)
491         {
492           if (!g_slist_find (gtk_modules, modinit_func))
493             {
494               g_module_make_resident (module);
495               gtk_modules = g_slist_prepend (gtk_modules, modinit_func);
496             }
497           else
498             {
499               g_module_close (module);
500               module = NULL;
501             }
502         }
503     }
504   if (!modinit_func)
505     {
506       g_message ("Failed to load module \"%s\": %s",
507                  module ? g_module_name (module) : name,
508                  g_module_error ());
509       if (module)
510         g_module_close (module);
511     }
512   
513   return gtk_modules;
514 }
515
516 static GSList *
517 load_modules (const char *module_str)
518 {
519   gchar **module_path = get_module_path ();
520   gchar **module_names = pango_split_file_list (module_str);
521   GSList *gtk_modules = NULL;
522   gint i;
523   
524   for (i = 0; module_names[i]; i++)
525     gtk_modules = load_module (gtk_modules, module_path, module_names[i]);
526   
527   gtk_modules = g_slist_reverse (gtk_modules);
528   
529   g_strfreev (module_names);
530   g_strfreev (module_path);
531
532   return gtk_modules;
533 }
534
535 static gboolean do_setlocale = TRUE;
536
537 /**
538  * gtk_disable_setlocale:
539  * 
540  * Prevents gtk_init() and gtk_init_check() from automatically
541  * calling <literal>setlocale (LC_ALL, "")</literal>. You would 
542  * want to use this function if you wanted to set the locale for 
543  * your program to something other than the user's locale, or if 
544  * you wanted to set different values for different locale categories.
545  *
546  * Most programs should not need to call this function.
547  **/
548 void
549 gtk_disable_setlocale (void)
550 {
551   if (gtk_initialized)
552     g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
553     
554   do_setlocale = FALSE;
555 }
556
557 gboolean
558 gtk_init_check (int      *argc,
559                 char   ***argv)
560 {
561   GString *gtk_modules_string = NULL;
562   GSList *gtk_modules = NULL;
563   GSList *slist;
564   const gchar *env_string;
565
566   if (gtk_initialized)
567     return TRUE;
568
569   if (!check_setugid ())
570     return FALSE;
571   
572 #if     0
573   g_set_error_handler (gtk_error);
574   g_set_warning_handler (gtk_warning);
575   g_set_message_handler (gtk_message);
576   g_set_print_handler (gtk_print);
577 #endif
578
579   if (do_setlocale)
580     {
581       if (!setlocale (LC_ALL, ""))
582         g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
583     }
584   
585   /* Initialize "gdk". We pass along the 'argc' and 'argv'
586    *  parameters as they contain information that GDK uses
587    */
588   if (!gdk_init_check (argc, argv))
589     return FALSE;
590
591   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
592   
593 #ifdef G_ENABLE_DEBUG
594   env_string = g_getenv ("GTK_DEBUG");
595   if (env_string != NULL)
596     {
597       gtk_debug_flags = g_parse_debug_string (env_string,
598                                               gtk_debug_keys,
599                                               gtk_ndebug_keys);
600       env_string = NULL;
601     }
602 #endif  /* G_ENABLE_DEBUG */
603
604   env_string = g_getenv ("GTK_MODULES");
605   if (env_string)
606     gtk_modules_string = g_string_new (env_string);
607
608   if (argc && argv)
609     {
610       gint i, j, k;
611       
612       for (i = 1; i < *argc;)
613         {
614           if (strcmp ("--gtk-module", (*argv)[i]) == 0 ||
615               strncmp ("--gtk-module=", (*argv)[i], 13) == 0)
616             {
617               gchar *module_name = (*argv)[i] + 12;
618               
619               if (*module_name == '=')
620                 module_name++;
621               else if (i + 1 < *argc)
622                 {
623                   (*argv)[i] = NULL;
624                   i += 1;
625                   module_name = (*argv)[i];
626                 }
627               (*argv)[i] = NULL;
628
629               if (module_name && *module_name)
630                 {
631                   if (gtk_modules_string)
632                     g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
633                   else
634                     gtk_modules_string = g_string_new (NULL);
635
636                   g_string_append (gtk_modules_string, module_name);
637                 }
638             }
639           else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0)
640             {
641               GLogLevelFlags fatal_mask;
642               
643               fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
644               fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
645               g_log_set_always_fatal (fatal_mask);
646               (*argv)[i] = NULL;
647             }
648 #ifdef G_ENABLE_DEBUG
649           else if ((strcmp ("--gtk-debug", (*argv)[i]) == 0) ||
650                    (strncmp ("--gtk-debug=", (*argv)[i], 12) == 0))
651             {
652               gchar *equal_pos = strchr ((*argv)[i], '=');
653               
654               if (equal_pos != NULL)
655                 {
656                   gtk_debug_flags |= g_parse_debug_string (equal_pos+1,
657                                                            gtk_debug_keys,
658                                                            gtk_ndebug_keys);
659                 }
660               else if ((i + 1) < *argc && (*argv)[i + 1])
661                 {
662                   gtk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
663                                                            gtk_debug_keys,
664                                                            gtk_ndebug_keys);
665                   (*argv)[i] = NULL;
666                   i += 1;
667                 }
668               (*argv)[i] = NULL;
669             }
670           else if ((strcmp ("--gtk-no-debug", (*argv)[i]) == 0) ||
671                    (strncmp ("--gtk-no-debug=", (*argv)[i], 15) == 0))
672             {
673               gchar *equal_pos = strchr ((*argv)[i], '=');
674               
675               if (equal_pos != NULL)
676                 {
677                   gtk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
678                                                             gtk_debug_keys,
679                                                             gtk_ndebug_keys);
680                 }
681               else if ((i + 1) < *argc && (*argv)[i + 1])
682                 {
683                   gtk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
684                                                             gtk_debug_keys,
685                                                             gtk_ndebug_keys);
686                   (*argv)[i] = NULL;
687                   i += 1;
688                 }
689               (*argv)[i] = NULL;
690             }
691 #endif /* G_ENABLE_DEBUG */
692           i += 1;
693         }
694       
695       for (i = 1; i < *argc; i++)
696         {
697           for (k = i; k < *argc; k++)
698             if ((*argv)[k] != NULL)
699               break;
700           
701           if (k > i)
702             {
703               k -= i;
704               for (j = i + k; j < *argc; j++)
705                 (*argv)[j-k] = (*argv)[j];
706               *argc -= k;
707             }
708         }
709     }
710
711   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
712     gdk_window_set_debug_updates (TRUE);
713
714   /* load gtk modules */
715   if (gtk_modules_string)
716     {
717       gtk_modules = load_modules (gtk_modules_string->str);
718       g_string_free (gtk_modules_string, TRUE);
719     }
720
721 #ifdef ENABLE_NLS
722   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
723 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
724   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
725 #    endif
726 #endif  
727
728   {
729   /* Translate to default:RTL if you want your widgets
730    * to be RTL, otherwise translate to default:LTR.
731    * Do *not* translate it to "predefinito:LTR", if it
732    * it isn't default:LTR or default:RTL it will not work 
733    */
734     char *e = _("default:LTR");
735     if (strcmp (e, "default:RTL")==0) {
736       gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
737     } else if (strcmp (e, "default:LTR")) {
738       g_warning ("Whoever translated default:LTR did so wrongly.\n");
739     }
740   }
741
742   /* Initialize the default visual and colormap to be
743    *  used in creating widgets. (We want to use the system
744    *  defaults so as to be nice to the colormap).
745    */
746   gtk_visual = gdk_visual_get_system ();
747   gtk_colormap = gdk_colormap_get_system ();
748
749   gtk_type_init (0);
750   _gtk_accel_map_init ();  
751   _gtk_rc_init ();
752   
753   /* Set the 'initialized' flag.
754    */
755   gtk_initialized = TRUE;
756
757   /* initialize gtk modules
758    */
759   for (slist = gtk_modules; slist; slist = slist->next)
760     {
761       if (slist->data)
762         {
763           GtkModuleInitFunc modinit;
764           
765           modinit = slist->data;
766           modinit (argc, argv);
767         }
768     }
769   g_slist_free (gtk_modules);
770   
771   return TRUE;
772 }
773
774 #undef gtk_init
775
776 void
777 gtk_init (int *argc, char ***argv)
778 {
779   if (!gtk_init_check (argc, argv))
780     {
781       g_warning ("cannot open display: %s", gdk_get_display ());
782       exit (1);
783     }
784 }
785
786 #ifdef G_OS_WIN32
787
788 static void
789 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
790 {
791   if (sizeof_GtkWindow != sizeof (GtkWindow))
792     g_error ("Incompatible build!\n"
793              "The code using GTK+ thinks GtkWindow is of different\n"
794              "size than it actually is in this build of GTK+.\n"
795              "On Windows, this probably means that you have compiled\n"
796              "your code with gcc without the -fnative-struct switch.");
797 }
798
799 /* These two functions might get more checks added later, thus pass
800  * in the number of extra args.
801  */
802 void
803 gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
804 {
805   check_sizeof_GtkWindow (sizeof_GtkWindow);
806   gtk_init (argc, argv);
807 }
808
809 gboolean
810 gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
811 {
812   check_sizeof_GtkWindow (sizeof_GtkWindow);
813   return gtk_init_check (argc, argv);
814 }
815
816 #endif
817
818 void
819 gtk_exit (gint errorcode)
820 {
821   /* Only if "gtk" has been initialized should we de-initialize.
822    */
823   gdk_exit (errorcode);
824 }
825
826
827 /**
828  * gtk_set_locale:
829  *
830  * Initializes internationalization support for GTK+. gtk_init()
831  * automatically does this, so there is typically no point
832  * in calling this function.
833  *
834  * If you are calling this function because you changed the locale
835  * after GTK+ is was initialized, then calling this function
836  * may help a bit. (Note, however, that changing the locale
837  * after GTK+ is initialized may produce inconsistent results and
838  * is not really supported.)
839  * 
840  * In detail - sets the current locale according to the
841  * program environment. This is the same as calling the C library function
842  * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the 
843  * locale specific setup of the windowing system used by GDK.
844  * 
845  * Return value: a string corresponding to the locale set, as with the
846  * C library function <function>setlocale()</function>.
847  **/
848 gchar*
849 gtk_set_locale (void)
850 {
851   return gdk_set_locale ();
852 }
853
854 /**
855  * gtk_get_default_language:
856  *
857  * Returns the ISO language code for the default language currently in
858  * effect. (Note that this can change over the life of an
859  * application.)  The default language is derived from the current
860  * locale. It determines, for example, whether GTK+ uses the
861  * right-to-left or left-to-right text direction.
862  * 
863  * Return value: the default language as an allocated string, must be freed
864  **/
865 PangoLanguage *
866 gtk_get_default_language (void)
867 {
868   gchar *lang;
869   PangoLanguage *result;
870   gchar *p;
871   
872   lang = g_strdup (setlocale (LC_CTYPE, NULL));
873   p = strchr (lang, '.');
874   if (p)
875     *p = '\0';
876   p = strchr (lang, '@');
877   if (p)
878     *p = '\0';
879
880   result = pango_language_from_string (lang);
881   g_free (lang);
882   
883   return result;
884 }
885
886 void
887 gtk_main (void)
888 {
889   GList *tmp_list;
890   GList *functions;
891   GtkInitFunction *init;
892   GMainLoop *loop;
893
894   gtk_main_loop_level++;
895   
896   loop = g_main_new (TRUE);
897   main_loops = g_slist_prepend (main_loops, loop);
898
899   tmp_list = functions = init_functions;
900   init_functions = NULL;
901   
902   while (tmp_list)
903     {
904       init = tmp_list->data;
905       tmp_list = tmp_list->next;
906       
907       (* init->function) (init->data);
908       g_free (init);
909     }
910   g_list_free (functions);
911
912   if (g_main_is_running (main_loops->data))
913     {
914       GDK_THREADS_LEAVE ();
915       g_main_run (loop);
916       GDK_THREADS_ENTER ();
917       gdk_flush ();
918     }
919
920   if (quit_functions)
921     {
922       GList *reinvoke_list = NULL;
923       GtkQuitFunction *quitf;
924
925       while (quit_functions)
926         {
927           quitf = quit_functions->data;
928
929           tmp_list = quit_functions;
930           quit_functions = g_list_remove_link (quit_functions, quit_functions);
931           g_list_free_1 (tmp_list);
932
933           if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
934               gtk_quit_invoke_function (quitf))
935             {
936               reinvoke_list = g_list_prepend (reinvoke_list, quitf);
937             }
938           else
939             {
940               gtk_quit_destroy (quitf);
941             }
942         }
943       if (reinvoke_list)
944         {
945           GList *work;
946           
947           work = g_list_last (reinvoke_list);
948           if (quit_functions)
949             quit_functions->prev = work;
950           work->next = quit_functions;
951           quit_functions = work;
952         }
953
954       gdk_flush ();
955     }
956               
957   main_loops = g_slist_remove (main_loops, loop);
958
959   g_main_destroy (loop);
960
961   gtk_main_loop_level--;
962 }
963
964 guint
965 gtk_main_level (void)
966 {
967   return gtk_main_loop_level;
968 }
969
970 void
971 gtk_main_quit (void)
972 {
973   g_return_if_fail (main_loops != NULL);
974
975   g_main_quit (main_loops->data);
976 }
977
978 gint
979 gtk_events_pending (void)
980 {
981   gboolean result;
982   
983   GDK_THREADS_LEAVE ();  
984   result = g_main_pending ();
985   GDK_THREADS_ENTER ();
986
987   return result;
988 }
989
990 gboolean
991 gtk_main_iteration (void)
992 {
993   GDK_THREADS_LEAVE ();
994   g_main_iteration (TRUE);
995   GDK_THREADS_ENTER ();
996
997   if (main_loops)
998     return !g_main_is_running (main_loops->data);
999   else
1000     return TRUE;
1001 }
1002
1003 gboolean
1004 gtk_main_iteration_do (gboolean blocking)
1005 {
1006   GDK_THREADS_LEAVE ();
1007   g_main_iteration (blocking);
1008   GDK_THREADS_ENTER ();
1009
1010   if (main_loops)
1011     return !g_main_is_running (main_loops->data);
1012   else
1013     return TRUE;
1014 }
1015
1016 /* private libgtk to libgdk interfaces
1017  */
1018 gboolean gdk_pointer_grab_info_libgtk_only  (GdkWindow **grab_window,
1019                                              gboolean   *owner_events);
1020 gboolean gdk_keyboard_grab_info_libgtk_only (GdkWindow **grab_window,
1021                                              gboolean   *owner_events);
1022
1023 static void
1024 rewrite_events_translate (GdkWindow *old_window,
1025                           GdkWindow *new_window,
1026                           gdouble   *x,
1027                           gdouble   *y)
1028 {
1029   gint old_origin_x, old_origin_y;
1030   gint new_origin_x, new_origin_y;
1031
1032   gdk_window_get_origin (old_window, &old_origin_x, &old_origin_y);
1033   gdk_window_get_origin (new_window, &new_origin_x, &new_origin_y);
1034
1035   *x += new_origin_x - old_origin_x;
1036   *y += new_origin_y - old_origin_y;
1037 }
1038
1039 GdkEvent *
1040 rewrite_event_for_window (GdkEvent  *event,
1041                           GdkWindow *new_window)
1042 {
1043   event = gdk_event_copy (event);
1044
1045   switch (event->type)
1046     {
1047     case GDK_SCROLL:
1048       rewrite_events_translate (event->any.window,
1049                                 new_window,
1050                                 &event->scroll.x, &event->scroll.y);
1051       break;
1052     case GDK_BUTTON_PRESS:
1053     case GDK_2BUTTON_PRESS:
1054     case GDK_3BUTTON_PRESS:
1055     case GDK_BUTTON_RELEASE:
1056       rewrite_events_translate (event->any.window,
1057                                 new_window,
1058                                 &event->button.x, &event->button.y);
1059       break;
1060     case GDK_MOTION_NOTIFY:
1061       rewrite_events_translate (event->any.window,
1062                                 new_window,
1063                                 &event->motion.x, &event->motion.y);
1064       break;
1065     case GDK_KEY_PRESS:
1066     case GDK_KEY_RELEASE:
1067     case GDK_PROXIMITY_IN:
1068     case GDK_PROXIMITY_OUT:
1069       break;
1070
1071     default:
1072       return event;
1073     }
1074
1075   g_object_unref (event->any.window);
1076   event->any.window = g_object_ref (new_window);
1077
1078   return event;
1079 }
1080
1081 /* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
1082  * then what X11 does is deliver the event normally if it was going to this
1083  * client, otherwise, delivers it in terms of the grab window. This function
1084  * rewrites events to the effect that events going to the same window group
1085  * are delivered normally, otherwise, the event is delivered in terms of the
1086  * grab window.
1087  */
1088 static GdkEvent *
1089 rewrite_event_for_grabs (GdkEvent *event)
1090 {
1091   GdkWindow *grab_window;
1092   GtkWidget *event_widget, *grab_widget;
1093   gboolean owner_events;
1094
1095   switch (event->type)
1096     {
1097     case GDK_SCROLL:
1098     case GDK_BUTTON_PRESS:
1099     case GDK_2BUTTON_PRESS:
1100     case GDK_3BUTTON_PRESS:
1101     case GDK_BUTTON_RELEASE:
1102     case GDK_MOTION_NOTIFY:
1103     case GDK_PROXIMITY_IN:
1104     case GDK_PROXIMITY_OUT:
1105       if (!gdk_pointer_grab_info_libgtk_only (&grab_window, &owner_events) ||
1106           !owner_events)
1107         return NULL;
1108       break;
1109
1110     case GDK_KEY_PRESS:
1111     case GDK_KEY_RELEASE:
1112       if (!gdk_keyboard_grab_info_libgtk_only (&grab_window, &owner_events) ||
1113           !owner_events)
1114         return NULL;
1115       break;
1116
1117     default:
1118       return NULL;
1119     }
1120
1121   event_widget = gtk_get_event_widget (event);
1122   gdk_window_get_user_data (grab_window, (void**) &grab_widget);
1123
1124   if (grab_widget &&
1125       gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
1126     return rewrite_event_for_window (event, grab_window);
1127   else
1128     return NULL;
1129 }
1130
1131 void 
1132 gtk_main_do_event (GdkEvent *event)
1133 {
1134   GtkWidget *event_widget;
1135   GtkWidget *grab_widget;
1136   GtkWindowGroup *window_group;
1137   GdkEvent *next_event;
1138   GdkEvent *rewritten_event = NULL;
1139   GList *tmp_list;
1140
1141   /* If there are any events pending then get the next one.
1142    */
1143   next_event = gdk_event_peek ();
1144   
1145   /* Try to compress enter/leave notify events. These event
1146    *  pairs occur when the mouse is dragged quickly across
1147    *  a window with many buttons (or through a menu). Instead
1148    *  of highlighting and de-highlighting each widget that
1149    *  is crossed it is better to simply de-highlight the widget
1150    *  which contained the mouse initially and highlight the
1151    *  widget which ends up containing the mouse.
1152    */
1153   if (next_event)
1154     if (((event->type == GDK_ENTER_NOTIFY) ||
1155          (event->type == GDK_LEAVE_NOTIFY)) &&
1156         ((next_event->type == GDK_ENTER_NOTIFY) ||
1157          (next_event->type == GDK_LEAVE_NOTIFY)) &&
1158         (next_event->type != event->type) &&
1159         (next_event->any.window == event->any.window))
1160       {
1161         /* Throw both the peeked copy and the queued copy away 
1162          */
1163         gdk_event_free (next_event);
1164         next_event = gdk_event_get ();
1165         gdk_event_free (next_event);
1166         
1167         return;
1168       }
1169
1170   if (next_event)
1171     gdk_event_free (next_event);
1172
1173   /* Find the widget which got the event. We store the widget
1174    *  in the user_data field of GdkWindow's.
1175    *  Ignore the event if we don't have a widget for it, except
1176    *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
1177    *  Though this happens rarely, bogus events can occour
1178    *  for e.g. destroyed GdkWindows. 
1179    */
1180   event_widget = gtk_get_event_widget (event);
1181   if (!event_widget)
1182     {
1183       /* To handle selection INCR transactions, we select
1184        * PropertyNotify events on the requestor window and create
1185        * a corresponding (fake) GdkWindow so that events get
1186        * here. There won't be a widget though, so we have to handle
1187            * them specially
1188            */
1189       if (event->type == GDK_PROPERTY_NOTIFY)
1190         gtk_selection_incr_event (event->any.window,
1191                                   &event->property);
1192       else if (event->type == GDK_SETTING)
1193         _gtk_settings_handle_event (&event->setting);
1194
1195       return;
1196     }
1197
1198   /* If pointer or keyboard grabs are in effect, munge the events
1199    * so that each window group looks like a separate app.
1200    */
1201   rewritten_event = rewrite_event_for_grabs (event);
1202   if (rewritten_event)
1203     {
1204       event = rewritten_event;
1205       event_widget = gtk_get_event_widget (event);
1206     }
1207   
1208   window_group = gtk_main_get_window_group (event_widget);
1209
1210   /* Push the event onto a stack of current events for
1211    * gtk_current_event_get().
1212    */
1213   current_events = g_list_prepend (current_events, event);
1214
1215   /* If there is a grab in effect...
1216    */
1217   if (window_group->grabs)
1218     {
1219       grab_widget = window_group->grabs->data;
1220       
1221       /* If the grab widget is an ancestor of the event widget
1222        *  then we send the event to the original event widget.
1223        *  This is the key to implementing modality.
1224        */
1225       if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
1226           gtk_widget_is_ancestor (event_widget, grab_widget))
1227         grab_widget = event_widget;
1228     }
1229   else
1230     {
1231       grab_widget = event_widget;
1232     }
1233
1234   /* Not all events get sent to the grabbing widget.
1235    * The delete, destroy, expose, focus change and resize
1236    *  events still get sent to the event widget because
1237    *  1) these events have no meaning for the grabbing widget
1238    *  and 2) redirecting these events to the grabbing widget
1239    *  could cause the display to be messed up.
1240    * 
1241    * Drag events are also not redirected, since it isn't
1242    *  clear what the semantics of that would be.
1243    */
1244   switch (event->type)
1245     {
1246     case GDK_NOTHING:
1247       break;
1248       
1249     case GDK_DELETE:
1250       gtk_widget_ref (event_widget);
1251       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1252           !gtk_widget_event (event_widget, event))
1253         gtk_widget_destroy (event_widget);
1254       gtk_widget_unref (event_widget);
1255       break;
1256       
1257     case GDK_DESTROY:
1258       /* Unexpected GDK_DESTROY from the outside, ignore for
1259        * child windows, handle like a GDK_DELETE for toplevels
1260        */
1261       if (!event_widget->parent)
1262         {
1263           gtk_widget_ref (event_widget);
1264           if (!gtk_widget_event (event_widget, event) &&
1265               GTK_WIDGET_REALIZED (event_widget))
1266             gtk_widget_destroy (event_widget);
1267           gtk_widget_unref (event_widget);
1268         }
1269       break;
1270       
1271     case GDK_EXPOSE:
1272       if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
1273         {
1274           gdk_window_begin_paint_region (event->any.window, event->expose.region);
1275           gtk_widget_send_expose (event_widget, event);
1276           gdk_window_end_paint (event->any.window);
1277         }
1278       else
1279         gtk_widget_send_expose (event_widget, event);
1280       break;
1281
1282     case GDK_PROPERTY_NOTIFY:
1283     case GDK_NO_EXPOSE:
1284     case GDK_FOCUS_CHANGE:
1285     case GDK_CONFIGURE:
1286     case GDK_MAP:
1287     case GDK_UNMAP:
1288     case GDK_SELECTION_CLEAR:
1289     case GDK_SELECTION_REQUEST:
1290     case GDK_SELECTION_NOTIFY:
1291     case GDK_CLIENT_EVENT:
1292     case GDK_VISIBILITY_NOTIFY:
1293     case GDK_WINDOW_STATE:
1294       gtk_widget_event (event_widget, event);
1295       break;
1296
1297     case GDK_SCROLL:
1298     case GDK_BUTTON_PRESS:
1299     case GDK_2BUTTON_PRESS:
1300     case GDK_3BUTTON_PRESS:
1301       gtk_propagate_event (grab_widget, event);
1302       break;
1303
1304     case GDK_KEY_PRESS:
1305     case GDK_KEY_RELEASE:
1306       if (key_snoopers)
1307         {
1308           if (gtk_invoke_key_snoopers (grab_widget, event))
1309             break;
1310         }
1311       /* else fall through */
1312     case GDK_MOTION_NOTIFY:
1313     case GDK_BUTTON_RELEASE:
1314     case GDK_PROXIMITY_IN:
1315     case GDK_PROXIMITY_OUT:
1316       gtk_propagate_event (grab_widget, event);
1317       break;
1318       
1319     case GDK_ENTER_NOTIFY:
1320       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1321         {
1322           g_object_ref (event_widget);
1323           
1324           gtk_widget_event (grab_widget, event);
1325           if (event_widget == grab_widget)
1326             GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
1327           
1328           g_object_unref (event_widget);
1329         }
1330       break;
1331       
1332     case GDK_LEAVE_NOTIFY:
1333       if (GTK_WIDGET_LEAVE_PENDING (event_widget))
1334         {
1335           GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
1336           gtk_widget_event (event_widget, event);
1337         }
1338       else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
1339         gtk_widget_event (grab_widget, event);
1340       break;
1341       
1342     case GDK_DRAG_STATUS:
1343     case GDK_DROP_FINISHED:
1344       _gtk_drag_source_handle_event (event_widget, event);
1345       break;
1346     case GDK_DRAG_ENTER:
1347     case GDK_DRAG_LEAVE:
1348     case GDK_DRAG_MOTION:
1349     case GDK_DROP_START:
1350       _gtk_drag_dest_handle_event (event_widget, event);
1351       break;
1352     default:
1353       g_assert_not_reached ();
1354       break;
1355     }
1356   
1357   tmp_list = current_events;
1358   current_events = g_list_remove_link (current_events, tmp_list);
1359   g_list_free_1 (tmp_list);
1360
1361   if (rewritten_event)
1362     gdk_event_free (rewritten_event);
1363 }
1364
1365 gboolean
1366 gtk_true (void)
1367 {
1368   return TRUE;
1369 }
1370
1371 gboolean
1372 gtk_false (void)
1373 {
1374   return FALSE;
1375 }
1376
1377 static GtkWindowGroup *
1378 gtk_main_get_window_group (GtkWidget   *widget)
1379 {
1380   GtkWidget *toplevel = NULL;
1381
1382   if (widget)
1383     toplevel = gtk_widget_get_toplevel (widget);
1384
1385   if (toplevel && GTK_IS_WINDOW (toplevel))
1386     return _gtk_window_get_group (GTK_WINDOW (toplevel));
1387   else
1388     return _gtk_window_get_group (NULL);
1389 }
1390
1391 typedef struct
1392 {
1393   GtkWidget *old_grab_widget;
1394   GtkWidget *new_grab_widget;
1395 } GrabNotifyInfo;
1396
1397 static gboolean
1398 check_is_grabbed (GtkWidget *widget,
1399                   GtkWidget *grab_widget)
1400 {
1401   if (grab_widget)
1402     return !(widget == grab_widget || gtk_widget_is_ancestor (widget, grab_widget));
1403   else
1404     return FALSE;
1405 }
1406
1407 static void
1408 gtk_grab_notify_foreach (GtkWidget *child,
1409                          gpointer   data)
1410                         
1411 {
1412   GrabNotifyInfo *info = data;
1413   gboolean was_grabbed = check_is_grabbed (child, info->old_grab_widget);
1414   gboolean is_grabbed = check_is_grabbed (child, info->new_grab_widget);
1415
1416   if (was_grabbed != is_grabbed)
1417     {
1418       g_object_ref (G_OBJECT (child));
1419       
1420       gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", was_grabbed);
1421       
1422       if (GTK_IS_CONTAINER (child))
1423         gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1424       
1425       g_object_unref (G_OBJECT (child));
1426     }
1427 }
1428
1429 static void
1430 gtk_grab_notify (GtkWindowGroup *group,
1431                  GtkWidget      *grab_widget,
1432                  gboolean        was_grabbed)
1433 {
1434   GList *toplevels;
1435   GrabNotifyInfo info;
1436
1437   if (was_grabbed)
1438     {
1439       info.old_grab_widget = grab_widget;
1440       info.new_grab_widget = group->grabs ? group->grabs->data : NULL;
1441     }
1442   else
1443     {
1444       info.old_grab_widget = (group->grabs && group->grabs->next) ? group->grabs->next->data : NULL;
1445       info.new_grab_widget = grab_widget;
1446     }
1447
1448   g_object_ref (group);
1449   g_object_ref (grab_widget);
1450
1451   toplevels = gtk_window_list_toplevels ();
1452   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1453                             
1454   while (toplevels)
1455     {
1456       GtkWindow *toplevel = toplevels->data;
1457       toplevels = g_list_delete_link (toplevels, toplevels);
1458
1459       if (group == _gtk_window_get_group (toplevel))
1460         gtk_container_foreach (GTK_CONTAINER (toplevel), gtk_grab_notify_foreach, &info);
1461       g_object_unref (toplevel);
1462     }
1463
1464   g_object_unref (group);
1465   g_object_unref (grab_widget);
1466 }
1467
1468 void
1469 gtk_grab_add (GtkWidget *widget)
1470 {
1471   GtkWindowGroup *group;
1472   gboolean was_grabbed;
1473   
1474   g_return_if_fail (widget != NULL);
1475   
1476   if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
1477     {
1478       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
1479       
1480       group = gtk_main_get_window_group (widget);
1481
1482       was_grabbed = (group->grabs != NULL);
1483       
1484       gtk_widget_ref (widget);
1485       group->grabs = g_slist_prepend (group->grabs, widget);
1486
1487       gtk_grab_notify (group, widget, FALSE);
1488     }
1489 }
1490
1491 GtkWidget*
1492 gtk_grab_get_current (void)
1493 {
1494   GtkWindowGroup *group;
1495
1496   group = gtk_main_get_window_group (NULL);
1497
1498   if (group->grabs)
1499     return GTK_WIDGET (group->grabs->data);
1500   return NULL;
1501 }
1502
1503 void
1504 gtk_grab_remove (GtkWidget *widget)
1505 {
1506   GtkWindowGroup *group;
1507   
1508   g_return_if_fail (widget != NULL);
1509   
1510   if (GTK_WIDGET_HAS_GRAB (widget))
1511     {
1512       GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
1513
1514       group = gtk_main_get_window_group (widget);
1515       group->grabs = g_slist_remove (group->grabs, widget);
1516       
1517       gtk_widget_unref (widget);
1518
1519       gtk_grab_notify (group, widget, TRUE);
1520     }
1521 }
1522
1523 void
1524 gtk_init_add (GtkFunction function,
1525               gpointer    data)
1526 {
1527   GtkInitFunction *init;
1528   
1529   init = g_new (GtkInitFunction, 1);
1530   init->function = function;
1531   init->data = data;
1532   
1533   init_functions = g_list_prepend (init_functions, init);
1534 }
1535
1536 guint
1537 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
1538                          gpointer        func_data)
1539 {
1540   GtkKeySnooperData *data;
1541   static guint snooper_id = 1;
1542
1543   g_return_val_if_fail (snooper != NULL, 0);
1544
1545   data = g_new (GtkKeySnooperData, 1);
1546   data->func = snooper;
1547   data->func_data = func_data;
1548   data->id = snooper_id++;
1549   key_snoopers = g_slist_prepend (key_snoopers, data);
1550
1551   return data->id;
1552 }
1553
1554 void
1555 gtk_key_snooper_remove (guint            snooper_id)
1556 {
1557   GtkKeySnooperData *data = NULL;
1558   GSList *slist;
1559
1560   slist = key_snoopers;
1561   while (slist)
1562     {
1563       data = slist->data;
1564       if (data->id == snooper_id)
1565         break;
1566
1567       slist = slist->next;
1568       data = NULL;
1569     }
1570   if (data)
1571     key_snoopers = g_slist_remove (key_snoopers, data);
1572 }
1573
1574 static gint
1575 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
1576                          GdkEvent  *event)
1577 {
1578   GSList *slist;
1579   gint return_val = FALSE;
1580
1581   slist = key_snoopers;
1582   while (slist && !return_val)
1583     {
1584       GtkKeySnooperData *data;
1585
1586       data = slist->data;
1587       slist = slist->next;
1588       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
1589     }
1590
1591   return return_val;
1592 }
1593
1594 guint
1595 gtk_quit_add_full (guint                main_level,
1596                    GtkFunction          function,
1597                    GtkCallbackMarshal   marshal,
1598                    gpointer             data,
1599                    GtkDestroyNotify     destroy)
1600 {
1601   static guint quit_id = 1;
1602   GtkQuitFunction *quitf;
1603   
1604   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
1605
1606   if (!quit_mem_chunk)
1607     quit_mem_chunk = g_mem_chunk_new ("quit mem chunk", sizeof (GtkQuitFunction),
1608                                       512, G_ALLOC_AND_FREE);
1609   
1610   quitf = g_chunk_new (GtkQuitFunction, quit_mem_chunk);
1611   
1612   quitf->id = quit_id++;
1613   quitf->main_level = main_level;
1614   quitf->function = function;
1615   quitf->marshal = marshal;
1616   quitf->data = data;
1617   quitf->destroy = destroy;
1618
1619   quit_functions = g_list_prepend (quit_functions, quitf);
1620   
1621   return quitf->id;
1622 }
1623
1624 static void
1625 gtk_quit_destroy (GtkQuitFunction *quitf)
1626 {
1627   if (quitf->destroy)
1628     quitf->destroy (quitf->data);
1629   g_mem_chunk_free (quit_mem_chunk, quitf);
1630 }
1631
1632 static gint
1633 gtk_quit_destructor (GtkObject **object_p)
1634 {
1635   if (*object_p)
1636     gtk_object_destroy (*object_p);
1637   g_free (object_p);
1638
1639   return FALSE;
1640 }
1641
1642 void
1643 gtk_quit_add_destroy (guint              main_level,
1644                       GtkObject         *object)
1645 {
1646   GtkObject **object_p;
1647
1648   g_return_if_fail (main_level > 0);
1649   g_return_if_fail (GTK_IS_OBJECT (object));
1650
1651   object_p = g_new (GtkObject*, 1);
1652   *object_p = object;
1653   gtk_signal_connect (object,
1654                       "destroy",
1655                       GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1656                       object_p);
1657   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1658 }
1659
1660 guint
1661 gtk_quit_add (guint       main_level,
1662               GtkFunction function,
1663               gpointer    data)
1664 {
1665   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
1666 }
1667
1668 void
1669 gtk_quit_remove (guint id)
1670 {
1671   GtkQuitFunction *quitf;
1672   GList *tmp_list;
1673   
1674   tmp_list = quit_functions;
1675   while (tmp_list)
1676     {
1677       quitf = tmp_list->data;
1678       
1679       if (quitf->id == id)
1680         {
1681           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1682           g_list_free (tmp_list);
1683           gtk_quit_destroy (quitf);
1684           
1685           return;
1686         }
1687       
1688       tmp_list = tmp_list->next;
1689     }
1690 }
1691
1692 void
1693 gtk_quit_remove_by_data (gpointer data)
1694 {
1695   GtkQuitFunction *quitf;
1696   GList *tmp_list;
1697   
1698   tmp_list = quit_functions;
1699   while (tmp_list)
1700     {
1701       quitf = tmp_list->data;
1702       
1703       if (quitf->data == data)
1704         {
1705           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1706           g_list_free (tmp_list);
1707           gtk_quit_destroy (quitf);
1708
1709           return;
1710         }
1711       
1712       tmp_list = tmp_list->next;
1713     }
1714 }
1715
1716 guint
1717 gtk_timeout_add_full (guint32            interval,
1718                       GtkFunction        function,
1719                       GtkCallbackMarshal marshal,
1720                       gpointer           data,
1721                       GtkDestroyNotify   destroy)
1722 {
1723   if (marshal)
1724     {
1725       GtkClosure *closure;
1726
1727       closure = g_new (GtkClosure, 1);
1728       closure->marshal = marshal;
1729       closure->data = data;
1730       closure->destroy = destroy;
1731
1732       return g_timeout_add_full (0, interval, 
1733                                  gtk_invoke_idle_timeout,
1734                                  closure,
1735                                  gtk_destroy_closure);
1736     }
1737   else
1738     return g_timeout_add_full (0, interval, function, data, destroy);
1739 }
1740
1741 guint
1742 gtk_timeout_add (guint32     interval,
1743                  GtkFunction function,
1744                  gpointer    data)
1745 {
1746   return g_timeout_add_full (0, interval, function, data, NULL);
1747 }
1748
1749 void
1750 gtk_timeout_remove (guint tag)
1751 {
1752   g_source_remove (tag);
1753 }
1754
1755 guint
1756 gtk_idle_add_full (gint                 priority,
1757                    GtkFunction          function,
1758                    GtkCallbackMarshal   marshal,
1759                    gpointer             data,
1760                    GtkDestroyNotify     destroy)
1761 {
1762   if (marshal)
1763     {
1764       GtkClosure *closure;
1765
1766       closure = g_new (GtkClosure, 1);
1767       closure->marshal = marshal;
1768       closure->data = data;
1769       closure->destroy = destroy;
1770
1771       return g_idle_add_full (priority,
1772                               gtk_invoke_idle_timeout,
1773                               closure,
1774                               gtk_destroy_closure);
1775     }
1776   else
1777     return g_idle_add_full (priority, function, data, destroy);
1778 }
1779
1780 guint
1781 gtk_idle_add (GtkFunction function,
1782               gpointer    data)
1783 {
1784   return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL);
1785 }
1786
1787 guint       
1788 gtk_idle_add_priority (gint        priority,
1789                        GtkFunction function,
1790                        gpointer    data)
1791 {
1792   return g_idle_add_full (priority, function, data, NULL);
1793 }
1794
1795 void
1796 gtk_idle_remove (guint tag)
1797 {
1798   g_source_remove (tag);
1799 }
1800
1801 void
1802 gtk_idle_remove_by_data (gpointer data)
1803 {
1804   if (!g_idle_remove_by_data (data))
1805     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
1806 }
1807
1808 guint
1809 gtk_input_add_full (gint                source,
1810                     GdkInputCondition   condition,
1811                     GdkInputFunction    function,
1812                     GtkCallbackMarshal  marshal,
1813                     gpointer            data,
1814                     GtkDestroyNotify    destroy)
1815 {
1816   if (marshal)
1817     {
1818       GtkClosure *closure;
1819
1820       closure = g_new (GtkClosure, 1);
1821       closure->marshal = marshal;
1822       closure->data = data;
1823       closure->destroy = destroy;
1824
1825       return gdk_input_add_full (source,
1826                                  condition,
1827                                  (GdkInputFunction) gtk_invoke_input,
1828                                  closure,
1829                                  (GdkDestroyNotify) gtk_destroy_closure);
1830     }
1831   else
1832     return gdk_input_add_full (source, condition, function, data, destroy);
1833 }
1834
1835 void
1836 gtk_input_remove (guint tag)
1837 {
1838   g_source_remove (tag);
1839 }
1840
1841 static void
1842 gtk_destroy_closure (gpointer data)
1843 {
1844   GtkClosure *closure = data;
1845
1846   if (closure->destroy)
1847     (closure->destroy) (closure->data);
1848   g_free (closure);
1849 }
1850
1851 static gboolean
1852 gtk_invoke_idle_timeout (gpointer data)
1853 {
1854   GtkClosure *closure = data;
1855
1856   GtkArg args[1];
1857   gint ret_val = FALSE;
1858   args[0].name = NULL;
1859   args[0].type = GTK_TYPE_BOOL;
1860   args[0].d.pointer_data = &ret_val;
1861   closure->marshal (NULL, closure->data,  0, args);
1862   return ret_val;
1863 }
1864
1865 static void
1866 gtk_invoke_input (gpointer          data,
1867                   gint              source,
1868                   GdkInputCondition condition)
1869 {
1870   GtkClosure *closure = data;
1871
1872   GtkArg args[3];
1873   args[0].type = GTK_TYPE_INT;
1874   args[0].name = NULL;
1875   GTK_VALUE_INT (args[0]) = source;
1876   args[1].type = GDK_TYPE_INPUT_CONDITION;
1877   args[1].name = NULL;
1878   GTK_VALUE_FLAGS (args[1]) = condition;
1879   args[2].type = GTK_TYPE_NONE;
1880   args[2].name = NULL;
1881
1882   closure->marshal (NULL, closure->data, 2, args);
1883 }
1884
1885 /**
1886  * gtk_get_current_event:
1887  * 
1888  * Obtains a copy of the event currently being processed by GTK+.  For
1889  * example, if you get a "clicked" signal from #GtkButton, the current
1890  * event will be the #GdkEventButton that triggered the "clicked"
1891  * signal. The returned event must be freed with gdk_event_free().
1892  * If there is no current event, the function returns %NULL.
1893  * 
1894  * Return value: a copy of the current event, or %NULL if no current event.
1895  **/
1896 GdkEvent*
1897 gtk_get_current_event (void)
1898 {
1899   if (current_events)
1900     return gdk_event_copy (current_events->data);
1901   else
1902     return NULL;
1903 }
1904
1905 /**
1906  * gtk_get_current_event_time:
1907  * 
1908  * If there is a current event and it has a timestamp, return that
1909  * timestamp, otherwise return %GDK_CURRENT_TIME.
1910  * 
1911  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
1912  **/
1913 guint32
1914 gtk_get_current_event_time (void)
1915 {
1916   if (current_events)
1917     return gdk_event_get_time (current_events->data);
1918   else
1919     return GDK_CURRENT_TIME;
1920 }
1921
1922 /**
1923  * gtk_get_current_event_state:
1924  * @state: a location to store the state of the current event
1925  * 
1926  * If there is a current event and it has a state field, place
1927  * that state field in @state and return %TRUE, otherwise return
1928  * %FALSE.
1929  * 
1930  * Return value: %TRUE if there was a current event and it had a state field
1931  **/
1932 gboolean
1933 gtk_get_current_event_state (GdkModifierType *state)
1934 {
1935   g_return_val_if_fail (state != NULL, FALSE);
1936   
1937   if (current_events)
1938     return gdk_event_get_state (current_events->data, state);
1939   else
1940     {
1941       *state = 0;
1942       return FALSE;
1943     }
1944 }
1945
1946 /**
1947  * gtk_get_event_widget:
1948  * @event: a #GdkEvent
1949  *
1950  * If @event is %NULL or the event was not associated with any widget,
1951  * returns %NULL, otherwise returns the widget that received the event
1952  * originally.
1953  * 
1954  * Return value: the widget that originally received @event, or %NULL
1955  **/
1956 GtkWidget*
1957 gtk_get_event_widget (GdkEvent *event)
1958 {
1959   GtkWidget *widget;
1960
1961   widget = NULL;
1962   if (event && event->any.window)
1963     gdk_window_get_user_data (event->any.window, (void**) &widget);
1964   
1965   return widget;
1966 }
1967
1968 static gint
1969 gtk_quit_invoke_function (GtkQuitFunction *quitf)
1970 {
1971   if (!quitf->marshal)
1972     return quitf->function (quitf->data);
1973   else
1974     {
1975       GtkArg args[1];
1976       gint ret_val = FALSE;
1977
1978       args[0].name = NULL;
1979       args[0].type = GTK_TYPE_BOOL;
1980       args[0].d.pointer_data = &ret_val;
1981       ((GtkCallbackMarshal) quitf->marshal) (NULL,
1982                                              quitf->data,
1983                                              0, args);
1984       return ret_val;
1985     }
1986 }
1987
1988 /**
1989  * gtk_propagate_event:
1990  * @widget: a #GtkWidget
1991  * @event: an event
1992  *
1993  * Sends an event to a widget, propagating the event to parent widgets
1994  * if the event remains unhandled. Events received by GTK+ from GDK
1995  * normally begin in gtk_main_do_event(). Depending on the type of
1996  * event, existence of modal dialogs, grabs, etc., the event may be
1997  * propagated; if so, this function is used. gtk_propagate_event()
1998  * calls gtk_widget_event() on each widget it decides to send the
1999  * event to.  So gtk_widget_event() is the lowest-level function; it
2000  * simply emits the "event" and possibly an event-specific signal on a
2001  * widget.  gtk_propagate_event() is a bit higher-level, and
2002  * gtk_main_do_event() is the highest level.
2003  *
2004  * All that said, you most likely don't want to use any of these
2005  * functions; synthesizing events is rarely needed. Consider asking on
2006  * the mailing list for better ways to achieve your goals. For
2007  * example, use gdk_window_invalidate_rect() or
2008  * gtk_widget_queue_draw() instead of making up expose events.
2009  * 
2010  **/
2011 void
2012 gtk_propagate_event (GtkWidget *widget,
2013                      GdkEvent  *event)
2014 {
2015   gint handled_event;
2016   
2017   g_return_if_fail (GTK_IS_WIDGET (widget));
2018   g_return_if_fail (event != NULL);
2019   
2020   handled_event = FALSE;
2021
2022   gtk_widget_ref (widget);
2023       
2024   if ((event->type == GDK_KEY_PRESS) ||
2025       (event->type == GDK_KEY_RELEASE))
2026     {
2027       /* Only send key events within Window widgets to the Window
2028        *  The Window widget will in turn pass the
2029        *  key event on to the currently focused widget
2030        *  for that window.
2031        */
2032       GtkWidget *window;
2033
2034       window = gtk_widget_get_toplevel (widget);
2035       if (window && GTK_IS_WINDOW (window))
2036         {
2037           /* If there is a grab within the window, give the grab widget
2038            * a first crack at the key event
2039            */
2040           if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
2041             handled_event = gtk_widget_event (widget, event);
2042           
2043           if (!handled_event)
2044             {
2045               window = gtk_widget_get_toplevel (widget);
2046               if (window && GTK_IS_WINDOW (window))
2047                 {
2048                   if (GTK_WIDGET_IS_SENSITIVE (window))
2049                     gtk_widget_event (window, event);
2050                 }
2051             }
2052                   
2053           handled_event = TRUE; /* don't send to widget */
2054         }
2055     }
2056   
2057   /* Other events get propagated up the widget tree
2058    *  so that parents can see the button and motion
2059    *  events of the children.
2060    */
2061   if (!handled_event)
2062     {
2063       while (TRUE)
2064         {
2065           GtkWidget *tmp;
2066           
2067           handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
2068           tmp = widget->parent;
2069           gtk_widget_unref (widget);
2070
2071           widget = tmp;
2072           
2073           if (!handled_event && widget)
2074             gtk_widget_ref (widget);
2075           else
2076             break;
2077         }
2078     }
2079   else
2080     gtk_widget_unref (widget);
2081 }
2082
2083 #if 0
2084 static void
2085 gtk_error (gchar *str)
2086 {
2087   gtk_print (str);
2088 }
2089
2090 static void
2091 gtk_warning (gchar *str)
2092 {
2093   gtk_print (str);
2094 }
2095
2096 static void
2097 gtk_message (gchar *str)
2098 {
2099   gtk_print (str);
2100 }
2101
2102 static void
2103 gtk_print (gchar *str)
2104 {
2105   static GtkWidget *window = NULL;
2106   static GtkWidget *text;
2107   static int level = 0;
2108   GtkWidget *box1;
2109   GtkWidget *box2;
2110   GtkWidget *table;
2111   GtkWidget *hscrollbar;
2112   GtkWidget *vscrollbar;
2113   GtkWidget *separator;
2114   GtkWidget *button;
2115   
2116   if (level > 0)
2117     {
2118       fputs (str, stdout);
2119       fflush (stdout);
2120       return;
2121     }
2122   
2123   if (!window)
2124     {
2125       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2126       
2127       gtk_signal_connect (GTK_OBJECT (window), "destroy",
2128                           (GtkSignalFunc) gtk_widget_destroyed,
2129                           &window);
2130       
2131       gtk_window_set_title (GTK_WINDOW (window), "Messages");
2132       
2133       box1 = gtk_vbox_new (FALSE, 0);
2134       gtk_container_add (GTK_CONTAINER (window), box1);
2135       gtk_widget_show (box1);
2136       
2137       
2138       box2 = gtk_vbox_new (FALSE, 10);
2139       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2140       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2141       gtk_widget_show (box2);
2142       
2143       
2144       table = gtk_table_new (2, 2, FALSE);
2145       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
2146       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
2147       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
2148       gtk_widget_show (table);
2149       
2150       text = gtk_text_new (NULL, NULL);
2151       gtk_text_set_editable (GTK_TEXT (text), FALSE);
2152       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
2153       gtk_widget_show (text);
2154       gtk_widget_realize (text);
2155       
2156       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
2157       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
2158                         GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
2159       gtk_widget_show (hscrollbar);
2160       
2161       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
2162       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
2163                         GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2164       gtk_widget_show (vscrollbar);
2165       
2166       separator = gtk_hseparator_new ();
2167       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2168       gtk_widget_show (separator);
2169       
2170       
2171       box2 = gtk_vbox_new (FALSE, 10);
2172       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2173       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2174       gtk_widget_show (box2);
2175       
2176       
2177       button = gtk_button_new_with_label ("close");
2178       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2179                                  (GtkSignalFunc) gtk_widget_hide,
2180                                  GTK_OBJECT (window));
2181       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2182       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2183       gtk_widget_grab_default (button);
2184       gtk_widget_show (button);
2185     }
2186   
2187   level += 1;
2188   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
2189   level -= 1;
2190   
2191   if (!GTK_WIDGET_VISIBLE (window))
2192     gtk_widget_show (window);
2193 }
2194 #endif
2195
2196 gboolean
2197 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2198                                   GValue                *return_accu,
2199                                   const GValue          *handler_return,
2200                                   gpointer               dummy)
2201 {
2202   gboolean continue_emission;
2203   gboolean signal_handled;
2204   
2205   signal_handled = g_value_get_boolean (handler_return);
2206   g_value_set_boolean (return_accu, signal_handled);
2207   continue_emission = !signal_handled;
2208   
2209   return continue_emission;
2210 }