]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
Destroy widgets _after_ propagating unrealize signals through the widget
[~andy/gtk] / gdk / gdk.c
1 /* GDK - The GIMP Drawing Kit
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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include "config.h"
20
21 /* If you don't want to use gdk's signal handlers define this */
22 /* #define I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS 1 */
23
24 #include <X11/Xlocale.h>
25 #include <ctype.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <limits.h>
31
32 #ifdef HAVE_SYS_SELECT_H
33 #include <sys/select.h>
34 #endif /* HAVE_SYS_SELECT_H_ */
35
36 #define XLIB_ILLEGAL_ACCESS
37 #include <X11/Xatom.h>
38 #include <X11/Xlib.h>
39 #include <X11/Xos.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xmu/WinUtil.h>
42 #include <X11/cursorfont.h>
43 #include "gdk.h"
44 #include "gdkprivate.h"
45 #include "gdkinput.h"
46 #include "gdki18n.h"
47 #include "gdkx.h"
48 #include "gdkkeysyms.h"
49
50 #ifndef X_GETTIMEOFDAY
51 #define X_GETTIMEOFDAY(tv)  gettimeofday (tv, NULL)
52 #endif /* X_GETTIMEOFDAY */
53
54
55 #define DOUBLE_CLICK_TIME      250
56 #define TRIPLE_CLICK_TIME      500
57 #define DOUBLE_CLICK_DIST      5
58 #define TRIPLE_CLICK_DIST      5
59
60
61 #ifndef NO_FD_SET
62 #  define SELECT_MASK fd_set
63 #else
64 #  ifndef _AIX
65 typedef long fd_mask;
66 #  endif
67 #  if defined(_IBMR2)
68 #    define SELECT_MASK void
69 #  else
70 #    define SELECT_MASK int
71 #  endif
72 #endif
73
74
75 typedef struct _GdkInput      GdkInput;
76 typedef struct _GdkPredicate  GdkPredicate;
77
78 struct _GdkInput
79 {
80   gint tag;
81   gint source;
82   GdkInputCondition condition;
83   GdkInputFunction function;
84   gpointer data;
85   GdkDestroyNotify destroy;
86 };
87
88 struct _GdkPredicate
89 {
90   GdkEventFunc func;
91   gpointer data;
92 };
93
94 /* 
95  * Private function declarations
96  */
97
98 static GdkEvent *gdk_event_new          (void);
99 static gint      gdk_event_wait         (void);
100 static gint      gdk_event_apply_filters (XEvent *xevent,
101                                           GdkEvent *event,
102                                           GList *filters);
103 static gint      gdk_event_translate    (GdkEvent     *event, 
104                                          XEvent       *xevent);
105 #if 0
106 static Bool      gdk_event_get_type     (Display      *display, 
107                                          XEvent       *xevent, 
108                                          XPointer      arg);
109 #endif
110 static void      gdk_synthesize_click   (GdkEvent     *event, 
111                                          gint          nclicks);
112
113 #ifndef HAVE_XCONVERTCASE
114 static void      gdkx_XConvertCase      (KeySym        symbol,
115                                          KeySym       *lower,
116                                          KeySym       *upper);
117 #define XConvertCase gdkx_XConvertCase
118 #endif
119
120 /* 
121  * old junk from offix, we might use it though so leave it 
122  */
123 Window       gdk_get_client_window   (Display     *dpy, 
124                                       Window       win);
125 #ifdef WE_HAVE_MOTIF_DROPS_DONE
126 static GdkWindow *  gdk_drop_get_real_window     (GdkWindow   *w, 
127                                                   guint16     *x,
128                                                   guint16     *y);
129 #endif
130 static void         gdk_exit_func                (void);
131 static int          gdk_x_error                  (Display     *display, 
132                                                   XErrorEvent *error);
133 static int          gdk_x_io_error               (Display     *display);
134 static RETSIGTYPE   gdk_signal                   (int          signum);
135
136 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
137                                          GdkEvent  *event,
138                                          gpointer   data);
139
140 /* Private variable declarations
141  */
142 static int gdk_initialized = 0;                     /* 1 if the library is initialized,
143                                                      * 0 otherwise.
144                                                      */
145 static int connection_number = 0;                   /* The file descriptor number of our
146                                                      *  connection to the X server. This
147                                                      *  is used so that we may determine
148                                                      *  when events are pending by using
149                                                      *  the "select" system call.
150                                                      */
151
152
153 static struct timeval start;                        /* The time at which the library was
154                                                      *  last initialized.
155                                                      */
156 static struct timeval timer;                        /* Timeout interval to use in the call
157                                                      *  to "select". This is used in
158                                                      *  conjunction with "timerp" to create
159                                                      *  a maximum time to wait for an event
160                                                      *  to arrive.
161                                                      */
162 static struct timeval *timerp;                      /* The actual timer passed to "select"
163                                                      *  This may be NULL, in which case
164                                                      *  "select" will block until an event
165                                                      *  arrives.
166                                                      */
167 static guint32 timer_val;                           /* The timeout length as specified by
168                                                      *  the user in milliseconds.
169                                                      */
170 static GList *inputs;                               /* A list of the input file descriptors
171                                                      *  that we care about. Each list node
172                                                      *  contains a GdkInput struct that describes
173                                                      *  when we are interested in the specified
174                                                      *  file descriptor. That is, when it is
175                                                      *  available for read, write or has an
176                                                      *  exception pending.
177                                                      */
178 static guint32 button_click_time[2];                /* The last 2 button click times. Used
179                                                      *  to determine if the latest button click
180                                                      *  is part of a double or triple click.
181                                                      */
182 static GdkWindow *button_window[2];                 /* The last 2 windows to receive button presses.
183                                                      *  Also used to determine if the latest button
184                                                      *  click is part of a double or triple click.
185                                                      */
186 static guint button_number[2];                      /* The last 2 buttons to be pressed.
187                                                      */
188 static GdkWindowPrivate *xgrab_window = NULL;       /* Window that currently holds the
189                                                      *  x pointer grab
190                                                      */
191
192 static GList *client_filters;                       /* Filters for client messages */
193
194 static GList *putback_events = NULL;
195
196 static gulong base_id;
197 static gint autorepeat;
198
199 #ifdef G_ENABLE_DEBUG
200 static const GDebugKey gdk_debug_keys[] = {
201   {"events",        GDK_DEBUG_EVENTS},
202   {"misc",          GDK_DEBUG_MISC},
203   {"dnd",           GDK_DEBUG_DND},
204   {"color-context", GDK_DEBUG_COLOR_CONTEXT},
205   {"xim",           GDK_DEBUG_XIM}
206 };
207
208 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
209
210 #endif /* G_ENABLE_DEBUG */
211
212 /*
213  *--------------------------------------------------------------
214  * gdk_init
215  *
216  *   Initialize the library for use.
217  *
218  * Arguments:
219  *   "argc" is the number of arguments.
220  *   "argv" is an array of strings.
221  *
222  * Results:
223  *   "argc" and "argv" are modified to reflect any arguments
224  *   which were not handled. (Such arguments should either
225  *   be handled by the application or dismissed).
226  *
227  * Side effects:
228  *   The library is initialized.
229  *
230  *--------------------------------------------------------------
231  */
232
233 void
234 gdk_init (int    *argc,
235           char ***argv)
236 {
237   XKeyboardState keyboard_state;
238   gint synchronize;
239   gint i, j, k;
240   XClassHint *class_hint;
241   gchar **argv_orig = NULL;
242   gint argc_orig = 0;
243   
244   if (gdk_initialized)
245     return;
246   
247   if (argc && argv)
248     {
249       argc_orig = *argc;
250       
251       argv_orig = g_malloc ((argc_orig + 1) * sizeof (char*));
252       for (i = 0; i < argc_orig; i++)
253         argv_orig[i] = g_strdup ((*argv)[i]);
254       argv_orig[argc_orig] = NULL;
255     }
256   
257   X_GETTIMEOFDAY (&start);
258   
259 #ifndef I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS
260   signal (SIGHUP, gdk_signal);
261   signal (SIGINT, gdk_signal);
262   signal (SIGQUIT, gdk_signal);
263   signal (SIGBUS, gdk_signal);
264   signal (SIGSEGV, gdk_signal);
265   signal (SIGPIPE, gdk_signal);
266   signal (SIGTERM, gdk_signal);
267 #endif
268   
269   gdk_display_name = NULL;
270   
271   XSetErrorHandler (gdk_x_error);
272   XSetIOErrorHandler (gdk_x_io_error);
273   
274   synchronize = FALSE;
275   
276 #ifdef G_ENABLE_DEBUG
277   {
278     gchar *debug_string = getenv("GDK_DEBUG");
279     if (debug_string != NULL)
280       gdk_debug_flags = g_parse_debug_string (debug_string,
281                                               gdk_debug_keys,
282                                               gdk_ndebug_keys);
283   }
284 #endif  /* G_ENABLE_DEBUG */
285   
286   if (argc && argv)
287     {
288       if (*argc > 0)
289         {
290           gchar *d;
291           
292           d = strrchr((*argv)[0],'/');
293           if (d != NULL)
294             g_set_prgname (d + 1);
295           else
296             g_set_prgname ((*argv)[0]);
297         }
298       
299       for (i = 1; i < *argc;)
300         {
301 #ifdef G_ENABLE_DEBUG     
302           if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) ||
303               (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0))
304             {
305               gchar *equal_pos = strchr ((*argv)[i], '=');
306               
307               if (equal_pos != NULL)
308                 {
309                   gdk_debug_flags |= g_parse_debug_string (equal_pos+1,
310                                                            gdk_debug_keys,
311                                                            gdk_ndebug_keys);
312                 }
313               else if ((i + 1) < *argc && (*argv)[i + 1])
314                 {
315                   gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
316                                                            gdk_debug_keys,
317                                                            gdk_ndebug_keys);
318                   (*argv)[i] = NULL;
319                   i += 1;
320                 }
321               (*argv)[i] = NULL;
322             }
323           else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) ||
324                    (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0))
325             {
326               gchar *equal_pos = strchr ((*argv)[i], '=');
327               
328               if (equal_pos != NULL)
329                 {
330                   gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
331                                                             gdk_debug_keys,
332                                                             gdk_ndebug_keys);
333                 }
334               else if ((i + 1) < *argc && (*argv)[i + 1])
335                 {
336                   gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
337                                                             gdk_debug_keys,
338                                                             gdk_ndebug_keys);
339                   (*argv)[i] = NULL;
340                   i += 1;
341                 }
342               (*argv)[i] = NULL;
343             }
344           else 
345 #endif /* G_ENABLE_DEBUG */
346             if (strcmp ("--display", (*argv)[i]) == 0)
347               {
348                 (*argv)[i] = NULL;
349                 
350                 if ((i + 1) < *argc && (*argv)[i + 1])
351                   {
352                     gdk_display_name = g_strdup ((*argv)[i + 1]);
353                     (*argv)[i + 1] = NULL;
354                     i += 1;
355                   }
356               }
357             else if (strcmp ("--sync", (*argv)[i]) == 0)
358               {
359                 (*argv)[i] = NULL;
360                 synchronize = TRUE;
361               }
362             else if (strcmp ("--no-xshm", (*argv)[i]) == 0)
363               {
364                 (*argv)[i] = NULL;
365                 gdk_use_xshm = FALSE;
366               }
367             else if (strcmp ("--name", (*argv)[i]) == 0)
368               {
369                 if ((i + 1) < *argc && (*argv)[i + 1])
370                   {
371                     (*argv)[i++] = NULL;
372                     g_set_prgname ((*argv)[i]);
373                     (*argv)[i] = NULL;
374                   }
375               }
376             else if (strcmp ("--class", (*argv)[i]) == 0)
377               {
378                 if ((i + 1) < *argc && (*argv)[i + 1])
379                   {
380                     (*argv)[i++] = NULL;
381                     gdk_progclass = (*argv)[i];
382                     (*argv)[i] = NULL;
383                   }
384               }
385 #ifdef XINPUT_GXI
386             else if (strcmp ("--gxid_host", (*argv)[i]) == 0)
387               {
388                 if ((i + 1) < *argc && (*argv)[i + 1])
389                   {
390                     (*argv)[i++] = NULL;
391                     gdk_input_gxid_host = ((*argv)[i]);
392                     (*argv)[i] = NULL;
393                   }
394               }
395             else if (strcmp ("--gxid_port", (*argv)[i]) == 0)
396               {
397                 if ((i + 1) < *argc && (*argv)[i + 1])
398                   {
399                     (*argv)[i++] = NULL;
400                     gdk_input_gxid_port = atoi ((*argv)[i]);
401                     (*argv)[i] = NULL;
402                   }
403               }
404 #endif
405 #ifdef USE_XIM
406             else if (strcmp ("--xim-preedit", (*argv)[i]) == 0)
407               {
408                 if ((i + 1) < *argc && (*argv)[i + 1])
409                   {
410                     (*argv)[i++] = NULL;
411                     if (strcmp ("none", (*argv)[i]) == 0)
412                       gdk_im_set_best_style (GDK_IM_PREEDIT_NONE);
413                     else if (strcmp ("nothing", (*argv)[i]) == 0)
414                       gdk_im_set_best_style (GDK_IM_PREEDIT_NOTHING);
415                     else if (strcmp ("area", (*argv)[i]) == 0)
416                       gdk_im_set_best_style (GDK_IM_PREEDIT_AREA);
417                     else if (strcmp ("position", (*argv)[i]) == 0)
418                       gdk_im_set_best_style (GDK_IM_PREEDIT_POSITION);
419                     else if (strcmp ("callbacks", (*argv)[i]) == 0)
420                       gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS);
421                   }
422               }
423             else if (strcmp ("--xim-status", (*argv)[i]) == 0)
424               {
425                 if ((i + 1) < *argc && (*argv)[i + 1])
426                   {
427                     (*argv)[i++] = NULL;
428                     if (strcmp ("none", (*argv)[i]) == 0)
429                       gdk_im_set_best_style (GDK_IM_STATUS_NONE);
430                     else if (strcmp ("nothing", (*argv)[i]) == 0)
431                       gdk_im_set_best_style (GDK_IM_STATUS_NOTHING);
432                     else if (strcmp ("area", (*argv)[i]) == 0)
433                       gdk_im_set_best_style (GDK_IM_STATUS_AREA);
434                     else if (strcmp ("callbacks", (*argv)[i]) == 0)
435                       gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS);
436                   }
437               }
438 #endif
439           
440           i += 1;
441         }
442       
443       for (i = 1; i < *argc; i++)
444         {
445           for (k = i; k < *argc; k++)
446             if ((*argv)[k] != NULL)
447               break;
448           
449           if (k > i)
450             {
451               k -= i;
452               for (j = i + k; j < *argc; j++)
453                 (*argv)[j-k] = (*argv)[j];
454               *argc -= k;
455             }
456         }
457     }
458   else
459     {
460       g_set_prgname ("<unknown>");
461     }
462   
463   GDK_NOTE (MISC, g_message ("progname: \"%s\"", g_get_prgname ()));
464   
465   gdk_display = XOpenDisplay (gdk_display_name);
466   if (!gdk_display)
467     {
468       g_warning ("cannot open display: %s", XDisplayName (gdk_display_name));
469       exit(1);
470     }
471   
472   /* This is really crappy. We have to look into the display structure
473    *  to find the base resource id. This is only needed for recording
474    *  and playback of events.
475    */
476   /* base_id = RESOURCE_BASE; */
477   base_id = 0;
478   GDK_NOTE (EVENTS, g_message ("base id: %lu", base_id));
479   
480   connection_number = ConnectionNumber (gdk_display);
481   GDK_NOTE (MISC,
482             g_message ("connection number: %d", connection_number));
483   
484   if (synchronize)
485     XSynchronize (gdk_display, True);
486   
487   gdk_screen = DefaultScreen (gdk_display);
488   gdk_root_window = RootWindow (gdk_display, gdk_screen);
489   
490   gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
491                                           10, 10, 10, 10, 0, 0 , 0);
492   class_hint = XAllocClassHint();
493   class_hint->res_name = g_get_prgname ();
494   if (gdk_progclass == NULL)
495     {
496       gdk_progclass = g_strdup (g_get_prgname ());
497       gdk_progclass[0] = toupper (gdk_progclass[0]);
498     }
499   class_hint->res_class = gdk_progclass;
500   XSetClassHint(gdk_display, gdk_leader_window, class_hint);
501   XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig);
502   XFree (class_hint);
503   
504   for (i = 0; i < argc_orig; i++)
505     g_free(argv_orig[i]);
506   g_free(argv_orig);
507   
508   gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True);
509   gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True);
510   gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True);
511   gdk_wm_window_protocols[0] = gdk_wm_delete_window;
512   gdk_wm_window_protocols[1] = gdk_wm_take_focus;
513   gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
514   
515   XGetKeyboardControl (gdk_display, &keyboard_state);
516   autorepeat = keyboard_state.global_auto_repeat;
517   
518   timer.tv_sec = 0;
519   timer.tv_usec = 0;
520   timerp = NULL;
521   
522   button_click_time[0] = 0;
523   button_click_time[1] = 0;
524   button_window[0] = NULL;
525   button_window[1] = NULL;
526   button_number[0] = -1;
527   button_number[1] = -1;
528   
529   g_atexit (gdk_exit_func);
530   
531   gdk_visual_init ();
532   gdk_window_init ();
533   gdk_image_init ();
534   gdk_input_init ();
535   gdk_dnd_init ();
536
537   gdk_add_client_message_filter (gdk_wm_protocols, 
538                                  gdk_wm_protocols_filter, NULL);
539   
540 #ifdef USE_XIM
541   gdk_im_open ();
542 #endif
543   
544   gdk_initialized = 1;
545 }
546
547 /*
548  *--------------------------------------------------------------
549  * gdk_exit
550  *
551  *   Restores the library to an un-itialized state and exits
552  *   the program using the "exit" system call.
553  *
554  * Arguments:
555  *   "errorcode" is the error value to pass to "exit".
556  *
557  * Results:
558  *   Allocated structures are freed and the program exits
559  *   cleanly.
560  *
561  * Side effects:
562  *
563  *--------------------------------------------------------------
564  */
565
566 void
567 gdk_exit (int errorcode)
568 {
569   /* de-initialisation is done by the gdk_exit_funct(),
570      no need to do this here (Alex J.) */
571   exit (errorcode);
572 }
573
574 /*
575  *--------------------------------------------------------------
576  * gdk_set_locale
577  *
578  * Arguments:
579  *
580  * Results:
581  *
582  * Side effects:
583  *
584  *--------------------------------------------------------------
585  */
586
587 gchar*
588 gdk_set_locale (void)
589 {
590   if (!setlocale (LC_ALL,""))
591     g_message ("locale not supported by C library");
592   
593   if (!XSupportsLocale ())
594     {
595       g_message ("locale not supported by Xlib, locale set to C");
596       setlocale (LC_ALL, "C");
597     }
598   
599   if (!XSetLocaleModifiers (""))
600     {
601       g_message ("can not set locale modifiers");
602     }
603   
604   return setlocale (LC_ALL,NULL);
605 }
606
607 /*
608  *--------------------------------------------------------------
609  * gdk_events_pending
610  *
611  *   Returns the number of events pending on the queue.
612  *   These events have already been read from the server
613  *   connection.
614  *
615  * Arguments:
616  *
617  * Results:
618  *   Returns the number of events on XLib's event queue.
619  *
620  * Side effects:
621  *
622  *--------------------------------------------------------------
623  */
624
625 gint
626 gdk_events_pending (void)
627 {
628   gint result;
629   GList *tmp_list;
630   
631   result = XPending (gdk_display);
632   
633   tmp_list = putback_events;
634   while (tmp_list)
635     {
636       result++;
637       tmp_list = tmp_list->next;
638     }
639   
640   return result;
641 }
642
643 /*
644  *--------------------------------------------------------------
645  * gdk_event_get_graphics_expose
646  *
647  *   Waits for a GraphicsExpose or NoExpose event
648  *
649  * Arguments:
650  *
651  * Results: 
652  *   For GraphicsExpose events, returns a pointer to the event
653  *   converted into a GdkEvent Otherwise, returns NULL.
654  *
655  * Side effects:
656  *
657  *-------------------------------------------------------------- */
658
659 static Bool
660 graphics_expose_predicate  (Display  *display,
661                             XEvent   *xevent,
662                             XPointer  arg)
663 {
664   GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
665   
666   g_return_val_if_fail (private != NULL, False);
667   
668   if ((xevent->xany.window == private->xwindow) &&
669       ((xevent->xany.type == GraphicsExpose) ||
670        (xevent->xany.type == NoExpose)))
671     return True;
672   else
673     return False;
674 }
675
676 GdkEvent *
677 gdk_event_get_graphics_expose (GdkWindow *window)
678 {
679   XEvent xevent;
680   GdkEvent *event;
681   
682   g_return_val_if_fail (window != NULL, NULL);
683   
684   XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window);
685   
686   if (xevent.xany.type == GraphicsExpose)
687     {
688       event = gdk_event_new ();
689       
690       if (gdk_event_translate (event, &xevent))
691         return event;
692       else
693         gdk_event_free (event);
694     }
695   
696   return NULL;  
697 }
698
699 /************************
700  * Exposure compression *
701  ************************/
702
703 /*
704  * The following implements simple exposure compression. It is
705  * modelled after the way Xt does exposure compression - in
706  * particular compress_expose = XtExposeCompressMultiple.
707  * It compress consecutive sequences of exposure events,
708  * but not sequences that cross other events. (This is because
709  * if it crosses a ConfigureNotify, we could screw up and
710  * mistakenly compress the exposures generated for the new
711  * size - could we just check for ConfigureNotify?)
712  *
713  * Xt compresses to a region / bounding rectangle, we compress
714  * to two rectangles, and try find the two rectangles of minimal
715  * area for this - this is supposed to handle the typical
716  * L-shaped regions generated by OpaqueMove.
717  */
718
719 /* Given three rectangles, find the two rectangles that cover
720  * them with the smallest area.
721  */
722 static void
723 gdk_add_rect_to_rects (GdkRectangle *rect1,
724                        GdkRectangle *rect2, 
725                        GdkRectangle *new_rect)
726 {
727   GdkRectangle t1, t2, t3;
728   gint size1, size2, size3;
729
730   gdk_rectangle_union (rect1, rect2, &t1);
731   gdk_rectangle_union (rect1, new_rect, &t2);
732   gdk_rectangle_union (rect2, new_rect, &t3);
733
734   size1 = t1.width * t1.height + new_rect->width * new_rect->height;
735   size2 = t2.width * t2.height + rect2->width * rect2->height;
736   size3 = t1.width * t1.height + rect1->width * rect1->height;
737
738   if (size1 < size2)
739     {
740       if (size1 < size3)
741         {
742           *rect1 = t1;
743           *rect2 = *new_rect;
744         }
745       else
746         *rect2 = t3;
747     }
748   else
749     {
750       if (size2 < size3)
751         *rect1 = t2;
752       else
753         *rect2 = t3;
754     }
755 }
756
757 typedef struct _GdkExposeInfo GdkExposeInfo;
758
759 struct _GdkExposeInfo {
760   Window window;
761   gboolean seen_nonmatching;
762 };
763
764 Bool
765 expose_predicate (Display *display, XEvent *xevent, XPointer arg)
766 {
767   GdkExposeInfo *info = (GdkExposeInfo *)arg;
768
769   if (xevent->xany.type != Expose)
770     {
771       info->seen_nonmatching = TRUE;
772     }
773
774   if (info->seen_nonmatching || (xevent->xany.window != info->window))
775     return FALSE;
776   else
777     return TRUE;
778 }
779
780 void
781 gdk_compress_exposures (XEvent *xevent, GdkWindow *window)
782 {
783   gint nrects = 1;
784   gint count = 0;
785   GdkRectangle rect1;
786   GdkRectangle rect2;
787   GdkRectangle tmp_rect;
788   XEvent tmp_event;
789   GdkFilterReturn result;
790   GdkExposeInfo info;
791   GdkEvent event;
792
793   info.window = xevent->xany.window;
794   info.seen_nonmatching = FALSE;
795   
796   rect1.x = xevent->xexpose.x;
797   rect1.y = xevent->xexpose.y;
798   rect1.width = xevent->xexpose.width;
799   rect1.height = xevent->xexpose.height;
800
801   while (1)
802     {
803       if (count == 0)
804         {
805           if (!XCheckIfEvent (gdk_display, 
806                               &tmp_event, 
807                               expose_predicate, 
808                               (XPointer)&info))
809             break;
810         }
811       else
812         XIfEvent (gdk_display, 
813                   &tmp_event, 
814                   expose_predicate, 
815                   (XPointer)&info);
816       
817       /* We apply filters here, and if it was filtered, completely
818        * ignore the return
819        */
820       result = gdk_event_apply_filters (xevent, &event,
821                                         window ? 
822                                           ((GdkWindowPrivate *)window)->filters
823                                           : gdk_default_filters);
824       
825       if (result != GDK_FILTER_CONTINUE)
826         {
827           if (result == GDK_FILTER_TRANSLATE)
828             gdk_event_put (&event);
829           continue;
830         }
831
832       if (nrects == 1)
833         {
834           rect2.x = tmp_event.xexpose.x;
835           rect2.y = tmp_event.xexpose.y;
836           rect2.width = tmp_event.xexpose.width;
837           rect2.height = tmp_event.xexpose.height;
838
839           nrects++;
840         }
841       else
842         {
843           tmp_rect.x = tmp_event.xexpose.x;
844           tmp_rect.y = tmp_event.xexpose.y;
845           tmp_rect.width = tmp_event.xexpose.width;
846           tmp_rect.height = tmp_event.xexpose.height;
847
848           gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
849         }
850
851       count = tmp_event.xexpose.count;
852     }
853
854   if (nrects == 2)
855     {
856       gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
857
858       if ((tmp_rect.width * tmp_rect.height) <
859           2 * (rect1.height * rect1.width +
860                rect2.height * rect2.width))
861         {
862           rect1 = tmp_rect;
863           nrects = 1;
864         }
865     }
866
867   if (nrects == 2)
868     {
869       event.expose.type = GDK_EXPOSE;
870       event.expose.window = window;
871       event.expose.area.x = rect2.x;
872       event.expose.area.y = rect2.y;
873       event.expose.area.width = rect2.width;
874       event.expose.area.height = rect2.height;
875       event.expose.count = 0;
876
877       gdk_event_put (&event);
878     }
879
880   xevent->xexpose.count = nrects - 1;
881   xevent->xexpose.x = rect1.x;
882   xevent->xexpose.y = rect1.y;
883   xevent->xexpose.width = rect1.width;
884   xevent->xexpose.height = rect1.height;
885 }
886
887 /*
888  *--------------------------------------------------------------
889  * gdk_event_get
890  *
891  *   Gets the next event.
892  *
893  * Arguments:
894  *
895  * Results:
896  *   If an event was received that we care about, returns 
897  *   a pointer to that event, to be freed with gdk_event_free.
898  *   Otherwise, returns NULL. This function will also return
899  *   before an event is received if the timeout interval
900  *   runs out.
901  *
902  * Side effects:
903  *
904  *--------------------------------------------------------------
905  */
906
907 GdkEvent *
908 gdk_event_get (void)
909 {
910   GdkEvent *event;
911   GList *temp_list;
912   XEvent xevent;
913   
914 #if 0
915   if (pred)
916     {
917       temp_list = putback_events;
918       while (temp_list)
919         {
920           temp_event = temp_list->data;
921           
922           if ((* pred) (temp_event, data))
923             {
924               if (event)
925                 *event = *temp_event;
926               putback_events = g_list_remove_link (putback_events, temp_list);
927               g_list_free (temp_list);
928               return TRUE;
929             }
930           
931           temp_list = temp_list->next;
932         }
933       
934       event_pred.func = pred;
935       event_pred.data = data;
936       
937       if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) & event_pred))
938         if (event)
939           return gdk_event_translate (event, &xevent);
940     }
941   else
942 #endif
943     if (putback_events)
944       {
945         event = putback_events->data;
946         
947         temp_list = putback_events;
948         putback_events = g_list_remove_link (putback_events, temp_list);
949         g_list_free_1 (temp_list);
950         
951         return event;
952       }
953   
954   /* Wait for an event to occur or the timeout to elapse.
955    * If an event occurs "gdk_event_wait" will return TRUE.
956    *  If the timeout elapses "gdk_event_wait" will return
957    *  FALSE.
958    */
959   if (gdk_event_wait ())
960     {
961       /* If we get here we can rest assurred that an event
962        *  has occurred. Read it.
963        */
964 #ifdef USE_XIM
965       Window w = None;
966
967       XNextEvent (gdk_display, &xevent);
968       if (gdk_xim_window)
969         switch (xevent.type)
970           {
971           case KeyPress:
972           case KeyRelease:
973           case ButtonPress:
974           case ButtonRelease:
975             w = GDK_WINDOW_XWINDOW (gdk_xim_window);
976             break;
977           }
978
979       if (XFilterEvent (&xevent, w))
980         return NULL;
981 #else
982       XNextEvent (gdk_display, &xevent);
983 #endif
984       
985       event = gdk_event_new ();
986       
987       event->any.type = GDK_NOTHING;
988       event->any.window = NULL;
989       event->any.send_event = FALSE;
990       event->any.send_event = xevent.xany.send_event;
991       
992       if (gdk_event_translate (event, &xevent))
993         return event;
994       else
995         gdk_event_free (event);
996     }
997   
998   return NULL;
999 }
1000
1001 void
1002 gdk_event_put (GdkEvent *event)
1003 {
1004   GdkEvent *new_event;
1005   
1006   g_return_if_fail (event != NULL);
1007   
1008   new_event = gdk_event_copy (event);
1009   
1010   putback_events = g_list_prepend (putback_events, new_event);
1011 }
1012
1013 /*
1014  *--------------------------------------------------------------
1015  * gdk_event_copy
1016  *
1017  *   Copy a event structure into new storage.
1018  *
1019  * Arguments:
1020  *   "event" is the event struct to copy.
1021  *
1022  * Results:
1023  *   A new event structure.  Free it with gdk_event_free.
1024  *
1025  * Side effects:
1026  *   The reference count of the window in the event is increased.
1027  *
1028  *--------------------------------------------------------------
1029  */
1030
1031 static GMemChunk *event_chunk;
1032
1033 static GdkEvent*
1034 gdk_event_new (void)
1035 {
1036   GdkEvent *new_event;
1037   
1038   if (event_chunk == NULL)
1039     event_chunk = g_mem_chunk_new ("events",
1040                                    sizeof (GdkEvent),
1041                                    4096,
1042                                    G_ALLOC_AND_FREE);
1043   
1044   new_event = g_chunk_new (GdkEvent, event_chunk);
1045   
1046   return new_event;
1047 }
1048
1049 GdkEvent*
1050 gdk_event_copy (GdkEvent *event)
1051 {
1052   GdkEvent *new_event;
1053   
1054   g_return_val_if_fail (event != NULL, NULL);
1055   
1056   new_event = gdk_event_new ();
1057   
1058   *new_event = *event;
1059   gdk_window_ref (new_event->any.window);
1060   
1061   switch (event->any.type)
1062     {
1063     case GDK_KEY_PRESS:
1064     case GDK_KEY_RELEASE:
1065       new_event->key.string = g_strdup (event->key.string);
1066       break;
1067       
1068     case GDK_ENTER_NOTIFY:
1069     case GDK_LEAVE_NOTIFY:
1070       if (event->crossing.subwindow != NULL)
1071         gdk_window_ref (event->crossing.subwindow);
1072       break;
1073       
1074     case GDK_DRAG_ENTER:
1075     case GDK_DRAG_LEAVE:
1076     case GDK_DRAG_MOTION:
1077     case GDK_DRAG_STATUS:
1078     case GDK_DROP_START:
1079     case GDK_DROP_FINISHED:
1080       gdk_drag_context_ref (event->dnd.context);
1081       break;
1082
1083       
1084     default:
1085       break;
1086     }
1087   
1088   return new_event;
1089 }
1090
1091 /*
1092  *--------------------------------------------------------------
1093  * gdk_event_free
1094  *
1095  *   Free a event structure obtained from gdk_event_copy.  Do not use
1096  *   with other event structures.
1097  *
1098  * Arguments:
1099  *   "event" is the event struct to free.
1100  *
1101  * Results:
1102  *
1103  * Side effects:
1104  *   The reference count of the window in the event is decreased and
1105  *   might be freed, too.
1106  *
1107  *-------------------------------------------------------------- */
1108
1109 void
1110 gdk_event_free (GdkEvent *event)
1111 {
1112   g_assert (event_chunk != NULL);
1113   g_return_if_fail (event != NULL);
1114   
1115   if (event->any.window)
1116     gdk_window_unref (event->any.window);
1117   
1118   switch (event->any.type)
1119     {
1120     case GDK_KEY_PRESS:
1121     case GDK_KEY_RELEASE:
1122       g_free (event->key.string);
1123       break;
1124       
1125     case GDK_ENTER_NOTIFY:
1126     case GDK_LEAVE_NOTIFY:
1127       if (event->crossing.subwindow != NULL)
1128         gdk_window_unref (event->crossing.subwindow);
1129       break;
1130       
1131     case GDK_DRAG_ENTER:
1132     case GDK_DRAG_LEAVE:
1133     case GDK_DRAG_MOTION:
1134     case GDK_DRAG_STATUS:
1135     case GDK_DROP_START:
1136     case GDK_DROP_FINISHED:
1137       gdk_drag_context_unref (event->dnd.context);
1138       break;
1139
1140       
1141     default:
1142       break;
1143     }
1144   
1145   g_mem_chunk_free (event_chunk, event);
1146 }
1147
1148 /*
1149  *--------------------------------------------------------------
1150  * gdk_set_show_events
1151  *
1152  *   Turns on/off the showing of events.
1153  *
1154  * Arguments:
1155  *   "show_events" is a boolean describing whether or
1156  *   not to show the events gdk receives.
1157  *
1158  * Results:
1159  *
1160  * Side effects:
1161  *   When "show_events" is TRUE, calls to "gdk_event_get"
1162  *   will output debugging informatin regarding the event
1163  *   received to stdout.
1164  *
1165  *--------------------------------------------------------------
1166  */
1167
1168 /*
1169  *--------------------------------------------------------------
1170  * gdk_event_get_time:
1171  *    Get the timestamp from an event.
1172  *   arguments:
1173  *     event:
1174  *   results:
1175  *    The event's time stamp, if it has one, otherwise
1176  *    GDK_CURRENT_TIME.
1177  *--------------------------------------------------------------
1178  */
1179
1180 guint32
1181 gdk_event_get_time (GdkEvent *event)
1182 {
1183   if (event)
1184     switch (event->type)
1185       {
1186       case GDK_MOTION_NOTIFY:
1187         return event->motion.time;
1188       case GDK_BUTTON_PRESS:
1189       case GDK_2BUTTON_PRESS:
1190       case GDK_3BUTTON_PRESS:
1191       case GDK_BUTTON_RELEASE:
1192         return event->button.time;
1193       case GDK_KEY_PRESS:
1194       case GDK_KEY_RELEASE:
1195         return event->key.time;
1196       case GDK_ENTER_NOTIFY:
1197       case GDK_LEAVE_NOTIFY:
1198         return event->crossing.time;
1199       case GDK_PROPERTY_NOTIFY:
1200         return event->property.time;
1201       case GDK_SELECTION_CLEAR:
1202       case GDK_SELECTION_REQUEST:
1203       case GDK_SELECTION_NOTIFY:
1204         return event->selection.time;
1205       case GDK_PROXIMITY_IN:
1206       case GDK_PROXIMITY_OUT:
1207         return event->proximity.time;
1208       case GDK_DRAG_ENTER:
1209       case GDK_DRAG_LEAVE:
1210       case GDK_DRAG_MOTION:
1211       case GDK_DRAG_STATUS:
1212       case GDK_DROP_START:
1213       case GDK_DROP_FINISHED:
1214         return event->dnd.time;
1215       default:                  /* use current time */
1216         break;
1217       }
1218   
1219   return GDK_CURRENT_TIME;
1220 }
1221
1222 void
1223 gdk_set_show_events (int show_events)
1224 {
1225   if (show_events)
1226     gdk_debug_flags |= GDK_DEBUG_EVENTS;
1227   else
1228     gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
1229 }
1230
1231 void
1232 gdk_set_use_xshm (gint use_xshm)
1233 {
1234   gdk_use_xshm = use_xshm;
1235 }
1236
1237 gint
1238 gdk_get_show_events (void)
1239 {
1240   return gdk_debug_flags & GDK_DEBUG_EVENTS;
1241 }
1242
1243 gint
1244 gdk_get_use_xshm (void)
1245 {
1246   return gdk_use_xshm;
1247 }
1248
1249 /*
1250  *--------------------------------------------------------------
1251  * gdk_time_get
1252  *
1253  *   Get the number of milliseconds since the library was
1254  *   initialized.
1255  *
1256  * Arguments:
1257  *
1258  * Results:
1259  *   The time since the library was initialized is returned.
1260  *   This time value is accurate to milliseconds even though
1261  *   a more accurate time down to the microsecond could be
1262  *   returned.
1263  *
1264  * Side effects:
1265  *
1266  *--------------------------------------------------------------
1267  */
1268
1269 guint32
1270 gdk_time_get (void)
1271 {
1272   struct timeval end;
1273   struct timeval elapsed;
1274   guint32 milliseconds;
1275   
1276   X_GETTIMEOFDAY (&end);
1277   
1278   if (start.tv_usec > end.tv_usec)
1279     {
1280       end.tv_usec += 1000000;
1281       end.tv_sec--;
1282     }
1283   elapsed.tv_sec = end.tv_sec - start.tv_sec;
1284   elapsed.tv_usec = end.tv_usec - start.tv_usec;
1285   
1286   milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000);
1287   
1288   return milliseconds;
1289 }
1290
1291 /*
1292  *--------------------------------------------------------------
1293  * gdk_timer_get
1294  *
1295  *   Returns the current timer.
1296  *
1297  * Arguments:
1298  *
1299  * Results:
1300  *   Returns the current timer interval. This interval is
1301  *   in units of milliseconds.
1302  *
1303  * Side effects:
1304  *
1305  *--------------------------------------------------------------
1306  */
1307
1308 guint32
1309 gdk_timer_get (void)
1310 {
1311   return timer_val;
1312 }
1313
1314 /*
1315  *--------------------------------------------------------------
1316  * gdk_timer_set
1317  *
1318  *   Sets the timer interval.
1319  *
1320  * Arguments:
1321  *   "milliseconds" is the new value for the timer.
1322  *
1323  * Results:
1324  *
1325  * Side effects:
1326  *   Calls to "gdk_event_get" will last for a maximum
1327  *   of time of "milliseconds". However, a value of 0
1328  *   milliseconds will cause "gdk_event_get" to block
1329  *   indefinately until an event is received.
1330  *
1331  *--------------------------------------------------------------
1332  */
1333
1334 void
1335 gdk_timer_set (guint32 milliseconds)
1336 {
1337   timer_val = milliseconds;
1338   timer.tv_sec = milliseconds / 1000;
1339   timer.tv_usec = (milliseconds % 1000) * 1000;
1340   
1341 }
1342
1343 void
1344 gdk_timer_enable (void)
1345 {
1346   timerp = &timer;
1347 }
1348
1349 void
1350 gdk_timer_disable (void)
1351 {
1352   timerp = NULL;
1353 }
1354
1355 gint
1356 gdk_input_add_full (gint              source,
1357                     GdkInputCondition condition,
1358                     GdkInputFunction  function,
1359                     gpointer          data,
1360                     GdkDestroyNotify  destroy)
1361 {
1362   static gint next_tag = 1;
1363   GList *list;
1364   GdkInput *input;
1365   gint tag;
1366   
1367   tag = 0;
1368   list = inputs;
1369   
1370   while (list)
1371     {
1372       input = list->data;
1373       list = list->next;
1374       
1375       if ((input->source == source) && (input->condition == condition))
1376         {
1377           if (input->destroy)
1378             (input->destroy) (input->data);
1379           input->function = function;
1380           input->data = data;
1381           input->destroy = destroy;
1382           tag = input->tag;
1383         }
1384     }
1385   
1386   if (!tag)
1387     {
1388       input = g_new (GdkInput, 1);
1389       input->tag = next_tag++;
1390       input->source = source;
1391       input->condition = condition;
1392       input->function = function;
1393       input->data = data;
1394       input->destroy = destroy;
1395       tag = input->tag;
1396       
1397       inputs = g_list_prepend (inputs, input);
1398     }
1399   
1400   return tag;
1401 }
1402
1403 gint
1404 gdk_input_add (gint              source,
1405                GdkInputCondition condition,
1406                GdkInputFunction  function,
1407                gpointer          data)
1408 {
1409   return gdk_input_add_interp (source, condition, function, data, NULL);
1410 }
1411
1412 void
1413 gdk_input_remove (gint tag)
1414 {
1415   GList *list;
1416   GdkInput *input;
1417   
1418   list = inputs;
1419   while (list)
1420     {
1421       input = list->data;
1422       
1423       if (input->tag == tag)
1424         {
1425           if (input->destroy)
1426             (input->destroy) (input->data);
1427           
1428           input->tag = 0;             /* do not free it here */
1429           input->condition = 0;       /* it's done in gdk_event_wait */
1430           
1431           break;
1432         }
1433       
1434       list = list->next;
1435     }
1436 }
1437
1438 /*
1439  *--------------------------------------------------------------
1440  * gdk_pointer_grab
1441  *
1442  *   Grabs the pointer to a specific window
1443  *
1444  * Arguments:
1445  *   "window" is the window which will receive the grab
1446  *   "owner_events" specifies whether events will be reported as is,
1447  *     or relative to "window"
1448  *   "event_mask" masks only interesting events
1449  *   "confine_to" limits the cursor movement to the specified window
1450  *   "cursor" changes the cursor for the duration of the grab
1451  *   "time" specifies the time
1452  *
1453  * Results:
1454  *
1455  * Side effects:
1456  *   requires a corresponding call to gdk_pointer_ungrab
1457  *
1458  *--------------------------------------------------------------
1459  */
1460
1461 gint
1462 gdk_pointer_grab (GdkWindow *     window,
1463                   gint            owner_events,
1464                   GdkEventMask    event_mask,
1465                   GdkWindow *     confine_to,
1466                   GdkCursor *     cursor,
1467                   guint32         time)
1468 {
1469   /*  From gdkwindow.c  */
1470   extern const int nevent_masks;
1471   extern const int event_mask_table[];
1472   
1473   gint return_val;
1474   GdkWindowPrivate *window_private;
1475   GdkWindowPrivate *confine_to_private;
1476   GdkCursorPrivate *cursor_private;
1477   guint xevent_mask;
1478   Window xwindow;
1479   Window xconfine_to;
1480   Cursor xcursor;
1481   int i;
1482   
1483   g_return_val_if_fail (window != NULL, 0);
1484   
1485   window_private = (GdkWindowPrivate*) window;
1486   confine_to_private = (GdkWindowPrivate*) confine_to;
1487   cursor_private = (GdkCursorPrivate*) cursor;
1488   
1489   xwindow = window_private->xwindow;
1490   
1491   if (!confine_to || confine_to_private->destroyed)
1492     xconfine_to = None;
1493   else
1494     xconfine_to = confine_to_private->xwindow;
1495   
1496   if (!cursor)
1497     xcursor = None;
1498   else
1499     xcursor = cursor_private->xcursor;
1500   
1501   
1502   xevent_mask = 0;
1503   for (i = 0; i < nevent_masks; i++)
1504     {
1505       if (event_mask & (1 << (i + 1)))
1506         xevent_mask |= event_mask_table[i];
1507     }
1508   
1509   if (gdk_input_vtable.grab_pointer)
1510     return_val = gdk_input_vtable.grab_pointer (window,
1511                                                 owner_events,
1512                                                 event_mask,
1513                                                 confine_to,
1514                                                 time);
1515   else
1516     return_val = Success;
1517   
1518   if (return_val == Success)
1519     {
1520       if (!window_private->destroyed)
1521         return_val = XGrabPointer (window_private->xdisplay,
1522                                    xwindow,
1523                                    owner_events,
1524                                    xevent_mask,
1525                                    GrabModeAsync, GrabModeAsync,
1526                                    xconfine_to,
1527                                    xcursor,
1528                                    time);
1529       else
1530         return_val = AlreadyGrabbed;
1531     }
1532   
1533   if (return_val == GrabSuccess)
1534     xgrab_window = window_private;
1535   
1536   return return_val;
1537 }
1538
1539 /*
1540  *--------------------------------------------------------------
1541  * gdk_pointer_ungrab
1542  *
1543  *   Releases any pointer grab
1544  *
1545  * Arguments:
1546  *
1547  * Results:
1548  *
1549  * Side effects:
1550  *
1551  *--------------------------------------------------------------
1552  */
1553
1554 void
1555 gdk_pointer_ungrab (guint32 time)
1556 {
1557   if (gdk_input_vtable.ungrab_pointer)
1558     gdk_input_vtable.ungrab_pointer (time);
1559   
1560   XUngrabPointer (gdk_display, time);
1561   xgrab_window = NULL;
1562 }
1563
1564 /*
1565  *--------------------------------------------------------------
1566  * gdk_pointer_is_grabbed
1567  *
1568  *   Tell wether there is an active x pointer grab in effect
1569  *
1570  * Arguments:
1571  *
1572  * Results:
1573  *
1574  * Side effects:
1575  *
1576  *--------------------------------------------------------------
1577  */
1578
1579 gint
1580 gdk_pointer_is_grabbed (void)
1581 {
1582   return xgrab_window != NULL;
1583 }
1584
1585 /*
1586  *--------------------------------------------------------------
1587  * gdk_keyboard_grab
1588  *
1589  *   Grabs the keyboard to a specific window
1590  *
1591  * Arguments:
1592  *   "window" is the window which will receive the grab
1593  *   "owner_events" specifies whether events will be reported as is,
1594  *     or relative to "window"
1595  *   "time" specifies the time
1596  *
1597  * Results:
1598  *
1599  * Side effects:
1600  *   requires a corresponding call to gdk_keyboard_ungrab
1601  *
1602  *--------------------------------------------------------------
1603  */
1604
1605 gint
1606 gdk_keyboard_grab (GdkWindow *     window,
1607                    gint            owner_events,
1608                    guint32         time)
1609 {
1610   GdkWindowPrivate *window_private;
1611   Window xwindow;
1612   
1613   g_return_val_if_fail (window != NULL, 0);
1614   
1615   window_private = (GdkWindowPrivate*) window;
1616   xwindow = window_private->xwindow;
1617   
1618   if (!window_private->destroyed)
1619     return XGrabKeyboard (window_private->xdisplay,
1620                           xwindow,
1621                           owner_events,
1622                           GrabModeAsync, GrabModeAsync,
1623                           time);
1624   else
1625     return AlreadyGrabbed;
1626 }
1627
1628 /*
1629  *--------------------------------------------------------------
1630  * gdk_keyboard_ungrab
1631  *
1632  *   Releases any keyboard grab
1633  *
1634  * Arguments:
1635  *
1636  * Results:
1637  *
1638  * Side effects:
1639  *
1640  *--------------------------------------------------------------
1641  */
1642
1643 void
1644 gdk_keyboard_ungrab (guint32 time)
1645 {
1646   XUngrabKeyboard (gdk_display, time);
1647 }
1648
1649 /*
1650  *--------------------------------------------------------------
1651  * gdk_screen_width
1652  *
1653  *   Return the width of the screen.
1654  *
1655  * Arguments:
1656  *
1657  * Results:
1658  *
1659  * Side effects:
1660  *
1661  *--------------------------------------------------------------
1662  */
1663
1664 gint
1665 gdk_screen_width (void)
1666 {
1667   gint return_val;
1668   
1669   return_val = DisplayWidth (gdk_display, gdk_screen);
1670   
1671   return return_val;
1672 }
1673
1674 /*
1675  *--------------------------------------------------------------
1676  * gdk_screen_height
1677  *
1678  *   Return the height of the screen.
1679  *
1680  * Arguments:
1681  *
1682  * Results:
1683  *
1684  * Side effects:
1685  *
1686  *--------------------------------------------------------------
1687  */
1688
1689 gint
1690 gdk_screen_height (void)
1691 {
1692   gint return_val;
1693   
1694   return_val = DisplayHeight (gdk_display, gdk_screen);
1695   
1696   return return_val;
1697 }
1698
1699 /*
1700  *--------------------------------------------------------------
1701  * gdk_screen_width_mm
1702  *
1703  *   Return the width of the screen in millimeters.
1704  *
1705  * Arguments:
1706  *
1707  * Results:
1708  *
1709  * Side effects:
1710  *
1711  *--------------------------------------------------------------
1712  */
1713
1714 gint
1715 gdk_screen_width_mm (void)
1716 {
1717   gint return_val;
1718   
1719   return_val = DisplayWidthMM (gdk_display, gdk_screen);
1720   
1721   return return_val;
1722 }
1723
1724 /*
1725  *--------------------------------------------------------------
1726  * gdk_screen_height
1727  *
1728  *   Return the height of the screen in millimeters.
1729  *
1730  * Arguments:
1731  *
1732  * Results:
1733  *
1734  * Side effects:
1735  *
1736  *--------------------------------------------------------------
1737  */
1738
1739 gint
1740 gdk_screen_height_mm (void)
1741 {
1742   gint return_val;
1743   
1744   return_val = DisplayHeightMM (gdk_display, gdk_screen);
1745   
1746   return return_val;
1747 }
1748
1749 void
1750 gdk_key_repeat_disable (void)
1751 {
1752   XAutoRepeatOff (gdk_display);
1753 }
1754
1755 void
1756 gdk_key_repeat_restore (void)
1757 {
1758   if (autorepeat)
1759     XAutoRepeatOn (gdk_display);
1760   else
1761     XAutoRepeatOff (gdk_display);
1762 }
1763
1764
1765 /*
1766  *--------------------------------------------------------------
1767  * gdk_flush
1768  *
1769  *   Flushes the Xlib output buffer and then waits
1770  *   until all requests have been received and processed
1771  *   by the X server. The only real use for this function
1772  *   is in dealing with XShm.
1773  *
1774  * Arguments:
1775  *
1776  * Results:
1777  *
1778  * Side effects:
1779  *
1780  *--------------------------------------------------------------
1781  */
1782
1783 void gdk_flush (void)
1784 {
1785   XSync (gdk_display, False);
1786 }
1787
1788
1789 void
1790 gdk_beep (void)
1791 {
1792   XBell(gdk_display, 100);
1793 }
1794
1795
1796 /*
1797  *--------------------------------------------------------------
1798  * gdk_event_wait
1799  *
1800  *   Waits until an event occurs or the timer runs out.
1801  *
1802  * Arguments:
1803  *
1804  * Results:
1805  *   Returns TRUE if an event is ready to be read and FALSE
1806  *   if the timer ran out.
1807  *
1808  * Side effects:
1809  *
1810  *--------------------------------------------------------------
1811  */
1812
1813 static gint
1814 gdk_event_wait (void)
1815 {
1816   GList *list;
1817   GList *temp_list;
1818   GdkInput *input;
1819   GdkInputCondition condition;
1820   SELECT_MASK readfds;
1821   SELECT_MASK writefds;
1822   SELECT_MASK exceptfds;
1823   int max_input;
1824   int nfd;
1825   
1826   /* If there are no events pending we will wait for an event.
1827    * The time we wait is dependant on the "timer". If no timer
1828    *  has been specified then we'll block until an event arrives.
1829    *  If a timer has been specified we'll block until an event
1830    *  arrives or the timer expires. (This is all done using the
1831    *  "select" system call).
1832    */
1833   
1834   if (XPending (gdk_display) == 0)
1835     {
1836       FD_ZERO (&readfds);
1837       FD_ZERO (&writefds);
1838       FD_ZERO (&exceptfds);
1839       
1840       FD_SET (connection_number, &readfds);
1841       max_input = connection_number;
1842       
1843       list = inputs;
1844       while (list)
1845         {
1846           input = list->data;
1847           
1848           if (input->tag) 
1849             {
1850               if (input->condition & GDK_INPUT_READ)
1851                 FD_SET (input->source, &readfds);
1852               if (input->condition & GDK_INPUT_WRITE)
1853                 FD_SET (input->source, &writefds);
1854               if (input->condition & GDK_INPUT_EXCEPTION)
1855                 FD_SET (input->source, &exceptfds);
1856               
1857               max_input = MAX (max_input, input->source);
1858               list = list->next;
1859             }
1860           else    /* free removed inputs */
1861             {
1862               temp_list = list;
1863               
1864               if (list->next)
1865                 list->next->prev = list->prev;
1866               if (list->prev)
1867                 list->prev->next = list->next;
1868               if (inputs == list)
1869                 inputs = list->next;
1870               
1871               list = list->next;
1872               
1873               temp_list->next = NULL;
1874               temp_list->prev = NULL;
1875               
1876               g_free (temp_list->data);
1877               g_list_free (temp_list);
1878             }
1879         }
1880       
1881 #ifdef USE_PTHREADS
1882       if (gdk_using_threads)
1883         {
1884           gdk_select_waiting = TRUE;
1885           
1886           FD_SET (gdk_threads_pipe[0], &readfds);
1887           max_input = MAX (max_input, gdk_threads_pipe[0]);
1888           gdk_threads_leave ();
1889         }
1890 #endif
1891       
1892       nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp);
1893       
1894 #ifdef USE_PTHREADS
1895       if (gdk_using_threads)
1896         {
1897           gchar c;
1898           gdk_threads_enter ();
1899           gdk_select_waiting = FALSE;
1900           
1901           if (FD_ISSET (gdk_threads_pipe[0], &readfds))
1902             read (gdk_threads_pipe[0], &c, 1);
1903         }
1904 #endif
1905       
1906       timerp = NULL;
1907       timer_val = 0;
1908       
1909       if (nfd > 0)
1910         {
1911           if (FD_ISSET (connection_number, &readfds))
1912             {
1913               if (XPending (gdk_display) == 0)
1914                 {
1915                   if (nfd == 1)
1916                     {
1917                       XNoOp (gdk_display);
1918                       XFlush (gdk_display);
1919                     }
1920                   return FALSE;
1921                 }
1922               else
1923                 return TRUE;
1924             }
1925           
1926           list = inputs;
1927           while (list)
1928             {
1929               input = list->data;
1930               list = list->next;
1931               
1932               condition = 0;
1933               if (FD_ISSET (input->source, &readfds))
1934                 condition |= GDK_INPUT_READ;
1935               if (FD_ISSET (input->source, &writefds))
1936                 condition |= GDK_INPUT_WRITE;
1937               if (FD_ISSET (input->source, &exceptfds))
1938                 condition |= GDK_INPUT_EXCEPTION;
1939               
1940               if (condition && input->function)
1941                 (* input->function) (input->data, input->source, condition);
1942             }
1943         }
1944     }
1945   else
1946     return TRUE;
1947   
1948   return FALSE;
1949 }
1950
1951 static gint
1952 gdk_event_apply_filters (XEvent *xevent,
1953                          GdkEvent *event,
1954                          GList *filters)
1955 {
1956   GdkEventFilter *filter;
1957   GList *tmp_list;
1958   GdkFilterReturn result;
1959   
1960   tmp_list = filters;
1961   
1962   while (tmp_list)
1963     {
1964       filter = (GdkEventFilter *)tmp_list->data;
1965       
1966       result = (*filter->function)(xevent, event, filter->data);
1967       if (result !=  GDK_FILTER_CONTINUE)
1968         return result;
1969       
1970       tmp_list = tmp_list->next;
1971     }
1972   
1973   return GDK_FILTER_CONTINUE;
1974 }
1975
1976 void 
1977 gdk_add_client_message_filter (GdkAtom       message_type,
1978                                GdkFilterFunc func,
1979                                gpointer      data)
1980 {
1981   GdkClientFilter *filter = g_new (GdkClientFilter, 1);
1982
1983   filter->type = message_type;
1984   filter->function = func;
1985   filter->data = data;
1986   
1987   client_filters = g_list_prepend (client_filters, filter);
1988 }
1989
1990 static gint
1991 gdk_event_translate (GdkEvent *event,
1992                      XEvent   *xevent)
1993 {
1994   
1995   GdkWindow *window;
1996   GdkWindowPrivate *window_private;
1997   static XComposeStatus compose;
1998   KeySym keysym;
1999   int charcount;
2000 #ifdef USE_XIM
2001   static gchar* buf = NULL;
2002   static gint buf_len= 0;
2003 #else
2004   char buf[16];
2005 #endif
2006   gint return_val;
2007   
2008   return_val = FALSE;
2009   
2010   /* Find the GdkWindow that this event occurred in.
2011    * 
2012    * We handle events with window=None
2013    *  specially - they are generated by XFree86's XInput under
2014    *  some circumstances.
2015    */
2016   
2017   if ((xevent->xany.window == None) &&
2018       gdk_input_vtable.window_none_event)
2019     {
2020       return_val = gdk_input_vtable.window_none_event (event,xevent);
2021       
2022       if (return_val >= 0)      /* was handled */
2023         return return_val;
2024       else
2025         return_val = FALSE;
2026     }
2027   
2028   window = gdk_window_lookup (xevent->xany.window);
2029   window_private = (GdkWindowPrivate *) window;
2030   
2031   if (window != NULL)
2032     gdk_window_ref (window);
2033   
2034   event->any.window = window;
2035   event->any.send_event = xevent->xany.send_event;
2036   
2037   if (window_private && window_private->destroyed)
2038     {
2039       if (xevent->type != DestroyNotify)
2040         return FALSE;
2041     }
2042   else
2043     {
2044       /* Check for filters for this window */
2045   
2046       GdkFilterReturn result;
2047
2048 #ifdef USE_XIM
2049       if (window == NULL && 
2050           xevent->type == KeyPress &&
2051           gdk_xim_window && 
2052           !((GdkWindowPrivate *) gdk_xim_window)->destroyed)
2053         {
2054           /*
2055            * If user presses a key in Preedit or Status window, keypress event
2056            * is sometimes sent to these windows. These windows are not managed
2057            * by GDK, so we redirect KeyPress event to gdk_xim_window.
2058            *
2059            * If someone want to use the window whitch is not managed by GDK
2060            * and want to get KeyPress event, he/she must register the filter
2061            * function to gdk_default_filters to intercept the event.
2062            */
2063           
2064           window = gdk_xim_window;
2065           window_private = (GdkWindowPrivate *) window;
2066           gdk_window_ref (window);
2067           event->any.window = window;
2068           
2069           GDK_NOTE (XIM,
2070                     g_message ("KeyPress event is redirected to gdk_xim_window: %#lx",
2071                                xevent->xany.window));
2072         }
2073 #endif /* USE_XIM */
2074       
2075       result = gdk_event_apply_filters (xevent, event,
2076                                         window_private
2077                                         ?window_private->filters
2078                                         :gdk_default_filters);
2079       
2080       if (result != GDK_FILTER_CONTINUE)
2081         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
2082     }
2083
2084   if (window == NULL)
2085     g_message ("Got event for unknown window: %#lx\n", xevent->xany.window);
2086
2087   /* We do a "manual" conversion of the XEvent to a
2088    *  GdkEvent. The structures are mostly the same so
2089    *  the conversion is fairly straightforward. We also
2090    *  optionally print debugging info regarding events
2091    *  received.
2092    */
2093
2094   return_val = TRUE;
2095
2096   switch (xevent->type)
2097     {
2098     case KeyPress:
2099       /* Lookup the string corresponding to the given keysym.
2100        */
2101 #ifdef USE_XIM
2102       if (buf_len == 0) 
2103         {
2104           buf_len = 128;
2105           buf = g_new (gchar, buf_len);
2106         }
2107       keysym = GDK_VoidSymbol;
2108       
2109       if (gdk_xim_ic && gdk_xim_ic->xic)
2110         {
2111           Status status;
2112           
2113           /* Clear keyval. Depending on status, may not be set */
2114           charcount = XmbLookupString(gdk_xim_ic->xic,
2115                                       &xevent->xkey, buf, buf_len-1,
2116                                       &keysym, &status);
2117           if (status == XBufferOverflow)
2118             {                     /* retry */
2119               /* alloc adequate size of buffer */
2120               GDK_NOTE (XIM,
2121                         g_message("XIM: overflow (required %i)", charcount));
2122               
2123               while (buf_len <= charcount)
2124                 buf_len *= 2;
2125               buf = (gchar *) g_realloc (buf, buf_len);
2126               
2127               charcount = XmbLookupString (gdk_xim_ic->xic,
2128                                            &xevent->xkey, buf, buf_len-1,
2129                                            &keysym, &status);
2130             }
2131           if (status == XLookupNone)
2132             {
2133               return_val = FALSE;
2134               break;
2135             }
2136         }
2137       else
2138         charcount = XLookupString (&xevent->xkey, buf, buf_len,
2139                                    &keysym, &compose);
2140 #else
2141       charcount = XLookupString (&xevent->xkey, buf, 16,
2142                                  &keysym, &compose);
2143 #endif
2144       event->key.keyval = keysym;
2145       
2146       if (charcount > 0 && buf[charcount-1] == '\0')
2147         charcount --;
2148       else
2149         buf[charcount] = '\0';
2150       
2151       /* Print debugging info.
2152        */
2153 #ifdef G_ENABLE_DEBUG
2154       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
2155         {
2156           g_message ("key press:\twindow: %ld  key: %12s  %d",
2157                      xevent->xkey.window - base_id,
2158                      event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
2159                      event->key.keyval);
2160           if (charcount > 0)
2161             g_message ("\t\tlength: %4d string: \"%s\"",
2162                        charcount, buf);
2163         }
2164 #endif /* G_ENABLE_DEBUG */
2165       
2166       event->key.type = GDK_KEY_PRESS;
2167       event->key.window = window;
2168       event->key.time = xevent->xkey.time;
2169       event->key.state = (GdkModifierType) xevent->xkey.state;
2170       event->key.string = g_strdup (buf);
2171       event->key.length = charcount;
2172       
2173       break;
2174       
2175     case KeyRelease:
2176       /* Lookup the string corresponding to the given keysym.
2177        */
2178 #ifdef USE_XIM
2179       if (buf_len == 0) 
2180         {
2181           buf_len = 128;
2182           buf = g_new (gchar, buf_len);
2183         }
2184 #endif
2185       keysym = GDK_VoidSymbol;
2186       charcount = XLookupString (&xevent->xkey, buf, 16,
2187                                  &keysym, &compose);
2188       event->key.keyval = keysym;      
2189       
2190       /* Print debugging info.
2191        */
2192       GDK_NOTE (EVENTS, 
2193                 g_message ("key release:\t\twindow: %ld  key: %12s  %d",
2194                            xevent->xkey.window - base_id,
2195                            XKeysymToString (event->key.keyval),
2196                            event->key.keyval));
2197       
2198       event->key.type = GDK_KEY_RELEASE;
2199       event->key.window = window;
2200       event->key.time = xevent->xkey.time;
2201       event->key.state = (GdkModifierType) xevent->xkey.state;
2202       event->key.length = 0;
2203       event->key.string = NULL;
2204       
2205       break;
2206       
2207     case ButtonPress:
2208       /* Print debugging info.
2209        */
2210       GDK_NOTE (EVENTS, 
2211                 g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
2212                            xevent->xbutton.window - base_id,
2213                            xevent->xbutton.x, xevent->xbutton.y,
2214                            xevent->xbutton.button));
2215       
2216       if (window_private &&
2217           (window_private->extension_events != 0) &&
2218           gdk_input_ignore_core)
2219         {
2220           return_val = FALSE;
2221           break;
2222         }
2223       
2224       event->button.type = GDK_BUTTON_PRESS;
2225       event->button.window = window;
2226       event->button.time = xevent->xbutton.time;
2227       event->button.x = xevent->xbutton.x;
2228       event->button.y = xevent->xbutton.y;
2229       event->button.x_root = (gfloat)xevent->xbutton.x_root;
2230       event->button.y_root = (gfloat)xevent->xbutton.y_root;
2231       event->button.pressure = 0.5;
2232       event->button.xtilt = 0;
2233       event->button.ytilt = 0;
2234       event->button.state = (GdkModifierType) xevent->xbutton.state;
2235       event->button.button = xevent->xbutton.button;
2236       event->button.source = GDK_SOURCE_MOUSE;
2237       event->button.deviceid = GDK_CORE_POINTER;
2238       
2239       if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
2240           (event->button.window == button_window[1]) &&
2241           (event->button.button == button_number[1]))
2242         {
2243           gdk_synthesize_click (event, 3);
2244           
2245           button_click_time[1] = 0;
2246           button_click_time[0] = 0;
2247           button_window[1] = NULL;
2248           button_window[0] = 0;
2249           button_number[1] = -1;
2250           button_number[0] = -1;
2251         }
2252       else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
2253                (event->button.window == button_window[0]) &&
2254                (event->button.button == button_number[0]))
2255         {
2256           gdk_synthesize_click (event, 2);
2257           
2258           button_click_time[1] = button_click_time[0];
2259           button_click_time[0] = event->button.time;
2260           button_window[1] = button_window[0];
2261           button_window[0] = event->button.window;
2262           button_number[1] = button_number[0];
2263           button_number[0] = event->button.button;
2264         }
2265       else
2266         {
2267           button_click_time[1] = 0;
2268           button_click_time[0] = event->button.time;
2269           button_window[1] = NULL;
2270           button_window[0] = event->button.window;
2271           button_number[1] = -1;
2272           button_number[0] = event->button.button;
2273         }
2274
2275       break;
2276       
2277     case ButtonRelease:
2278       /* Print debugging info.
2279        */
2280       GDK_NOTE (EVENTS, 
2281                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
2282                            xevent->xbutton.window - base_id,
2283                            xevent->xbutton.x, xevent->xbutton.y,
2284                            xevent->xbutton.button));
2285       
2286       if (window_private &&
2287           (window_private->extension_events != 0) &&
2288           gdk_input_ignore_core)
2289         {
2290           return_val = FALSE;
2291           break;
2292         }
2293       
2294       event->button.type = GDK_BUTTON_RELEASE;
2295       event->button.window = window;
2296       event->button.time = xevent->xbutton.time;
2297       event->button.x = xevent->xbutton.x;
2298       event->button.y = xevent->xbutton.y;
2299       event->button.x_root = (gfloat)xevent->xbutton.x_root;
2300       event->button.y_root = (gfloat)xevent->xbutton.y_root;
2301       event->button.pressure = 0.5;
2302       event->button.xtilt = 0;
2303       event->button.ytilt = 0;
2304       event->button.state = (GdkModifierType) xevent->xbutton.state;
2305       event->button.button = xevent->xbutton.button;
2306       event->button.source = GDK_SOURCE_MOUSE;
2307       event->button.deviceid = GDK_CORE_POINTER;
2308       
2309       break;
2310       
2311     case MotionNotify:
2312       /* Print debugging info.
2313        */
2314       GDK_NOTE (EVENTS,
2315                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
2316                            xevent->xmotion.window - base_id,
2317                            xevent->xmotion.x, xevent->xmotion.y,
2318                            (xevent->xmotion.is_hint) ? "true" : "false"));
2319       
2320       if (window_private &&
2321           (window_private->extension_events != 0) &&
2322           gdk_input_ignore_core)
2323         {
2324           return_val = FALSE;
2325           break;
2326         }
2327       
2328       event->motion.type = GDK_MOTION_NOTIFY;
2329       event->motion.window = window;
2330       event->motion.time = xevent->xmotion.time;
2331       event->motion.x = xevent->xmotion.x;
2332       event->motion.y = xevent->xmotion.y;
2333       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
2334       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
2335       event->motion.pressure = 0.5;
2336       event->motion.xtilt = 0;
2337       event->motion.ytilt = 0;
2338       event->motion.state = (GdkModifierType) xevent->xmotion.state;
2339       event->motion.is_hint = xevent->xmotion.is_hint;
2340       event->motion.source = GDK_SOURCE_MOUSE;
2341       event->motion.deviceid = GDK_CORE_POINTER;
2342       
2343       break;
2344       
2345     case EnterNotify:
2346       /* Print debugging info.
2347        */
2348       GDK_NOTE (EVENTS,
2349                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
2350                            xevent->xcrossing.window - base_id,
2351                            xevent->xcrossing.detail,
2352                            xevent->xcrossing.subwindow - base_id));
2353       
2354       /* Tell XInput stuff about it if appropriate */
2355       if (window_private &&
2356           !window_private->destroyed &&
2357           (window_private->extension_events != 0) &&
2358           gdk_input_vtable.enter_event)
2359         gdk_input_vtable.enter_event (&xevent->xcrossing, window);
2360       
2361       event->crossing.type = GDK_ENTER_NOTIFY;
2362       event->crossing.window = window;
2363       
2364       /* If the subwindow field of the XEvent is non-NULL, then
2365        *  lookup the corresponding GdkWindow.
2366        */
2367       if (xevent->xcrossing.subwindow != None)
2368         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2369       else
2370         event->crossing.subwindow = NULL;
2371       
2372       event->crossing.time = xevent->xcrossing.time;
2373       event->crossing.x = xevent->xcrossing.x;
2374       event->crossing.y = xevent->xcrossing.y;
2375       event->crossing.x_root = xevent->xcrossing.x_root;
2376       event->crossing.y_root = xevent->xcrossing.y_root;
2377       
2378       /* Translate the crossing mode into Gdk terms.
2379        */
2380       switch (xevent->xcrossing.mode)
2381         {
2382         case NotifyNormal:
2383           event->crossing.mode = GDK_CROSSING_NORMAL;
2384           break;
2385         case NotifyGrab:
2386           event->crossing.mode = GDK_CROSSING_GRAB;
2387           break;
2388         case NotifyUngrab:
2389           event->crossing.mode = GDK_CROSSING_UNGRAB;
2390           break;
2391         };
2392       
2393       /* Translate the crossing detail into Gdk terms.
2394        */
2395       switch (xevent->xcrossing.detail)
2396         {
2397         case NotifyInferior:
2398           event->crossing.detail = GDK_NOTIFY_INFERIOR;
2399           break;
2400         case NotifyAncestor:
2401           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2402           break;
2403         case NotifyVirtual:
2404           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2405           break;
2406         case NotifyNonlinear:
2407           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2408           break;
2409         case NotifyNonlinearVirtual:
2410           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2411           break;
2412         default:
2413           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2414           break;
2415         }
2416       
2417       event->crossing.focus = xevent->xcrossing.focus;
2418       event->crossing.state = xevent->xcrossing.state;
2419   
2420       break;
2421       
2422     case LeaveNotify:
2423       /* Print debugging info.
2424        */
2425       GDK_NOTE (EVENTS, 
2426                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
2427                            xevent->xcrossing.window - base_id,
2428                            xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id));
2429       
2430       event->crossing.type = GDK_LEAVE_NOTIFY;
2431       event->crossing.window = window;
2432       
2433       /* If the subwindow field of the XEvent is non-NULL, then
2434        *  lookup the corresponding GdkWindow.
2435        */
2436       if (xevent->xcrossing.subwindow != None)
2437         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2438       else
2439         event->crossing.subwindow = NULL;
2440       
2441       event->crossing.time = xevent->xcrossing.time;
2442       event->crossing.x = xevent->xcrossing.x;
2443       event->crossing.y = xevent->xcrossing.y;
2444       event->crossing.x_root = xevent->xcrossing.x_root;
2445       event->crossing.y_root = xevent->xcrossing.y_root;
2446       
2447       /* Translate the crossing mode into Gdk terms.
2448        */
2449       switch (xevent->xcrossing.mode)
2450         {
2451         case NotifyNormal:
2452           event->crossing.mode = GDK_CROSSING_NORMAL;
2453           break;
2454         case NotifyGrab:
2455           event->crossing.mode = GDK_CROSSING_GRAB;
2456           break;
2457         case NotifyUngrab:
2458           event->crossing.mode = GDK_CROSSING_UNGRAB;
2459           break;
2460         };
2461       
2462       /* Translate the crossing detail into Gdk terms.
2463        */
2464       switch (xevent->xcrossing.detail)
2465         {
2466         case NotifyInferior:
2467           event->crossing.detail = GDK_NOTIFY_INFERIOR;
2468           break;
2469         case NotifyAncestor:
2470           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2471           break;
2472         case NotifyVirtual:
2473           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2474           break;
2475         case NotifyNonlinear:
2476           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2477           break;
2478         case NotifyNonlinearVirtual:
2479           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2480           break;
2481         default:
2482           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2483           break;
2484         }
2485       
2486       event->crossing.focus = xevent->xcrossing.focus;
2487       event->crossing.state = xevent->xcrossing.state;
2488       
2489       break;
2490       
2491     case FocusIn:
2492     case FocusOut:
2493       /* We only care about focus events that indicate that _this_
2494        * window (not a ancestor or child) got or lost the focus
2495        */
2496       switch (xevent->xfocus.detail)
2497         {
2498         case NotifyAncestor:
2499         case NotifyInferior:
2500         case NotifyNonlinear:
2501           /* Print debugging info.
2502            */
2503           GDK_NOTE (EVENTS,
2504                     g_message ("focus %s:\t\twindow: %ld",
2505                                (xevent->xany.type == FocusIn) ? "in" : "out",
2506                                xevent->xfocus.window - base_id));
2507           
2508           /* gdk_keyboard_grab() causes following events. These events confuse
2509            * the XIM focus, so ignore them.
2510            */
2511           if (xevent->xfocus.mode == NotifyGrab ||
2512               xevent->xfocus.mode == NotifyUngrab)
2513             break;
2514
2515           event->focus_change.type = GDK_FOCUS_CHANGE;
2516           event->focus_change.window = window;
2517           event->focus_change.in = (xevent->xany.type == FocusIn);
2518
2519           break;
2520         default:
2521           return_val = FALSE;
2522         }
2523       break;
2524       
2525     case KeymapNotify:
2526       /* Print debugging info.
2527        */
2528       GDK_NOTE (EVENTS,
2529                 g_message ("keymap notify"));
2530
2531       /* Not currently handled */
2532       return_val = FALSE;
2533       break;
2534       
2535     case Expose:
2536       /* Print debugging info.
2537        */
2538       GDK_NOTE (EVENTS,
2539                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d",
2540                            xevent->xexpose.window - base_id, xevent->xexpose.count,
2541                            xevent->xexpose.x, xevent->xexpose.y,
2542                            xevent->xexpose.width, xevent->xexpose.height));
2543       gdk_compress_exposures (xevent, window);
2544       
2545       event->expose.type = GDK_EXPOSE;
2546       event->expose.window = window;
2547       event->expose.area.x = xevent->xexpose.x;
2548       event->expose.area.y = xevent->xexpose.y;
2549       event->expose.area.width = xevent->xexpose.width;
2550       event->expose.area.height = xevent->xexpose.height;
2551       event->expose.count = xevent->xexpose.count;
2552       
2553       break;
2554       
2555     case GraphicsExpose:
2556       /* Print debugging info.
2557        */
2558       GDK_NOTE (EVENTS,
2559                 g_message ("graphics expose:\tdrawable: %ld",
2560                            xevent->xgraphicsexpose.drawable - base_id));
2561       
2562       event->expose.type = GDK_EXPOSE;
2563       event->expose.window = window;
2564       event->expose.area.x = xevent->xgraphicsexpose.x;
2565       event->expose.area.y = xevent->xgraphicsexpose.y;
2566       event->expose.area.width = xevent->xgraphicsexpose.width;
2567       event->expose.area.height = xevent->xgraphicsexpose.height;
2568       event->expose.count = xevent->xexpose.count;
2569       
2570       break;
2571       
2572     case NoExpose:
2573       /* Print debugging info.
2574        */
2575       GDK_NOTE (EVENTS,
2576                 g_message ("no expose:\t\tdrawable: %ld",
2577                            xevent->xnoexpose.drawable - base_id));
2578       
2579       event->no_expose.type = GDK_NO_EXPOSE;
2580       event->no_expose.window = window;
2581       
2582       break;
2583       
2584     case VisibilityNotify:
2585       /* Print debugging info.
2586        */
2587 #ifdef G_ENABLE_DEBUG
2588       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
2589         switch (xevent->xvisibility.state)
2590           {
2591           case VisibilityFullyObscured:
2592             g_message ("visibility notify:\twindow: %ld  none",
2593                        xevent->xvisibility.window - base_id);
2594             break;
2595           case VisibilityPartiallyObscured:
2596             g_message ("visibility notify:\twindow: %ld  partial",
2597                        xevent->xvisibility.window - base_id);
2598             break;
2599           case VisibilityUnobscured:
2600             g_message ("visibility notify:\twindow: %ld  full",
2601                        xevent->xvisibility.window - base_id);
2602             break;
2603           }
2604 #endif /* G_ENABLE_DEBUG */
2605       
2606       event->visibility.type = GDK_VISIBILITY_NOTIFY;
2607       event->visibility.window = window;
2608       
2609       switch (xevent->xvisibility.state)
2610         {
2611         case VisibilityFullyObscured:
2612           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
2613           break;
2614           
2615         case VisibilityPartiallyObscured:
2616           event->visibility.state = GDK_VISIBILITY_PARTIAL;
2617           break;
2618           
2619         case VisibilityUnobscured:
2620           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
2621           break;
2622         }
2623       
2624       break;
2625       
2626     case CreateNotify:
2627       /* Not currently handled */
2628       break;
2629       
2630     case DestroyNotify:
2631       /* Print debugging info.
2632        */
2633       GDK_NOTE (EVENTS,
2634                 g_message ("destroy notify:\twindow: %ld",
2635                            xevent->xdestroywindow.window - base_id));
2636       
2637       event->any.type = GDK_DESTROY;
2638       event->any.window = window;
2639       
2640       return_val = window_private && !window_private->destroyed;
2641       
2642       if(window && window_private->xwindow != GDK_ROOT_WINDOW())
2643         gdk_window_destroy_notify (window);
2644       break;
2645       
2646     case UnmapNotify:
2647       /* Print debugging info.
2648        */
2649       GDK_NOTE (EVENTS,
2650                 g_message ("unmap notify:\t\twindow: %ld",
2651                            xevent->xmap.window - base_id));
2652       
2653       event->any.type = GDK_UNMAP;
2654       event->any.window = window;
2655       
2656       if (xgrab_window == window_private)
2657         xgrab_window = NULL;
2658       
2659       break;
2660       
2661     case MapNotify:
2662       /* Print debugging info.
2663        */
2664       GDK_NOTE (EVENTS,
2665                 g_message ("map notify:\t\twindow: %ld",
2666                            xevent->xmap.window - base_id));
2667       
2668       event->any.type = GDK_MAP;
2669       event->any.window = window;
2670       
2671       break;
2672       
2673     case ReparentNotify:
2674       /* Print debugging info.
2675        */
2676       GDK_NOTE (EVENTS,
2677                 g_message ("reparent notify:\twindow: %ld",
2678                            xevent->xreparent.window - base_id));
2679
2680       /* Not currently handled */
2681       return_val = FALSE;
2682       break;
2683       
2684     case ConfigureNotify:
2685       /* Print debugging info.
2686        */
2687       while ((XPending (gdk_display) > 0) &&
2688              XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
2689                                     ConfigureNotify, xevent))
2690         {
2691           GdkFilterReturn result;
2692           
2693           GDK_NOTE (EVENTS, 
2694                     g_message ("configure notify discarded:\twindow: %ld",
2695                                xevent->xconfigure.window - base_id));
2696           
2697           result = gdk_event_apply_filters (xevent, event,
2698                                             window_private
2699                                             ?window_private->filters
2700                                             :gdk_default_filters);
2701           
2702           /* If the result is GDK_FILTER_REMOVE, there will be
2703            * trouble, but anybody who filtering the Configure events
2704            * better know what they are doing
2705            */
2706           if (result != GDK_FILTER_CONTINUE)
2707             {
2708               return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
2709             }
2710           
2711           /*XSync (gdk_display, 0);*/
2712         }
2713       
2714       
2715       GDK_NOTE (EVENTS,
2716                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d",
2717                            xevent->xconfigure.window - base_id,
2718                            xevent->xconfigure.x,
2719                            xevent->xconfigure.y,
2720                            xevent->xconfigure.width,
2721                            xevent->xconfigure.height,
2722                            xevent->xconfigure.border_width,
2723                            xevent->xconfigure.above - base_id,
2724                            xevent->xconfigure.override_redirect));
2725       
2726       if (!window_private->destroyed &&
2727           (window_private->extension_events != 0) &&
2728           gdk_input_vtable.configure_event)
2729         gdk_input_vtable.configure_event (&xevent->xconfigure, window);
2730
2731       if (window_private->window_type == GDK_WINDOW_CHILD)
2732         return_val = FALSE;
2733       else
2734         {
2735           event->configure.type = GDK_CONFIGURE;
2736           event->configure.window = window;
2737           event->configure.width = xevent->xconfigure.width;
2738           event->configure.height = xevent->xconfigure.height;
2739           
2740           if (!xevent->xconfigure.x &&
2741               !xevent->xconfigure.y &&
2742               !window_private->destroyed)
2743             {
2744               gint tx = 0;
2745               gint ty = 0;
2746               Window child_window = 0;
2747               
2748               if (!XTranslateCoordinates (window_private->xdisplay,
2749                                           window_private->xwindow,
2750                                           gdk_root_window,
2751                                           0, 0,
2752                                           &tx, &ty,
2753                                           &child_window))
2754                 g_warning ("GdkWindow %ld doesn't share root windows display?",
2755                            window_private->xwindow - base_id);
2756               event->configure.x = tx;
2757               event->configure.y = ty;
2758             }
2759           else
2760             {
2761               event->configure.x = xevent->xconfigure.x;
2762               event->configure.y = xevent->xconfigure.y;
2763             }
2764           window_private->x = event->configure.x;
2765           window_private->y = event->configure.y;
2766           window_private->width = xevent->xconfigure.width;
2767           window_private->height = xevent->xconfigure.height;
2768           if (window_private->resize_count > 1)
2769             window_private->resize_count -= 1;
2770         }
2771       break;
2772       
2773     case PropertyNotify:
2774       /* Print debugging info.
2775        */
2776       GDK_NOTE (EVENTS,
2777                 g_message ("property notify:\twindow: %ld",
2778                            xevent->xproperty.window - base_id));
2779       
2780       event->property.type = GDK_PROPERTY_NOTIFY;
2781       event->property.window = window;
2782       event->property.atom = xevent->xproperty.atom;
2783       event->property.time = xevent->xproperty.time;
2784       event->property.state = xevent->xproperty.state;
2785       
2786       break;
2787       
2788     case SelectionClear:
2789       GDK_NOTE (EVENTS,
2790                 g_message ("selection clear:\twindow: %ld",
2791                            xevent->xproperty.window - base_id));
2792       
2793       event->selection.type = GDK_SELECTION_CLEAR;
2794       event->selection.window = window;
2795       event->selection.selection = xevent->xselectionclear.selection;
2796       event->selection.time = xevent->xselectionclear.time;
2797       
2798       break;
2799       
2800     case SelectionRequest:
2801       GDK_NOTE (EVENTS,
2802                 g_message ("selection request:\twindow: %ld",
2803                            xevent->xproperty.window - base_id));
2804       
2805       event->selection.type = GDK_SELECTION_REQUEST;
2806       event->selection.window = window;
2807       event->selection.selection = xevent->xselectionrequest.selection;
2808       event->selection.target = xevent->xselectionrequest.target;
2809       event->selection.property = xevent->xselectionrequest.property;
2810       event->selection.requestor = xevent->xselectionrequest.requestor;
2811       event->selection.time = xevent->xselectionrequest.time;
2812       
2813       break;
2814       
2815     case SelectionNotify:
2816       GDK_NOTE (EVENTS,
2817                 g_message ("selection notify:\twindow: %ld",
2818                            xevent->xproperty.window - base_id));
2819       
2820       
2821       event->selection.type = GDK_SELECTION_NOTIFY;
2822       event->selection.window = window;
2823       event->selection.selection = xevent->xselection.selection;
2824       event->selection.target = xevent->xselection.target;
2825       event->selection.property = xevent->xselection.property;
2826       event->selection.time = xevent->xselection.time;
2827       
2828       break;
2829       
2830     case ColormapNotify:
2831       /* Print debugging info.
2832        */
2833       GDK_NOTE (EVENTS,
2834                 g_message ("colormap notify:\twindow: %ld",
2835                            xevent->xcolormap.window - base_id));
2836       
2837       /* Not currently handled */
2838       return_val = FALSE;
2839       break;
2840       
2841     case ClientMessage:
2842       {
2843         GList *tmp_list;
2844         GdkFilterReturn result = GDK_FILTER_CONTINUE;
2845
2846         /* Print debugging info.
2847          */
2848         GDK_NOTE (EVENTS,
2849                   g_message ("client message:\twindow: %ld",
2850                              xevent->xclient.window - base_id));
2851         
2852         tmp_list = client_filters;
2853         while (tmp_list)
2854           {
2855             GdkClientFilter *filter = tmp_list->data;
2856             if (filter->type == xevent->xclient.message_type)
2857               {
2858                 result = (*filter->function) (xevent, event, filter->data);
2859                 break;
2860               }
2861             
2862             tmp_list = tmp_list->next;
2863           }
2864
2865         switch (result)
2866           {
2867           case GDK_FILTER_REMOVE:
2868             return_val = FALSE;
2869             break;
2870           case GDK_FILTER_TRANSLATE:
2871             return_val = TRUE;
2872             break;
2873           case GDK_FILTER_CONTINUE:
2874             /* Send unknown ClientMessage's on to Gtk for it to use */
2875             event->client.type = GDK_CLIENT_EVENT;
2876             event->client.window = window;
2877             event->client.message_type = xevent->xclient.message_type;
2878             event->client.data_format = xevent->xclient.format;
2879             memcpy(&event->client.data, &xevent->xclient.data,
2880                    sizeof(event->client.data));
2881           }
2882       }
2883       
2884       break;
2885       
2886     case MappingNotify:
2887       /* Print debugging info.
2888        */
2889       GDK_NOTE (EVENTS,
2890                 g_message ("mapping notify"));
2891       
2892       /* Let XLib know that there is a new keyboard mapping.
2893        */
2894       XRefreshKeyboardMapping (&xevent->xmapping);
2895       return_val = FALSE;
2896       break;
2897       
2898     default:
2899       /* something else - (e.g., a Xinput event) */
2900       
2901       if (window_private &&
2902           !window_private->destroyed &&
2903           (window_private->extension_events != 0) &&
2904           gdk_input_vtable.other_event)
2905         return_val = gdk_input_vtable.other_event(event, xevent, window);
2906       else
2907         return_val = FALSE;
2908       
2909       break;
2910     }
2911   
2912   if (return_val)
2913     {
2914       if (event->any.window)
2915         gdk_window_ref (event->any.window);
2916       if (((event->any.type == GDK_ENTER_NOTIFY) ||
2917            (event->any.type == GDK_LEAVE_NOTIFY)) &&
2918           (event->crossing.subwindow != NULL))
2919         gdk_window_ref (event->crossing.subwindow);
2920     }
2921   else
2922     {
2923       /* Mark this event as having no resources to be freed */
2924       event->any.window = NULL;
2925       event->any.type = GDK_NOTHING;
2926     }
2927   
2928   if (window)
2929     gdk_window_unref (window);
2930   
2931   return return_val;
2932 }
2933
2934 GdkFilterReturn
2935 gdk_wm_protocols_filter (GdkXEvent *xev,
2936                      GdkEvent  *event,
2937                      gpointer data)
2938 {
2939   XEvent *xevent = (XEvent *)xev;
2940
2941   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
2942     {
2943   /* The delete window request specifies a window
2944    *  to delete. We don't actually destroy the
2945    *  window because "it is only a request". (The
2946    *  window might contain vital data that the
2947    *  program does not want destroyed). Instead
2948    *  the event is passed along to the program,
2949    *  which should then destroy the window.
2950    */
2951       GDK_NOTE (EVENTS,
2952                 g_message ("delete window:\t\twindow: %ld",
2953                            xevent->xclient.window - base_id));
2954       
2955       event->any.type = GDK_DELETE;
2956
2957       return GDK_FILTER_TRANSLATE;
2958     }
2959   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
2960     {
2961     }
2962
2963   return GDK_FILTER_REMOVE;
2964 }
2965
2966 #if 0
2967 static Bool
2968 gdk_event_get_type (Display  *display,
2969                     XEvent   *xevent,
2970                     XPointer  arg)
2971 {
2972   GdkEvent event;
2973   GdkPredicate *pred;
2974   
2975   if (gdk_event_translate (&event, xevent))
2976     {
2977       pred = (GdkPredicate*) arg;
2978       return (* pred->func) (&event, pred->data);
2979     }
2980   
2981   return FALSE;
2982 }
2983 #endif
2984
2985 static void
2986 gdk_synthesize_click (GdkEvent *event,
2987                       gint      nclicks)
2988 {
2989   GdkEvent temp_event;
2990   
2991   g_return_if_fail (event != NULL);
2992   
2993   temp_event = *event;
2994   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
2995   
2996   gdk_event_put (&temp_event);
2997 }
2998
2999 /*
3000  *--------------------------------------------------------------
3001  * gdk_exit_func
3002  *
3003  *   This is the "atexit" function that makes sure the
3004  *   library gets a chance to cleanup.
3005  *
3006  * Arguments:
3007  *
3008  * Results:
3009  *
3010  * Side effects:
3011  *   The library is un-initialized and the program exits.
3012  *
3013  *--------------------------------------------------------------
3014  */
3015
3016 static void
3017 gdk_exit_func (void)
3018 {
3019   static gboolean in_gdk_exit_func = FALSE;
3020   
3021   /* This is to avoid an infinite loop if a program segfaults in
3022      an atexit() handler (and yes, it does happen, especially if a program
3023      has trounced over memory too badly for even g_message to work) */
3024   if (in_gdk_exit_func == TRUE)
3025     return;
3026   in_gdk_exit_func = TRUE;
3027   
3028   if (gdk_initialized)
3029     {
3030 #ifdef USE_XIM
3031       /* cleanup IC */
3032       gdk_ic_cleanup ();
3033       /* close IM */
3034       gdk_im_close ();
3035 #endif
3036       gdk_image_exit ();
3037       gdk_input_exit ();
3038       gdk_key_repeat_restore ();
3039       
3040       XCloseDisplay (gdk_display);
3041       gdk_initialized = 0;
3042     }
3043 }
3044
3045 /*
3046  *--------------------------------------------------------------
3047  * gdk_x_error
3048  *
3049  *   The X error handling routine.
3050  *
3051  * Arguments:
3052  *   "display" is the X display the error orignated from.
3053  *   "error" is the XErrorEvent that we are handling.
3054  *
3055  * Results:
3056  *   Either we were expecting some sort of error to occur,
3057  *   in which case we set the "gdk_error_code" flag, or this
3058  *   error was unexpected, in which case we will print an
3059  *   error message and exit. (Since trying to continue will
3060  *   most likely simply lead to more errors).
3061  *
3062  * Side effects:
3063  *
3064  *--------------------------------------------------------------
3065  */
3066
3067 static int
3068 gdk_x_error (Display     *display,
3069              XErrorEvent *error)
3070 {
3071   char buf[64];
3072   
3073   if (gdk_error_warnings)
3074     {
3075       XGetErrorText (display, error->error_code, buf, 63);
3076       g_error ("%s\n  serial %ld error_code %d request_code %d minor_code %d\n", 
3077                buf, 
3078                error->serial, 
3079                error->error_code, 
3080                error->request_code,
3081                error->minor_code);
3082     }
3083   
3084   gdk_error_code = -1;
3085   return 0;
3086 }
3087
3088 /*
3089  *--------------------------------------------------------------
3090  * gdk_x_io_error
3091  *
3092  *   The X I/O error handling routine.
3093  *
3094  * Arguments:
3095  *   "display" is the X display the error orignated from.
3096  *
3097  * Results:
3098  *   An X I/O error basically means we lost our connection
3099  *   to the X server. There is not much we can do to
3100  *   continue, so simply print an error message and exit.
3101  *
3102  * Side effects:
3103  *
3104  *--------------------------------------------------------------
3105  */
3106
3107 static int
3108 gdk_x_io_error (Display *display)
3109 {
3110   g_error ("an x io error occurred");
3111   return 0;
3112 }
3113
3114 /*
3115  *--------------------------------------------------------------
3116  * gdk_signal
3117  *
3118  *   The signal handler.
3119  *
3120  * Arguments:
3121  *   "sig_num" is the number of the signal we received.
3122  *
3123  * Results:
3124  *   The signals we catch are all fatal. So we simply build
3125  *   up a nice little error message and print it and exit.
3126  *   If in the process of doing so another signal is received
3127  *   we notice that we are already exiting and simply kill
3128  *   our process.
3129  *
3130  * Side effects:
3131  *
3132  *--------------------------------------------------------------
3133  */
3134
3135 static RETSIGTYPE
3136 gdk_signal (int sig_num)
3137 {
3138   static int caught_fatal_sig = 0;
3139   char *sig;
3140   
3141   if (caught_fatal_sig)
3142     kill (getpid (), sig_num);
3143   caught_fatal_sig = 1;
3144   
3145   switch (sig_num)
3146     {
3147     case SIGHUP:
3148       sig = "sighup";
3149       break;
3150     case SIGINT:
3151       sig = "sigint";
3152       break;
3153     case SIGQUIT:
3154       sig = "sigquit";
3155       break;
3156     case SIGBUS:
3157       sig = "sigbus";
3158       break;
3159     case SIGSEGV:
3160       sig = "sigsegv";
3161       break;
3162     case SIGPIPE:
3163       sig = "sigpipe";
3164       break;
3165     case SIGTERM:
3166       sig = "sigterm";
3167       break;
3168     default:
3169       sig = "unknown signal";
3170       break;
3171     }
3172   
3173   g_message ("\n** ERROR **: %s caught", sig);
3174 #ifdef G_ENABLE_DEBUG
3175   abort ();
3176 #else /* !G_ENABLE_DEBUG */
3177   gdk_exit (1);
3178 #endif /* !G_ENABLE_DEBUG */
3179 }
3180
3181 /* Sends a ClientMessage to all toplevel client windows */
3182 gboolean
3183 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
3184 {
3185   XEvent sev;
3186   
3187   g_return_val_if_fail(event != NULL, FALSE);
3188   
3189   /* Set up our event to send, with the exception of its target window */
3190   sev.xclient.type = ClientMessage;
3191   sev.xclient.display = gdk_display;
3192   sev.xclient.format = event->client.data_format;
3193   sev.xclient.window = xid;
3194   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
3195   sev.xclient.message_type = event->client.message_type;
3196   
3197   return gdk_send_xevent (xid, False, NoEventMask, &sev);
3198 }
3199
3200 /* Sends a ClientMessage to all toplevel client windows */
3201 gboolean
3202 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
3203                                               guint32  xid,
3204                                               guint    level)
3205 {
3206   static GdkAtom wm_state_atom = GDK_NONE;
3207
3208   Atom type = None;
3209   int format;
3210   unsigned long nitems, after;
3211   unsigned char *data;
3212   
3213   Window *ret_children, ret_root, ret_parent;
3214   unsigned int ret_nchildren;
3215   int i;
3216   
3217   gboolean send = FALSE;
3218   gboolean found = FALSE;
3219
3220   if (!wm_state_atom)
3221     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
3222
3223   gdk_error_code = 0;
3224   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
3225                       &type, &format, &nitems, &after, &data);
3226
3227   if (gdk_error_code)
3228     {
3229       gdk_error_code = 0;
3230       return FALSE;
3231     }
3232
3233   if (type)
3234     {
3235       send = TRUE;
3236       XFree (data);
3237     }
3238   else
3239     {
3240       /* OK, we're all set, now let's find some windows to send this to */
3241       if (XQueryTree(gdk_display, xid, &ret_root, &ret_parent,
3242                      &ret_children, &ret_nchildren) != True)
3243         return FALSE;
3244       
3245       if (gdk_error_code)
3246         return FALSE;
3247
3248       for(i = 0; i < ret_nchildren; i++)
3249         if (gdk_event_send_client_message_to_all_recurse(xev, ret_children[i], level + 1))
3250           found = TRUE;
3251
3252       XFree(ret_children);
3253     }
3254
3255   if (send || (!found && (level == 1)))
3256     {
3257       xev->xclient.window = xid;
3258       gdk_send_xevent (xid, False, NoEventMask, xev);
3259     }
3260
3261   return (send || found);
3262 }
3263
3264 void
3265 gdk_event_send_clientmessage_toall (GdkEvent *event)
3266 {
3267   XEvent sev;
3268   gint old_warnings = gdk_error_warnings;
3269
3270   g_return_if_fail(event != NULL);
3271   
3272   /* Set up our event to send, with the exception of its target window */
3273   sev.xclient.type = ClientMessage;
3274   sev.xclient.display = gdk_display;
3275   sev.xclient.format = event->client.data_format;
3276   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
3277   sev.xclient.message_type = event->client.message_type;
3278
3279   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
3280
3281   gdk_error_warnings = old_warnings;
3282 }
3283
3284 gchar *
3285 gdk_get_display(void)
3286 {
3287   return (gchar *)XDisplayName (gdk_display_name);
3288 }
3289
3290 gint 
3291 gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
3292                  XEvent *event_send)
3293 {
3294   Status result;
3295   gint old_warnings = gdk_error_warnings;
3296   
3297   gdk_error_code = 0;
3298   
3299   gdk_error_warnings = 0;
3300   result = XSendEvent (gdk_display, window, propagate, event_mask, event_send);
3301   XSync (gdk_display, False);
3302   gdk_error_warnings = old_warnings;
3303   
3304   return result && (gdk_error_code != -1);
3305 }
3306
3307 #ifndef HAVE_XCONVERTCASE
3308 /* compatibility function from X11R6.3, since XConvertCase is not
3309  * supplied by X11R5.
3310  */
3311 static void
3312 gdkx_XConvertCase (KeySym symbol,
3313                    KeySym *lower,
3314                    KeySym *upper)
3315 {
3316   register KeySym sym = symbol;
3317   
3318   g_return_if_fail (lower != NULL);
3319   g_return_if_fail (upper != NULL);
3320   
3321   *lower = sym;
3322   *upper = sym;
3323   
3324   switch (sym >> 8)
3325     {
3326 #if     defined (GDK_A) && defined (GDK_Ooblique)
3327     case 0: /* Latin 1 */
3328       if ((sym >= GDK_A) && (sym <= GDK_Z))
3329         *lower += (GDK_a - GDK_A);
3330       else if ((sym >= GDK_a) && (sym <= GDK_z))
3331         *upper -= (GDK_a - GDK_A);
3332       else if ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis))
3333         *lower += (GDK_agrave - GDK_Agrave);
3334       else if ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis))
3335         *upper -= (GDK_agrave - GDK_Agrave);
3336       else if ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn))
3337         *lower += (GDK_oslash - GDK_Ooblique);
3338       else if ((sym >= GDK_oslash) && (sym <= GDK_thorn))
3339         *upper -= (GDK_oslash - GDK_Ooblique);
3340       break;
3341 #endif  /* LATIN1 */
3342       
3343 #if     defined (GDK_Aogonek) && defined (GDK_tcedilla)
3344     case 1: /* Latin 2 */
3345       /* Assume the KeySym is a legal value (ignore discontinuities) */
3346       if (sym == GDK_Aogonek)
3347         *lower = GDK_aogonek;
3348       else if (sym >= GDK_Lstroke && sym <= GDK_Sacute)
3349         *lower += (GDK_lstroke - GDK_Lstroke);
3350       else if (sym >= GDK_Scaron && sym <= GDK_Zacute)
3351         *lower += (GDK_scaron - GDK_Scaron);
3352       else if (sym >= GDK_Zcaron && sym <= GDK_Zabovedot)
3353         *lower += (GDK_zcaron - GDK_Zcaron);
3354       else if (sym == GDK_aogonek)
3355         *upper = GDK_Aogonek;
3356       else if (sym >= GDK_lstroke && sym <= GDK_sacute)
3357         *upper -= (GDK_lstroke - GDK_Lstroke);
3358       else if (sym >= GDK_scaron && sym <= GDK_zacute)
3359         *upper -= (GDK_scaron - GDK_Scaron);
3360       else if (sym >= GDK_zcaron && sym <= GDK_zabovedot)
3361         *upper -= (GDK_zcaron - GDK_Zcaron);
3362       else if (sym >= GDK_Racute && sym <= GDK_Tcedilla)
3363         *lower += (GDK_racute - GDK_Racute);
3364       else if (sym >= GDK_racute && sym <= GDK_tcedilla)
3365         *upper -= (GDK_racute - GDK_Racute);
3366       break;
3367 #endif  /* LATIN2 */
3368       
3369 #if     defined (GDK_Hstroke) && defined (GDK_Cabovedot)
3370     case 2: /* Latin 3 */
3371       /* Assume the KeySym is a legal value (ignore discontinuities) */
3372       if (sym >= GDK_Hstroke && sym <= GDK_Hcircumflex)
3373         *lower += (GDK_hstroke - GDK_Hstroke);
3374       else if (sym >= GDK_Gbreve && sym <= GDK_Jcircumflex)
3375         *lower += (GDK_gbreve - GDK_Gbreve);
3376       else if (sym >= GDK_hstroke && sym <= GDK_hcircumflex)
3377         *upper -= (GDK_hstroke - GDK_Hstroke);
3378       else if (sym >= GDK_gbreve && sym <= GDK_jcircumflex)
3379         *upper -= (GDK_gbreve - GDK_Gbreve);
3380       else if (sym >= GDK_Cabovedot && sym <= GDK_Scircumflex)
3381         *lower += (GDK_cabovedot - GDK_Cabovedot);
3382       else if (sym >= GDK_cabovedot && sym <= GDK_scircumflex)
3383         *upper -= (GDK_cabovedot - GDK_Cabovedot);
3384       break;
3385 #endif  /* LATIN3 */
3386       
3387 #if     defined (GDK_Rcedilla) && defined (GDK_Amacron)
3388     case 3: /* Latin 4 */
3389       /* Assume the KeySym is a legal value (ignore discontinuities) */
3390       if (sym >= GDK_Rcedilla && sym <= GDK_Tslash)
3391         *lower += (GDK_rcedilla - GDK_Rcedilla);
3392       else if (sym >= GDK_rcedilla && sym <= GDK_tslash)
3393         *upper -= (GDK_rcedilla - GDK_Rcedilla);
3394       else if (sym == GDK_ENG)
3395         *lower = GDK_eng;
3396       else if (sym == GDK_eng)
3397         *upper = GDK_ENG;
3398       else if (sym >= GDK_Amacron && sym <= GDK_Umacron)
3399         *lower += (GDK_amacron - GDK_Amacron);
3400       else if (sym >= GDK_amacron && sym <= GDK_umacron)
3401         *upper -= (GDK_amacron - GDK_Amacron);
3402       break;
3403 #endif  /* LATIN4 */
3404       
3405 #if     defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu)
3406     case 6: /* Cyrillic */
3407       /* Assume the KeySym is a legal value (ignore discontinuities) */
3408       if (sym >= GDK_Serbian_DJE && sym <= GDK_Serbian_DZE)
3409         *lower -= (GDK_Serbian_DJE - GDK_Serbian_dje);
3410       else if (sym >= GDK_Serbian_dje && sym <= GDK_Serbian_dze)
3411         *upper += (GDK_Serbian_DJE - GDK_Serbian_dje);
3412       else if (sym >= GDK_Cyrillic_YU && sym <= GDK_Cyrillic_HARDSIGN)
3413         *lower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
3414       else if (sym >= GDK_Cyrillic_yu && sym <= GDK_Cyrillic_hardsign)
3415         *upper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
3416       break;
3417 #endif  /* CYRILLIC */
3418       
3419 #if     defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma)
3420     case 7: /* Greek */
3421       /* Assume the KeySym is a legal value (ignore discontinuities) */
3422       if (sym >= GDK_Greek_ALPHAaccent && sym <= GDK_Greek_OMEGAaccent)
3423         *lower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
3424       else if (sym >= GDK_Greek_alphaaccent && sym <= GDK_Greek_omegaaccent &&
3425                sym != GDK_Greek_iotaaccentdieresis &&
3426                sym != GDK_Greek_upsilonaccentdieresis)
3427         *upper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
3428       else if (sym >= GDK_Greek_ALPHA && sym <= GDK_Greek_OMEGA)
3429         *lower += (GDK_Greek_alpha - GDK_Greek_ALPHA);
3430       else if (sym >= GDK_Greek_alpha && sym <= GDK_Greek_omega &&
3431                sym != GDK_Greek_finalsmallsigma)
3432         *upper -= (GDK_Greek_alpha - GDK_Greek_ALPHA);
3433       break;
3434 #endif  /* GREEK */
3435     }
3436 }
3437 #endif
3438
3439 gchar*
3440 gdk_keyval_name (guint        keyval)
3441 {
3442   return XKeysymToString (keyval);
3443 }
3444
3445 guint
3446 gdk_keyval_from_name (const gchar *keyval_name)
3447 {
3448   g_return_val_if_fail (keyval_name != NULL, 0);
3449   
3450   return XStringToKeysym (keyval_name);
3451 }
3452
3453 guint
3454 gdk_keyval_to_upper (guint        keyval)
3455 {
3456   if (keyval)
3457     {
3458       KeySym lower_val = 0;
3459       KeySym upper_val = 0;
3460       
3461       XConvertCase (keyval, &lower_val, &upper_val);
3462       return upper_val;
3463     }
3464   return 0;
3465 }
3466
3467 guint
3468 gdk_keyval_to_lower (guint        keyval)
3469 {
3470   if (keyval)
3471     {
3472       KeySym lower_val = 0;
3473       KeySym upper_val = 0;
3474       
3475       XConvertCase (keyval, &lower_val, &upper_val);
3476       return lower_val;
3477     }
3478   return 0;
3479 }
3480
3481 gboolean
3482 gdk_keyval_is_upper (guint        keyval)
3483 {
3484   if (keyval)
3485     {
3486       KeySym lower_val = 0;
3487       KeySym upper_val = 0;
3488       
3489       XConvertCase (keyval, &lower_val, &upper_val);
3490       return upper_val == keyval;
3491     }
3492   return TRUE;
3493 }
3494
3495 gboolean
3496 gdk_keyval_is_lower (guint        keyval)
3497 {
3498   if (keyval)
3499     {
3500       KeySym lower_val = 0;
3501       KeySym upper_val = 0;
3502       
3503       XConvertCase (keyval, &lower_val, &upper_val);
3504       return lower_val == keyval;
3505     }
3506   return TRUE;
3507 }