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