http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / rotzoomer.c
1 /* rotzoomer - creates a collage of rotated and scaled portions of the screen
2  * Copyright (C) 2001 Claudio Matsuoka <claudio@helllabs.org>
3  *
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
10  * implied warranty.
11  */
12
13 /*
14  * Options:
15  *
16  * -shm         enable MIT shared memory extension
17  * -no-shm      disable MIT shared memory extension
18  * -n <num>     number of zoomboxes
19  * -move        enable mobile zoomboxes
20  * -sweep       enable sweep mode
21  * -anim        enable snapshot mode
22  * -no-anim     enable snapshot mode
23  * -delay       delay in milliseconds
24  */
25
26 #include <math.h>
27 #include "screenhack.h"
28 #include <X11/Xutil.h>
29
30 #ifdef HAVE_XSHM_EXTENSION
31 #include "xshm.h"
32 static Bool use_shm;
33 static XShmSegmentInfo shm_info;
34 #endif
35
36 struct zoom_area {
37         int w, h;               /* rectangle width and height */
38         int inc1, inc2;         /* rotation and zoom angle increments */
39         int dx, dy;             /* translation increments */
40         int a1, a2;             /* rotation and zoom angular variables */
41         int ox, oy;             /* origin in the background copy */
42         int xx, yy;             /* left-upper corner position (* 256) */
43         int x, y;               /* left-upper corner position */
44         int ww, hh;             /* valid area to place left-upper corner */
45         int n;                  /* number of iteractions */
46         int count;              /* current iteraction */
47 };
48
49 static Window window;
50 static Display *display;
51 static GC gc;
52 static Visual *visual;
53 static XImage *orig_map, *buffer_map;
54 static Colormap colormap;
55
56 static int width, height;
57 static struct zoom_area **zoom_box;
58 static int num_zoom = 2;
59 static int move = 0;
60 static int sweep = 0;
61 static int delay = 10;
62 static int anim = 1;
63
64
65 static void rotzoom (struct zoom_area *za)
66 {
67         int x, y, c, s, zoom, z;
68         int x2 = za->x + za->w - 1, y2 = za->y + za->h - 1;
69         int ox = 0, oy = 0;
70
71         z = 8100 * sin (M_PI * za->a2 / 8192);
72         zoom = 8192 + z;
73
74         c = zoom * cos (M_PI * za->a1 / 8192);
75         s = zoom * sin (M_PI * za->a1 / 8192);
76         for (y = za->y; y <= y2; y++) {
77                 for (x = za->x; x <= x2; x++) {
78                         ox = (x * c + y * s) >> 13;
79                         oy = (-x * s + y * c) >> 13;
80
81                         while (ox < 0)
82                                 ox += width;
83                         while (oy < 0)
84                                 oy += height;
85                         while (ox >= width)
86                                 ox -= width;
87                         while (oy >= height)
88                                 oy -= height;
89
90                         XPutPixel (buffer_map, x, y, XGetPixel (orig_map, ox, oy));
91                 }
92         }
93
94         za->a1 += za->inc1;             /* Rotation angle */
95         za->a1 &= 0x3fff;;
96
97         za->a2 += za->inc2;             /* Zoom */
98         za->a2 &= 0x3fff;
99
100         za->ox = ox;                    /* Save state for next iteration */
101         za->oy = oy;
102
103         za->count++;
104 }
105
106
107 static void reset_zoom (struct zoom_area *za)
108 {
109         if (sweep) {
110                 int speed = random () % 100 + 100;
111                 switch (random () % 4) {
112                 case 0:
113                         za->w = width;
114                         za->h = 10;
115                         za->x = 0;
116                         za->y = 0;
117                         za->dx = 0;
118                         za->dy = speed;
119                         za->n = (height - 10) * 256 / speed;
120                         break;
121                 case 1:
122                         za->w = 10;
123                         za->h = height;
124                         za->x = width - 10;
125                         za->y = 0;
126                         za->dx = -speed;
127                         za->dy = 0;
128                         za->n = (width - 10) * 256 / speed;
129                         break;
130                 case 2:
131                         za->w = width;
132                         za->h = 10;
133                         za->x = 0;
134                         za->y = height - 10;
135                         za->dx = 0;
136                         za->dy = -speed;
137                         za->n = (height - 10) * 256 / speed;
138                         break;
139                 case 3:
140                         za->w = 10;
141                         za->h = height;
142                         za->x = 0;
143                         za->y = 0;
144                         za->dx = speed;
145                         za->dy = 0;
146                         za->n = (width - 10) * 256 / speed;
147                         break;
148                 }
149                 za->ww = width - za->w;
150                 za->hh = height - za->h;
151
152                 /* We want smaller angle increments in sweep mode (looks better) */
153
154                 za->a1 = 0;
155                 za->a2 = 0;
156                 za->inc1 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
157                 za->inc2 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
158         } else {
159                 za->w = 50 + random() % 300;
160                 za->h = 50 + random() % 300;
161
162                 if (za->w > width / 3)
163                         za->w = width / 3;
164                 if (za->h > height / 3)
165                         za->h = height / 3;
166
167                 za->ww = width - za->w;
168                 za->hh = height - za->h;
169
170                 za->x = (random() % za->ww);
171                 za->y = (random() % za->hh);
172
173                 za->dx = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
174                 za->dy = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
175
176                 if (anim) {
177                         za->n = 50 + random() % 1000;
178                         za->a1 = 0;
179                         za->a2 = 0;
180                 } else {
181                         za->n = 5 + random() % 10;
182                         za->a1 = random ();
183                         za->a2 = random ();
184                 }
185
186                 za->inc1 = ((2 * (random() & 1)) - 1) * (random () % 30);
187                 za->inc2 = ((2 * (random() & 1)) - 1) * (random () % 30);
188         }
189
190         za->xx = za->x * 256;
191         za->yy = za->y * 256;
192
193         za->count = 0;
194 }
195
196
197 static struct zoom_area *create_zoom (void)
198 {
199         struct zoom_area *za;
200
201         za = malloc (sizeof (struct zoom_area));
202         reset_zoom (za);
203
204         return za;
205 }
206
207
208 static void update_position (struct zoom_area *za)
209 {
210         za->xx += za->dx;
211         za->yy += za->dy;
212
213         za->x = za->xx >> 8;
214         za->y = za->yy >> 8;
215
216         if (za->x < 0) {
217                 za->x = 0;
218                 za->dx = 100 + random() % 100;
219         }
220                 
221         if (za->y < 0) {
222                 za->y = 0;
223                 za->dy = 100 + random() % 100;
224         }
225                 
226         if (za->x > za->ww) {
227                 za->x = za->ww;
228                 za->dx = -(100 + random() % 100);
229         }
230
231         if (za->y > za->hh) {
232                 za->y = za->hh;
233                 za->dy = -(100 + random() % 100);
234         }
235 }
236
237
238 static void DisplayImage (int x, int y, int w, int h)
239 {
240 #ifdef HAVE_XSHM_EXTENSION
241         if (use_shm)
242                 XShmPutImage (display, window, gc, buffer_map, x, y, x, y,
243                         w, h, False);
244         else
245 #endif /* HAVE_XSHM_EXTENSION */
246                 XPutImage(display, window, gc, buffer_map, x, y, x, y, w, h);
247 }
248
249
250 static void hack_main (void)
251 {
252         int i;
253
254         for (i = 0; i < num_zoom; i++) {
255                 if (move || sweep)
256                         update_position (zoom_box[i]);
257
258                 if (zoom_box[i]->n > 0) {
259                         if (anim || zoom_box[i]->count == 0) {
260                                 rotzoom (zoom_box[i]);
261                         } else {
262                                 sleep (1);
263                         }
264                         zoom_box[i]->n--;
265                 } else {
266                         reset_zoom (zoom_box[i]);
267                 }
268         }
269
270         for (i = 0; i < num_zoom; i++) {
271                 DisplayImage(zoom_box[i]->x, zoom_box[i]->y,
272                         zoom_box[i]->w, zoom_box[i]->h);
273         }
274
275         XSync(display,False);
276         screenhack_handle_events(display);
277 }
278
279
280 static void init_hack (void)
281 {
282         int i;
283
284         zoom_box = calloc (num_zoom, sizeof (struct zoom_area *));
285         for (i = 0; i < num_zoom; i++) {
286                 zoom_box[i] = create_zoom ();
287         }
288
289         memcpy (buffer_map->data, orig_map->data,
290                 height * buffer_map->bytes_per_line);
291
292         DisplayImage(0, 0, width, height);
293         XSync(display,False);
294 }
295
296
297 static void setup_X (Display * disp, Window win)
298 {
299         XWindowAttributes xwa;
300         int depth;
301         XGCValues gcv;
302         long gcflags;
303
304         XGetWindowAttributes (disp, win, &xwa);
305         window = win;
306         display = disp;
307         depth = xwa.depth;
308         colormap = xwa.colormap;
309         width = xwa.width;
310         height = xwa.height;
311         visual = xwa.visual;
312
313         if (width % 2)
314                 width--;
315         if (height % 2)
316                 height--;
317
318         gcv.function = GXcopy;
319         gcv.subwindow_mode = IncludeInferiors;
320         gcflags = GCForeground | GCFunction;
321         if (use_subwindow_mode_p (xwa.screen, window))  /* see grabscreen.c */
322                 gcflags |= GCSubwindowMode;
323         gc = XCreateGC (display, window, gcflags, &gcv);
324         load_random_image (xwa.screen, window, window, NULL);
325
326         orig_map = XGetImage (display, window, 0, 0, width, height, ~0L, ZPixmap);
327
328         if (!gc) {
329                 fprintf(stderr, "XCreateGC failed\n");
330                 exit(1);
331         }
332
333         buffer_map = 0;
334
335 #ifdef HAVE_XSHM_EXTENSION
336         if (use_shm) {
337                 buffer_map = create_xshm_image(display, xwa.visual, depth,
338                         ZPixmap, 0, &shm_info, width, height);
339                 if (!buffer_map) {
340                         use_shm = False;
341                         fprintf(stderr, "create_xshm_image failed\n");
342                 }
343         }
344 #endif /* HAVE_XSHM_EXTENSION */
345
346         if (!buffer_map) {
347                 buffer_map = XCreateImage(display, xwa.visual,
348                         depth, ZPixmap, 0, 0, width, height, 8, 0);
349                 buffer_map->data = (char *)calloc (buffer_map->height,
350                         buffer_map->bytes_per_line);
351         }
352 }
353
354
355 char *progclass = "Rotzoomer";
356
357 char *defaults[] = {
358 #ifdef HAVE_XSHM_EXTENSION
359         "*useSHM: True",
360 #endif
361         "*move: False",
362         "*sweep: False",
363         "*anim: True",
364         "*numboxes: 2",
365         "*delay: 10",
366         0
367 };
368
369
370 XrmOptionDescRec options[] = {
371 #ifdef HAVE_XSHM_EXTENSION
372         { "-shm",       ".useSHM",      XrmoptionNoArg, "True"  },
373         { "-no-shm",    ".useSHM",      XrmoptionNoArg, "False" },
374 #endif
375         { "-move",      ".move",        XrmoptionNoArg, "True"  },
376         { "-sweep",     ".sweep",       XrmoptionNoArg, "True"  },
377         { "-anim",      ".anim",        XrmoptionNoArg, "True"  },
378         { "-no-anim",   ".anim",        XrmoptionNoArg, "False" },
379         { "-delay",     ".delay",       XrmoptionSepArg, 0      },
380         { "-n",         ".numboxes",    XrmoptionSepArg, 0      },
381         { 0, 0, 0, 0 }
382 };
383
384
385 void screenhack(Display *disp, Window win)
386 {
387 #ifdef HAVE_XSHM_EXTENSION
388         use_shm = get_boolean_resource ("useSHM", "Boolean");
389 #endif
390         num_zoom = get_integer_resource ("numboxes", "Integer");
391         move = get_boolean_resource ("move", "Boolean");
392         delay = get_integer_resource ("delay", "Integer");
393         sweep = get_boolean_resource ("sweep", "Boolean");
394         anim = get_boolean_resource ("anim", "Boolean");
395
396         /* In sweep or static mode, we want only one box */
397         if (sweep || !anim)
398                 num_zoom = 1;
399
400         /* Can't have static sweep mode */
401         if (!anim)
402                 sweep = 0;
403
404         setup_X (disp, win);
405
406         init_hack ();
407
408         /* Main drawing loop */
409         while (42) {
410                 hack_main ();
411                 usleep (delay * 1000);
412         }
413 }