--- /dev/null
+/*
+ * Copyright (C) 2000 James Macnicol
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#include <math.h>
+#include "screenhack.h"
+#include <X11/Xutil.h>
+#include <sys/time.h>
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b))?(a):(b))
+#endif
+
+#define MINX 0.0
+#define MINY 0.0
+/* This should be *way* slower than the spotlight hack was */
+#define X_PERIOD 45000.0
+#define Y_PERIOD 36000.0
+
+static int sizex, sizey;
+
+static int delay;
+static int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety;
+static Bool lenses;
+
+static GC window_gc;
+
+static XImage *orig_map;
+static Pixmap pm;
+
+static int tlx, tly, s;
+
+static long currentTimeInMs(void)
+{
+ struct timeval curTime;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tz = {0,0};
+ gettimeofday(&curTime, &tz);
+#else
+ gettimeofday(&curTime);
+#endif
+ return curTime.tv_sec*1000 + curTime.tv_usec/1000.0;
+}
+
+static void init_hack(Display *dpy, Window window)
+{
+ XGCValues gcv;
+ XWindowAttributes xgwa;
+ Colormap cmap;
+ unsigned long fg, bg;
+ long gcflags;
+ int nblocksx, nblocksy;
+
+ XGetWindowAttributes(dpy, window, &xgwa);
+ sizex = xgwa.width;
+ 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));
+
+ 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 */
+ gcflags |= GCSubwindowMode;
+ window_gc = XCreateGC(dpy, 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);
+
+ 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;
+ else
+ s = MAX(nblocksx, nblocksy) * 2;
+}
+
+static void onestep(Display *dpy, Window window)
+{
+ unsigned x, y, i, j;
+
+ long now;
+
+#define nrnd(x) (random() % (x))
+
+ now = currentTimeInMs();
+
+ /* 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,
+ 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);
+ }
+ }
+}
+
+char *progclass = "Zoom";
+
+char *defaults[] = {
+ "*dontClearRoot: True",
+#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
+ "*visualID: Best",
+#endif
+ "*lenses: false",
+ "*delay: 10000",
+ "*pixwidth: 10",
+ "*pixheight: 10",
+ "*pixspacex: 2",
+ "*pixspacey: 2",
+ "*lensoffsetx: 5",
+ "*lensoffsety: 5",
+ 0
+};
+
+XrmOptionDescRec options[] = {
+ { "-lenses", ".lenses", XrmoptionNoArg, "true" },
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-pixwidth", ".pixwidth", XrmoptionSepArg, 0 },
+ { "-pixheight", ".pixheight", XrmoptionSepArg, 0 },
+ { "-pixspacex", ".pixspacex", XrmoptionSepArg, 0 },
+ { "-pixspacey", ".pixspacex", 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);
+ }
+}