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