]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkmain-x11.c
de696cca984ddc36a51bcef744b72c869802e3b8
[~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
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 #include <errno.h>
35
36 #ifdef HAVE_SYS_SELECT_H
37 #include <sys/select.h>
38 #endif /* HAVE_SYS_SELECT_H_ */
39
40 #define XLIB_ILLEGAL_ACCESS
41 #include <X11/Xatom.h>
42 #include <X11/Xlib.h>
43 #include <X11/Xos.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xmu/WinUtil.h>
46 #include <X11/cursorfont.h>
47
48 #include "gdk.h"
49
50 #include "gdkx.h"
51 #include "gdkprivate.h"
52 #include "gdkinputprivate.h"
53
54 typedef struct _GdkPredicate  GdkPredicate;
55 typedef struct _GdkErrorTrap  GdkErrorTrap;
56
57 struct _GdkPredicate
58 {
59   GdkEventFunc func;
60   gpointer data;
61 };
62
63 struct _GdkErrorTrap
64 {
65   gint error_warnings;
66   gint error_code;
67 };
68
69 /* 
70  * Private function declarations
71  */
72
73 #ifndef HAVE_XCONVERTCASE
74 static void      gdkx_XConvertCase      (KeySym        symbol,
75                                          KeySym       *lower,
76                                          KeySym       *upper);
77 #define XConvertCase gdkx_XConvertCase
78 #endif
79
80 static int          gdk_x_error                  (Display     *display, 
81                                                   XErrorEvent *error);
82 static int          gdk_x_io_error               (Display     *display);
83
84 /* Private variable declarations
85  */
86 static int gdk_initialized = 0;                     /* 1 if the library is initialized,
87                                                      * 0 otherwise.
88                                                      */
89
90 static gint autorepeat;
91 static gboolean gdk_synchronize = FALSE;
92
93 #ifdef G_ENABLE_DEBUG
94 static const GDebugKey gdk_debug_keys[] = {
95   {"events",        GDK_DEBUG_EVENTS},
96   {"misc",          GDK_DEBUG_MISC},
97   {"dnd",           GDK_DEBUG_DND},
98   {"color-context", GDK_DEBUG_COLOR_CONTEXT},
99   {"xim",           GDK_DEBUG_XIM}
100 };
101
102 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
103
104 #endif /* G_ENABLE_DEBUG */
105
106 static void
107 gdk_arg_xim_preedit_cb (const gchar *arg, const gchar *value, gpointer cb_data)
108 {
109   if (strcmp ("none", value) == 0)
110     gdk_im_set_best_style (GDK_IM_PREEDIT_NONE);
111   else if (strcmp ("nothing", value) == 0)
112     gdk_im_set_best_style (GDK_IM_PREEDIT_NOTHING);
113   else if (strcmp ("area", value) == 0)
114     gdk_im_set_best_style (GDK_IM_PREEDIT_AREA);
115   else if (strcmp ("position", value) == 0)
116     gdk_im_set_best_style (GDK_IM_PREEDIT_POSITION);
117   else if (strcmp ("callbacks", value) == 0)
118     gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS);
119 }
120
121 static void
122 gdk_arg_xim_status_cb (const gchar *arg, const gchar *value, gpointer cb_data)
123 {
124   if (strcmp ("none", value) == 0)
125     gdk_im_set_best_style (GDK_IM_STATUS_NONE);
126   else if (strcmp ("nothing", value) == 0)
127     gdk_im_set_best_style (GDK_IM_STATUS_NOTHING);
128   else if (strcmp ("area", value) == 0)
129     gdk_im_set_best_style (GDK_IM_STATUS_AREA);
130   else if (strcmp ("callbacks", value) == 0)
131     gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS);
132 }
133
134 GdkArgDesc _gdk_windowing_args[] = {
135   { "display",     GDK_ARG_STRING,   &gdk_display_name,    (GdkArgFunc)NULL   },
136   { "sync",        GDK_ARG_BOOL,     &gdk_synchronize,     (GdkArgFunc)NULL   },
137   { "no-xshm",     GDK_ARG_NOBOOL,   &gdk_use_xshm,        (GdkArgFunc)NULL   },
138   { "class",       GDK_ARG_STRING,   &gdk_progclass,       (GdkArgFunc)NULL   },
139   { "gxid-host",   GDK_ARG_STRING,   &gdk_input_gxid_host, (GdkArgFunc)NULL   },
140   { "gxid-port",   GDK_ARG_INT,      &gdk_input_gxid_port, (GdkArgFunc)NULL   },
141   { "xim-preedit", GDK_ARG_CALLBACK, NULL,                 gdk_arg_xim_preedit_cb },
142   { "xim-status",  GDK_ARG_CALLBACK, NULL,                 gdk_arg_xim_status_cb  },
143   { NULL }
144 };
145
146 gboolean
147 _gdk_windowing_init_check (int argc, char **argv)
148 {
149   XKeyboardState keyboard_state;
150   XClassHint *class_hint;
151   
152   XSetErrorHandler (gdk_x_error);
153   XSetIOErrorHandler (gdk_x_io_error);
154   
155   gdk_display = XOpenDisplay (gdk_display_name);
156   if (!gdk_display)
157     return FALSE;
158   
159   if (gdk_synchronize)
160     XSynchronize (gdk_display, True);
161   
162   gdk_screen = DefaultScreen (gdk_display);
163   gdk_root_window = RootWindow (gdk_display, gdk_screen);
164   
165   gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
166                                           10, 10, 10, 10, 0, 0 , 0);
167   class_hint = XAllocClassHint();
168   class_hint->res_name = g_get_prgname ();
169   if (gdk_progclass == NULL)
170     {
171       gdk_progclass = g_strdup (g_get_prgname ());
172       gdk_progclass[0] = toupper (gdk_progclass[0]);
173     }
174   class_hint->res_class = gdk_progclass;
175   XmbSetWMProperties (gdk_display, gdk_leader_window,
176                       NULL, NULL, argv, argc, 
177                       NULL, NULL, class_hint);
178   XFree (class_hint);
179   
180   gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", False);
181   gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", False);
182   gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", False);
183   gdk_wm_window_protocols[0] = gdk_wm_delete_window;
184   gdk_wm_window_protocols[1] = gdk_wm_take_focus;
185   gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
186   
187   XGetKeyboardControl (gdk_display, &keyboard_state);
188   autorepeat = keyboard_state.global_auto_repeat;
189   
190   return TRUE;
191 }
192
193 void
194 gdk_set_use_xshm (gint use_xshm)
195 {
196   gdk_use_xshm = use_xshm;
197 }
198
199 gint
200 gdk_get_use_xshm (void)
201 {
202   return gdk_use_xshm;
203 }
204
205 /*
206  *--------------------------------------------------------------
207  * gdk_pointer_grab
208  *
209  *   Grabs the pointer to a specific window
210  *
211  * Arguments:
212  *   "window" is the window which will receive the grab
213  *   "owner_events" specifies whether events will be reported as is,
214  *     or relative to "window"
215  *   "event_mask" masks only interesting events
216  *   "confine_to" limits the cursor movement to the specified window
217  *   "cursor" changes the cursor for the duration of the grab
218  *   "time" specifies the time
219  *
220  * Results:
221  *
222  * Side effects:
223  *   requires a corresponding call to gdk_pointer_ungrab
224  *
225  *--------------------------------------------------------------
226  */
227
228 gint
229 gdk_pointer_grab (GdkWindow *     window,
230                   gint            owner_events,
231                   GdkEventMask    event_mask,
232                   GdkWindow *     confine_to,
233                   GdkCursor *     cursor,
234                   guint32         time)
235 {
236   gint return_val;
237   GdkCursorPrivate *cursor_private;
238   guint xevent_mask;
239   Window xwindow;
240   Window xconfine_to;
241   Cursor xcursor;
242   int i;
243   
244   g_return_val_if_fail (window != NULL, 0);
245   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
246   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
247   
248   cursor_private = (GdkCursorPrivate*) cursor;
249   
250   xwindow = GDK_DRAWABLE_XID (window);
251   
252   if (!confine_to || GDK_DRAWABLE_DESTROYED (confine_to))
253     xconfine_to = None;
254   else
255     xconfine_to = GDK_DRAWABLE_XID (confine_to);
256   
257   if (!cursor)
258     xcursor = None;
259   else
260     xcursor = cursor_private->xcursor;
261   
262   
263   xevent_mask = 0;
264   for (i = 0; i < gdk_nevent_masks; i++)
265     {
266       if (event_mask & (1 << (i + 1)))
267         xevent_mask |= gdk_event_mask_table[i];
268     }
269   
270   if (gdk_input_vtable.grab_pointer)
271     return_val = gdk_input_vtable.grab_pointer (window,
272                                                 owner_events,
273                                                 event_mask,
274                                                 confine_to,
275                                                 time);
276   else
277     return_val = Success;
278   
279   if (return_val == Success)
280     {
281       if (!GDK_DRAWABLE_DESTROYED (window))
282         return_val = XGrabPointer (GDK_DRAWABLE_XDISPLAY (window),
283                                    xwindow,
284                                    owner_events,
285                                    xevent_mask,
286                                    GrabModeAsync, GrabModeAsync,
287                                    xconfine_to,
288                                    xcursor,
289                                    time);
290       else
291         return_val = AlreadyGrabbed;
292     }
293   
294   if (return_val == GrabSuccess)
295     gdk_xgrab_window = (GdkWindowPrivate *)window;
296   
297   return return_val;
298 }
299
300 /*
301  *--------------------------------------------------------------
302  * gdk_pointer_ungrab
303  *
304  *   Releases any pointer grab
305  *
306  * Arguments:
307  *
308  * Results:
309  *
310  * Side effects:
311  *
312  *--------------------------------------------------------------
313  */
314
315 void
316 gdk_pointer_ungrab (guint32 time)
317 {
318   if (gdk_input_vtable.ungrab_pointer)
319     gdk_input_vtable.ungrab_pointer (time);
320   
321   XUngrabPointer (gdk_display, time);
322   gdk_xgrab_window = NULL;
323 }
324
325 /*
326  *--------------------------------------------------------------
327  * gdk_pointer_is_grabbed
328  *
329  *   Tell wether there is an active x pointer grab in effect
330  *
331  * Arguments:
332  *
333  * Results:
334  *
335  * Side effects:
336  *
337  *--------------------------------------------------------------
338  */
339
340 gint
341 gdk_pointer_is_grabbed (void)
342 {
343   return gdk_xgrab_window != NULL;
344 }
345
346 /*
347  *--------------------------------------------------------------
348  * gdk_keyboard_grab
349  *
350  *   Grabs the keyboard to a specific window
351  *
352  * Arguments:
353  *   "window" is the window which will receive the grab
354  *   "owner_events" specifies whether events will be reported as is,
355  *     or relative to "window"
356  *   "time" specifies the time
357  *
358  * Results:
359  *
360  * Side effects:
361  *   requires a corresponding call to gdk_keyboard_ungrab
362  *
363  *--------------------------------------------------------------
364  */
365
366 gint
367 gdk_keyboard_grab (GdkWindow *     window,
368                    gint            owner_events,
369                    guint32         time)
370 {
371   g_return_val_if_fail (window != NULL, 0);
372   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
373   
374   if (!GDK_DRAWABLE_DESTROYED (window))
375     return XGrabKeyboard (GDK_DRAWABLE_XDISPLAY (window),
376                           GDK_DRAWABLE_XID (window),
377                           owner_events,
378                           GrabModeAsync, GrabModeAsync,
379                           time);
380   else
381     return AlreadyGrabbed;
382 }
383
384 /*
385  *--------------------------------------------------------------
386  * gdk_keyboard_ungrab
387  *
388  *   Releases any keyboard grab
389  *
390  * Arguments:
391  *
392  * Results:
393  *
394  * Side effects:
395  *
396  *--------------------------------------------------------------
397  */
398
399 void
400 gdk_keyboard_ungrab (guint32 time)
401 {
402   XUngrabKeyboard (gdk_display, time);
403 }
404
405 /*
406  *--------------------------------------------------------------
407  * gdk_screen_width
408  *
409  *   Return the width of the screen.
410  *
411  * Arguments:
412  *
413  * Results:
414  *
415  * Side effects:
416  *
417  *--------------------------------------------------------------
418  */
419
420 gint
421 gdk_screen_width (void)
422 {
423   gint return_val;
424   
425   return_val = DisplayWidth (gdk_display, gdk_screen);
426   
427   return return_val;
428 }
429
430 /*
431  *--------------------------------------------------------------
432  * gdk_screen_height
433  *
434  *   Return the height of the screen.
435  *
436  * Arguments:
437  *
438  * Results:
439  *
440  * Side effects:
441  *
442  *--------------------------------------------------------------
443  */
444
445 gint
446 gdk_screen_height (void)
447 {
448   gint return_val;
449   
450   return_val = DisplayHeight (gdk_display, gdk_screen);
451   
452   return return_val;
453 }
454
455 /*
456  *--------------------------------------------------------------
457  * gdk_screen_width_mm
458  *
459  *   Return the width of the screen in millimeters.
460  *
461  * Arguments:
462  *
463  * Results:
464  *
465  * Side effects:
466  *
467  *--------------------------------------------------------------
468  */
469
470 gint
471 gdk_screen_width_mm (void)
472 {
473   gint return_val;
474   
475   return_val = DisplayWidthMM (gdk_display, gdk_screen);
476   
477   return return_val;
478 }
479
480 /*
481  *--------------------------------------------------------------
482  * gdk_screen_height
483  *
484  *   Return the height of the screen in millimeters.
485  *
486  * Arguments:
487  *
488  * Results:
489  *
490  * Side effects:
491  *
492  *--------------------------------------------------------------
493  */
494
495 gint
496 gdk_screen_height_mm (void)
497 {
498   gint return_val;
499   
500   return_val = DisplayHeightMM (gdk_display, gdk_screen);
501   
502   return return_val;
503 }
504
505 /*
506  *--------------------------------------------------------------
507  * gdk_set_sm_client_id
508  *
509  *   Set the SM_CLIENT_ID property on the WM_CLIENT_LEADER window
510  *   so that the window manager can save our state using the
511  *   X11R6 ICCCM session management protocol. A NULL value should 
512  *   be set following disconnection from the session manager to
513  *   remove the SM_CLIENT_ID property.
514  *
515  * Arguments:
516  * 
517  *   "sm_client_id" specifies the client id assigned to us by the
518  *   session manager or NULL to remove the property.
519  *
520  * Results:
521  *
522  * Side effects:
523  *
524  *--------------------------------------------------------------
525  */
526
527 void
528 gdk_set_sm_client_id (const gchar* sm_client_id)
529 {
530   if (sm_client_id && strcmp (sm_client_id, ""))
531     {
532       XChangeProperty (gdk_display, gdk_leader_window,
533                        gdk_atom_intern ("SM_CLIENT_ID", FALSE),
534                        XA_STRING, 8, PropModeReplace,
535                        sm_client_id, strlen(sm_client_id));
536     }
537   else
538      XDeleteProperty (gdk_display, gdk_leader_window,
539                       gdk_atom_intern ("SM_CLIENT_ID", FALSE));
540 }
541
542 void
543 gdk_key_repeat_disable (void)
544 {
545   XAutoRepeatOff (gdk_display);
546 }
547
548 void
549 gdk_key_repeat_restore (void)
550 {
551   if (autorepeat)
552     XAutoRepeatOn (gdk_display);
553   else
554     XAutoRepeatOff (gdk_display);
555 }
556
557
558 void
559 gdk_beep (void)
560 {
561   XBell(gdk_display, 0);
562 }
563
564 void
565 gdk_windowing_exit (void)
566 {
567   XCloseDisplay (gdk_display);
568 }
569
570 /*
571  *--------------------------------------------------------------
572  * gdk_x_error
573  *
574  *   The X error handling routine.
575  *
576  * Arguments:
577  *   "display" is the X display the error orignated from.
578  *   "error" is the XErrorEvent that we are handling.
579  *
580  * Results:
581  *   Either we were expecting some sort of error to occur,
582  *   in which case we set the "gdk_error_code" flag, or this
583  *   error was unexpected, in which case we will print an
584  *   error message and exit. (Since trying to continue will
585  *   most likely simply lead to more errors).
586  *
587  * Side effects:
588  *
589  *--------------------------------------------------------------
590  */
591
592 static int
593 gdk_x_error (Display     *display,
594              XErrorEvent *error)
595 {
596   if (error->error_code)
597     {
598       if (gdk_error_warnings)
599         {
600           char buf[64];
601           
602           XGetErrorText (display, error->error_code, buf, 63);
603
604 #ifdef G_ENABLE_DEBUG     
605           g_error ("%s\n  serial %ld error_code %d request_code %d minor_code %d\n", 
606                    buf, 
607                    error->serial, 
608                    error->error_code, 
609                    error->request_code,
610                    error->minor_code);
611 #else /* !G_ENABLE_DEBUG */
612           fprintf (stderr, "Gdk-ERROR **: %s\n  serial %ld error_code %d request_code %d minor_code %d\n",
613                    buf, 
614                    error->serial, 
615                    error->error_code, 
616                    error->request_code,
617                    error->minor_code);
618
619           exit(1);
620 #endif /* G_ENABLE_DEBUG */
621         }
622       gdk_error_code = error->error_code;
623     }
624   
625   return 0;
626 }
627
628 /*
629  *--------------------------------------------------------------
630  * gdk_x_io_error
631  *
632  *   The X I/O error handling routine.
633  *
634  * Arguments:
635  *   "display" is the X display the error orignated from.
636  *
637  * Results:
638  *   An X I/O error basically means we lost our connection
639  *   to the X server. There is not much we can do to
640  *   continue, so simply print an error message and exit.
641  *
642  * Side effects:
643  *
644  *--------------------------------------------------------------
645  */
646
647 static int
648 gdk_x_io_error (Display *display)
649 {
650   /* This is basically modelled after the code in XLib. We need
651    * an explicit error handler here, so we can disable our atexit()
652    * which would otherwise cause a nice segfault.
653    * We fprintf(stderr, instead of g_warning() because g_warning()
654    * could possibly be redirected to a dialog
655    */
656   if (errno == EPIPE)
657     {
658       fprintf (stderr, "Gdk-ERROR **: X connection to %s broken (explicit kill or server shutdown).\n", gdk_display ? DisplayString (gdk_display) : gdk_get_display());
659     }
660   else
661     {
662       fprintf (stderr, "Gdk-ERROR **: Fatal IO error %d (%s) on X server %s.\n",
663                errno, g_strerror (errno),
664                gdk_display ? DisplayString (gdk_display) : gdk_get_display());
665     }
666
667   /* Disable the atexit shutdown for GDK */
668   gdk_initialized = 0;
669   
670   exit(1);
671 }
672
673 gchar *
674 gdk_get_display (void)
675 {
676   return (gchar *)XDisplayName (gdk_display_name);
677 }
678
679 gint 
680 gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
681                  XEvent *event_send)
682 {
683   Status result;
684   gint old_warnings = gdk_error_warnings;
685   
686   gdk_error_code = 0;
687   
688   gdk_error_warnings = 0;
689   result = XSendEvent (gdk_display, window, propagate, event_mask, event_send);
690   XSync (gdk_display, False);
691   gdk_error_warnings = old_warnings;
692   
693   return result && !gdk_error_code;
694 }
695
696 gchar*
697 gdk_keyval_name (guint        keyval)
698 {
699   return XKeysymToString (keyval);
700 }
701
702 guint
703 gdk_keyval_from_name (const gchar *keyval_name)
704 {
705   g_return_val_if_fail (keyval_name != NULL, 0);
706   
707   return XStringToKeysym (keyval_name);
708 }
709
710 #ifdef HAVE_XCONVERTCASE
711 void
712 gdk_keyval_convert_case (guint symbol,
713                          guint *lower,
714                          guint *upper)
715 {
716   KeySym xlower = 0;
717   KeySym xupper = 0;
718
719   if (symbol)
720     XConvertCase (symbol, &xlower, &xupper);
721
722   if (lower)
723     *lower = xlower;
724   if (upper)
725     *upper = xupper;
726 }  
727 #endif HAVE_XCONVERTCASE