]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkimage-x11.c
Use asynchronously _gdk_x11_set_input_focus_safe to avoid having to trap
[~andy/gtk] / gdk / x11 / gdkimage-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28
29 #include <stdlib.h>
30 #include <sys/types.h>
31
32 #if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
33 #define USE_SHM
34 #endif
35
36 #ifdef USE_SHM
37 #include <sys/ipc.h>
38 #include <sys/shm.h>
39 #endif /* USE_SHM */
40
41 #include <X11/Xlib.h>
42 #include <X11/Xutil.h>
43
44 #ifdef USE_SHM
45 #include <X11/extensions/XShm.h>
46 #endif /* USE_SHM */
47
48 #include <errno.h>
49
50 #include "gdk.h"                /* For gdk_error_trap_* / gdk_flush_* */
51 #include "gdkx.h"
52 #include "gdkimage.h"
53 #include "gdkprivate.h"
54 #include "gdkprivate-x11.h"
55 #include "gdkdisplay-x11.h"
56 #include "gdkscreen-x11.h"
57
58 typedef struct _GdkImagePrivateX11     GdkImagePrivateX11;
59
60 struct _GdkImagePrivateX11
61 {
62   XImage *ximage;
63   GdkScreen *screen;
64   gpointer x_shm_info;
65   Pixmap shm_pixmap;
66 };
67
68 static GList *image_list = NULL;
69 static gpointer parent_class = NULL;
70
71 static void gdk_x11_image_destroy (GdkImage      *image);
72 static void gdk_image_init        (GdkImage      *image);
73 static void gdk_image_class_init  (GdkImageClass *klass);
74 static void gdk_image_finalize    (GObject       *object);
75
76 #define PRIVATE_DATA(image) ((GdkImagePrivateX11 *) GDK_IMAGE (image)->windowing_data)
77
78 GType
79 gdk_image_get_type (void)
80 {
81   static GType object_type = 0;
82
83   if (!object_type)
84     {
85       static const GTypeInfo object_info =
86       {
87         sizeof (GdkImageClass),
88         (GBaseInitFunc) NULL,
89         (GBaseFinalizeFunc) NULL,
90         (GClassInitFunc) gdk_image_class_init,
91         NULL,           /* class_finalize */
92         NULL,           /* class_data */
93         sizeof (GdkImage),
94         0,              /* n_preallocs */
95         (GInstanceInitFunc) gdk_image_init,
96       };
97       
98       object_type = g_type_register_static (G_TYPE_OBJECT,
99                                             "GdkImage",
100                                             &object_info, 0);
101     }
102   
103   return object_type;
104 }
105
106 static void
107 gdk_image_init (GdkImage *image)
108 {
109   image->windowing_data = g_new0 (GdkImagePrivateX11, 1);
110 }
111
112 static void
113 gdk_image_class_init (GdkImageClass *klass)
114 {
115   GObjectClass *object_class = G_OBJECT_CLASS (klass);
116
117   parent_class = g_type_class_peek_parent (klass);
118
119   object_class->finalize = gdk_image_finalize;
120 }
121
122 static void
123 gdk_image_finalize (GObject *object)
124 {
125   GdkImage *image = GDK_IMAGE (object);
126
127   gdk_x11_image_destroy (image);
128   
129   G_OBJECT_CLASS (parent_class)->finalize (object);
130 }
131
132
133 void
134 _gdk_image_exit (void)
135 {
136   GdkImage *image;
137
138   while (image_list)
139     {
140       image = image_list->data;
141       gdk_x11_image_destroy (image);
142     }
143 }
144
145 /**
146  * gdk_image_new_bitmap:
147  * @visual: the #GdkVisual to use for the image.
148  * @data: the pixel data. 
149  * @width: the width of the image in pixels. 
150  * @height: the height of the image in pixels. 
151  * 
152  * Creates a new #GdkImage with a depth of 1 from the given data.
153  * <warning><para>THIS FUNCTION IS INCREDIBLY BROKEN. The passed-in data must 
154  * be allocated by malloc() (NOT g_malloc()) and will be freed when the 
155  * image is freed.</para></warning>
156  * 
157  * Return value: a new #GdkImage.
158  **/
159 GdkImage *
160 gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint width, gint height)
161 {
162   Visual *xvisual;
163   GdkImage *image;
164   GdkDisplay *display;
165   GdkImagePrivateX11 *private;
166   
167   image = g_object_new (gdk_image_get_type (), NULL);
168   private = PRIVATE_DATA (image);
169   private->screen = gdk_visual_get_screen (visual);
170   display = GDK_SCREEN_DISPLAY (private->screen);
171   
172   image->type = GDK_IMAGE_NORMAL;
173   image->visual = visual;
174   image->width = width;
175   image->height = height;
176   image->depth = 1;
177   image->bits_per_pixel = 1;
178   if (display->closed)
179     private->ximage = NULL;
180   else
181     {
182       xvisual = ((GdkVisualPrivate*) visual)->xvisual;
183       private->ximage = XCreateImage (GDK_SCREEN_XDISPLAY (private->screen),
184                                       xvisual, 1, XYBitmap,
185                                       0, 0, width, height, 8, 0);
186     }
187   
188   private->ximage->data = data;
189   private->ximage->bitmap_bit_order = MSBFirst;
190   private->ximage->byte_order = MSBFirst;
191   image->byte_order = MSBFirst;
192   image->mem =  private->ximage->data;
193   image->bpl = private->ximage->bytes_per_line;
194   image->bpp = 1;
195   return(image);
196 } /* gdk_image_new_bitmap() */
197
198 /* 
199  * Desc: query the server for support for the MIT_SHM extension
200  * Return:  0 = not available
201  *          1 = shared XImage support available
202  *          2 = shared Pixmap support available also
203  */
204 static int
205 gdk_image_check_xshm(Display *display)
206 {
207 #ifdef USE_SHM
208   int major, minor;
209   Bool pixmaps;
210   
211   if (XShmQueryExtension (display) &&
212       XShmQueryVersion (display, &major, &minor, &pixmaps))
213     return pixmaps ? 2 : 1;
214 #endif /* USE_SHM */
215   return 0;
216 }
217
218 void
219 _gdk_windowing_image_init (GdkDisplay *display)
220 {
221   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
222   
223   if (display_x11->use_xshm)
224     {
225       gint res = gdk_image_check_xshm (GDK_DISPLAY_XDISPLAY (display));
226       
227       if (!res)
228         display_x11->use_xshm = False;
229       else
230         display_x11->have_shm_pixmaps = (res == 2);
231     }
232 }
233
234 GdkImage*
235 _gdk_image_new_for_depth (GdkScreen    *screen,
236                           GdkImageType  type,
237                           GdkVisual    *visual,
238                           gint          width,
239                           gint          height,
240                           gint          depth)
241 {
242   GdkImage *image;
243   GdkImagePrivateX11 *private;
244 #ifdef USE_SHM
245   XShmSegmentInfo *x_shm_info;
246 #endif /* USE_SHM */
247   Visual *xvisual = NULL;
248   GdkDisplayX11 *display_x11;
249   GdkScreenX11 *screen_x11;
250
251   g_return_val_if_fail (!visual || GDK_IS_VISUAL (visual), NULL);
252   g_return_val_if_fail (visual || depth != -1, NULL);
253   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
254   
255   screen_x11 = GDK_SCREEN_X11 (screen);
256   display_x11 = GDK_DISPLAY_X11 (screen_x11->display);
257   
258   if (visual)
259     depth = visual->depth;
260   
261   switch (type)
262     {
263     case GDK_IMAGE_FASTEST:
264       image = _gdk_image_new_for_depth (screen, GDK_IMAGE_SHARED, 
265                                         visual, width, height, depth);
266       if (!image)
267         image = _gdk_image_new_for_depth (screen, GDK_IMAGE_NORMAL,
268                                           visual, width, height, depth);
269       break;
270
271     default:
272       image = g_object_new (gdk_image_get_type (), NULL);
273       
274       private = PRIVATE_DATA (image);
275
276       private->screen = screen;
277
278       image->type = type;
279       image->visual = visual;
280       image->width = width;
281       image->height = height;
282       image->depth = depth;
283
284       if (visual)
285         xvisual = ((GdkVisualPrivate*) visual)->xvisual;
286
287       switch (type)
288         {
289         case GDK_IMAGE_SHARED:
290 #ifdef USE_SHM
291           if (display_x11->use_xshm)
292             {
293               private->x_shm_info = g_new (XShmSegmentInfo, 1);
294               x_shm_info = private->x_shm_info;
295               x_shm_info->shmid = -1;
296               x_shm_info->shmaddr = (char*) -1;
297
298               private->ximage = XShmCreateImage (screen_x11->xdisplay, xvisual, depth,
299                                                  ZPixmap, NULL, x_shm_info, width, height);
300               if (private->ximage == NULL)
301                 {
302                   g_warning ("XShmCreateImage failed");
303                   display_x11->use_xshm = FALSE;
304                   
305                   goto error;
306                 }
307
308               x_shm_info->shmid = shmget (IPC_PRIVATE,
309                                           private->ximage->bytes_per_line * private->ximage->height,
310                                           IPC_CREAT | 0600);
311
312               if (x_shm_info->shmid == -1)
313                 {
314                   /* EINVAL indicates, most likely, that the segment we asked for
315                    * is bigger than SHMMAX, so we don't treat it as a permanent
316                    * error. ENOSPC and ENOMEM may also indicate this, but
317                    * more likely are permanent errors.
318                    */
319                   if (errno != EINVAL)
320                     {
321                       g_warning ("shmget failed: error %d (%s)", errno, g_strerror (errno));
322                       display_x11->use_xshm = FALSE;
323                     }
324
325                   goto error;
326                 }
327
328               x_shm_info->readOnly = False;
329               x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0);
330               private->ximage->data = x_shm_info->shmaddr;
331
332               if (x_shm_info->shmaddr == (char*) -1)
333                 {
334                   g_warning ("shmat failed: error %d (%s)", errno, g_strerror (errno));
335                   /* Failure in shmat is almost certainly permanent. Most likely error is
336                    * EMFILE, which would mean that we've exceeded the per-process
337                    * Shm segment limit.
338                    */
339                   display_x11->use_xshm = FALSE;
340                   goto error;
341                 }
342
343               gdk_error_trap_push ();
344
345               XShmAttach (screen_x11->xdisplay, x_shm_info);
346               XSync (screen_x11->xdisplay, False);
347
348               if (gdk_error_trap_pop ())
349                 {
350                   /* this is the common failure case so omit warning */
351                   display_x11->use_xshm = FALSE;
352                   goto error;
353                 }
354               
355               /* We mark the segment as destroyed so that when
356                * the last process detaches, it will be deleted.
357                * There is a small possibility of leaking if
358                * we die in XShmAttach. In theory, a signal handler
359                * could be set up.
360                */
361               shmctl (x_shm_info->shmid, IPC_RMID, 0);                
362
363               if (image)
364                 image_list = g_list_prepend (image_list, image);
365             }
366           else
367 #endif /* USE_SHM */
368             goto error;
369           break;
370         case GDK_IMAGE_NORMAL:
371           private->ximage = XCreateImage (screen_x11->xdisplay, xvisual, depth,
372                                           ZPixmap, 0, 0, width, height, 32, 0);
373
374           /* Use malloc, not g_malloc here, because X will call free()
375            * on this data
376            */
377           private->ximage->data = malloc (private->ximage->bytes_per_line *
378                                           private->ximage->height);
379           if (!private->ximage->data)
380             goto error;
381           break;
382
383         case GDK_IMAGE_FASTEST:
384           g_assert_not_reached ();
385         }
386
387       if (image)
388         {
389           image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
390           image->mem = private->ximage->data;
391           image->bpl = private->ximage->bytes_per_line;
392           image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
393           image->bits_per_pixel = private->ximage->bits_per_pixel;
394         }
395     }
396
397   return image;
398
399  error:
400   if (private->ximage)
401     {
402       XDestroyImage (private->ximage);
403       private->ximage = NULL;
404     }
405 #ifdef USE_SHM
406   if (private->x_shm_info)
407     {
408       x_shm_info = private->x_shm_info;
409       
410       if (x_shm_info->shmaddr != (char *)-1)
411         shmdt (x_shm_info->shmaddr);
412       if (x_shm_info->shmid != -1) 
413         shmctl (x_shm_info->shmid, IPC_RMID, 0);
414       
415       g_free (x_shm_info);
416       private->x_shm_info = NULL;
417     }
418 #endif /* USE_SHM */
419   g_object_unref (image);
420   
421   return NULL;
422 }
423
424 Pixmap
425 _gdk_x11_image_get_shm_pixmap (GdkImage *image)
426 {
427   GdkImagePrivateX11 *private = PRIVATE_DATA (image);
428   GdkDisplay *display = GDK_SCREEN_DISPLAY (private->screen);
429
430   if (display->closed)
431     return None;
432
433 #ifdef USE_SHM  
434   /* Future: do we need one of these per-screen per-image? ShmPixmaps
435    * are the same for every screen, but can they be shared? Not a concern
436    * right now since we tie images to a particular screen.
437    */
438   if (!private->shm_pixmap && image->type == GDK_IMAGE_SHARED && 
439       GDK_DISPLAY_X11 (display)->have_shm_pixmaps)
440     private->shm_pixmap = XShmCreatePixmap (GDK_SCREEN_XDISPLAY (private->screen),
441                                             GDK_SCREEN_XROOTWIN (private->screen),
442                                             image->mem, private->x_shm_info, 
443                                             image->width, image->height, image->depth);
444
445   return private->shm_pixmap;
446 #else
447   return None;
448 #endif    
449 }
450
451 static GdkImage*
452 get_full_image (GdkDrawable    *drawable,
453                 gint            src_x,
454                 gint            src_y,
455                 gint            width,
456                 gint            height)
457 {
458   GdkImage *image;
459   GdkImagePrivateX11 *private;
460   GdkDrawableImplX11 *impl;
461   XImage *ximage;
462
463   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
464   
465   ximage = XGetImage (GDK_SCREEN_XDISPLAY (impl->screen),
466                       impl->xid,
467                       src_x, src_y, width, height,
468                       AllPlanes, ZPixmap);
469   
470   if (!ximage)
471     return NULL;
472   
473   image = g_object_new (gdk_image_get_type (), NULL);
474   
475   private = PRIVATE_DATA (image);
476   
477   private->screen = impl->screen;
478   private->ximage = ximage;
479   
480   image->type = GDK_IMAGE_NORMAL;
481   image->visual = gdk_drawable_get_visual (drawable); /* could be NULL */
482   image->width = width;
483   image->height = height;
484   image->depth = gdk_drawable_get_depth (drawable);
485   
486   image->mem = private->ximage->data;
487   image->bpl = private->ximage->bytes_per_line;
488   image->bits_per_pixel = private->ximage->bits_per_pixel;
489   image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
490   image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
491   
492   return image;
493 }
494
495 GdkImage*
496 _gdk_x11_copy_to_image (GdkDrawable    *drawable,
497                         GdkImage       *image,
498                         gint            src_x,
499                         gint            src_y,
500                         gint            dest_x,
501                         gint            dest_y,
502                         gint            width,
503                         gint            height)
504 {
505   GdkImagePrivateX11 *private;
506   GdkDrawableImplX11 *impl;
507   GdkVisual *visual;
508   GdkDisplay *display;
509   Display *xdisplay;
510   gboolean have_grab;
511   GdkRectangle req;
512   GdkRectangle window_rect;
513   Pixmap shm_pixmap = None;
514   gboolean success = TRUE;
515   
516   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
517   g_return_val_if_fail (image != NULL || (dest_x == 0 && dest_y == 0), NULL);
518
519   visual = gdk_drawable_get_visual (drawable);
520   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
521   display = gdk_drawable_get_display (drawable);
522   xdisplay = gdk_x11_display_get_xdisplay (display);
523
524   if (display->closed)
525     return NULL;
526   
527   have_grab = FALSE;
528
529 #define UNGRAB() G_STMT_START {                                 \
530     if (have_grab) {                                            \
531       gdk_x11_display_ungrab (display);                         \
532       have_grab = FALSE; }                                      \
533   } G_STMT_END
534
535   if (!image && !GDK_IS_WINDOW_IMPL_X11 (drawable))
536     return get_full_image (drawable, src_x, src_y, width, height);
537
538   if (image && image->type == GDK_IMAGE_SHARED)
539     {
540       shm_pixmap = _gdk_x11_image_get_shm_pixmap (image);
541       if (shm_pixmap)
542         {
543           GC xgc;
544           XGCValues values;
545
546           /* Again easy, we can just XCopyArea, and don't have to worry about clipping
547            */
548           values.subwindow_mode = IncludeInferiors;
549           xgc = XCreateGC (xdisplay, impl->xid, GCSubwindowMode, &values);
550           
551           XCopyArea (xdisplay, impl->xid, shm_pixmap, xgc,
552                      src_x, src_y, width, height, dest_x, dest_y);
553           XSync (xdisplay, FALSE);
554           
555           XFreeGC (xdisplay, xgc);
556           
557           return image;
558         }
559     }
560
561   /* Now the general case - we may have to worry about clipping to the screen
562    * bounds, in which case we'll have to grab the server and only get a piece
563    * of the window.
564    */
565   if (GDK_IS_WINDOW_IMPL_X11 (drawable))
566     {
567       GdkRectangle screen_rect;
568       Window child;
569
570       have_grab = TRUE;
571       gdk_x11_display_grab (display);
572
573       /* Translate screen area into window coordinates */
574       XTranslateCoordinates (xdisplay,
575                              GDK_SCREEN_XROOTWIN (impl->screen),
576                              impl->xid,
577                              0, 0, 
578                              &screen_rect.x, &screen_rect.y, 
579                              &child);
580
581       screen_rect.width = gdk_screen_get_width (impl->screen);
582       screen_rect.height = gdk_screen_get_height (impl->screen);
583       
584       gdk_error_trap_push ();
585
586       window_rect.x = 0;
587       window_rect.y = 0;
588       
589       gdk_window_get_geometry (GDK_WINDOW (impl->wrapper),
590                                NULL, NULL,
591                                &window_rect.width,
592                                &window_rect.height,
593                                NULL);
594       
595       /* compute intersection of screen and window, in window
596        * coordinates
597        */
598       if (gdk_error_trap_pop () ||
599           !gdk_rectangle_intersect (&window_rect, &screen_rect, 
600                                     &window_rect))
601         goto out;
602     }
603   else
604     {
605       window_rect.x = 0;
606       window_rect.y = 0;
607       gdk_drawable_get_size (drawable,
608                              &window_rect.width,
609                              &window_rect.height);
610     }
611       
612   req.x = src_x;
613   req.y = src_y;
614   req.width = width;
615   req.height = height;
616   
617   /* window_rect specifies the part of drawable which we can get from
618    * the server in window coordinates. 
619    * For pixmaps this is all of the pixmap, for windows it is just 
620    * the onscreen part.
621    */
622   if (!gdk_rectangle_intersect (&req, &window_rect, &req))
623     goto out;
624
625   gdk_error_trap_push ();
626   
627   if (!image &&
628       req.x == src_x && req.y == src_y && req.width == width && req.height == height)
629     {
630       image = get_full_image (drawable, src_x, src_y, width, height);
631       if (!image)
632         success = FALSE;
633     }
634   else
635     {
636       gboolean created_image = FALSE;
637       
638       if (!image)
639         {
640           image = _gdk_image_new_for_depth (impl->screen, GDK_IMAGE_NORMAL, 
641                                             visual, width, height,
642                                             gdk_drawable_get_depth (drawable));
643           created_image = TRUE;
644         }
645
646       private = PRIVATE_DATA (image);
647
648       /* In the ShmImage but no ShmPixmap case, we could use XShmGetImage when
649        * we are getting the entire image.
650        */
651       if (XGetSubImage (xdisplay, impl->xid,
652                         req.x, req.y, req.width, req.height,
653                         AllPlanes, ZPixmap,
654                         private->ximage,
655                         dest_x + req.x - src_x, dest_y + req.y - src_y) == None)
656         {
657           if (created_image)
658             g_object_unref (image);
659           image = NULL;
660           success = FALSE;
661         }
662     }
663
664  out:
665   
666   if (have_grab)
667     {                           
668       gdk_x11_display_ungrab (display);
669       have_grab = FALSE;
670     }
671   
672   gdk_error_trap_pop ();
673
674   if (success && !image)
675     {
676       /* We "succeeded", but could get no content for the image so return junk */
677       image = _gdk_image_new_for_depth (impl->screen, GDK_IMAGE_NORMAL, 
678                                         visual, width, height,
679                                         gdk_drawable_get_depth (drawable));
680     }
681       
682   return image;
683 }
684
685 guint32
686 gdk_image_get_pixel (GdkImage *image,
687                      gint x,
688                      gint y)
689 {
690   guint32 pixel;
691   GdkImagePrivateX11 *private;
692
693   g_return_val_if_fail (GDK_IS_IMAGE (image), 0);
694   g_return_val_if_fail (x >= 0 && x < image->width, 0);
695   g_return_val_if_fail (y >= 0 && y < image->height, 0);
696
697   private = PRIVATE_DATA (image);
698
699   if (!private->screen->closed)
700     pixel = XGetPixel (private->ximage, x, y);
701   else
702     pixel = 0;
703
704   return pixel;
705 }
706
707 void
708 gdk_image_put_pixel (GdkImage *image,
709                      gint x,
710                      gint y,
711                      guint32 pixel)
712 {
713   GdkImagePrivateX11 *private;
714
715   g_return_if_fail (GDK_IS_IMAGE (image));
716   g_return_if_fail (x >= 0 && x < image->width);
717   g_return_if_fail (y >= 0 && y < image->height);
718
719   private = PRIVATE_DATA (image);
720
721   if (!private->screen->closed)
722     pixel = XPutPixel (private->ximage, x, y, pixel);
723 }
724
725 static void
726 gdk_x11_image_destroy (GdkImage *image)
727 {
728   GdkImagePrivateX11 *private;
729 #ifdef USE_SHM
730   XShmSegmentInfo *x_shm_info;
731 #endif /* USE_SHM */
732
733   g_return_if_fail (GDK_IS_IMAGE (image));
734
735   private = PRIVATE_DATA (image);
736
737   if (private == NULL) /* This means that _gdk_image_exit() destroyed the
738                         * image already, and now we're called a second
739                         * time from _finalize()
740                         */
741     return;
742
743   if (private->ximage)          /* Deal with failure of creation */
744     {
745       switch (image->type)
746         {
747         case GDK_IMAGE_NORMAL:
748           if (!private->screen->closed)
749             XDestroyImage (private->ximage);
750           break;
751           
752         case GDK_IMAGE_SHARED:
753 #ifdef USE_SHM
754           if (!private->screen->closed)
755             {
756               gdk_display_sync (GDK_SCREEN_DISPLAY (private->screen));
757
758               if (private->shm_pixmap)
759                 XFreePixmap (GDK_SCREEN_XDISPLAY (private->screen), private->shm_pixmap);
760                   
761               XShmDetach (GDK_SCREEN_XDISPLAY (private->screen), private->x_shm_info);
762               XDestroyImage (private->ximage);
763             }
764           
765           image_list = g_list_remove (image_list, image);
766
767           x_shm_info = private->x_shm_info;
768           shmdt (x_shm_info->shmaddr);
769           
770           g_free (private->x_shm_info);
771           private->x_shm_info = NULL;
772
773 #else /* USE_SHM */
774           g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support");
775 #endif /* USE_SHM */
776           break;
777           
778         case GDK_IMAGE_FASTEST:
779           g_assert_not_reached ();
780         }
781     }
782
783   g_free (private);
784   image->windowing_data = NULL;
785 }
786
787 /**
788  * gdk_x11_image_get_xdisplay:
789  * @image: a #GdkImage.
790  * 
791  * Returns the display of a #GdkImage.
792  * 
793  * Return value: an Xlib <type>Display*</type>.
794  **/
795 Display *
796 gdk_x11_image_get_xdisplay (GdkImage *image)
797 {
798   GdkImagePrivateX11 *private;
799
800   g_return_val_if_fail (GDK_IS_IMAGE (image), NULL);
801
802   private = PRIVATE_DATA (image);
803
804   return GDK_SCREEN_XDISPLAY (private->screen);
805 }
806
807 /**
808  * gdk_x11_image_get_ximage:
809  * @image: a #GdkImage.
810  * 
811  * Returns the X image belonging to a #GdkImage.
812  * 
813  * Return value: an <type>XImage*</type>.
814  **/
815 XImage *
816 gdk_x11_image_get_ximage (GdkImage *image)
817 {
818   GdkImagePrivateX11 *private;
819
820   g_return_val_if_fail (GDK_IS_IMAGE (image), NULL);
821
822   private = PRIVATE_DATA (image);
823
824   if (private->screen->closed)
825     return NULL;
826   else
827     return private->ximage;
828 }
829
830 gint
831 _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
832                                    gint        depth)
833 {
834   XPixmapFormatValues *formats;
835   gint count, i;
836
837   formats = XListPixmapFormats (GDK_DISPLAY_XDISPLAY (display), &count);
838   
839   for (i = 0; i < count; i++)
840     if (formats[i].depth == depth)
841       {
842         gint result = formats[i].bits_per_pixel;
843         XFree (formats);
844         return result;
845       }
846
847   g_assert_not_reached ();
848   return -1;
849 }
850