]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
hell, what CVS magic is going on here?
[~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 #ifdef GDK_WINDOWING_X11
28 #include <X11/Xlocale.h>        /* so we get the right setlocale */
29 #else
30 #include <locale.h>
31 #endif
32
33 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
34 #include <libintl.h>
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <gmodule.h>
41 #include "gtkdnd.h"
42 #include "gtkcompat.h"
43 #include "gtkmain.h"
44 #include "gtkrc.h"
45 #include "gtkselection.h"
46 #include "gtksignal.h"
47 #include "gtkwidget.h"
48 #include "gtkwindow.h"
49 #include "gtkprivate.h"
50 #include "gdk/gdki18n.h"
51 #include "config.h"
52 #include "gtkdebug.h"
53 #include "gtkintl.h"
54
55 /* Private type definitions
56  */
57 typedef struct _GtkInitFunction          GtkInitFunction;
58 typedef struct _GtkQuitFunction          GtkQuitFunction;
59 typedef struct _GtkClosure               GtkClosure;
60 typedef struct _GtkKeySnooperData        GtkKeySnooperData;
61
62 struct _GtkInitFunction
63 {
64   GtkFunction function;
65   gpointer data;
66 };
67
68 struct _GtkQuitFunction
69 {
70   guint id;
71   guint main_level;
72   GtkCallbackMarshal marshal;
73   GtkFunction function;
74   gpointer data;
75   GtkDestroyNotify destroy;
76 };
77
78 struct _GtkClosure
79 {
80   GtkCallbackMarshal marshal;
81   gpointer data;
82   GtkDestroyNotify destroy;
83 };
84
85 struct _GtkKeySnooperData
86 {
87   GtkKeySnoopFunc func;
88   gpointer func_data;
89   guint id;
90 };
91
92 static void  gtk_exit_func               (void);
93 static gint  gtk_quit_invoke_function    (GtkQuitFunction    *quitf);
94 static void  gtk_quit_destroy            (GtkQuitFunction    *quitf);
95 static gint  gtk_invoke_key_snoopers     (GtkWidget          *grab_widget,
96                                           GdkEvent           *event);
97
98 static void     gtk_destroy_closure      (gpointer            data);
99 static gboolean gtk_invoke_idle_timeout  (gpointer            data);
100 static void     gtk_invoke_input         (gpointer            data,
101                                           gint                source,
102                                           GdkInputCondition   condition);
103
104 #if 0
105 static void  gtk_error                   (gchar              *str);
106 static void  gtk_warning                 (gchar              *str);
107 static void  gtk_message                 (gchar              *str);
108 static void  gtk_print                   (gchar              *str);
109 #endif
110
111 const guint gtk_major_version = GTK_MAJOR_VERSION;
112 const guint gtk_minor_version = GTK_MINOR_VERSION;
113 const guint gtk_micro_version = GTK_MICRO_VERSION;
114 const guint gtk_binary_age = GTK_BINARY_AGE;
115 const guint gtk_interface_age = GTK_INTERFACE_AGE;
116
117 static guint gtk_main_loop_level = 0;
118 static gint gtk_initialized = FALSE;
119 static GList *current_events = NULL;
120
121 static GSList *main_loops = NULL;      /* stack of currently executing main loops */
122
123 static GSList *grabs = NULL;               /* A stack of unique grabs. The grabbing
124                                             *  widget is the first one on the list.
125                                             */
126 static GList *init_functions = NULL;       /* A list of init functions.
127                                             */
128 static GList *quit_functions = NULL;       /* A list of quit functions.
129                                             */
130 static GMemChunk *quit_mem_chunk = NULL;
131
132 static GSList *key_snoopers = NULL;
133
134 static GdkVisual *gtk_visual;              /* The visual to be used in creating new
135                                             *  widgets.
136                                             */
137 static GdkColormap *gtk_colormap;          /* The colormap to be used in creating new
138                                             *  widgets.
139                                             */
140
141 guint gtk_debug_flags = 0;                 /* Global GTK debug flag */
142
143 #ifdef G_ENABLE_DEBUG
144 static const GDebugKey gtk_debug_keys[] = {
145   {"misc", GTK_DEBUG_MISC},
146   {"dnd", GTK_DEBUG_DND},
147   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
148   {"text", GTK_DEBUG_TEXT},
149   {"tree", GTK_DEBUG_TREE},
150   {"updates", GTK_DEBUG_UPDATES}
151 };
152
153 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
154
155 #endif /* G_ENABLE_DEBUG */
156
157 gchar*
158 gtk_check_version (guint required_major,
159                    guint required_minor,
160                    guint required_micro)
161 {
162   if (required_major > GTK_MAJOR_VERSION)
163     return "Gtk+ version too old (major mismatch)";
164   if (required_major < GTK_MAJOR_VERSION)
165     return "Gtk+ version too new (major mismatch)";
166   if (required_minor > GTK_MINOR_VERSION)
167     return "Gtk+ version too old (minor mismatch)";
168   if (required_minor < GTK_MINOR_VERSION)
169     return "Gtk+ version too new (minor mismatch)";
170   if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
171     return "Gtk+ version too new (micro mismatch)";
172   if (required_micro > GTK_MICRO_VERSION)
173     return "Gtk+ version too old (micro mismatch)";
174   return NULL;
175 }
176
177 #ifdef __EMX__
178 static gchar *add_dll_suffix(gchar *module_name)
179 {
180     gchar *suffix = strrchr(module_name, '.');
181     
182     if (!suffix || stricmp(suffix, ".dll"))
183     {
184         gchar *old = module_name;
185           
186         module_name = g_strconcat (module_name, ".dll", NULL);
187         g_free (old);
188     }
189     return (module_name);
190 }
191 #endif
192
193 #undef gtk_init_check
194
195 gboolean
196 gtk_init_check (int      *argc,
197                 char   ***argv)
198 {
199   GSList *gtk_modules = NULL;
200   GSList *slist;
201   gchar *env_string = NULL;
202
203   if (gtk_initialized)
204     return TRUE;
205
206 #if     0
207   g_set_error_handler (gtk_error);
208   g_set_warning_handler (gtk_warning);
209   g_set_message_handler (gtk_message);
210   g_set_print_handler (gtk_print);
211 #endif
212   
213   /* Initialize "gdk". We pass along the 'argc' and 'argv'
214    *  parameters as they contain information that GDK uses
215    */
216   if (!gdk_init_check (argc, argv))
217     return FALSE;
218
219   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
220   
221 #ifdef G_ENABLE_DEBUG
222   env_string = getenv ("GTK_DEBUG");
223   if (env_string != NULL)
224     {
225       gtk_debug_flags = g_parse_debug_string (env_string,
226                                               gtk_debug_keys,
227                                               gtk_ndebug_keys);
228       env_string = NULL;
229     }
230 #endif  /* G_ENABLE_DEBUG */
231
232   env_string = getenv ("GTK_MODULES");
233   if (env_string)
234     {
235       gchar **modules, **as;
236
237 #ifndef __EMX__
238       modules = g_strsplit (env_string, G_SEARCHPATH_SEPARATOR_S, -1);
239 #else
240       modules = g_strsplit (env_string, ";", -1);
241 #endif
242       for (as = modules; *as; as++)
243         {
244           if (**as)
245             gtk_modules = g_slist_prepend (gtk_modules, *as);
246           else
247             g_free (*as);
248         }
249       g_free (modules);
250       env_string = NULL;
251     }
252
253   if (argc && argv)
254     {
255       gint i, j, k;
256       
257       for (i = 1; i < *argc;)
258         {
259           if (strcmp ("--gtk-module", (*argv)[i]) == 0 ||
260               strncmp ("--gtk-module=", (*argv)[i], 13) == 0)
261             {
262               gchar *module_name = (*argv)[i] + 12;
263               
264               if (*module_name == '=')
265                 module_name++;
266               else if (i + 1 < *argc)
267                 {
268                   (*argv)[i] = NULL;
269                   i += 1;
270                   module_name = (*argv)[i];
271                 }
272               (*argv)[i] = NULL;
273
274               if (module_name && *module_name)
275                 gtk_modules = g_slist_prepend (gtk_modules, g_strdup (module_name));
276             }
277           else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0)
278             {
279               GLogLevelFlags fatal_mask;
280               
281               fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
282               fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
283               g_log_set_always_fatal (fatal_mask);
284               (*argv)[i] = NULL;
285             }
286 #ifdef G_ENABLE_DEBUG
287           else if ((strcmp ("--gtk-debug", (*argv)[i]) == 0) ||
288                    (strncmp ("--gtk-debug=", (*argv)[i], 12) == 0))
289             {
290               gchar *equal_pos = strchr ((*argv)[i], '=');
291               
292               if (equal_pos != NULL)
293                 {
294                   gtk_debug_flags |= g_parse_debug_string (equal_pos+1,
295                                                            gtk_debug_keys,
296                                                            gtk_ndebug_keys);
297                 }
298               else if ((i + 1) < *argc && (*argv)[i + 1])
299                 {
300                   gtk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
301                                                            gtk_debug_keys,
302                                                            gtk_ndebug_keys);
303                   (*argv)[i] = NULL;
304                   i += 1;
305                 }
306               (*argv)[i] = NULL;
307             }
308           else if ((strcmp ("--gtk-no-debug", (*argv)[i]) == 0) ||
309                    (strncmp ("--gtk-no-debug=", (*argv)[i], 15) == 0))
310             {
311               gchar *equal_pos = strchr ((*argv)[i], '=');
312               
313               if (equal_pos != NULL)
314                 {
315                   gtk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
316                                                             gtk_debug_keys,
317                                                             gtk_ndebug_keys);
318                 }
319               else if ((i + 1) < *argc && (*argv)[i + 1])
320                 {
321                   gtk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
322                                                             gtk_debug_keys,
323                                                             gtk_ndebug_keys);
324                   (*argv)[i] = NULL;
325                   i += 1;
326                 }
327               (*argv)[i] = NULL;
328             }
329 #endif /* G_ENABLE_DEBUG */
330           i += 1;
331         }
332       
333       for (i = 1; i < *argc; i++)
334         {
335           for (k = i; k < *argc; k++)
336             if ((*argv)[k] != NULL)
337               break;
338           
339           if (k > i)
340             {
341               k -= i;
342               for (j = i + k; j < *argc; j++)
343                 (*argv)[j-k] = (*argv)[j];
344               *argc -= k;
345             }
346         }
347     }
348
349   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
350     gdk_window_set_debug_updates (TRUE);
351   
352   /* load gtk modules */
353   gtk_modules = g_slist_reverse (gtk_modules);
354   for (slist = gtk_modules; slist; slist = slist->next)
355     {
356       gchar *module_name;
357       GModule *module = NULL;
358       GtkModuleInitFunc modinit_func = NULL;
359       
360       module_name = slist->data;
361       slist->data = NULL;
362 #ifndef __EMX__
363       if (!g_path_is_absolute (module_name))
364         {
365           gchar *old = module_name;
366           
367           module_name = g_module_build_path (NULL, module_name);
368           g_free (old);
369         }
370 #else
371       module_name = add_dll_suffix(module_name);
372 #endif
373       if (g_module_supported ())
374         {
375           module = g_module_open (module_name, G_MODULE_BIND_LAZY);
376           if (module &&
377               g_module_symbol (module, "gtk_module_init", (gpointer*) &modinit_func) &&
378               modinit_func)
379             {
380               if (!g_slist_find (gtk_modules, modinit_func))
381                 {
382                   g_module_make_resident (module);
383                   slist->data = modinit_func;
384                 }
385               else
386                 {
387                   g_module_close (module);
388                   module = NULL;
389                 }
390             }
391         }
392       if (!modinit_func)
393         {
394           g_message ("Failed to load module \"%s\": %s",
395                      module ? g_module_name (module) : module_name,
396                      g_module_error ());
397           if (module)
398             g_module_close (module);
399         }
400       g_free (module_name);
401     }
402
403 #ifdef ENABLE_NLS
404 #  ifndef G_OS_WIN32
405   bindtextdomain(GETTEXT_PACKAGE, GTK_LOCALEDIR);
406 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
407   bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
408 #    endif
409 #  else /* !G_OS_WIN32 */
410   {
411     bindtextdomain (GETTEXT_PACKAGE,
412                     g_win32_get_package_installation_subdirectory (GETTEXT_PACKAGE,
413                                                                    g_strdup_printf ("gtk-%d.%d.dll", GTK_MAJOR_VERSION, GTK_MINOR_VERSION),
414                                                                    "locale"));
415   }
416 #endif
417 #endif  
418
419   {
420   /* Translate to default:RTL if you want your widgets
421    * to be RTL, otherwise translate to default:LTR.
422    * Do *not* translate it to "predefinito:LTR", if it
423    * it isn't default:LTR or default:RTL it will not work 
424    */
425     char *e = _("default:LTR");
426     if (strcmp (e, "default:RTL")==0) {
427       gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
428     } else if (strcmp (e, "default:LTR")) {
429       g_warning ("Whoever translated default:LTR did so wrongly.\n");
430     }
431   }
432
433   /* Initialize the default visual and colormap to be
434    *  used in creating widgets. (We want to use the system
435    *  defaults so as to be nice to the colormap).
436    */
437   gtk_visual = gdk_visual_get_system ();
438   gtk_colormap = gdk_colormap_get_system ();
439
440   gtk_type_init (0);
441   gtk_rc_init ();
442   
443   
444   /* Register an exit function to make sure we are able to cleanup.
445    */
446   g_atexit (gtk_exit_func);
447   
448   /* Set the 'initialized' flag.
449    */
450   gtk_initialized = TRUE;
451
452   /* initialize gtk modules
453    */
454   for (slist = gtk_modules; slist; slist = slist->next)
455     {
456       if (slist->data)
457         {
458           GtkModuleInitFunc modinit;
459           
460           modinit = slist->data;
461           modinit (argc, argv);
462         }
463     }
464   g_slist_free (gtk_modules);
465   
466 #ifndef G_OS_WIN32
467   /* No use warning on Win32, there aren't any non-devel versions anyhow... */
468   g_message (""              "YOU ARE USING THE DEVEL BRANCH 1.3.x OF GTK+ WHICH IS CURRENTLY\n"
469              "                UNDER HEAVY DEVELOPMENT AND FREQUENTLY INTRODUCES INSTABILITIES.\n"
470              "                if you don't know why you are getting this, you probably want to\n"
471              "                use the stable branch which can be retrived from\n"
472              "                ftp://ftp.gtk.org/pub/gtk/v1.2/ or via CVS with\n"
473              "                cvs checkout -r glib-1-2 glib; cvs checkout -r gtk-1-2 gtk+");
474 #endif
475
476   return TRUE;
477 }
478
479 #undef gtk_init
480
481 void
482 gtk_init (int *argc, char ***argv)
483 {
484   if (!gtk_init_check (argc, argv))
485     {
486       g_warning ("cannot open display: %s", gdk_get_display ());
487       exit(1);
488     }
489 }
490
491 #ifdef G_OS_WIN32
492
493 static void
494 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
495 {
496   if (sizeof_GtkWindow != sizeof (GtkWindow))
497     g_error ("Incompatible build!\n"
498              "The code using GTK+ thinks GtkWindow is of different\n"
499              "size than it actually is in this build of GTK+.\n"
500              "On Windows, this probably means that you have compiled\n"
501              "your code with gcc without the -fnative-struct switch.");
502 }
503
504 /* These two functions might get more checks added later, thus pass
505  * in the number of extra args.
506  */
507 void
508 gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
509 {
510   check_sizeof_GtkWindow (sizeof_GtkWindow);
511   gtk_init (argc, argv);
512 }
513
514 gboolean
515 gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
516 {
517   check_sizeof_GtkWindow (sizeof_GtkWindow);
518   return gtk_init_check (argc, argv);
519 }
520
521 #endif
522
523 void
524 gtk_exit (gint errorcode)
525 {
526   /* Only if "gtk" has been initialized should we de-initialize.
527    */
528   /* de-initialisation is done by the gtk_exit_funct(),
529    * no need to do this here (Alex J.)
530    */
531   gdk_exit(errorcode);
532 }
533
534 gchar*
535 gtk_set_locale (void)
536 {
537   return gdk_set_locale ();
538 }
539
540 /**
541  * gtk_get_default_language:
542  *
543  * Returns the ISO language code for the default language currently in
544  * effect. (Note that this can change over the life of an
545  * application.)  The default language is derived from the current
546  * locale. It determines, for example, whether GTK+ uses the
547  * right-to-left or left-to-right text direction.
548  * 
549  * Return value: the default language as an allocated string, must be freed
550  **/
551 gchar*
552 gtk_get_default_language (void)
553 {
554   gchar *lang;
555   gchar *p;
556   
557   lang = g_strdup (setlocale (LC_CTYPE, NULL));
558   p = strchr (lang, '.');
559   if (p)
560     *p = '\0';
561   p = strchr (lang, '@');
562   if (p)
563     *p = '\0';
564
565   return lang;
566 }
567
568 void
569 gtk_main (void)
570 {
571   GList *tmp_list;
572   GList *functions;
573   GtkInitFunction *init;
574   GMainLoop *loop;
575
576   gtk_main_loop_level++;
577   
578   loop = g_main_new (TRUE);
579   main_loops = g_slist_prepend (main_loops, loop);
580
581   tmp_list = functions = init_functions;
582   init_functions = NULL;
583   
584   while (tmp_list)
585     {
586       init = tmp_list->data;
587       tmp_list = tmp_list->next;
588       
589       (* init->function) (init->data);
590       g_free (init);
591     }
592   g_list_free (functions);
593
594   if (g_main_is_running (main_loops->data))
595     {
596       GDK_THREADS_LEAVE ();
597       g_main_run (loop);
598       GDK_THREADS_ENTER ();
599       gdk_flush ();
600     }
601
602   if (quit_functions)
603     {
604       GList *reinvoke_list = NULL;
605       GtkQuitFunction *quitf;
606
607       while (quit_functions)
608         {
609           quitf = quit_functions->data;
610
611           tmp_list = quit_functions;
612           quit_functions = g_list_remove_link (quit_functions, quit_functions);
613           g_list_free_1 (tmp_list);
614
615           if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
616               gtk_quit_invoke_function (quitf))
617             {
618               reinvoke_list = g_list_prepend (reinvoke_list, quitf);
619             }
620           else
621             {
622               gtk_quit_destroy (quitf);
623             }
624         }
625       if (reinvoke_list)
626         {
627           GList *work;
628           
629           work = g_list_last (reinvoke_list);
630           if (quit_functions)
631             quit_functions->prev = work;
632           work->next = quit_functions;
633           quit_functions = work;
634         }
635
636       gdk_flush ();
637     }
638               
639   main_loops = g_slist_remove (main_loops, loop);
640
641   g_main_destroy (loop);
642
643   gtk_main_loop_level--;
644 }
645
646 guint
647 gtk_main_level (void)
648 {
649   return gtk_main_loop_level;
650 }
651
652 void
653 gtk_main_quit (void)
654 {
655   g_return_if_fail (main_loops != NULL);
656
657   g_main_quit (main_loops->data);
658 }
659
660 gint
661 gtk_events_pending (void)
662 {
663   gboolean result;
664   
665   GDK_THREADS_LEAVE ();  
666   result = g_main_pending();
667   GDK_THREADS_ENTER ();
668
669   return result;
670 }
671
672 gint 
673 gtk_main_iteration (void)
674 {
675   GDK_THREADS_LEAVE ();
676   g_main_iteration (TRUE);
677   GDK_THREADS_ENTER ();
678
679   if (main_loops)
680     return !g_main_is_running (main_loops->data);
681   else
682     return TRUE;
683 }
684
685 gint 
686 gtk_main_iteration_do (gboolean blocking)
687 {
688   GDK_THREADS_LEAVE ();
689   g_main_iteration (blocking);
690   GDK_THREADS_ENTER ();
691
692   if (main_loops)
693     return !g_main_is_running (main_loops->data);
694   else
695     return TRUE;
696 }
697
698 void 
699 gtk_main_do_event (GdkEvent *event)
700 {
701   GtkWidget *event_widget;
702   GtkWidget *grab_widget;
703   GdkEvent *next_event;
704   GList *tmp_list;
705
706   /* If there are any events pending then get the next one.
707    */
708   next_event = gdk_event_peek ();
709   
710   /* Try to compress enter/leave notify events. These event
711    *  pairs occur when the mouse is dragged quickly across
712    *  a window with many buttons (or through a menu). Instead
713    *  of highlighting and de-highlighting each widget that
714    *  is crossed it is better to simply de-highlight the widget
715    *  which contained the mouse initially and highlight the
716    *  widget which ends up containing the mouse.
717    */
718   if (next_event)
719     if (((event->type == GDK_ENTER_NOTIFY) ||
720          (event->type == GDK_LEAVE_NOTIFY)) &&
721         ((next_event->type == GDK_ENTER_NOTIFY) ||
722          (next_event->type == GDK_LEAVE_NOTIFY)) &&
723         (next_event->type != event->type) &&
724         (next_event->any.window == event->any.window))
725       {
726         /* Throw both the peeked copy and the queued copy away 
727          */
728         gdk_event_free (next_event);
729         next_event = gdk_event_get ();
730         gdk_event_free (next_event);
731         
732         return;
733       }
734
735   if (next_event)
736     gdk_event_free (next_event);
737
738   /* Find the widget which got the event. We store the widget
739    *  in the user_data field of GdkWindow's.
740    *  Ignore the event if we don't have a widget for it, except
741    *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
742    *  Though this happens rarely, bogus events can occour
743    *  for e.g. destroyed GdkWindows. 
744    */
745   event_widget = gtk_get_event_widget (event);
746   if (!event_widget)
747     {
748       /* To handle selection INCR transactions, we select
749        * PropertyNotify events on the requestor window and create
750        * a corresponding (fake) GdkWindow so that events get
751        * here. There won't be a widget though, so we have to handle
752            * them specially
753            */
754       if (event->type == GDK_PROPERTY_NOTIFY)
755         gtk_selection_incr_event (event->any.window,
756                                   &event->property);
757       
758       return;
759     }
760   
761   /* Push the event onto a stack of current events for
762    * gtk_current_event_get().
763    */
764   current_events = g_list_prepend (current_events, event);
765   
766   /* If there is a grab in effect...
767    */
768   if (grabs)
769     {
770       grab_widget = grabs->data;
771       
772       /* If the grab widget is an ancestor of the event widget
773        *  then we send the event to the original event widget.
774        *  This is the key to implementing modality.
775        */
776       if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
777           gtk_widget_is_ancestor (event_widget, grab_widget))
778         grab_widget = event_widget;
779     }
780   else
781     {
782       grab_widget = event_widget;
783     }
784
785   /* Not all events get sent to the grabbing widget.
786    * The delete, destroy, expose, focus change and resize
787    *  events still get sent to the event widget because
788    *  1) these events have no meaning for the grabbing widget
789    *  and 2) redirecting these events to the grabbing widget
790    *  could cause the display to be messed up.
791    * 
792    * Drag events are also not redirected, since it isn't
793    *  clear what the semantics of that would be.
794    */
795   switch (event->type)
796     {
797     case GDK_NOTHING:
798       break;
799       
800     case GDK_DELETE:
801       gtk_widget_ref (event_widget);
802       if ((!grabs || gtk_widget_get_toplevel (grabs->data) == event_widget) &&
803           !gtk_widget_event (event_widget, event))
804         gtk_widget_destroy (event_widget);
805       gtk_widget_unref (event_widget);
806       break;
807       
808     case GDK_DESTROY:
809       /* Unexpected GDK_DESTROY from the outside, ignore for
810        * child windows, handle like a GDK_DELETE for toplevels
811        */
812       if (!event_widget->parent)
813         {
814           gtk_widget_ref (event_widget);
815           if (!gtk_widget_event (event_widget, event) &&
816               !GTK_OBJECT_DESTROYED (event_widget))
817             gtk_widget_destroy (event_widget);
818           gtk_widget_unref (event_widget);
819         }
820       break;
821       
822     case GDK_EXPOSE:
823       if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
824         gdk_window_begin_paint_rect (event->any.window, &event->expose.area);
825
826       gtk_widget_event (event_widget, event);
827
828       if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
829         gdk_window_end_paint (event->any.window);
830       break;
831
832     case GDK_PROPERTY_NOTIFY:
833     case GDK_NO_EXPOSE:
834     case GDK_FOCUS_CHANGE:
835     case GDK_CONFIGURE:
836     case GDK_MAP:
837     case GDK_UNMAP:
838     case GDK_SELECTION_CLEAR:
839     case GDK_SELECTION_REQUEST:
840     case GDK_SELECTION_NOTIFY:
841     case GDK_CLIENT_EVENT:
842     case GDK_VISIBILITY_NOTIFY:
843       gtk_widget_event (event_widget, event);
844       break;
845
846     case GDK_SCROLL:
847     case GDK_BUTTON_PRESS:
848     case GDK_2BUTTON_PRESS:
849     case GDK_3BUTTON_PRESS:
850       gtk_propagate_event (grab_widget, event);
851       break;
852
853     case GDK_KEY_PRESS:
854     case GDK_KEY_RELEASE:
855       if (key_snoopers)
856         {
857           if (gtk_invoke_key_snoopers (grab_widget, event))
858             break;
859         }
860       /* else fall through */
861     case GDK_MOTION_NOTIFY:
862     case GDK_BUTTON_RELEASE:
863     case GDK_PROXIMITY_IN:
864     case GDK_PROXIMITY_OUT:
865       gtk_propagate_event (grab_widget, event);
866       break;
867       
868     case GDK_ENTER_NOTIFY:
869       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
870         {
871           gtk_widget_event (grab_widget, event);
872           if (event_widget == grab_widget)
873             GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
874         }
875       break;
876       
877     case GDK_LEAVE_NOTIFY:
878       if (GTK_WIDGET_LEAVE_PENDING (event_widget))
879         {
880           GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
881           gtk_widget_event (event_widget, event);
882         }
883       else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
884         gtk_widget_event (grab_widget, event);
885       break;
886       
887     case GDK_DRAG_STATUS:
888     case GDK_DROP_FINISHED:
889       gtk_drag_source_handle_event (event_widget, event);
890       break;
891     case GDK_DRAG_ENTER:
892     case GDK_DRAG_LEAVE:
893     case GDK_DRAG_MOTION:
894     case GDK_DROP_START:
895       gtk_drag_dest_handle_event (event_widget, event);
896       break;
897     }
898   
899   tmp_list = current_events;
900   current_events = g_list_remove_link (current_events, tmp_list);
901   g_list_free_1 (tmp_list);
902 }
903
904 gint
905 gtk_true (void)
906 {
907   return TRUE;
908 }
909
910 gint
911 gtk_false (void)
912 {
913   return FALSE;
914 }
915
916 void
917 gtk_grab_add (GtkWidget *widget)
918 {
919   g_return_if_fail (widget != NULL);
920   
921   if (!GTK_WIDGET_HAS_GRAB (widget))
922     {
923       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
924       
925       grabs = g_slist_prepend (grabs, widget);
926       gtk_widget_ref (widget);
927     }
928 }
929
930 GtkWidget*
931 gtk_grab_get_current (void)
932 {
933   if (grabs)
934     return GTK_WIDGET (grabs->data);
935   return NULL;
936 }
937
938 void
939 gtk_grab_remove (GtkWidget *widget)
940 {
941   g_return_if_fail (widget != NULL);
942   
943   if (GTK_WIDGET_HAS_GRAB (widget))
944     {
945       GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
946       
947       grabs = g_slist_remove (grabs, widget);
948       gtk_widget_unref (widget);
949     }
950 }
951
952 void
953 gtk_init_add (GtkFunction function,
954               gpointer    data)
955 {
956   GtkInitFunction *init;
957   
958   init = g_new (GtkInitFunction, 1);
959   init->function = function;
960   init->data = data;
961   
962   init_functions = g_list_prepend (init_functions, init);
963 }
964
965 guint
966 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
967                          gpointer        func_data)
968 {
969   GtkKeySnooperData *data;
970   static guint snooper_id = 1;
971
972   g_return_val_if_fail (snooper != NULL, 0);
973
974   data = g_new (GtkKeySnooperData, 1);
975   data->func = snooper;
976   data->func_data = func_data;
977   data->id = snooper_id++;
978   key_snoopers = g_slist_prepend (key_snoopers, data);
979
980   return data->id;
981 }
982
983 void
984 gtk_key_snooper_remove (guint            snooper_id)
985 {
986   GtkKeySnooperData *data = NULL;
987   GSList *slist;
988
989   slist = key_snoopers;
990   while (slist)
991     {
992       data = slist->data;
993       if (data->id == snooper_id)
994         break;
995
996       slist = slist->next;
997       data = NULL;
998     }
999   if (data)
1000     key_snoopers = g_slist_remove (key_snoopers, data);
1001 }
1002
1003 static gint
1004 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
1005                          GdkEvent  *event)
1006 {
1007   GSList *slist;
1008   gint return_val = FALSE;
1009
1010   slist = key_snoopers;
1011   while (slist && !return_val)
1012     {
1013       GtkKeySnooperData *data;
1014
1015       data = slist->data;
1016       slist = slist->next;
1017       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
1018     }
1019
1020   return return_val;
1021 }
1022
1023 guint
1024 gtk_quit_add_full (guint                main_level,
1025                    GtkFunction          function,
1026                    GtkCallbackMarshal   marshal,
1027                    gpointer             data,
1028                    GtkDestroyNotify     destroy)
1029 {
1030   static guint quit_id = 1;
1031   GtkQuitFunction *quitf;
1032   
1033   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
1034
1035   if (!quit_mem_chunk)
1036     quit_mem_chunk = g_mem_chunk_new ("quit mem chunk", sizeof (GtkQuitFunction),
1037                                       512, G_ALLOC_AND_FREE);
1038   
1039   quitf = g_chunk_new (GtkQuitFunction, quit_mem_chunk);
1040   
1041   quitf->id = quit_id++;
1042   quitf->main_level = main_level;
1043   quitf->function = function;
1044   quitf->marshal = marshal;
1045   quitf->data = data;
1046   quitf->destroy = destroy;
1047
1048   quit_functions = g_list_prepend (quit_functions, quitf);
1049   
1050   return quitf->id;
1051 }
1052
1053 static void
1054 gtk_quit_destroy (GtkQuitFunction *quitf)
1055 {
1056   if (quitf->destroy)
1057     quitf->destroy (quitf->data);
1058   g_mem_chunk_free (quit_mem_chunk, quitf);
1059 }
1060
1061 static gint
1062 gtk_quit_destructor (GtkObject **object_p)
1063 {
1064   if (*object_p)
1065     gtk_object_destroy (*object_p);
1066   g_free (object_p);
1067
1068   return FALSE;
1069 }
1070
1071 void
1072 gtk_quit_add_destroy (guint              main_level,
1073                       GtkObject         *object)
1074 {
1075   GtkObject **object_p;
1076
1077   g_return_if_fail (main_level > 0);
1078   g_return_if_fail (object != NULL);
1079   g_return_if_fail (GTK_IS_OBJECT (object));
1080
1081   object_p = g_new (GtkObject*, 1);
1082   *object_p = object;
1083   gtk_signal_connect (object,
1084                       "destroy",
1085                       GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1086                       object_p);
1087   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1088 }
1089
1090 guint
1091 gtk_quit_add (guint       main_level,
1092               GtkFunction function,
1093               gpointer    data)
1094 {
1095   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
1096 }
1097
1098 void
1099 gtk_quit_remove (guint id)
1100 {
1101   GtkQuitFunction *quitf;
1102   GList *tmp_list;
1103   
1104   tmp_list = quit_functions;
1105   while (tmp_list)
1106     {
1107       quitf = tmp_list->data;
1108       
1109       if (quitf->id == id)
1110         {
1111           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1112           g_list_free (tmp_list);
1113           gtk_quit_destroy (quitf);
1114           
1115           return;
1116         }
1117       
1118       tmp_list = tmp_list->next;
1119     }
1120 }
1121
1122 void
1123 gtk_quit_remove_by_data (gpointer data)
1124 {
1125   GtkQuitFunction *quitf;
1126   GList *tmp_list;
1127   
1128   tmp_list = quit_functions;
1129   while (tmp_list)
1130     {
1131       quitf = tmp_list->data;
1132       
1133       if (quitf->data == data)
1134         {
1135           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1136           g_list_free (tmp_list);
1137           gtk_quit_destroy (quitf);
1138
1139           return;
1140         }
1141       
1142       tmp_list = tmp_list->next;
1143     }
1144 }
1145
1146 guint
1147 gtk_timeout_add_full (guint32            interval,
1148                       GtkFunction        function,
1149                       GtkCallbackMarshal marshal,
1150                       gpointer           data,
1151                       GtkDestroyNotify   destroy)
1152 {
1153   if (marshal)
1154     {
1155       GtkClosure *closure;
1156
1157       closure = g_new (GtkClosure, 1);
1158       closure->marshal = marshal;
1159       closure->data = data;
1160       closure->destroy = destroy;
1161
1162       return g_timeout_add_full (0, interval, 
1163                                  gtk_invoke_idle_timeout,
1164                                  closure,
1165                                  gtk_destroy_closure);
1166     }
1167   else
1168     return g_timeout_add_full (0, interval, function, data, destroy);
1169 }
1170
1171 guint
1172 gtk_timeout_add (guint32     interval,
1173                  GtkFunction function,
1174                  gpointer    data)
1175 {
1176   return g_timeout_add_full (0, interval, function, data, NULL);
1177 }
1178
1179 void
1180 gtk_timeout_remove (guint tag)
1181 {
1182   g_source_remove (tag);
1183 }
1184
1185 guint
1186 gtk_idle_add_full (gint                 priority,
1187                    GtkFunction          function,
1188                    GtkCallbackMarshal   marshal,
1189                    gpointer             data,
1190                    GtkDestroyNotify     destroy)
1191 {
1192   if (marshal)
1193     {
1194       GtkClosure *closure;
1195
1196       closure = g_new (GtkClosure, 1);
1197       closure->marshal = marshal;
1198       closure->data = data;
1199       closure->destroy = destroy;
1200
1201       return g_idle_add_full (priority,
1202                               gtk_invoke_idle_timeout,
1203                               closure,
1204                               gtk_destroy_closure);
1205     }
1206   else
1207     return g_idle_add_full (priority, function, data, destroy);
1208 }
1209
1210 guint
1211 gtk_idle_add (GtkFunction function,
1212               gpointer    data)
1213 {
1214   return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL);
1215 }
1216
1217 guint       
1218 gtk_idle_add_priority   (gint               priority,
1219                          GtkFunction        function,
1220                          gpointer           data)
1221 {
1222   return g_idle_add_full (priority, function, data, NULL);
1223 }
1224
1225 void
1226 gtk_idle_remove (guint tag)
1227 {
1228   g_source_remove (tag);
1229 }
1230
1231 void
1232 gtk_idle_remove_by_data (gpointer data)
1233 {
1234   if (!g_idle_remove_by_data (data))
1235     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
1236 }
1237
1238 guint
1239 gtk_input_add_full (gint                source,
1240                     GdkInputCondition   condition,
1241                     GdkInputFunction    function,
1242                     GtkCallbackMarshal  marshal,
1243                     gpointer            data,
1244                     GtkDestroyNotify    destroy)
1245 {
1246   if (marshal)
1247     {
1248       GtkClosure *closure;
1249
1250       closure = g_new (GtkClosure, 1);
1251       closure->marshal = marshal;
1252       closure->data = data;
1253       closure->destroy = destroy;
1254
1255       return gdk_input_add_full (source,
1256                                  condition,
1257                                  (GdkInputFunction) gtk_invoke_input,
1258                                  closure,
1259                                  (GdkDestroyNotify) gtk_destroy_closure);
1260     }
1261   else
1262     return gdk_input_add_full (source, condition, function, data, destroy);
1263 }
1264
1265 void
1266 gtk_input_remove (guint tag)
1267 {
1268   g_source_remove (tag);
1269 }
1270
1271 static void
1272 gtk_destroy_closure (gpointer data)
1273 {
1274   GtkClosure *closure = data;
1275
1276   if (closure->destroy)
1277     (closure->destroy) (closure->data);
1278   g_free (closure);
1279 }
1280
1281 static gboolean
1282 gtk_invoke_idle_timeout (gpointer data)
1283 {
1284   GtkClosure *closure = data;
1285
1286   GtkArg args[1];
1287   gint ret_val = FALSE;
1288   args[0].name = NULL;
1289   args[0].type = GTK_TYPE_BOOL;
1290   args[0].d.pointer_data = &ret_val;
1291   closure->marshal (NULL, closure->data,  0, args);
1292   return ret_val;
1293 }
1294
1295 static void
1296 gtk_invoke_input (gpointer          data,
1297                   gint              source,
1298                   GdkInputCondition condition)
1299 {
1300   GtkClosure *closure = data;
1301
1302   GtkArg args[3];
1303   args[0].type = GTK_TYPE_INT;
1304   args[0].name = NULL;
1305   GTK_VALUE_INT(args[0]) = source;
1306   args[1].type = GTK_TYPE_GDK_INPUT_CONDITION;
1307   args[1].name = NULL;
1308   GTK_VALUE_FLAGS(args[1]) = condition;
1309   args[2].type = GTK_TYPE_NONE;
1310   args[2].name = NULL;
1311
1312   closure->marshal (NULL, closure->data, 2, args);
1313 }
1314
1315 /**
1316  * gtk_get_current_event:
1317  * 
1318  * Obtains a copy of the event currently being processed by GTK+.  For
1319  * example, if you get a "clicked" signal from #GtkButton, the current
1320  * event will be the #GdkEventButton that triggered the "clicked"
1321  * signal. The returned event must be freed with gdk_event_free().
1322  * If there is no current event, the function returns %NULL.
1323  * 
1324  * Return value: a copy of the current event, or %NULL if no current event.
1325  **/
1326 GdkEvent*
1327 gtk_get_current_event (void)
1328 {
1329   if (current_events)
1330     return gdk_event_copy (current_events->data);
1331   else
1332     return NULL;
1333 }
1334
1335 /**
1336  * gtk_get_current_event_time:
1337  * 
1338  * If there is a current event and it has a timestamp, return that
1339  * timestamp, otherwise return %GDK_CURRENT_TIME.
1340  * 
1341  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
1342  **/
1343 guint32
1344 gtk_get_current_event_time (void)
1345 {
1346   if (current_events)
1347     return gdk_event_get_time (current_events->data);
1348   else
1349     return GDK_CURRENT_TIME;
1350 }
1351
1352 /**
1353  * gtk_get_current_event_state:
1354  * @state: a location to store the state of the current event
1355  * 
1356  * If there is a current event and it has a state field, place
1357  * that state field in @state and return %TRUE, otherwise return
1358  * %FALSE.
1359  * 
1360  * Return value: %TRUE if there was a current event and it had a state field
1361  **/
1362 gboolean
1363 gtk_get_current_event_state (GdkModifierType *state)
1364 {
1365   g_return_val_if_fail (state != NULL, FALSE);
1366   
1367   if (current_events)
1368     return gdk_event_get_state (current_events->data, state);
1369   else
1370     {
1371       *state = 0;
1372       return FALSE;
1373     }
1374 }
1375
1376 /**
1377  * gtk_get_event_widget:
1378  * @event: a #GdkEvent
1379  *
1380  * If @event is %NULL or the event was not associated with any widget,
1381  * returns %NULL, otherwise returns the widget that received the event
1382  * originally.
1383  * 
1384  * Return value: the widget that originally received @event, or %NULL
1385  **/
1386 GtkWidget*
1387 gtk_get_event_widget (GdkEvent *event)
1388 {
1389   GtkWidget *widget;
1390
1391   widget = NULL;
1392   if (event && event->any.window)
1393     gdk_window_get_user_data (event->any.window, (void**) &widget);
1394   
1395   return widget;
1396 }
1397
1398 static void
1399 gtk_exit_func (void)
1400 {
1401   if (gtk_initialized)
1402     {
1403       gtk_initialized = FALSE;
1404     }
1405 }
1406
1407
1408 static gint
1409 gtk_quit_invoke_function (GtkQuitFunction *quitf)
1410 {
1411   if (!quitf->marshal)
1412     return quitf->function (quitf->data);
1413   else
1414     {
1415       GtkArg args[1];
1416       gint ret_val = FALSE;
1417
1418       args[0].name = NULL;
1419       args[0].type = GTK_TYPE_BOOL;
1420       args[0].d.pointer_data = &ret_val;
1421       ((GtkCallbackMarshal) quitf->marshal) (NULL,
1422                                              quitf->data,
1423                                              0, args);
1424       return ret_val;
1425     }
1426 }
1427
1428 /**
1429  * gtk_propagate_event:
1430  * @widget: a #GtkWidget
1431  * @event: an event
1432  *
1433  * Sends an event to a widget, propagating the event to parent widgets
1434  * if the event remains unhandled. Events received by GTK+ from GDK
1435  * normally begin in gtk_main_do_event(). Depending on the type of
1436  * event, existence of modal dialogs, grabs, etc., the event may be
1437  * propagated; if so, this function is used. gtk_propagate_event()
1438  * calls gtk_widget_event() on each widget it decides to send the
1439  * event to.  So gtk_widget_event() is the lowest-level function; it
1440  * simply emits the "event" and possibly an event-specific signal on a
1441  * widget.  gtk_propagate_event() is a bit higher-level, and
1442  * gtk_main_do_event() is the highest level.
1443  *
1444  * All that said, you most likely don't want to use any of these
1445  * functions; synthesizing events is rarely needed. Consider asking on
1446  * the mailing list for better ways to achieve your goals. For
1447  * example, use gdk_window_invalidate_rect() or
1448  * gtk_widget_queue_draw() instead of making up expose events.
1449  * 
1450  **/
1451 void
1452 gtk_propagate_event (GtkWidget *widget,
1453                      GdkEvent  *event)
1454 {
1455   gint handled_event;
1456   
1457   g_return_if_fail (widget != NULL);
1458   g_return_if_fail (GTK_IS_WIDGET (widget));
1459   g_return_if_fail (event != NULL);
1460   
1461   handled_event = FALSE;
1462
1463   if ((event->type == GDK_KEY_PRESS) ||
1464       (event->type == GDK_KEY_RELEASE))
1465     {
1466       /* Only send key events within Window widgets to the Window
1467        *  The Window widget will in turn pass the
1468        *  key event on to the currently focused widget
1469        *  for that window.
1470        */
1471       GtkWidget *window;
1472
1473       window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
1474       if (window)
1475         {
1476           if (GTK_WIDGET_IS_SENSITIVE (window))
1477             gtk_widget_event (window, event);
1478
1479           handled_event = TRUE; /* don't send to widget */
1480         }
1481     }
1482   
1483   /* Other events get propagated up the widget tree
1484    *  so that parents can see the button and motion
1485    *  events of the children.
1486    */
1487   while (!handled_event && widget)
1488     {
1489       GtkWidget *tmp;
1490
1491       gtk_widget_ref (widget);
1492       handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
1493       tmp = widget->parent;
1494       gtk_widget_unref (widget);
1495       widget  = tmp;
1496     }
1497 }
1498
1499 #if 0
1500 static void
1501 gtk_error (gchar *str)
1502 {
1503   gtk_print (str);
1504 }
1505
1506 static void
1507 gtk_warning (gchar *str)
1508 {
1509   gtk_print (str);
1510 }
1511
1512 static void
1513 gtk_message (gchar *str)
1514 {
1515   gtk_print (str);
1516 }
1517
1518 static void
1519 gtk_print (gchar *str)
1520 {
1521   static GtkWidget *window = NULL;
1522   static GtkWidget *text;
1523   static int level = 0;
1524   GtkWidget *box1;
1525   GtkWidget *box2;
1526   GtkWidget *table;
1527   GtkWidget *hscrollbar;
1528   GtkWidget *vscrollbar;
1529   GtkWidget *separator;
1530   GtkWidget *button;
1531   
1532   if (level > 0)
1533     {
1534       fputs (str, stdout);
1535       fflush (stdout);
1536       return;
1537     }
1538   
1539   if (!window)
1540     {
1541       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1542       
1543       gtk_signal_connect (GTK_OBJECT (window), "destroy",
1544                           (GtkSignalFunc) gtk_widget_destroyed,
1545                           &window);
1546       
1547       gtk_window_set_title (GTK_WINDOW (window), "Messages");
1548       
1549       box1 = gtk_vbox_new (FALSE, 0);
1550       gtk_container_add (GTK_CONTAINER (window), box1);
1551       gtk_widget_show (box1);
1552       
1553       
1554       box2 = gtk_vbox_new (FALSE, 10);
1555       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1556       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
1557       gtk_widget_show (box2);
1558       
1559       
1560       table = gtk_table_new (2, 2, FALSE);
1561       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
1562       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
1563       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
1564       gtk_widget_show (table);
1565       
1566       text = gtk_text_new (NULL, NULL);
1567       gtk_text_set_editable (GTK_TEXT (text), FALSE);
1568       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
1569       gtk_widget_show (text);
1570       gtk_widget_realize (text);
1571       
1572       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
1573       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
1574                         GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1575       gtk_widget_show (hscrollbar);
1576       
1577       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
1578       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
1579                         GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1580       gtk_widget_show (vscrollbar);
1581       
1582       separator = gtk_hseparator_new ();
1583       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
1584       gtk_widget_show (separator);
1585       
1586       
1587       box2 = gtk_vbox_new (FALSE, 10);
1588       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1589       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
1590       gtk_widget_show (box2);
1591       
1592       
1593       button = gtk_button_new_with_label ("close");
1594       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1595                                  (GtkSignalFunc) gtk_widget_hide,
1596                                  GTK_OBJECT (window));
1597       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1598       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1599       gtk_widget_grab_default (button);
1600       gtk_widget_show (button);
1601     }
1602   
1603   level += 1;
1604   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
1605   level -= 1;
1606   
1607   if (!GTK_WIDGET_VISIBLE (window))
1608     gtk_widget_show (window);
1609 }
1610 #endif