]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
e907f04adb55bb371b64926bb2b96ddb5f113a8f
[~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
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <limits.h>
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 #include <X11/cursorfont.h>
46 #include "gdk.h"
47 #include "gdkprivate.h"
48 #include "gdkinput.h"
49 #include "gdkx.h"
50 #include "gdki18n.h"
51
52 #ifndef X_GETTIMEOFDAY
53 #define X_GETTIMEOFDAY(tv)  gettimeofday (tv, NULL)
54 #endif /* X_GETTIMEOFDAY */
55
56
57 typedef struct _GdkPredicate  GdkPredicate;
58 typedef struct _GdkErrorTrap  GdkErrorTrap;
59
60 struct _GdkPredicate
61 {
62   GdkEventFunc func;
63   gpointer data;
64 };
65
66 struct _GdkErrorTrap
67 {
68   gint error_warnings;
69   gint error_code;
70 };
71
72 /* 
73  * Private function declarations
74  */
75
76 #ifndef HAVE_XCONVERTCASE
77 static void      gdkx_XConvertCase      (KeySym        symbol,
78                                          KeySym       *lower,
79                                          KeySym       *upper);
80 #define XConvertCase gdkx_XConvertCase
81 #endif
82
83 static void         gdk_exit_func                (void);
84 static int          gdk_x_error                  (Display     *display, 
85                                                   XErrorEvent *error);
86 static int          gdk_x_io_error               (Display     *display);
87
88 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
89                                          GdkEvent  *event,
90                                          gpointer   data);
91
92 /* Private variable declarations
93  */
94 static int gdk_initialized = 0;                     /* 1 if the library is initialized,
95                                                      * 0 otherwise.
96                                                      */
97
98 static struct timeval start;                        /* The time at which the library was
99                                                      *  last initialized.
100                                                      */
101 static struct timeval timer;                        /* Timeout interval to use in the call
102                                                      *  to "select". This is used in
103                                                      *  conjunction with "timerp" to create
104                                                      *  a maximum time to wait for an event
105                                                      *  to arrive.
106                                                      */
107 static struct timeval *timerp;                      /* The actual timer passed to "select"
108                                                      *  This may be NULL, in which case
109                                                      *  "select" will block until an event
110                                                      *  arrives.
111                                                      */
112 static guint32 timer_val;                           /* The timeout length as specified by
113                                                      *  the user in milliseconds.
114                                                      */
115 static gint autorepeat;
116
117 static GSList *gdk_error_traps = NULL;               /* List of error traps */
118 static GSList *gdk_error_trap_free_list = NULL;      /* Free list */
119
120 #ifdef G_ENABLE_DEBUG
121 static const GDebugKey gdk_debug_keys[] = {
122   {"events",        GDK_DEBUG_EVENTS},
123   {"misc",          GDK_DEBUG_MISC},
124   {"dnd",           GDK_DEBUG_DND},
125   {"color-context", GDK_DEBUG_COLOR_CONTEXT},
126   {"xim",           GDK_DEBUG_XIM}
127 };
128
129 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
130
131 #endif /* G_ENABLE_DEBUG */
132
133 /*
134  *--------------------------------------------------------------
135  * gdk_init_heck
136  *
137  *   Initialize the library for use.
138  *
139  * Arguments:
140  *   "argc" is the number of arguments.
141  *   "argv" is an array of strings.
142  *
143  * Results:
144  *   "argc" and "argv" are modified to reflect any arguments
145  *   which were not handled. (Such arguments should either
146  *   be handled by the application or dismissed). If initialization
147  *   fails, returns FALSE, otherwise TRUE.
148  *
149  * Side effects:
150  *   The library is initialized.
151  *
152  *--------------------------------------------------------------
153  */
154
155 gboolean
156 gdk_init_check (int      *argc,
157                 char ***argv)
158 {
159   XKeyboardState keyboard_state;
160   gint synchronize;
161   gint i, j, k;
162   XClassHint *class_hint;
163   gchar **argv_orig = NULL;
164   gint argc_orig = 0;
165   
166   if (gdk_initialized)
167     return TRUE;
168   
169   if (g_thread_supported ())
170     gdk_threads_mutex = g_mutex_new ();
171   
172   if (argc && argv)
173     {
174       argc_orig = *argc;
175       
176       argv_orig = g_malloc ((argc_orig + 1) * sizeof (char*));
177       for (i = 0; i < argc_orig; i++)
178         argv_orig[i] = g_strdup ((*argv)[i]);
179       argv_orig[argc_orig] = NULL;
180     }
181   
182   X_GETTIMEOFDAY (&start);
183   
184   gdk_display_name = NULL;
185   
186   XSetErrorHandler (gdk_x_error);
187   XSetIOErrorHandler (gdk_x_io_error);
188   
189   synchronize = FALSE;
190   
191 #ifdef G_ENABLE_DEBUG
192   {
193     gchar *debug_string = getenv("GDK_DEBUG");
194     if (debug_string != NULL)
195       gdk_debug_flags = g_parse_debug_string (debug_string,
196                                               (GDebugKey *) gdk_debug_keys,
197                                               gdk_ndebug_keys);
198   }
199 #endif  /* G_ENABLE_DEBUG */
200   
201   if (argc && argv)
202     {
203       if (*argc > 0)
204         {
205           gchar *d;
206           
207           d = strrchr((*argv)[0],'/');
208           if (d != NULL)
209             g_set_prgname (d + 1);
210           else
211             g_set_prgname ((*argv)[0]);
212         }
213       
214       for (i = 1; i < *argc;)
215         {
216 #ifdef G_ENABLE_DEBUG     
217           if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) ||
218               (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0))
219             {
220               gchar *equal_pos = strchr ((*argv)[i], '=');
221               
222               if (equal_pos != NULL)
223                 {
224                   gdk_debug_flags |= g_parse_debug_string (equal_pos+1,
225                                                            (GDebugKey *) gdk_debug_keys,
226                                                            gdk_ndebug_keys);
227                 }
228               else if ((i + 1) < *argc && (*argv)[i + 1])
229                 {
230                   gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
231                                                            (GDebugKey *) gdk_debug_keys,
232                                                            gdk_ndebug_keys);
233                   (*argv)[i] = NULL;
234                   i += 1;
235                 }
236               (*argv)[i] = NULL;
237             }
238           else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) ||
239                    (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0))
240             {
241               gchar *equal_pos = strchr ((*argv)[i], '=');
242               
243               if (equal_pos != NULL)
244                 {
245                   gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
246                                                             (GDebugKey *) gdk_debug_keys,
247                                                             gdk_ndebug_keys);
248                 }
249               else if ((i + 1) < *argc && (*argv)[i + 1])
250                 {
251                   gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
252                                                             (GDebugKey *) gdk_debug_keys,
253                                                             gdk_ndebug_keys);
254                   (*argv)[i] = NULL;
255                   i += 1;
256                 }
257               (*argv)[i] = NULL;
258             }
259           else 
260 #endif /* G_ENABLE_DEBUG */
261             if (strcmp ("--display", (*argv)[i]) == 0)
262               {
263                 (*argv)[i] = NULL;
264                 
265                 if ((i + 1) < *argc && (*argv)[i + 1])
266                   {
267                     gdk_display_name = g_strdup ((*argv)[i + 1]);
268                     (*argv)[i + 1] = NULL;
269                     i += 1;
270                   }
271               }
272             else if (strcmp ("--sync", (*argv)[i]) == 0)
273               {
274                 (*argv)[i] = NULL;
275                 synchronize = TRUE;
276               }
277             else if (strcmp ("--no-xshm", (*argv)[i]) == 0)
278               {
279                 (*argv)[i] = NULL;
280                 gdk_use_xshm = FALSE;
281               }
282             else if (strcmp ("--name", (*argv)[i]) == 0)
283               {
284                 if ((i + 1) < *argc && (*argv)[i + 1])
285                   {
286                     (*argv)[i++] = NULL;
287                     g_set_prgname ((*argv)[i]);
288                     (*argv)[i] = NULL;
289                   }
290               }
291             else if (strcmp ("--class", (*argv)[i]) == 0)
292               {
293                 if ((i + 1) < *argc && (*argv)[i + 1])
294                   {
295                     (*argv)[i++] = NULL;
296                     gdk_progclass = (*argv)[i];
297                     (*argv)[i] = NULL;
298                   }
299               }
300 #ifdef XINPUT_GXI
301             else if (strcmp ("--gxid_host", (*argv)[i]) == 0)
302               {
303                 if ((i + 1) < *argc && (*argv)[i + 1])
304                   {
305                     (*argv)[i++] = NULL;
306                     gdk_input_gxid_host = ((*argv)[i]);
307                     (*argv)[i] = NULL;
308                   }
309               }
310             else if (strcmp ("--gxid_port", (*argv)[i]) == 0)
311               {
312                 if ((i + 1) < *argc && (*argv)[i + 1])
313                   {
314                     (*argv)[i++] = NULL;
315                     gdk_input_gxid_port = atoi ((*argv)[i]);
316                     (*argv)[i] = NULL;
317                   }
318               }
319 #endif
320 #ifdef USE_XIM
321             else if (strcmp ("--xim-preedit", (*argv)[i]) == 0)
322               {
323                 if ((i + 1) < *argc && (*argv)[i + 1])
324                   {
325                     (*argv)[i++] = NULL;
326                     if (strcmp ("none", (*argv)[i]) == 0)
327                       gdk_im_set_best_style (GDK_IM_PREEDIT_NONE);
328                     else if (strcmp ("nothing", (*argv)[i]) == 0)
329                       gdk_im_set_best_style (GDK_IM_PREEDIT_NOTHING);
330                     else if (strcmp ("area", (*argv)[i]) == 0)
331                       gdk_im_set_best_style (GDK_IM_PREEDIT_AREA);
332                     else if (strcmp ("position", (*argv)[i]) == 0)
333                       gdk_im_set_best_style (GDK_IM_PREEDIT_POSITION);
334                     else if (strcmp ("callbacks", (*argv)[i]) == 0)
335                       gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS);
336                   }
337               }
338             else if (strcmp ("--xim-status", (*argv)[i]) == 0)
339               {
340                 if ((i + 1) < *argc && (*argv)[i + 1])
341                   {
342                     (*argv)[i++] = NULL;
343                     if (strcmp ("none", (*argv)[i]) == 0)
344                       gdk_im_set_best_style (GDK_IM_STATUS_NONE);
345                     else if (strcmp ("nothing", (*argv)[i]) == 0)
346                       gdk_im_set_best_style (GDK_IM_STATUS_NOTHING);
347                     else if (strcmp ("area", (*argv)[i]) == 0)
348                       gdk_im_set_best_style (GDK_IM_STATUS_AREA);
349                     else if (strcmp ("callbacks", (*argv)[i]) == 0)
350                       gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS);
351                   }
352               }
353 #endif
354           
355           i += 1;
356         }
357       
358       for (i = 1; i < *argc; i++)
359         {
360           for (k = i; k < *argc; k++)
361             if ((*argv)[k] != NULL)
362               break;
363           
364           if (k > i)
365             {
366               k -= i;
367               for (j = i + k; j < *argc; j++)
368                 (*argv)[j-k] = (*argv)[j];
369               *argc -= k;
370             }
371         }
372     }
373   else
374     {
375       g_set_prgname ("<unknown>");
376     }
377   
378   GDK_NOTE (MISC, g_message ("progname: \"%s\"", g_get_prgname ()));
379   
380   gdk_display = XOpenDisplay (gdk_display_name);
381   if (!gdk_display)
382     return FALSE;
383   
384   if (synchronize)
385     XSynchronize (gdk_display, True);
386   
387   gdk_screen = DefaultScreen (gdk_display);
388   gdk_root_window = RootWindow (gdk_display, gdk_screen);
389   
390   gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
391                                           10, 10, 10, 10, 0, 0 , 0);
392   class_hint = XAllocClassHint();
393   class_hint->res_name = g_get_prgname ();
394   if (gdk_progclass == NULL)
395     {
396       gdk_progclass = g_strdup (g_get_prgname ());
397       gdk_progclass[0] = toupper (gdk_progclass[0]);
398     }
399   class_hint->res_class = gdk_progclass;
400   XmbSetWMProperties (gdk_display, gdk_leader_window,
401                       NULL, NULL, argv_orig, argc_orig, 
402                       NULL, NULL, class_hint);
403   XFree (class_hint);
404   
405   for (i = 0; i < argc_orig; i++)
406     g_free(argv_orig[i]);
407   g_free(argv_orig);
408   
409   gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True);
410   gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True);
411   gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True);
412   gdk_wm_window_protocols[0] = gdk_wm_delete_window;
413   gdk_wm_window_protocols[1] = gdk_wm_take_focus;
414   gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
415   
416   XGetKeyboardControl (gdk_display, &keyboard_state);
417   autorepeat = keyboard_state.global_auto_repeat;
418   
419   timer.tv_sec = 0;
420   timer.tv_usec = 0;
421   timerp = NULL;
422   
423   g_atexit (gdk_exit_func);
424   
425   gdk_events_init ();
426   gdk_visual_init ();
427   gdk_window_init ();
428   gdk_image_init ();
429   gdk_input_init ();
430   gdk_dnd_init ();
431
432 #ifdef USE_XIM
433   gdk_im_open ();
434 #endif
435   
436   gdk_initialized = 1;
437
438   return TRUE;
439 }
440
441 void
442 gdk_init (int *argc, char ***argv)
443 {
444   if (!gdk_init_check (argc, argv))
445     {
446       g_warning ("cannot open display: %s", gdk_get_display ());
447       exit(1);
448     }
449 }
450
451 /*
452  *--------------------------------------------------------------
453  * gdk_exit
454  *
455  *   Restores the library to an un-itialized state and exits
456  *   the program using the "exit" system call.
457  *
458  * Arguments:
459  *   "errorcode" is the error value to pass to "exit".
460  *
461  * Results:
462  *   Allocated structures are freed and the program exits
463  *   cleanly.
464  *
465  * Side effects:
466  *
467  *--------------------------------------------------------------
468  */
469
470 void
471 gdk_exit (gint errorcode)
472 {
473   /* de-initialisation is done by the gdk_exit_funct(),
474      no need to do this here (Alex J.) */
475   exit (errorcode);
476 }
477
478 void
479 gdk_set_use_xshm (gint use_xshm)
480 {
481   gdk_use_xshm = use_xshm;
482 }
483
484 gint
485 gdk_get_use_xshm (void)
486 {
487   return gdk_use_xshm;
488 }
489
490 /*
491  *--------------------------------------------------------------
492  * gdk_time_get
493  *
494  *   Get the number of milliseconds since the library was
495  *   initialized.
496  *
497  * Arguments:
498  *
499  * Results:
500  *   The time since the library was initialized is returned.
501  *   This time value is accurate to milliseconds even though
502  *   a more accurate time down to the microsecond could be
503  *   returned.
504  *
505  * Side effects:
506  *
507  *--------------------------------------------------------------
508  */
509
510 guint32
511 gdk_time_get (void)
512 {
513   struct timeval end;
514   struct timeval elapsed;
515   guint32 milliseconds;
516   
517   X_GETTIMEOFDAY (&end);
518   
519   if (start.tv_usec > end.tv_usec)
520     {
521       end.tv_usec += 1000000;
522       end.tv_sec--;
523     }
524   elapsed.tv_sec = end.tv_sec - start.tv_sec;
525   elapsed.tv_usec = end.tv_usec - start.tv_usec;
526   
527   milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000);
528   
529   return milliseconds;
530 }
531
532 /*
533  *--------------------------------------------------------------
534  * gdk_timer_get
535  *
536  *   Returns the current timer.
537  *
538  * Arguments:
539  *
540  * Results:
541  *   Returns the current timer interval. This interval is
542  *   in units of milliseconds.
543  *
544  * Side effects:
545  *
546  *--------------------------------------------------------------
547  */
548
549 guint32
550 gdk_timer_get (void)
551 {
552   return timer_val;
553 }
554
555 /*
556  *--------------------------------------------------------------
557  * gdk_timer_set
558  *
559  *   Sets the timer interval.
560  *
561  * Arguments:
562  *   "milliseconds" is the new value for the timer.
563  *
564  * Results:
565  *
566  * Side effects:
567  *   Calls to "gdk_event_get" will last for a maximum
568  *   of time of "milliseconds". However, a value of 0
569  *   milliseconds will cause "gdk_event_get" to block
570  *   indefinately until an event is received.
571  *
572  *--------------------------------------------------------------
573  */
574
575 void
576 gdk_timer_set (guint32 milliseconds)
577 {
578   timer_val = milliseconds;
579   timer.tv_sec = milliseconds / 1000;
580   timer.tv_usec = (milliseconds % 1000) * 1000;
581   
582 }
583
584 void
585 gdk_timer_enable (void)
586 {
587   timerp = &timer;
588 }
589
590 void
591 gdk_timer_disable (void)
592 {
593   timerp = NULL;
594 }
595
596 /*
597  *--------------------------------------------------------------
598  * gdk_pointer_grab
599  *
600  *   Grabs the pointer to a specific window
601  *
602  * Arguments:
603  *   "window" is the window which will receive the grab
604  *   "owner_events" specifies whether events will be reported as is,
605  *     or relative to "window"
606  *   "event_mask" masks only interesting events
607  *   "confine_to" limits the cursor movement to the specified window
608  *   "cursor" changes the cursor for the duration of the grab
609  *   "time" specifies the time
610  *
611  * Results:
612  *
613  * Side effects:
614  *   requires a corresponding call to gdk_pointer_ungrab
615  *
616  *--------------------------------------------------------------
617  */
618
619 gint
620 gdk_pointer_grab (GdkWindow *     window,
621                   gint            owner_events,
622                   GdkEventMask    event_mask,
623                   GdkWindow *     confine_to,
624                   GdkCursor *     cursor,
625                   guint32         time)
626 {
627   /*  From gdkwindow.c  */
628   gint return_val;
629   GdkWindowPrivate *window_private;
630   GdkWindowPrivate *confine_to_private;
631   GdkCursorPrivate *cursor_private;
632   guint xevent_mask;
633   Window xwindow;
634   Window xconfine_to;
635   Cursor xcursor;
636   int i;
637   
638   g_return_val_if_fail (window != NULL, 0);
639   
640   window_private = (GdkWindowPrivate*) window;
641   confine_to_private = (GdkWindowPrivate*) confine_to;
642   cursor_private = (GdkCursorPrivate*) cursor;
643   
644   xwindow = window_private->xwindow;
645   
646   if (!confine_to || confine_to_private->destroyed)
647     xconfine_to = None;
648   else
649     xconfine_to = confine_to_private->xwindow;
650   
651   if (!cursor)
652     xcursor = None;
653   else
654     xcursor = cursor_private->xcursor;
655   
656   
657   xevent_mask = 0;
658   for (i = 0; i < gdk_nevent_masks; i++)
659     {
660       if (event_mask & (1 << (i + 1)))
661         xevent_mask |= gdk_event_mask_table[i];
662     }
663   
664   if (gdk_input_vtable.grab_pointer)
665     return_val = gdk_input_vtable.grab_pointer (window,
666                                                 owner_events,
667                                                 event_mask,
668                                                 confine_to,
669                                                 time);
670   else
671     return_val = Success;
672   
673   if (return_val == Success)
674     {
675       if (!window_private->destroyed)
676         return_val = XGrabPointer (window_private->xdisplay,
677                                    xwindow,
678                                    owner_events,
679                                    xevent_mask,
680                                    GrabModeAsync, GrabModeAsync,
681                                    xconfine_to,
682                                    xcursor,
683                                    time);
684       else
685         return_val = AlreadyGrabbed;
686     }
687   
688   if (return_val == GrabSuccess)
689     gdk_xgrab_window = window_private;
690   
691   return return_val;
692 }
693
694 /*
695  *--------------------------------------------------------------
696  * gdk_pointer_ungrab
697  *
698  *   Releases any pointer grab
699  *
700  * Arguments:
701  *
702  * Results:
703  *
704  * Side effects:
705  *
706  *--------------------------------------------------------------
707  */
708
709 void
710 gdk_pointer_ungrab (guint32 time)
711 {
712   if (gdk_input_vtable.ungrab_pointer)
713     gdk_input_vtable.ungrab_pointer (time);
714   
715   XUngrabPointer (gdk_display, time);
716   gdk_xgrab_window = NULL;
717 }
718
719 /*
720  *--------------------------------------------------------------
721  * gdk_pointer_is_grabbed
722  *
723  *   Tell wether there is an active x pointer grab in effect
724  *
725  * Arguments:
726  *
727  * Results:
728  *
729  * Side effects:
730  *
731  *--------------------------------------------------------------
732  */
733
734 gint
735 gdk_pointer_is_grabbed (void)
736 {
737   return gdk_xgrab_window != NULL;
738 }
739
740 /*
741  *--------------------------------------------------------------
742  * gdk_keyboard_grab
743  *
744  *   Grabs the keyboard to a specific window
745  *
746  * Arguments:
747  *   "window" is the window which will receive the grab
748  *   "owner_events" specifies whether events will be reported as is,
749  *     or relative to "window"
750  *   "time" specifies the time
751  *
752  * Results:
753  *
754  * Side effects:
755  *   requires a corresponding call to gdk_keyboard_ungrab
756  *
757  *--------------------------------------------------------------
758  */
759
760 gint
761 gdk_keyboard_grab (GdkWindow *     window,
762                    gint            owner_events,
763                    guint32         time)
764 {
765   GdkWindowPrivate *window_private;
766   Window xwindow;
767   
768   g_return_val_if_fail (window != NULL, 0);
769   
770   window_private = (GdkWindowPrivate*) window;
771   xwindow = window_private->xwindow;
772   
773   if (!window_private->destroyed)
774     return XGrabKeyboard (window_private->xdisplay,
775                           xwindow,
776                           owner_events,
777                           GrabModeAsync, GrabModeAsync,
778                           time);
779   else
780     return AlreadyGrabbed;
781 }
782
783 /*
784  *--------------------------------------------------------------
785  * gdk_keyboard_ungrab
786  *
787  *   Releases any keyboard grab
788  *
789  * Arguments:
790  *
791  * Results:
792  *
793  * Side effects:
794  *
795  *--------------------------------------------------------------
796  */
797
798 void
799 gdk_keyboard_ungrab (guint32 time)
800 {
801   XUngrabKeyboard (gdk_display, time);
802 }
803
804 /*
805  *--------------------------------------------------------------
806  * gdk_screen_width
807  *
808  *   Return the width of the screen.
809  *
810  * Arguments:
811  *
812  * Results:
813  *
814  * Side effects:
815  *
816  *--------------------------------------------------------------
817  */
818
819 gint
820 gdk_screen_width (void)
821 {
822   gint return_val;
823   
824   return_val = DisplayWidth (gdk_display, gdk_screen);
825   
826   return return_val;
827 }
828
829 /*
830  *--------------------------------------------------------------
831  * gdk_screen_height
832  *
833  *   Return the height of the screen.
834  *
835  * Arguments:
836  *
837  * Results:
838  *
839  * Side effects:
840  *
841  *--------------------------------------------------------------
842  */
843
844 gint
845 gdk_screen_height (void)
846 {
847   gint return_val;
848   
849   return_val = DisplayHeight (gdk_display, gdk_screen);
850   
851   return return_val;
852 }
853
854 /*
855  *--------------------------------------------------------------
856  * gdk_screen_width_mm
857  *
858  *   Return the width of the screen in millimeters.
859  *
860  * Arguments:
861  *
862  * Results:
863  *
864  * Side effects:
865  *
866  *--------------------------------------------------------------
867  */
868
869 gint
870 gdk_screen_width_mm (void)
871 {
872   gint return_val;
873   
874   return_val = DisplayWidthMM (gdk_display, gdk_screen);
875   
876   return return_val;
877 }
878
879 /*
880  *--------------------------------------------------------------
881  * gdk_screen_height
882  *
883  *   Return the height of the screen in millimeters.
884  *
885  * Arguments:
886  *
887  * Results:
888  *
889  * Side effects:
890  *
891  *--------------------------------------------------------------
892  */
893
894 gint
895 gdk_screen_height_mm (void)
896 {
897   gint return_val;
898   
899   return_val = DisplayHeightMM (gdk_display, gdk_screen);
900   
901   return return_val;
902 }
903
904 /*
905  *--------------------------------------------------------------
906  * gdk_set_sm_client_id
907  *
908  *   Set the SM_CLIENT_ID property on the WM_CLIENT_LEADER window
909  *   so that the window manager can save our state using the
910  *   X11R6 ICCCM session management protocol. A NULL value should 
911  *   be set following disconnection from the session manager to
912  *   remove the SM_CLIENT_ID property.
913  *
914  * Arguments:
915  * 
916  *   "sm_client_id" specifies the client id assigned to us by the
917  *   session manager or NULL to remove the property.
918  *
919  * Results:
920  *
921  * Side effects:
922  *
923  *--------------------------------------------------------------
924  */
925
926 void
927 gdk_set_sm_client_id (const gchar* sm_client_id)
928 {
929   if (sm_client_id && strcmp (sm_client_id, ""))
930     {
931       XChangeProperty (gdk_display, gdk_leader_window,
932                        gdk_atom_intern ("SM_CLIENT_ID", FALSE),
933                        XA_STRING, 8, PropModeReplace,
934                        sm_client_id, strlen(sm_client_id));
935     }
936   else
937      XDeleteProperty (gdk_display, gdk_leader_window,
938                       gdk_atom_intern ("SM_CLIENT_ID", FALSE));
939 }
940
941 void
942 gdk_key_repeat_disable (void)
943 {
944   XAutoRepeatOff (gdk_display);
945 }
946
947 void
948 gdk_key_repeat_restore (void)
949 {
950   if (autorepeat)
951     XAutoRepeatOn (gdk_display);
952   else
953     XAutoRepeatOff (gdk_display);
954 }
955
956
957 void
958 gdk_beep (void)
959 {
960   XBell(gdk_display, 100);
961 }
962
963 /*
964  *--------------------------------------------------------------
965  * gdk_exit_func
966  *
967  *   This is the "atexit" function that makes sure the
968  *   library gets a chance to cleanup.
969  *
970  * Arguments:
971  *
972  * Results:
973  *
974  * Side effects:
975  *   The library is un-initialized and the program exits.
976  *
977  *--------------------------------------------------------------
978  */
979
980 static void
981 gdk_exit_func (void)
982 {
983   static gboolean in_gdk_exit_func = FALSE;
984   
985   /* This is to avoid an infinite loop if a program segfaults in
986      an atexit() handler (and yes, it does happen, especially if a program
987      has trounced over memory too badly for even g_message to work) */
988   if (in_gdk_exit_func == TRUE)
989     return;
990   in_gdk_exit_func = TRUE;
991   
992   if (gdk_initialized)
993     {
994 #ifdef USE_XIM
995       /* cleanup IC */
996       gdk_ic_cleanup ();
997       /* close IM */
998       gdk_im_close ();
999 #endif
1000       gdk_image_exit ();
1001       gdk_input_exit ();
1002       gdk_key_repeat_restore ();
1003       
1004       XCloseDisplay (gdk_display);
1005       gdk_initialized = 0;
1006     }
1007 }
1008
1009 /*
1010  *--------------------------------------------------------------
1011  * gdk_x_error
1012  *
1013  *   The X error handling routine.
1014  *
1015  * Arguments:
1016  *   "display" is the X display the error orignated from.
1017  *   "error" is the XErrorEvent that we are handling.
1018  *
1019  * Results:
1020  *   Either we were expecting some sort of error to occur,
1021  *   in which case we set the "gdk_error_code" flag, or this
1022  *   error was unexpected, in which case we will print an
1023  *   error message and exit. (Since trying to continue will
1024  *   most likely simply lead to more errors).
1025  *
1026  * Side effects:
1027  *
1028  *--------------------------------------------------------------
1029  */
1030
1031 static int
1032 gdk_x_error (Display     *display,
1033              XErrorEvent *error)
1034 {
1035   char buf[64];
1036   
1037   if (gdk_error_warnings)
1038     {
1039       XGetErrorText (display, error->error_code, buf, 63);
1040       g_error ("%s\n  serial %ld error_code %d request_code %d minor_code %d\n", 
1041                buf, 
1042                error->serial, 
1043                error->error_code, 
1044                error->request_code,
1045                error->minor_code);
1046     }
1047   
1048   gdk_error_code = -1;
1049   return 0;
1050 }
1051
1052 /*
1053  *--------------------------------------------------------------
1054  * gdk_x_io_error
1055  *
1056  *   The X I/O error handling routine.
1057  *
1058  * Arguments:
1059  *   "display" is the X display the error orignated from.
1060  *
1061  * Results:
1062  *   An X I/O error basically means we lost our connection
1063  *   to the X server. There is not much we can do to
1064  *   continue, so simply print an error message and exit.
1065  *
1066  * Side effects:
1067  *
1068  *--------------------------------------------------------------
1069  */
1070
1071 static int
1072 gdk_x_io_error (Display *display)
1073 {
1074   g_error ("an x io error occurred");
1075   return 0;
1076 }
1077
1078 gchar *
1079 gdk_get_display (void)
1080 {
1081   return (gchar *)XDisplayName (gdk_display_name);
1082 }
1083
1084 /*************************************************************
1085  * gdk_error_trap_push:
1086  *     Push an error trap. X errors will be trapped until
1087  *     the corresponding gdk_error_pop(), which will return
1088  *     the error code, if any.
1089  *   arguments:
1090  *     
1091  *   results:
1092  *************************************************************/
1093
1094 void
1095 gdk_error_trap_push (void)
1096 {
1097   GSList *node;
1098   GdkErrorTrap *trap;
1099
1100   if (gdk_error_trap_free_list)
1101     {
1102       node = gdk_error_trap_free_list;
1103       gdk_error_trap_free_list = gdk_error_trap_free_list->next;
1104     }
1105   else
1106     {
1107       node = g_slist_alloc();
1108       node->data = g_new (GdkErrorTrap, 1);
1109     }
1110
1111   node->next = gdk_error_traps;
1112   gdk_error_traps = node;
1113   
1114   trap = node->data;
1115   trap->error_code = gdk_error_code;
1116   trap->error_warnings = gdk_error_warnings;
1117
1118   gdk_error_code = 0;
1119   gdk_error_warnings = 0;
1120 }
1121
1122 /*************************************************************
1123  * gdk_error_trap_pop:
1124  *     Pop an error trap added with gdk_error_push()
1125  *   arguments:
1126  *     
1127  *   results:
1128  *     0, if no error occured, otherwise the error code.
1129  *************************************************************/
1130
1131 gint
1132 gdk_error_trap_pop (void)
1133 {
1134   GSList *node;
1135   GdkErrorTrap *trap;
1136   gint result;
1137
1138   g_return_val_if_fail (gdk_error_traps != NULL, 0);
1139
1140   node = gdk_error_traps;
1141   gdk_error_traps = gdk_error_traps->next;
1142
1143   node->next = gdk_error_trap_free_list;
1144   gdk_error_trap_free_list = node;
1145   
1146   result = gdk_error_code;
1147   
1148   trap = node->data;
1149   gdk_error_code = trap->error_code;
1150   gdk_error_warnings = trap->error_warnings;
1151   
1152   return result;
1153 }
1154
1155 gint 
1156 gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
1157                  XEvent *event_send)
1158 {
1159   Status result;
1160   gint old_warnings = gdk_error_warnings;
1161   
1162   gdk_error_code = 0;
1163   
1164   gdk_error_warnings = 0;
1165   result = XSendEvent (gdk_display, window, propagate, event_mask, event_send);
1166   XSync (gdk_display, False);
1167   gdk_error_warnings = old_warnings;
1168   
1169   return result && (gdk_error_code != -1);
1170 }
1171
1172 #ifndef HAVE_XCONVERTCASE
1173 /* compatibility function from X11R6.3, since XConvertCase is not
1174  * supplied by X11R5.
1175  */
1176 static void
1177 gdkx_XConvertCase (KeySym symbol,
1178                    KeySym *lower,
1179                    KeySym *upper)
1180 {
1181   register KeySym sym = symbol;
1182   
1183   g_return_if_fail (lower != NULL);
1184   g_return_if_fail (upper != NULL);
1185   
1186   *lower = sym;
1187   *upper = sym;
1188   
1189   switch (sym >> 8)
1190     {
1191 #if     defined (GDK_A) && defined (GDK_Ooblique)
1192     case 0: /* Latin 1 */
1193       if ((sym >= GDK_A) && (sym <= GDK_Z))
1194         *lower += (GDK_a - GDK_A);
1195       else if ((sym >= GDK_a) && (sym <= GDK_z))
1196         *upper -= (GDK_a - GDK_A);
1197       else if ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis))
1198         *lower += (GDK_agrave - GDK_Agrave);
1199       else if ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis))
1200         *upper -= (GDK_agrave - GDK_Agrave);
1201       else if ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn))
1202         *lower += (GDK_oslash - GDK_Ooblique);
1203       else if ((sym >= GDK_oslash) && (sym <= GDK_thorn))
1204         *upper -= (GDK_oslash - GDK_Ooblique);
1205       break;
1206 #endif  /* LATIN1 */
1207       
1208 #if     defined (GDK_Aogonek) && defined (GDK_tcedilla)
1209     case 1: /* Latin 2 */
1210       /* Assume the KeySym is a legal value (ignore discontinuities) */
1211       if (sym == GDK_Aogonek)
1212         *lower = GDK_aogonek;
1213       else if (sym >= GDK_Lstroke && sym <= GDK_Sacute)
1214         *lower += (GDK_lstroke - GDK_Lstroke);
1215       else if (sym >= GDK_Scaron && sym <= GDK_Zacute)
1216         *lower += (GDK_scaron - GDK_Scaron);
1217       else if (sym >= GDK_Zcaron && sym <= GDK_Zabovedot)
1218         *lower += (GDK_zcaron - GDK_Zcaron);
1219       else if (sym == GDK_aogonek)
1220         *upper = GDK_Aogonek;
1221       else if (sym >= GDK_lstroke && sym <= GDK_sacute)
1222         *upper -= (GDK_lstroke - GDK_Lstroke);
1223       else if (sym >= GDK_scaron && sym <= GDK_zacute)
1224         *upper -= (GDK_scaron - GDK_Scaron);
1225       else if (sym >= GDK_zcaron && sym <= GDK_zabovedot)
1226         *upper -= (GDK_zcaron - GDK_Zcaron);
1227       else if (sym >= GDK_Racute && sym <= GDK_Tcedilla)
1228         *lower += (GDK_racute - GDK_Racute);
1229       else if (sym >= GDK_racute && sym <= GDK_tcedilla)
1230         *upper -= (GDK_racute - GDK_Racute);
1231       break;
1232 #endif  /* LATIN2 */
1233       
1234 #if     defined (GDK_Hstroke) && defined (GDK_Cabovedot)
1235     case 2: /* Latin 3 */
1236       /* Assume the KeySym is a legal value (ignore discontinuities) */
1237       if (sym >= GDK_Hstroke && sym <= GDK_Hcircumflex)
1238         *lower += (GDK_hstroke - GDK_Hstroke);
1239       else if (sym >= GDK_Gbreve && sym <= GDK_Jcircumflex)
1240         *lower += (GDK_gbreve - GDK_Gbreve);
1241       else if (sym >= GDK_hstroke && sym <= GDK_hcircumflex)
1242         *upper -= (GDK_hstroke - GDK_Hstroke);
1243       else if (sym >= GDK_gbreve && sym <= GDK_jcircumflex)
1244         *upper -= (GDK_gbreve - GDK_Gbreve);
1245       else if (sym >= GDK_Cabovedot && sym <= GDK_Scircumflex)
1246         *lower += (GDK_cabovedot - GDK_Cabovedot);
1247       else if (sym >= GDK_cabovedot && sym <= GDK_scircumflex)
1248         *upper -= (GDK_cabovedot - GDK_Cabovedot);
1249       break;
1250 #endif  /* LATIN3 */
1251       
1252 #if     defined (GDK_Rcedilla) && defined (GDK_Amacron)
1253     case 3: /* Latin 4 */
1254       /* Assume the KeySym is a legal value (ignore discontinuities) */
1255       if (sym >= GDK_Rcedilla && sym <= GDK_Tslash)
1256         *lower += (GDK_rcedilla - GDK_Rcedilla);
1257       else if (sym >= GDK_rcedilla && sym <= GDK_tslash)
1258         *upper -= (GDK_rcedilla - GDK_Rcedilla);
1259       else if (sym == GDK_ENG)
1260         *lower = GDK_eng;
1261       else if (sym == GDK_eng)
1262         *upper = GDK_ENG;
1263       else if (sym >= GDK_Amacron && sym <= GDK_Umacron)
1264         *lower += (GDK_amacron - GDK_Amacron);
1265       else if (sym >= GDK_amacron && sym <= GDK_umacron)
1266         *upper -= (GDK_amacron - GDK_Amacron);
1267       break;
1268 #endif  /* LATIN4 */
1269       
1270 #if     defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu)
1271     case 6: /* Cyrillic */
1272       /* Assume the KeySym is a legal value (ignore discontinuities) */
1273       if (sym >= GDK_Serbian_DJE && sym <= GDK_Serbian_DZE)
1274         *lower -= (GDK_Serbian_DJE - GDK_Serbian_dje);
1275       else if (sym >= GDK_Serbian_dje && sym <= GDK_Serbian_dze)
1276         *upper += (GDK_Serbian_DJE - GDK_Serbian_dje);
1277       else if (sym >= GDK_Cyrillic_YU && sym <= GDK_Cyrillic_HARDSIGN)
1278         *lower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
1279       else if (sym >= GDK_Cyrillic_yu && sym <= GDK_Cyrillic_hardsign)
1280         *upper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
1281       break;
1282 #endif  /* CYRILLIC */
1283       
1284 #if     defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma)
1285     case 7: /* Greek */
1286       /* Assume the KeySym is a legal value (ignore discontinuities) */
1287       if (sym >= GDK_Greek_ALPHAaccent && sym <= GDK_Greek_OMEGAaccent)
1288         *lower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
1289       else if (sym >= GDK_Greek_alphaaccent && sym <= GDK_Greek_omegaaccent &&
1290                sym != GDK_Greek_iotaaccentdieresis &&
1291                sym != GDK_Greek_upsilonaccentdieresis)
1292         *upper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
1293       else if (sym >= GDK_Greek_ALPHA && sym <= GDK_Greek_OMEGA)
1294         *lower += (GDK_Greek_alpha - GDK_Greek_ALPHA);
1295       else if (sym >= GDK_Greek_alpha && sym <= GDK_Greek_omega &&
1296                sym != GDK_Greek_finalsmallsigma)
1297         *upper -= (GDK_Greek_alpha - GDK_Greek_ALPHA);
1298       break;
1299 #endif  /* GREEK */
1300     }
1301 }
1302 #endif
1303
1304 gchar*
1305 gdk_keyval_name (guint        keyval)
1306 {
1307   return XKeysymToString (keyval);
1308 }
1309
1310 guint
1311 gdk_keyval_from_name (const gchar *keyval_name)
1312 {
1313   g_return_val_if_fail (keyval_name != NULL, 0);
1314   
1315   return XStringToKeysym (keyval_name);
1316 }
1317
1318 guint
1319 gdk_keyval_to_upper (guint        keyval)
1320 {
1321   if (keyval)
1322     {
1323       KeySym lower_val = 0;
1324       KeySym upper_val = 0;
1325       
1326       XConvertCase (keyval, &lower_val, &upper_val);
1327       return upper_val;
1328     }
1329   return 0;
1330 }
1331
1332 guint
1333 gdk_keyval_to_lower (guint        keyval)
1334 {
1335   if (keyval)
1336     {
1337       KeySym lower_val = 0;
1338       KeySym upper_val = 0;
1339       
1340       XConvertCase (keyval, &lower_val, &upper_val);
1341       return lower_val;
1342     }
1343   return 0;
1344 }
1345
1346 gboolean
1347 gdk_keyval_is_upper (guint        keyval)
1348 {
1349   if (keyval)
1350     {
1351       KeySym lower_val = 0;
1352       KeySym upper_val = 0;
1353       
1354       XConvertCase (keyval, &lower_val, &upper_val);
1355       return upper_val == keyval;
1356     }
1357   return TRUE;
1358 }
1359
1360 gboolean
1361 gdk_keyval_is_lower (guint        keyval)
1362 {
1363   if (keyval)
1364     {
1365       KeySym lower_val = 0;
1366       KeySym upper_val = 0;
1367       
1368       XConvertCase (keyval, &lower_val, &upper_val);
1369       return lower_val == keyval;
1370     }
1371   return TRUE;
1372 }
1373
1374 void
1375 gdk_threads_enter ()
1376 {
1377   GDK_THREADS_ENTER ();
1378 }
1379
1380 void
1381 gdk_threads_leave ()
1382 {
1383   GDK_THREADS_LEAVE ();
1384 }
1385