1 | /* |
---|
2 | * spotlight - an xscreensaver module |
---|
3 | * Copyright (c) 1999, 2001 Rick Schultz <rick@skapunx.net> |
---|
4 | * |
---|
5 | * loosely based on the BackSpace module "StefView" by Darcy Brockbank |
---|
6 | */ |
---|
7 | |
---|
8 | /* modified from a module from the xscreensaver distribution */ |
---|
9 | |
---|
10 | /* |
---|
11 | * xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998 |
---|
12 | * Jamie Zawinski <jwz@jwz.org> |
---|
13 | * |
---|
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 |
---|
20 | * implied warranty. |
---|
21 | */ |
---|
22 | |
---|
23 | /* #define DEBUG */ |
---|
24 | #include <math.h> |
---|
25 | #include "screenhack.h" |
---|
26 | #include <X11/Xutil.h> |
---|
27 | #include <sys/time.h> |
---|
28 | |
---|
29 | #define MINX 0.0 |
---|
30 | #define MINY 0.0 |
---|
31 | #define X_PERIOD 15000.0 |
---|
32 | #define Y_PERIOD 12000.0 |
---|
33 | |
---|
34 | static int sizex, sizey; /* screen size */ |
---|
35 | static int delay; /* in case it's too fast... */ |
---|
36 | static GC window_gc; |
---|
37 | #ifdef DEBUG |
---|
38 | static GC white_gc; |
---|
39 | #endif |
---|
40 | static GC buffer_gc; /* draw in buffer, then flush to screen |
---|
41 | to avoid flicker */ |
---|
42 | static int radius; /* radius of spotlight in pixels */ |
---|
43 | |
---|
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 */ |
---|
47 | |
---|
48 | static GC clip_gc; /* GC for the clip pixmap */ |
---|
49 | |
---|
50 | static int x, y, s; /* x & y coords of buffer (upper left corner) */ |
---|
51 | /* s is the width of the buffer */ |
---|
52 | |
---|
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 */ |
---|
57 | |
---|
58 | /* The path the spotlight follows around the screen is sinusoidal. |
---|
59 | This function is fed to sin() to get the x & y coords */ |
---|
60 | static long |
---|
61 | currentTimeInMs(void) |
---|
62 | { |
---|
63 | struct timeval curTime; |
---|
64 | #ifdef GETTIMEOFDAY_TWO_ARGS |
---|
65 | struct timezone tz = {0,0}; |
---|
66 | gettimeofday(&curTime, &tz); |
---|
67 | #else |
---|
68 | gettimeofday(&curTime); |
---|
69 | #endif |
---|
70 | return curTime.tv_sec*1000 + curTime.tv_usec/1000.0; |
---|
71 | } |
---|
72 | |
---|
73 | |
---|
74 | static void |
---|
75 | init_hack (Display *dpy, Window window) |
---|
76 | { |
---|
77 | XGCValues gcv; |
---|
78 | XWindowAttributes xgwa; |
---|
79 | long gcflags; |
---|
80 | Colormap cmap; |
---|
81 | unsigned long fg, bg; |
---|
82 | |
---|
83 | XGetWindowAttributes (dpy, window, &xgwa); |
---|
84 | sizex = xgwa.width; |
---|
85 | sizey = xgwa.height; |
---|
86 | cmap = xgwa.colormap; |
---|
87 | fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap); |
---|
88 | bg = get_pixel_resource ("background", "Background", dpy, cmap); |
---|
89 | |
---|
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; |
---|
95 | |
---|
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; |
---|
99 | |
---|
100 | /* do the dance */ |
---|
101 | gcv.function = GXcopy; |
---|
102 | gcv.subwindow_mode = IncludeInferiors; |
---|
103 | gcflags = GCForeground | GCFunction; |
---|
104 | gcv.foreground = bg; |
---|
105 | |
---|
106 | #ifdef NOPE |
---|
107 | if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */ |
---|
108 | gcflags |= GCSubwindowMode; |
---|
109 | #endif |
---|
110 | window_gc = XCreateGC(dpy, window, gcflags, &gcv); |
---|
111 | |
---|
112 | /* grab screen to pixmap */ |
---|
113 | pm = XCreatePixmap(dpy, window, sizex, sizey, xgwa.depth); |
---|
114 | load_random_image (xgwa.screen, window, pm, NULL); |
---|
115 | XClearWindow(dpy, window); |
---|
116 | XFlush (dpy); |
---|
117 | |
---|
118 | /* create buffer to reduce flicker */ |
---|
119 | buffer = XCreatePixmap(dpy, window, sizex, sizey, xgwa.depth); |
---|
120 | buffer_gc = XCreateGC(dpy, buffer, gcflags, &gcv); |
---|
121 | XFillRectangle(dpy, buffer, buffer_gc, 0, 0, sizex, sizey); |
---|
122 | |
---|
123 | /* blank out screen */ |
---|
124 | XFillRectangle(dpy, window, window_gc, 0, 0, sizex, sizey); |
---|
125 | XSetWindowBackground (dpy, window, bg); |
---|
126 | |
---|
127 | /* create clip mask (so it's a circle, not a square) */ |
---|
128 | clip_pm = XCreatePixmap(dpy, window, radius*4, radius*4, 1); |
---|
129 | |
---|
130 | gcv.foreground = 0L; |
---|
131 | clip_gc = XCreateGC(dpy, clip_pm, gcflags, &gcv); |
---|
132 | XFillRectangle(dpy, clip_pm, clip_gc, 0, 0, radius*4, radius*4); |
---|
133 | |
---|
134 | XSetForeground(dpy, clip_gc, 1L); |
---|
135 | XFillArc(dpy, clip_pm, clip_gc, radius , radius, |
---|
136 | radius*2, radius*2, 0, 360*64); |
---|
137 | |
---|
138 | /* set buffer's clip mask to the one we just made */ |
---|
139 | XSetClipMask(dpy, buffer_gc, clip_pm); |
---|
140 | |
---|
141 | /* free everything */ |
---|
142 | XFreeGC(dpy, clip_gc); |
---|
143 | XFreePixmap(dpy, clip_pm); |
---|
144 | |
---|
145 | /* avoid remants */ |
---|
146 | max_x_speed = max_y_speed = radius; |
---|
147 | |
---|
148 | #ifdef DEBUG |
---|
149 | /* create GC with white fg */ |
---|
150 | gcv.foreground = fg; |
---|
151 | white_gc = XCreateGC(dpy, window, gcflags, &gcv); |
---|
152 | #endif |
---|
153 | |
---|
154 | /* initialize x and y to avoid initial `jump' across screen */ |
---|
155 | x = ((1 + sin(((float)currentTimeInMs()) / X_PERIOD * 2. * M_PI))/2.0) |
---|
156 | * (sizex - s/2) -s/4 + MINX; |
---|
157 | y = ((1 + sin(((float)currentTimeInMs()) / Y_PERIOD * 2. * M_PI))/2.0) |
---|
158 | * (sizey - s/2) -s/4 + MINY; |
---|
159 | |
---|
160 | } |
---|
161 | |
---|
162 | |
---|
163 | /* |
---|
164 | * perform one iteration |
---|
165 | */ |
---|
166 | static void |
---|
167 | onestep (Display *dpy, Window window) |
---|
168 | { |
---|
169 | long now; |
---|
170 | |
---|
171 | /* clear buffer */ |
---|
172 | XFillRectangle(dpy, buffer, buffer_gc, x, y, s, s); |
---|
173 | |
---|
174 | |
---|
175 | #define nrnd(x) (random() % (x)) |
---|
176 | |
---|
177 | oldx = x; |
---|
178 | oldy = y; |
---|
179 | |
---|
180 | s = radius *4 ; /* s = width of buffer */ |
---|
181 | |
---|
182 | now = currentTimeInMs(); |
---|
183 | |
---|
184 | /* find new x,y */ |
---|
185 | x = ((1 + sin(((float)now) / X_PERIOD * 2. * M_PI))/2.0) |
---|
186 | * (sizex - s/2) -s/4 + MINX; |
---|
187 | y = ((1 + sin(((float)now) / Y_PERIOD * 2. * M_PI))/2.0) |
---|
188 | * (sizey - s/2) -s/4 + MINY; |
---|
189 | |
---|
190 | /* limit change in x and y to buffer width */ |
---|
191 | if ( x < (oldx - max_x_speed) ) x = oldx - max_x_speed; |
---|
192 | if ( x > (oldx + max_x_speed) ) x = oldx + max_x_speed; |
---|
193 | if ( y < (oldy - max_y_speed) ) y = oldy - max_y_speed; |
---|
194 | if ( y > (oldy + max_y_speed) ) y = oldy + max_y_speed; |
---|
195 | |
---|
196 | /* copy area of screen image (pm) to buffer |
---|
197 | Clip to a circle */ |
---|
198 | XSetClipOrigin(dpy, buffer_gc, x,y); |
---|
199 | XCopyArea(dpy, pm, buffer, buffer_gc, x, y, s, s, x, y); |
---|
200 | /* copy buffer to screen (window) */ |
---|
201 | XCopyArea(dpy, buffer, window, window_gc, x , y, s, s, x, y); |
---|
202 | |
---|
203 | #ifdef DEBUG |
---|
204 | /* draw a box around the buffer */ |
---|
205 | XDrawLine(dpy, window, white_gc, x, y, x+s, y); |
---|
206 | XDrawLine(dpy, window, white_gc, x, y, x, y+s); |
---|
207 | XDrawLine(dpy, window, white_gc, x+s, y, x+s, y+s); |
---|
208 | XDrawLine(dpy, window, white_gc, x, y+s, x+s, y+s); |
---|
209 | #endif |
---|
210 | |
---|
211 | } |
---|
212 | |
---|
213 | |
---|
214 | char *progclass = "Spotlight"; |
---|
215 | |
---|
216 | char *defaults [] = { |
---|
217 | ".background: black", |
---|
218 | ".foreground: white", |
---|
219 | "*dontClearRoot: True", |
---|
220 | |
---|
221 | #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */ |
---|
222 | "*visualID: Best", |
---|
223 | #endif |
---|
224 | |
---|
225 | "*delay: 10000", |
---|
226 | "*radius: 125", |
---|
227 | 0 |
---|
228 | }; |
---|
229 | |
---|
230 | XrmOptionDescRec options [] = { |
---|
231 | { "-delay", ".delay", XrmoptionSepArg, 0 }, |
---|
232 | { "-radius", ".radius", XrmoptionSepArg, 0 }, |
---|
233 | { 0, 0, 0, 0 } |
---|
234 | }; |
---|
235 | |
---|
236 | void |
---|
237 | screenhack (Display *dpy, Window window) |
---|
238 | { |
---|
239 | init_hack (dpy, window); |
---|
240 | while (1) { |
---|
241 | onestep(dpy, window); |
---|
242 | XSync(dpy, False); |
---|
243 | if (delay) usleep (delay); |
---|
244 | screenhack_handle_events (dpy); |
---|
245 | } |
---|
246 | } |
---|
247 | |
---|