#include <math.h>
#include "screenhack.h"
-#include <X11/Xutil.h>
-#include <sys/time.h>
#ifndef MIN
#define MIN(a, b) (((a) < (b))?(a):(b))
#define X_PERIOD 45000.0
#define Y_PERIOD 36000.0
-static int sizex, sizey;
+struct state {
+ Display *dpy;
+ Window window;
+ Screen *screen;
-static int delay;
-static int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety;
-static Bool lenses;
+ int sizex, sizey;
-static GC window_gc;
+ int delay;
+ int duration;
+ int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety;
+ Bool lenses;
-static XImage *orig_map;
-static Pixmap pm;
+ GC window_gc;
-static int tlx, tly, s;
+ XImage *orig_map;
+ Pixmap pm;
-static long currentTimeInMs(void)
+ int tlx, tly, s;
+
+ int sinusoid_offset;
+
+ time_t start_time;
+ async_load_state *img_loader;
+};
+
+
+static long currentTimeInMs(struct state *st)
{
struct timeval curTime;
#ifdef GETTIMEOFDAY_TWO_ARGS
return curTime.tv_sec*1000 + curTime.tv_usec/1000.0;
}
-static void init_hack(Display *dpy, Window window)
+static void *
+zoom_init (Display *dpy, Window window)
{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
XGCValues gcv;
XWindowAttributes xgwa;
Colormap cmap;
long gcflags;
int nblocksx, nblocksy;
- XGetWindowAttributes(dpy, window, &xgwa);
- sizex = xgwa.width;
- sizey = xgwa.height;
+ st->dpy = dpy;
+ st->window = window;
+ XGetWindowAttributes(st->dpy, st->window, &xgwa);
+ st->screen = xgwa.screen;
+ st->sizex = xgwa.width;
+ st->sizey = xgwa.height;
cmap = xgwa.colormap;
- fg = get_pixel_resource("foreground", "Foreground", dpy, cmap);
- bg = get_pixel_resource("background", "Background", dpy, cmap);
-
- delay = get_integer_resource("delay", "Integer");
- if (delay < 1)
- delay = 1;
- pixwidth = get_integer_resource("pixwidth", "Integer");
- if (pixwidth < 1)
- pixwidth = 1;
- pixheight = get_integer_resource("pixheight", "Integer");
- if (pixheight < 1)
- pixheight = 1;
- pixspacex = get_integer_resource("pixspacex", "Integer");
- if (pixspacex < 0)
- pixspacex = 0;
- pixspacey = get_integer_resource("pixspacey", "Integer");
- if (pixspacey < 0)
- pixspacey = 0;
- lenses = get_boolean_resource("lenses", "Boolean");
- lensoffsetx = get_integer_resource("lensoffsetx", "Integer");
- lensoffsetx = MAX(0, MIN(pixwidth, lensoffsetx));
- lensoffsety = get_integer_resource("lensoffsety", "Integer");
- lensoffsety = MAX(0, MIN(pixwidth, lensoffsety));
+ fg = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground");
+ bg = get_pixel_resource(st->dpy, cmap, "background", "Background");
+
+ st->delay = get_integer_resource(st->dpy, "delay", "Integer");
+ if (st->delay < 1)
+ st->delay = 1;
+ st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+ if (st->duration < 1)
+ st->duration = 1;
+ st->pixwidth = get_integer_resource(st->dpy, "pixwidth", "Integer");
+ if (st->pixwidth < 1)
+ st->pixwidth = 1;
+ st->pixheight = get_integer_resource(st->dpy, "pixheight", "Integer");
+ if (st->pixheight < 1)
+ st->pixheight = 1;
+ st->pixspacex = get_integer_resource(st->dpy, "pixspacex", "Integer");
+ if (st->pixspacex < 0)
+ st->pixspacex = 0;
+ st->pixspacey = get_integer_resource(st->dpy, "pixspacey", "Integer");
+ if (st->pixspacey < 0)
+ st->pixspacey = 0;
+ st->lenses = get_boolean_resource(st->dpy, "lenses", "Boolean");
+ st->lensoffsetx = get_integer_resource(st->dpy, "lensoffsetx", "Integer");
+ st->lensoffsetx = MAX(0, MIN(st->pixwidth, st->lensoffsetx));
+ st->lensoffsety = get_integer_resource(st->dpy, "lensoffsety", "Integer");
+ st->lensoffsety = MAX(0, MIN(st->pixwidth, st->lensoffsety));
gcv.function = GXcopy;
gcv.subwindow_mode = IncludeInferiors;
gcflags = GCForeground|GCFunction;
gcv.foreground = bg;
- if (!lenses && use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
+ if (!st->lenses && use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */
gcflags |= GCSubwindowMode;
- window_gc = XCreateGC(dpy, window, gcflags, &gcv);
+ st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv);
- grab_screen_image(xgwa.screen, window);
- if (lenses) {
- orig_map = NULL;
- pm = XCreatePixmap(dpy, window, sizex, sizey, xgwa.depth);
- XCopyArea(dpy, window, pm, window_gc, 0, 0, sizex, sizey, 0, 0);
- } else {
- orig_map = XGetImage(dpy, window, 0, 0, sizex, sizey, ~0L, ZPixmap);
- pm = 0;
- }
- XFillRectangle(dpy, window, window_gc, 0, 0, sizex, sizey);
- XSetWindowBackground(dpy, window, bg);
+ st->orig_map = NULL;
+ st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth);
- nblocksx = (int)ceil((double)sizex / (double)(pixwidth + pixspacex));
- nblocksy = (int)ceil((double)sizey / (double)(pixheight + pixspacey));
- if (lenses)
- s = MAX((nblocksx - 1) * lensoffsetx + pixwidth,
- (nblocksy - 1) * lensoffsety + pixheight) * 2;
+ XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey);
+ XSetWindowBackground(st->dpy, st->window, bg);
+
+ st->start_time = time ((time_t) 0);
+ st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+ st->pm, 0, 0);
+
+ /* We might have needed this to grab the image, but if we leave this set
+ to GCSubwindowMode, then we'll *draw* right over subwindows too. */
+ XSetSubwindowMode (st->dpy, st->window_gc, ClipByChildren);
+
+
+ nblocksx = (int)ceil((double)st->sizex / (double)(st->pixwidth + st->pixspacex));
+ nblocksy = (int)ceil((double)st->sizey / (double)(st->pixheight + st->pixspacey));
+ if (st->lenses)
+ st->s = MAX((nblocksx - 1) * st->lensoffsetx + st->pixwidth,
+ (nblocksy - 1) * st->lensoffsety + st->pixheight) * 2;
else
- s = MAX(nblocksx, nblocksy) * 2;
+ st->s = MAX(nblocksx, nblocksy) * 2;
+
+ st->sinusoid_offset = random();
+
+ return st;
}
-static void onestep(Display *dpy, Window window)
+static unsigned long
+zoom_draw (Display *dpy, Window window, void *closure)
{
+ struct state *st = (struct state *) closure;
unsigned x, y, i, j;
long now;
+ if (st->img_loader) /* still loading */
+ {
+ st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
+ if (! st->img_loader) { /* just finished */
+ XClearWindow (st->dpy, st->window);
+ st->start_time = time ((time_t) 0);
+ if (!st->lenses) {
+ st->orig_map = XGetImage(st->dpy, st->pm, 0, 0, st->sizex, st->sizey, ~0L, ZPixmap);
+/* XFreePixmap(st->dpy, st->pm);
+ st->pm = 0;*/
+ }
+ }
+ return st->delay;
+ }
+
+ if (!st->img_loader &&
+ st->start_time + st->duration < time ((time_t) 0)) {
+ st->img_loader = load_image_async_simple (0, st->screen, st->window,
+ st->pm, 0, 0);
+ return st->delay;
+ }
+
#define nrnd(x) (random() % (x))
- now = currentTimeInMs();
+ now = currentTimeInMs(st);
+ now += st->sinusoid_offset; /* don't run multiple screens in lock-step */
/* find new x,y */
- tlx = ((1. + sin(((float)now) / X_PERIOD * 2. * M_PI))/2.0)
- * (sizex - s/2) /* -s/4 */ + MINX;
- tly = ((1. + sin(((float)now) / Y_PERIOD * 2. * M_PI))/2.0)
- * (sizey - s/2) /* -s/4 */ + MINY;
-
- if (lenses) {
- for (x = i = 0; x < sizex; x += (pixwidth + pixspacex), ++i)
- for (y = j = 0; y < sizey; y += (pixheight + pixspacey), ++j) {
- XCopyArea(dpy, pm /* src */, window /* dest */, window_gc,
- tlx + i * lensoffsetx /* src_x */,
- tly + j * lensoffsety /* src_y */,
- pixwidth, pixheight,
+ st->tlx = ((1. + sin(((double)now) / X_PERIOD * 2. * M_PI))/2.0)
+ * (st->sizex - st->s/2) /* -s/4 */ + MINX;
+ st->tly = ((1. + sin(((double)now) / Y_PERIOD * 2. * M_PI))/2.0)
+ * (st->sizey - st->s/2) /* -s/4 */ + MINY;
+
+ if (st->lenses) {
+ for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i)
+ for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) {
+ XCopyArea(st->dpy, st->pm /* src */, st->window /* dest */, st->window_gc,
+ st->tlx + i * st->lensoffsetx /* src_x */,
+ st->tly + j * st->lensoffsety /* src_y */,
+ st->pixwidth, st->pixheight,
x /* dest_x */, y /* dest_y */);
}
} else {
- for (x = i = 0; x < sizex; x += (pixwidth + pixspacex), ++i)
- for (y = j = 0; y < sizey; y += (pixheight + pixspacey), ++j) {
- XSetForeground(dpy, window_gc, XGetPixel(orig_map, tlx+i, tly+j));
- XFillRectangle(dpy, window, window_gc,
- i * (pixwidth + pixspacex),
- j * (pixheight + pixspacey), pixwidth, pixheight);
+ for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i)
+ for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) {
+ XSetForeground(st->dpy, st->window_gc, XGetPixel(st->orig_map, st->tlx+i, st->tly+j));
+ XFillRectangle(st->dpy, st->window, st->window_gc,
+ i * (st->pixwidth + st->pixspacex),
+ j * (st->pixheight + st->pixspacey), st->pixwidth, st->pixheight);
}
}
+
+ return st->delay;
+}
+
+static void
+zoom_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+}
+
+static Bool
+zoom_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ return False;
+}
+
+static void
+zoom_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ XFreeGC (st->dpy, st->window_gc);
+ if (st->orig_map) XDestroyImage (st->orig_map);
+ if (st->pm) XFreePixmap (st->dpy, st->pm);
+ free (st);
}
-char *progclass = "Zoom";
-char *defaults[] = {
+static const char *zoom_defaults[] = {
"*dontClearRoot: True",
+ ".foreground: white",
+ ".background: #111111",
+ "*fpsSolid: true",
#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
"*visualID: Best",
#endif
- "*lenses: false",
+ "*lenses: true",
"*delay: 10000",
+ "*duration: 120",
"*pixwidth: 10",
"*pixheight: 10",
"*pixspacex: 2",
0
};
-XrmOptionDescRec options[] = {
+static XrmOptionDescRec zoom_options[] = {
{ "-lenses", ".lenses", XrmoptionNoArg, "true" },
+ { "-no-lenses", ".lenses", XrmoptionNoArg, "false" },
{ "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-duration", ".duration", XrmoptionSepArg, 0 },
{ "-pixwidth", ".pixwidth", XrmoptionSepArg, 0 },
{ "-pixheight", ".pixheight", XrmoptionSepArg, 0 },
{ "-pixspacex", ".pixspacex", XrmoptionSepArg, 0 },
- { "-pixspacey", ".pixspacex", XrmoptionSepArg, 0 },
+ { "-pixspacey", ".pixspacey", XrmoptionSepArg, 0 },
{ "-lensoffsetx", ".lensoffsetx", XrmoptionSepArg, 0 },
{ "-lensoffsety", ".lensoffsety", XrmoptionSepArg, 0 },
{ 0, 0, 0, 0 }
};
-void screenhack(Display *dpy, Window window)
-{
- init_hack(dpy, window);
- while (1) {
- onestep(dpy, window);
- XSync(dpy, False);
- if (delay)
- usleep(delay);
- screenhack_handle_events(dpy);
- }
-}
+XSCREENSAVER_MODULE ("Zoom", zoom)