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