http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / utils / xshm.c
index d37afa47cd7f8856b31fbb80369cffd959564732..a05601503663f9473927d9a20b791f52ecf00846 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
+/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 2001
  *  by Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
@@ -21,8 +21,7 @@
    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".
+   http://www.x.org/X11R6.8.1/docs/Xext/
 
    (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
 
 #ifdef HAVE_XSHM_EXTENSION     /* whole file */
 
+/* #define DEBUG */
+
 #include <errno.h>             /* for perror() */
 #include <X11/Xutil.h>         /* for XDestroyImage() */
 
 #include "xshm.h"
 #include "resources.h"         /* for get_string_resource() */
 
+#ifdef DEBUG
+# include <X11/Xmu/Error.h>
+#endif
 
 extern char *progname;
 
+
+/* The documentation for the XSHM extension implies that if the server
+   supports XSHM but is not the local machine, the XShm calls will return
+   False; but this turns out not to be the case.  Instead, the server
+   throws a BadAccess error.  So, we need to catch X errors around all
+   of our XSHM calls, sigh.
+ */
+
+static Bool shm_got_x_error = False;
+XErrorHandler old_handler = 0;
+static int
+shm_ehandler (Display *dpy, XErrorEvent *error)
+{
+  shm_got_x_error = True;
+
+#ifdef DEBUG
+  fprintf (stderr, "\n%s: ignoring X error from XSHM:\n", progname);
+  XmuPrintDefaultErrorMessage (dpy, error, stderr);
+  fprintf (stderr, "\n");
+#endif
+
+  return 0;
+}
+
+
+#define CATCH_X_ERROR(DPY) do {                                \
+  XSync((DPY), False);                                         \
+  shm_got_x_error = False;                             \
+  if (old_handler != shm_ehandler)                     \
+    old_handler = XSetErrorHandler (shm_ehandler);     \
+} while(0)
+
+#define UNCATCH_X_ERROR(DPY) do {                      \
+  XSync((DPY), False);                                         \
+  if (old_handler)                                     \
+    XSetErrorHandler (old_handler);                    \
+    old_handler = 0;                                   \
+} while(0)
+
+
 XImage *
 create_xshm_image (Display *dpy, Visual *visual,
                   unsigned int depth,
@@ -51,6 +95,7 @@ create_xshm_image (Display *dpy, Visual *visual,
                   XShmSegmentInfo *shm_info,
                   unsigned int width, unsigned int height)
 {
+  Status status;
   XImage *image = 0;
   if (!get_boolean_resource("useSHM", "Boolean"))
     return 0;
@@ -58,8 +103,13 @@ create_xshm_image (Display *dpy, Visual *visual,
   if (!XShmQueryExtension (dpy))
     return 0;
 
+  CATCH_X_ERROR(dpy);
   image = XShmCreateImage(dpy, visual, depth,
-                             format, data, shm_info, width, height);
+                         format, data, shm_info, width, height);
+  UNCATCH_X_ERROR(dpy);
+  if (shm_got_x_error)
+    return 0;
+
 #ifdef DEBUG
   fprintf(stderr, "\n%s: XShmCreateImage(... %d, %d)\n", progname,
          width, height);
@@ -92,7 +142,13 @@ create_xshm_image (Display *dpy, Visual *visual,
              shm_info->shmid, (int) image->data);
 #endif
 
-      if (!XShmAttach(dpy, shm_info))
+      CATCH_X_ERROR(dpy);
+      status = XShmAttach(dpy, shm_info);
+      UNCATCH_X_ERROR(dpy);
+      if (shm_got_x_error)
+       status = False;
+
+      if (!status)
        {
          fprintf (stderr, "%s: XShmAttach failed!\n", progname);
          XDestroyImage (image);
@@ -100,9 +156,9 @@ create_xshm_image (Display *dpy, Visual *visual,
          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);
@@ -131,4 +187,43 @@ create_xshm_image (Display *dpy, Visual *visual,
   return image;
 }
 
+
+void
+destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
+{
+  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 */