2 * Copyright (C) 2000 James Macnicol
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
15 #include "screenhack.h"
18 #define MIN(a, b) (((a) < (b))?(a):(b))
22 #define MAX(a, b) (((a) > (b))?(a):(b))
27 /* This should be *way* slower than the spotlight hack was */
28 #define X_PERIOD (45000.0 * 3)
29 #define Y_PERIOD (36000.0 * 3)
40 int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety;
53 async_load_state *img_loader;
57 static long currentTimeInMs(struct state *st)
59 struct timeval curTime;
60 unsigned long ret_unsigned;
61 #ifdef GETTIMEOFDAY_TWO_ARGS
62 struct timezone tz = {0,0};
63 gettimeofday(&curTime, &tz);
65 gettimeofday(&curTime);
67 ret_unsigned = curTime.tv_sec *1000U + curTime.tv_usec / 1000;
68 return (ret_unsigned <= LONG_MAX) ? ret_unsigned : -1 - (long)(ULONG_MAX - ret_unsigned);
72 zoom_init (Display *dpy, Window window)
74 struct state *st = (struct state *) calloc (1, sizeof(*st));
76 XWindowAttributes xgwa;
80 int nblocksx, nblocksy;
84 XGetWindowAttributes(st->dpy, st->window, &xgwa);
85 st->screen = xgwa.screen;
86 st->sizex = xgwa.width;
87 st->sizey = xgwa.height;
89 bg = get_pixel_resource(st->dpy, cmap, "background", "Background");
91 st->delay = get_integer_resource(st->dpy, "delay", "Integer");
94 st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
97 st->pixwidth = get_integer_resource(st->dpy, "pixwidth", "Integer");
100 st->pixheight = get_integer_resource(st->dpy, "pixheight", "Integer");
101 if (st->pixheight < 1)
103 st->pixspacex = get_integer_resource(st->dpy, "pixspacex", "Integer");
104 if (st->pixspacex < 0)
106 st->pixspacey = get_integer_resource(st->dpy, "pixspacey", "Integer");
107 if (st->pixspacey < 0)
109 st->lenses = get_boolean_resource(st->dpy, "lenses", "Boolean");
110 st->lensoffsetx = get_integer_resource(st->dpy, "lensoffsetx", "Integer");
111 st->lensoffsetx = MAX(0, MIN(st->pixwidth, st->lensoffsetx));
112 st->lensoffsety = get_integer_resource(st->dpy, "lensoffsety", "Integer");
113 st->lensoffsety = MAX(0, MIN(st->pixwidth, st->lensoffsety));
115 gcv.function = GXcopy;
116 gcv.subwindow_mode = IncludeInferiors;
117 gcflags = GCForeground|GCFunction;
119 if (!st->lenses && use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */
120 gcflags |= GCSubwindowMode;
121 st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv);
125 st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth);
127 XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey);
128 XSetWindowBackground(st->dpy, st->window, bg);
130 st->start_time = time ((time_t *) 0);
131 st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
134 /* We might have needed this to grab the image, but if we leave this set
135 to GCSubwindowMode, then we'll *draw* right over subwindows too. */
136 XSetSubwindowMode (st->dpy, st->window_gc, ClipByChildren);
139 nblocksx = (int)ceil((double)st->sizex / (double)(st->pixwidth + st->pixspacex));
140 nblocksy = (int)ceil((double)st->sizey / (double)(st->pixheight + st->pixspacey));
142 st->s = MAX((nblocksx - 1) * st->lensoffsetx + st->pixwidth,
143 (nblocksy - 1) * st->lensoffsety + st->pixheight) * 2;
145 st->s = MAX(nblocksx, nblocksy) * 2;
147 st->sinusoid_offset = random();
153 zoom_draw (Display *dpy, Window window, void *closure)
155 struct state *st = (struct state *) closure;
159 unsigned long now_unsigned;
161 if (st->img_loader) /* still loading */
163 st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
164 if (! st->img_loader) { /* just finished */
165 XClearWindow (st->dpy, st->window);
166 st->start_time = time ((time_t *) 0);
168 st->orig_map = XGetImage(st->dpy, st->pm, 0, 0, st->sizex, st->sizey, ~0L, ZPixmap);
169 /* XFreePixmap(st->dpy, st->pm);
176 if (!st->img_loader &&
177 st->start_time + st->duration < time ((time_t *) 0)) {
178 st->img_loader = load_image_async_simple (0, st->screen, st->window,
183 #define nrnd(x) (random() % (x))
185 now = currentTimeInMs(st);
186 now_unsigned = (unsigned long) now + st->sinusoid_offset; /* don't run multiple screens in lock-step */
187 now = (now_unsigned <= LONG_MAX) ? now_unsigned : -1 - (long)(ULONG_MAX - now_unsigned);
190 st->tlx = ((1. + sin(((double)now) / X_PERIOD * 2. * M_PI))/2.0)
191 * (st->sizex - st->s/2) /* -s/4 */ + MINX;
192 st->tly = ((1. + sin(((double)now) / Y_PERIOD * 2. * M_PI))/2.0)
193 * (st->sizey - st->s/2) /* -s/4 */ + MINY;
196 for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i)
197 for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) {
198 XCopyArea(st->dpy, st->pm /* src */, st->window /* dest */, st->window_gc,
199 st->tlx + i * st->lensoffsetx /* src_x */,
200 st->tly + j * st->lensoffsety /* src_y */,
201 st->pixwidth, st->pixheight,
202 x /* dest_x */, y /* dest_y */);
205 for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i)
206 for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) {
207 XSetForeground(st->dpy, st->window_gc, XGetPixel(st->orig_map, st->tlx+i, st->tly+j));
208 XFillRectangle(st->dpy, st->window, st->window_gc,
209 i * (st->pixwidth + st->pixspacex),
210 j * (st->pixheight + st->pixspacey), st->pixwidth, st->pixheight);
218 zoom_reshape (Display *dpy, Window window, void *closure,
219 unsigned int w, unsigned int h)
224 zoom_event (Display *dpy, Window window, void *closure, XEvent *event)
226 struct state *st = (struct state *) closure;
227 if (screenhack_event_helper (dpy, window, event))
236 zoom_free (Display *dpy, Window window, void *closure)
238 struct state *st = (struct state *) closure;
239 XFreeGC (st->dpy, st->window_gc);
240 if (st->orig_map) XDestroyImage (st->orig_map);
241 if (st->pm) XFreePixmap (st->dpy, st->pm);
246 static const char *zoom_defaults[] = {
247 "*dontClearRoot: True",
248 ".foreground: white",
249 ".background: #111111",
251 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
264 "*ignoreRotation: True",
265 "*rotateImages: True",
270 static XrmOptionDescRec zoom_options[] = {
271 { "-lenses", ".lenses", XrmoptionNoArg, "true" },
272 { "-no-lenses", ".lenses", XrmoptionNoArg, "false" },
273 { "-delay", ".delay", XrmoptionSepArg, 0 },
274 { "-duration", ".duration", XrmoptionSepArg, 0 },
275 { "-pixwidth", ".pixwidth", XrmoptionSepArg, 0 },
276 { "-pixheight", ".pixheight", XrmoptionSepArg, 0 },
277 { "-pixspacex", ".pixspacex", XrmoptionSepArg, 0 },
278 { "-pixspacey", ".pixspacey", XrmoptionSepArg, 0 },
279 { "-lensoffsetx", ".lensoffsetx", XrmoptionSepArg, 0 },
280 { "-lensoffsety", ".lensoffsety", XrmoptionSepArg, 0 },
284 XSCREENSAVER_MODULE ("Zoom", zoom)