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