+static void screen_to_texture_async_cb (Screen *screen,
+ Window window, Drawable drawable,
+ const char *name, XRectangle *geometry,
+ void *closure);
+
+
+/* Grabs an image of the desktop (or another random image file) and
+ loads tht image into GL's texture memory.
+ Writes to stderr and returns False on error.
+ */
+Bool
+screen_to_texture (Screen *screen, Window window,
+ int desired_width, int desired_height,
+ Bool mipmap_p,
+ char **filename_return,
+ XRectangle *geometry_return,
+ int *image_width_return,
+ int *image_height_return,
+ int *texture_width_return,
+ int *texture_height_return)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ img_closure *data = (img_closure *) calloc (1, sizeof(*data));
+ XWindowAttributes xgwa;
+ char *filename = 0;
+ XRectangle geom = { 0, 0, 0, 0 };
+ int wret;
+
+ if (! image_width_return)
+ image_width_return = &wret;
+
+ if (debug_p)
+ data->load_time = double_time();
+
+ data->texid = -1;
+ data->mipmap_p = mipmap_p;
+ data->filename_return = filename_return;
+ data->geometry_return = geometry_return;
+ data->image_width_return = image_width_return;
+ data->image_height_return = image_height_return;
+ data->texture_width_return = texture_width_return;
+ data->texture_height_return = texture_height_return;
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ data->pix_width = xgwa.width;
+ data->pix_height = xgwa.height;
+ data->pix_depth = xgwa.depth;
+
+ if (desired_width && desired_width < xgwa.width)
+ data->pix_width = desired_width;
+ if (desired_height && desired_height < xgwa.height)
+ data->pix_height = desired_height;
+
+ data->pixmap = XCreatePixmap (dpy, window, data->pix_width, data->pix_height,
+ data->pix_depth);
+ load_random_image (screen, window, data->pixmap, &filename, &geom);
+ screen_to_texture_async_cb (screen, window, data->pixmap, filename, &geom,
+ data);
+
+ return (*image_width_return != 0);
+}
+
+
+/* Like the above, but the image is loaded in a background process,
+ and a callback is run when the loading is complete.
+ When the callback is called, the image data will have been loaded
+ into texture number `texid' (via glBindTexture.)
+
+ If an error occurred, width/height will be 0.
+ */
+void
+screen_to_texture_async (Screen *screen, Window window,
+ int desired_width, int desired_height,
+ Bool mipmap_p,
+ GLuint texid,
+ void (*callback) (const char *filename,
+ XRectangle *geometry,
+ int image_width,
+ int image_height,
+ int texture_width,
+ int texture_height,
+ void *closure),
+ void *closure)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ img_closure *data = (img_closure *) calloc (1, sizeof(*data));
+
+ if (debug_p)
+ data->load_time = double_time();
+
+ data->texid = texid;
+ data->mipmap_p = mipmap_p;
+ data->callback = callback;
+ data->closure = closure;
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ data->pix_width = xgwa.width;
+ data->pix_height = xgwa.height;
+ data->pix_depth = xgwa.depth;
+
+ if (desired_width && desired_width < xgwa.width)
+ data->pix_width = desired_width;
+ if (desired_height && desired_height < xgwa.height)
+ data->pix_height = desired_height;
+
+ data->pixmap = XCreatePixmap (dpy, window, data->pix_width, data->pix_height,
+ data->pix_depth);
+ fork_load_random_image (screen, window, data->pixmap,
+ screen_to_texture_async_cb, data);
+}
+
+
+/* Once we have an XImage, this loads it into GL.
+ This is used in both synchronous and asynchronous mode.
+ */
+static void
+screen_to_texture_async_cb (Screen *screen, Window window, Drawable drawable,
+ const char *name, XRectangle *geometry,
+ void *closure)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ Bool ok;
+ XImage *ximage;
+ GLint type, format;
+ int iw=0, ih=0, tw=0, th=0;
+ double cvt_time=0, tex_time=0, done_time=0;
+ 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;
+
+ if (geometry->width <= 0 || geometry->height <= 0)
+ {
+ /* This can happen if an old version of xscreensaver-getimage
+ is installed. */
+ geometry->x = 0;
+ geometry->y = 0;
+ geometry->width = dd.pix_width;
+ geometry->height = dd.pix_height;
+ }
+
+ if (geometry->width <= 0 || geometry->height <= 0)
+ abort();
+
+ if (debug_p)
+ cvt_time = double_time();
+
+# ifdef REFORMAT_IMAGE_DATA
+ ximage = pixmap_to_gl_ximage (screen, window, dd.pixmap);
+ format = GL_RGBA;
+ type = GL_UNSIGNED_BYTE;
+
+#else /* ! REFORMAT_IMAGE_DATA */
+ {
+ Visual *visual = DefaultVisualOfScreen (screen);
+ GLint swap;
+
+ ximage = XCreateImage (dpy, visual, dd.pix_depth, ZPixmap, 0, 0,
+ dd.pix_width, dd.pix_height, 32, 0);
+
+ /* Note: height+2 in "to" to be to work around an array bounds overrun
+ in gluBuild2DMipmaps / gluScaleImage. */
+ ximage->data = (char *) calloc (ximage->height+2, ximage->bytes_per_line);
+
+ if (!ximage->data ||
+ !XGetSubImage (dpy, dd.pixmap, 0, 0, ximage->width, ximage->height,
+ ~0L, ximage->format, ximage, 0, 0))
+ {
+ XDestroyImage (ximage);
+ ximage = 0;
+ }
+
+ gl_settings_for_ximage (ximage, &type, &format, &swap);
+ glPixelStorei (GL_UNPACK_SWAP_BYTES, !swap);