]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdisplay-x11.c
Merge branch 'bgo593793-filechooser-recent-folders-master'
[~andy/gtk] / gdk / x11 / gdkdisplay-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * gdkdisplay-x11.c
3  * 
4  * Copyright 2001 Sun Microsystems Inc.
5  * Copyright (C) 2004 Nokia Corporation
6  *
7  * Erwann Chenede <erwann.chenede@sun.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "config.h"
26
27 #include "gdkasync.h"
28 #include "gdkdisplay.h"
29 #include "gdkeventsource.h"
30 #include "gdkeventtranslator.h"
31 #include "gdkinternals.h"
32 #include "gdkscreen.h"
33 #include "gdkinternals.h"
34 #include "gdkdeviceprivate.h"
35 #include "gdkkeysprivate.h"
36 #include "gdkdevicemanager.h"
37 #include "xsettings-client.h"
38 #include "gdkdisplay-x11.h"
39 #include "gdkprivate-x11.h"
40 #include "gdkscreen-x11.h"
41
42 #include <glib.h>
43 #include <glib/gprintf.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <unistd.h>
48
49 #include <X11/Xatom.h>
50
51 #ifdef HAVE_XKB
52 #include <X11/XKBlib.h>
53 #endif
54
55 #ifdef HAVE_XFIXES
56 #include <X11/extensions/Xfixes.h>
57 #endif
58
59 #include <X11/extensions/shape.h>
60
61 #ifdef HAVE_XCOMPOSITE
62 #include <X11/extensions/Xcomposite.h>
63 #endif
64
65 #ifdef HAVE_XDAMAGE
66 #include <X11/extensions/Xdamage.h>
67 #endif
68
69 #ifdef HAVE_RANDR
70 #include <X11/extensions/Xrandr.h>
71 #endif
72
73 typedef struct _GdkErrorTrap  GdkErrorTrap;
74
75 struct _GdkErrorTrap
76 {
77   /* Next sequence when trap was pushed, i.e. first sequence to
78    * ignore
79    */
80   gulong start_sequence;
81
82   /* Next sequence when trap was popped, i.e. first sequence
83    * to not ignore. 0 if trap is still active.
84    */
85   gulong end_sequence;
86
87   /* Most recent error code within the sequence */
88   int error_code;
89 };
90
91 static void   gdk_x11_display_dispose            (GObject            *object);
92 static void   gdk_x11_display_finalize           (GObject            *object);
93
94 static void     gdk_x11_display_event_translator_init (GdkEventTranslatorIface *iface);
95
96 static gboolean gdk_x11_display_translate_event (GdkEventTranslator *translator,
97                                                  GdkDisplay         *display,
98                                                  GdkEvent           *event,
99                                                  XEvent             *xevent);
100
101 #ifdef HAVE_X11R6
102 static void gdk_internal_connection_watch (Display  *display,
103                                            XPointer  arg,
104                                            gint      fd,
105                                            gboolean  opening,
106                                            XPointer *watch_data);
107 #endif /* HAVE_X11R6 */
108
109 typedef struct _GdkEventTypeX11 GdkEventTypeX11;
110
111 struct _GdkEventTypeX11
112 {
113   gint base;
114   gint n_events;
115 };
116
117 /* Note that we never *directly* use WM_LOCALE_NAME, WM_PROTOCOLS,
118  * but including them here has the side-effect of getting them
119  * into the internal Xlib cache
120  */
121 static const char *const precache_atoms[] = {
122   "UTF8_STRING",
123   "WM_CLIENT_LEADER",
124   "WM_DELETE_WINDOW",
125   "WM_ICON_NAME",
126   "WM_LOCALE_NAME",
127   "WM_NAME",
128   "WM_PROTOCOLS",
129   "WM_TAKE_FOCUS",
130   "WM_WINDOW_ROLE",
131   "_NET_ACTIVE_WINDOW",
132   "_NET_CURRENT_DESKTOP",
133   "_NET_FRAME_EXTENTS",
134   "_NET_STARTUP_ID",
135   "_NET_WM_CM_S0",
136   "_NET_WM_DESKTOP",
137   "_NET_WM_ICON",
138   "_NET_WM_ICON_NAME",
139   "_NET_WM_NAME",
140   "_NET_WM_PID",
141   "_NET_WM_PING",
142   "_NET_WM_STATE",
143   "_NET_WM_STATE_ABOVE",
144   "_NET_WM_STATE_BELOW",
145   "_NET_WM_STATE_FULLSCREEN",
146   "_NET_WM_STATE_MODAL",
147   "_NET_WM_STATE_MAXIMIZED_VERT",
148   "_NET_WM_STATE_MAXIMIZED_HORZ",
149   "_NET_WM_STATE_SKIP_TASKBAR",
150   "_NET_WM_STATE_SKIP_PAGER",
151   "_NET_WM_STATE_STICKY",
152   "_NET_WM_SYNC_REQUEST",
153   "_NET_WM_SYNC_REQUEST_COUNTER",
154   "_NET_WM_WINDOW_TYPE",
155   "_NET_WM_WINDOW_TYPE_NORMAL",
156   "_NET_WM_USER_TIME",
157   "_NET_VIRTUAL_ROOTS",
158   "GDK_SELECTION"
159 };
160
161 static char *gdk_sm_client_id;
162
163 G_DEFINE_TYPE_WITH_CODE (GdkX11Display, gdk_x11_display, GDK_TYPE_DISPLAY,
164                          G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
165                                                 gdk_x11_display_event_translator_init))
166
167
168 static void
169 gdk_x11_display_init (GdkX11Display *display)
170 {
171   _gdk_x11_display_manager_add_display (gdk_display_manager_get (),
172                                         GDK_DISPLAY (display));
173 }
174
175 static void
176 gdk_x11_display_event_translator_init (GdkEventTranslatorIface *iface)
177 {
178   iface->translate_event = gdk_x11_display_translate_event;
179 }
180
181 static void
182 do_net_wm_state_changes (GdkWindow *window)
183 {
184   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
185   GdkWindowState old_state;
186
187   if (GDK_WINDOW_DESTROYED (window) ||
188       gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
189     return;
190
191   old_state = gdk_window_get_state (window);
192
193   /* For found_sticky to remain TRUE, we have to also be on desktop
194    * 0xFFFFFFFF
195    */
196   if (old_state & GDK_WINDOW_STATE_STICKY)
197     {
198       if (!(toplevel->have_sticky && toplevel->on_all_desktops))
199         gdk_synthesize_window_state (window,
200                                      GDK_WINDOW_STATE_STICKY,
201                                      0);
202     }
203   else
204     {
205       if (toplevel->have_sticky || toplevel->on_all_desktops)
206         gdk_synthesize_window_state (window,
207                                      0,
208                                      GDK_WINDOW_STATE_STICKY);
209     }
210
211   if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
212     {
213       if (!toplevel->have_fullscreen)
214         gdk_synthesize_window_state (window,
215                                      GDK_WINDOW_STATE_FULLSCREEN,
216                                      0);
217     }
218   else
219     {
220       if (toplevel->have_fullscreen)
221         gdk_synthesize_window_state (window,
222                                      0,
223                                      GDK_WINDOW_STATE_FULLSCREEN);
224     }
225
226   /* Our "maximized" means both vertical and horizontal; if only one,
227    * we don't expose that via GDK
228    */
229   if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
230     {
231       if (!(toplevel->have_maxvert && toplevel->have_maxhorz))
232         gdk_synthesize_window_state (window,
233                                      GDK_WINDOW_STATE_MAXIMIZED,
234                                      0);
235     }
236   else
237     {
238       if (toplevel->have_maxvert && toplevel->have_maxhorz)
239         gdk_synthesize_window_state (window,
240                                      0,
241                                      GDK_WINDOW_STATE_MAXIMIZED);
242     }
243 }
244
245 static void
246 gdk_check_wm_desktop_changed (GdkWindow *window)
247 {
248   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
249   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
250
251   Atom type;
252   gint format;
253   gulong nitems;
254   gulong bytes_after;
255   guchar *data;
256   gulong *desktop;
257
258   type = None;
259   gdk_x11_display_error_trap_push (display);
260   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
261                       GDK_WINDOW_XID (window),
262                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
263                       0, G_MAXLONG, False, XA_CARDINAL, &type,
264                       &format, &nitems,
265                       &bytes_after, &data);
266   gdk_x11_display_error_trap_pop_ignored (display);
267
268   if (type != None)
269     {
270       desktop = (gulong *)data;
271       toplevel->on_all_desktops = (*desktop == 0xFFFFFFFF);
272       XFree (desktop);
273     }
274   else
275     toplevel->on_all_desktops = FALSE;
276
277   do_net_wm_state_changes (window);
278 }
279
280 static void
281 gdk_check_wm_state_changed (GdkWindow *window)
282 {
283   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
284   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
285
286   Atom type;
287   gint format;
288   gulong nitems;
289   gulong bytes_after;
290   guchar *data;
291   Atom *atoms = NULL;
292   gulong i;
293
294   gboolean had_sticky = toplevel->have_sticky;
295
296   toplevel->have_sticky = FALSE;
297   toplevel->have_maxvert = FALSE;
298   toplevel->have_maxhorz = FALSE;
299   toplevel->have_fullscreen = FALSE;
300
301   type = None;
302   gdk_x11_display_error_trap_push (display);
303   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
304                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
305                       0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
306                       &bytes_after, &data);
307   gdk_x11_display_error_trap_pop_ignored (display);
308
309   if (type != None)
310     {
311       Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
312       Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
313       Atom maxhorz_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
314       Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
315
316       atoms = (Atom *)data;
317
318       i = 0;
319       while (i < nitems)
320         {
321           if (atoms[i] == sticky_atom)
322             toplevel->have_sticky = TRUE;
323           else if (atoms[i] == maxvert_atom)
324             toplevel->have_maxvert = TRUE;
325           else if (atoms[i] == maxhorz_atom)
326             toplevel->have_maxhorz = TRUE;
327           else if (atoms[i] == fullscreen_atom)
328             toplevel->have_fullscreen = TRUE;
329
330           ++i;
331         }
332
333       XFree (atoms);
334     }
335
336   /* When have_sticky is turned on, we have to check the DESKTOP property
337    * as well.
338    */
339   if (toplevel->have_sticky && !had_sticky)
340     gdk_check_wm_desktop_changed (window);
341   else
342     do_net_wm_state_changes (window);
343 }
344
345 static GdkWindow *
346 get_event_window (GdkEventTranslator *translator,
347                   XEvent             *xevent)
348 {
349   GdkDisplay *display;
350   Window xwindow;
351
352   display = (GdkDisplay *) translator;
353
354   switch (xevent->type)
355     {
356     case DestroyNotify:
357       xwindow = xevent->xdestroywindow.window;
358       break;
359     case UnmapNotify:
360       xwindow = xevent->xunmap.window;
361       break;
362     case MapNotify:
363       xwindow = xevent->xmap.window;
364       break;
365     case ConfigureNotify:
366       xwindow = xevent->xconfigure.window;
367       break;
368     default:
369       xwindow = xevent->xany.window;
370     }
371
372   return gdk_x11_window_lookup_for_display (display, xwindow);
373 }
374
375 static gboolean
376 gdk_x11_display_translate_event (GdkEventTranslator *translator,
377                                  GdkDisplay         *display,
378                                  GdkEvent           *event,
379                                  XEvent             *xevent)
380 {
381   GdkWindow *window;
382   GdkWindowImplX11 *window_impl = NULL;
383   GdkScreen *screen = NULL;
384   GdkX11Screen *x11_screen = NULL;
385   GdkToplevelX11 *toplevel = NULL;
386   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
387   gboolean return_val;
388   Window xwindow = None;
389
390   /* Find the GdkWindow that this event relates to.
391    * Basically this means substructure events
392    * are reported same as structure events
393    */
394   window = get_event_window (translator, xevent);
395
396   if (window)
397     {
398       /* We may receive events such as NoExpose/GraphicsExpose
399        * and ShmCompletion for pixmaps
400        */
401       if (!GDK_IS_WINDOW (window))
402         return FALSE;
403
404       screen = GDK_WINDOW_SCREEN (window);
405       x11_screen = GDK_X11_SCREEN (screen);
406       toplevel = _gdk_x11_window_get_toplevel (window);
407       window_impl = GDK_WINDOW_IMPL_X11 (window->impl);
408       xwindow = GDK_WINDOW_XID (window);
409
410       g_object_ref (window);
411     }
412
413   event->any.window = window;
414   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
415
416   if (window && GDK_WINDOW_DESTROYED (window))
417     {
418       if (xevent->type != DestroyNotify)
419         {
420           return_val = FALSE;
421           goto done;
422         }
423     }
424
425   if (xevent->type == DestroyNotify)
426     {
427       int i, n;
428
429       n = gdk_display_get_n_screens (display);
430       for (i = 0; i < n; i++)
431         {
432           screen = gdk_display_get_screen (display, i);
433           x11_screen = GDK_X11_SCREEN (screen);
434
435           if (x11_screen->wmspec_check_window == xwindow)
436             {
437               x11_screen->wmspec_check_window = None;
438               x11_screen->last_wmspec_check_time = 0;
439               g_free (x11_screen->window_manager_name);
440               x11_screen->window_manager_name = g_strdup ("unknown");
441
442               /* careful, reentrancy */
443               _gdk_x11_screen_window_manager_changed (screen);
444
445               return_val = FALSE;
446               goto done;
447             }
448         }
449     }
450
451   /* We do a "manual" conversion of the XEvent to a
452    *  GdkEvent. The structures are mostly the same so
453    *  the conversion is fairly straightforward. We also
454    *  optionally print debugging info regarding events
455    *  received.
456    */
457
458   return_val = TRUE;
459
460   switch (xevent->type)
461     {
462     case KeymapNotify:
463       GDK_NOTE (EVENTS,
464                 g_message ("keymap notify"));
465
466       /* Not currently handled */
467       return_val = FALSE;
468       break;
469
470     case Expose:
471       GDK_NOTE (EVENTS,
472                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
473                            xevent->xexpose.window, xevent->xexpose.count,
474                            xevent->xexpose.x, xevent->xexpose.y,
475                            xevent->xexpose.width, xevent->xexpose.height,
476                            event->any.send_event ? " (send)" : ""));
477
478       if (window == NULL)
479         {
480           return_val = FALSE;
481           break;
482         }
483
484       {
485         GdkRectangle expose_rect;
486
487         expose_rect.x = xevent->xexpose.x;
488         expose_rect.y = xevent->xexpose.y;
489         expose_rect.width = xevent->xexpose.width;
490         expose_rect.height = xevent->xexpose.height;
491
492         _gdk_x11_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
493         return_val = FALSE;
494       }
495
496       break;
497
498     case GraphicsExpose:
499       {
500         GdkRectangle expose_rect;
501
502         GDK_NOTE (EVENTS,
503                   g_message ("graphics expose:\tdrawable: %ld",
504                              xevent->xgraphicsexpose.drawable));
505
506         if (window == NULL)
507           {
508             return_val = FALSE;
509             break;
510           }
511
512         expose_rect.x = xevent->xgraphicsexpose.x;
513         expose_rect.y = xevent->xgraphicsexpose.y;
514         expose_rect.width = xevent->xgraphicsexpose.width;
515         expose_rect.height = xevent->xgraphicsexpose.height;
516
517         _gdk_x11_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
518         return_val = FALSE;
519       }
520       break;
521
522     case VisibilityNotify:
523 #ifdef G_ENABLE_DEBUG
524       if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
525         switch (xevent->xvisibility.state)
526           {
527           case VisibilityFullyObscured:
528             g_message ("visibility notify:\twindow: %ld  none",
529                        xevent->xvisibility.window);
530             break;
531           case VisibilityPartiallyObscured:
532             g_message ("visibility notify:\twindow: %ld  partial",
533                        xevent->xvisibility.window);
534             break;
535           case VisibilityUnobscured:
536             g_message ("visibility notify:\twindow: %ld  full",
537                        xevent->xvisibility.window);
538             break;
539           }
540 #endif /* G_ENABLE_DEBUG */
541
542       if (window == NULL)
543         {
544           return_val = FALSE;
545           break;
546         }
547
548       event->visibility.type = GDK_VISIBILITY_NOTIFY;
549       event->visibility.window = window;
550
551       switch (xevent->xvisibility.state)
552         {
553         case VisibilityFullyObscured:
554           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
555           break;
556
557         case VisibilityPartiallyObscured:
558           event->visibility.state = GDK_VISIBILITY_PARTIAL;
559           break;
560
561         case VisibilityUnobscured:
562           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
563           break;
564         }
565
566       break;
567
568     case CreateNotify:
569       GDK_NOTE (EVENTS,
570                 g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
571                            xevent->xcreatewindow.window,
572                            xevent->xcreatewindow.x,
573                            xevent->xcreatewindow.y,
574                            xevent->xcreatewindow.width,
575                            xevent->xcreatewindow.height,
576                            xevent->xcreatewindow.border_width,
577                            xevent->xcreatewindow.parent,
578                            xevent->xcreatewindow.override_redirect));
579       /* not really handled */
580       break;
581
582     case DestroyNotify:
583       GDK_NOTE (EVENTS,
584                 g_message ("destroy notify:\twindow: %ld",
585                            xevent->xdestroywindow.window));
586
587       /* Ignore DestroyNotify from SubstructureNotifyMask */
588       if (xevent->xdestroywindow.window == xevent->xdestroywindow.event)
589         {
590           event->any.type = GDK_DESTROY;
591           event->any.window = window;
592
593           return_val = window && !GDK_WINDOW_DESTROYED (window);
594
595           if (window && GDK_WINDOW_XID (window) != x11_screen->xroot_window)
596             gdk_window_destroy_notify (window);
597         }
598       else
599         return_val = FALSE;
600
601       break;
602
603     case UnmapNotify:
604       GDK_NOTE (EVENTS,
605                 g_message ("unmap notify:\t\twindow: %ld",
606                            xevent->xmap.window));
607
608       event->any.type = GDK_UNMAP;
609       event->any.window = window;
610
611       /* If we are shown (not withdrawn) and get an unmap, it means we
612        * were iconified in the X sense. If we are withdrawn, and get
613        * an unmap, it means we hid the window ourselves, so we
614        * will have already flipped the iconified bit off.
615        */
616       if (window)
617         {
618           if (GDK_WINDOW_IS_MAPPED (window))
619             gdk_synthesize_window_state (window,
620                                          0,
621                                          GDK_WINDOW_STATE_ICONIFIED);
622
623           _gdk_x11_window_grab_check_unmap (window, xevent->xany.serial);
624         }
625
626       break;
627
628     case MapNotify:
629       GDK_NOTE (EVENTS,
630                 g_message ("map notify:\t\twindow: %ld",
631                            xevent->xmap.window));
632
633       event->any.type = GDK_MAP;
634       event->any.window = window;
635
636       /* Unset iconified if it was set */
637       if (window && (window->state & GDK_WINDOW_STATE_ICONIFIED))
638         gdk_synthesize_window_state (window,
639                                      GDK_WINDOW_STATE_ICONIFIED,
640                                      0);
641
642       break;
643
644     case ReparentNotify:
645       GDK_NOTE (EVENTS,
646                 g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
647                            xevent->xreparent.window,
648                            xevent->xreparent.x,
649                            xevent->xreparent.y,
650                            xevent->xreparent.parent,
651                            xevent->xreparent.override_redirect));
652
653       /* Not currently handled */
654       return_val = FALSE;
655       break;
656
657     case ConfigureNotify:
658       GDK_NOTE (EVENTS,
659                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
660                            xevent->xconfigure.window,
661                            xevent->xconfigure.x,
662                            xevent->xconfigure.y,
663                            xevent->xconfigure.width,
664                            xevent->xconfigure.height,
665                            xevent->xconfigure.border_width,
666                            xevent->xconfigure.above,
667                            xevent->xconfigure.override_redirect,
668                            !window
669                            ? " (discarding)"
670                            : window->window_type == GDK_WINDOW_CHILD
671                            ? " (discarding child)"
672                            : xevent->xconfigure.event != xevent->xconfigure.window
673                            ? " (discarding substructure)"
674                            : ""));
675       if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
676         {
677           window->width = xevent->xconfigure.width;
678           window->height = xevent->xconfigure.height;
679
680           _gdk_window_update_size (window);
681           _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
682           _gdk_x11_screen_size_changed (screen, xevent);
683         }
684
685 #ifdef HAVE_XSYNC
686       if (toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value))
687         {
688           toplevel->current_counter_value = toplevel->pending_counter_value;
689           XSyncIntToValue (&toplevel->pending_counter_value, 0);
690         }
691 #endif
692
693     if (!window ||
694           xevent->xconfigure.event != xevent->xconfigure.window ||
695           GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
696           GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
697         return_val = FALSE;
698       else
699         {
700           event->configure.type = GDK_CONFIGURE;
701           event->configure.window = window;
702           event->configure.width = xevent->xconfigure.width;
703           event->configure.height = xevent->xconfigure.height;
704
705           if (!xevent->xconfigure.send_event &&
706               !xevent->xconfigure.override_redirect &&
707               !GDK_WINDOW_DESTROYED (window))
708             {
709               gint tx = 0;
710               gint ty = 0;
711               Window child_window = 0;
712
713               gdk_x11_display_error_trap_push (display);
714               if (XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
715                                          GDK_WINDOW_XID (window),
716                                          x11_screen->xroot_window,
717                                          0, 0,
718                                          &tx, &ty,
719                                          &child_window))
720                 {
721                   event->configure.x = tx;
722                   event->configure.y = ty;
723                 }
724               gdk_x11_display_error_trap_pop_ignored (display);
725             }
726           else
727             {
728               event->configure.x = xevent->xconfigure.x;
729               event->configure.y = xevent->xconfigure.y;
730             }
731           window->x = event->configure.x;
732           window->y = event->configure.y;
733           window->width = xevent->xconfigure.width;
734           window->height = xevent->xconfigure.height;
735
736           _gdk_window_update_size (window);
737           _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
738
739           if (window->resize_count >= 1)
740             {
741               window->resize_count -= 1;
742
743               if (window->resize_count == 0)
744                 _gdk_x11_moveresize_configure_done (display, window);
745             }
746         }
747       break;
748
749     case PropertyNotify:
750       GDK_NOTE (EVENTS,
751                 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
752                            xevent->xproperty.window,
753                            xevent->xproperty.atom,
754                            "\"",
755                            gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
756                            "\""));
757
758       if (window == NULL)
759         {
760           return_val = FALSE;
761           break;
762         }
763
764       /* We compare with the serial of the last time we mapped the
765        * window to avoid refetching properties that we set ourselves
766        */
767       if (toplevel &&
768           xevent->xproperty.serial >= toplevel->map_serial)
769         {
770           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
771             gdk_check_wm_state_changed (window);
772
773           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
774             gdk_check_wm_desktop_changed (window);
775         }
776
777       if (window->event_mask & GDK_PROPERTY_CHANGE_MASK)
778         {
779           event->property.type = GDK_PROPERTY_NOTIFY;
780           event->property.window = window;
781           event->property.atom = gdk_x11_xatom_to_atom_for_display (display, xevent->xproperty.atom);
782           event->property.time = xevent->xproperty.time;
783           event->property.state = xevent->xproperty.state;
784         }
785       else
786         return_val = FALSE;
787
788       break;
789
790     case SelectionClear:
791       GDK_NOTE (EVENTS,
792                 g_message ("selection clear:\twindow: %ld",
793                            xevent->xproperty.window));
794
795       if (_gdk_x11_selection_filter_clear_event (&xevent->xselectionclear))
796         {
797           event->selection.type = GDK_SELECTION_CLEAR;
798           event->selection.window = window;
799           event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection);
800           event->selection.time = xevent->xselectionclear.time;
801         }
802       else
803         return_val = FALSE;
804
805       break;
806
807     case SelectionRequest:
808       GDK_NOTE (EVENTS,
809                 g_message ("selection request:\twindow: %ld",
810                            xevent->xproperty.window));
811
812       event->selection.type = GDK_SELECTION_REQUEST;
813       event->selection.window = window;
814       event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
815       event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
816       event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
817       if (xevent->xselectionrequest.requestor != None)
818         event->selection.requestor = gdk_x11_window_foreign_new_for_display (display,
819                                                                              xevent->xselectionrequest.requestor);
820       else
821         event->selection.requestor = NULL;
822       event->selection.time = xevent->xselectionrequest.time;
823
824       break;
825
826     case SelectionNotify:
827       GDK_NOTE (EVENTS,
828                 g_message ("selection notify:\twindow: %ld",
829                            xevent->xproperty.window));
830
831       event->selection.type = GDK_SELECTION_NOTIFY;
832       event->selection.window = window;
833       event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
834       event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
835       if (xevent->xselection.property == None)
836         event->selection.property = GDK_NONE;
837       else
838         event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
839       event->selection.time = xevent->xselection.time;
840
841       break;
842
843     case ColormapNotify:
844       GDK_NOTE (EVENTS,
845                 g_message ("colormap notify:\twindow: %ld",
846                            xevent->xcolormap.window));
847
848       /* Not currently handled */
849       return_val = FALSE;
850       break;
851
852     case ClientMessage:
853       GDK_NOTE (EVENTS,
854                 g_message ("client message:\twindow: %ld",
855                            xevent->xclient.window));
856
857       /* Not currently handled */
858       return_val = FALSE;
859       break;
860
861     case MappingNotify:
862       GDK_NOTE (EVENTS,
863                 g_message ("mapping notify"));
864
865       /* Let XLib know that there is a new keyboard mapping.
866        */
867       XRefreshKeyboardMapping (&xevent->xmapping);
868       _gdk_x11_keymap_keys_changed (display);
869       return_val = FALSE;
870       break;
871
872     default:
873 #ifdef HAVE_XFIXES
874       if (xevent->type - display_x11->xfixes_event_base == XFixesSelectionNotify)
875         {
876           XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent;
877
878           _gdk_x11_screen_process_owner_change (screen, xevent);
879           
880           event->owner_change.type = GDK_OWNER_CHANGE;
881           event->owner_change.window = window;
882           if (selection_notify->owner != None)
883             event->owner_change.owner = gdk_x11_window_foreign_new_for_display (display,
884                                                                                 selection_notify->owner);
885           else
886             event->owner_change.owner = NULL;
887           event->owner_change.reason = selection_notify->subtype;
888           event->owner_change.selection = 
889             gdk_x11_xatom_to_atom_for_display (display, 
890                                                selection_notify->selection);
891           event->owner_change.time = selection_notify->timestamp;
892           event->owner_change.selection_time = selection_notify->selection_timestamp;
893           
894           return_val = TRUE;
895         }
896       else
897 #endif
898 #ifdef HAVE_RANDR
899       if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
900           xevent->type - display_x11->xrandr_event_base == RRNotify)
901         {
902           if (screen)
903             _gdk_x11_screen_size_changed (screen, xevent);
904         }
905       else
906 #endif
907 #if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
908       if (display_x11->have_xdamage && window && window->composited &&
909           xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
910           ((XDamageNotifyEvent *) xevent)->damage == window_impl->damage)
911         {
912           XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
913           XserverRegion repair;
914           GdkRectangle rect;
915
916           rect.x = window->x + damage_event->area.x;
917           rect.y = window->y + damage_event->area.y;
918           rect.width = damage_event->area.width;
919           rect.height = damage_event->area.height;
920
921           repair = XFixesCreateRegion (display_x11->xdisplay,
922                                        &damage_event->area, 1);
923           XDamageSubtract (display_x11->xdisplay,
924                            window_impl->damage,
925                            repair, None);
926           XFixesDestroyRegion (display_x11->xdisplay, repair);
927
928           if (window->parent != NULL)
929            _gdk_x11_window_process_expose (window->parent,
930                                            damage_event->serial, &rect);
931
932           return_val = TRUE;
933         }
934       else
935 #endif
936 #ifdef HAVE_XKB
937       if (xevent->type == display_x11->xkb_event_type)
938         {
939           XkbEvent *xkb_event = (XkbEvent *) xevent;
940
941           switch (xkb_event->any.xkb_type)
942             {
943             case XkbNewKeyboardNotify:
944             case XkbMapNotify:
945               _gdk_x11_keymap_keys_changed (display);
946
947               return_val = FALSE;
948               break;
949
950             case XkbStateNotify:
951               _gdk_x11_keymap_state_changed (display, xevent);
952               break;
953             }
954         }
955       else
956 #endif
957         return_val = FALSE;
958     }
959
960  done:
961   if (return_val)
962     {
963       if (event->any.window)
964         g_object_ref (event->any.window);
965     }
966   else
967     {
968       /* Mark this event as having no resources to be freed */
969       event->any.window = NULL;
970       event->any.type = GDK_NOTHING;
971     }
972
973   if (window)
974     g_object_unref (window);
975
976   return return_val;
977 }
978
979 GdkFilterReturn
980 _gdk_wm_protocols_filter (GdkXEvent *xev,
981                           GdkEvent  *event,
982                           gpointer   data)
983 {
984   XEvent *xevent = (XEvent *)xev;
985   GdkWindow *win = event->any.window;
986   GdkDisplay *display;
987   Atom atom;
988
989   if (!GDK_IS_X11_WINDOW (win))
990     return GDK_FILTER_CONTINUE;
991
992   if (xevent->type != ClientMessage)
993     return GDK_FILTER_CONTINUE;
994
995   display = GDK_WINDOW_DISPLAY (win);
996
997   if (xevent->xclient.message_type != gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS"))
998     return GDK_FILTER_CONTINUE;
999
1000   atom = (Atom) xevent->xclient.data.l[0];
1001
1002   if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
1003     {
1004   /* The delete window request specifies a window
1005    *  to delete. We don't actually destroy the
1006    *  window because "it is only a request". (The
1007    *  window might contain vital data that the
1008    *  program does not want destroyed). Instead
1009    *  the event is passed along to the program,
1010    *  which should then destroy the window.
1011    */
1012       GDK_NOTE (EVENTS,
1013                 g_message ("delete window:\t\twindow: %ld",
1014                            xevent->xclient.window));
1015
1016       event->any.type = GDK_DELETE;
1017
1018       gdk_x11_window_set_user_time (win, xevent->xclient.data.l[1]);
1019
1020       return GDK_FILTER_TRANSLATE;
1021     }
1022   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
1023     {
1024       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
1025
1026       /* There is no way of knowing reliably whether we are viewable;
1027        * so trap errors asynchronously around the XSetInputFocus call
1028        */
1029       if (toplevel && win->accept_focus)
1030         {
1031           gdk_x11_display_error_trap_push (display);
1032           XSetInputFocus (GDK_DISPLAY_XDISPLAY (display),
1033                           toplevel->focus_window,
1034                           RevertToParent,
1035                           xevent->xclient.data.l[1]);
1036           gdk_x11_display_error_trap_pop_ignored (display);
1037        }
1038
1039       return GDK_FILTER_REMOVE;
1040     }
1041   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING") &&
1042            !_gdk_x11_display_is_root_window (display,
1043                                              xevent->xclient.window))
1044     {
1045       XClientMessageEvent xclient = xevent->xclient;
1046
1047       xclient.window = GDK_WINDOW_XROOTWIN (win);
1048       XSendEvent (GDK_WINDOW_XDISPLAY (win),
1049                   xclient.window,
1050                   False,
1051                   SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
1052
1053       return GDK_FILTER_REMOVE;
1054     }
1055   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") &&
1056            GDK_X11_DISPLAY (display)->use_sync)
1057     {
1058       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
1059       if (toplevel)
1060         {
1061 #ifdef HAVE_XSYNC
1062           XSyncIntsToValue (&toplevel->pending_counter_value,
1063                             xevent->xclient.data.l[2],
1064                             xevent->xclient.data.l[3]);
1065 #endif
1066         }
1067       return GDK_FILTER_REMOVE;
1068     }
1069
1070   return GDK_FILTER_CONTINUE;
1071 }
1072
1073 static void
1074 gdk_event_init (GdkDisplay *display)
1075 {
1076   GdkX11Display *display_x11;
1077   GdkDeviceManager *device_manager;
1078
1079   display_x11 = GDK_X11_DISPLAY (display);
1080   display_x11->event_source = gdk_x11_event_source_new (display);
1081
1082   gdk_x11_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
1083                                        GDK_EVENT_TRANSLATOR (display));
1084
1085   device_manager = gdk_display_get_device_manager (display);
1086   gdk_x11_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
1087                                         GDK_EVENT_TRANSLATOR (device_manager));
1088 }
1089
1090 static void
1091 gdk_x11_display_init_input (GdkDisplay *display)
1092 {
1093   GdkX11Display *display_x11;
1094   GdkDeviceManager *device_manager;
1095   GdkDevice *device;
1096   GList *list, *l;
1097
1098   display_x11 = GDK_X11_DISPLAY (display);
1099   device_manager = gdk_display_get_device_manager (display);
1100
1101   /* For backwards compatibility, just add
1102    * floating devices that are not keyboards.
1103    */
1104   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
1105
1106   for (l = list; l; l = l->next)
1107     {
1108       device = l->data;
1109
1110       if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
1111         continue;
1112
1113       display_x11->input_devices = g_list_prepend (display_x11->input_devices,
1114                                                    g_object_ref (l->data));
1115     }
1116
1117   g_list_free (list);
1118
1119   /* Now set "core" pointer to the first
1120    * master device that is a pointer.
1121    */
1122   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
1123
1124   for (l = list; l; l = l->next)
1125     {
1126       device = l->data;
1127
1128       if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
1129         continue;
1130
1131       display->core_pointer = device;
1132       break;
1133     }
1134
1135   /* Add the core pointer to the devices list */
1136   display_x11->input_devices = g_list_prepend (display_x11->input_devices,
1137                                                g_object_ref (display->core_pointer));
1138
1139   g_list_free (list);
1140 }
1141
1142 static void
1143 set_sm_client_id (GdkDisplay  *display,
1144                   const gchar *sm_client_id)
1145 {
1146   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
1147
1148   if (gdk_display_is_closed (display))
1149     return;
1150
1151   if (sm_client_id && strcmp (sm_client_id, ""))
1152     XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
1153                      gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
1154                      XA_STRING, 8, PropModeReplace, (guchar *)sm_client_id,
1155                      strlen (sm_client_id));
1156   else
1157     XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
1158                      gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
1159 }
1160
1161 GdkDisplay *
1162 _gdk_x11_display_open (const gchar *display_name)
1163 {
1164   Display *xdisplay;
1165   GdkDisplay *display;
1166   GdkX11Display *display_x11;
1167   GdkWindowAttr attr;
1168   gint argc;
1169   gchar *argv[1];
1170
1171   XClassHint *class_hint;
1172   gulong pid;
1173   gint i;
1174   gint ignore;
1175   gint maj, min;
1176
1177   xdisplay = XOpenDisplay (display_name);
1178   if (!xdisplay)
1179     return NULL;
1180   
1181   display = g_object_new (GDK_TYPE_X11_DISPLAY, NULL);
1182   display_x11 = GDK_X11_DISPLAY (display);
1183
1184   display_x11->xdisplay = xdisplay;
1185
1186 #ifdef HAVE_X11R6  
1187   /* Set up handlers for Xlib internal connections */
1188   XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
1189 #endif /* HAVE_X11R6 */
1190   
1191   _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
1192
1193   /* RandR must be initialized before we initialize the screens */
1194   display_x11->have_randr12 = FALSE;
1195   display_x11->have_randr13 = FALSE;
1196 #ifdef HAVE_RANDR
1197   if (XRRQueryExtension (display_x11->xdisplay,
1198                          &display_x11->xrandr_event_base, &ignore))
1199   {
1200       int major, minor;
1201
1202       XRRQueryVersion (display_x11->xdisplay, &major, &minor);
1203
1204       if ((major == 1 && minor >= 2) || major > 1) {
1205           display_x11->have_randr12 = TRUE;
1206           if (minor >= 3 || major > 1)
1207               display_x11->have_randr13 = TRUE;
1208       }
1209
1210        gdk_x11_register_standard_event_type (display, display_x11->xrandr_event_base, RRNumberEvents);
1211   }
1212 #endif
1213
1214   /* initialize the display's screens */ 
1215   display_x11->screens = g_new (GdkScreen *, ScreenCount (display_x11->xdisplay));
1216   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1217     display_x11->screens[i] = _gdk_x11_screen_new (display, i);
1218
1219   /* We need to initialize events after we have the screen
1220    * structures in places
1221    */
1222   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1223     _gdk_x11_screen_init_events (display_x11->screens[i]);
1224
1225   /*set the default screen */
1226   display_x11->default_screen = display_x11->screens[DefaultScreen (display_x11->xdisplay)];
1227
1228   display->device_manager = _gdk_x11_device_manager_new (display);
1229
1230   gdk_event_init (display);
1231
1232   attr.window_type = GDK_WINDOW_TOPLEVEL;
1233   attr.wclass = GDK_INPUT_OUTPUT;
1234   attr.x = 10;
1235   attr.y = 10;
1236   attr.width = 10;
1237   attr.height = 10;
1238   attr.event_mask = 0;
1239
1240   display_x11->leader_gdk_window = gdk_window_new (GDK_X11_SCREEN (display_x11->default_screen)->root_window, 
1241                                                    &attr, GDK_WA_X | GDK_WA_Y);
1242   (_gdk_x11_window_get_toplevel (display_x11->leader_gdk_window))->is_leader = TRUE;
1243
1244   display_x11->leader_window = GDK_WINDOW_XID (display_x11->leader_gdk_window);
1245
1246   display_x11->leader_window_title_set = FALSE;
1247
1248 #ifdef HAVE_XFIXES
1249   if (XFixesQueryExtension (display_x11->xdisplay, 
1250                             &display_x11->xfixes_event_base, 
1251                             &ignore))
1252     {
1253       display_x11->have_xfixes = TRUE;
1254
1255       gdk_x11_register_standard_event_type (display,
1256                                             display_x11->xfixes_event_base, 
1257                                             XFixesNumberEvents);
1258     }
1259   else
1260 #endif
1261     display_x11->have_xfixes = FALSE;
1262
1263 #ifdef HAVE_XCOMPOSITE
1264   if (XCompositeQueryExtension (display_x11->xdisplay,
1265                                 &ignore, &ignore))
1266     {
1267       int major, minor;
1268
1269       XCompositeQueryVersion (display_x11->xdisplay, &major, &minor);
1270
1271       /* Prior to Composite version 0.4, composited windows clipped their
1272        * parents, so you had to use IncludeInferiors to draw to the parent
1273        * This isn't useful for our purposes, so require 0.4
1274        */
1275       display_x11->have_xcomposite = major > 0 || (major == 0 && minor >= 4);
1276     }
1277   else
1278 #endif
1279     display_x11->have_xcomposite = FALSE;
1280
1281 #ifdef HAVE_XDAMAGE
1282   if (XDamageQueryExtension (display_x11->xdisplay,
1283                              &display_x11->xdamage_event_base,
1284                              &ignore))
1285     {
1286       display_x11->have_xdamage = TRUE;
1287
1288       gdk_x11_register_standard_event_type (display,
1289                                             display_x11->xdamage_event_base,
1290                                             XDamageNumberEvents);
1291     }
1292   else
1293 #endif
1294     display_x11->have_xdamage = FALSE;
1295
1296   display_x11->have_shapes = FALSE;
1297   display_x11->have_input_shapes = FALSE;
1298
1299   if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &display_x11->shape_event_base, &ignore))
1300     {
1301       display_x11->have_shapes = TRUE;
1302 #ifdef ShapeInput
1303       if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
1304         display_x11->have_input_shapes = (maj == 1 && min >= 1);
1305 #endif
1306     }
1307
1308   display_x11->trusted_client = TRUE;
1309   {
1310     Window root, child;
1311     int rootx, rooty, winx, winy;
1312     unsigned int xmask;
1313
1314     gdk_x11_display_error_trap_push (display);
1315     XQueryPointer (display_x11->xdisplay,
1316                    GDK_X11_SCREEN (display_x11->default_screen)->xroot_window,
1317                    &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
1318     if (G_UNLIKELY (gdk_x11_display_error_trap_pop (display) == BadWindow))
1319       {
1320         g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display));
1321         display_x11->trusted_client = FALSE;
1322       }
1323   }
1324
1325   if (g_getenv ("GDK_SYNCHRONIZE"))
1326     XSynchronize (display_x11->xdisplay, True);
1327
1328   class_hint = XAllocClassHint();
1329   class_hint->res_name = g_get_prgname ();
1330
1331   class_hint->res_class = (char *)gdk_get_program_class ();
1332
1333   /* XmbSetWMProperties sets the RESOURCE_NAME environment variable
1334    * from argv[0], so we just synthesize an argument array here.
1335    */
1336   argc = 1;
1337   argv[0] = g_get_prgname ();
1338
1339   XmbSetWMProperties (display_x11->xdisplay,
1340                       display_x11->leader_window,
1341                       NULL, NULL, argv, argc, NULL, NULL,
1342                       class_hint);
1343   XFree (class_hint);
1344
1345   if (gdk_sm_client_id)
1346     set_sm_client_id (display, gdk_sm_client_id);
1347
1348   pid = getpid ();
1349   XChangeProperty (display_x11->xdisplay,
1350                    display_x11->leader_window,
1351                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
1352                    XA_CARDINAL, 32, PropModeReplace, (guchar *) & pid, 1);
1353
1354   /* We don't yet know a valid time. */
1355   display_x11->user_time = 0;
1356   
1357 #ifdef HAVE_XKB
1358   {
1359     gint xkb_major = XkbMajorVersion;
1360     gint xkb_minor = XkbMinorVersion;
1361     if (XkbLibraryVersion (&xkb_major, &xkb_minor))
1362       {
1363         xkb_major = XkbMajorVersion;
1364         xkb_minor = XkbMinorVersion;
1365             
1366         if (XkbQueryExtension (display_x11->xdisplay, 
1367                                NULL, &display_x11->xkb_event_type, NULL,
1368                                &xkb_major, &xkb_minor))
1369           {
1370             Bool detectable_autorepeat_supported;
1371             
1372             display_x11->use_xkb = TRUE;
1373
1374             XkbSelectEvents (display_x11->xdisplay,
1375                              XkbUseCoreKbd,
1376                              XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
1377                              XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
1378
1379             /* keep this in sync with _gdk_x11_keymap_state_changed() */
1380             XkbSelectEventDetails (display_x11->xdisplay,
1381                                    XkbUseCoreKbd, XkbStateNotify,
1382                                    XkbAllStateComponentsMask,
1383                                    XkbGroupLockMask|XkbModifierLockMask);
1384
1385             XkbSetDetectableAutoRepeat (display_x11->xdisplay,
1386                                         True,
1387                                         &detectable_autorepeat_supported);
1388
1389             GDK_NOTE (MISC, g_message ("Detectable autorepeat %s.",
1390                                        detectable_autorepeat_supported ?
1391                                        "supported" : "not supported"));
1392             
1393             display_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
1394           }
1395       }
1396   }
1397 #endif
1398
1399   display_x11->use_sync = FALSE;
1400 #ifdef HAVE_XSYNC
1401   {
1402     int major, minor;
1403     int error_base, event_base;
1404     
1405     if (XSyncQueryExtension (display_x11->xdisplay,
1406                              &event_base, &error_base) &&
1407         XSyncInitialize (display_x11->xdisplay,
1408                          &major, &minor))
1409       display_x11->use_sync = TRUE;
1410   }
1411 #endif
1412
1413   gdk_x11_display_init_input (display);
1414
1415   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1416     _gdk_x11_screen_setup (display_x11->screens[i]);
1417
1418   g_signal_emit_by_name (display, "opened");
1419   g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
1420
1421   return display;
1422 }
1423
1424 #ifdef HAVE_X11R6
1425 /*
1426  * XLib internal connection handling
1427  */
1428 typedef struct _GdkInternalConnection GdkInternalConnection;
1429
1430 struct _GdkInternalConnection
1431 {
1432   gint           fd;
1433   GSource       *source;
1434   Display       *display;
1435 };
1436
1437 static gboolean
1438 process_internal_connection (GIOChannel  *gioc,
1439                              GIOCondition cond,
1440                              gpointer     data)
1441 {
1442   GdkInternalConnection *connection = (GdkInternalConnection *)data;
1443
1444   GDK_THREADS_ENTER ();
1445
1446   XProcessInternalConnection ((Display*)connection->display, connection->fd);
1447
1448   GDK_THREADS_LEAVE ();
1449
1450   return TRUE;
1451 }
1452
1453 static gulong
1454 gdk_x11_display_get_next_serial (GdkDisplay *display)
1455 {
1456   return NextRequest (GDK_DISPLAY_XDISPLAY (display));
1457 }
1458
1459
1460 static GdkInternalConnection *
1461 gdk_add_connection_handler (Display *display,
1462                             guint    fd)
1463 {
1464   GIOChannel *io_channel;
1465   GdkInternalConnection *connection;
1466
1467   connection = g_new (GdkInternalConnection, 1);
1468
1469   connection->fd = fd;
1470   connection->display = display;
1471   
1472   io_channel = g_io_channel_unix_new (fd);
1473   
1474   connection->source = g_io_create_watch (io_channel, G_IO_IN);
1475   g_source_set_callback (connection->source,
1476                          (GSourceFunc)process_internal_connection, connection, NULL);
1477   g_source_attach (connection->source, NULL);
1478   
1479   g_io_channel_unref (io_channel);
1480   
1481   return connection;
1482 }
1483
1484 static void
1485 gdk_remove_connection_handler (GdkInternalConnection *connection)
1486 {
1487   g_source_destroy (connection->source);
1488   g_free (connection);
1489 }
1490
1491 static void
1492 gdk_internal_connection_watch (Display  *display,
1493                                XPointer  arg,
1494                                gint      fd,
1495                                gboolean  opening,
1496                                XPointer *watch_data)
1497 {
1498   if (opening)
1499     *watch_data = (XPointer)gdk_add_connection_handler (display, fd);
1500   else
1501     gdk_remove_connection_handler ((GdkInternalConnection *)*watch_data);
1502 }
1503 #endif /* HAVE_X11R6 */
1504
1505 static const gchar *
1506 gdk_x11_display_get_name (GdkDisplay *display)
1507 {
1508   return (gchar *) DisplayString (GDK_X11_DISPLAY (display)->xdisplay);
1509 }
1510
1511 static gint
1512 gdk_x11_display_get_n_screens (GdkDisplay *display)
1513 {
1514   return ScreenCount (GDK_X11_DISPLAY (display)->xdisplay);
1515 }
1516
1517 static GdkScreen *
1518 gdk_x11_display_get_screen (GdkDisplay *display,
1519                             gint        screen_num)
1520 {
1521   g_return_val_if_fail (ScreenCount (GDK_X11_DISPLAY (display)->xdisplay) > screen_num, NULL);
1522
1523   return GDK_X11_DISPLAY (display)->screens[screen_num];
1524 }
1525
1526 static GdkScreen *
1527 gdk_x11_display_get_default_screen (GdkDisplay *display)
1528 {
1529   return GDK_X11_DISPLAY (display)->default_screen;
1530 }
1531
1532 gboolean
1533 _gdk_x11_display_is_root_window (GdkDisplay *display,
1534                                  Window      xroot_window)
1535 {
1536   GdkX11Display *display_x11;
1537   gint i;
1538
1539   display_x11 = GDK_X11_DISPLAY (display);
1540
1541   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1542     {
1543       if (GDK_SCREEN_XROOTWIN (display_x11->screens[i]) == xroot_window)
1544         return TRUE;
1545     }
1546   return FALSE;
1547 }
1548
1549 struct XPointerUngrabInfo {
1550   GdkDisplay *display;
1551   guint32 time;
1552 };
1553
1554 static void
1555 device_grab_update_callback (GdkDisplay *display,
1556                              gpointer    data,
1557                              gulong      serial)
1558 {
1559   GdkDevice *device = data;
1560
1561   _gdk_display_device_grab_update (display, device, NULL, serial);
1562 }
1563
1564 #define XSERVER_TIME_IS_LATER(time1, time2)                        \
1565   ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) ||  \
1566     (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 ))     \
1567   )
1568
1569 void
1570 _gdk_x11_display_update_grab_info (GdkDisplay *display,
1571                                    GdkDevice  *device,
1572                                    gint        status)
1573 {
1574   if (status == GrabSuccess)
1575     _gdk_x11_roundtrip_async (display, device_grab_update_callback, device);
1576 }
1577
1578 void
1579 _gdk_x11_display_update_grab_info_ungrab (GdkDisplay *display,
1580                                           GdkDevice  *device,
1581                                           guint32     time,
1582                                           gulong      serial)
1583 {
1584   GdkDeviceGrabInfo *grab;
1585
1586   XFlush (GDK_DISPLAY_XDISPLAY (display));
1587
1588   grab = _gdk_display_get_last_device_grab (display, device);
1589   if (grab &&
1590       (time == GDK_CURRENT_TIME ||
1591        grab->time == GDK_CURRENT_TIME ||
1592        !XSERVER_TIME_IS_LATER (grab->time, time)))
1593     {
1594       grab->serial_end = serial;
1595       _gdk_x11_roundtrip_async (display, device_grab_update_callback, device);
1596     }
1597 }
1598
1599 static void
1600 gdk_x11_display_beep (GdkDisplay *display)
1601 {
1602 #ifdef HAVE_XKB
1603   XkbBell (GDK_DISPLAY_XDISPLAY (display), None, 0, None);
1604 #else
1605   XBell (GDK_DISPLAY_XDISPLAY (display), 0);
1606 #endif
1607 }
1608
1609 static void
1610 gdk_x11_display_sync (GdkDisplay *display)
1611 {
1612   XSync (GDK_DISPLAY_XDISPLAY (display), False);
1613 }
1614
1615 static void
1616 gdk_x11_display_flush (GdkDisplay *display)
1617 {
1618   if (!display->closed)
1619     XFlush (GDK_DISPLAY_XDISPLAY (display));
1620 }
1621
1622 static gboolean
1623 gdk_x11_display_has_pending (GdkDisplay *display)
1624 {
1625   return XPending (GDK_DISPLAY_XDISPLAY (display));
1626 }
1627
1628 static GdkWindow *
1629 gdk_x11_display_get_default_group (GdkDisplay *display)
1630 {
1631   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1632
1633   return GDK_X11_DISPLAY (display)->leader_gdk_window;
1634 }
1635
1636 /**
1637  * gdk_x11_display_grab:
1638  * @display: (type GdkX11Display): a #GdkDisplay 
1639  * 
1640  * Call XGrabServer() on @display. 
1641  * To ungrab the display again, use gdk_x11_display_ungrab(). 
1642  *
1643  * gdk_x11_display_grab()/gdk_x11_display_ungrab() calls can be nested.
1644  *
1645  * Since: 2.2
1646  **/
1647 void
1648 gdk_x11_display_grab (GdkDisplay *display)
1649 {
1650   GdkX11Display *display_x11;
1651   
1652   g_return_if_fail (GDK_IS_DISPLAY (display));
1653   
1654   display_x11 = GDK_X11_DISPLAY (display);
1655   
1656   if (display_x11->grab_count == 0)
1657     XGrabServer (display_x11->xdisplay);
1658   display_x11->grab_count++;
1659 }
1660
1661 /**
1662  * gdk_x11_display_ungrab:
1663  * @display: (type GdkX11Display): a #GdkDisplay
1664  * 
1665  * Ungrab @display after it has been grabbed with 
1666  * gdk_x11_display_grab(). 
1667  *
1668  * Since: 2.2
1669  **/
1670 void
1671 gdk_x11_display_ungrab (GdkDisplay *display)
1672 {
1673   GdkX11Display *display_x11;
1674   
1675   g_return_if_fail (GDK_IS_DISPLAY (display));
1676   
1677   display_x11 = GDK_X11_DISPLAY (display);;
1678   g_return_if_fail (display_x11->grab_count > 0);
1679   
1680   display_x11->grab_count--;
1681   if (display_x11->grab_count == 0)
1682     {
1683       XUngrabServer (display_x11->xdisplay);
1684       XFlush (display_x11->xdisplay);
1685     }
1686 }
1687
1688 static void
1689 gdk_x11_display_dispose (GObject *object)
1690 {
1691   GdkDisplay *display = GDK_DISPLAY (object);
1692   GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
1693   gint           i;
1694
1695   _gdk_x11_display_manager_remove_display (gdk_display_manager_get (), display);
1696
1697   g_list_foreach (display_x11->input_devices, (GFunc) g_object_run_dispose, NULL);
1698
1699   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1700     _gdk_screen_close (display_x11->screens[i]);
1701
1702   if (display_x11->event_source)
1703     {
1704       g_source_destroy (display_x11->event_source);
1705       g_source_unref (display_x11->event_source);
1706       display_x11->event_source = NULL;
1707     }
1708
1709   G_OBJECT_CLASS (gdk_x11_display_parent_class)->dispose (object);
1710 }
1711
1712 static void
1713 gdk_x11_display_finalize (GObject *object)
1714 {
1715   GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
1716   gint           i;
1717
1718   /* Keymap */
1719   if (display_x11->keymap)
1720     g_object_unref (display_x11->keymap);
1721
1722   /* Free motif Dnd */
1723   if (display_x11->motif_target_lists)
1724     {
1725       for (i = 0; i < display_x11->motif_n_target_lists; i++)
1726         g_list_free (display_x11->motif_target_lists[i]);
1727       g_free (display_x11->motif_target_lists);
1728     }
1729
1730   _gdk_x11_cursor_display_finalize (GDK_DISPLAY (display_x11));
1731
1732   /* Empty the event queue */
1733   _gdk_x11_display_free_translate_queue (GDK_DISPLAY (display_x11));
1734
1735   /* Atom Hashtable */
1736   g_hash_table_destroy (display_x11->atom_from_virtual);
1737   g_hash_table_destroy (display_x11->atom_to_virtual);
1738
1739   /* Leader Window */
1740   XDestroyWindow (display_x11->xdisplay, display_x11->leader_window);
1741
1742   /* List of event window extraction functions */
1743   g_slist_foreach (display_x11->event_types, (GFunc)g_free, NULL);
1744   g_slist_free (display_x11->event_types);
1745
1746   /* input GdkDevice list */
1747   g_list_foreach (display_x11->input_devices, (GFunc) g_object_unref, NULL);
1748   g_list_free (display_x11->input_devices);
1749
1750   /* input GdkWindow list */
1751   g_list_foreach (display_x11->input_windows, (GFunc) g_free, NULL);
1752   g_list_free (display_x11->input_windows);
1753
1754   /* Free all GdkScreens */
1755   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1756     g_object_unref (display_x11->screens[i]);
1757   g_free (display_x11->screens);
1758
1759   g_free (display_x11->startup_notification_id);
1760
1761   /* X ID hashtable */
1762   g_hash_table_destroy (display_x11->xid_ht);
1763
1764   XCloseDisplay (display_x11->xdisplay);
1765
1766   /* error traps */
1767   while (display_x11->error_traps != NULL)
1768     {
1769       GdkErrorTrap *trap = display_x11->error_traps->data;
1770
1771       display_x11->error_traps =
1772         g_slist_delete_link (display_x11->error_traps,
1773                              display_x11->error_traps);
1774
1775       if (trap->end_sequence == 0)
1776         g_warning ("Display finalized with an unpopped error trap");
1777
1778       g_slice_free (GdkErrorTrap, trap);
1779     }
1780
1781   G_OBJECT_CLASS (gdk_x11_display_parent_class)->finalize (object);
1782 }
1783
1784 /**
1785  * gdk_x11_lookup_xdisplay:
1786  * @xdisplay: a pointer to an X Display
1787  * 
1788  * Find the #GdkDisplay corresponding to @display, if any exists.
1789  * 
1790  * Return value: (transfer none): the #GdkDisplay, if found, otherwise %NULL.
1791  *
1792  * Since: 2.2
1793  **/
1794 GdkDisplay *
1795 gdk_x11_lookup_xdisplay (Display *xdisplay)
1796 {
1797   GSList *list, *l;
1798   GdkDisplay *display;
1799
1800   display = NULL;
1801
1802   list = gdk_display_manager_list_displays (gdk_display_manager_get ());
1803
1804   for (l = list; l; l = l->next)
1805     {
1806       if (GDK_DISPLAY_XDISPLAY (l->data) == xdisplay)
1807         {
1808           display = l->data;
1809           break;
1810         }
1811     }
1812
1813   g_slist_free (list);
1814
1815   return display;
1816 }
1817
1818 /**
1819  * _gdk_x11_display_screen_for_xrootwin:
1820  * @display: a #GdkDisplay
1821  * @xrootwin: window ID for one of of the screen's of the display.
1822  * 
1823  * Given the root window ID of one of the screen's of a #GdkDisplay,
1824  * finds the screen.
1825  * 
1826  * Return value: (transfer none): the #GdkScreen corresponding to
1827  *     @xrootwin, or %NULL.
1828  **/
1829 GdkScreen *
1830 _gdk_x11_display_screen_for_xrootwin (GdkDisplay *display,
1831                                       Window      xrootwin)
1832 {
1833   gint i;
1834
1835   for (i = 0; i < ScreenCount (GDK_X11_DISPLAY (display)->xdisplay); i++)
1836     {
1837       GdkScreen *screen = gdk_display_get_screen (display, i);
1838       if (GDK_SCREEN_XROOTWIN (screen) == xrootwin)
1839         return screen;
1840     }
1841
1842   return NULL;
1843 }
1844
1845 /**
1846  * gdk_x11_display_get_xdisplay:
1847  * @display: (type GdkX11Display): a #GdkDisplay
1848  * @returns: (transfer none): an X display.
1849  *
1850  * Returns the X display of a #GdkDisplay.
1851  *
1852  * Since: 2.2
1853  */
1854 Display *
1855 gdk_x11_display_get_xdisplay (GdkDisplay *display)
1856 {
1857   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1858   return GDK_X11_DISPLAY (display)->xdisplay;
1859 }
1860
1861 void
1862 _gdk_x11_display_make_default (GdkDisplay *display)
1863 {
1864   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
1865   const gchar *startup_id;
1866
1867   g_free (display_x11->startup_notification_id);
1868   display_x11->startup_notification_id = NULL;
1869
1870   startup_id = g_getenv ("DESKTOP_STARTUP_ID");
1871   if (startup_id && *startup_id != '\0')
1872     {
1873       if (!g_utf8_validate (startup_id, -1, NULL))
1874         g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
1875       else
1876         gdk_x11_display_set_startup_notification_id (display, startup_id);
1877
1878       /* Clear the environment variable so it won't be inherited by
1879        * child processes and confuse things.
1880        */
1881       g_unsetenv ("DESKTOP_STARTUP_ID");
1882     }
1883 }
1884
1885 static void
1886 broadcast_xmessage (GdkDisplay *display,
1887                     const char *message_type,
1888                     const char *message_type_begin,
1889                     const char *message)
1890 {
1891   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
1892   GdkScreen *screen = gdk_display_get_default_screen (display);
1893   GdkWindow *root_window = gdk_screen_get_root_window (screen);
1894   Window xroot_window = GDK_WINDOW_XID (root_window);
1895   
1896   Atom type_atom;
1897   Atom type_atom_begin;
1898   Window xwindow;
1899
1900   if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1901     return;
1902
1903   {
1904     XSetWindowAttributes attrs;
1905
1906     attrs.override_redirect = True;
1907     attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
1908
1909     xwindow =
1910       XCreateWindow (xdisplay,
1911                      xroot_window,
1912                      -100, -100, 1, 1,
1913                      0,
1914                      CopyFromParent,
1915                      CopyFromParent,
1916                      (Visual *)CopyFromParent,
1917                      CWOverrideRedirect | CWEventMask,
1918                      &attrs);
1919   }
1920
1921   type_atom = gdk_x11_get_xatom_by_name_for_display (display,
1922                                                      message_type);
1923   type_atom_begin = gdk_x11_get_xatom_by_name_for_display (display,
1924                                                            message_type_begin);
1925   
1926   {
1927     XClientMessageEvent xclient;
1928     const char *src;
1929     const char *src_end;
1930     char *dest;
1931     char *dest_end;
1932     
1933                 memset(&xclient, 0, sizeof (xclient));
1934     xclient.type = ClientMessage;
1935     xclient.message_type = type_atom_begin;
1936     xclient.display =xdisplay;
1937     xclient.window = xwindow;
1938     xclient.format = 8;
1939
1940     src = message;
1941     src_end = message + strlen (message) + 1; /* +1 to include nul byte */
1942     
1943     while (src != src_end)
1944       {
1945         dest = &xclient.data.b[0];
1946         dest_end = dest + 20;        
1947         
1948         while (dest != dest_end &&
1949                src != src_end)
1950           {
1951             *dest = *src;
1952             ++dest;
1953             ++src;
1954           }
1955
1956         while (dest != dest_end)
1957           {
1958             *dest = 0;
1959             ++dest;
1960           }
1961         
1962         XSendEvent (xdisplay,
1963                     xroot_window,
1964                     False,
1965                     PropertyChangeMask,
1966                     (XEvent *)&xclient);
1967
1968         xclient.message_type = type_atom;
1969       }
1970   }
1971
1972   XDestroyWindow (xdisplay, xwindow);
1973   XFlush (xdisplay);
1974 }
1975
1976 /**
1977  * gdk_x11_display_broadcast_startup_message:
1978  * @display: (type GdkX11Display): a #GdkDisplay
1979  * @message_type: startup notification message type ("new", "change",
1980  * or "remove")
1981  * @...: a list of key/value pairs (as strings), terminated by a
1982  * %NULL key. (A %NULL value for a key will cause that key to be
1983  * skipped in the output.)
1984  *
1985  * Sends a startup notification message of type @message_type to
1986  * @display. 
1987  *
1988  * This is a convenience function for use by code that implements the
1989  * freedesktop startup notification specification. Applications should
1990  * not normally need to call it directly. See the <ulink
1991  * url="http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt">Startup
1992  * Notification Protocol specification</ulink> for
1993  * definitions of the message types and keys that can be used.
1994  *
1995  * Since: 2.12
1996  **/
1997 void
1998 gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
1999                                            const char *message_type,
2000                                            ...)
2001 {
2002   GString *message;
2003   va_list ap;
2004   const char *key, *value, *p;
2005
2006   message = g_string_new (message_type);
2007   g_string_append_c (message, ':');
2008
2009   va_start (ap, message_type);
2010   while ((key = va_arg (ap, const char *)))
2011     {
2012       value = va_arg (ap, const char *);
2013       if (!value)
2014         continue;
2015
2016       g_string_append_printf (message, " %s=\"", key);
2017       for (p = value; *p; p++)
2018         {
2019           switch (*p)
2020             {
2021             case ' ':
2022             case '"':
2023             case '\\':
2024               g_string_append_c (message, '\\');
2025               break;
2026             }
2027
2028           g_string_append_c (message, *p);
2029         }
2030       g_string_append_c (message, '\"');
2031     }
2032   va_end (ap);
2033
2034   broadcast_xmessage (display,
2035                       "_NET_STARTUP_INFO",
2036                       "_NET_STARTUP_INFO_BEGIN",
2037                       message->str);
2038
2039   g_string_free (message, TRUE);
2040 }
2041
2042 static void
2043 gdk_x11_display_notify_startup_complete (GdkDisplay  *display,
2044                                          const gchar *startup_id)
2045 {
2046   if (startup_id == NULL)
2047     {
2048       startup_id = GDK_X11_DISPLAY (display)->startup_notification_id;
2049       if (startup_id == NULL)
2050         return;
2051     }
2052
2053   gdk_x11_display_broadcast_startup_message (display, "remove",
2054                                              "ID", startup_id,
2055                                              NULL);
2056 }
2057
2058 static gboolean
2059 gdk_x11_display_supports_selection_notification (GdkDisplay *display)
2060 {
2061   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
2062
2063   return display_x11->have_xfixes;
2064 }
2065
2066 static gboolean
2067 gdk_x11_display_request_selection_notification (GdkDisplay *display,
2068                                                 GdkAtom     selection)
2069
2070 {
2071 #ifdef HAVE_XFIXES
2072   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
2073   Atom atom;
2074
2075   if (display_x11->have_xfixes)
2076     {
2077       atom = gdk_x11_atom_to_xatom_for_display (display, 
2078                                                 selection);
2079       XFixesSelectSelectionInput (display_x11->xdisplay, 
2080                                   display_x11->leader_window,
2081                                   atom,
2082                                   XFixesSetSelectionOwnerNotifyMask |
2083                                   XFixesSelectionWindowDestroyNotifyMask |
2084                                   XFixesSelectionClientCloseNotifyMask);
2085       return TRUE;
2086     }
2087   else
2088 #endif
2089     return FALSE;
2090 }
2091
2092 static gboolean
2093 gdk_x11_display_supports_clipboard_persistence (GdkDisplay *display)
2094 {
2095   Atom clipboard_manager;
2096
2097   /* It might make sense to cache this */
2098   clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
2099   return XGetSelectionOwner (GDK_X11_DISPLAY (display)->xdisplay, clipboard_manager) != None;
2100 }
2101
2102 static void
2103 gdk_x11_display_store_clipboard (GdkDisplay    *display,
2104                                  GdkWindow     *clipboard_window,
2105                                  guint32        time_,
2106                                  const GdkAtom *targets,
2107                                  gint           n_targets)
2108 {
2109   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
2110   Atom clipboard_manager, save_targets;
2111
2112   g_return_if_fail (GDK_WINDOW_IS_X11 (clipboard_window));
2113
2114   clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
2115   save_targets = gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS");
2116
2117   gdk_x11_display_error_trap_push (display);
2118
2119   if (XGetSelectionOwner (display_x11->xdisplay, clipboard_manager) != None)
2120     {
2121       Atom property_name = None;
2122       Atom *xatoms;
2123       int i;
2124
2125       if (n_targets > 0)
2126         {
2127           property_name = gdk_x11_get_xatom_by_name_for_display (display, "GDK_SELECTION");
2128
2129           xatoms = g_new (Atom, n_targets);
2130           for (i = 0; i < n_targets; i++)
2131             xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, targets[i]);
2132
2133           XChangeProperty (display_x11->xdisplay, GDK_WINDOW_XID (clipboard_window),
2134                            property_name, XA_ATOM,
2135                            32, PropModeReplace, (guchar *)xatoms, n_targets);
2136           g_free (xatoms);
2137
2138         }
2139
2140       XConvertSelection (display_x11->xdisplay,
2141                          clipboard_manager, save_targets, property_name,
2142                          GDK_WINDOW_XID (clipboard_window), time_);
2143
2144     }
2145   gdk_x11_display_error_trap_pop_ignored (display);
2146
2147 }
2148
2149 /**
2150  * gdk_x11_display_get_user_time:
2151  * @display: (type GdkX11Display): a #GdkDisplay
2152  *
2153  * Returns the timestamp of the last user interaction on 
2154  * @display. The timestamp is taken from events caused
2155  * by user interaction such as key presses or pointer 
2156  * movements. See gdk_x11_window_set_user_time().
2157  *
2158  * Returns: the timestamp of the last user interaction 
2159  *
2160  * Since: 2.8
2161  */
2162 guint32
2163 gdk_x11_display_get_user_time (GdkDisplay *display)
2164 {
2165   return GDK_X11_DISPLAY (display)->user_time;
2166 }
2167
2168 static gboolean
2169 gdk_x11_display_supports_shapes (GdkDisplay *display)
2170 {
2171   return GDK_X11_DISPLAY (display)->have_shapes;
2172 }
2173
2174 static gboolean
2175 gdk_x11_display_supports_input_shapes (GdkDisplay *display)
2176 {
2177   return GDK_X11_DISPLAY (display)->have_input_shapes;
2178 }
2179
2180
2181 /**
2182  * gdk_x11_display_get_startup_notification_id:
2183  * @display: (type GdkX11Display): a #GdkDisplay
2184  *
2185  * Gets the startup notification ID for a display.
2186  * 
2187  * Returns: the startup notification ID for @display
2188  *
2189  * Since: 2.12
2190  */
2191 const gchar *
2192 gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
2193 {
2194   return GDK_X11_DISPLAY (display)->startup_notification_id;
2195 }
2196
2197 /**
2198  * gdk_x11_display_set_startup_notification_id:
2199  * @display: (type GdkX11Display): a #GdkDisplay
2200  * @startup_id: the startup notification ID (must be valid utf8)
2201  *
2202  * Sets the startup notification ID for a display.
2203  *
2204  * This is usually taken from the value of the DESKTOP_STARTUP_ID
2205  * environment variable, but in some cases (such as the application not
2206  * being launched using exec()) it can come from other sources.
2207  *
2208  * If the ID contains the string "_TIME" then the portion following that
2209  * string is taken to be the X11 timestamp of the event that triggered
2210  * the application to be launched and the GDK current event time is set
2211  * accordingly.
2212  *
2213  * The startup ID is also what is used to signal that the startup is
2214  * complete (for example, when opening a window or when calling
2215  * gdk_notify_startup_complete()).
2216  *
2217  * Since: 3.0
2218  **/
2219 void
2220 gdk_x11_display_set_startup_notification_id (GdkDisplay  *display,
2221                                              const gchar *startup_id)
2222 {
2223   GdkX11Display *display_x11;
2224   gchar *time_str;
2225
2226   display_x11 = GDK_X11_DISPLAY (display);
2227
2228   g_free (display_x11->startup_notification_id);
2229   display_x11->startup_notification_id = g_strdup (startup_id);
2230
2231   /* Find the launch time from the startup_id, if it's there.  Newer spec
2232    * states that the startup_id is of the form <unique>_TIME<timestamp>
2233    */
2234   time_str = g_strrstr (startup_id, "_TIME");
2235   if (time_str != NULL)
2236     {
2237       gulong retval;
2238       gchar *end;
2239       errno = 0;
2240
2241       /* Skip past the "_TIME" part */
2242       time_str += 5;
2243
2244       retval = strtoul (time_str, &end, 0);
2245       if (end != time_str && errno == 0)
2246         display_x11->user_time = retval;
2247     }
2248
2249   /* Set the startup id on the leader window so it
2250    * applies to all windows we create on this display
2251    */
2252   XChangeProperty (display_x11->xdisplay,
2253                    display_x11->leader_window,
2254                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
2255                    gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2256                    PropModeReplace,
2257                    (guchar *)startup_id, strlen (startup_id));
2258 }
2259
2260 static gboolean
2261 gdk_x11_display_supports_composite (GdkDisplay *display)
2262 {
2263   GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
2264
2265   return x11_display->have_xcomposite &&
2266          x11_display->have_xdamage &&
2267          x11_display->have_xfixes;
2268 }
2269
2270 static GList *
2271 gdk_x11_display_list_devices (GdkDisplay *display)
2272 {
2273   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
2274
2275   return GDK_X11_DISPLAY (display)->input_devices;
2276 }
2277
2278 /**
2279  * gdk_x11_register_standard_event_type:
2280  * @display: a #GdkDisplay
2281  * @event_base: first event type code to register
2282  * @n_events: number of event type codes to register
2283  *
2284  * Registers interest in receiving extension events with type codes
2285  * between @event_base and <literal>event_base + n_events - 1</literal>.
2286  * The registered events must have the window field in the same place
2287  * as core X events (this is not the case for e.g. XKB extension events).
2288  *
2289  * If an event type is registered, events of this type will go through
2290  * global and window-specific filters (see gdk_window_add_filter()).
2291  * Unregistered events will only go through global filters.
2292  * GDK may register the events of some X extensions on its own.
2293  *
2294  * This function should only be needed in unusual circumstances, e.g.
2295  * when filtering XInput extension events on the root window.
2296  *
2297  * Since: 2.4
2298  **/
2299 void
2300 gdk_x11_register_standard_event_type (GdkDisplay *display,
2301                                       gint        event_base,
2302                                       gint        n_events)
2303 {
2304   GdkEventTypeX11 *event_type;
2305   GdkX11Display *display_x11;
2306
2307   display_x11 = GDK_X11_DISPLAY (display);
2308   event_type = g_new (GdkEventTypeX11, 1);
2309
2310   event_type->base = event_base;
2311   event_type->n_events = n_events;
2312
2313   display_x11->event_types = g_slist_prepend (display_x11->event_types, event_type);
2314 }
2315
2316 /* compare X sequence numbers handling wraparound */
2317 #define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
2318
2319 /* delivers an error event from the error handler in gdkmain-x11.c */
2320 void
2321 _gdk_x11_display_error_event (GdkDisplay  *display,
2322                               XErrorEvent *error)
2323 {
2324   GdkX11Display *display_x11;
2325   GSList *tmp_list;
2326   gboolean ignore;
2327
2328   display_x11 = GDK_X11_DISPLAY (display);
2329
2330   ignore = FALSE;
2331   for (tmp_list = display_x11->error_traps;
2332        tmp_list != NULL;
2333        tmp_list = tmp_list->next)
2334     {
2335       GdkErrorTrap *trap;
2336
2337       trap = tmp_list->data;
2338
2339       if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
2340           (trap->end_sequence == 0 ||
2341            SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
2342         {
2343           ignore = TRUE;
2344           trap->error_code = error->error_code;
2345           break; /* only innermost trap gets the error code */
2346         }
2347     }
2348
2349   if (!ignore)
2350     {
2351       gchar buf[64];
2352       gchar *msg;
2353
2354       XGetErrorText (display_x11->xdisplay, error->error_code, buf, 63);
2355
2356       msg =
2357         g_strdup_printf ("The program '%s' received an X Window System error.\n"
2358                          "This probably reflects a bug in the program.\n"
2359                          "The error was '%s'.\n"
2360                          "  (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
2361                          "  (Note to programmers: normally, X errors are reported asynchronously;\n"
2362                          "   that is, you will receive the error a while after causing it.\n"
2363                          "   To debug your program, run it with the --sync command line\n"
2364                          "   option to change this behavior. You can then get a meaningful\n"
2365                          "   backtrace from your debugger if you break on the gdk_x_error() function.)",
2366                          g_get_prgname (),
2367                          buf,
2368                          error->serial,
2369                          error->error_code,
2370                          error->request_code,
2371                          error->minor_code);
2372
2373 #ifdef G_ENABLE_DEBUG
2374       g_error ("%s", msg);
2375 #else /* !G_ENABLE_DEBUG */
2376       g_warning ("%s\n", msg);
2377
2378       _exit (1);
2379 #endif /* G_ENABLE_DEBUG */
2380     }
2381 }
2382
2383 static void
2384 delete_outdated_error_traps (GdkX11Display *display_x11)
2385 {
2386   GSList *tmp_list;
2387   gulong processed_sequence;
2388
2389   processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
2390
2391   tmp_list = display_x11->error_traps;
2392   while (tmp_list != NULL)
2393     {
2394       GdkErrorTrap *trap = tmp_list->data;
2395
2396       if (trap->end_sequence != 0 &&
2397           SEQUENCE_COMPARE (trap->end_sequence, <=, processed_sequence))
2398         {
2399           GSList *free_me = tmp_list;
2400
2401           tmp_list = tmp_list->next;
2402           display_x11->error_traps =
2403             g_slist_delete_link (display_x11->error_traps, free_me);
2404           g_slice_free (GdkErrorTrap, trap);
2405         }
2406       else
2407         {
2408           tmp_list = tmp_list->next;
2409         }
2410     }
2411 }
2412
2413 /**
2414  * gdk_x11_display_error_trap_push:
2415  * @display: (type GdkX11Display): a #GdkDisplay
2416  *
2417  * Begins a range of X requests on @display for which X error events
2418  * will be ignored. Unignored errors (when no trap is pushed) will abort
2419  * the application. Use gdk_x11_display_error_trap_pop() or
2420  * gdk_x11_display_error_trap_pop_ignored()to lift a trap pushed
2421  * with this function.
2422  *
2423  * See also gdk_error_trap_push() to push a trap on all displays.
2424  *
2425  * Since: 3.0
2426  */
2427 void
2428 gdk_x11_display_error_trap_push (GdkDisplay *display)
2429 {
2430   GdkX11Display *display_x11;
2431   GdkErrorTrap *trap;
2432
2433   display_x11 = GDK_X11_DISPLAY (display);
2434
2435   delete_outdated_error_traps (display_x11);
2436
2437   /* set up the Xlib callback to tell us about errors */
2438   _gdk_x11_error_handler_push ();
2439
2440   trap = g_slice_new0 (GdkErrorTrap);
2441
2442   trap->start_sequence = XNextRequest (display_x11->xdisplay);
2443   trap->error_code = Success;
2444
2445   display_x11->error_traps =
2446     g_slist_prepend (display_x11->error_traps, trap);
2447 }
2448
2449 static gint
2450 gdk_x11_display_error_trap_pop_internal (GdkDisplay *display,
2451                                          gboolean    need_code)
2452 {
2453   GdkX11Display *display_x11;
2454   GdkErrorTrap *trap;
2455   GSList *tmp_list;
2456   int result;
2457
2458   display_x11 = GDK_X11_DISPLAY (display);
2459
2460   g_return_val_if_fail (display_x11->error_traps != NULL, Success);
2461
2462   /* Find the first trap that hasn't been popped already */
2463   trap = NULL; /* quiet gcc */
2464   for (tmp_list = display_x11->error_traps;
2465        tmp_list != NULL;
2466        tmp_list = tmp_list->next)
2467     {
2468       trap = tmp_list->data;
2469
2470       if (trap->end_sequence == 0)
2471         break;
2472     }
2473
2474   g_return_val_if_fail (trap != NULL, Success);
2475   g_assert (trap->end_sequence == 0);
2476
2477   /* May need to sync to fill in trap->error_code if we care about
2478    * getting an error code.
2479    */
2480   if (need_code)
2481     {
2482       gulong processed_sequence;
2483       gulong next_sequence;
2484
2485       next_sequence = XNextRequest (display_x11->xdisplay);
2486       processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
2487
2488       /* If our last request was already processed, there is no point
2489        * in syncing. i.e. if last request was a round trip (or even if
2490        * we got an event with the serial of a non-round-trip)
2491        */
2492       if ((next_sequence - 1) != processed_sequence)
2493         {
2494           XSync (display_x11->xdisplay, False);
2495         }
2496
2497       result = trap->error_code;
2498     }
2499   else
2500     {
2501       result = Success;
2502     }
2503
2504   /* record end of trap, giving us a range of
2505    * error sequences we'll ignore.
2506    */
2507   trap->end_sequence = XNextRequest (display_x11->xdisplay);
2508
2509   /* remove the Xlib callback */
2510   _gdk_x11_error_handler_pop ();
2511
2512   /* we may already be outdated */
2513   delete_outdated_error_traps (display_x11);
2514
2515   return result;
2516 }
2517
2518 /**
2519  * gdk_x11_display_error_trap_pop:
2520  * @display: (type GdkX11Display): the display
2521  *
2522  * Pops the error trap pushed by gdk_x11_display_error_trap_push().
2523  * Will XSync() if necessary and will always block until
2524  * the error is known to have occurred or not occurred,
2525  * so the error code can be returned.
2526  *
2527  * If you don't need to use the return value,
2528  * gdk_x11_display_error_trap_pop_ignored() would be more efficient.
2529  *
2530  * See gdk_error_trap_pop() for the all-displays-at-once
2531  * equivalent.
2532  *
2533  * Since: 3.0
2534  *
2535  * Return value: X error code or 0 on success
2536  */
2537 gint
2538 gdk_x11_display_error_trap_pop (GdkDisplay *display)
2539 {
2540   g_return_val_if_fail (GDK_IS_X11_DISPLAY (display), Success);
2541
2542   return gdk_x11_display_error_trap_pop_internal (display, TRUE);
2543 }
2544
2545 /**
2546  * gdk_x11_display_error_trap_pop_ignored:
2547  * @display: (type GdkX11Display): the display
2548  *
2549  * Pops the error trap pushed by gdk_x11_display_error_trap_push().
2550  * Does not block to see if an error occurred; merely records the
2551  * range of requests to ignore errors for, and ignores those errors
2552  * if they arrive asynchronously.
2553  *
2554  * See gdk_error_trap_pop_ignored() for the all-displays-at-once
2555  * equivalent.
2556  *
2557  * Since: 3.0
2558  */
2559 void
2560 gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
2561 {
2562   g_return_if_fail (GDK_IS_X11_DISPLAY (display));
2563
2564   gdk_x11_display_error_trap_pop_internal (display, FALSE);
2565 }
2566
2567 /**
2568  * gdk_x11_set_sm_client_id:
2569  * @sm_client_id: the client id assigned by the session manager when the
2570  *    connection was opened, or %NULL to remove the property.
2571  *
2572  * Sets the <literal>SM_CLIENT_ID</literal> property on the application's leader window so that
2573  * the window manager can save the application's state using the X11R6 ICCCM
2574  * session management protocol.
2575  *
2576  * See the X Session Management Library documentation for more information on
2577  * session management and the Inter-Client Communication Conventions Manual
2578  *
2579  * Since: 2.24
2580  */
2581 void
2582 gdk_x11_set_sm_client_id (const gchar *sm_client_id)
2583 {
2584  GSList *displays, *l;
2585
2586   g_free (gdk_sm_client_id);
2587   gdk_sm_client_id = g_strdup (sm_client_id);
2588
2589   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
2590   for (l = displays; l; l = l->next)
2591     set_sm_client_id (l->data, sm_client_id);
2592
2593   g_slist_free (displays);
2594 }
2595
2596 static void
2597 gdk_x11_display_event_data_copy (GdkDisplay    *display,
2598                                 const GdkEvent *src,
2599                                 GdkEvent       *dst)
2600 {
2601 }
2602
2603 static void
2604 gdk_x11_display_event_data_free (GdkDisplay *display,
2605                                  GdkEvent *event)
2606 {
2607 }
2608
2609 static gint
2610 pop_error_trap (GdkDisplay *display,
2611                 gboolean    ignored)
2612 {
2613   if (ignored)
2614     {
2615       gdk_x11_display_error_trap_pop_ignored (display);
2616       return Success;
2617     }
2618   else
2619     {
2620       return gdk_x11_display_error_trap_pop (display);
2621     }
2622 }
2623
2624 static GdkKeymap *
2625 gdk_x11_display_get_keymap (GdkDisplay *display)
2626 {
2627   GdkX11Display *display_x11;
2628   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
2629   display_x11 = GDK_X11_DISPLAY (display);
2630
2631   if (!display_x11->keymap)
2632     display_x11->keymap = g_object_new (GDK_TYPE_X11_KEYMAP, NULL);
2633
2634   display_x11->keymap->display = display;
2635
2636   return display_x11->keymap;
2637 }
2638
2639 static void
2640 gdk_x11_display_class_init (GdkX11DisplayClass * class)
2641 {
2642   GObjectClass *object_class = G_OBJECT_CLASS (class);
2643   GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);
2644
2645   object_class->dispose = gdk_x11_display_dispose;
2646   object_class->finalize = gdk_x11_display_finalize;
2647
2648   display_class->window_type = GDK_TYPE_X11_WINDOW;
2649
2650   display_class->get_name = gdk_x11_display_get_name;
2651   display_class->get_n_screens = gdk_x11_display_get_n_screens;
2652   display_class->get_screen = gdk_x11_display_get_screen;
2653   display_class->get_default_screen = gdk_x11_display_get_default_screen;
2654   display_class->beep = gdk_x11_display_beep;
2655   display_class->sync = gdk_x11_display_sync;
2656   display_class->flush = gdk_x11_display_flush;
2657   display_class->has_pending = gdk_x11_display_has_pending;
2658   display_class->queue_events = _gdk_x11_display_queue_events;
2659   display_class->get_default_group = gdk_x11_display_get_default_group;
2660   display_class->supports_selection_notification = gdk_x11_display_supports_selection_notification;
2661   display_class->request_selection_notification = gdk_x11_display_request_selection_notification;
2662   display_class->supports_clipboard_persistence = gdk_x11_display_supports_clipboard_persistence;
2663   display_class->store_clipboard = gdk_x11_display_store_clipboard;
2664   display_class->supports_shapes = gdk_x11_display_supports_shapes;
2665   display_class->supports_input_shapes = gdk_x11_display_supports_input_shapes;
2666   display_class->supports_composite = gdk_x11_display_supports_composite;
2667   display_class->list_devices = gdk_x11_display_list_devices;
2668   display_class->get_app_launch_context = _gdk_x11_display_get_app_launch_context;
2669   display_class->get_cursor_for_type = _gdk_x11_display_get_cursor_for_type;
2670   display_class->get_cursor_for_name = _gdk_x11_display_get_cursor_for_name;
2671   display_class->get_cursor_for_pixbuf = _gdk_x11_display_get_cursor_for_pixbuf;
2672   display_class->get_default_cursor_size = _gdk_x11_display_get_default_cursor_size;
2673   display_class->get_maximal_cursor_size = _gdk_x11_display_get_maximal_cursor_size;
2674   display_class->supports_cursor_alpha = _gdk_x11_display_supports_cursor_alpha;
2675   display_class->supports_cursor_color = _gdk_x11_display_supports_cursor_color;
2676
2677   display_class->before_process_all_updates = _gdk_x11_display_before_process_all_updates;
2678   display_class->after_process_all_updates = _gdk_x11_display_after_process_all_updates;
2679   display_class->get_next_serial = gdk_x11_display_get_next_serial;
2680   display_class->notify_startup_complete = gdk_x11_display_notify_startup_complete;
2681   display_class->event_data_copy = gdk_x11_display_event_data_copy;
2682   display_class->event_data_free = gdk_x11_display_event_data_free;
2683   display_class->create_window_impl = _gdk_x11_display_create_window_impl;
2684   display_class->get_keymap = gdk_x11_display_get_keymap;
2685   display_class->push_error_trap = gdk_x11_display_error_trap_push;
2686   display_class->pop_error_trap = pop_error_trap;
2687   display_class->get_selection_owner = _gdk_x11_display_get_selection_owner;
2688   display_class->set_selection_owner = _gdk_x11_display_set_selection_owner;
2689   display_class->send_selection_notify = _gdk_x11_display_send_selection_notify;
2690   display_class->get_selection_property = _gdk_x11_display_get_selection_property;
2691   display_class->convert_selection = _gdk_x11_display_convert_selection;
2692   display_class->text_property_to_utf8_list = _gdk_x11_display_text_property_to_utf8_list;
2693   display_class->utf8_to_string_target = _gdk_x11_display_utf8_to_string_target;
2694 }