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, 1993, 1994, 1996, 1997, 1998
12 * Jamie Zawinski <jwz@jwz.org>
14 * Permission to use, copy, modify, distribute, and sell this software and its
15 * documentation for any purpose is hereby granted without fee, provided that
16 * the above copyright notice appear in all copies and that both that
17 * copyright notice and this permission notice appear in supporting
18 * documentation. No representations are made about the suitability of this
19 * software for any purpose. It is provided "as is" without express or
25 #include "screenhack.h"
26 #include <X11/Xutil.h>
31 #define X_PERIOD 15000.0
32 #define Y_PERIOD 12000.0
34 static int sizex, sizey; /* screen size */
35 static int delay; /* in case it's too fast... */
40 static GC buffer_gc; /* draw in buffer, then flush to screen
42 static int radius; /* radius of spotlight in pixels */
44 static Pixmap pm; /* pixmap grabbed from screen */
45 static Pixmap clip_pm; /* pixmap for clipping (spotlight shape) */
46 static Pixmap buffer; /* pixmap for the buffer */
48 static GC clip_gc; /* GC for the clip pixmap */
50 static int x, y, s; /* x & y coords of buffer (upper left corner) */
51 /* s is the width of the buffer */
53 static int oldx, oldy, max_x_speed, max_y_speed;
54 /* used to keep the new buffer position
55 over the old spotlight image to make sure
56 the old image is completely erased */
58 /* The path the spotlight follows around the screen is sinusoidal.
59 This function is fed to sin() to get the x & y coords */
63 struct timeval curTime;
64 #ifdef GETTIMEOFDAY_TWO_ARGS
65 struct timezone tz = {0,0};
66 gettimeofday(&curTime, &tz);
68 gettimeofday(&curTime);
70 return curTime.tv_sec*1000 + curTime.tv_usec/1000.0;
75 init_hack (Display *dpy, Window window)
78 XWindowAttributes xgwa;
83 XGetWindowAttributes (dpy, window, &xgwa);
87 fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
88 bg = get_pixel_resource ("background", "Background", dpy, cmap);
90 /* read parameters, keep em sane */
91 delay = get_integer_resource ("delay", "Integer");
92 if (delay < 1) delay = 1;
93 radius = get_integer_resource ("radius", "Integer");
94 if (radius < 0) radius = 125;
96 /* Don't let the spotlight be bigger than 1/4 of the window */
97 if (radius > xgwa.width / 4) radius = xgwa.width / 4;
98 if (radius > xgwa.height / 4) radius = xgwa.height / 4;
101 gcv.function = GXcopy;
102 gcv.subwindow_mode = IncludeInferiors;
103 gcflags = GCForeground | GCFunction;
107 if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
108 gcflags |= GCSubwindowMode;
110 window_gc = XCreateGC(dpy, window, gcflags, &gcv);
113 /* grab screen to window */
114 grab_screen_image(xgwa.screen, window);
116 /* save screen to pixmap for copying later */
117 pm = XCreatePixmap(dpy, window, sizex, sizey, xgwa.depth);
118 XCopyArea(dpy, window, pm, window_gc, 0, 0, sizex, sizey, 0, 0);
121 /* create buffer to reduce flicker */
122 buffer = XCreatePixmap(dpy, window, sizex, sizey, xgwa.depth);
123 buffer_gc = XCreateGC(dpy, buffer, gcflags, &gcv);
124 XFillRectangle(dpy, buffer, buffer_gc, 0, 0, sizex, sizey);
126 /* blank out screen */
127 XFillRectangle(dpy, window, window_gc, 0, 0, sizex, sizey);
128 XSetWindowBackground (dpy, window, bg);
130 /* create clip mask (so it's a circle, not a square) */
131 clip_pm = XCreatePixmap(dpy, window, radius*4, radius*4, 1);
134 clip_gc = XCreateGC(dpy, clip_pm, gcflags, &gcv);
135 XFillRectangle(dpy, clip_pm, clip_gc, 0, 0, radius*4, radius*4);
137 XSetForeground(dpy, clip_gc, 1L);
138 XFillArc(dpy, clip_pm, clip_gc, radius , radius,
139 radius*2, radius*2, 0, 360*64);
141 /* set buffer's clip mask to the one we just made */
142 XSetClipMask(dpy, buffer_gc, clip_pm);
144 /* free everything */
145 XFreeGC(dpy, clip_gc);
146 XFreePixmap(dpy, clip_pm);
149 max_x_speed = max_y_speed = radius;
152 /* create GC with white fg */
154 white_gc = XCreateGC(dpy, window, gcflags, &gcv);
157 /* initialize x and y to avoid initial `jump' across screen */
158 x = ((1 + sin(((float)currentTimeInMs()) / X_PERIOD * 2. * M_PI))/2.0)
159 * (sizex - s/2) -s/4 + MINX;
160 y = ((1 + sin(((float)currentTimeInMs()) / Y_PERIOD * 2. * M_PI))/2.0)
161 * (sizey - s/2) -s/4 + MINY;
167 * perform one iteration
170 onestep (Display *dpy, Window window)
175 XFillRectangle(dpy, buffer, buffer_gc, x, y, s, s);
178 #define nrnd(x) (random() % (x))
183 s = radius *4 ; /* s = width of buffer */
185 now = currentTimeInMs();
188 x = ((1 + sin(((float)now) / X_PERIOD * 2. * M_PI))/2.0)
189 * (sizex - s/2) -s/4 + MINX;
190 y = ((1 + sin(((float)now) / Y_PERIOD * 2. * M_PI))/2.0)
191 * (sizey - s/2) -s/4 + MINY;
193 /* limit change in x and y to buffer width */
194 if ( x < (oldx - max_x_speed) ) x = oldx - max_x_speed;
195 if ( x > (oldx + max_x_speed) ) x = oldx + max_x_speed;
196 if ( y < (oldy - max_y_speed) ) y = oldy - max_y_speed;
197 if ( y > (oldy + max_y_speed) ) y = oldy + max_y_speed;
199 /* copy area of screen image (pm) to buffer
201 XSetClipOrigin(dpy, buffer_gc, x,y);
202 XCopyArea(dpy, pm, buffer, buffer_gc, x, y, s, s, x, y);
203 /* copy buffer to screen (window) */
204 XCopyArea(dpy, buffer, window, window_gc, x , y, s, s, x, y);
207 /* draw a box around the buffer */
208 XDrawLine(dpy, window, white_gc, x, y, x+s, y);
209 XDrawLine(dpy, window, white_gc, x, y, x, y+s);
210 XDrawLine(dpy, window, white_gc, x+s, y, x+s, y+s);
211 XDrawLine(dpy, window, white_gc, x, y+s, x+s, y+s);
217 char *progclass = "Spotlight";
219 char *defaults [] = {
220 ".background: black",
221 ".foreground: white",
222 "*dontClearRoot: True",
224 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
233 XrmOptionDescRec options [] = {
234 { "-delay", ".delay", XrmoptionSepArg, 0 },
235 { "-radius", ".radius", XrmoptionSepArg, 0 },
240 screenhack (Display *dpy, Window window)
242 init_hack (dpy, window);
244 onestep(dpy, window);
246 if (delay) usleep (delay);
247 screenhack_handle_events (dpy);