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