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