/* grab-ximage.c --- grab the screen to an XImage for use with OpenGL.
- * xscreensaver, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 2001, 2003 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
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h> /* only for GLfloat */
extern char *progname;
#include <X11/Xutil.h>
+#include <sys/time.h>
#undef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
}
-/* Returns an XImage structure containing an image of the desktop.
- (As a side-effect, that image will be painted onto the given Window.)
- This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
- extra byte set to 0xFF.
- */
-XImage *
-screen_to_ximage (Screen *screen, Window window)
+static Bool
+bigendian (void)
+{
+ union { int i; char c[sizeof(int)]; } u;
+ u.i = 1;
+ return !u.c[0];
+}
+
+
+static XImage *
+screen_to_ximage_1 (Screen *screen, Window window, Pixmap pixmap)
{
Display *dpy = DisplayOfScreen (screen);
XWindowAttributes xgwa;
int win_width, win_height;
int tex_width, tex_height;
- grab_screen_image (screen, window);
-
XGetWindowAttributes (dpy, window, &xgwa);
win_width = xgwa.width;
win_height = xgwa.height;
tex_width = to_pow2(win_width);
tex_height = to_pow2(win_height);
- /* Convert the server-side Drawable to a client-side GL-ordered XImage.
+ /* Convert the server-side Pixmap to a client-side GL-ordered XImage.
*/
{
XImage *ximage1, *ximage2;
XColor *colors = 0;
- ximage1 = XGetImage (dpy, window, 0, 0, win_width, win_height, ~0L,
+ ximage1 = XGetImage (dpy, pixmap, 0, 0, win_width, win_height, ~0L,
ZPixmap);
+ XFreePixmap (dpy, pixmap);
+ pixmap = 0;
+
ximage2 = XCreateImage (dpy, xgwa.visual, 32, ZPixmap, 0, 0,
tex_width, tex_height, 32, 0);
*/
{
int x, y;
- int crpos, cgpos, cbpos, capos; /* bitfield positions */
- int srpos, sgpos, sbpos;
- int srmsk, sgmsk, sbmsk;
- int srsiz, sgsiz, sbsiz;
+ unsigned int crpos=0, cgpos=0, cbpos=0, capos=0; /* bitfield positions */
+ unsigned int srpos=0, sgpos=0, sbpos=0;
+ unsigned int srmsk=0, sgmsk=0, sbmsk=0;
+ unsigned int srsiz=0, sgsiz=0, sbsiz=0;
int i;
unsigned char spread_map[3][256];
- srmsk = ximage1->red_mask;
- sgmsk = ximage1->green_mask;
- sbmsk = ximage1->blue_mask;
+ if (colors == 0) /* truecolor */
+ {
+ srmsk = ximage2->red_mask;
+ sgmsk = ximage2->green_mask;
+ sbmsk = ximage2->blue_mask;
- decode_mask (srmsk, &srpos, &srsiz);
- decode_mask (sgmsk, &sgpos, &sgsiz);
- decode_mask (sbmsk, &sbpos, &sbsiz);
+ decode_mask (srmsk, &srpos, &srsiz);
+ decode_mask (sgmsk, &sgpos, &sgsiz);
+ decode_mask (sbmsk, &sbpos, &sbsiz);
+ }
/* Note that unlike X, which is endianness-agnostic (since any XImage
can have its own specific bit ordering, with the server reversing
we need to pack things in "RGBA" order on the client machine,
regardless of its endianness.
*/
- crpos = 0, cgpos = 8, cbpos = 16, capos = 24;
+ if (bigendian())
+ crpos = 24, cgpos = 16, cbpos = 8, capos = 0;
+ else
+ crpos = 0, cgpos = 8, cbpos = 16, capos = 24;
- for (i = 0; i < 256; i++)
+ if (colors == 0) /* truecolor */
{
- spread_map[0][i] = spread_bits (i, srsiz);
- spread_map[1][i] = spread_bits (i, sgsiz);
- spread_map[2][i] = spread_bits (i, sbsiz);
+ for (i = 0; i < 256; i++)
+ {
+ spread_map[0][i] = spread_bits (i, srsiz);
+ spread_map[1][i] = spread_bits (i, sgsiz);
+ spread_map[2][i] = spread_bits (i, sbsiz);
+ }
}
for (y = 0; y < win_height; y++)
}
}
+ if (pixmap) XFreePixmap (dpy, pixmap);
if (colors) free (colors);
free (ximage1->data);
ximage1->data = 0;
return ximage2;
}
}
+
+
+/* Returns an XImage structure containing an image of the desktop.
+ (As a side-effect, that image *may* be painted onto the given Window.)
+ This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
+ extra byte set to 0xFF.
+ */
+XImage *
+screen_to_ximage (Screen *screen, Window window, char **filename_return)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ Pixmap pixmap = 0;
+ XWindowAttributes xgwa;
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ pixmap = XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
+ load_random_image (screen, window, pixmap, filename_return);
+
+ return screen_to_ximage_1 (screen, window, pixmap);
+}
+
+
+typedef struct {
+ void (*callback) (Screen *, Window, XImage *,
+ const char *name, void *closure, double cvt_time);
+ void *closure;
+ Pixmap pixmap;
+} img_closure;
+
+
+/* Returns the current time in seconds as a double.
+ */
+static double
+double_time (void)
+{
+ struct timeval now;
+# ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tzp;
+ gettimeofday(&now, &tzp);
+# else
+ gettimeofday(&now);
+# endif
+
+ return (now.tv_sec + ((double) now.tv_usec * 0.000001));
+}
+
+
+static void
+img_cb (Screen *screen, Window window, Drawable drawable,
+ const char *name, void *closure)
+{
+ XImage *ximage;
+ double cvt_time = double_time();
+ img_closure *data = (img_closure *) closure;
+ /* copy closure data to stack and free the original before running cb */
+ img_closure dd = *data;
+ memset (data, 0, sizeof (*data));
+ free (data);
+ data = 0;
+ ximage = screen_to_ximage_1 (screen, window, dd.pixmap);
+ dd.callback (screen, window, ximage, name, dd.closure, cvt_time);
+}
+
+
+/* Like the above, but loads the image in the background and runs the
+ given callback once it has been loaded.
+ */
+#include <X11/Intrinsic.h>
+extern XtAppContext app;
+
+void
+fork_screen_to_ximage (Screen *screen, Window window,
+ void (*callback) (Screen *, Window, XImage *,
+ const char *name,
+ void *closure,
+ double cvt_time),
+ void *closure)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ img_closure *data = (img_closure *) calloc (1, sizeof(*data));
+ data->callback = callback;
+ data->closure = closure;
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ data->pixmap = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,
+ xgwa.depth);
+ fork_load_random_image (screen, window, data->pixmap, img_cb, data);
+}