]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdisplay-x11.c
Requires glib-2.3.0, pango-1.2.0.
[~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  *
6  * Erwann Chenede <erwann.chenede@sun.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include <config.h>
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <glib.h>
31 #include "gdkx.h"
32 #include "gdkdisplay.h"
33 #include "gdkdisplay-x11.h"
34 #include "gdkscreen.h"
35 #include "gdkscreen-x11.h"
36 #include "gdkinternals.h"
37 #include "gdkinputprivate.h"
38 #include "xsettings-client.h"
39
40 #include <X11/Xatom.h>
41
42 #ifdef HAVE_XKB
43 #include <X11/XKBlib.h>
44 #endif
45
46 static void                 gdk_display_x11_class_init         (GdkDisplayX11Class *class);
47 static void                 gdk_display_x11_dispose            (GObject            *object);
48 static void                 gdk_display_x11_finalize           (GObject            *object);
49
50 #ifdef HAVE_X11R6
51 static void gdk_internal_connection_watch (Display  *display,
52                                            XPointer  arg,
53                                            gint      fd,
54                                            gboolean  opening,
55                                            XPointer *watch_data);
56 #endif /* HAVE_X11R6 */
57
58 static gpointer parent_class = NULL;
59
60 /* Note that we never *directly* use WM_LOCALE_NAME, WM_PROTOCOLS,
61  * but including them here has the side-effect of getting them
62  * into the internal Xlib cache
63  */
64 static const char *const precache_atoms[] = {
65   "UTF8_STRING",
66   "WM_CLIENT_LEADER",
67   "WM_DELETE_WINDOW",
68   "WM_LOCALE_NAME",
69   "WM_PROTOCOLS",
70   "WM_TAKE_FOCUS",
71   "_NET_WM_DESKTOP",
72   "_NET_WM_ICON",
73   "_NET_WM_ICON_NAME",
74   "_NET_WM_NAME",
75   "_NET_WM_PID",
76   "_NET_WM_PING",
77   "_NET_WM_STATE",
78   "_NET_WM_STATE_STICKY",
79   "_NET_WM_STATE_MAXIMIZED_VERT",
80   "_NET_WM_STATE_MAXIMIZED_HORZ",
81   "_NET_WM_STATE_FULLSCREEN",
82   "_NET_WM_WINDOW_TYPE",
83   "_NET_WM_WINDOW_TYPE_NORMAL",
84 };
85
86 GType
87 _gdk_display_x11_get_type (void)
88 {
89   static GType object_type = 0;
90
91   if (!object_type)
92     {
93       static const GTypeInfo object_info =
94         {
95           sizeof (GdkDisplayX11Class),
96           (GBaseInitFunc) NULL,
97           (GBaseFinalizeFunc) NULL,
98           (GClassInitFunc) gdk_display_x11_class_init,
99           NULL,                 /* class_finalize */
100           NULL,                 /* class_data */
101           sizeof (GdkDisplayX11),
102           0,                    /* n_preallocs */
103           (GInstanceInitFunc) NULL,
104         };
105       
106       object_type = g_type_register_static (GDK_TYPE_DISPLAY,
107                                             "GdkDisplayX11",
108                                             &object_info, 0);
109     }
110   
111   return object_type;
112 }
113
114 static void
115 gdk_display_x11_class_init (GdkDisplayX11Class * class)
116 {
117   GObjectClass *object_class = G_OBJECT_CLASS (class);
118   
119   object_class->dispose = gdk_display_x11_dispose;
120   object_class->finalize = gdk_display_x11_finalize;
121   
122   parent_class = g_type_class_peek_parent (class);
123 }
124
125 /**
126  * gdk_display_open:
127  * @display_name: the name of the display to open
128  * @returns: a #GdkDisplay, or %NULL if the display
129  *  could not be opened.
130  *
131  * Opens a display.
132  *
133  * Since: 2.2
134  */
135 GdkDisplay *
136 gdk_display_open (const gchar *display_name)
137 {
138   Display *xdisplay;
139   GdkDisplay *display;
140   GdkDisplayX11 *display_x11;
141   gint argc;
142   gchar **argv;
143   const char *sm_client_id;
144   
145   XClassHint *class_hint;
146   gulong pid;
147   gint i;
148
149   xdisplay = XOpenDisplay (display_name);
150   if (!xdisplay)
151     return NULL;
152   
153   display = g_object_new (GDK_TYPE_DISPLAY_X11, NULL);
154   display_x11 = GDK_DISPLAY_X11 (display);
155
156   display_x11->use_xshm = TRUE;
157   display_x11->xdisplay = xdisplay;
158
159 #ifdef HAVE_X11R6  
160   /* Set up handlers for Xlib internal connections */
161   XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
162 #endif /* HAVE_X11R6 */
163   
164   /* initialize the display's screens */ 
165   display_x11->screens = g_new (GdkScreen *, ScreenCount (display_x11->xdisplay));
166   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
167     display_x11->screens[i] = _gdk_x11_screen_new (display, i);
168
169   /* We need to initialize events after we have the screen
170    * structures in places
171    */
172   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
173     _gdk_x11_events_init_screen (display_x11->screens[i]);
174   
175   /*set the default screen */
176   display_x11->default_screen = display_x11->screens[DefaultScreen (display_x11->xdisplay)];
177   display_x11->leader_window = XCreateSimpleWindow (display_x11->xdisplay,
178                                                     GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window,
179                                                     10, 10, 10, 10, 0, 0, 0);
180   display_x11->leader_window_title_set = FALSE;
181
182   display_x11->gravity_works = GDK_UNKNOWN;
183   display_x11->have_render = GDK_UNKNOWN;
184
185   if (_gdk_synchronize)
186     XSynchronize (display_x11->xdisplay, True);
187   
188   _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
189
190   class_hint = XAllocClassHint();
191   class_hint->res_name = g_get_prgname ();
192   
193   class_hint->res_class = (char *)gdk_get_program_class ();
194   _gdk_get_command_line_args (&argc, &argv);
195   XmbSetWMProperties (display_x11->xdisplay,
196                       display_x11->leader_window,
197                       NULL, NULL, argv, argc, NULL, NULL,
198                       class_hint);
199   XFree (class_hint);
200
201   sm_client_id = _gdk_get_sm_client_id ();
202   if (sm_client_id)
203     _gdk_windowing_display_set_sm_client_id (display, sm_client_id);
204
205   pid = getpid ();
206   XChangeProperty (display_x11->xdisplay,
207                    display_x11->leader_window,
208                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
209                    XA_CARDINAL, 32, PropModeReplace, (guchar *) & pid, 1);
210   
211 #ifdef HAVE_XKB
212   {
213     gint xkb_major = XkbMajorVersion;
214     gint xkb_minor = XkbMinorVersion;
215     if (XkbLibraryVersion (&xkb_major, &xkb_minor))
216       {
217         xkb_major = XkbMajorVersion;
218         xkb_minor = XkbMinorVersion;
219             
220         if (XkbQueryExtension (display_x11->xdisplay, 
221                                NULL, &display_x11->xkb_event_type, NULL,
222                                &xkb_major, &xkb_minor))
223           {
224             Bool detectable_autorepeat_supported;
225             
226             display_x11->use_xkb = TRUE;
227
228             XkbSelectEvents (display_x11->xdisplay,
229                              XkbUseCoreKbd,
230                              XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
231                              XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
232
233             XkbSetDetectableAutoRepeat (display_x11->xdisplay,
234                                         True,
235                                         &detectable_autorepeat_supported);
236
237             GDK_NOTE (MISC, g_message ("Detectable autorepeat %s.",
238                                        detectable_autorepeat_supported ? 
239                                        "supported" : "not supported"));
240             
241             display_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
242           }
243       }
244   }
245 #endif
246
247   _gdk_windowing_image_init (display);
248   _gdk_events_init (display);
249   _gdk_input_init (display);
250   _gdk_dnd_init (display);
251
252   g_signal_emit_by_name (gdk_display_manager_get(),
253                          "display_opened", display);
254
255   return display;
256 }
257
258 #ifdef HAVE_X11R6
259 /*
260  * XLib internal connection handling
261  */
262 typedef struct _GdkInternalConnection GdkInternalConnection;
263
264 struct _GdkInternalConnection
265 {
266   gint           fd;
267   GSource       *source;
268   Display       *display;
269 };
270
271 static gboolean
272 process_internal_connection (GIOChannel  *gioc,
273                              GIOCondition cond,
274                              gpointer     data)
275 {
276   GdkInternalConnection *connection = (GdkInternalConnection *)data;
277
278   GDK_THREADS_ENTER ();
279
280   XProcessInternalConnection ((Display*)connection->display, connection->fd);
281
282   GDK_THREADS_LEAVE ();
283
284   return TRUE;
285 }
286
287 static GdkInternalConnection *
288 gdk_add_connection_handler (Display *display,
289                             guint    fd)
290 {
291   GIOChannel *io_channel;
292   GdkInternalConnection *connection;
293
294   connection = g_new (GdkInternalConnection, 1);
295
296   connection->fd = fd;
297   connection->display = display;
298   
299   io_channel = g_io_channel_unix_new (fd);
300   
301   connection->source = g_io_create_watch (io_channel, G_IO_IN);
302   g_source_set_callback (connection->source,
303                          (GSourceFunc)process_internal_connection, connection, NULL);
304   g_source_attach (connection->source, NULL);
305   
306   g_io_channel_unref (io_channel);
307   
308   return connection;
309 }
310
311 static void
312 gdk_remove_connection_handler (GdkInternalConnection *connection)
313 {
314   g_source_destroy (connection->source);
315   g_free (connection);
316 }
317
318 static void
319 gdk_internal_connection_watch (Display  *display,
320                                XPointer  arg,
321                                gint      fd,
322                                gboolean  opening,
323                                XPointer *watch_data)
324 {
325   if (opening)
326     *watch_data = (XPointer)gdk_add_connection_handler (display, fd);
327   else
328     gdk_remove_connection_handler ((GdkInternalConnection *)*watch_data);
329 }
330 #endif /* HAVE_X11R6 */
331
332 /**
333  * gdk_display_get_name:
334  * @display: a #GdkDisplay
335  *
336  * Gets the name of the display.
337  * 
338  * Returns: a string representing the display name. This string is owned
339  * by GDK and should not be modified or freed.
340  * 
341  * Since: 2.2
342  */
343 G_CONST_RETURN gchar *
344 gdk_display_get_name (GdkDisplay * display)
345 {
346   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
347   
348   return (gchar *) DisplayString (GDK_DISPLAY_X11 (display)->xdisplay);
349 }
350
351 /**
352  * gdk_display_get_n_screens:
353  * @display: a #GdkDisplay
354  *
355  * Gets the number of screen managed by the @display.
356  * 
357  * Returns: number of screens.
358  * 
359  * Since: 2.2
360  */
361 gint
362 gdk_display_get_n_screens (GdkDisplay * display)
363 {
364   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
365   
366   return ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay);
367 }
368
369 /**
370  * gdk_display_get_screen:
371  * @display: a #GdkDisplay
372  * @screen_num: the screen number
373  *
374  * Returns a screen object for one of the screens of the display.
375  *
376  * Returns: the #GdkScreen object
377  *
378  * Since: 2.2
379  */
380 GdkScreen *
381 gdk_display_get_screen (GdkDisplay * display, gint screen_num)
382 {
383   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
384   g_return_val_if_fail (ScreenCount (GDK_DISPLAY_X11 (display)->xdisplay) > screen_num, NULL);
385   
386   return GDK_DISPLAY_X11 (display)->screens[screen_num];
387 }
388
389 /**
390  * gdk_display_get_default_screen:
391  * @display: a #GdkDisplay
392  *
393  * Get the default #GdkScreen for @display.
394  * 
395  * Returns: the default #GdkScreen object for @display
396  *
397  * Since: 2.2
398  */
399 GdkScreen *
400 gdk_display_get_default_screen (GdkDisplay * display)
401 {
402   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
403   
404   return GDK_DISPLAY_X11 (display)->default_screen;
405 }
406
407 gboolean
408 _gdk_x11_display_is_root_window (GdkDisplay *display,
409                                  Window      xroot_window)
410 {
411   GdkDisplayX11 *display_x11;
412   gint i;
413   
414   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
415   
416   display_x11 = GDK_DISPLAY_X11 (display);
417   
418   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
419     {
420       if (GDK_SCREEN_XROOTWIN (display_x11->screens[i]) == xroot_window)
421         return TRUE;
422     }
423   return FALSE;
424 }
425
426 /**
427  * gdk_display_pointer_ungrab:
428  * @display: a #GdkDisplay.
429  * @time_: a timestap (e.g. GDK_CURRENT_TIME).
430  *
431  * Release any pointer grab.
432  *
433  * Since: 2.2
434  */
435 void
436 gdk_display_pointer_ungrab (GdkDisplay *display,
437                             guint32     time)
438 {
439   Display *xdisplay;
440   
441   g_return_if_fail (GDK_IS_DISPLAY (display));
442
443   xdisplay = GDK_DISPLAY_XDISPLAY (display);
444   
445   _gdk_input_ungrab_pointer (display, time);
446   XUngrabPointer (xdisplay, time);
447   XFlush (xdisplay);
448   
449   GDK_DISPLAY_X11 (display)->pointer_xgrab_window = NULL;
450 }
451
452 /**
453  * gdk_display_pointer_is_grabbed:
454  * @display: a #GdkDisplay
455  *
456  * Test if the pointer is grabbed.
457  *
458  * Returns: %TRUE if an active X pointer grab is in effect
459  *
460  * Since: 2.2
461  */
462 gboolean
463 gdk_display_pointer_is_grabbed (GdkDisplay * display)
464 {
465   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
466   
467   return (GDK_DISPLAY_X11 (display)->pointer_xgrab_window != NULL);
468 }
469
470 /**
471  * gdk_display_keyboard_ungrab:
472  * @display: a #GdkDisplay.
473  * @time_: a timestap (e.g #GDK_CURRENT_TIME).
474  *
475  * Release any keyboard grab
476  *
477  * Since: 2.2
478  */
479 void
480 gdk_display_keyboard_ungrab (GdkDisplay *display,
481                              guint32     time)
482 {
483   Display *xdisplay;
484   
485   g_return_if_fail (GDK_IS_DISPLAY (display));
486
487   xdisplay = GDK_DISPLAY_XDISPLAY (display);
488   
489   XUngrabKeyboard (xdisplay, time);
490   XFlush (xdisplay);
491   
492   GDK_DISPLAY_X11 (display)->keyboard_xgrab_window = NULL;
493 }
494
495 /**
496  * gdk_display_beep:
497  * @display: a #GdkDisplay
498  *
499  * Emits a short beep on @display
500  *
501  * Since: 2.2
502  */
503 void
504 gdk_display_beep (GdkDisplay * display)
505 {
506   g_return_if_fail (GDK_IS_DISPLAY (display));
507   
508   XBell (GDK_DISPLAY_XDISPLAY (display), 0);
509 }
510
511 /**
512  * gdk_display_sync:
513  * @display: a #GdkDisplay
514  *
515  * Flushes any requests queued for the windowing system and waits until all
516  * requests have been handled. This is often used for making sure that the
517  * display is synchronized with the current state of the program. Calling
518  * gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors
519  * generated from earlier requests are handled before the error trap is 
520  * removed.
521  *
522  * This is most useful for X11. On windowing systems where requests are
523  * handled synchronously, this function will do nothing.
524  *
525  * Since: 2.2
526  */
527 void
528 gdk_display_sync (GdkDisplay * display)
529 {
530   g_return_if_fail (GDK_IS_DISPLAY (display));
531   
532   XSync (GDK_DISPLAY_XDISPLAY (display), False);
533 }
534
535 /**
536  * gdk_display_flush:
537  * @display: a #GdkDisplay
538  *
539  * Flushes any requests queued for the windowing system; this happens automatically
540  * when the main loop blocks waiting for new events, but if your application
541  * is drawing without returning control to the main loop, you may need
542  * to call this function explicitely. A common case where this function
543  * needs to be called is when an application is executing drawing commands
544  * from a thread other than the thread where the main loop is running.
545  *
546  * This is most useful for X11. On windowing systems where requests are
547  * handled synchronously, this function will do nothing.
548  *
549  * Since: 2.4
550  */
551 void 
552 gdk_display_flush (GdkDisplay *display)
553 {
554   g_return_if_fail (GDK_IS_DISPLAY (display));
555
556   if (!display->closed)
557     XFlush (GDK_DISPLAY_XDISPLAY (display));
558 }
559
560 /**
561  * gdk_x11_display_grab:
562  * @display: a #GdkDisplay 
563  * 
564  * Call XGrabServer() on @display. 
565  * To ungrab the display again, use gdk_x11_display_ungrab(). 
566  *
567  * gdk_x11_display_grab()/gdk_x11_display_ungrab() calls can be nested.
568  *
569  * Since: 2.2
570  **/
571 void
572 gdk_x11_display_grab (GdkDisplay * display)
573 {
574   GdkDisplayX11 *display_x11;
575   
576   g_return_if_fail (GDK_IS_DISPLAY (display));
577   
578   display_x11 = GDK_DISPLAY_X11 (display);
579   
580   if (display_x11->grab_count == 0)
581     XGrabServer (display_x11->xdisplay);
582   display_x11->grab_count++;
583 }
584
585 /**
586  * gdk_x11_display_ungrab:
587  * @display: a #GdkDisplay
588  * 
589  * Ungrab @display after it has been grabbed with 
590  * gdk_x11_display_grab(). 
591  *
592  * Since: 2.2
593  **/
594 void
595 gdk_x11_display_ungrab (GdkDisplay * display)
596 {
597   GdkDisplayX11 *display_x11;
598   
599   g_return_if_fail (GDK_IS_DISPLAY (display));
600   
601   display_x11 = GDK_DISPLAY_X11 (display);;
602   g_return_if_fail (display_x11->grab_count > 0);
603   
604   display_x11->grab_count--;
605   if (display_x11->grab_count == 0)
606     {
607       XUngrabServer (display_x11->xdisplay);
608       XFlush (display_x11->xdisplay);
609     }
610 }
611
612 static void
613 gdk_display_x11_dispose (GObject *object)
614 {
615   GdkDisplayX11 *display_x11;
616   gint i;
617   
618   display_x11 = GDK_DISPLAY_X11 (object);
619   
620   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
621     _gdk_screen_close (display_x11->screens[i]);
622
623   g_source_destroy (display_x11->event_source);
624
625   XCloseDisplay (display_x11->xdisplay);
626   display_x11->xdisplay = NULL;
627
628   G_OBJECT_CLASS (parent_class)->dispose (object);
629 }
630
631 static void
632 gdk_display_x11_finalize (GObject *object)
633 {
634   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (object);
635   int i;
636   GList *tmp;
637   /* FIXME need to write GdkKeymap finalize fct 
638      g_object_unref (display_x11->keymap);
639    */
640   /* Free motif Dnd */
641   if (display_x11->motif_target_lists)
642     {
643       for (i = 0; i < display_x11->motif_n_target_lists; i++)
644         g_list_free (display_x11->motif_target_lists[i]);
645       g_free (display_x11->motif_target_lists);
646     }
647
648   /* Atom Hashtable */
649   g_hash_table_destroy (display_x11->atom_from_virtual);
650   g_hash_table_destroy (display_x11->atom_to_virtual);
651   /* Leader Window */
652   XDestroyWindow (display_x11->xdisplay, display_x11->leader_window);
653   /* list of filters for client messages */
654   g_list_free (display_x11->client_filters);
655   /* List of event window extraction functions */
656   g_slist_foreach (display_x11->event_types, (GFunc)g_free, NULL);
657   g_slist_free (display_x11->event_types);
658   /* X ID hashtable */
659   g_hash_table_destroy (display_x11->xid_ht);
660   /* input GdkDevice list */
661   /* FIXME need to write finalize fct */
662   for (tmp = display_x11->input_devices; tmp; tmp = tmp->next)
663     g_object_unref (tmp->data);
664   g_list_free (display_x11->input_devices);
665   /* input GdkWindow list */
666   for (tmp = display_x11->input_windows; tmp; tmp = tmp->next)
667     g_object_unref (tmp->data);
668   g_list_free (display_x11->input_windows);
669   /* Free all GdkScreens */
670   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
671     g_object_unref (display_x11->screens[i]);
672   g_free (display_x11->screens);
673   g_free (display_x11->startup_notification_id);
674   
675   G_OBJECT_CLASS (parent_class)->finalize (object);
676 }
677
678 /**
679  * gdk_x11_lookup_xdisplay:
680  * @xdisplay: a pointer to an X Display
681  * 
682  * Find the #GdkDisplay corresponding to @display, if any exists.
683  * 
684  * Return value: the #GdkDisplay, if found, otherwise %NULL.
685  *
686  * Since: 2.2
687  **/
688 GdkDisplay *
689 gdk_x11_lookup_xdisplay (Display *xdisplay)
690 {
691   GSList *tmp_list;
692
693   for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
694     {
695       if (GDK_DISPLAY_XDISPLAY (tmp_list->data) == xdisplay)
696         return tmp_list->data;
697     }
698   
699   return NULL;
700 }
701
702 /**
703  * _gdk_x11_display_screen_for_xrootwin:
704  * @display: a #Display
705  * @xrootwin: window ID for one of of the screen's of the display.
706  * 
707  * Given the root window ID of one of the screen's of a #GdkDisplay,
708  * finds the screen.
709  * 
710  * Return value: the #GdkScreen corresponding to @xrootwin, or %NULL.
711  **/
712 GdkScreen *
713 _gdk_x11_display_screen_for_xrootwin (GdkDisplay *display,
714                                       Window      xrootwin)
715 {
716   gint n_screens, i;
717
718   n_screens = gdk_display_get_n_screens (display);
719   for (i = 0; i < n_screens; i++)
720     {
721       GdkScreen *screen = gdk_display_get_screen (display, i);
722       if (GDK_SCREEN_XROOTWIN (screen) == xrootwin)
723         return screen;
724     }
725
726   return NULL;
727 }
728
729 /**
730  * gdk_x11_display_get_xdisplay:
731  * @display: a #GdkDisplay
732  * @returns: an X display.
733  *
734  * Returns the X display of a #GdkDisplay.
735  *
736  * Since: 2.2
737  */
738 Display *
739 gdk_x11_display_get_xdisplay (GdkDisplay  *display)
740 {
741   return GDK_DISPLAY_X11 (display)->xdisplay;
742 }
743
744 void
745 _gdk_windowing_set_default_display (GdkDisplay *display)
746 {
747   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
748   const gchar *startup_id;
749   
750   if (display)
751     gdk_display = GDK_DISPLAY_XDISPLAY (display);
752   else
753     gdk_display = NULL;
754
755   g_free (display_x11->startup_notification_id);
756   display_x11->startup_notification_id = NULL;
757   
758   startup_id = g_getenv ("DESKTOP_STARTUP_ID");
759   if (startup_id && *startup_id != '\0')
760     {
761       if (!g_utf8_validate (startup_id, -1, NULL))
762         g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
763       else
764         display_x11->startup_notification_id = g_strdup (startup_id);
765       
766       /* Clear the environment variable so it won't be inherited by
767        * child processes and confuse things.  unsetenv isn't portable,
768        * right...
769        */
770       putenv ("DESKTOP_STARTUP_ID=");
771
772       /* Set the startup id on the leader window so it
773        * applies to all windows we create on this display
774        */
775       XChangeProperty (display_x11->xdisplay,
776                        display_x11->leader_window,
777                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
778                        gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
779                        PropModeReplace,
780                        startup_id, strlen (startup_id));
781     }
782 }
783
784 char*
785 escape_for_xmessage (const char *str)
786 {
787   GString *retval;
788   const char *p;
789   
790   retval = g_string_new (NULL);
791
792   p = str;
793   while (*p)
794     {
795       switch (*p)
796         {
797         case ' ':
798         case '"':
799         case '\\':
800           g_string_append_c (retval, '\\');
801           break;
802         }
803
804       g_string_append_c (retval, *p);
805       ++p;
806     }
807
808   return g_string_free (retval, FALSE);
809 }
810
811 static void
812 broadcast_xmessage   (GdkDisplay   *display,
813                       const char   *message_type,
814                       const char   *message_type_begin,
815                       const char   *message)
816 {
817   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
818   GdkScreen *screen = gdk_display_get_default_screen (display);
819   GdkWindow *root_window = gdk_screen_get_root_window (screen);
820   Window xroot_window = GDK_WINDOW_XID (root_window);
821   
822   Atom type_atom;
823   Atom type_atom_begin;
824   Window xwindow;
825
826   {
827     XSetWindowAttributes attrs;
828
829     attrs.override_redirect = True;
830     attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
831
832     xwindow =
833       XCreateWindow (xdisplay,
834                      xroot_window,
835                      -100, -100, 1, 1,
836                      0,
837                      CopyFromParent,
838                      CopyFromParent,
839                      CopyFromParent,
840                      CWOverrideRedirect | CWEventMask,
841                      &attrs);
842   }
843
844   type_atom = gdk_x11_get_xatom_by_name_for_display (display,
845                                                      message_type);
846   type_atom_begin = gdk_x11_get_xatom_by_name_for_display (display,
847                                                            message_type_begin);
848   
849   {
850     XEvent xevent;
851     const char *src;
852     const char *src_end;
853     char *dest;
854     char *dest_end;
855     
856     xevent.xclient.type = ClientMessage;
857     xevent.xclient.message_type = type_atom_begin;
858     xevent.xclient.display =xdisplay;
859     xevent.xclient.window = xwindow;
860     xevent.xclient.format = 8;
861
862     src = message;
863     src_end = message + strlen (message) + 1; /* +1 to include nul byte */
864     
865     while (src != src_end)
866       {
867         dest = &xevent.xclient.data.b[0];
868         dest_end = dest + 20;        
869         
870         while (dest != dest_end &&
871                src != src_end)
872           {
873             *dest = *src;
874             ++dest;
875             ++src;
876           }
877
878         while (dest != dest_end)
879           {
880             *dest = 0;
881             ++dest;
882           }
883         
884         XSendEvent (xdisplay,
885                     xroot_window,
886                     False,
887                     PropertyChangeMask,
888                     &xevent);
889
890         xevent.xclient.message_type = type_atom;
891       }
892   }
893
894   XDestroyWindow (xdisplay, xwindow);
895   XFlush (xdisplay);
896 }
897
898 /**
899  * gdk_notify_startup_complete:
900  * 
901  * Indicates to the GUI environment that the application has finished
902  * loading. If the applications opens windows, this function is
903  * normally called after opening the application's initial set of
904  * windows.
905  * 
906  * GTK+ will call this function automatically after opening the first
907  * #GtkWindow unless gtk_window_set_auto_startup_notification() is called 
908  * to disable that feature.
909  *
910  * Since: 2.2
911  **/
912 void
913 gdk_notify_startup_complete (void)
914 {
915   GdkDisplay *display;
916   GdkDisplayX11 *display_x11;
917   gchar *escaped_id;
918   gchar *message;
919
920   display = gdk_display_get_default ();
921   if (!display)
922     return;
923   
924   display_x11 = GDK_DISPLAY_X11 (display);
925
926   if (display_x11->startup_notification_id == NULL)
927     return;
928
929   escaped_id = escape_for_xmessage (display_x11->startup_notification_id);
930   message = g_strdup_printf ("remove: ID=%s", escaped_id);
931   g_free (escaped_id);
932
933   broadcast_xmessage (display,
934                       "_NET_STARTUP_INFO",
935                       "_NET_STARTUP_INFO_BEGIN",
936                       message);
937
938   g_free (message);
939 }