1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* slip --- lots of slipping blits */
3
4 #if 0
5 static const char sccsid[] = "@(#)slip.c 5.00 2000/11/01 xlockmore";
6 #endif
7
8 /*-
9 * Copyright (c) 1992 by Scott Draves <spot@cs.cmu.edu>
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 * 01-Nov-2000: Allocation checks
24 * 10-May-1997: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
25 * 01-Dec-1995: Patched for VMS <joukj@hrem.stm.tudelft.nl>
26 */
27
28 #ifdef STANDALONE
29 # define MODE_slip
30 # define DEFAULTS "*delay: 50000 \n" \
31 "*count: 35 \n" \
32 "*cycles: 50 \n" \
33 "*ncolors: 200 \n" \
34 "*fpsSolid: true \n" \
35 "*ignoreRotation: True \n" \
36
37 # define free_slip 0
38 # define release_slip 0
39 # include "xlockmore.h" /* in xscreensaver distribution */
40 #else /* STANDALONE */
41 # include "xlock.h" /* in xlockmore distribution */
42 #endif /* STANDALONE */
43
44 #ifdef MODE_slip
45
46 ENTRYPOINT ModeSpecOpt slip_opts =
47 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
48
49 #ifdef USE_MODULES
50 ModStruct slip_description =
51 {"slip", "init_slip", "draw_slip", (char *) NULL,
52 "init_slip", "init_slip", (char *) NULL, &slip_opts,
53 50000, 35, 50, 1, 64, 1.0, "",
54 "Shows slipping blits", 0, NULL};
55
56 #endif
57
58 typedef struct {
59 int width, height;
60 int nblits_remaining;
61 int blit_width, blit_height;
62 int mode;
63 int first_time;
64 int backwards;
65 short lasthalf;
66 int stage;
67 unsigned long r;
68 Bool image_loading_p;
69 } slipstruct;
70 static slipstruct *slips = (slipstruct *) NULL;
71
72 static short
halfrandom(slipstruct * sp,int mv)73 halfrandom(slipstruct *sp, int mv)
74 {
75 unsigned long r;
76
77 if (sp->lasthalf) {
78 r = sp->lasthalf;
79 sp->lasthalf = 0;
80 } else {
81 r = LRAND();
82 sp->lasthalf = (short) (r >> 16);
83 }
84 return r % mv;
85 }
86
87 static int
erandom(slipstruct * sp,int mv)88 erandom(slipstruct *sp, int mv)
89 {
90 int res;
91
92 if (0 == sp->stage) {
93 sp->r = LRAND();
94 sp->stage = 7;
95 }
96 res = (int) (sp->r & 0xf);
97 sp->r = sp->r >> 4;
98 sp->stage--;
99 if (res & 8)
100 return res & mv;
101 else
102 return -(res & mv);
103 }
104
105 #ifdef STANDALONE
106 static void
image_loaded_cb(Screen * screen,Window w,Drawable d,const char * name,XRectangle * geom,void * closure)107 image_loaded_cb (Screen *screen, Window w, Drawable d,
108 const char *name, XRectangle *geom,
109 void *closure)
110 {
111 ModeInfo *mi = (ModeInfo *) closure;
112 slipstruct *sp = &slips[MI_SCREEN(mi)];
113 Display *dpy = DisplayOfScreen (screen);
114 XCopyArea (dpy, d, w, mi->gc, 0, 0,
115 sp->width, sp->height, 0, 0);
116 XFreePixmap (dpy, d);
117 sp->image_loading_p = False;
118 }
119 #endif /* STANDALONE */
120
121 static Bool
prepare_screen(ModeInfo * mi,slipstruct * sp)122 prepare_screen(ModeInfo * mi, slipstruct * sp)
123 {
124
125 Display *display = MI_DISPLAY(mi);
126 GC gc = MI_GC(mi);
127 int i, n, w = sp->width / 20;
128 int not_solid = halfrandom(sp, 10);
129
130 sp->backwards = (int) (LRAND() & 1); /* jwz: go the other way sometimes */
131
132 if (sp->first_time) {
133 XClearWindow (display, MI_WINDOW(mi));
134 n = 300;
135 } else if (!sp->image_loading_p && !halfrandom(sp, 10)) {
136 sp->first_time = 1;
137 sp->nblits_remaining = 0;
138 MI_CLEARWINDOW(mi);
139 return False;
140 } else {
141 if (halfrandom(sp, 5))
142 return True;
143 if (halfrandom(sp, 5))
144 n = 100;
145 else
146 n = 2000;
147 }
148
149 if (MI_NPIXELS(mi) > 2)
150 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
151 else if (halfrandom(sp, 2))
152 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
153 else
154 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
155
156 for (i = 0; i < n; i++) {
157 int ww = ((w / 2) + halfrandom(sp, MAX(w, 1)));
158
159 if (not_solid) {
160 if (MI_NPIXELS(mi) > 2)
161 XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
162 else if (halfrandom(sp, 2))
163 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
164 else
165 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
166 }
167 XFillRectangle(display, MI_WINDOW(mi), gc,
168 halfrandom(sp, MAX(sp->width - ww, 1)),
169 halfrandom(sp, MAX(sp->height - ww, 1)),
170 ww, ww);
171 }
172 sp->first_time = 0;
173
174
175 #ifdef STANDALONE /* jwz -- sometimes hack the desktop image! */
176 if (!sp->image_loading_p &&
177 (1||halfrandom(sp, 2) == 0)) {
178 /* Load it into a pixmap so that the "Loading" message and checkerboard
179 don't show up on the window -- we keep running while the image is
180 in progress... */
181 Pixmap p = XCreatePixmap (MI_DISPLAY(mi), MI_WINDOW(mi),
182 sp->width, sp->height, mi->xgwa.depth);
183 sp->image_loading_p = True;
184 load_image_async (ScreenOfDisplay (MI_DISPLAY(mi), 0/*####MI_SCREEN(mi)*/),
185 MI_WINDOW(mi), p, image_loaded_cb, mi);
186 }
187 #endif
188
189 return True;
190 }
191
192 static int
quantize(double d)193 quantize(double d)
194 {
195 int i = (int) floor(d);
196 double f = d - i;
197
198 if ((LRAND() & 0xff) < f * 0xff)
199 i++;
200 return i;
201 }
202
203 ENTRYPOINT void
reshape_slip(ModeInfo * mi,int w,int h)204 reshape_slip (ModeInfo * mi, int w, int h)
205 {
206 slipstruct *sp = &slips[MI_SCREEN(mi)];
207 sp->width = w;
208 sp->height = h;
209 sp->blit_width = sp->width / 25;
210 sp->blit_height = sp->height / 25;
211
212 sp->mode = 0;
213 sp->nblits_remaining = 0;
214 }
215
216 ENTRYPOINT void
init_slip(ModeInfo * mi)217 init_slip (ModeInfo * mi)
218 {
219 slipstruct *sp;
220
221 MI_INIT (mi, slips);
222 sp = &slips[MI_SCREEN(mi)];
223
224 sp->nblits_remaining = 0;
225 sp->mode = 0;
226 sp->first_time = 1;
227
228 /* no "NoExpose" events from XCopyArea wanted */
229 XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
230
231 reshape_slip (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
232 }
233
234 ENTRYPOINT void
draw_slip(ModeInfo * mi)235 draw_slip (ModeInfo * mi)
236 {
237 Display *display = MI_DISPLAY(mi);
238 Window window = MI_WINDOW(mi);
239 GC gc = MI_GC(mi);
240 int timer;
241 slipstruct *sp;
242
243 if (slips == NULL)
244 return;
245 sp = &slips[MI_SCREEN(mi)];
246
247 timer = MI_COUNT(mi) * MI_CYCLES(mi);
248
249 while (timer--) {
250 int xi = halfrandom(sp, MAX(sp->width - sp->blit_width, 1));
251 int yi = halfrandom(sp, MAX(sp->height - sp->blit_height, 1));
252 double x, y, dx = 0, dy = 0, t, s1, s2;
253
254 if (0 == sp->nblits_remaining--) {
255 static const int lut[] = {0, 0, 0, 1, 1, 1, 2};
256
257 if (!prepare_screen(mi, sp))
258 break;
259 MI_IS_DRAWN(mi) = True;
260 sp->nblits_remaining = MI_COUNT(mi) *
261 (2000 + halfrandom(sp, 1000) + halfrandom(sp, 1000));
262 if (sp->mode == 2)
263 sp->mode = halfrandom(sp, 2);
264 else
265 sp->mode = lut[halfrandom(sp, 7)];
266 }
267 x = (2 * xi + sp->blit_width) / (double) sp->width - 1;
268 y = (2 * yi + sp->blit_height) / (double) sp->height - 1;
269
270 /* (x,y) is in biunit square */
271 switch (sp->mode) {
272 case 0: /* rotor */
273 dx = x;
274 dy = y;
275
276 if (dy < 0) {
277 dy += 0.04;
278 if (dy > 0)
279 dy = 0.00;
280 }
281 if (dy > 0) {
282 dy -= 0.04;
283 if (dy < 0)
284 dy = 0.00;
285 }
286 t = dx * dx + dy * dy + 1e-10;
287 s1 = 2 * dx * dx / t - 1;
288 s2 = 2 * dx * dy / t;
289 dx = s1 * 5;
290 dy = s2 * 5;
291
292 if (sp->backwards) { /* jwz: go the other way sometimes */
293 dx = -dx;
294 dy = -dy;
295 }
296 break;
297 case 1: /* shuffle */
298 dx = erandom(sp, 3);
299 dy = erandom(sp, 3);
300 break;
301 case 2: /* explode */
302 dx = x * 3;
303 dy = y * 3;
304 break;
305 }
306 {
307 int qx = xi + quantize(dx), qy = yi + quantize(dy);
308 int wrap;
309
310 if (qx < 0 || qy < 0 ||
311 qx >= sp->width - sp->blit_width ||
312 qy >= sp->height - sp->blit_height)
313 continue;
314
315 /*-
316 Seems to cause problems using Exceed
317 with PseudoColor
318 X Error of failed request: BadGC (invalid GC parameter)
319 with TrueColor
320 X Error of failed request: BadDrawable (invalid Pixmap or Window parameter)
321 Major opcode of failed request: 62 (X_CopyArea)
322 */
323 XCopyArea(display, window, window, gc, xi, yi,
324 sp->blit_width, sp->blit_height,
325 qx, qy);
326 switch (sp->mode) {
327 case 0:
328 /* wrap */
329 wrap = sp->width - (2 * sp->blit_width);
330 if (qx > wrap ) {
331 XCopyArea(display, window, window, gc, qx, qy,
332 sp->blit_width, sp->blit_height,
333 qx - wrap, qy);
334 }
335 if (qx < 2 * sp->blit_width) {
336 XCopyArea(display, window, window, gc, qx, qy,
337 sp->blit_width, sp->blit_height,
338 qx + wrap, qy);
339 }
340 wrap = sp->height - (2 * sp->blit_height);
341 if (qy > wrap) {
342 XCopyArea(display, window, window, gc, qx, qy,
343 sp->blit_width, sp->blit_height,
344 qx, qy - wrap);
345 }
346 if (qy < 2 * sp->blit_height) {
347 XCopyArea(display, window, window, gc, qx, qy,
348 sp->blit_width, sp->blit_height,
349 qx, qy + wrap);
350 }
351 break;
352 case 1:
353 case 2:
354 break;
355 }
356 }
357 }
358 }
359
360 ENTRYPOINT Bool
slip_handle_event(ModeInfo * mi,XEvent * event)361 slip_handle_event (ModeInfo *mi, XEvent *event)
362 {
363 slipstruct *sp = &slips[MI_SCREEN(mi)];
364 if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
365 {
366 sp->first_time = 1;
367 sp->nblits_remaining = 0;
368 return True;
369 }
370 return False;
371 }
372
373 XSCREENSAVER_MODULE ("Slip", slip)
374
375 #endif /* MODE_slip */
376