1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
30 #include <sys/types.h>
32 #if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
42 #include <X11/Xutil.h>
45 #include <X11/extensions/XShm.h>
50 #include "gdk.h" /* For gdk_error_trap_* / gdk_flush_* */
52 #include "gdkprivate.h"
53 #include "gdkprivate-x11.h"
55 static GList *image_list = NULL;
56 static gpointer parent_class = NULL;
58 static void gdk_x11_image_destroy (GdkImage *image);
59 static void gdk_image_init (GdkImage *image);
60 static void gdk_image_class_init (GdkImageClass *klass);
61 static void gdk_image_finalize (GObject *object);
63 #define PRIVATE_DATA(image) ((GdkImagePrivateX11 *) GDK_IMAGE (image)->windowing_data)
66 gdk_image_get_type (void)
68 static GType object_type = 0;
72 static const GTypeInfo object_info =
74 sizeof (GdkImageClass),
76 (GBaseFinalizeFunc) NULL,
77 (GClassInitFunc) gdk_image_class_init,
78 NULL, /* class_finalize */
79 NULL, /* class_data */
82 (GInstanceInitFunc) gdk_image_init,
85 object_type = g_type_register_static (G_TYPE_OBJECT,
94 gdk_image_init (GdkImage *image)
96 image->windowing_data = g_new0 (GdkImagePrivateX11, 1);
100 gdk_image_class_init (GdkImageClass *klass)
102 GObjectClass *object_class = G_OBJECT_CLASS (klass);
104 parent_class = g_type_class_peek_parent (klass);
106 object_class->finalize = gdk_image_finalize;
110 gdk_image_finalize (GObject *object)
112 GdkImage *image = GDK_IMAGE (object);
114 gdk_x11_image_destroy (image);
116 G_OBJECT_CLASS (parent_class)->finalize (object);
121 gdk_image_exit (void)
127 image = image_list->data;
128 gdk_x11_image_destroy (image);
133 gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h)
135 * Desc: create a new bitmap image
140 GdkImagePrivateX11 *private;
141 image = g_object_new (gdk_image_get_type (), NULL);
142 private = PRIVATE_DATA (image);
143 private->xdisplay = gdk_display;
144 image->type = GDK_IMAGE_NORMAL;
145 image->visual = visual;
149 image->bits_per_pixel = 1;
150 xvisual = ((GdkVisualPrivate*) visual)->xvisual;
151 private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap,
153 private->ximage->data = data;
154 private->ximage->bitmap_bit_order = MSBFirst;
155 private->ximage->byte_order = MSBFirst;
156 image->byte_order = MSBFirst;
157 image->mem = private->ximage->data;
158 image->bpl = private->ximage->bytes_per_line;
161 } /* gdk_image_new_bitmap() */
164 gdk_image_check_xshm(Display *display)
166 * Desc: query the server for support for the MIT_SHM extension
167 * Return: 0 = not available
168 * 1 = shared XImage support available
169 * 2 = shared Pixmap support available also
173 int major, minor, ignore;
176 if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore))
178 if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True)
180 return (pixmaps==True) ? 2 : 1;
188 _gdk_windowing_image_init (void)
192 if (!gdk_image_check_xshm (gdk_display))
194 gdk_use_xshm = False;
200 gdk_image_new (GdkImageType type,
206 GdkImagePrivateX11 *private;
208 XShmSegmentInfo *x_shm_info;
214 case GDK_IMAGE_FASTEST:
215 image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height);
218 image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height);
222 image = g_object_new (gdk_image_get_type (), NULL);
224 private = PRIVATE_DATA (image);
226 private->xdisplay = gdk_display;
229 image->visual = visual;
230 image->width = width;
231 image->height = height;
232 image->depth = visual->depth;
234 xvisual = ((GdkVisualPrivate*) visual)->xvisual;
238 case GDK_IMAGE_SHARED:
242 private->x_shm_info = g_new (XShmSegmentInfo, 1);
243 x_shm_info = private->x_shm_info;
244 x_shm_info->shmid = -1;
245 x_shm_info->shmaddr = (char*) -1;
247 private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth,
248 ZPixmap, NULL, x_shm_info, width, height);
249 if (private->ximage == NULL)
251 g_warning ("XShmCreateImage failed");
252 gdk_use_xshm = FALSE;
257 x_shm_info->shmid = shmget (IPC_PRIVATE,
258 private->ximage->bytes_per_line * private->ximage->height,
261 if (x_shm_info->shmid == -1)
263 /* EINVAL indicates, most likely, that the segment we asked for
264 * is bigger than SHMMAX, so we don't treat it as a permanent
265 * error. ENOSPC and ENOMEM may also indicate this, but
266 * more likely are permanent errors.
270 g_warning ("shmget failed: error %d (%s)", errno, g_strerror (errno));
271 gdk_use_xshm = FALSE;
277 x_shm_info->readOnly = False;
278 x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0);
279 private->ximage->data = x_shm_info->shmaddr;
281 if (x_shm_info->shmaddr == (char*) -1)
283 g_warning ("shmat failed: error %d (%s)", errno, g_strerror (errno));
284 /* Failure in shmat is almost certainly permanent. Most likely error is
285 * EMFILE, which would mean that we've exceeded the per-process
288 gdk_use_xshm = FALSE;
292 gdk_error_trap_push ();
294 XShmAttach (private->xdisplay, x_shm_info);
295 XSync (private->xdisplay, False);
297 if (gdk_error_trap_pop ())
299 /* this is the common failure case so omit warning */
300 gdk_use_xshm = FALSE;
304 /* We mark the segment as destroyed so that when
305 * the last process detaches, it will be deleted.
306 * There is a small possibility of leaking if
307 * we die in XShmAttach. In theory, a signal handler
310 shmctl (x_shm_info->shmid, IPC_RMID, 0);
313 image_list = g_list_prepend (image_list, image);
319 case GDK_IMAGE_NORMAL:
320 private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth,
321 ZPixmap, 0, 0, width, height, 32, 0);
323 /* Use malloc, not g_malloc here, because X will call free()
326 private->ximage->data = malloc (private->ximage->bytes_per_line *
327 private->ximage->height);
328 if (!private->ximage->data)
332 case GDK_IMAGE_FASTEST:
333 g_assert_not_reached ();
338 image->byte_order = private->ximage->byte_order;
339 image->mem = private->ximage->data;
340 image->bpl = private->ximage->bytes_per_line;
341 image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
342 image->bits_per_pixel = private->ximage->bits_per_pixel;
351 XDestroyImage (private->ximage);
352 private->ximage = NULL;
355 if (private->x_shm_info)
357 x_shm_info = private->x_shm_info;
359 if (x_shm_info->shmaddr != (char *)-1)
360 shmdt (x_shm_info->shmaddr);
361 if (x_shm_info->shmid != -1)
362 shmctl (x_shm_info->shmid, IPC_RMID, 0);
365 private->x_shm_info = NULL;
368 g_object_unref (image);
374 _gdk_x11_get_image (GdkDrawable *drawable,
381 GdkImagePrivateX11 *private;
382 GdkDrawableImplX11 *impl;
386 GdkRectangle window_rect;
389 g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
391 visual = gdk_drawable_get_visual (drawable);
393 g_assert (visual || !GDK_IS_WINDOW_IMPL_X11 (drawable));
395 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
399 if (GDK_IS_WINDOW_IMPL_X11 (drawable))
401 GdkRectangle screen_rect;
407 gdk_x11_grab_server ();
409 /* Translate screen area into window coordinates */
410 XTranslateCoordinates (gdk_display,
414 &screen_rect.x, &screen_rect.y,
417 screen_rect.width = gdk_screen_width ();
418 screen_rect.height = gdk_screen_height ();
420 gdk_error_trap_push ();
425 gdk_window_get_geometry (GDK_WINDOW (impl->wrapper),
431 /* compute intersection of screen and window, in window
434 if (gdk_error_trap_pop () ||
435 !gdk_rectangle_intersect (&window_rect, &screen_rect,
439 gdk_x11_ungrab_server ();
440 return image = gdk_image_new (GDK_IMAGE_FASTEST,
449 gdk_drawable_get_size (drawable,
451 &window_rect.height);
459 /* window_rect specifies the part of drawable which we can get from
460 * the server in window coordinates.
461 * For pixmaps this is all of the pixmap, for windows it is just
464 if (!gdk_rectangle_intersect (&req, &window_rect, &req) && visual)
467 gdk_x11_ungrab_server ();
468 return image = gdk_image_new (GDK_IMAGE_FASTEST,
473 if (req.x != x || req.y != y)
475 g_assert (GDK_IS_WINDOW (drawable));
478 image = gdk_image_new (GDK_IMAGE_FASTEST,
484 gdk_x11_ungrab_server ();
488 private = PRIVATE_DATA (image);
490 gdk_error_trap_push ();
492 ximage = XGetSubImage (impl->xdisplay,
494 req.x, req.y, req.width, req.height,
497 req.x - x, req.y - y);
501 gdk_x11_ungrab_server ();
505 if (gdk_error_trap_pop () || ximage == NULL)
507 g_object_unref (G_OBJECT (image));
511 g_assert (ximage == private->ximage);
515 /* Here we ignore the req.width, req.height -
516 * XGetImage() will do the right thing without
519 ximage = XGetImage (impl->xdisplay,
526 gdk_x11_ungrab_server ();
533 image = g_object_new (gdk_image_get_type (), NULL);
535 private = PRIVATE_DATA (image);
537 private->xdisplay = gdk_display;
538 private->ximage = ximage;
540 image->type = GDK_IMAGE_NORMAL;
541 image->visual = visual; /* May be NULL */
542 image->width = width;
543 image->height = height;
544 image->depth = gdk_drawable_get_depth (drawable);
546 image->mem = private->ximage->data;
547 image->bpl = private->ximage->bytes_per_line;
548 image->bits_per_pixel = private->ximage->bits_per_pixel;
549 image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
550 image->byte_order = private->ximage->byte_order;
553 g_assert (!have_grab);
559 gdk_image_get_pixel (GdkImage *image,
564 GdkImagePrivateX11 *private;
566 g_return_val_if_fail (GDK_IS_IMAGE (image), 0);
568 private = PRIVATE_DATA (image);
570 pixel = XGetPixel (private->ximage, x, y);
576 gdk_image_put_pixel (GdkImage *image,
581 GdkImagePrivateX11 *private;
583 g_return_if_fail (GDK_IS_IMAGE (image));
585 private = PRIVATE_DATA (image);
587 pixel = XPutPixel (private->ximage, x, y, pixel);
591 gdk_x11_image_destroy (GdkImage *image)
593 GdkImagePrivateX11 *private;
595 XShmSegmentInfo *x_shm_info;
598 g_return_if_fail (GDK_IS_IMAGE (image));
600 private = PRIVATE_DATA (image);
602 if (private == NULL) /* This means that gdk_image_exit() destroyed the
603 * image already, and now we're called a second
604 * time from _finalize()
608 if (private->ximage) /* Deal with failure of creation */
612 case GDK_IMAGE_NORMAL:
613 XDestroyImage (private->ximage);
616 case GDK_IMAGE_SHARED:
620 XShmDetach (private->xdisplay, private->x_shm_info);
621 XDestroyImage (private->ximage);
623 x_shm_info = private->x_shm_info;
624 shmdt (x_shm_info->shmaddr);
626 g_free (private->x_shm_info);
627 private->x_shm_info = NULL;
629 image_list = g_list_remove (image_list, image);
631 g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support");
635 case GDK_IMAGE_FASTEST:
636 g_assert_not_reached ();
641 image->windowing_data = NULL;