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 | } |
---|