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