2 * spotlight - an xscreensaver module
3 * Copyright (c) 1999, 2001 Rick Schultz <rick@skapunx.net>
5 * loosely based on the BackSpace module "StefView" by Darcy Brockbank
8 /* modified from a module from the xscreensaver distribution */
11 * xscreensaver, Copyright (c) 1992-2006 Jamie Zawinski <jwz@jwz.org>
13 * Permission to use, copy, modify, distribute, and sell this software and its
14 * documentation for any purpose is hereby granted without fee, provided that
15 * the above copyright notice appear in all copies and that both that
16 * copyright notice and this permission notice appear in supporting
17 * documentation. No representations are made about the suitability of this
18 * software for any purpose. It is provided "as is" without express or
25 #include "screenhack.h"
29 #define X_PERIOD 15000.0
30 #define Y_PERIOD 12000.0
36 int sizex, sizey; /* screen size */
37 int delay; /* in case it's too fast... */
42 GC buffer_gc; /* draw in buffer, then flush to screen
44 int radius; /* radius of spotlight in pixels */
46 Pixmap pm; /* pixmap grabbed from screen */
47 Pixmap buffer; /* pixmap for the buffer */
49 int x, y, s; /* x & y coords of buffer (upper left corner) */
50 /* s is the width of the buffer */
52 int off; /* random offset from currentTimeInMs(), so that
53 two concurrent copies of spotlight have different
56 int oldx, oldy, max_x_speed, max_y_speed;
57 /* used to keep the new buffer position
58 over the old spotlight image to make sure
59 the old image is completely erased */
62 async_load_state *img_loader;
66 /* The path the spotlight follows around the screen is sinusoidal.
67 This function is fed to sin() to get the x & y coords */
69 currentTimeInMs(struct state *st)
71 struct timeval curTime;
72 #ifdef GETTIMEOFDAY_TWO_ARGS
73 struct timezone tz = {0,0};
74 gettimeofday(&curTime, &tz);
76 gettimeofday(&curTime);
78 return curTime.tv_sec*1000 + curTime.tv_usec/1000.0;
83 spotlight_init (Display *dpy, Window window)
85 struct state *st = (struct state *) calloc (1, sizeof(*st));
87 XWindowAttributes xgwa;
98 XGetWindowAttributes (st->dpy, st->window, &xgwa);
99 st->sizex = xgwa.width;
100 st->sizey = xgwa.height;
101 cmap = xgwa.colormap;
102 fg = get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
103 bg = get_pixel_resource (st->dpy, cmap, "background", "Background");
105 /* read parameters, keep em sane */
106 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
107 if (st->delay < 1) st->delay = 1;
108 st->radius = get_integer_resource (st->dpy, "radius", "Integer");
109 if (st->radius < 0) st->radius = 125;
111 /* Don't let the spotlight be bigger than the window */
112 while (st->radius > xgwa.width * 0.45)
114 while (st->radius > xgwa.height * 0.45)
121 gcv.function = GXcopy;
122 gcv.subwindow_mode = IncludeInferiors;
123 gcflags = GCForeground | GCFunction;
127 if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */
128 gcflags |= GCSubwindowMode;
130 st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv);
132 /* grab screen to pixmap */
133 st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth);
134 XClearWindow(st->dpy, st->window);
136 /* create buffer to reduce flicker */
137 #ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
140 st->buffer = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth);
143 st->buffer_gc = XCreateGC(st->dpy, (st->buffer ? st->buffer : window), gcflags, &gcv);
145 XFillRectangle(st->dpy, st->buffer, st->buffer_gc, 0, 0, st->sizex, st->sizey);
147 /* blank out screen */
148 XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey);
149 XSetWindowBackground (st->dpy, st->window, bg);
151 /* create clip mask (so it's a circle, not a square) */
152 clip_pm = XCreatePixmap(st->dpy, st->window, st->radius*4, st->radius*4, 1);
153 st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, st->pm,
157 clip_gc = XCreateGC(st->dpy, clip_pm, gcflags, &gcv);
158 XFillRectangle(st->dpy, clip_pm, clip_gc, 0, 0, st->radius*4, st->radius*4);
160 XSetForeground(st->dpy, clip_gc, 1L);
161 XFillArc(st->dpy, clip_pm, clip_gc, st->radius , st->radius,
162 st->radius*2, st->radius*2, 0, 360*64);
164 /* set buffer's clip mask to the one we just made */
165 XSetClipMask(st->dpy, st->buffer_gc, clip_pm);
167 /* free everything */
168 XFreeGC(st->dpy, clip_gc);
169 XFreePixmap(st->dpy, clip_pm);
172 st->max_x_speed = st->max_y_speed = st->radius;
177 /* create GC with white fg */
179 st->white_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv);
186 * perform one iteration
189 onestep (struct state *st, Bool first_p)
193 if (st->img_loader) /* still loading */
195 st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
199 #define nrnd(x) (random() % (x))
204 st->s = st->radius *4 ; /* s = width of buffer */
206 now = currentTimeInMs(st) + st->off;
209 st->x = ((1 + sin(((double)now) / X_PERIOD * 2. * M_PI))/2.0)
210 * (st->sizex - st->s/2) -st->s/4 + MINX;
211 st->y = ((1 + sin(((double)now) / Y_PERIOD * 2. * M_PI))/2.0)
212 * (st->sizey - st->s/2) -st->s/4 + MINY;
216 /* limit change in x and y to buffer width */
217 if ( st->x < (st->oldx - st->max_x_speed) ) st->x = st->oldx - st->max_x_speed;
218 if ( st->x > (st->oldx + st->max_x_speed) ) st->x = st->oldx + st->max_x_speed;
219 if ( st->y < (st->oldy - st->max_y_speed) ) st->y = st->oldy - st->max_y_speed;
220 if ( st->y > (st->oldy + st->max_y_speed) ) st->y = st->oldy + st->max_y_speed;
225 XClearWindow (st->dpy, st->window);
226 XSetClipOrigin(st->dpy, st->buffer_gc, st->x,st->y);
227 XCopyArea(st->dpy, st->pm, st->window, st->buffer_gc, st->x, st->y, st->s, st->s, st->x, st->y);
232 XFillRectangle(st->dpy, st->buffer, st->buffer_gc, st->x, st->y, st->s, st->s);
234 /* copy area of screen image (pm) to buffer
236 XSetClipOrigin(st->dpy, st->buffer_gc, st->x,st->y);
237 XCopyArea(st->dpy, st->pm, st->buffer, st->buffer_gc, st->x, st->y, st->s, st->s, st->x, st->y);
239 /* copy buffer to screen (window) */
240 XCopyArea(st->dpy, st->buffer, st->window, st->window_gc, st->x , st->y, st->s, st->s, st->x, st->y);
244 /* draw a box around the buffer */
245 XDrawRectangle(st->dpy, st->window, st->white_gc, st->x , st->y, st->s, st->s);
252 spotlight_draw (Display *dpy, Window window, void *closure)
254 struct state *st = (struct state *) closure;
255 onestep(st, st->first_p);
261 spotlight_reshape (Display *dpy, Window window, void *closure,
262 unsigned int w, unsigned int h)
267 spotlight_event (Display *dpy, Window window, void *closure, XEvent *event)
273 spotlight_free (Display *dpy, Window window, void *closure)
275 struct state *st = (struct state *) closure;
276 XFreeGC (dpy, st->window_gc);
277 XFreeGC (dpy, st->buffer_gc);
278 if (st->pm) XFreePixmap (dpy, st->pm);
279 if (st->buffer) XFreePixmap (dpy, st->buffer);
286 static const char *spotlight_defaults [] = {
287 ".background: black",
288 ".foreground: white",
289 "*dontClearRoot: True",
291 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
300 static XrmOptionDescRec spotlight_options [] = {
301 { "-delay", ".delay", XrmoptionSepArg, 0 },
302 { "-radius", ".radius", XrmoptionSepArg, 0 },
306 XSCREENSAVER_MODULE ("Spotlight", spotlight)