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