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 Library 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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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-1999. 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/.
29 /* gcc -ansi -pedantic on GNU/Linux causes warnings and errors
30 * unless this is defined:
31 * warning: #warning "Files using this header must be compiled with _SVID_SOURCE or _XOPEN_SOURCE"
34 # define _XOPEN_SOURCE 1
38 #include <sys/types.h>
40 #if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
50 #include <X11/Xutil.h>
53 #include <X11/extensions/XShm.h>
58 #include "gdk.h" /* For gdk_error_trap_* / gdk_flush_* */
60 #include "gdkprivate.h"
61 #include "gdkprivate-x11.h"
63 static GList *image_list = NULL;
64 static gpointer parent_class = NULL;
66 static void gdk_x11_image_destroy (GdkImage *image);
67 static void gdk_image_init (GdkImage *image);
68 static void gdk_image_class_init (GdkImageClass *klass);
69 static void gdk_image_finalize (GObject *object);
71 #define PRIVATE_DATA(image) ((GdkImagePrivateX11 *) GDK_IMAGE (image)->windowing_data)
74 gdk_image_get_type (void)
76 static GType object_type = 0;
80 static const GTypeInfo object_info =
82 sizeof (GdkImageClass),
84 (GBaseFinalizeFunc) NULL,
85 (GClassInitFunc) gdk_image_class_init,
86 NULL, /* class_finalize */
87 NULL, /* class_data */
90 (GInstanceInitFunc) gdk_image_init,
93 object_type = g_type_register_static (G_TYPE_OBJECT,
102 gdk_image_init (GdkImage *image)
104 image->windowing_data = g_new0 (GdkImagePrivateX11, 1);
109 gdk_image_class_init (GdkImageClass *klass)
111 GObjectClass *object_class = G_OBJECT_CLASS (klass);
113 parent_class = g_type_class_peek_parent (klass);
115 object_class->finalize = gdk_image_finalize;
119 gdk_image_finalize (GObject *object)
121 GdkImage *image = GDK_IMAGE (object);
123 gdk_x11_image_destroy (image);
125 G_OBJECT_CLASS (parent_class)->finalize (object);
130 gdk_image_exit (void)
136 image = image_list->data;
137 gdk_x11_image_destroy (image);
142 gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h)
144 * Desc: create a new bitmap image
149 GdkImagePrivateX11 *private;
150 image = GDK_IMAGE (g_type_create_instance (gdk_image_get_type ()));
151 private = PRIVATE_DATA (image);
152 private->xdisplay = gdk_display;
153 image->type = GDK_IMAGE_NORMAL;
154 image->visual = visual;
158 xvisual = ((GdkVisualPrivate*) visual)->xvisual;
159 private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap,
161 private->ximage->data = data;
162 private->ximage->bitmap_bit_order = MSBFirst;
163 private->ximage->byte_order = MSBFirst;
164 image->byte_order = MSBFirst;
165 image->mem = private->ximage->data;
166 image->bpl = private->ximage->bytes_per_line;
169 } /* gdk_image_new_bitmap() */
172 gdk_image_check_xshm(Display *display)
174 * Desc: query the server for support for the MIT_SHM extension
175 * Return: 0 = not available
176 * 1 = shared XImage support available
177 * 2 = shared Pixmap support available also
181 int major, minor, ignore;
184 if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore))
186 if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True)
188 return (pixmaps==True) ? 2 : 1;
196 _gdk_windowing_image_init (void)
200 if (!gdk_image_check_xshm (gdk_display))
202 gdk_use_xshm = False;
208 gdk_image_new (GdkImageType type,
214 GdkImagePrivateX11 *private;
216 XShmSegmentInfo *x_shm_info;
222 case GDK_IMAGE_FASTEST:
223 image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height);
226 image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height);
230 image = GDK_IMAGE (g_type_create_instance (gdk_image_get_type ()));
232 private = PRIVATE_DATA (image);
234 private->xdisplay = gdk_display;
237 image->visual = visual;
238 image->width = width;
239 image->height = height;
240 image->depth = visual->depth;
242 xvisual = ((GdkVisualPrivate*) visual)->xvisual;
246 case GDK_IMAGE_SHARED:
250 private->x_shm_info = g_new (XShmSegmentInfo, 1);
251 x_shm_info = private->x_shm_info;
253 private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth,
254 ZPixmap, NULL, x_shm_info, width, height);
255 if (private->ximage == NULL)
257 g_warning ("XShmCreateImage failed");
260 gdk_use_xshm = False;
264 x_shm_info->shmid = shmget (IPC_PRIVATE,
265 private->ximage->bytes_per_line * private->ximage->height,
268 if (x_shm_info->shmid == -1)
270 /* EINVAL indicates, most likely, that the segment we asked for
271 * is bigger than SHMMAX, so we don't treat it as a permanently
272 * fatal error. ENOSPC and ENOMEM may also indicate this, but
273 * more likely are permanent errors.
277 g_warning ("shmget failed!");
278 gdk_use_xshm = False;
281 XDestroyImage (private->ximage);
282 g_free (private->x_shm_info);
288 x_shm_info->readOnly = False;
289 x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0);
290 private->ximage->data = x_shm_info->shmaddr;
292 if (x_shm_info->shmaddr == (char*) -1)
294 g_warning ("shmat failed!");
296 XDestroyImage (private->ximage);
297 shmctl (x_shm_info->shmid, IPC_RMID, 0);
299 g_free (private->x_shm_info);
305 gdk_error_trap_push ();
307 XShmAttach (private->xdisplay, x_shm_info);
308 XSync (private->xdisplay, False);
310 if (gdk_error_trap_pop ())
312 /* this is the common failure case so omit warning */
313 XDestroyImage (private->ximage);
314 shmdt (x_shm_info->shmaddr);
315 shmctl (x_shm_info->shmid, IPC_RMID, 0);
317 g_free (private->x_shm_info);
320 gdk_use_xshm = False;
325 /* We mark the segment as destroyed so that when
326 * the last process detaches, it will be deleted.
327 * There is a small possibility of leaking if
328 * we die in XShmAttach. In theory, a signal handler
331 shmctl (x_shm_info->shmid, IPC_RMID, 0);
334 image_list = g_list_prepend (image_list, image);
346 case GDK_IMAGE_NORMAL:
347 private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth,
348 ZPixmap, 0, 0, width, height, 32, 0);
350 /* Use malloc, not g_malloc here, because X will call free()
353 private->ximage->data = malloc (private->ximage->bytes_per_line *
354 private->ximage->height);
357 case GDK_IMAGE_FASTEST:
358 case GDK_IMAGE_SHARED_PIXMAP:
359 g_assert_not_reached ();
364 image->byte_order = private->ximage->byte_order;
365 image->mem = private->ximage->data;
366 image->bpl = private->ximage->bytes_per_line;
367 image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
375 gdk_image_get (GdkWindow *window,
382 GdkImagePrivateX11 *private;
384 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
386 if (GDK_WINDOW_DESTROYED (window))
389 image = GDK_IMAGE (g_type_create_instance (gdk_image_get_type ()));
390 private = PRIVATE_DATA (image);
392 private->xdisplay = gdk_display;
393 private->ximage = XGetImage (private->xdisplay,
394 GDK_DRAWABLE_XID (window),
398 image->type = GDK_IMAGE_NORMAL;
399 image->visual = gdk_window_get_visual (window);
400 image->width = width;
401 image->height = height;
402 image->depth = private->ximage->depth;
404 image->mem = private->ximage->data;
405 image->bpl = private->ximage->bytes_per_line;
406 if (private->ximage->bits_per_pixel <= 8)
408 else if (private->ximage->bits_per_pixel <= 16)
410 else if (private->ximage->bits_per_pixel <= 24)
414 image->byte_order = private->ximage->byte_order;
420 gdk_image_get_pixel (GdkImage *image,
425 GdkImagePrivateX11 *private;
427 g_return_val_if_fail (GDK_IS_IMAGE (image), 0);
429 private = PRIVATE_DATA (image);
431 pixel = XGetPixel (private->ximage, x, y);
437 gdk_image_put_pixel (GdkImage *image,
442 GdkImagePrivateX11 *private;
444 g_return_if_fail (GDK_IS_IMAGE (image));
446 private = PRIVATE_DATA (image);
448 pixel = XPutPixel (private->ximage, x, y, pixel);
452 gdk_x11_image_destroy (GdkImage *image)
454 GdkImagePrivateX11 *private;
456 XShmSegmentInfo *x_shm_info;
459 g_return_if_fail (GDK_IS_IMAGE (image));
461 private = PRIVATE_DATA (image);
463 if (private == NULL) /* This means that gdk_image_exit() destroyed the
464 * image already, and now we're called a second
465 * time from _finalize()
471 case GDK_IMAGE_NORMAL:
472 XDestroyImage (private->ximage);
475 case GDK_IMAGE_SHARED:
479 XShmDetach (private->xdisplay, private->x_shm_info);
480 XDestroyImage (private->ximage);
482 x_shm_info = private->x_shm_info;
483 shmdt (x_shm_info->shmaddr);
485 g_free (private->x_shm_info);
486 private->x_shm_info = NULL;
488 image_list = g_list_remove (image_list, image);
490 g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support");
494 case GDK_IMAGE_FASTEST:
495 case GDK_IMAGE_SHARED_PIXMAP:
496 g_assert_not_reached ();
500 image->windowing_data = NULL;