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