]> Pileus Git - ~andy/gtk/blob - gtk/gtkmain.c
For XEMBED embedding add a _XEMBED_INFO property to the client with
[~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 "gtkcompat.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   {"dnd", GTK_DEBUG_DND},
148   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
149   {"text", GTK_DEBUG_TEXT},
150   {"tree", GTK_DEBUG_TREE},
151   {"updates", GTK_DEBUG_UPDATES}
152 };
153
154 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
155
156 #endif /* G_ENABLE_DEBUG */
157
158 gchar*
159 gtk_check_version (guint required_major,
160                    guint required_minor,
161                    guint required_micro)
162 {
163   if (required_major > GTK_MAJOR_VERSION)
164     return "Gtk+ version too old (major mismatch)";
165   if (required_major < GTK_MAJOR_VERSION)
166     return "Gtk+ version too new (major mismatch)";
167   if (required_minor > GTK_MINOR_VERSION)
168     return "Gtk+ version too old (minor mismatch)";
169   if (required_minor < GTK_MINOR_VERSION)
170     return "Gtk+ version too new (minor mismatch)";
171   if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
172     return "Gtk+ version too new (micro mismatch)";
173   if (required_micro > GTK_MICRO_VERSION)
174     return "Gtk+ version too old (micro mismatch)";
175   return NULL;
176 }
177
178 #ifdef __EMX__
179 static gchar *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 Windoze 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 (object != NULL);
1234   g_return_if_fail (GTK_IS_OBJECT (object));
1235
1236   object_p = g_new (GtkObject*, 1);
1237   *object_p = object;
1238   gtk_signal_connect (object,
1239                       "destroy",
1240                       GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1241                       object_p);
1242   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1243 }
1244
1245 guint
1246 gtk_quit_add (guint       main_level,
1247               GtkFunction function,
1248               gpointer    data)
1249 {
1250   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
1251 }
1252
1253 void
1254 gtk_quit_remove (guint id)
1255 {
1256   GtkQuitFunction *quitf;
1257   GList *tmp_list;
1258   
1259   tmp_list = quit_functions;
1260   while (tmp_list)
1261     {
1262       quitf = tmp_list->data;
1263       
1264       if (quitf->id == id)
1265         {
1266           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1267           g_list_free (tmp_list);
1268           gtk_quit_destroy (quitf);
1269           
1270           return;
1271         }
1272       
1273       tmp_list = tmp_list->next;
1274     }
1275 }
1276
1277 void
1278 gtk_quit_remove_by_data (gpointer data)
1279 {
1280   GtkQuitFunction *quitf;
1281   GList *tmp_list;
1282   
1283   tmp_list = quit_functions;
1284   while (tmp_list)
1285     {
1286       quitf = tmp_list->data;
1287       
1288       if (quitf->data == data)
1289         {
1290           quit_functions = g_list_remove_link (quit_functions, tmp_list);
1291           g_list_free (tmp_list);
1292           gtk_quit_destroy (quitf);
1293
1294           return;
1295         }
1296       
1297       tmp_list = tmp_list->next;
1298     }
1299 }
1300
1301 guint
1302 gtk_timeout_add_full (guint32            interval,
1303                       GtkFunction        function,
1304                       GtkCallbackMarshal marshal,
1305                       gpointer           data,
1306                       GtkDestroyNotify   destroy)
1307 {
1308   if (marshal)
1309     {
1310       GtkClosure *closure;
1311
1312       closure = g_new (GtkClosure, 1);
1313       closure->marshal = marshal;
1314       closure->data = data;
1315       closure->destroy = destroy;
1316
1317       return g_timeout_add_full (0, interval, 
1318                                  gtk_invoke_idle_timeout,
1319                                  closure,
1320                                  gtk_destroy_closure);
1321     }
1322   else
1323     return g_timeout_add_full (0, interval, function, data, destroy);
1324 }
1325
1326 guint
1327 gtk_timeout_add (guint32     interval,
1328                  GtkFunction function,
1329                  gpointer    data)
1330 {
1331   return g_timeout_add_full (0, interval, function, data, NULL);
1332 }
1333
1334 void
1335 gtk_timeout_remove (guint tag)
1336 {
1337   g_source_remove (tag);
1338 }
1339
1340 guint
1341 gtk_idle_add_full (gint                 priority,
1342                    GtkFunction          function,
1343                    GtkCallbackMarshal   marshal,
1344                    gpointer             data,
1345                    GtkDestroyNotify     destroy)
1346 {
1347   if (marshal)
1348     {
1349       GtkClosure *closure;
1350
1351       closure = g_new (GtkClosure, 1);
1352       closure->marshal = marshal;
1353       closure->data = data;
1354       closure->destroy = destroy;
1355
1356       return g_idle_add_full (priority,
1357                               gtk_invoke_idle_timeout,
1358                               closure,
1359                               gtk_destroy_closure);
1360     }
1361   else
1362     return g_idle_add_full (priority, function, data, destroy);
1363 }
1364
1365 guint
1366 gtk_idle_add (GtkFunction function,
1367               gpointer    data)
1368 {
1369   return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL);
1370 }
1371
1372 guint       
1373 gtk_idle_add_priority   (gint               priority,
1374                          GtkFunction        function,
1375                          gpointer           data)
1376 {
1377   return g_idle_add_full (priority, function, data, NULL);
1378 }
1379
1380 void
1381 gtk_idle_remove (guint tag)
1382 {
1383   g_source_remove (tag);
1384 }
1385
1386 void
1387 gtk_idle_remove_by_data (gpointer data)
1388 {
1389   if (!g_idle_remove_by_data (data))
1390     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
1391 }
1392
1393 guint
1394 gtk_input_add_full (gint                source,
1395                     GdkInputCondition   condition,
1396                     GdkInputFunction    function,
1397                     GtkCallbackMarshal  marshal,
1398                     gpointer            data,
1399                     GtkDestroyNotify    destroy)
1400 {
1401   if (marshal)
1402     {
1403       GtkClosure *closure;
1404
1405       closure = g_new (GtkClosure, 1);
1406       closure->marshal = marshal;
1407       closure->data = data;
1408       closure->destroy = destroy;
1409
1410       return gdk_input_add_full (source,
1411                                  condition,
1412                                  (GdkInputFunction) gtk_invoke_input,
1413                                  closure,
1414                                  (GdkDestroyNotify) gtk_destroy_closure);
1415     }
1416   else
1417     return gdk_input_add_full (source, condition, function, data, destroy);
1418 }
1419
1420 void
1421 gtk_input_remove (guint tag)
1422 {
1423   g_source_remove (tag);
1424 }
1425
1426 static void
1427 gtk_destroy_closure (gpointer data)
1428 {
1429   GtkClosure *closure = data;
1430
1431   if (closure->destroy)
1432     (closure->destroy) (closure->data);
1433   g_free (closure);
1434 }
1435
1436 static gboolean
1437 gtk_invoke_idle_timeout (gpointer data)
1438 {
1439   GtkClosure *closure = data;
1440
1441   GtkArg args[1];
1442   gint ret_val = FALSE;
1443   args[0].name = NULL;
1444   args[0].type = GTK_TYPE_BOOL;
1445   args[0].d.pointer_data = &ret_val;
1446   closure->marshal (NULL, closure->data,  0, args);
1447   return ret_val;
1448 }
1449
1450 static void
1451 gtk_invoke_input (gpointer          data,
1452                   gint              source,
1453                   GdkInputCondition condition)
1454 {
1455   GtkClosure *closure = data;
1456
1457   GtkArg args[3];
1458   args[0].type = GTK_TYPE_INT;
1459   args[0].name = NULL;
1460   GTK_VALUE_INT(args[0]) = source;
1461   args[1].type = GDK_TYPE_INPUT_CONDITION;
1462   args[1].name = NULL;
1463   GTK_VALUE_FLAGS(args[1]) = condition;
1464   args[2].type = GTK_TYPE_NONE;
1465   args[2].name = NULL;
1466
1467   closure->marshal (NULL, closure->data, 2, args);
1468 }
1469
1470 /**
1471  * gtk_get_current_event:
1472  * 
1473  * Obtains a copy of the event currently being processed by GTK+.  For
1474  * example, if you get a "clicked" signal from #GtkButton, the current
1475  * event will be the #GdkEventButton that triggered the "clicked"
1476  * signal. The returned event must be freed with gdk_event_free().
1477  * If there is no current event, the function returns %NULL.
1478  * 
1479  * Return value: a copy of the current event, or %NULL if no current event.
1480  **/
1481 GdkEvent*
1482 gtk_get_current_event (void)
1483 {
1484   if (current_events)
1485     return gdk_event_copy (current_events->data);
1486   else
1487     return NULL;
1488 }
1489
1490 /**
1491  * gtk_get_current_event_time:
1492  * 
1493  * If there is a current event and it has a timestamp, return that
1494  * timestamp, otherwise return %GDK_CURRENT_TIME.
1495  * 
1496  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
1497  **/
1498 guint32
1499 gtk_get_current_event_time (void)
1500 {
1501   if (current_events)
1502     return gdk_event_get_time (current_events->data);
1503   else
1504     return GDK_CURRENT_TIME;
1505 }
1506
1507 /**
1508  * gtk_get_current_event_state:
1509  * @state: a location to store the state of the current event
1510  * 
1511  * If there is a current event and it has a state field, place
1512  * that state field in @state and return %TRUE, otherwise return
1513  * %FALSE.
1514  * 
1515  * Return value: %TRUE if there was a current event and it had a state field
1516  **/
1517 gboolean
1518 gtk_get_current_event_state (GdkModifierType *state)
1519 {
1520   g_return_val_if_fail (state != NULL, FALSE);
1521   
1522   if (current_events)
1523     return gdk_event_get_state (current_events->data, state);
1524   else
1525     {
1526       *state = 0;
1527       return FALSE;
1528     }
1529 }
1530
1531 /**
1532  * gtk_get_event_widget:
1533  * @event: a #GdkEvent
1534  *
1535  * If @event is %NULL or the event was not associated with any widget,
1536  * returns %NULL, otherwise returns the widget that received the event
1537  * originally.
1538  * 
1539  * Return value: the widget that originally received @event, or %NULL
1540  **/
1541 GtkWidget*
1542 gtk_get_event_widget (GdkEvent *event)
1543 {
1544   GtkWidget *widget;
1545
1546   widget = NULL;
1547   if (event && event->any.window)
1548     gdk_window_get_user_data (event->any.window, (void**) &widget);
1549   
1550   return widget;
1551 }
1552
1553 static void
1554 gtk_exit_func (void)
1555 {
1556   if (gtk_initialized)
1557     {
1558       gtk_initialized = FALSE;
1559     }
1560 }
1561
1562
1563 static gint
1564 gtk_quit_invoke_function (GtkQuitFunction *quitf)
1565 {
1566   if (!quitf->marshal)
1567     return quitf->function (quitf->data);
1568   else
1569     {
1570       GtkArg args[1];
1571       gint ret_val = FALSE;
1572
1573       args[0].name = NULL;
1574       args[0].type = GTK_TYPE_BOOL;
1575       args[0].d.pointer_data = &ret_val;
1576       ((GtkCallbackMarshal) quitf->marshal) (NULL,
1577                                              quitf->data,
1578                                              0, args);
1579       return ret_val;
1580     }
1581 }
1582
1583 /**
1584  * gtk_propagate_event:
1585  * @widget: a #GtkWidget
1586  * @event: an event
1587  *
1588  * Sends an event to a widget, propagating the event to parent widgets
1589  * if the event remains unhandled. Events received by GTK+ from GDK
1590  * normally begin in gtk_main_do_event(). Depending on the type of
1591  * event, existence of modal dialogs, grabs, etc., the event may be
1592  * propagated; if so, this function is used. gtk_propagate_event()
1593  * calls gtk_widget_event() on each widget it decides to send the
1594  * event to.  So gtk_widget_event() is the lowest-level function; it
1595  * simply emits the "event" and possibly an event-specific signal on a
1596  * widget.  gtk_propagate_event() is a bit higher-level, and
1597  * gtk_main_do_event() is the highest level.
1598  *
1599  * All that said, you most likely don't want to use any of these
1600  * functions; synthesizing events is rarely needed. Consider asking on
1601  * the mailing list for better ways to achieve your goals. For
1602  * example, use gdk_window_invalidate_rect() or
1603  * gtk_widget_queue_draw() instead of making up expose events.
1604  * 
1605  **/
1606 void
1607 gtk_propagate_event (GtkWidget *widget,
1608                      GdkEvent  *event)
1609 {
1610   gint handled_event;
1611   
1612   g_return_if_fail (widget != NULL);
1613   g_return_if_fail (GTK_IS_WIDGET (widget));
1614   g_return_if_fail (event != NULL);
1615   
1616   handled_event = FALSE;
1617
1618   gtk_widget_ref (widget);
1619       
1620   if ((event->type == GDK_KEY_PRESS) ||
1621       (event->type == GDK_KEY_RELEASE))
1622     {
1623       /* Only send key events within Window widgets to the Window
1624        *  The Window widget will in turn pass the
1625        *  key event on to the currently focused widget
1626        *  for that window.
1627        */
1628       GtkWidget *window;
1629
1630       window = gtk_widget_get_toplevel (widget);
1631       if (window && GTK_IS_WINDOW (window))
1632         {
1633           /* If there is a grab within the window, give the grab widget
1634            * a first crack at the key event
1635            */
1636           if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
1637             handled_event = gtk_widget_event (widget, event);
1638           
1639           if (!handled_event)
1640             {
1641               window = gtk_widget_get_toplevel (widget);
1642               if (window && GTK_IS_WINDOW (window))
1643                 {
1644                   if (GTK_WIDGET_IS_SENSITIVE (window))
1645                     gtk_widget_event (window, event);
1646                 }
1647             }
1648                   
1649           handled_event = TRUE; /* don't send to widget */
1650         }
1651     }
1652   
1653   /* Other events get propagated up the widget tree
1654    *  so that parents can see the button and motion
1655    *  events of the children.
1656    */
1657   if (!handled_event)
1658     {
1659       while (TRUE)
1660         {
1661           GtkWidget *tmp;
1662           
1663           handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
1664           tmp = widget->parent;
1665           gtk_widget_unref (widget);
1666
1667           widget = tmp;
1668           
1669           if (!handled_event && widget)
1670             gtk_widget_ref (widget);
1671           else
1672             break;
1673         }
1674     }
1675   else
1676     gtk_widget_unref (widget);
1677 }
1678
1679 #if 0
1680 static void
1681 gtk_error (gchar *str)
1682 {
1683   gtk_print (str);
1684 }
1685
1686 static void
1687 gtk_warning (gchar *str)
1688 {
1689   gtk_print (str);
1690 }
1691
1692 static void
1693 gtk_message (gchar *str)
1694 {
1695   gtk_print (str);
1696 }
1697
1698 static void
1699 gtk_print (gchar *str)
1700 {
1701   static GtkWidget *window = NULL;
1702   static GtkWidget *text;
1703   static int level = 0;
1704   GtkWidget *box1;
1705   GtkWidget *box2;
1706   GtkWidget *table;
1707   GtkWidget *hscrollbar;
1708   GtkWidget *vscrollbar;
1709   GtkWidget *separator;
1710   GtkWidget *button;
1711   
1712   if (level > 0)
1713     {
1714       fputs (str, stdout);
1715       fflush (stdout);
1716       return;
1717     }
1718   
1719   if (!window)
1720     {
1721       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1722       
1723       gtk_signal_connect (GTK_OBJECT (window), "destroy",
1724                           (GtkSignalFunc) gtk_widget_destroyed,
1725                           &window);
1726       
1727       gtk_window_set_title (GTK_WINDOW (window), "Messages");
1728       
1729       box1 = gtk_vbox_new (FALSE, 0);
1730       gtk_container_add (GTK_CONTAINER (window), box1);
1731       gtk_widget_show (box1);
1732       
1733       
1734       box2 = gtk_vbox_new (FALSE, 10);
1735       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1736       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
1737       gtk_widget_show (box2);
1738       
1739       
1740       table = gtk_table_new (2, 2, FALSE);
1741       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
1742       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
1743       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
1744       gtk_widget_show (table);
1745       
1746       text = gtk_text_new (NULL, NULL);
1747       gtk_text_set_editable (GTK_TEXT (text), FALSE);
1748       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
1749       gtk_widget_show (text);
1750       gtk_widget_realize (text);
1751       
1752       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
1753       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
1754                         GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1755       gtk_widget_show (hscrollbar);
1756       
1757       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
1758       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
1759                         GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1760       gtk_widget_show (vscrollbar);
1761       
1762       separator = gtk_hseparator_new ();
1763       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
1764       gtk_widget_show (separator);
1765       
1766       
1767       box2 = gtk_vbox_new (FALSE, 10);
1768       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1769       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
1770       gtk_widget_show (box2);
1771       
1772       
1773       button = gtk_button_new_with_label ("close");
1774       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1775                                  (GtkSignalFunc) gtk_widget_hide,
1776                                  GTK_OBJECT (window));
1777       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1778       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1779       gtk_widget_grab_default (button);
1780       gtk_widget_show (button);
1781     }
1782   
1783   level += 1;
1784   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
1785   level -= 1;
1786   
1787   if (!GTK_WIDGET_VISIBLE (window))
1788     gtk_widget_show (window);
1789 }
1790 #endif
1791
1792 gboolean
1793 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
1794                                   GValue                *return_accu,
1795                                   const GValue          *handler_return,
1796                                   gpointer               dummy)
1797 {
1798   gboolean continue_emission;
1799   gboolean signal_handled;
1800   
1801   signal_handled = g_value_get_boolean (handler_return);
1802   g_value_set_boolean (return_accu, signal_handled);
1803   continue_emission = !signal_handled;
1804   
1805   return continue_emission;
1806 }