summaryrefslogtreecommitdiffstats
path: root/hacks/zoom.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/zoom.c')
-rw-r--r--hacks/zoom.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/hacks/zoom.c b/hacks/zoom.c
new file mode 100644
index 0000000..35ba248
--- /dev/null
+++ b/hacks/zoom.c
@@ -0,0 +1,291 @@
+/*
+ * 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 <limits.h>
+#include "screenhack.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 * 3)
+#define Y_PERIOD (36000.0 * 3)
+
+struct state {
+ Display *dpy;
+ Window window;
+ Screen *screen;
+
+ int sizex, sizey;
+
+ int delay;
+ int duration;
+ int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety;
+ Bool lenses;
+
+ GC window_gc;
+
+ XImage *orig_map;
+ Pixmap pm;
+
+ 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;
+ unsigned long ret_unsigned;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tz = {0,0};
+ gettimeofday(&curTime, &tz);
+#else
+ gettimeofday(&curTime);
+#endif
+ ret_unsigned = curTime.tv_sec *1000U + curTime.tv_usec / 1000;
+ return (ret_unsigned <= LONG_MAX) ? ret_unsigned : -1 - (long)(ULONG_MAX - ret_unsigned);
+}
+
+static void *
+zoom_init (Display *dpy, Window window)
+{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
+ XGCValues gcv;
+ XWindowAttributes xgwa;
+ Colormap cmap;
+ unsigned long bg;
+ long gcflags;
+ int nblocksx, nblocksy;
+
+ 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;
+ 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;
+
+ if (st->sizex < 50 || st->sizey < 50) { /* tiny window */
+ st->pixwidth = 10;
+ st->pixheight = 10;
+ }
+
+ 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 (!st->lenses && use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */
+ gcflags |= GCSubwindowMode;
+ st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv);
+
+
+ st->orig_map = NULL;
+ st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth);
+
+ 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
+ st->s = MAX(nblocksx, nblocksy) * 2;
+
+ st->sinusoid_offset = random();
+
+ return st;
+}
+
+static unsigned long
+zoom_draw (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ unsigned x, y, i, j;
+
+ long now;
+ unsigned long now_unsigned;
+
+ 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(st);
+ now_unsigned = (unsigned long) now + st->sinusoid_offset; /* don't run multiple screens in lock-step */
+ now = (now_unsigned <= LONG_MAX) ? now_unsigned : -1 - (long)(ULONG_MAX - now_unsigned);
+
+ /* find new x,y */
+ 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 < 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)
+{
+ struct state *st = (struct state *) closure;
+ if (screenhack_event_helper (dpy, window, event))
+ {
+ st->start_time = 0;
+ return True;
+ }
+ 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);
+}
+
+
+static const char *zoom_defaults[] = {
+ "*dontClearRoot: True",
+ ".foreground: white",
+ ".background: #111111",
+ ".lowrez: true",
+ "*fpsSolid: true",
+#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
+ "*visualID: Best",
+#endif
+ "*lenses: true",
+ "*delay: 10000",
+ "*duration: 120",
+ "*pixwidth: 40",
+ "*pixheight: 40",
+ "*pixspacex: 2",
+ "*pixspacey: 2",
+ "*lensoffsetx: 5",
+ "*lensoffsety: 5",
+#ifdef HAVE_MOBILE
+ "*ignoreRotation: True",
+ "*rotateImages: True",
+#endif
+ 0
+};
+
+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", ".pixspacey", XrmoptionSepArg, 0 },
+ { "-lensoffsetx", ".lensoffsetx", XrmoptionSepArg, 0 },
+ { "-lensoffsety", ".lensoffsety", XrmoptionSepArg, 0 },
+ { 0, 0, 0, 0 }
+};
+
+XSCREENSAVER_MODULE ("Zoom", zoom)