-/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
- * by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1993-2017 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
needed, anyway.)
If you don't have man pages for this extension, see
- http://www.physik.uni-regensburg.de/~scs22156/sofie-0.2/mit-shm.html
- or in the R6 sources as "xc/doc/specs/Xext/mit-shm.ms", for example,
- ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/mit-shm.ms
+ https://www.x.org/releases/current/doc/xextproto/shm.html
(This document seems not to ever remain available on the web in one place
for very long; you can search for it by the title, "MIT-SHM -- The MIT
#include "utils.h"
-#ifdef HAVE_XSHM_EXTENSION /* whole file */
-
/* #define DEBUG */
#include <errno.h> /* for perror() */
-#include <X11/Xutil.h> /* for XDestroyImage() */
+
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else
+# include <X11/Xutil.h> /* for XDestroyImage() */
+#endif
#include "xshm.h"
#include "resources.h" /* for get_string_resource() */
+#include "thread_util.h" /* for thread_malloc() */
#ifdef DEBUG
# include <X11/Xmu/Error.h>
of our XSHM calls, sigh.
*/
+#ifdef HAVE_XSHM_EXTENSION
+
static Bool shm_got_x_error = False;
XErrorHandler old_handler = 0;
static int
old_handler = 0; \
} while(0)
+#endif /* HAVE_XSHM_EXTENSION */
+
+
+static void
+print_error (int err)
+{
+ fprintf(stderr, "%s: %s\n", progname, strerror(err));
+}
+
+static XImage *
+create_fallback (Display *dpy, Visual *visual,
+ unsigned int depth,
+ int format, XShmSegmentInfo *shm_info,
+ unsigned int width, unsigned int height)
+{
+ XImage *image = XCreateImage (dpy, visual, depth, format, 0, NULL,
+ width, height, BitmapPad(dpy), 0);
+ shm_info->shmid = -1;
+
+ if (!image) {
+ print_error (ENOMEM);
+ } else {
+ /* Sometimes the XImage data needs to be aligned, such as for SIMD (SSE2
+ in Fireworkx), or multithreading (AnalogTV).
+ */
+ int error = thread_malloc ((void **)&image->data, dpy,
+ image->height * image->bytes_per_line);
+ if (error) {
+ print_error (error);
+ XDestroyImage (image);
+ image = NULL;
+ } else {
+ memset (image->data, 0, image->height * image->bytes_per_line);
+ }
+ }
+
+ return image;
+}
+
XImage *
create_xshm_image (Display *dpy, Visual *visual,
unsigned int depth,
- int format, char *data,
- XShmSegmentInfo *shm_info,
+ int format, XShmSegmentInfo *shm_info,
unsigned int width, unsigned int height)
{
+#ifndef HAVE_XSHM_EXTENSION
+
+ return create_fallback (dpy, visual, depth, format, shm_info, width, height);
+
+#else /* HAVE_XSHM_EXTENSION */
+
Status status;
XImage *image = 0;
- if (!get_boolean_resource("useSHM", "Boolean"))
- return 0;
-
- if (!XShmQueryExtension (dpy))
- return 0;
+ if (!get_boolean_resource(dpy, "useSHM", "Boolean") ||
+ !XShmQueryExtension (dpy)) {
+ return create_fallback (dpy, visual, depth, format, shm_info,
+ width, height);
+ }
CATCH_X_ERROR(dpy);
image = XShmCreateImage(dpy, visual, depth,
- format, data, shm_info, width, height);
+ format, NULL, shm_info, width, height);
UNCATCH_X_ERROR(dpy);
if (shm_got_x_error)
- return 0;
+ return create_fallback (dpy, visual, depth, format, shm_info,
+ width, height);
#ifdef DEBUG
fprintf(stderr, "\n%s: XShmCreateImage(... %d, %d)\n", progname,
shmdt (shm_info->shmaddr);
image = 0;
}
-
#ifdef DEBUG
- fprintf(stderr, "%s: XShmAttach(dpy, shm_info) ==> True\n", progname);
+ else
+ fprintf(stderr, "%s: XShmAttach(dpy, shm_info) ==> True\n", progname);
#endif
XSync(dpy, False);
#endif
}
+ if (!image) {
+ return create_fallback (dpy, visual, depth, format, shm_info,
+ width, height);
+ }
+
return image;
+
+#endif /* HAVE_XSHM_EXTENSION */
}
+
+Bool
+put_xshm_image (Display *dpy, Drawable d, GC gc, XImage *image,
+ int src_x, int src_y, int dest_x, int dest_y,
+ unsigned int width, unsigned int height,
+ XShmSegmentInfo *shm_info)
+{
+#ifdef HAVE_XSHM_EXTENSION
+ assert (shm_info); /* Don't just s/XShmPutImage/put_xshm_image/. */
+ if (shm_info->shmid != -1) {
+ /* XShmPutImage is asynchronous; the contents of the XImage must not be
+ modified until the server has placed the pixels on the screen and the
+ client has received an XShmCompletionEvent. Breaking this rule can cause
+ tearing. That said, put_xshm_image doesn't provide a send_event
+ parameter, so we're always breaking this rule. Not that it seems to
+ matter; everything (so far) looks fine without it.
+
+ ####: Add a send_event parameter. And fake it for XPutImage.
+ */
+ return XShmPutImage (dpy, d, gc, image, src_x, src_y, dest_x, dest_y,
+ width, height, False);
+ }
#endif /* HAVE_XSHM_EXTENSION */
+
+ return XPutImage (dpy, d, gc, image, src_x, src_y, dest_x, dest_y,
+ width, height);
+}
+
+
+Bool
+get_xshm_image (Display *dpy, Drawable d, XImage *image, int x, int y,
+ unsigned long plane_mask, XShmSegmentInfo *shm_info)
+{
+#ifdef HAVE_XSHM_EXTENSION
+ if (shm_info->shmid != -1) {
+ return XShmGetImage (dpy, d, image, x, y, plane_mask);
+ }
+#endif /* HAVE_XSHM_EXTENSION */
+ return XGetSubImage (dpy, d, x, y, image->width, image->height, plane_mask,
+ image->format, image, 0, 0) != NULL;
+}
+
+
+void
+destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
+{
+#ifdef HAVE_XSHM_EXTENSION
+ if (shm_info->shmid == -1) {
+#endif /* HAVE_XSHM_EXTENSION */
+
+ /* Don't let XDestroyImage free image->data. */
+ thread_free (image->data);
+ image->data = NULL;
+ XDestroyImage (image);
+ return;
+
+#ifdef HAVE_XSHM_EXTENSION
+ }
+
+ Status status;
+
+ CATCH_X_ERROR(dpy);
+ status = XShmDetach (dpy, shm_info);
+ UNCATCH_X_ERROR(dpy);
+ if (shm_got_x_error)
+ status = False;
+ if (!status)
+ fprintf (stderr, "%s: XShmDetach failed!\n", progname);
+#ifdef DEBUG
+ else
+ fprintf (stderr, "%s: XShmDetach(dpy, shm_info) ==> True\n", progname);
+#endif
+
+ XDestroyImage (image);
+ XSync(dpy, False);
+
+ status = shmdt (shm_info->shmaddr);
+
+ if (status != 0)
+ {
+ char buf[1024];
+ sprintf (buf, "%s: shmdt(0x%lx) failed", progname,
+ (unsigned long) shm_info->shmaddr);
+ perror(buf);
+ }
+#ifdef DEBUG
+ else
+ fprintf (stderr, "%s: shmdt(shm_info->shmaddr) ==> 0\n", progname);
+#endif
+
+ XSync(dpy, False);
+
+#endif /* HAVE_XSHM_EXTENSION */
+}