diff options
Diffstat (limited to 'gdk/x11/gdkimage-x11.c')
-rw-r--r-- | gdk/x11/gdkimage-x11.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c new file mode 100644 index 0000000000..bcda3119fc --- /dev/null +++ b/gdk/x11/gdkimage-x11.c @@ -0,0 +1,492 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include <sys/types.h> + +#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) +#define USE_SHM +#endif + +#ifdef USE_SHM +#include <sys/ipc.h> +#include <sys/shm.h> +#endif /* USE_SHM */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#ifdef USE_SHM +#include <X11/extensions/XShm.h> +#endif /* USE_SHM */ + +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + + +static GList *image_list = NULL; + + +void +gdk_image_exit () +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap, + 0, 0, w ,h, 8, 0); + private->ximage->data = data; + private->ximage->bitmap_bit_order = MSBFirst; + private->ximage->byte_order = MSBFirst; + image->byte_order = MSBFirst; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +static int +gdk_image_check_xshm(Display *display) +/* + * Desc: query the server for support for the MIT_SHM extension + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +{ +#ifdef USE_SHM + int major, minor, ignore; + Bool pixmaps; + + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) + { + return (pixmaps==True) ? 2 : 1; + } + } +#endif /* USE_SHM */ + return 0; +} + +void +gdk_image_init () +{ + if (gdk_use_xshm) + { + if (!gdk_image_check_xshm (gdk_display)) + { + g_warning ("MIT-SHM Extension not availible on server"); + gdk_use_xshm = False; + } + } +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + Visual *xvisual; + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + + if (!image) + image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = visual->depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + if (gdk_use_xshm) + { + private->image_put = gdk_image_put_shared; + + private->x_shm_info = g_new (XShmSegmentInfo, 1); + x_shm_info = private->x_shm_info; + + private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, NULL, x_shm_info, width, height); + if (private->ximage == NULL) + { + g_warning ("XShmCreateImage failed"); + + g_free (image); + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->shmid = shmget (IPC_PRIVATE, + private->ximage->bytes_per_line * private->ximage->height, + IPC_CREAT | 0777); + + if (x_shm_info->shmid == -1) + { + g_warning ("shmget failed!"); + + XDestroyImage (private->ximage); + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->readOnly = False; + x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0); + private->ximage->data = x_shm_info->shmaddr; + + if (x_shm_info->shmaddr == (char*) -1) + { + g_warning ("shmat failed!"); + + XDestroyImage (private->ximage); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + return NULL; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (x_shm_info->shmaddr != (char*) -1) + shmctl (x_shm_info->shmid, IPC_RMID, 0); +#endif + + gdk_error_code = 0; + gdk_error_warnings = 0; + + XShmAttach (private->xdisplay, x_shm_info); + XSync (private->xdisplay, False); + + gdk_error_warnings = 1; + if (gdk_error_code == -1) + { + g_warning ("XShmAttach failed!"); + + XDestroyImage (private->ximage); + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + return NULL; + } + + if (image) + image_list = g_list_prepend (image_list, image); + } + else + { + g_free (image); + return NULL; + } + break; +#else /* USE_SHM */ + g_free (image); + return NULL; +#endif /* USE_SHM */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, 0, 0, width, height, 32, 0); + + private->ximage->data = g_new (char, private->ximage->bytes_per_line * + private->ximage->height); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + if (image) + { + image->byte_order = private->ximage->byte_order; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + + switch (private->ximage->bits_per_pixel) + { + case 8: + image->bpp = 1; + break; + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + } + } + } + + return image; +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + private->ximage = XGetImage (private->xdisplay, + win_private->xwindow, + x, y, width, height, + AllPlanes, ZPixmap); + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + image->depth = private->ximage->depth; + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + pixel = XGetPixel (private->ximage, x, y); + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + pixel = XPutPixel (private->ximage, x, y, pixel); +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + switch (image->type) + { + case GDK_IMAGE_NORMAL: + XDestroyImage (private->ximage); + break; + + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + XShmDetach (private->xdisplay, private->x_shm_info); + XDestroyImage (private->ximage); + + x_shm_info = private->x_shm_info; + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + + image_list = g_list_remove (image_list, image); +#else /* USE_SHM */ + g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_NORMAL); + + XPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height); +} + +static void +gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ +#ifdef USE_SHM + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_SHARED); + + XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height, False); +#else /* USE_SHM */ + g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ +} |