]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdisplay-x11.c
API: Remove GdkNoExposeEvent
[~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 "gdkdisplay-x11.h"
28
29 #include "gdkx.h"
30 #include "gdkasync.h"
31 #include "gdkdisplay.h"
32 #include "gdkeventsource.h"
33 #include "gdkeventtranslator.h"
34 #include "gdkinternals.h"
35 #include "gdkscreen.h"
36 #include "gdkscreen-x11.h"
37 #include "gdkinternals.h"
38 #include "gdkdeviceprivate.h"
39 #include "gdkdevicemanager.h"
40 #include "xsettings-client.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_display_x11_dispose            (GObject            *object);
92 static void   gdk_display_x11_finalize           (GObject            *object);
93
94 static void     gdk_display_x11_event_translator_init (GdkEventTranslatorIface *iface);
95
96 static gboolean gdk_display_x11_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 };
159
160 G_DEFINE_TYPE_WITH_CODE (GdkDisplayX11, _gdk_display_x11, GDK_TYPE_DISPLAY,
161                          G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
162                                                 gdk_display_x11_event_translator_init))
163
164
165 static void
166 _gdk_display_x11_class_init (GdkDisplayX11Class * class)
167 {
168   GObjectClass *object_class = G_OBJECT_CLASS (class);
169   
170   object_class->dispose = gdk_display_x11_dispose;
171   object_class->finalize = gdk_display_x11_finalize;
172 }
173
174 static void
175 _gdk_display_x11_init (GdkDisplayX11 *display)
176 {
177 }
178
179 static void
180 gdk_display_x11_event_translator_init (GdkEventTranslatorIface *iface)
181 {
182   iface->translate_event = gdk_display_x11_translate_event;
183 }
184
185 static void
186 do_net_wm_state_changes (GdkWindow *window)
187 {
188   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
189   GdkWindowState old_state;
190
191   if (GDK_WINDOW_DESTROYED (window) ||
192       gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
193     return;
194
195   old_state = gdk_window_get_state (window);
196
197   /* For found_sticky to remain TRUE, we have to also be on desktop
198    * 0xFFFFFFFF
199    */
200   if (old_state & GDK_WINDOW_STATE_STICKY)
201     {
202       if (!(toplevel->have_sticky && toplevel->on_all_desktops))
203         gdk_synthesize_window_state (window,
204                                      GDK_WINDOW_STATE_STICKY,
205                                      0);
206     }
207   else
208     {
209       if (toplevel->have_sticky || toplevel->on_all_desktops)
210         gdk_synthesize_window_state (window,
211                                      0,
212                                      GDK_WINDOW_STATE_STICKY);
213     }
214
215   if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
216     {
217       if (!toplevel->have_fullscreen)
218         gdk_synthesize_window_state (window,
219                                      GDK_WINDOW_STATE_FULLSCREEN,
220                                      0);
221     }
222   else
223     {
224       if (toplevel->have_fullscreen)
225         gdk_synthesize_window_state (window,
226                                      0,
227                                      GDK_WINDOW_STATE_FULLSCREEN);
228     }
229
230   /* Our "maximized" means both vertical and horizontal; if only one,
231    * we don't expose that via GDK
232    */
233   if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
234     {
235       if (!(toplevel->have_maxvert && toplevel->have_maxhorz))
236         gdk_synthesize_window_state (window,
237                                      GDK_WINDOW_STATE_MAXIMIZED,
238                                      0);
239     }
240   else
241     {
242       if (toplevel->have_maxvert && toplevel->have_maxhorz)
243         gdk_synthesize_window_state (window,
244                                      0,
245                                      GDK_WINDOW_STATE_MAXIMIZED);
246     }
247 }
248
249 static void
250 gdk_check_wm_desktop_changed (GdkWindow *window)
251 {
252   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
253   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
254
255   Atom type;
256   gint format;
257   gulong nitems;
258   gulong bytes_after;
259   guchar *data;
260   gulong *desktop;
261
262   type = None;
263   gdk_error_trap_push ();
264   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
265                       GDK_WINDOW_XID (window),
266                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
267                       0, G_MAXLONG, False, XA_CARDINAL, &type,
268                       &format, &nitems,
269                       &bytes_after, &data);
270   gdk_error_trap_pop_ignored ();
271
272   if (type != None)
273     {
274       desktop = (gulong *)data;
275       toplevel->on_all_desktops = (*desktop == 0xFFFFFFFF);
276       XFree (desktop);
277     }
278   else
279     toplevel->on_all_desktops = FALSE;
280
281   do_net_wm_state_changes (window);
282 }
283
284 static void
285 gdk_check_wm_state_changed (GdkWindow *window)
286 {
287   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
288   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
289
290   Atom type;
291   gint format;
292   gulong nitems;
293   gulong bytes_after;
294   guchar *data;
295   Atom *atoms = NULL;
296   gulong i;
297
298   gboolean had_sticky = toplevel->have_sticky;
299
300   toplevel->have_sticky = FALSE;
301   toplevel->have_maxvert = FALSE;
302   toplevel->have_maxhorz = FALSE;
303   toplevel->have_fullscreen = FALSE;
304
305   type = None;
306   gdk_error_trap_push ();
307   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
308                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
309                       0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
310                       &bytes_after, &data);
311   gdk_error_trap_pop_ignored ();
312
313   if (type != None)
314     {
315       Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
316       Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
317       Atom maxhorz_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
318       Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
319
320       atoms = (Atom *)data;
321
322       i = 0;
323       while (i < nitems)
324         {
325           if (atoms[i] == sticky_atom)
326             toplevel->have_sticky = TRUE;
327           else if (atoms[i] == maxvert_atom)
328             toplevel->have_maxvert = TRUE;
329           else if (atoms[i] == maxhorz_atom)
330             toplevel->have_maxhorz = TRUE;
331           else if (atoms[i] == fullscreen_atom)
332             toplevel->have_fullscreen = TRUE;
333
334           ++i;
335         }
336
337       XFree (atoms);
338     }
339
340   /* When have_sticky is turned on, we have to check the DESKTOP property
341    * as well.
342    */
343   if (toplevel->have_sticky && !had_sticky)
344     gdk_check_wm_desktop_changed (window);
345   else
346     do_net_wm_state_changes (window);
347 }
348
349 static GdkWindow *
350 get_event_window (GdkEventTranslator *translator,
351                   XEvent             *xevent)
352 {
353   GdkDisplay *display;
354   Window xwindow;
355
356   display = (GdkDisplay *) translator;
357
358   switch (xevent->type)
359     {
360     case DestroyNotify:
361       xwindow = xevent->xdestroywindow.window;
362       break;
363     case UnmapNotify:
364       xwindow = xevent->xunmap.window;
365       break;
366     case MapNotify:
367       xwindow = xevent->xmap.window;
368       break;
369     case ConfigureNotify:
370       xwindow = xevent->xconfigure.window;
371       break;
372     default:
373       xwindow = xevent->xany.window;
374     }
375
376   return gdk_window_lookup_for_display (display, xwindow);
377 }
378
379 static gboolean
380 gdk_display_x11_translate_event (GdkEventTranslator *translator,
381                                  GdkDisplay         *display,
382                                  GdkEvent           *event,
383                                  XEvent             *xevent)
384 {
385   GdkWindow *window;
386   GdkWindowImplX11 *window_impl = NULL;
387   GdkScreen *screen = NULL;
388   GdkScreenX11 *screen_x11 = NULL;
389   GdkToplevelX11 *toplevel = NULL;
390   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
391   gboolean return_val;
392   Window xwindow = None;
393
394   /* Find the GdkWindow that this event relates to.
395    * Basically this means substructure events
396    * are reported same as structure events
397    */
398   window = get_event_window (translator, xevent);
399
400   if (window)
401     {
402       /* We may receive events such as NoExpose/GraphicsExpose
403        * and ShmCompletion for pixmaps
404        */
405       if (!GDK_IS_WINDOW (window))
406         return FALSE;
407
408       screen = GDK_WINDOW_SCREEN (window);
409       screen_x11 = GDK_SCREEN_X11 (screen);
410       toplevel = _gdk_x11_window_get_toplevel (window);
411       window_impl = GDK_WINDOW_IMPL_X11 (window->impl);
412       xwindow = GDK_WINDOW_XID (window);
413
414       g_object_ref (window);
415     }
416
417   event->any.window = window;
418   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
419
420   if (window && GDK_WINDOW_DESTROYED (window))
421     {
422       if (xevent->type != DestroyNotify)
423         {
424           return_val = FALSE;
425           goto done;
426         }
427     }
428
429   if (xevent->type == DestroyNotify)
430     {
431       int i, n;
432
433       n = gdk_display_get_n_screens (display);
434       for (i = 0; i < n; i++)
435         {
436           screen = gdk_display_get_screen (display, i);
437           screen_x11 = GDK_SCREEN_X11 (screen);
438
439           if (screen_x11->wmspec_check_window == xwindow)
440             {
441               screen_x11->wmspec_check_window = None;
442               screen_x11->last_wmspec_check_time = 0;
443               g_free (screen_x11->window_manager_name);
444               screen_x11->window_manager_name = g_strdup ("unknown");
445
446               /* careful, reentrancy */
447               _gdk_x11_screen_window_manager_changed (screen);
448
449               return_val = FALSE;
450               goto done;
451             }
452         }
453     }
454
455   /* We do a "manual" conversion of the XEvent to a
456    *  GdkEvent. The structures are mostly the same so
457    *  the conversion is fairly straightforward. We also
458    *  optionally print debugging info regarding events
459    *  received.
460    */
461
462   return_val = TRUE;
463
464   switch (xevent->type)
465     {
466     case KeymapNotify:
467       GDK_NOTE (EVENTS,
468                 g_message ("keymap notify"));
469
470       /* Not currently handled */
471       return_val = FALSE;
472       break;
473
474     case Expose:
475       GDK_NOTE (EVENTS,
476                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
477                            xevent->xexpose.window, xevent->xexpose.count,
478                            xevent->xexpose.x, xevent->xexpose.y,
479                            xevent->xexpose.width, xevent->xexpose.height,
480                            event->any.send_event ? " (send)" : ""));
481
482       if (window == NULL)
483         {
484           return_val = FALSE;
485           break;
486         }
487
488       {
489         GdkRectangle expose_rect;
490
491         expose_rect.x = xevent->xexpose.x;
492         expose_rect.y = xevent->xexpose.y;
493         expose_rect.width = xevent->xexpose.width;
494         expose_rect.height = xevent->xexpose.height;
495
496         _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
497         return_val = FALSE;
498       }
499
500       break;
501
502     case GraphicsExpose:
503       {
504         GdkRectangle expose_rect;
505
506         GDK_NOTE (EVENTS,
507                   g_message ("graphics expose:\tdrawable: %ld",
508                              xevent->xgraphicsexpose.drawable));
509
510         if (window == NULL)
511           {
512             return_val = FALSE;
513             break;
514           }
515
516         expose_rect.x = xevent->xgraphicsexpose.x;
517         expose_rect.y = xevent->xgraphicsexpose.y;
518         expose_rect.width = xevent->xgraphicsexpose.width;
519         expose_rect.height = xevent->xgraphicsexpose.height;
520
521         _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
522         return_val = FALSE;
523       }
524       break;
525
526     case VisibilityNotify:
527 #ifdef G_ENABLE_DEBUG
528       if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
529         switch (xevent->xvisibility.state)
530           {
531           case VisibilityFullyObscured:
532             g_message ("visibility notify:\twindow: %ld  none",
533                        xevent->xvisibility.window);
534             break;
535           case VisibilityPartiallyObscured:
536             g_message ("visibility notify:\twindow: %ld  partial",
537                        xevent->xvisibility.window);
538             break;
539           case VisibilityUnobscured:
540             g_message ("visibility notify:\twindow: %ld  full",
541                        xevent->xvisibility.window);
542             break;
543           }
544 #endif /* G_ENABLE_DEBUG */
545
546       if (window == NULL)
547         {
548           return_val = FALSE;
549           break;
550         }
551
552       event->visibility.type = GDK_VISIBILITY_NOTIFY;
553       event->visibility.window = window;
554
555       switch (xevent->xvisibility.state)
556         {
557         case VisibilityFullyObscured:
558           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
559           break;
560
561         case VisibilityPartiallyObscured:
562           event->visibility.state = GDK_VISIBILITY_PARTIAL;
563           break;
564
565         case VisibilityUnobscured:
566           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
567           break;
568         }
569
570       break;
571
572     case CreateNotify:
573       GDK_NOTE (EVENTS,
574                 g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
575                            xevent->xcreatewindow.window,
576                            xevent->xcreatewindow.x,
577                            xevent->xcreatewindow.y,
578                            xevent->xcreatewindow.width,
579                            xevent->xcreatewindow.height,
580                            xevent->xcreatewindow.border_width,
581                            xevent->xcreatewindow.parent,
582                            xevent->xcreatewindow.override_redirect));
583       /* not really handled */
584       break;
585
586     case DestroyNotify:
587       GDK_NOTE (EVENTS,
588                 g_message ("destroy notify:\twindow: %ld",
589                            xevent->xdestroywindow.window));
590
591       /* Ignore DestroyNotify from SubstructureNotifyMask */
592       if (xevent->xdestroywindow.window == xevent->xdestroywindow.event)
593         {
594           event->any.type = GDK_DESTROY;
595           event->any.window = window;
596
597           return_val = window && !GDK_WINDOW_DESTROYED (window);
598
599           if (window && GDK_WINDOW_XID (window) != screen_x11->xroot_window)
600             gdk_window_destroy_notify (window);
601         }
602       else
603         return_val = FALSE;
604
605       break;
606
607     case UnmapNotify:
608       GDK_NOTE (EVENTS,
609                 g_message ("unmap notify:\t\twindow: %ld",
610                            xevent->xmap.window));
611
612       event->any.type = GDK_UNMAP;
613       event->any.window = window;
614
615       /* If we are shown (not withdrawn) and get an unmap, it means we
616        * were iconified in the X sense. If we are withdrawn, and get
617        * an unmap, it means we hid the window ourselves, so we
618        * will have already flipped the iconified bit off.
619        */
620       if (window)
621         {
622           if (GDK_WINDOW_IS_MAPPED (window))
623             gdk_synthesize_window_state (window,
624                                          0,
625                                          GDK_WINDOW_STATE_ICONIFIED);
626
627           _gdk_xgrab_check_unmap (window, xevent->xany.serial);
628         }
629
630       break;
631
632     case MapNotify:
633       GDK_NOTE (EVENTS,
634                 g_message ("map notify:\t\twindow: %ld",
635                            xevent->xmap.window));
636
637       event->any.type = GDK_MAP;
638       event->any.window = window;
639
640       /* Unset iconified if it was set */
641       if (window && (window->state & GDK_WINDOW_STATE_ICONIFIED))
642         gdk_synthesize_window_state (window,
643                                      GDK_WINDOW_STATE_ICONIFIED,
644                                      0);
645
646       break;
647
648     case ReparentNotify:
649       GDK_NOTE (EVENTS,
650                 g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
651                            xevent->xreparent.window,
652                            xevent->xreparent.x,
653                            xevent->xreparent.y,
654                            xevent->xreparent.parent,
655                            xevent->xreparent.override_redirect));
656
657       /* Not currently handled */
658       return_val = FALSE;
659       break;
660
661     case ConfigureNotify:
662       GDK_NOTE (EVENTS,
663                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
664                            xevent->xconfigure.window,
665                            xevent->xconfigure.x,
666                            xevent->xconfigure.y,
667                            xevent->xconfigure.width,
668                            xevent->xconfigure.height,
669                            xevent->xconfigure.border_width,
670                            xevent->xconfigure.above,
671                            xevent->xconfigure.override_redirect,
672                            !window
673                            ? " (discarding)"
674                            : window->window_type == GDK_WINDOW_CHILD
675                            ? " (discarding child)"
676                            : xevent->xconfigure.event != xevent->xconfigure.window
677                            ? " (discarding substructure)"
678                            : ""));
679       if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
680         {
681           window->width = xevent->xconfigure.width;
682           window->height = xevent->xconfigure.height;
683
684           _gdk_window_update_size (window);
685           _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
686           _gdk_x11_screen_size_changed (screen, xevent);
687         }
688
689 #ifdef HAVE_XSYNC
690       if (toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value))
691         {
692           toplevel->current_counter_value = toplevel->pending_counter_value;
693           XSyncIntToValue (&toplevel->pending_counter_value, 0);
694         }
695 #endif
696
697     if (!window ||
698           xevent->xconfigure.event != xevent->xconfigure.window ||
699           GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
700           GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
701         return_val = FALSE;
702       else
703         {
704           event->configure.type = GDK_CONFIGURE;
705           event->configure.window = window;
706           event->configure.width = xevent->xconfigure.width;
707           event->configure.height = xevent->xconfigure.height;
708
709           if (!xevent->xconfigure.send_event &&
710               !xevent->xconfigure.override_redirect &&
711               !GDK_WINDOW_DESTROYED (window))
712             {
713               gint tx = 0;
714               gint ty = 0;
715               Window child_window = 0;
716
717               gdk_error_trap_push ();
718               if (XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
719                                          GDK_WINDOW_XID (window),
720                                          screen_x11->xroot_window,
721                                          0, 0,
722                                          &tx, &ty,
723                                          &child_window))
724                 {
725                   event->configure.x = tx;
726                   event->configure.y = ty;
727                 }
728               gdk_error_trap_pop_ignored ();
729             }
730           else
731             {
732               event->configure.x = xevent->xconfigure.x;
733               event->configure.y = xevent->xconfigure.y;
734             }
735           window->x = event->configure.x;
736           window->y = event->configure.y;
737           window->width = xevent->xconfigure.width;
738           window->height = xevent->xconfigure.height;
739
740           _gdk_window_update_size (window);
741           _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
742
743           if (window->resize_count >= 1)
744             {
745               window->resize_count -= 1;
746
747               if (window->resize_count == 0)
748                 _gdk_moveresize_configure_done (display, window);
749             }
750         }
751       break;
752
753     case PropertyNotify:
754       GDK_NOTE (EVENTS,
755                 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
756                            xevent->xproperty.window,
757                            xevent->xproperty.atom,
758                            "\"",
759                            gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
760                            "\""));
761
762       if (window == NULL)
763         {
764           return_val = FALSE;
765           break;
766         }
767
768       /* We compare with the serial of the last time we mapped the
769        * window to avoid refetching properties that we set ourselves
770        */
771       if (toplevel &&
772           xevent->xproperty.serial >= toplevel->map_serial)
773         {
774           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
775             gdk_check_wm_state_changed (window);
776
777           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
778             gdk_check_wm_desktop_changed (window);
779         }
780
781       if (window->event_mask & GDK_PROPERTY_CHANGE_MASK)
782         {
783           event->property.type = GDK_PROPERTY_NOTIFY;
784           event->property.window = window;
785           event->property.atom = gdk_x11_xatom_to_atom_for_display (display, xevent->xproperty.atom);
786           event->property.time = xevent->xproperty.time;
787           event->property.state = xevent->xproperty.state;
788         }
789       else
790         return_val = FALSE;
791
792       break;
793
794     case SelectionClear:
795       GDK_NOTE (EVENTS,
796                 g_message ("selection clear:\twindow: %ld",
797                            xevent->xproperty.window));
798
799       if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
800         {
801           event->selection.type = GDK_SELECTION_CLEAR;
802           event->selection.window = window;
803           event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection);
804           event->selection.time = xevent->xselectionclear.time;
805         }
806       else
807         return_val = FALSE;
808
809       break;
810
811     case SelectionRequest:
812       GDK_NOTE (EVENTS,
813                 g_message ("selection request:\twindow: %ld",
814                            xevent->xproperty.window));
815
816       event->selection.type = GDK_SELECTION_REQUEST;
817       event->selection.window = window;
818       event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
819       event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
820       event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
821       event->selection.requestor = xevent->xselectionrequest.requestor;
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       {
854         GList *tmp_list;
855         GdkFilterReturn result = GDK_FILTER_CONTINUE;
856         GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type);
857
858         GDK_NOTE (EVENTS,
859                   g_message ("client message:\twindow: %ld",
860                              xevent->xclient.window));
861
862         tmp_list = display_x11->client_filters;
863         while (tmp_list)
864           {
865             GdkClientFilter *filter = tmp_list->data;
866             tmp_list = tmp_list->next;
867
868             if (filter->type == message_type)
869               {
870                 result = (*filter->function) (xevent, event, filter->data);
871                 if (result != GDK_FILTER_CONTINUE)
872                   break;
873               }
874           }
875
876         switch (result)
877           {
878           case GDK_FILTER_REMOVE:
879             return_val = FALSE;
880             break;
881           case GDK_FILTER_TRANSLATE:
882             return_val = TRUE;
883             break;
884           case GDK_FILTER_CONTINUE:
885             /* Send unknown ClientMessage's on to Gtk for it to use */
886             if (window == NULL)
887               {
888                 return_val = FALSE;
889               }
890             else
891               {
892                 event->client.type = GDK_CLIENT_EVENT;
893                 event->client.window = window;
894                 event->client.message_type = message_type;
895                 event->client.data_format = xevent->xclient.format;
896                 memcpy(&event->client.data, &xevent->xclient.data,
897                        sizeof(event->client.data));
898               }
899             break;
900           }
901       }
902
903       break;
904
905     case MappingNotify:
906       GDK_NOTE (EVENTS,
907                 g_message ("mapping notify"));
908
909       /* Let XLib know that there is a new keyboard mapping.
910        */
911       XRefreshKeyboardMapping (&xevent->xmapping);
912       _gdk_keymap_keys_changed (display);
913       return_val = FALSE;
914       break;
915
916     default:
917 #ifdef HAVE_XFIXES
918       if (xevent->type - display_x11->xfixes_event_base == XFixesSelectionNotify)
919         {
920           XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent;
921
922           _gdk_x11_screen_process_owner_change (screen, xevent);
923           
924           event->owner_change.type = GDK_OWNER_CHANGE;
925           event->owner_change.window = window;
926           event->owner_change.owner = selection_notify->owner;
927           event->owner_change.reason = selection_notify->subtype;
928           event->owner_change.selection = 
929             gdk_x11_xatom_to_atom_for_display (display, 
930                                                selection_notify->selection);
931           event->owner_change.time = selection_notify->timestamp;
932           event->owner_change.selection_time = selection_notify->selection_timestamp;
933           
934           return_val = TRUE;
935         }
936       else
937 #endif
938 #ifdef HAVE_RANDR
939       if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
940           xevent->type - display_x11->xrandr_event_base == RRNotify)
941         {
942           if (screen)
943             _gdk_x11_screen_size_changed (screen, xevent);
944         }
945       else
946 #endif
947 #if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
948       if (display_x11->have_xdamage && window && window->composited &&
949           xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
950           ((XDamageNotifyEvent *) xevent)->damage == window_impl->damage)
951         {
952           XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
953           XserverRegion repair;
954           GdkRectangle rect;
955
956           rect.x = window->x + damage_event->area.x;
957           rect.y = window->y + damage_event->area.y;
958           rect.width = damage_event->area.width;
959           rect.height = damage_event->area.height;
960
961           repair = XFixesCreateRegion (display_x11->xdisplay,
962                                        &damage_event->area, 1);
963           XDamageSubtract (display_x11->xdisplay,
964                            window_impl->damage,
965                            repair, None);
966           XFixesDestroyRegion (display_x11->xdisplay, repair);
967
968           if (window->parent != NULL)
969             _gdk_window_process_expose (window->parent,
970                                         damage_event->serial, &rect);
971
972           return_val = TRUE;
973         }
974       else
975 #endif
976 #ifdef HAVE_XKB
977       if (xevent->type == display_x11->xkb_event_type)
978         {
979           XkbEvent *xkb_event = (XkbEvent *) xevent;
980
981           switch (xkb_event->any.xkb_type)
982             {
983             case XkbNewKeyboardNotify:
984             case XkbMapNotify:
985               _gdk_keymap_keys_changed (display);
986
987               return_val = FALSE;
988               break;
989
990             case XkbStateNotify:
991               _gdk_keymap_state_changed (display, xevent);
992               break;
993             }
994         }
995       else
996 #endif
997         return_val = FALSE;
998     }
999
1000  done:
1001   if (return_val)
1002     {
1003       if (event->any.window)
1004         g_object_ref (event->any.window);
1005     }
1006   else
1007     {
1008       /* Mark this event as having no resources to be freed */
1009       event->any.window = NULL;
1010       event->any.type = GDK_NOTHING;
1011     }
1012
1013   if (window)
1014     g_object_unref (window);
1015
1016   return return_val;
1017 }
1018
1019 static GdkFilterReturn
1020 gdk_wm_protocols_filter (GdkXEvent *xev,
1021                          GdkEvent  *event,
1022                          gpointer data)
1023 {
1024   XEvent *xevent = (XEvent *)xev;
1025   GdkWindow *win = event->any.window;
1026   GdkDisplay *display;
1027   Atom atom;
1028
1029   if (!win)
1030       return GDK_FILTER_REMOVE;
1031
1032   display = GDK_WINDOW_DISPLAY (win);
1033   atom = (Atom)xevent->xclient.data.l[0];
1034
1035   if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
1036     {
1037   /* The delete window request specifies a window
1038    *  to delete. We don't actually destroy the
1039    *  window because "it is only a request". (The
1040    *  window might contain vital data that the
1041    *  program does not want destroyed). Instead
1042    *  the event is passed along to the program,
1043    *  which should then destroy the window.
1044    */
1045       GDK_NOTE (EVENTS,
1046                 g_message ("delete window:\t\twindow: %ld",
1047                            xevent->xclient.window));
1048
1049       event->any.type = GDK_DELETE;
1050
1051       gdk_x11_window_set_user_time (win, xevent->xclient.data.l[1]);
1052
1053       return GDK_FILTER_TRANSLATE;
1054     }
1055   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
1056     {
1057       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
1058
1059       /* There is no way of knowing reliably whether we are viewable;
1060        * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
1061        */
1062       if (toplevel && win->accept_focus)
1063         _gdk_x11_set_input_focus_safe (display, toplevel->focus_window,
1064                                        RevertToParent,
1065                                        xevent->xclient.data.l[1]);
1066
1067       return GDK_FILTER_REMOVE;
1068     }
1069   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING") &&
1070            !_gdk_x11_display_is_root_window (display,
1071                                              xevent->xclient.window))
1072     {
1073       XClientMessageEvent xclient = xevent->xclient;
1074
1075       xclient.window = GDK_WINDOW_XROOTWIN (win);
1076       XSendEvent (GDK_WINDOW_XDISPLAY (win),
1077                   xclient.window,
1078                   False,
1079                   SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
1080
1081       return GDK_FILTER_REMOVE;
1082     }
1083   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") &&
1084            GDK_DISPLAY_X11 (display)->use_sync)
1085     {
1086       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
1087       if (toplevel)
1088         {
1089 #ifdef HAVE_XSYNC
1090           XSyncIntsToValue (&toplevel->pending_counter_value,
1091                             xevent->xclient.data.l[2],
1092                             xevent->xclient.data.l[3]);
1093 #endif
1094         }
1095       return GDK_FILTER_REMOVE;
1096     }
1097
1098   return GDK_FILTER_CONTINUE;
1099 }
1100
1101 static void
1102 _gdk_event_init (GdkDisplay *display)
1103 {
1104   GdkDisplayX11 *display_x11;
1105   GdkDeviceManager *device_manager;
1106
1107   display_x11 = GDK_DISPLAY_X11 (display);
1108   display_x11->event_source = gdk_event_source_new (display);
1109
1110   gdk_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
1111                                    GDK_EVENT_TRANSLATOR (display));
1112
1113   device_manager = gdk_display_get_device_manager (display);
1114   gdk_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
1115                                    GDK_EVENT_TRANSLATOR (device_manager));
1116
1117   gdk_display_add_client_message_filter (display,
1118                                          gdk_atom_intern_static_string ("WM_PROTOCOLS"),
1119                                          gdk_wm_protocols_filter,
1120                                          NULL);
1121 }
1122
1123 static void
1124 _gdk_input_init (GdkDisplay *display)
1125 {
1126   GdkDisplayX11 *display_x11;
1127   GdkDeviceManager *device_manager;
1128   GdkDevice *device;
1129   GList *list, *l;
1130
1131   display_x11 = GDK_DISPLAY_X11 (display);
1132   device_manager = gdk_display_get_device_manager (display);
1133
1134   /* For backwards compatibility, just add
1135    * floating devices that are not keyboards.
1136    */
1137   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
1138
1139   for (l = list; l; l = l->next)
1140     {
1141       device = l->data;
1142
1143       if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
1144         continue;
1145
1146       display_x11->input_devices = g_list_prepend (display_x11->input_devices,
1147                                                    g_object_ref (l->data));
1148     }
1149
1150   g_list_free (list);
1151
1152   /* Now set "core" pointer to the first
1153    * master device that is a pointer.
1154    */
1155   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
1156
1157   for (l = list; l; l = l->next)
1158     {
1159       device = list->data;
1160
1161       if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
1162         continue;
1163
1164       display->core_pointer = device;
1165       break;
1166     }
1167
1168   /* Add the core pointer to the devices list */
1169   display_x11->input_devices = g_list_prepend (display_x11->input_devices,
1170                                                g_object_ref (display->core_pointer));
1171
1172   g_list_free (list);
1173 }
1174
1175 /**
1176  * gdk_display_open:
1177  * @display_name: the name of the display to open
1178  *
1179  * Opens a display.
1180  *
1181  * Return value: (transfer none): a #GdkDisplay, or %NULL if the display
1182  *               could not be opened.
1183  *
1184  * Since: 2.2
1185  */
1186 GdkDisplay *
1187 gdk_display_open (const gchar *display_name)
1188 {
1189   Display *xdisplay;
1190   GdkDisplay *display;
1191   GdkDisplayX11 *display_x11;
1192   GdkWindowAttr attr;
1193   gint argc;
1194   gchar *argv[1];
1195   const char *sm_client_id;
1196   
1197   XClassHint *class_hint;
1198   gulong pid;
1199   gint i;
1200   gint ignore;
1201   gint maj, min;
1202
1203   xdisplay = XOpenDisplay (display_name);
1204   if (!xdisplay)
1205     return NULL;
1206   
1207   display = g_object_new (GDK_TYPE_DISPLAY_X11, NULL);
1208   display_x11 = GDK_DISPLAY_X11 (display);
1209
1210   display_x11->xdisplay = xdisplay;
1211
1212 #ifdef HAVE_X11R6  
1213   /* Set up handlers for Xlib internal connections */
1214   XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
1215 #endif /* HAVE_X11R6 */
1216   
1217   _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
1218
1219   /* RandR must be initialized before we initialize the screens */
1220   display_x11->have_randr13 = FALSE;
1221 #ifdef HAVE_RANDR
1222   if (XRRQueryExtension (display_x11->xdisplay,
1223                          &display_x11->xrandr_event_base, &ignore))
1224   {
1225       int major, minor;
1226       
1227       XRRQueryVersion (display_x11->xdisplay, &major, &minor);
1228
1229       if ((major == 1 && minor >= 3) || major > 1)
1230           display_x11->have_randr13 = TRUE;
1231
1232        gdk_x11_register_standard_event_type (display, display_x11->xrandr_event_base, RRNumberEvents);
1233   }
1234 #endif
1235   
1236   /* initialize the display's screens */ 
1237   display_x11->screens = g_new (GdkScreen *, ScreenCount (display_x11->xdisplay));
1238   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1239     display_x11->screens[i] = _gdk_x11_screen_new (display, i);
1240
1241   /* We need to initialize events after we have the screen
1242    * structures in places
1243    */
1244   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1245     _gdk_screen_x11_events_init (display_x11->screens[i]);
1246
1247   /*set the default screen */
1248   display_x11->default_screen = display_x11->screens[DefaultScreen (display_x11->xdisplay)];
1249
1250   display->device_manager = _gdk_device_manager_new (display);
1251
1252   _gdk_event_init (display);
1253
1254   attr.window_type = GDK_WINDOW_TOPLEVEL;
1255   attr.wclass = GDK_INPUT_OUTPUT;
1256   attr.x = 10;
1257   attr.y = 10;
1258   attr.width = 10;
1259   attr.height = 10;
1260   attr.event_mask = 0;
1261
1262   display_x11->leader_gdk_window = gdk_window_new (GDK_SCREEN_X11 (display_x11->default_screen)->root_window, 
1263                                                    &attr, GDK_WA_X | GDK_WA_Y);
1264   (_gdk_x11_window_get_toplevel (display_x11->leader_gdk_window))->is_leader = TRUE;
1265
1266   display_x11->leader_window = GDK_WINDOW_XID (display_x11->leader_gdk_window);
1267
1268   display_x11->leader_window_title_set = FALSE;
1269
1270 #ifdef HAVE_XFIXES
1271   if (XFixesQueryExtension (display_x11->xdisplay, 
1272                             &display_x11->xfixes_event_base, 
1273                             &ignore))
1274     {
1275       display_x11->have_xfixes = TRUE;
1276
1277       gdk_x11_register_standard_event_type (display,
1278                                             display_x11->xfixes_event_base, 
1279                                             XFixesNumberEvents);
1280     }
1281   else
1282 #endif
1283     display_x11->have_xfixes = FALSE;
1284
1285 #ifdef HAVE_XCOMPOSITE
1286   if (XCompositeQueryExtension (display_x11->xdisplay,
1287                                 &ignore, &ignore))
1288     {
1289       int major, minor;
1290
1291       XCompositeQueryVersion (display_x11->xdisplay, &major, &minor);
1292
1293       /* Prior to Composite version 0.4, composited windows clipped their
1294        * parents, so you had to use IncludeInferiors to draw to the parent
1295        * This isn't useful for our purposes, so require 0.4
1296        */
1297       display_x11->have_xcomposite = major > 0 || (major == 0 && minor >= 4);
1298     }
1299   else
1300 #endif
1301     display_x11->have_xcomposite = FALSE;
1302
1303 #ifdef HAVE_XDAMAGE
1304   if (XDamageQueryExtension (display_x11->xdisplay,
1305                              &display_x11->xdamage_event_base,
1306                              &ignore))
1307     {
1308       display_x11->have_xdamage = TRUE;
1309
1310       gdk_x11_register_standard_event_type (display,
1311                                             display_x11->xdamage_event_base,
1312                                             XDamageNumberEvents);
1313     }
1314   else
1315 #endif
1316     display_x11->have_xdamage = FALSE;
1317
1318   display_x11->have_shapes = FALSE;
1319   display_x11->have_input_shapes = FALSE;
1320
1321   if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &display_x11->shape_event_base, &ignore))
1322     {
1323       display_x11->have_shapes = TRUE;
1324 #ifdef ShapeInput
1325       if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
1326         display_x11->have_input_shapes = (maj == 1 && min >= 1);
1327 #endif
1328     }
1329
1330   display_x11->trusted_client = TRUE;
1331   {
1332     Window root, child;
1333     int rootx, rooty, winx, winy;
1334     unsigned int xmask;
1335
1336     gdk_error_trap_push ();
1337     XQueryPointer (display_x11->xdisplay, 
1338                    GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window,
1339                    &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
1340     if (G_UNLIKELY (gdk_error_trap_pop () == BadWindow)) 
1341       {
1342         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));
1343         display_x11->trusted_client = FALSE;
1344       }
1345   }
1346
1347   if (_gdk_synchronize)
1348     XSynchronize (display_x11->xdisplay, True);
1349   
1350   class_hint = XAllocClassHint();
1351   class_hint->res_name = g_get_prgname ();
1352   
1353   class_hint->res_class = (char *)gdk_get_program_class ();
1354
1355   /* XmbSetWMProperties sets the RESOURCE_NAME environment variable
1356    * from argv[0], so we just synthesize an argument array here.
1357    */
1358   argc = 1;
1359   argv[0] = g_get_prgname ();
1360   
1361   XmbSetWMProperties (display_x11->xdisplay,
1362                       display_x11->leader_window,
1363                       NULL, NULL, argv, argc, NULL, NULL,
1364                       class_hint);
1365   XFree (class_hint);
1366
1367   sm_client_id = _gdk_get_sm_client_id ();
1368   if (sm_client_id)
1369     _gdk_windowing_display_set_sm_client_id (display, sm_client_id);
1370
1371   pid = getpid ();
1372   XChangeProperty (display_x11->xdisplay,
1373                    display_x11->leader_window,
1374                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
1375                    XA_CARDINAL, 32, PropModeReplace, (guchar *) & pid, 1);
1376
1377   /* We don't yet know a valid time. */
1378   display_x11->user_time = 0;
1379   
1380 #ifdef HAVE_XKB
1381   {
1382     gint xkb_major = XkbMajorVersion;
1383     gint xkb_minor = XkbMinorVersion;
1384     if (XkbLibraryVersion (&xkb_major, &xkb_minor))
1385       {
1386         xkb_major = XkbMajorVersion;
1387         xkb_minor = XkbMinorVersion;
1388             
1389         if (XkbQueryExtension (display_x11->xdisplay, 
1390                                NULL, &display_x11->xkb_event_type, NULL,
1391                                &xkb_major, &xkb_minor))
1392           {
1393             Bool detectable_autorepeat_supported;
1394             
1395             display_x11->use_xkb = TRUE;
1396
1397             XkbSelectEvents (display_x11->xdisplay,
1398                              XkbUseCoreKbd,
1399                              XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
1400                              XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
1401
1402             /* keep this in sync with _gdk_keymap_state_changed() */ 
1403             XkbSelectEventDetails (display_x11->xdisplay,
1404                                    XkbUseCoreKbd, XkbStateNotify,
1405                                    XkbAllStateComponentsMask,
1406                                    XkbGroupLockMask|XkbModifierLockMask);
1407
1408             XkbSetDetectableAutoRepeat (display_x11->xdisplay,
1409                                         True,
1410                                         &detectable_autorepeat_supported);
1411
1412             GDK_NOTE (MISC, g_message ("Detectable autorepeat %s.",
1413                                        detectable_autorepeat_supported ? 
1414                                        "supported" : "not supported"));
1415             
1416             display_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
1417           }
1418       }
1419   }
1420 #endif
1421
1422   display_x11->use_sync = FALSE;
1423 #ifdef HAVE_XSYNC
1424   {
1425     int major, minor;
1426     int error_base, event_base;
1427     
1428     if (XSyncQueryExtension (display_x11->xdisplay,
1429                              &event_base, &error_base) &&
1430         XSyncInitialize (display_x11->xdisplay,
1431                          &major, &minor))
1432       display_x11->use_sync = TRUE;
1433   }
1434 #endif
1435
1436   _gdk_input_init (display);
1437   _gdk_dnd_init (display);
1438
1439   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1440     _gdk_x11_screen_setup (display_x11->screens[i]);
1441
1442   g_signal_emit_by_name (display, "opened");
1443   g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
1444
1445   return display;
1446 }
1447
1448 #ifdef HAVE_X11R6
1449 /*
1450  * XLib internal connection handling
1451  */
1452 typedef struct _GdkInternalConnection GdkInternalConnection;
1453
1454 struct _GdkInternalConnection
1455 {
1456   gint           fd;
1457   GSource       *source;
1458   Display       *display;
1459 };
1460
1461 static gboolean
1462 process_internal_connection (GIOChannel  *gioc,
1463                              GIOCondition cond,
1464                              gpointer     data)
1465 {
1466   GdkInternalConnection *connection = (GdkInternalConnection *)data;
1467
1468   GDK_THREADS_ENTER ();
1469
1470   XProcessInternalConnection ((Display*)connection->display, connection->fd);
1471
1472   GDK_THREADS_LEAVE ();
1473
1474   return TRUE;
1475 }
1476
1477 gulong
1478 _gdk_windowing_window_get_next_serial (GdkDisplay *display)
1479 {
1480   return NextRequest (GDK_DISPLAY_XDISPLAY (display));
1481 }
1482
1483
1484 static GdkInternalConnection *
1485 gdk_add_connection_handler (Display *display,
1486                             guint    fd)
1487 {
1488   GIOChannel *io_channel;
1489   GdkInternalConnection *connection;
1490
1491   connection = g_new (GdkInternalConnection, 1);
1492
1493   connection->fd = fd;
1494   connection->display = display;
1495   
1496   io_channel = g_io_channel_unix_new (fd);
1497   
1498   connection->source = g_io_create_watch (io_channel, G_IO_IN);
1499   g_source_set_callback (connection->source,
1500                          (GSourceFunc)process_internal_connection, connection, NULL);
1501   g_source_attach (connection->source, NULL);
1502   
1503   g_io_channel_unref (io_channel);
1504   
1505   return connection;
1506 }
1507
1508 static void
1509 gdk_remove_connection_handler (GdkInternalConnection *connection)
1510 {
1511   g_source_destroy (connection->source);
1512   g_free (connection);
1513 }
1514
1515 static void
1516 gdk_internal_connection_watch (Display  *display,
1517                                XPointer  arg,
1518                                gint      fd,
1519                                gboolean  opening,
1520                                XPointer *watch_data)
1521 {
1522   if (opening)
1523     *watch_data = (XPointer)gdk_add_connection_handler (display, fd);
1524   else
1525     gdk_remove_connection_handler ((GdkInternalConnection *)*watch_data);
1526 }
1527 #endif /* HAVE_X11R6 */
1528
1529 /**
1530  * gdk_display_get_name:
1531  * @display: a #GdkDisplay
1532  *
1533  * Gets the name of the display.
1534  * 
1535  * Returns: a string representing the display name. This string is owned
1536  * by GDK and should not be modified or freed.
1537  * 
1538  * Since: 2.2
1539  */
1540 G_CONST_RETURN gchar *
1541 gdk_display_get_name (GdkDisplay *display)
1542 {
1543   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1544   
1545   return (gchar *) DisplayString (GDK_DISPLAY_X11 (display)->xdisplay);
1546 }
1547
1548 /**
1549  * gdk_display_get_n_screens:
1550  * @display: a #GdkDisplay
1551  *
1552  * Gets the number of screen managed by the @display.
1553  * 
1554  * Returns: number of screens.
1555  * 
1556  * Since: 2.2
1557  */
1558 gint
1559 gdk_display_get_n_screens (GdkDisplay *display)
1560 {
1561   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
1562   
1563   return ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay);
1564 }
1565
1566 /**
1567  * gdk_display_get_screen:
1568  * @display: a #GdkDisplay
1569  * @screen_num: the screen number
1570  *
1571  * Returns a screen object for one of the screens of the display.
1572  *
1573  * Returns: (transfer none): the #GdkScreen object
1574  *
1575  * Since: 2.2
1576  */
1577 GdkScreen *
1578 gdk_display_get_screen (GdkDisplay *display, 
1579                         gint        screen_num)
1580 {
1581   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1582   g_return_val_if_fail (ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay) > screen_num, NULL);
1583   
1584   return GDK_DISPLAY_X11 (display)->screens[screen_num];
1585 }
1586
1587 /**
1588  * gdk_display_get_default_screen:
1589  * @display: a #GdkDisplay
1590  *
1591  * Get the default #GdkScreen for @display.
1592  * 
1593  * Returns: (transfer none): the default #GdkScreen object for @display
1594  *
1595  * Since: 2.2
1596  */
1597 GdkScreen *
1598 gdk_display_get_default_screen (GdkDisplay *display)
1599 {
1600   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1601   
1602   return GDK_DISPLAY_X11 (display)->default_screen;
1603 }
1604
1605 gboolean
1606 _gdk_x11_display_is_root_window (GdkDisplay *display,
1607                                  Window      xroot_window)
1608 {
1609   GdkDisplayX11 *display_x11;
1610   gint i;
1611   
1612   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1613   
1614   display_x11 = GDK_DISPLAY_X11 (display);
1615   
1616   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1617     {
1618       if (GDK_SCREEN_XROOTWIN (display_x11->screens[i]) == xroot_window)
1619         return TRUE;
1620     }
1621   return FALSE;
1622 }
1623
1624 struct XPointerUngrabInfo {
1625   GdkDisplay *display;
1626   guint32 time;
1627 };
1628
1629 static void
1630 device_ungrab_callback (GdkDisplay *display,
1631                         gpointer    data,
1632                         gulong      serial)
1633 {
1634   GdkDevice *device = data;
1635
1636   _gdk_display_device_grab_update (display, device, serial);
1637 }
1638
1639
1640 #define XSERVER_TIME_IS_LATER(time1, time2)                        \
1641   ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) ||  \
1642     (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 ))     \
1643   )
1644
1645 /**
1646  * gdk_device_ungrab:
1647  * @device: a #GdkDevice
1648  * @time_: a timestap (e.g. %GDK_CURRENT_TIME).
1649  *
1650  * Release any grab on @device.
1651  *
1652  * Since: 3.0
1653  */
1654 void
1655 gdk_device_ungrab (GdkDevice  *device,
1656                    guint32     time_)
1657 {
1658   GdkDisplay *display;
1659   Display *xdisplay;
1660   GdkDeviceGrabInfo *grab;
1661   unsigned long serial;
1662
1663   g_return_if_fail (GDK_IS_DEVICE (device));
1664
1665   display = gdk_device_get_display (device);
1666   xdisplay = GDK_DISPLAY_XDISPLAY (display);
1667
1668   serial = NextRequest (xdisplay);
1669
1670   GDK_DEVICE_GET_CLASS (device)->ungrab (device, time_);
1671   XFlush (xdisplay);
1672
1673   grab = _gdk_display_get_last_device_grab (display, device);
1674   if (grab &&
1675       (time_ == GDK_CURRENT_TIME ||
1676        grab->time == GDK_CURRENT_TIME ||
1677        !XSERVER_TIME_IS_LATER (grab->time, time_)))
1678     {
1679       grab->serial_end = serial;
1680       _gdk_x11_roundtrip_async (display,
1681                                 device_ungrab_callback,
1682                                 device);
1683     }
1684 }
1685
1686 /**
1687  * gdk_display_beep:
1688  * @display: a #GdkDisplay
1689  *
1690  * Emits a short beep on @display
1691  *
1692  * Since: 2.2
1693  */
1694 void
1695 gdk_display_beep (GdkDisplay *display)
1696 {
1697   g_return_if_fail (GDK_IS_DISPLAY (display));
1698
1699 #ifdef HAVE_XKB
1700   XkbBell (GDK_DISPLAY_XDISPLAY (display), None, 0, None);
1701 #else
1702   XBell (GDK_DISPLAY_XDISPLAY (display), 0);
1703 #endif
1704 }
1705
1706 /**
1707  * gdk_display_sync:
1708  * @display: a #GdkDisplay
1709  *
1710  * Flushes any requests queued for the windowing system and waits until all
1711  * requests have been handled. This is often used for making sure that the
1712  * display is synchronized with the current state of the program. Calling
1713  * gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors
1714  * generated from earlier requests are handled before the error trap is 
1715  * removed.
1716  *
1717  * This is most useful for X11. On windowing systems where requests are
1718  * handled synchronously, this function will do nothing.
1719  *
1720  * Since: 2.2
1721  */
1722 void
1723 gdk_display_sync (GdkDisplay *display)
1724 {
1725   g_return_if_fail (GDK_IS_DISPLAY (display));
1726   
1727   XSync (GDK_DISPLAY_XDISPLAY (display), False);
1728 }
1729
1730 /**
1731  * gdk_display_flush:
1732  * @display: a #GdkDisplay
1733  *
1734  * Flushes any requests queued for the windowing system; this happens automatically
1735  * when the main loop blocks waiting for new events, but if your application
1736  * is drawing without returning control to the main loop, you may need
1737  * to call this function explicitely. A common case where this function
1738  * needs to be called is when an application is executing drawing commands
1739  * from a thread other than the thread where the main loop is running.
1740  *
1741  * This is most useful for X11. On windowing systems where requests are
1742  * handled synchronously, this function will do nothing.
1743  *
1744  * Since: 2.4
1745  */
1746 void 
1747 gdk_display_flush (GdkDisplay *display)
1748 {
1749   g_return_if_fail (GDK_IS_DISPLAY (display));
1750
1751   if (!display->closed)
1752     XFlush (GDK_DISPLAY_XDISPLAY (display));
1753 }
1754
1755 /**
1756  * gdk_display_get_default_group:
1757  * @display: a #GdkDisplay
1758  * 
1759  * Returns the default group leader window for all toplevel windows
1760  * on @display. This window is implicitly created by GDK. 
1761  * See gdk_window_set_group().
1762  * 
1763  * Return value: (transfer none): The default group leader window
1764  * for @display
1765  *
1766  * Since: 2.4
1767  **/
1768 GdkWindow *
1769 gdk_display_get_default_group (GdkDisplay *display)
1770 {
1771   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1772
1773   return GDK_DISPLAY_X11 (display)->leader_gdk_window;
1774 }
1775
1776 /**
1777  * gdk_x11_display_grab:
1778  * @display: a #GdkDisplay 
1779  * 
1780  * Call XGrabServer() on @display. 
1781  * To ungrab the display again, use gdk_x11_display_ungrab(). 
1782  *
1783  * gdk_x11_display_grab()/gdk_x11_display_ungrab() calls can be nested.
1784  *
1785  * Since: 2.2
1786  **/
1787 void
1788 gdk_x11_display_grab (GdkDisplay *display)
1789 {
1790   GdkDisplayX11 *display_x11;
1791   
1792   g_return_if_fail (GDK_IS_DISPLAY (display));
1793   
1794   display_x11 = GDK_DISPLAY_X11 (display);
1795   
1796   if (display_x11->grab_count == 0)
1797     XGrabServer (display_x11->xdisplay);
1798   display_x11->grab_count++;
1799 }
1800
1801 /**
1802  * gdk_x11_display_ungrab:
1803  * @display: a #GdkDisplay
1804  * 
1805  * Ungrab @display after it has been grabbed with 
1806  * gdk_x11_display_grab(). 
1807  *
1808  * Since: 2.2
1809  **/
1810 void
1811 gdk_x11_display_ungrab (GdkDisplay *display)
1812 {
1813   GdkDisplayX11 *display_x11;
1814   
1815   g_return_if_fail (GDK_IS_DISPLAY (display));
1816   
1817   display_x11 = GDK_DISPLAY_X11 (display);;
1818   g_return_if_fail (display_x11->grab_count > 0);
1819   
1820   display_x11->grab_count--;
1821   if (display_x11->grab_count == 0)
1822     {
1823       XUngrabServer (display_x11->xdisplay);
1824       XFlush (display_x11->xdisplay);
1825     }
1826 }
1827
1828 static void
1829 gdk_display_x11_dispose (GObject *object)
1830 {
1831   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (object);
1832   gint           i;
1833
1834   g_list_foreach (display_x11->input_devices, (GFunc) g_object_run_dispose, NULL);
1835
1836   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1837     _gdk_screen_close (display_x11->screens[i]);
1838
1839   if (display_x11->event_source)
1840     {
1841       g_source_destroy (display_x11->event_source);
1842       g_source_unref (display_x11->event_source);
1843       display_x11->event_source = NULL;
1844     }
1845
1846   G_OBJECT_CLASS (_gdk_display_x11_parent_class)->dispose (object);
1847 }
1848
1849 static void
1850 gdk_display_x11_finalize (GObject *object)
1851 {
1852   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (object);
1853   gint           i;
1854
1855   /* Keymap */
1856   if (display_x11->keymap)
1857     g_object_unref (display_x11->keymap);
1858
1859   /* Free motif Dnd */
1860   if (display_x11->motif_target_lists)
1861     {
1862       for (i = 0; i < display_x11->motif_n_target_lists; i++)
1863         g_list_free (display_x11->motif_target_lists[i]);
1864       g_free (display_x11->motif_target_lists);
1865     }
1866
1867   _gdk_x11_cursor_display_finalize (GDK_DISPLAY_OBJECT(display_x11));
1868
1869   /* Atom Hashtable */
1870   g_hash_table_destroy (display_x11->atom_from_virtual);
1871   g_hash_table_destroy (display_x11->atom_to_virtual);
1872
1873   /* Leader Window */
1874   XDestroyWindow (display_x11->xdisplay, display_x11->leader_window);
1875
1876   /* list of filters for client messages */
1877   g_list_foreach (display_x11->client_filters, (GFunc) g_free, NULL);
1878   g_list_free (display_x11->client_filters);
1879
1880   /* List of event window extraction functions */
1881   g_slist_foreach (display_x11->event_types, (GFunc)g_free, NULL);
1882   g_slist_free (display_x11->event_types);
1883
1884   /* input GdkDevice list */
1885   g_list_foreach (display_x11->input_devices, (GFunc) g_object_unref, NULL);
1886   g_list_free (display_x11->input_devices);
1887
1888   /* input GdkWindow list */
1889   g_list_foreach (display_x11->input_windows, (GFunc) g_free, NULL);
1890   g_list_free (display_x11->input_windows);
1891
1892   /* Free all GdkScreens */
1893   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
1894     g_object_unref (display_x11->screens[i]);
1895   g_free (display_x11->screens);
1896
1897   g_free (display_x11->startup_notification_id);
1898
1899   /* X ID hashtable */
1900   g_hash_table_destroy (display_x11->xid_ht);
1901
1902   XCloseDisplay (display_x11->xdisplay);
1903
1904   /* error traps */
1905   while (display_x11->error_traps != NULL)
1906     {
1907       GdkErrorTrap *trap = display_x11->error_traps->data;
1908
1909       display_x11->error_traps =
1910         g_slist_delete_link (display_x11->error_traps,
1911                              display_x11->error_traps);
1912
1913       if (trap->end_sequence == 0)
1914         g_warning ("Display finalized with an unpopped error trap");
1915
1916       g_slice_free (GdkErrorTrap, trap);
1917     }
1918
1919   G_OBJECT_CLASS (_gdk_display_x11_parent_class)->finalize (object);
1920 }
1921
1922 /**
1923  * gdk_x11_lookup_xdisplay:
1924  * @xdisplay: a pointer to an X Display
1925  * 
1926  * Find the #GdkDisplay corresponding to @display, if any exists.
1927  * 
1928  * Return value: (transfer none): the #GdkDisplay, if found, otherwise %NULL.
1929  *
1930  * Since: 2.2
1931  **/
1932 GdkDisplay *
1933 gdk_x11_lookup_xdisplay (Display *xdisplay)
1934 {
1935   GSList *tmp_list;
1936
1937   for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
1938     {
1939       if (GDK_DISPLAY_XDISPLAY (tmp_list->data) == xdisplay)
1940         return tmp_list->data;
1941     }
1942   
1943   return NULL;
1944 }
1945
1946 /**
1947  * _gdk_x11_display_screen_for_xrootwin:
1948  * @display: a #GdkDisplay
1949  * @xrootwin: window ID for one of of the screen's of the display.
1950  * 
1951  * Given the root window ID of one of the screen's of a #GdkDisplay,
1952  * finds the screen.
1953  * 
1954  * Return value: the #GdkScreen corresponding to @xrootwin, or %NULL.
1955  **/
1956 GdkScreen *
1957 _gdk_x11_display_screen_for_xrootwin (GdkDisplay *display,
1958                                       Window      xrootwin)
1959 {
1960   gint i;
1961
1962   for (i = 0; i < ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay); i++)
1963     {
1964       GdkScreen *screen = gdk_display_get_screen (display, i);
1965       if (GDK_SCREEN_XROOTWIN (screen) == xrootwin)
1966         return screen;
1967     }
1968
1969   return NULL;
1970 }
1971
1972 /**
1973  * gdk_x11_display_get_xdisplay:
1974  * @display: a #GdkDisplay
1975  * @returns: an X display.
1976  *
1977  * Returns the X display of a #GdkDisplay.
1978  *
1979  * Since: 2.2
1980  */
1981 Display *
1982 gdk_x11_display_get_xdisplay (GdkDisplay *display)
1983 {
1984   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1985   return GDK_DISPLAY_X11 (display)->xdisplay;
1986 }
1987
1988 void
1989 _gdk_windowing_set_default_display (GdkDisplay *display)
1990 {
1991   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1992   const gchar *startup_id;
1993   
1994   if (!display)
1995     return;
1996
1997   g_free (display_x11->startup_notification_id);
1998   display_x11->startup_notification_id = NULL;
1999   
2000   startup_id = g_getenv ("DESKTOP_STARTUP_ID");
2001   if (startup_id && *startup_id != '\0')
2002     {
2003       if (!g_utf8_validate (startup_id, -1, NULL))
2004         g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
2005       else
2006         gdk_x11_display_set_startup_notification_id (display, startup_id);
2007       
2008       /* Clear the environment variable so it won't be inherited by
2009        * child processes and confuse things.  
2010        */
2011       g_unsetenv ("DESKTOP_STARTUP_ID");
2012     }
2013 }
2014
2015 static void
2016 broadcast_xmessage (GdkDisplay *display,
2017                     const char *message_type,
2018                     const char *message_type_begin,
2019                     const char *message)
2020 {
2021   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
2022   GdkScreen *screen = gdk_display_get_default_screen (display);
2023   GdkWindow *root_window = gdk_screen_get_root_window (screen);
2024   Window xroot_window = GDK_WINDOW_XID (root_window);
2025   
2026   Atom type_atom;
2027   Atom type_atom_begin;
2028   Window xwindow;
2029
2030   if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
2031     return;
2032
2033   {
2034     XSetWindowAttributes attrs;
2035
2036     attrs.override_redirect = True;
2037     attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
2038
2039     xwindow =
2040       XCreateWindow (xdisplay,
2041                      xroot_window,
2042                      -100, -100, 1, 1,
2043                      0,
2044                      CopyFromParent,
2045                      CopyFromParent,
2046                      (Visual *)CopyFromParent,
2047                      CWOverrideRedirect | CWEventMask,
2048                      &attrs);
2049   }
2050
2051   type_atom = gdk_x11_get_xatom_by_name_for_display (display,
2052                                                      message_type);
2053   type_atom_begin = gdk_x11_get_xatom_by_name_for_display (display,
2054                                                            message_type_begin);
2055   
2056   {
2057     XClientMessageEvent xclient;
2058     const char *src;
2059     const char *src_end;
2060     char *dest;
2061     char *dest_end;
2062     
2063                 memset(&xclient, 0, sizeof (xclient));
2064     xclient.type = ClientMessage;
2065     xclient.message_type = type_atom_begin;
2066     xclient.display =xdisplay;
2067     xclient.window = xwindow;
2068     xclient.format = 8;
2069
2070     src = message;
2071     src_end = message + strlen (message) + 1; /* +1 to include nul byte */
2072     
2073     while (src != src_end)
2074       {
2075         dest = &xclient.data.b[0];
2076         dest_end = dest + 20;        
2077         
2078         while (dest != dest_end &&
2079                src != src_end)
2080           {
2081             *dest = *src;
2082             ++dest;
2083             ++src;
2084           }
2085
2086         while (dest != dest_end)
2087           {
2088             *dest = 0;
2089             ++dest;
2090           }
2091         
2092         XSendEvent (xdisplay,
2093                     xroot_window,
2094                     False,
2095                     PropertyChangeMask,
2096                     (XEvent *)&xclient);
2097
2098         xclient.message_type = type_atom;
2099       }
2100   }
2101
2102   XDestroyWindow (xdisplay, xwindow);
2103   XFlush (xdisplay);
2104 }
2105
2106 /**
2107  * gdk_x11_display_broadcast_startup_message:
2108  * @display: a #GdkDisplay
2109  * @message_type: startup notification message type ("new", "change",
2110  * or "remove")
2111  * @...: a list of key/value pairs (as strings), terminated by a
2112  * %NULL key. (A %NULL value for a key will cause that key to be
2113  * skipped in the output.)
2114  *
2115  * Sends a startup notification message of type @message_type to
2116  * @display. 
2117  *
2118  * This is a convenience function for use by code that implements the
2119  * freedesktop startup notification specification. Applications should
2120  * not normally need to call it directly. See the <ulink
2121  * url="http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt">Startup
2122  * Notification Protocol specification</ulink> for
2123  * definitions of the message types and keys that can be used.
2124  *
2125  * Since: 2.12
2126  **/
2127 void
2128 gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
2129                                            const char *message_type,
2130                                            ...)
2131 {
2132   GString *message;
2133   va_list ap;
2134   const char *key, *value, *p;
2135
2136   message = g_string_new (message_type);
2137   g_string_append_c (message, ':');
2138
2139   va_start (ap, message_type);
2140   while ((key = va_arg (ap, const char *)))
2141     {
2142       value = va_arg (ap, const char *);
2143       if (!value)
2144         continue;
2145
2146       g_string_append_printf (message, " %s=\"", key);
2147       for (p = value; *p; p++)
2148         {
2149           switch (*p)
2150             {
2151             case ' ':
2152             case '"':
2153             case '\\':
2154               g_string_append_c (message, '\\');
2155               break;
2156             }
2157
2158           g_string_append_c (message, *p);
2159         }
2160       g_string_append_c (message, '\"');
2161     }
2162   va_end (ap);
2163
2164   broadcast_xmessage (display,
2165                       "_NET_STARTUP_INFO",
2166                       "_NET_STARTUP_INFO_BEGIN",
2167                       message->str);
2168
2169   g_string_free (message, TRUE);
2170 }
2171
2172 /**
2173  * gdk_notify_startup_complete:
2174  * 
2175  * Indicates to the GUI environment that the application has finished
2176  * loading. If the applications opens windows, this function is
2177  * normally called after opening the application's initial set of
2178  * windows.
2179  * 
2180  * GTK+ will call this function automatically after opening the first
2181  * #GtkWindow unless gtk_window_set_auto_startup_notification() is called 
2182  * to disable that feature.
2183  *
2184  * Since: 2.2
2185  **/
2186 void
2187 gdk_notify_startup_complete (void)
2188 {
2189   GdkDisplay *display;
2190   GdkDisplayX11 *display_x11;
2191
2192   display = gdk_display_get_default ();
2193   if (!display)
2194     return;
2195   
2196   display_x11 = GDK_DISPLAY_X11 (display);
2197
2198   if (display_x11->startup_notification_id == NULL)
2199     return;
2200
2201   gdk_notify_startup_complete_with_id (display_x11->startup_notification_id);
2202 }
2203
2204 /**
2205  * gdk_notify_startup_complete_with_id:
2206  * @startup_id: a startup-notification identifier, for which notification
2207  *              process should be completed
2208  * 
2209  * Indicates to the GUI environment that the application has finished
2210  * loading, using a given identifier.
2211  * 
2212  * GTK+ will call this function automatically for #GtkWindow with custom
2213  * startup-notification identifier unless
2214  * gtk_window_set_auto_startup_notification() is called to disable
2215  * that feature.
2216  *
2217  * Since: 2.12
2218  **/
2219 void
2220 gdk_notify_startup_complete_with_id (const gchar* startup_id)
2221 {
2222   GdkDisplay *display;
2223
2224   display = gdk_display_get_default ();
2225   if (!display)
2226     return;
2227
2228   gdk_x11_display_broadcast_startup_message (display, "remove",
2229                                              "ID", startup_id,
2230                                              NULL);
2231 }
2232
2233 /**
2234  * gdk_display_supports_selection_notification:
2235  * @display: a #GdkDisplay
2236  * 
2237  * Returns whether #GdkEventOwnerChange events will be 
2238  * sent when the owner of a selection changes.
2239  * 
2240  * Return value: whether #GdkEventOwnerChange events will 
2241  *               be sent.
2242  *
2243  * Since: 2.6
2244  **/
2245 gboolean 
2246 gdk_display_supports_selection_notification (GdkDisplay *display)
2247 {
2248   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2249
2250   return display_x11->have_xfixes;
2251 }
2252
2253 /**
2254  * gdk_display_request_selection_notification:
2255  * @display: a #GdkDisplay
2256  * @selection: the #GdkAtom naming the selection for which
2257  *             ownership change notification is requested
2258  * 
2259  * Request #GdkEventOwnerChange events for ownership changes
2260  * of the selection named by the given atom.
2261  * 
2262  * Return value: whether #GdkEventOwnerChange events will 
2263  *               be sent.
2264  *
2265  * Since: 2.6
2266  **/
2267 gboolean
2268 gdk_display_request_selection_notification (GdkDisplay *display,
2269                                             GdkAtom     selection)
2270
2271 {
2272 #ifdef HAVE_XFIXES
2273   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2274   Atom atom;
2275
2276   if (display_x11->have_xfixes)
2277     {
2278       atom = gdk_x11_atom_to_xatom_for_display (display, 
2279                                                 selection);
2280       XFixesSelectSelectionInput (display_x11->xdisplay, 
2281                                   display_x11->leader_window,
2282                                   atom,
2283                                   XFixesSetSelectionOwnerNotifyMask |
2284                                   XFixesSelectionWindowDestroyNotifyMask |
2285                                   XFixesSelectionClientCloseNotifyMask);
2286       return TRUE;
2287     }
2288   else
2289 #endif
2290     return FALSE;
2291 }
2292
2293 /**
2294  * gdk_display_supports_clipboard_persistence
2295  * @display: a #GdkDisplay
2296  *
2297  * Returns whether the speicifed display supports clipboard
2298  * persistance; i.e. if it's possible to store the clipboard data after an
2299  * application has quit. On X11 this checks if a clipboard daemon is
2300  * running.
2301  *
2302  * Returns: %TRUE if the display supports clipboard persistance.
2303  *
2304  * Since: 2.6
2305  */
2306 gboolean
2307 gdk_display_supports_clipboard_persistence (GdkDisplay *display)
2308 {
2309   Atom clipboard_manager;
2310
2311   /* It might make sense to cache this */
2312   clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
2313   return XGetSelectionOwner (GDK_DISPLAY_X11 (display)->xdisplay, clipboard_manager) != None;
2314 }
2315
2316 /**
2317  * gdk_display_store_clipboard
2318  * @display:          a #GdkDisplay
2319  * @clipboard_window: a #GdkWindow belonging to the clipboard owner
2320  * @time_:            a timestamp
2321  * @targets:          an array of targets that should be saved, or %NULL 
2322  *                    if all available targets should be saved.
2323  * @n_targets:        length of the @targets array
2324  *
2325  * Issues a request to the clipboard manager to store the
2326  * clipboard data. On X11, this is a special program that works
2327  * according to the freedesktop clipboard specification, available at
2328  * <ulink url="http://www.freedesktop.org/Standards/clipboard-manager-spec">
2329  * http://www.freedesktop.org/Standards/clipboard-manager-spec</ulink>.
2330  *
2331  * Since: 2.6
2332  */
2333 void
2334 gdk_display_store_clipboard (GdkDisplay    *display,
2335                              GdkWindow     *clipboard_window,
2336                              guint32        time_,
2337                              const GdkAtom *targets,
2338                              gint           n_targets)
2339 {
2340   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2341   Atom clipboard_manager, save_targets;
2342
2343   g_return_if_fail (GDK_WINDOW_IS_X11 (clipboard_window));
2344
2345   clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
2346   save_targets = gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS");
2347
2348   gdk_error_trap_push ();
2349
2350   if (XGetSelectionOwner (display_x11->xdisplay, clipboard_manager) != None)
2351     {
2352       Atom property_name = None;
2353       Atom *xatoms;
2354       int i;
2355       
2356       if (n_targets > 0)
2357         {
2358           property_name = gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property);
2359
2360           xatoms = g_new (Atom, n_targets);
2361           for (i = 0; i < n_targets; i++)
2362             xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, targets[i]);
2363
2364           XChangeProperty (display_x11->xdisplay, GDK_WINDOW_XID (clipboard_window),
2365                            property_name, XA_ATOM,
2366                            32, PropModeReplace, (guchar *)xatoms, n_targets);
2367           g_free (xatoms);
2368
2369         }
2370       
2371       XConvertSelection (display_x11->xdisplay,
2372                          clipboard_manager, save_targets, property_name,
2373                          GDK_WINDOW_XID (clipboard_window), time_);
2374       
2375     }
2376   gdk_error_trap_pop_ignored ();
2377
2378 }
2379
2380 /**
2381  * gdk_x11_display_get_user_time:
2382  * @display: a #GdkDisplay
2383  *
2384  * Returns the timestamp of the last user interaction on 
2385  * @display. The timestamp is taken from events caused
2386  * by user interaction such as key presses or pointer 
2387  * movements. See gdk_x11_window_set_user_time().
2388  *
2389  * Returns: the timestamp of the last user interaction 
2390  *
2391  * Since: 2.8
2392  */
2393 guint32
2394 gdk_x11_display_get_user_time (GdkDisplay *display)
2395 {
2396   return GDK_DISPLAY_X11 (display)->user_time;
2397 }
2398
2399 /**
2400  * gdk_display_supports_shapes:
2401  * @display: a #GdkDisplay
2402  *
2403  * Returns %TRUE if gdk_window_shape_combine_mask() can
2404  * be used to create shaped windows on @display.
2405  *
2406  * Returns: %TRUE if shaped windows are supported 
2407  *
2408  * Since: 2.10
2409  */
2410 gboolean 
2411 gdk_display_supports_shapes (GdkDisplay *display)
2412 {
2413   return GDK_DISPLAY_X11 (display)->have_shapes;
2414 }
2415
2416 /**
2417  * gdk_display_supports_input_shapes:
2418  * @display: a #GdkDisplay
2419  *
2420  * Returns %TRUE if gdk_window_input_shape_combine_mask() can
2421  * be used to modify the input shape of windows on @display.
2422  *
2423  * Returns: %TRUE if windows with modified input shape are supported 
2424  *
2425  * Since: 2.10
2426  */
2427 gboolean 
2428 gdk_display_supports_input_shapes (GdkDisplay *display)
2429 {
2430   return GDK_DISPLAY_X11 (display)->have_input_shapes;
2431 }
2432
2433
2434 /**
2435  * gdk_x11_display_get_startup_notification_id:
2436  * @display: a #GdkDisplay
2437  *
2438  * Gets the startup notification ID for a display.
2439  * 
2440  * Returns: the startup notification ID for @display
2441  *
2442  * Since: 2.12
2443  */
2444 G_CONST_RETURN gchar *
2445 gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
2446 {
2447   return GDK_DISPLAY_X11 (display)->startup_notification_id;
2448 }
2449
2450 /**
2451  * gdk_x11_display_set_startup_notification_id:
2452  * @display: a #GdkDisplay
2453  * @startup_id: the startup notification ID (must be valid utf8)
2454  *
2455  * Sets the startup notification ID for a display.
2456  *
2457  * This is usually taken from the value of the DESKTOP_STARTUP_ID
2458  * environment variable, but in some cases (such as the application not
2459  * being launched using exec()) it can come from other sources.
2460  *
2461  * If the ID contains the string "_TIME" then the portion following that
2462  * string is taken to be the X11 timestamp of the event that triggered
2463  * the application to be launched and the GDK current event time is set
2464  * accordingly.
2465  *
2466  * The startup ID is also what is used to signal that the startup is
2467  * complete (for example, when opening a window or when calling
2468  * gdk_notify_startup_complete()).
2469  *
2470  * Since: 3.0
2471  **/
2472 void
2473 gdk_x11_display_set_startup_notification_id (GdkDisplay  *display,
2474                                              const gchar *startup_id)
2475 {
2476   GdkDisplayX11 *display_x11;
2477   gchar *time_str;
2478
2479   display_x11 = GDK_DISPLAY_X11 (display);
2480
2481   g_free (display_x11->startup_notification_id);
2482   display_x11->startup_notification_id = g_strdup (startup_id);
2483
2484   /* Find the launch time from the startup_id, if it's there.  Newer spec
2485    * states that the startup_id is of the form <unique>_TIME<timestamp>
2486    */
2487   time_str = g_strrstr (startup_id, "_TIME");
2488   if (time_str != NULL)
2489     {
2490       gulong retval;
2491       gchar *end;
2492       errno = 0;
2493
2494       /* Skip past the "_TIME" part */
2495       time_str += 5;
2496
2497       retval = strtoul (time_str, &end, 0);
2498       if (end != time_str && errno == 0)
2499         display_x11->user_time = retval;
2500     }
2501
2502   /* Set the startup id on the leader window so it
2503    * applies to all windows we create on this display
2504    */
2505   XChangeProperty (display_x11->xdisplay,
2506                    display_x11->leader_window,
2507                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
2508                    gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2509                    PropModeReplace,
2510                    (guchar *)startup_id, strlen (startup_id));
2511 }
2512
2513 /**
2514  * gdk_display_supports_composite:
2515  * @display: a #GdkDisplay
2516  *
2517  * Returns %TRUE if gdk_window_set_composited() can be used
2518  * to redirect drawing on the window using compositing.
2519  *
2520  * Currently this only works on X11 with XComposite and
2521  * XDamage extensions available.
2522  *
2523  * Returns: %TRUE if windows may be composited.
2524  *
2525  * Since: 2.12
2526  */
2527 gboolean
2528 gdk_display_supports_composite (GdkDisplay *display)
2529 {
2530   GdkDisplayX11 *x11_display = GDK_DISPLAY_X11 (display);
2531
2532   return x11_display->have_xcomposite &&
2533          x11_display->have_xdamage &&
2534          x11_display->have_xfixes;
2535 }
2536
2537 /**
2538  * gdk_display_list_devices:
2539  * @display: a #GdkDisplay
2540  *
2541  * Returns the list of available input devices attached to @display.
2542  * The list is statically allocated and should not be freed.
2543  *
2544  * Return value: (transfer none) (element-type GdkDevice):
2545  *     a list of #GdkDevice
2546  *
2547  * Since: 2.2
2548  *
2549  * Deprecated: 3.0: Use gdk_device_manager_list_devices() instead.
2550  **/
2551 GList *
2552 gdk_display_list_devices (GdkDisplay *display)
2553 {
2554   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
2555
2556   return GDK_DISPLAY_X11 (display)->input_devices;
2557 }
2558
2559 /**
2560  * gdk_event_send_client_message_for_display:
2561  * @display: the #GdkDisplay for the window where the message is to be sent.
2562  * @event: the #GdkEvent to send, which should be a #GdkEventClient.
2563  * @winid: the window to send the client message to.
2564  *
2565  * On X11, sends an X ClientMessage event to a given window. On
2566  * Windows, sends a message registered with the name
2567  * GDK_WIN32_CLIENT_MESSAGE.
2568  *
2569  * This could be used for communicating between different
2570  * applications, though the amount of data is limited to 20 bytes on
2571  * X11, and to just four bytes on Windows.
2572  *
2573  * Returns: non-zero on success.
2574  *
2575  * Since: 2.2
2576  */
2577 gboolean
2578 gdk_event_send_client_message_for_display (GdkDisplay     *display,
2579                                            GdkEvent       *event,
2580                                            GdkNativeWindow winid)
2581 {
2582   XEvent sev;
2583
2584   g_return_val_if_fail(event != NULL, FALSE);
2585
2586   /* Set up our event to send, with the exception of its target window */
2587   sev.xclient.type = ClientMessage;
2588   sev.xclient.display = GDK_DISPLAY_XDISPLAY (display);
2589   sev.xclient.format = event->client.data_format;
2590   sev.xclient.window = winid;
2591   memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
2592   sev.xclient.message_type = gdk_x11_atom_to_xatom_for_display (display, event->client.message_type);
2593
2594   return _gdk_send_xevent (display, winid, False, NoEventMask, &sev);
2595 }
2596
2597 /**
2598  * gdk_display_add_client_message_filter:
2599  * @display: a #GdkDisplay for which this message filter applies
2600  * @message_type: the type of ClientMessage events to receive.
2601  *   This will be checked against the @message_type field
2602  *   of the XClientMessage event struct.
2603  * @func: the function to call to process the event.
2604  * @data: user data to pass to @func.
2605  *
2606  * Adds a filter to be called when X ClientMessage events are received.
2607  * See gdk_window_add_filter() if you are interested in filtering other
2608  * types of events.
2609  *
2610  * Since: 2.2
2611  **/
2612 void
2613 gdk_display_add_client_message_filter (GdkDisplay   *display,
2614                                        GdkAtom       message_type,
2615                                        GdkFilterFunc func,
2616                                        gpointer      data)
2617 {
2618   GdkClientFilter *filter;
2619   g_return_if_fail (GDK_IS_DISPLAY (display));
2620   filter = g_new (GdkClientFilter, 1);
2621
2622   filter->type = message_type;
2623   filter->function = func;
2624   filter->data = data;
2625
2626   GDK_DISPLAY_X11(display)->client_filters =
2627     g_list_append (GDK_DISPLAY_X11 (display)->client_filters,
2628                    filter);
2629 }
2630
2631 /**
2632  * gdk_add_client_message_filter:
2633  * @message_type: the type of ClientMessage events to receive. This will be
2634  *     checked against the <structfield>message_type</structfield> field of the
2635  *     XClientMessage event struct.
2636  * @func: the function to call to process the event.
2637  * @data: user data to pass to @func.
2638  *
2639  * Adds a filter to the default display to be called when X ClientMessage events
2640  * are received. See gdk_display_add_client_message_filter().
2641  **/
2642 void
2643 gdk_add_client_message_filter (GdkAtom       message_type,
2644                                GdkFilterFunc func,
2645                                gpointer      data)
2646 {
2647   gdk_display_add_client_message_filter (gdk_display_get_default (),
2648                                          message_type, func, data);
2649 }
2650
2651 /*
2652  *--------------------------------------------------------------
2653  * gdk_flush
2654  *
2655  *   Flushes the Xlib output buffer and then waits
2656  *   until all requests have been received and processed
2657  *   by the X server. The only real use for this function
2658  *   is in dealing with XShm.
2659  *
2660  * Arguments:
2661  *
2662  * Results:
2663  *
2664  * Side effects:
2665  *
2666  *--------------------------------------------------------------
2667  */
2668 void
2669 gdk_flush (void)
2670 {
2671   GSList *tmp_list = _gdk_displays;
2672
2673   while (tmp_list)
2674     {
2675       XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False);
2676       tmp_list = tmp_list->next;
2677     }
2678 }
2679
2680 /**
2681  * gdk_x11_register_standard_event_type:
2682  * @display: a #GdkDisplay
2683  * @event_base: first event type code to register
2684  * @n_events: number of event type codes to register
2685  *
2686  * Registers interest in receiving extension events with type codes
2687  * between @event_base and <literal>event_base + n_events - 1</literal>.
2688  * The registered events must have the window field in the same place
2689  * as core X events (this is not the case for e.g. XKB extension events).
2690  *
2691  * If an event type is registered, events of this type will go through
2692  * global and window-specific filters (see gdk_window_add_filter()).
2693  * Unregistered events will only go through global filters.
2694  * GDK may register the events of some X extensions on its own.
2695  *
2696  * This function should only be needed in unusual circumstances, e.g.
2697  * when filtering XInput extension events on the root window.
2698  *
2699  * Since: 2.4
2700  **/
2701 void
2702 gdk_x11_register_standard_event_type (GdkDisplay *display,
2703                                       gint        event_base,
2704                                       gint        n_events)
2705 {
2706   GdkEventTypeX11 *event_type;
2707   GdkDisplayX11 *display_x11;
2708
2709   display_x11 = GDK_DISPLAY_X11 (display);
2710   event_type = g_new (GdkEventTypeX11, 1);
2711
2712   event_type->base = event_base;
2713   event_type->n_events = n_events;
2714
2715   display_x11->event_types = g_slist_prepend (display_x11->event_types, event_type);
2716 }
2717
2718 /* compare X sequence numbers handling wraparound */
2719 #define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
2720
2721 /* delivers an error event from the error handler in gdkmain-x11.c */
2722 void
2723 _gdk_x11_display_error_event (GdkDisplay  *display,
2724                               XErrorEvent *error)
2725 {
2726   GdkDisplayX11 *display_x11;
2727   GSList *tmp_list;
2728   gboolean ignore;
2729
2730   display_x11 = GDK_DISPLAY_X11 (display);
2731
2732   ignore = FALSE;
2733   for (tmp_list = display_x11->error_traps;
2734        tmp_list != NULL;
2735        tmp_list = tmp_list->next)
2736     {
2737       GdkErrorTrap *trap;
2738
2739       trap = tmp_list->data;
2740
2741       if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
2742           (trap->end_sequence == 0 ||
2743            SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
2744         {
2745           ignore = TRUE;
2746           trap->error_code = error->error_code;
2747           break; /* only innermost trap gets the error code */
2748         }
2749     }
2750
2751   if (!ignore)
2752     {
2753       gchar buf[64];
2754       gchar *msg;
2755
2756       XGetErrorText (display_x11->xdisplay, error->error_code, buf, 63);
2757
2758       msg =
2759         g_strdup_printf ("The program '%s' received an X Window System error.\n"
2760                          "This probably reflects a bug in the program.\n"
2761                          "The error was '%s'.\n"
2762                          "  (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
2763                          "  (Note to programmers: normally, X errors are reported asynchronously;\n"
2764                          "   that is, you will receive the error a while after causing it.\n"
2765                          "   To debug your program, run it with the --sync command line\n"
2766                          "   option to change this behavior. You can then get a meaningful\n"
2767                          "   backtrace from your debugger if you break on the gdk_x_error() function.)",
2768                          g_get_prgname (),
2769                          buf,
2770                          error->serial,
2771                          error->error_code,
2772                          error->request_code,
2773                          error->minor_code);
2774
2775 #ifdef G_ENABLE_DEBUG
2776       g_error ("%s", msg);
2777 #else /* !G_ENABLE_DEBUG */
2778       g_warning ("%s\n", msg);
2779
2780       exit (1);
2781 #endif /* G_ENABLE_DEBUG */
2782     }
2783 }
2784
2785 static void
2786 delete_outdated_error_traps (GdkDisplayX11 *display_x11)
2787 {
2788   GSList *tmp_list;
2789   gulong processed_sequence;
2790
2791   processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
2792
2793   tmp_list = display_x11->error_traps;
2794   while (tmp_list != NULL)
2795     {
2796       GdkErrorTrap *trap = tmp_list->data;
2797
2798       if (trap->end_sequence != 0 &&
2799           SEQUENCE_COMPARE (trap->end_sequence, <=, processed_sequence))
2800         {
2801           GSList *free_me = tmp_list;
2802
2803           tmp_list = tmp_list->next;
2804           display_x11->error_traps =
2805             g_slist_delete_link (display_x11->error_traps, free_me);
2806           g_slice_free (GdkErrorTrap, trap);
2807         }
2808       else
2809         {
2810           tmp_list = tmp_list->next;
2811         }
2812     }
2813 }
2814
2815 /**
2816  * gdk_x11_display_error_trap_push:
2817  * @display: a #GdkDisplay
2818  *
2819  * Begins a range of X requests on @display for which X error events
2820  * will be ignored. Unignored errors (when no trap is pushed) will abort
2821  * the application. Use gdk_x11_display_error_trap_pop() or
2822  * gdk_x11_display_error_trap_pop_ignored()to lift a trap pushed
2823  * with this function.
2824  *
2825  * See also gdk_error_trap_push() to push a trap on all displays.
2826  *
2827  * Since: 3.0
2828  */
2829 void
2830 gdk_x11_display_error_trap_push (GdkDisplay *display)
2831 {
2832   GdkDisplayX11 *display_x11;
2833   GdkErrorTrap *trap;
2834
2835   display_x11 = GDK_DISPLAY_X11 (display);
2836
2837   delete_outdated_error_traps (display_x11);
2838
2839   /* set up the Xlib callback to tell us about errors */
2840   _gdk_x11_error_handler_push ();
2841
2842   trap = g_slice_new0 (GdkErrorTrap);
2843
2844   trap->start_sequence = XNextRequest (display_x11->xdisplay);
2845   trap->error_code = Success;
2846
2847   display_x11->error_traps =
2848     g_slist_prepend (display_x11->error_traps, trap);
2849 }
2850
2851 static gint
2852 gdk_x11_display_error_trap_pop_internal (GdkDisplay *display,
2853                                          gboolean    need_code)
2854 {
2855   GdkDisplayX11 *display_x11;
2856   GdkErrorTrap *trap;
2857   GSList *tmp_list;
2858   int result;
2859
2860   display_x11 = GDK_DISPLAY_X11 (display);
2861
2862   g_return_val_if_fail (display_x11->error_traps != NULL, Success);
2863
2864   /* Find the first trap that hasn't been popped already */
2865   trap = NULL; /* quiet gcc */
2866   for (tmp_list = display_x11->error_traps;
2867        tmp_list != NULL;
2868        tmp_list = tmp_list->next)
2869     {
2870       trap = tmp_list->data;
2871
2872       if (trap->end_sequence == 0)
2873         break;
2874     }
2875
2876   g_return_val_if_fail (trap != NULL, Success);
2877   g_assert (trap->end_sequence == 0);
2878
2879   /* May need to sync to fill in trap->error_code if we care about
2880    * getting an error code.
2881    */
2882   if (need_code)
2883     {
2884       gulong processed_sequence;
2885       gulong next_sequence;
2886
2887       next_sequence = XNextRequest (display_x11->xdisplay);
2888       processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
2889
2890       /* If our last request was already processed, there is no point
2891        * in syncing. i.e. if last request was a round trip (or even if
2892        * we got an event with the serial of a non-round-trip)
2893        */
2894       if ((next_sequence - 1) != processed_sequence)
2895         {
2896           XSync (display_x11->xdisplay, False);
2897         }
2898
2899       result = trap->error_code;
2900     }
2901   else
2902     {
2903       result = Success;
2904     }
2905
2906   /* record end of trap, giving us a range of
2907    * error sequences we'll ignore.
2908    */
2909   trap->end_sequence = XNextRequest (display_x11->xdisplay);
2910
2911   /* remove the Xlib callback */
2912   _gdk_x11_error_handler_pop ();
2913
2914   /* we may already be outdated */
2915   delete_outdated_error_traps (display_x11);
2916
2917   return result;
2918 }
2919
2920 /**
2921  * gdk_x11_display_error_trap_pop:
2922  * @display: the display
2923  *
2924  * Pops the error trap pushed by gdk_x11_display_error_trap_push().
2925  * Will XSync() if necessary and will always block until
2926  * the error is known to have occurred or not occurred,
2927  * so the error code can be returned.
2928  *
2929  * If you don't need to use the return value,
2930  * gdk_x11_display_error_trap_pop_ignored() would be more efficient.
2931  *
2932  * See gdk_error_trap_pop() for the all-displays-at-once
2933  * equivalent.
2934  *
2935  * Since: 3.0
2936  *
2937  * Return value: X error code or 0 on success
2938  */
2939 gint
2940 gdk_x11_display_error_trap_pop (GdkDisplay *display)
2941 {
2942   g_return_val_if_fail (GDK_IS_DISPLAY_X11 (display), Success);
2943
2944   return gdk_x11_display_error_trap_pop_internal (display, TRUE);
2945 }
2946
2947 /**
2948  * gdk_x11_display_error_trap_pop_ignored:
2949  * @display: the display
2950  *
2951  * Pops the error trap pushed by gdk_x11_display_error_trap_push().
2952  * Does not block to see if an error occurred; merely records the
2953  * range of requests to ignore errors for, and ignores those errors
2954  * if they arrive asynchronously.
2955  *
2956  * See gdk_error_trap_pop_ignored() for the all-displays-at-once
2957  * equivalent.
2958  *
2959  * Since: 3.0
2960  */
2961 void
2962 gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
2963 {
2964   g_return_if_fail (GDK_IS_DISPLAY_X11 (display));
2965
2966   gdk_x11_display_error_trap_pop_internal (display, FALSE);
2967 }