Fix patches
[xfishtank.git] / xfish.c
1
2 /*
3
4 * Original Author Unknow.
5
6 * 8/10/88 - Ported from X10 to X11R3 by:
7
8 Jonathan Greenblatt (jonnyg@rover.umd.edu)
9
10 * Cleaned up by Dave Lemke (lemke@sun.com)
11
12 * Ported to monocrome by Jonathan Greenblatt (jonnyg@rover.umd.edu)
13
14 * 05/02/1996 Added TrueColor support by TJ Phan (phan@aur.alcatel.com)
15
16 TODO:
17
18 Parameter parsing needs to be redone.
19
20 * Throughout 1991 improved for animation and color and multiple
21 fish types. Broke monocrome in the process.
22 Eric Bina (ebina@ncsa.uiuc.edu)
23
24 * 1992 added extra color remapping control options, as well as ways
25 to let the fish swim on the root window, or an image of the users
26 choice. Eric Bina (ebina@ncsa.uiuc.edu)
27
28 */
29
30 #include <sys/types.h>
31 #ifndef hpux
32 #include <sys/time.h>
33 #else
34 #include <time.h>
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #ifdef sgi
42 #define _BSD_SIGNALS
43 #endif
44 #include <signal.h>
45 #include <X11/Xlib.h>
46 #include <X11/Xutil.h>
47
48 #include "vroot.h"
49 #include "xfishy.h"
50 #include "bubbles.h"
51 #include "medcut.h"
52
53 /* constants are based on rand(3C) returning an integer between 0 and 32767 */
54
55 #if defined(ultrix) || defined(sun) || defined(linux)
56 #define RAND_I_1_16 134217728
57 #define RAND_F_1_8 268435455.875
58 #define RAND_I_1_4 536870911
59 #define RAND_I_1_2 1073741823
60 #define RAND_I_3_4 1610612735
61 #define RAND_F_MAX 2147483647.0
62 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
63 #define RAND_I_1_16 (RAND_MAX>>4)
64 #define RAND_F_1_8 ((float)(RAND_MAX>>3))
65 #define RAND_I_1_4 (RAND_MAX>>2)
66 #define RAND_I_1_2 (RAND_MAX>>1)
67 #define RAND_I_3_4 ((RAND_MAX>>2)*3)
68 #define RAND_F_MAX ((float)RAND_MAX)
69 #else
70 #define RAND_I_1_16 2048
71 #define RAND_F_1_8 4096.0
72 #define RAND_I_1_4 8096
73 #define RAND_I_1_2 16384
74 #define RAND_I_3_4 24575
75 #define RAND_F_MAX 32767.0
76 #endif
77
78
79 extern unsigned char *ReadBitmap();
80
81
82 /* externals for pixmap and bimaps from xfishy.h */
83
84
85 /* typedefs for bubble and fish structures, also caddr_t (not used in X.h) */
86 typedef struct {
87 int x, y, s, erased, i;
88 } bubble;
89 typedef struct {
90 int x, y, d, frame, type, i;
91 } fish;
92 typedef unsigned char *caddrt;
93
94
95 /* bubble increment and yes check tables */
96 int binc[] = { 0, 64, 56, 48, 40, 32, 24, 16, 8 };
97 char *yess[] = { "yes", "Yes", "YES", "on", "On", "ON" };
98
99
100 char *pname, /* program name from argv[0] */
101 sname[64], /* host:display specification */
102 cname[64]; /* colorname specification */
103 char picname[256]; /* name of the background picture file */
104 int *Allocated; /* mark the used colors */
105 int AllocCnt; /* count number of colors used */
106 int mlimit = 0; /* num colors to median cut to. 0 = no limit */
107 int climit = 0; /* limit on color use. 0 = no limit */
108 int DoubleBuf = 0; /* Should we use double buffering */
109 int Overlap = 0; /* Should fish swim over each other */
110 int DoClipping = 0; /* Should clip masks be used. */
111 int blimit = 32, /* bubble limit */
112 flimit = 10, /* fish limit */
113 pmode = 1, /* pop mode, (1 for lower, 0 for raise) */
114 width, /* width of initial window in pixels */
115 height, /* height of initial window in pixels */
116 screen, /* Default screen of this display */
117 Init_B, *cmap; /* Initialize bubbles with random y value */
118 int Pwidth; /* width of background picture */
119 int Pheight; /* height of background picture */
120 int Pcnt; /* number of colors in background picture */
121 unsigned char *Pdata; /* data from background picture */
122 double rate = 0.2, /* update interval in seconds */
123 smooth = 0.2; /* smoothness increment multiplier */
124 bubble *binfo; /* bubble info structures, allocated
125 * dynamically */
126 fish *finfo; /* fish info structures, allocated dynamically */
127 Display *Dpy;
128 Window root_window;
129 XImage *xfishA[NUM_FISH][3]; /* fish pixmaps (1 is left-fish, 2 is
130 * right-fish) */
131 XImage *xfishB[NUM_FISH][3]; /* fish pixmaps (1 is left-fish, 2 is
132 * right-fish) */
133 Pixmap pfishA[NUM_FISH][3];
134 Pixmap pfishB[NUM_FISH][3];
135
136 Pixmap mfishA[NUM_FISH][3]; /* masking pixmaps for fish to use as */
137 Pixmap mfishB[NUM_FISH][3]; /* clipmasks */
138
139 Pixmap PicMap; /* pixmap for background picture */
140
141 Pixmap PixBuf; /* Pixmap buffer for double buffering */
142 Pixmap ClipBuf; /* Clipmask buffer for double buffering */
143
144 Pixmap xbubbles[9]; /* bubbles bitmaps (1 to 8, by size in pixels) */
145 Window wid; /* aqaurium window */
146 unsigned long white, black, bcolor;
147 Colormap colormap;
148 GC c0gc, cpgc; /* GCs to operateon the Clipmask buffer */
149 GC pgc;
150 GC gc, bgc;
151
152
153 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
154 Output desired error message and exit.
155 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
156 void
157 msgdie(message)
158 char *message;
159 {
160 fprintf(stderr, "%s: %s\n", pname, message);
161 exit(1);
162 }
163
164
165 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
166 Set up program defaults, get X defaults, parse command line using getopts.
167 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
168 void
169 parse(argc, argv)
170 int argc;
171 char **argv;
172 {
173 int c, i;
174 extern int optind;
175 extern char *optarg;
176 extern double atof();
177
178 pname = argv[0];
179 strncpy(sname, getenv("DISPLAY"), sizeof(sname) - 1);
180 strcpy(cname, "MediumAquamarine");
181
182 while ((c = getopt(argc, argv, "dDob:C:c:p:m:f:i:r:s")) != EOF) {
183 switch (c) {
184 case 'd':
185 DoClipping = 1;
186 break;
187 case 'D':
188 DoubleBuf = 1;
189 break;
190 case 'o':
191 Overlap = 1;
192 break;
193 case 'b':
194 blimit = atoi(optarg);
195 break;
196 case 'C':
197 climit = atoi(optarg);
198 break;
199 case 'm':
200 mlimit = atoi(optarg);
201 break;
202 case 'c':
203 strncpy(cname, optarg, sizeof(cname) - 1);
204 break;
205 case 'p':
206 strncpy(picname, optarg, sizeof(picname) - 1);
207 break;
208 case 'f':
209 flimit = atoi(optarg);
210 break;
211 case 'i':
212 smooth = atof(optarg);
213 break;
214 case 'r':
215 rate = atof(optarg);
216 break;
217 case 's':
218 pmode = 0;
219 break;
220 case '?':
221 fprintf(stderr, "usage: %s\n", pname);
222 fprintf(stderr, "\t\t[-c color] background color\n");
223 fprintf(stderr, "\t\t[-b limit] number of bubbles (default 32)\n");
224 fprintf(stderr, "\t\t[-f limit] number of fish (default 10)\n");
225 fprintf(stderr, "\t\t[-i mult] move interval (default 0.2)\n");
226 fprintf(stderr, "\t\t[-r rate] move frequency (default 0.2)\n");
227 fprintf(stderr, "\t\t[-m num] median cut to this many colors\n");
228 fprintf(stderr, "\t\t[-C num] use only this many color cells\n");
229 fprintf(stderr, "\t\t[-d] clip fish, swim on root window\n");
230 fprintf(stderr, "\t\t[-p file] fish swim on picture in file\n");
231 fprintf(stderr, "\t\t[host:display]\n");
232 exit(1);
233 }
234 }
235
236 if (optind < argc) {
237 char *display;
238
239 strncpy(sname, argv[optind], sizeof(sname) - 1);
240 display = (char *) malloc(strlen(sname) + 9);
241 snprintf(display, sizeof(display) - 1, "DISPLAY=%s", sname);
242 putenv(display);
243 }
244 }
245
246
247 void
248 erasefish(f, x, y, d)
249 fish *f;
250 int x, y, d;
251 {
252 /*
253 * for something as small as a bubble, it was never worth the
254 * effort of using clipmasks to only turn of the bubble itself, so
255 * we just clear the whole rectangle.
256 */
257 XClearArea(Dpy, wid, x, y, rwidth[f->type], rheight[f->type], False);
258 #if 0
259 XGCValues gcv;
260
261 if (f->frame) {
262 gcv.foreground = cmap[0];
263 gcv.fill_style = FillTiled;
264 gcv.fill_style = FillSolid;
265 gcv.tile = pfishB[f->type][d];
266 gcv.ts_x_origin = f->x;
267 gcv.ts_y_origin = f->y;
268 gcv.clip_mask = mfishB[f->type][d];
269 gcv.clip_x_origin = x;
270 gcv.clip_y_origin = y;
271 XChangeGC(Dpy, gc, GCForeground | GCClipMask |
272 GCTile | GCTileStipXOrigin | GCTileStipYOrigin |
273 GCFillStyle | GCClipXOrigin | GCClipYOrigin, &gcv);
274 XCopyPlane(Dpy, mfishB[f->type][d], wid, gc, 0, 0,
275 rwidth[f->type], rheight[f->type], x, y, (unsigned long) 1);
276 } else {
277 gcv.foreground = cmap[0];
278 gcv.fill_style = FillTiled;
279 gcv.fill_style = FillSolid;
280 gcv.tile = pfishA[f->type][d];
281 gcv.ts_x_origin = f->x;
282 gcv.ts_y_origin = f->y;
283 gcv.clip_mask = mfishA[f->type][d];
284 gcv.clip_x_origin = x;
285 gcv.clip_y_origin = y;
286 XChangeGC(Dpy, gc, GCForeground | GCClipMask |
287 GCTile | GCTileStipXOrigin | GCTileStipYOrigin |
288 GCFillStyle | GCClipXOrigin | GCClipYOrigin, &gcv);
289 XCopyPlane(Dpy, mfishA[f->type][d], wid, gc, 0, 0,
290 rwidth[f->type], rheight[f->type], x, y, (unsigned long) 1);
291 }
292 #endif
293 }
294
295
296 /*
297 * Just places a fish. Normally this is all you need for animation, since
298 * placeing the fish places an entire rectangle which erases most of the old
299 * fish (the rest being cleaned up by the function that called putfish.
300 * If DoClipping is set, this function is only called when placing a new
301 * fish, otherwise newfish is called.
302 */
303 void
304 putfish(f)
305 fish *f;
306 {
307 XGCValues gcv;
308
309 if (f->frame) {
310 /*
311 * If we have a pixmap of the fish use it, otherwise use
312 * the XImage of the fish. In reality we will never use
313 * the XImage since X dies if the pixmap create failed
314 */
315 if (pfishA[f->type][f->d]) {
316 /*
317 * Clipping overrides background picture because
318 * the clipping prevents the drawing of any background
319 * anyway.
320 * DoClipping says just print a fish leaving the
321 * background unchanged.
322 * If there is a background picture, we use a buffer
323 * to prevent flashing, we combine the background
324 * picture and the fish, and then copy the
325 * whole rectangle in.
326 * Default is just copy in fish in with a background
327 * color.
328 */
329 if (DoClipping) {
330 gcv.clip_mask = mfishA[f->type][f->d];
331 gcv.clip_x_origin = f->x;
332 gcv.clip_y_origin = f->y;
333 XChangeGC(Dpy, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
334 XCopyArea(Dpy, pfishA[f->type][f->d], wid, gc,
335 0, 0, rwidth[f->type], rheight[f->type], f->x, f->y);
336 } else if (picname[0] != '\0') {
337 gcv.fill_style = FillTiled;
338 gcv.tile = PicMap;
339 gcv.ts_x_origin = -(f->x);
340 gcv.ts_y_origin = -(f->y);
341 gcv.clip_mask = None;
342 XChangeGC(Dpy, pgc, (GCFillStyle |
343 GCTile | GCTileStipXOrigin |
344 GCTileStipYOrigin | GCClipMask), &gcv);
345 XFillRectangle(Dpy, PixBuf, pgc, 0, 0, rwidth[f->type], rheight[f->type]);
346
347 gcv.clip_mask = mfishA[f->type][f->d];
348 gcv.clip_x_origin = 0;
349 gcv.clip_y_origin = 0;
350 XChangeGC(Dpy, pgc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
351 XCopyArea(Dpy, pfishA[f->type][f->d], PixBuf, pgc,
352 0, 0, rwidth[f->type], rheight[f->type], 0, 0);
353
354 XCopyArea(Dpy, PixBuf, wid, gc,
355 0, 0, rwidth[f->type], rheight[f->type], f->x, f->y);
356 } else {
357 XCopyArea(Dpy, pfishA[f->type][f->d], wid, gc,
358 0, 0, rwidth[f->type], rheight[f->type], f->x, f->y);
359 }
360 } else {
361 XPutImage(Dpy, wid, gc, xfishA[f->type][f->d], 0, 0,
362 f->x, f->y, rwidth[f->type], rheight[f->type]);
363 }
364 f->frame = 0;
365 } else {
366 /*
367 * same as the above, only for the second frame of animation
368 */
369 if (pfishB[f->type][f->d]) {
370 if (DoClipping) {
371 gcv.clip_mask = mfishB[f->type][f->d];
372 gcv.clip_x_origin = f->x;
373 gcv.clip_y_origin = f->y;
374 XChangeGC(Dpy, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
375 XCopyArea(Dpy, pfishB[f->type][f->d], wid, gc,
376 0, 0, rwidth[f->type], rheight[f->type], f->x, f->y);
377 } else if (picname[0] != '\0') {
378 gcv.fill_style = FillTiled;
379 gcv.tile = PicMap;
380 gcv.ts_x_origin = -(f->x);
381 gcv.ts_y_origin = -(f->y);
382 gcv.clip_mask = None;
383 XChangeGC(Dpy, pgc, (GCFillStyle |
384 GCTile | GCTileStipXOrigin |
385 GCTileStipYOrigin | GCClipMask), &gcv);
386 XFillRectangle(Dpy, PixBuf, pgc, 0, 0, rwidth[f->type], rheight[f->type]);
387
388 gcv.clip_mask = mfishB[f->type][f->d];
389 gcv.clip_x_origin = 0;
390 gcv.clip_y_origin = 0;
391 XChangeGC(Dpy, pgc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
392 XCopyArea(Dpy, pfishB[f->type][f->d], PixBuf, pgc,
393 0, 0, rwidth[f->type], rheight[f->type], 0, 0);
394
395 XCopyArea(Dpy, PixBuf, wid, gc,
396 0, 0, rwidth[f->type], rheight[f->type], f->x, f->y);
397 } else {
398 XCopyArea(Dpy, pfishB[f->type][f->d], wid, gc,
399 0, 0, rwidth[f->type], rheight[f->type], f->x, f->y);
400 }
401 } else {
402 XPutImage(Dpy, wid, gc, xfishB[f->type][f->d], 0, 0,
403 f->x, f->y, rwidth[f->type], rheight[f->type]);
404 }
405 f->frame = 1;
406 }
407 }
408
409
410 /*
411 * This function can only be called if DoClipping is True. It is used to
412 * move a clipmasked fish. First the area under the fish is cleared,
413 * and then the new fish is masked in.
414 * The parameters x, y, amd d are from the old fish that is being
415 * erased before the new fish is drawn.
416 */
417 void
418 movefish(f, x, y, d)
419 fish *f;
420 int x, y, d;
421 {
422 XGCValues gcv;
423 int bx, by, bw, bh;
424
425 /*
426 * If we are going to double buffer, we need to find the bounding
427 * rectangle of the overlap of the bounding rectangles of the old
428 * and the new fish.
429 */
430 if (DoubleBuf) {
431 if (x < f->x) {
432 bx = x;
433 bw = f->x - x + rwidth[f->type];
434 } else {
435 bx = f->x;
436 bw = x - f->x + rwidth[f->type];
437 }
438 if (y < f->y) {
439 by = y;
440 bh = f->y - y + rheight[f->type];
441 } else {
442 by = f->y;
443 bh = y - f->y + rheight[f->type];
444 }
445 }
446
447 if (f->frame) {
448 /*
449 * If there is a pixmap use it.
450 * This branchis always taken since right now, if the pixmap
451 * allocation failed, the program dies.
452 */
453 if (pfishA[f->type][f->d]) {
454 /*
455 * A pointless if, you now only come here if
456 * DoClipping is set, I've just been too lazy to
457 * clean up my code.
458 */
459 if (DoClipping) {
460 /*
461 * Set up the masked gc for when we eventually
462 * draw the fish. Origin is different for
463 * whether we are drawing into the buffer
464 * or into the window
465 */
466 gcv.clip_mask = mfishA[f->type][f->d];
467 if (DoubleBuf) {
468 gcv.clip_x_origin = f->x - bx;
469 gcv.clip_y_origin = f->y - by;
470 } else {
471 gcv.clip_x_origin = f->x;
472 gcv.clip_y_origin = f->y;
473 }
474 XChangeGC(Dpy, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
475
476 /*
477 * If we have a background picture we want to
478 * clear to that background, otherwise we just
479 * do an XCleararea, and let the root restore
480 * the background.
481 */
482 if (picname[0] != '\0') {
483 gcv.fill_style = FillTiled;
484 gcv.tile = PicMap;
485 gcv.clip_mask = mfishB[f->type][d];
486 if (DoubleBuf) {
487 gcv.ts_x_origin = 0 - bx;
488 gcv.ts_y_origin = 0 - by;
489 gcv.clip_x_origin = x - bx;
490 gcv.clip_y_origin = y - by;
491 } else {
492 gcv.ts_x_origin = 0;
493 gcv.ts_y_origin = 0;
494 gcv.clip_x_origin = x;
495 gcv.clip_y_origin = y;
496 }
497 XChangeGC(Dpy, pgc, (GCFillStyle |
498 GCTile | GCTileStipXOrigin |
499 GCTileStipYOrigin | GCClipMask |
500 GCClipXOrigin | GCClipYOrigin), &gcv);
501
502 /*
503 * if bouble buffering we clear the buffer
504 * to the backgound picture, and then
505 * shape the clip buffer to the shape of
506 * the fish being erased.
507 */
508 if (DoubleBuf) {
509 XFillRectangle(Dpy, PixBuf, pgc,
510 x - bx, y - by, rwidth[f->type], rheight[f->type]);
511 XFillRectangle(Dpy, ClipBuf, c0gc, 0, 0, 500, 500);
512 XCopyArea(Dpy, mfishB[f->type][d],
513 ClipBuf, cpgc, 0, 0,
514 rwidth[f->type], rheight[f->type], x - bx, y - by);
515 } else {
516 XFillRectangle(Dpy, wid, pgc, x, y, rwidth[f->type], rheight[f->type]);
517 }
518 } else {
519 XClearArea(Dpy, wid, x, y, rwidth[f->type], rheight[f->type], 0);
520 }
521 }
522 /*
523 * Now we just copy in the new fish with a clipmasked gc.
524 * But if we doublebuffered, we copy the new fish into
525 * the buffer, combine the new fishes clipmask in, and
526 * then mask the whole lot from the buffer to the window.
527 */
528 if (DoubleBuf) {
529 XCopyArea(Dpy, pfishA[f->type][f->d], PixBuf, gc, 0, 0,
530 rwidth[f->type], rheight[f->type], f->x - bx, f->y - by);
531 XCopyArea(Dpy, mfishA[f->type][f->d], ClipBuf, cpgc,
532 0, 0, rwidth[f->type], rheight[f->type], f->x - bx, f->y - by);
533 gcv.clip_mask = ClipBuf;
534 gcv.clip_x_origin = bx;
535 gcv.clip_y_origin = by;
536 XChangeGC(Dpy, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
537 XCopyArea(Dpy, PixBuf, wid, gc, 0, 0, bw, bh, bx, by);
538 } else {
539 XCopyArea(Dpy, pfishA[f->type][f->d], wid, gc, 0, 0,
540 rwidth[f->type], rheight[f->type], f->x, f->y);
541 }
542 } else {
543 if (DoClipping) {
544 if (picname[0] != '\0') {
545 gcv.fill_style = FillTiled;
546 gcv.tile = PicMap;
547 gcv.ts_x_origin = 0;
548 gcv.ts_y_origin = 0;
549 gcv.clip_mask = mfishB[f->type][d];
550 gcv.clip_x_origin = x;
551 gcv.clip_y_origin = y;
552 XChangeGC(Dpy, pgc, (GCFillStyle |
553 GCTile | GCTileStipXOrigin |
554 GCTileStipYOrigin | GCClipMask |
555 GCClipXOrigin | GCClipYOrigin), &gcv);
556 XFillRectangle(Dpy, wid, pgc, x, y, rwidth[f->type], rheight[f->type]);
557 } else {
558 XClearArea(Dpy, wid, x, y, rwidth[f->type], rheight[f->type], 0);
559 }
560 }
561 XPutImage(Dpy, wid, gc, xfishA[f->type][f->d], 0, 0,
562 f->x, f->y, rwidth[f->type], rheight[f->type]);
563 }
564 f->frame = 0;
565 } else {
566 /*
567 * Same as above, only for the second frame of animation.
568 */
569 if (pfishB[f->type][f->d]) {
570 if (DoClipping) {
571 gcv.clip_mask = mfishB[f->type][f->d];
572 if (DoubleBuf) {
573 gcv.clip_x_origin = f->x - bx;
574 gcv.clip_y_origin = f->y - by;
575 } else {
576 gcv.clip_x_origin = f->x;
577 gcv.clip_y_origin = f->y;
578 }
579 XChangeGC(Dpy, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
580 if (picname[0] != '\0') {
581 gcv.fill_style = FillTiled;
582 gcv.tile = PicMap;
583 gcv.clip_mask = mfishA[f->type][d];
584 if (DoubleBuf) {
585 gcv.ts_x_origin = 0 - bx;
586 gcv.ts_y_origin = 0 - by;
587 gcv.clip_x_origin = x - bx;
588 gcv.clip_y_origin = y - by;
589 } else {
590 gcv.ts_x_origin = 0;
591 gcv.ts_y_origin = 0;
592 gcv.clip_x_origin = x;
593 gcv.clip_y_origin = y;
594 }
595 XChangeGC(Dpy, pgc, (GCFillStyle |
596 GCTile | GCTileStipXOrigin |
597 GCTileStipYOrigin | GCClipMask |
598 GCClipXOrigin | GCClipYOrigin), &gcv);
599 if (DoubleBuf) {
600 XFillRectangle(Dpy, PixBuf, pgc,
601 x - bx, y - by, rwidth[f->type], rheight[f->type]);
602 XFillRectangle(Dpy, ClipBuf, c0gc, 0, 0, 500, 500);
603 XCopyArea(Dpy, mfishA[f->type][d],
604 ClipBuf, cpgc, 0, 0,
605 rwidth[f->type], rheight[f->type], x - bx, y - by);
606 } else {
607 XFillRectangle(Dpy, wid, pgc, x, y, rwidth[f->type], rheight[f->type]);
608 }
609 } else {
610 XClearArea(Dpy, wid, x, y, rwidth[f->type], rheight[f->type], 0);
611 }
612 }
613 if (DoubleBuf) {
614 XCopyArea(Dpy, pfishB[f->type][f->d], PixBuf, gc, 0, 0,
615 rwidth[f->type], rheight[f->type], f->x - bx, f->y - by);
616 XCopyArea(Dpy, mfishB[f->type][f->d], ClipBuf, cpgc,
617 0, 0, rwidth[f->type], rheight[f->type], f->x - bx, f->y - by);
618 gcv.clip_mask = ClipBuf;
619 gcv.clip_x_origin = bx;
620 gcv.clip_y_origin = by;
621 XChangeGC(Dpy, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
622 XCopyArea(Dpy, PixBuf, wid, gc, 0, 0, bw, bh, bx, by);
623 } else {
624 XCopyArea(Dpy, pfishB[f->type][f->d], wid, gc, 0, 0,
625 rwidth[f->type], rheight[f->type], f->x, f->y);
626 }
627 } else {
628 if (DoClipping) {
629 if (picname[0] != '\0') {
630 gcv.fill_style = FillTiled;
631 gcv.tile = PicMap;
632 gcv.ts_x_origin = 0;
633 gcv.ts_y_origin = 0;
634 gcv.clip_mask = mfishA[f->type][d];
635 gcv.clip_x_origin = x;
636 gcv.clip_y_origin = y;
637 XChangeGC(Dpy, pgc, (GCFillStyle |
638 GCTile | GCTileStipXOrigin |
639 GCTileStipYOrigin | GCClipMask |
640 GCClipXOrigin | GCClipYOrigin), &gcv);
641 XFillRectangle(Dpy, wid, pgc, x, y, rwidth[f->type], rheight[f->type]);
642 } else {
643 XClearArea(Dpy, wid, x, y, rwidth[f->type], rheight[f->type], 0);
644 }
645 }
646 XPutImage(Dpy, wid, gc, xfishB[f->type][f->d], 0, 0,
647 f->x, f->y, rwidth[f->type], rheight[f->type]);
648 }
649 f->frame = 1;
650 }
651 }
652
653
654 erasebubble(b, s)
655 bubble *b;
656 int s;
657 {
658 XClearArea(Dpy, wid, b->x, b->y, s, s, 0);
659 }
660
661
662 putbubble(b, s, c)
663 bubble *b;
664 int s;
665 unsigned long c;
666 {
667 XGCValues gcv;
668
669 gcv.foreground = c;
670 gcv.clip_mask = xbubbles[s];
671 gcv.clip_x_origin = b->x;
672 gcv.clip_y_origin = b->y;
673 XChangeGC(Dpy, bgc, GCForeground | GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
674 XFillRectangle(Dpy, wid, bgc, b->x, b->y, s, s);
675 }
676
677
678 /*
679 * Find the closest color by allocating it, or picking an already allocated
680 * color
681 */
682 Visual(*visual_info) = NULL;
683 int r_mask, g_mask, b_mask;
684 int r_shift = 0, g_shift = 0, b_shift = 0;
685 int r_bits = 0, g_bits = 0, b_bits = 0;
686 void
687 FindColor(Dpy, colormap, colr)
688 Display *Dpy;
689 Colormap colormap;
690 XColor *colr;
691 {
692 int i, match;
693 double rd, gd, bd, dist, mindist;
694 int cindx;
695 XColor def_colrs[256];
696 int NumCells;
697
698 if (visual_info == NULL && DefaultDepth(Dpy, DefaultScreen(Dpy)) > 8) {
699 visual_info = DefaultVisual(Dpy, DefaultScreen(Dpy));
700 r_mask = visual_info->red_mask;
701 while (!(r_mask & 1)) {
702 r_mask >>= 1;
703 r_shift++;
704 }
705 while (r_mask & 1) {
706 r_mask >>= 1;
707 r_bits++;
708 }
709
710 g_mask = visual_info->green_mask;
711 while (!(g_mask & 1)) {
712 g_mask >>= 1;
713 g_shift++;
714 }
715 while (g_mask & 1) {
716 g_mask >>= 1;
717 g_bits++;
718 }
719
720 b_mask = visual_info->blue_mask;
721 while (!(b_mask & 1)) {
722 b_mask >>= 1;
723 b_shift++;
724 }
725 while (b_mask & 1) {
726 b_mask >>= 1;
727 b_bits++;
728 }
729 }
730
731 if (DefaultDepth(Dpy, DefaultScreen(Dpy)) > 8) {
732 colr->red >>= 16 - r_bits;
733 colr->green >>= 16 - g_bits;
734 colr->blue >>= 16 - b_bits;
735
736 colr->pixel = ((colr->red << r_shift) & visual_info->red_mask) |
737 ((colr->green << g_shift) & visual_info->green_mask) |
738 ((colr->blue << b_shift) & visual_info->blue_mask);
739 return;
740 }
741
742 if (AllocCnt < climit) {
743 match = XAllocColor(Dpy, colormap, colr);
744 } else {
745 match = 0;
746 }
747 if (match == 0) {
748 NumCells = DisplayCells(Dpy, DefaultScreen(Dpy));
749 for (i = 0; i < NumCells; i++) {
750 def_colrs[i].pixel = i;
751 }
752 XQueryColors(Dpy, colormap, def_colrs, NumCells);
753 mindist = 65536.0 * 65536.0;
754 cindx = colr->pixel;
755 for (i = 0; i < NumCells; i++) {
756 rd = (def_colrs[i].red - colr->red) / 256.0;
757 gd = (def_colrs[i].green - colr->green) / 256.0;
758 bd = (def_colrs[i].blue - colr->blue) / 256.0;
759 dist = (rd * rd * rd * rd) + (gd * gd * gd * gd) + (bd * bd * bd * bd);
760 if (dist < mindist) {
761 mindist = dist;
762 cindx = def_colrs[i].pixel;
763 }
764 }
765 colr->pixel = cindx;
766 colr->red = def_colrs[cindx].red;
767 colr->green = def_colrs[cindx].green;
768 colr->blue = def_colrs[cindx].blue;
769 } else {
770 if (Allocated[colr->pixel] == 0) {
771 Allocated[colr->pixel] = 1;
772 AllocCnt++;
773 }
774 }
775 }
776
777
778 int
779 ColorUsage(data, width, height, colrs)
780 unsigned char *data;
781 int width, height;
782 struct colr_data *colrs;
783 {
784 int mapping[256];
785 int i, size;
786 int cnt, indx;
787 unsigned char *ptr;
788 struct colr_data newcol[256];
789
790 for (i = 0; i < 256; i++) {
791 mapping[i] = -1;
792 }
793
794 size = width * height;
795 cnt = 0;
796 ptr = data;
797 for (i = 0; i < size; i++) {
798 indx = (int) *ptr;
799 if (mapping[indx] == -1) {
800 mapping[indx] = cnt;
801 newcol[cnt].red = colrs[indx].red;
802 newcol[cnt].green = colrs[indx].green;
803 newcol[cnt].blue = colrs[indx].blue;
804 cnt++;
805 }
806 ptr++;
807 }
808
809 ptr = data;
810 for (i = 0; i < size; i++) {
811 indx = (int) *ptr;
812 *ptr = (unsigned char) mapping[indx];
813 ptr++;
814 }
815
816 for (i = 0; i < cnt; i++) {
817 colrs[i].red = newcol[i].red;
818 colrs[i].green = newcol[i].green;
819 colrs[i].blue = newcol[i].blue;
820 }
821 for (i = cnt; i < 256; i++) {
822 colrs[i].red = 0;
823 colrs[i].green = 0;
824 colrs[i].blue = 0;
825 }
826
827 return (cnt);
828 }
829
830
831 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
832 Initialize colormap for background color and required fish colors.
833 The fish colors are coded in xfishy.h as a trio of tables.
834 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
835 void
836 init_colormap()
837 {
838 FILE *fp;
839 int i, j, cnt;
840 int NumCells;
841 XColor hdef, edef;
842 struct colr_data *cdp;
843 struct colr_data colrs[256];
844
845 colormap = XDefaultColormap(Dpy, screen);
846
847 NumCells = DisplayCells(Dpy, DefaultScreen(Dpy));
848 Allocated = (int *) malloc(NumCells * sizeof(int));
849 for (i = 0; i < NumCells; i++) {
850 Allocated[i] = 0;
851 }
852 AllocCnt = 0;
853 if ((climit <= 0) || (climit > NumCells)) {
854 climit = NumCells;
855 }
856
857 Pcnt = 0;
858 if (picname[0] != '\0') {
859 fp = fopen(picname, "r");
860 if (fp == NULL) {
861 fprintf(stderr, "Cannot open picture %s for reading\n", picname);
862 } else {
863 Pdata = ReadBitmap(fp, &Pwidth, &Pheight, colrs);
864 fclose(fp);
865 Pcnt = ColorUsage(Pdata, Pwidth, Pheight, colrs);
866 }
867 }
868
869 cnt = 0;
870 cnt += Pcnt;
871 for (i = 0; i < NUM_FISH; i++) {
872 cnt += rcolors[i];
873 }
874 cmap = (int *) malloc((cnt + 1) * sizeof(int));
875
876 XLookupColor(Dpy, colormap, cname, &hdef, &edef);
877 hdef.flags = DoRed | DoGreen | DoBlue;
878 FindColor(Dpy, colormap, &hdef);
879 cmap[0] = hdef.pixel;
880
881 if (mlimit > 0) {
882 MedianInit();
883 }
884
885 if (mlimit > 0) {
886 if (picname[0] != '\0') {
887 MedianCount(Pdata, Pwidth, Pheight, colrs);
888 }
889 for (j = 0; j < NUM_FISH; j++) {
890 int *rp, *gp, *bp;
891
892 cdp = (struct colr_data *) malloc(rcolors[j] * sizeof(struct colr_data));
893 rp = rreds[j];
894 gp = rgreens[j];
895 bp = rblues[j];
896 for (i = 0; i < rcolors[j]; i++) {
897 cdp[i].red = *rp++;
898 cdp[i].green = *gp++;
899 cdp[i].blue = *bp++;
900 }
901 MedianCount((unsigned char *) xfishRasterA[j],
902 (int) rwidth[j], (int) rheight[j], cdp);
903 free((char *) cdp);
904 }
905 MedianSplit(mlimit);
906 }
907
908 cnt = 1;
909 if (picname[0] != '\0') {
910 for (i = 0; i < Pcnt; i++) {
911 int rv, gv, bv;
912
913 rv = colrs[i].red;
914 gv = colrs[i].green;
915 bv = colrs[i].blue;
916
917 if (mlimit > 0) {
918 ConvertColor(&rv, &gv, &bv);
919 }
920
921 hdef.red = rv;
922 hdef.green = gv;
923 hdef.blue = bv;
924 hdef.flags = DoRed | DoGreen | DoBlue;
925 FindColor(Dpy, colormap, &hdef);
926 cmap[cnt] = hdef.pixel;
927 cnt++;
928 }
929 }
930 for (j = 0; j < NUM_FISH; j++) {
931 int *rp, *gp, *bp;
932
933 rp = rreds[j];
934 gp = rgreens[j];
935 bp = rblues[j];
936 for (i = 0; i < rcolors[j]; i++) {
937 int rv, gv, bv;
938
939 rv = *rp++;
940 gv = *gp++;
941 bv = *bp++;
942
943 if (mlimit > 0) {
944 ConvertColor(&rv, &gv, &bv);
945 }
946
947 hdef.red = rv;
948 hdef.green = gv;
949 hdef.blue = bv;
950 hdef.flags = DoRed | DoGreen | DoBlue;
951 FindColor(Dpy, colormap, &hdef);
952 cmap[cnt] = hdef.pixel;
953 if (i == rback[j]) {
954 cmap[cnt] = cmap[0];
955 }
956 cnt++;
957 }
958 }
959
960 bcolor = white;
961 }
962
963
964 /*
965 * Make am image of appropriate depth for display from image data.
966 */
967 XImage *
968 MakeImage(data, width, height)
969 unsigned char *data;
970 int width, height;
971 {
972 int linepad, shiftnum;
973 int shiftstart, shiftstop, shiftinc;
974 int bytesperline;
975 int depth, temp;
976 int w, h;
977 XImage *newimage;
978 unsigned char *bit_data, *bitp, *datap;
979
980 depth = DefaultDepth(Dpy, DefaultScreen(Dpy));
981 if ((depth != 1) && (depth != 2) && (depth != 4) && (depth != 8)) {
982 fprintf(stderr, "Don't know how to format image for display of depth %d\n", depth);
983 exit(1);
984 }
985
986 if (BitmapBitOrder(Dpy) == LSBFirst) {
987 shiftstart = 0;
988 shiftstop = 8;
989 shiftinc = depth;
990 } else {
991 shiftstart = 8 - depth;
992 shiftstop = -depth;
993 shiftinc = -depth;
994 }
995 linepad = 8 - (width % 8);
996 bit_data = (unsigned char *) malloc(((width + linepad) * height) + 1);
997 bitp = bit_data;
998 datap = data;
999 *bitp = 0;
1000 shiftnum = shiftstart;
1001 for (h = 0; h < height; h++) {
1002 for (w = 0; w < width; w++) {
1003 temp = *datap++ << shiftnum;
1004 *bitp = *bitp | temp;
1005 shiftnum = shiftnum + shiftinc;
1006 if (shiftnum == shiftstop) {
1007 shiftnum = shiftstart;
1008 bitp++;
1009 *bitp = 0;
1010 }
1011 }
1012 for (w = 0; w < linepad; w++) {
1013 shiftnum = shiftnum + shiftinc;
1014 if (shiftnum == shiftstop) {
1015 shiftnum = shiftstart;
1016 bitp++;
1017 *bitp = 0;
1018 }
1019 }
1020 }
1021
1022 bytesperline = (width * depth / 8 + linepad);
1023 newimage = XCreateImage(Dpy, DefaultVisual(Dpy, screen), depth,
1024 ZPixmap, 0, (char *) bit_data,
1025 (width + linepad), height, 8, bytesperline);
1026
1027 return (newimage);
1028 }
1029
1030
1031
1032 static unsigned char bits[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1033
1034 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1035 Calibrate the pixmaps and bimaps. The right-fish data is coded in xfishy.h,
1036 this is transformed to create the left-fish. The eight bubbles are coded
1037 in bubbles.h as a two dimensional array.
1038 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1039 void
1040 init_pixmap()
1041 {
1042 register caddrt p, q, x1A, x1B, x2A, x2B;
1043 unsigned char *data;
1044 register int i, j, k;
1045 int cnt, wcnt;
1046
1047 cnt = 1;
1048 cnt += Pcnt;
1049 for (k = 0; k < NUM_FISH; k++) {
1050
1051 /*
1052 * The clipmasks must be created before we remap colors.
1053 * otherwise an opaque color might get remapped to a
1054 * transparent color.
1055 */
1056 if ((DoClipping) || (picname[0] != '\0')) {
1057 data = (unsigned char *) malloc((rwidth[k] + 7) / 8 * rheight[k]);
1058
1059 p = (caddrt) xfishRasterA[k];
1060 q = data;
1061 wcnt = 0;
1062 for (i = 0; i < ((rwidth[k] + 7) / 8 * rheight[k]); i++) {
1063 unsigned char bt = 0x00;
1064 for (j = 0; j < 8; j++) {
1065 if (*p != rback[k]) {
1066 bt = bt | bits[j];
1067 }
1068 wcnt++;
1069 p++;
1070 if (wcnt == rwidth[k]) {
1071 wcnt = 0;
1072 break;
1073 }
1074 }
1075 *q++ = bt;
1076 }
1077 mfishA[k][2] = XCreateBitmapFromData(Dpy, wid,
1078 (char *) data, rwidth[k], rheight[k]);
1079
1080 p = (caddrt) xfishRasterA[k];
1081 p = p + rwidth[k] - 1;
1082 q = data;
1083 wcnt = 0;
1084 for (i = 0; i < ((rwidth[k] + 7) / 8 * rheight[k]); i++) {
1085 unsigned char bt = 0x00;
1086 for (j = 0; j < 8; j++) {
1087 if (*p != rback[k]) {
1088 bt = bt | bits[j];
1089 }
1090 wcnt++;
1091 p--;
1092 if (wcnt == rwidth[k]) {
1093 wcnt = 0;
1094 p = p + (2 * rwidth[k]);
1095 break;
1096 }
1097 }
1098 *q++ = bt;
1099 }
1100 mfishA[k][1] = XCreateBitmapFromData(Dpy, wid,
1101 (char *) data, rwidth[k], rheight[k]);
1102
1103 p = (caddrt) xfishRasterB[k];
1104 q = data;
1105 wcnt = 0;
1106 for (i = 0; i < ((rwidth[k] + 7) / 8 * rheight[k]); i++) {
1107 unsigned char bt = 0x00;
1108 for (j = 0; j < 8; j++) {
1109 if (*p != rback[k]) {
1110 bt = bt | bits[j];
1111 }
1112 wcnt++;
1113 p++;
1114 if (wcnt == rwidth[k]) {
1115 wcnt = 0;
1116 break;
1117 }
1118 }
1119 *q++ = bt;
1120 }
1121 mfishB[k][2] = XCreateBitmapFromData(Dpy, wid,
1122 (char *) data, rwidth[k], rheight[k]);
1123
1124 p = (caddrt) xfishRasterB[k];
1125 p = p + rwidth[k] - 1;
1126 q = data;
1127 wcnt = 0;
1128 for (i = 0; i < ((rwidth[k] + 7) / 8 * rheight[k]); i++) {
1129 unsigned char bt = 0x00;
1130 for (j = 0; j < 8; j++) {
1131 if (*p != rback[k]) {
1132 bt = bt | bits[j];
1133 }
1134 wcnt++;
1135 p--;
1136 if (wcnt == rwidth[k]) {
1137 wcnt = 0;
1138 p = p + (2 * rwidth[k]);
1139 break;
1140 }
1141 }
1142 *q++ = bt;
1143 }
1144 mfishB[k][1] = XCreateBitmapFromData(Dpy, wid,
1145 (char *) data, rwidth[k], rheight[k]);
1146
1147 free((char *) data);
1148 }
1149
1150 if (DisplayPlanes(Dpy, screen) < 8) {
1151
1152 j = rwidth[k] * rheight[k];
1153 x1A = (caddrt) malloc(rwidth[k] * rheight[k]);
1154 p = (caddrt) xfishRasterA[k];
1155
1156
1157 q = x1A;
1158 for (i = 0; i < j; i++) {
1159 *q = cmap[cnt + (int) (*p)];
1160 p++;
1161 q++;
1162 }
1163
1164 x1B = (caddrt) malloc(rwidth[k] * rheight[k]);
1165 p = (caddrt) xfishRasterB[k];
1166 q = x1B;
1167 for (i = 0; i < j; i++) {
1168 *q = cmap[cnt + (int) (*p)];
1169 p++;
1170 q++;
1171 }
1172
1173 x2A = (caddrt) malloc(rwidth[k] * rheight[k]);
1174 for (i = 0; i < rheight[k]; i++) {
1175 p = x1A + i * rwidth[k];
1176 q = x2A + (i + 1) * rwidth[k] - 1;
1177 for (j = 0; j < rwidth[k]; j++) {
1178 *q-- = *p++;
1179 }
1180 }
1181
1182 x2B = (caddrt) malloc(rwidth[k] * rheight[k]);
1183 for (i = 0; i < rheight[k]; i++) {
1184 p = x1B + i * rwidth[k];
1185 q = x2B + (i + 1) * rwidth[k] - 1;
1186 for (j = 0; j < rwidth[k]; j++) {
1187 *q-- = *p++;
1188 }
1189 }
1190
1191 xfishA[k][2] = MakeImage(x1A, rwidth[k], rheight[k]);
1192 xfishA[k][1] = MakeImage(x2A, rwidth[k], rheight[k]);
1193 xfishB[k][2] = MakeImage(x1B, rwidth[k], rheight[k]);
1194 xfishB[k][1] = MakeImage(x2B, rwidth[k], rheight[k]);
1195
1196 free((char *) x1A);
1197 free((char *) x2A);
1198 free((char *) x1B);
1199 free((char *) x2B);
1200 } else {
1201 i = DisplayPlanes(Dpy, screen);
1202
1203 xfishA[k][2] =
1204 XGetImage(Dpy, root_window, 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1205
1206 p = (caddrt) xfishRasterA[k];
1207
1208 for (j = 0; j < rheight[k]; j++) {
1209 for (i = 0; i < rwidth[k]; i++) {
1210 XPutPixel(xfishA[k][2], i, j, cmap[cnt + (int) (*p)]);
1211 p++;
1212 }
1213 }
1214
1215 xfishB[k][2] =
1216 XGetImage(Dpy, root_window, 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1217
1218 p = (caddrt) xfishRasterB[k];
1219
1220 for (j = 0; j < rheight[k]; j++) {
1221 for (i = 0; i < rwidth[k]; i++) {
1222 XPutPixel(xfishB[k][2], i, j, cmap[cnt + (int) (*p)]);
1223 p++;
1224 }
1225 }
1226
1227 xfishA[k][1] =
1228 XGetImage(Dpy, root_window, 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1229
1230 for (j = 0; j < rheight[k]; j++) {
1231 for (i = 0; i < rwidth[k]; i++) {
1232 XPutPixel(xfishA[k][1], i, j,
1233 XGetPixel(xfishA[k][2], rwidth[k] - i - 1, j));
1234 }
1235 }
1236
1237 xfishB[k][1] =
1238 XGetImage(Dpy, root_window, 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1239
1240 for (j = 0; j < rheight[k]; j++) {
1241 for (i = 0; i < rwidth[k]; i++) {
1242 XPutPixel(xfishB[k][1], i, j,
1243 XGetPixel(xfishB[k][2], rwidth[k] - i - 1, j));
1244 }
1245 }
1246
1247 }
1248
1249
1250 i = DisplayPlanes(Dpy, screen);
1251
1252 pfishA[k][1] = XCreatePixmap(Dpy, wid, rwidth[k], rheight[k], i);
1253 pfishA[k][2] = XCreatePixmap(Dpy, wid, rwidth[k], rheight[k], i);
1254 pfishB[k][1] = XCreatePixmap(Dpy, wid, rwidth[k], rheight[k], i);
1255 pfishB[k][2] = XCreatePixmap(Dpy, wid, rwidth[k], rheight[k], i);
1256
1257 if (pfishA[k][1]) {
1258 XPutImage(Dpy, pfishA[k][1], gc, xfishA[k][1], 0, 0, 0, 0, rwidth[k], rheight[k]);
1259 }
1260 if (pfishA[k][2]) {
1261 XPutImage(Dpy, pfishA[k][2], gc, xfishA[k][2], 0, 0, 0, 0, rwidth[k], rheight[k]);
1262 }
1263 if (pfishB[k][1]) {
1264 XPutImage(Dpy, pfishB[k][1], gc, xfishB[k][1], 0, 0, 0, 0, rwidth[k], rheight[k]);
1265 }
1266 if (pfishB[k][2]) {
1267 XPutImage(Dpy, pfishB[k][2], gc, xfishB[k][2], 0, 0, 0, 0, rwidth[k], rheight[k]);
1268 }
1269
1270 cnt += rcolors[k];
1271 }
1272
1273 for (i = 1; i <= 8; i++) {
1274 xbubbles[i] = XCreateBitmapFromData(Dpy, wid, (char *) xbBits[i], i, i);
1275 }
1276 }
1277
1278
1279 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1280 Toggle secure mode on receipt of signal
1281 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1282 #ifdef sgi
1283 int
1284 #else
1285 void
1286 #endif
1287 toggle_secure()
1288 {
1289 pmode = !pmode;
1290 if (pmode)
1291 XLowerWindow(Dpy, wid);
1292 else
1293 XRaiseWindow(Dpy, wid);
1294 XFlush(Dpy);
1295 #ifdef sgi
1296 return (1);
1297 #endif
1298 }
1299
1300
1301 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1302 Initialize signal so that SIGUSR1 causes secure mode to toggle.
1303 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1304 void
1305 init_signals()
1306 {
1307 int ret;
1308 #ifdef linux
1309 signal(SIGUSR1, toggle_secure);
1310 #else
1311 #if defined(MOTOROLA) || defined(SCO)
1312 sigset(SIGUSR1, toggle_secure);
1313 #else
1314 struct sigvec vec;
1315
1316 vec.sv_handler = toggle_secure;
1317 vec.sv_mask = 0;
1318 vec.sv_onstack = 0;
1319
1320 #ifndef hpux
1321 ret = sigvec(SIGUSR1, &vec, &vec);
1322 #if 0
1323 if (ret != 0) {
1324 fprintf(stderr, "sigvec call failed\n");
1325 } else {
1326 fprintf(stderr, "sigvec call OK\n");
1327 }
1328 #endif
1329 #else
1330 sigvector(SIGUSR1, &vec, &vec);
1331 #endif
1332 #endif /* MOTOROLA */
1333 #endif /* LINUX */
1334 }
1335
1336
1337 set_window_type_desktop(Display *dpy, Window wid)
1338 {
1339 Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DESKTOP;
1340
1341 _NET_WM_WINDOW_TYPE = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
1342 _NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
1343
1344 XChangeProperty(dpy, wid, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1345 PropModeReplace, (unsigned char *) &_NET_WM_WINDOW_TYPE_DESKTOP, 1);
1346 }
1347
1348
1349 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1350 Variety of initialization calls, including getting the window up and running.
1351 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1352 void
1353 initialize()
1354 {
1355 XWindowAttributes winfo;
1356 XSetWindowAttributes attr;
1357 XGCValues vals;
1358 XSizeHints xsh;
1359 XImage *pimage;
1360 int i, size, cnt;
1361 char *p;
1362 unsigned char *ndata;
1363 unsigned char *ptr1, *ptr2;
1364
1365 root_window = VirtualRootWindowOfScreen(DefaultScreenOfDisplay(Dpy));
1366
1367 XGetWindowAttributes(Dpy, root_window, &winfo);
1368 width = winfo.width;
1369 height = winfo.height;
1370
1371 picname[0] = '\0';
1372 if ((p = XGetDefault(Dpy, pname, "BubbleLimit")) != NULL)
1373 blimit = atoi(p);
1374 if ((p = XGetDefault(Dpy, pname, "ColorLimit")) != NULL)
1375 climit = atoi(p);
1376 if ((p = XGetDefault(Dpy, pname, "MedianCutLimit")) != NULL)
1377 mlimit = atoi(p);
1378 if ((p = XGetDefault(Dpy, pname, "DoClipping")) != NULL)
1379 DoClipping = atoi(p);
1380 if ((p = XGetDefault(Dpy, pname, "DoubleBuffer")) != NULL)
1381 DoubleBuf = atoi(p);
1382 if ((p = XGetDefault(Dpy, pname, "Overlap")) != NULL)
1383 Overlap = atoi(p);
1384 if ((p = XGetDefault(Dpy, pname, "Color")) != NULL)
1385 strcpy(cname, p);
1386 if ((p = XGetDefault(Dpy, pname, "Picture")) != NULL)
1387 strcpy(picname, p);
1388 if ((p = XGetDefault(Dpy, pname, "FishLimit")) != NULL)
1389 flimit = atoi(p);
1390 if ((p = XGetDefault(Dpy, pname, "IncMult")) != NULL)
1391 smooth = atof(p);
1392 if ((p = XGetDefault(Dpy, pname, "Rate")) != NULL)
1393 rate = atof(p);
1394 if ((p = XGetDefault(Dpy, pname, "Secure")) != NULL)
1395 for (i = 0; i < 6; i++)
1396 if (strcmp(p, yess[i]) == 0)
1397 pmode = 0;
1398
1399 /*
1400 * DoubleBuf is only useful if we are doing clipping on our
1401 * own background picture, otherwise turn it off.
1402 */
1403 if ((DoubleBuf) && ((!DoClipping) || (picname[0] == '\0'))) {
1404 DoubleBuf = 0;
1405 }
1406
1407 init_colormap();
1408
1409 if (picname[0] != '\0') {
1410 size = Pwidth * Pheight;
1411 ndata = (unsigned char *) malloc(size);
1412 ptr1 = Pdata;
1413 ptr2 = ndata;
1414 cnt = 1;
1415 for (i = 0; i < size; i++) {
1416 *ptr2 = cmap[cnt + (int) (*ptr1)];
1417 ptr1++;
1418 ptr2++;
1419 }
1420 pimage = MakeImage(ndata, Pwidth, Pheight);
1421 free((char *) ndata);
1422 i = DisplayPlanes(Dpy, screen);
1423 PicMap = XCreatePixmap(Dpy, root_window, Pwidth, Pheight, i);
1424 }
1425
1426 if ((DoubleBuf) || (picname[0] != '\0')) {
1427 i = DisplayPlanes(Dpy, screen);
1428 PixBuf = XCreatePixmap(Dpy, root_window, 500, 500, i);
1429 ClipBuf = XCreatePixmap(Dpy, root_window, 500, 500, 1);
1430 c0gc = XCreateGC(Dpy, ClipBuf, 0, NULL);
1431 XSetForeground(Dpy, c0gc, (unsigned long) 0);
1432 XSetFunction(Dpy, c0gc, GXcopy);
1433 cpgc = XCreateGC(Dpy, ClipBuf, 0, NULL);
1434 XSetFunction(Dpy, cpgc, GXor);
1435 }
1436
1437 attr.override_redirect = True;
1438 attr.background_pixel = cmap[0];
1439
1440 if (!DoClipping || picname[0] != '\0') {
1441 wid = XCreateWindow(Dpy, root_window,
1442 1, 1, width - 2, height - 2, 0,
1443 CopyFromParent, CopyFromParent, CopyFromParent,
1444 CWBackPixel | CWOverrideRedirect, &attr);
1445
1446 if (!wid)
1447 msgdie("XCreateWindow failed");
1448 set_window_type_desktop(Dpy, wid);
1449 } else {
1450 wid = root_window;
1451 XClearArea(Dpy, wid, 0, 0, 0, 0, False);
1452 }
1453
1454 vals.foreground = vals.background = cmap[0];
1455 vals.graphics_exposures = False;
1456 gc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals);
1457 pgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals);
1458 bgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals);
1459
1460 for (i = 0; i < NUM_FISH; i++) {
1461 pfishA[i][0] = 0;
1462 pfishA[i][1] = 0;
1463 pfishA[i][2] = 0;
1464 pfishB[i][0] = 0;
1465 pfishB[i][1] = 0;
1466 pfishB[i][2] = 0;
1467
1468 mfishA[i][0] = 0;
1469 mfishA[i][1] = 0;
1470 mfishA[i][2] = 0;
1471 mfishB[i][0] = 0;
1472 mfishB[i][1] = 0;
1473 mfishB[i][2] = 0;
1474 }
1475
1476 init_pixmap();
1477 init_signals();
1478
1479 if (!DoClipping || picname[0] != '\0') {
1480 XStoreName(Dpy, wid, pname);
1481
1482 xsh.flags = USSize | USPosition | PPosition | PSize;
1483 xsh.x = xsh.y = 0;
1484 xsh.width = width;
1485 xsh.height = height;
1486 XSetNormalHints(Dpy, wid, &xsh);
1487
1488 if (picname[0] != '\0') {
1489 XPutImage(Dpy, PicMap, gc, pimage, 0, 0, 0, 0, Pwidth, Pheight);
1490 XSetWindowBackgroundPixmap(Dpy, wid, PicMap);
1491 }
1492
1493 XMapWindow(Dpy, wid);
1494 }
1495
1496 binfo = (bubble *) malloc(blimit * sizeof(bubble));
1497 finfo = (fish *) malloc(flimit * sizeof(fish));
1498 }
1499
1500
1501 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1502 Create a new bubble. Placement along the x axis is random, as is the size of
1503 the bubble. Increment value is determined by speed.
1504 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1505 void
1506 new_bubble(b0)
1507 bubble *b0;
1508 {
1509 register int s;
1510 register bubble *b = b0;
1511
1512 b->x = width * (rand() / RAND_F_MAX);
1513 if (Init_B)
1514 b->y = (height / 16) * (rand() / RAND_I_1_16 + 1) - 1;
1515 else
1516 b->y = height - 1;
1517 b->s = s = 1.0 + rand() / RAND_F_1_8;
1518 if ((b->i = smooth * height / (float) binc[s]) == 0)
1519 b->i = 1;
1520 b->erased = 0;
1521 putbubble(b, s, bcolor);
1522 }
1523
1524 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1525 Erase old bubbles, move and draw new bubbles. Random left-right factor
1526 can move bubble one size-unit in either direction.
1527 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1528 void
1529 step_bubbles()
1530 {
1531 register int i, j, s;
1532 register bubble *b;
1533
1534 for (i = 0; i < blimit; i++) {
1535 b = &binfo[i];
1536 s = b->s;
1537 /* clear */
1538 if ((b->y > 0) && (b->erased == 0)) {
1539 if ((DoClipping) || (picname[0] != '\0')) {
1540 erasebubble(b, s);
1541 } else {
1542 putbubble(b, s, cmap[0]);
1543 }
1544 }
1545 if ((b->y -= b->i) > 0) {
1546 j = rand();
1547 if (j < RAND_I_1_4) {
1548 b->x -= s;
1549 } else if (j > RAND_I_3_4) {
1550 b->x += s;
1551 }
1552 putbubble(b, s, bcolor);
1553 } else {
1554 if (rand() < RAND_I_1_4) {
1555 new_bubble(b);
1556 }
1557 }
1558 b->erased = 0;
1559 }
1560 }
1561
1562
1563 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1564 Fish over bubble collision detection. The specified fish is checked against
1565 all bubbles for overlap. This way we don't try and erase bubbles that are
1566 already gone.
1567 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1568 void
1569 collide_bubbles(f0, ofx, ofy)
1570 fish *f0;
1571 int ofx, ofy;
1572 {
1573 int i, delta;
1574 register fish *f = f0;
1575 register bubble *b;
1576
1577 for (i = 0; i < blimit; i++) {
1578 b = &binfo[i];
1579 delta = b->x - ofx;
1580 if ((delta >= 0) && (delta <= (rwidth[f->type] - b->s))) {
1581 delta = b->y - ofy;
1582 if ((delta >= 0) && (delta <= (rheight[f->type] - b->s))) {
1583 b->erased = 1;
1584 continue;
1585 }
1586 }
1587 delta = b->x - f->x;
1588 if ((delta >= 0) && (delta <= (rwidth[f->type] - b->s))) {
1589 delta = b->y - f->y;
1590 if ((delta >= 0) && (delta <= (rheight[f->type] - b->s))) {
1591 b->erased = 1;
1592 continue;
1593 }
1594 }
1595 }
1596 }
1597
1598 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1599 Fish collision detection. The specified fish is checked against all other
1600 fish for overlap. The xt parameter specifies a x axis multiplier for overlap.
1601 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1602 int
1603 collide_fish(f0, xt)
1604 fish *f0;
1605 int xt;
1606 {
1607 int i, j;
1608 register fish *f = f0;
1609
1610 if (Overlap) {
1611 return (0);
1612 }
1613
1614 for (i = 0; i < flimit; i++) {
1615 if (&finfo[i] != f) {
1616 j = finfo[i].y - f->y;
1617 if ((j > -rheight[finfo[i].type]) && (j < rheight[f->type])) {
1618 j = finfo[i].x - f->x;
1619 if ((j > -xt * rwidth[finfo[i].type]) && (j < xt * rwidth[f->type])) {
1620 return (1);
1621 }
1622 }
1623 }
1624 }
1625 return (0);
1626 }
1627
1628
1629 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1630 Create a new fish. Placement along the y axis is random, as is the side
1631 >from which the fish appears. Direction is determined from side. Increment
1632 is also random.
1633 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1634 void
1635 new_fish(f0)
1636 fish *f0;
1637 {
1638 int i, collide;
1639 fish *f = f0;
1640
1641 f->type = rand() % NUM_FISH;
1642 for (i = 0, collide = 1; (i < 16) && (collide); i++) {
1643 f->y = (height - rheight[f->type]) * (rand() / RAND_F_MAX);
1644 if ((f->i = smooth * width / (8.0 * (1.0 + rand() / RAND_F_1_8))) == 0) {
1645 f->i = 1;
1646 }
1647 if (rand() < RAND_I_1_2) {
1648 f->d = 1;
1649 f->x = width;
1650 } else {
1651 f->d = 2;
1652 f->x = -rwidth[f->type];
1653 }
1654 collide = collide_fish(f, 2);
1655 }
1656
1657 if (!collide) {
1658 putfish(f);
1659 } else {
1660 f->d = 0;
1661 }
1662
1663 f->frame = 0;
1664 }
1665
1666
1667 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1668 Move all the fish. Clearing old fish is accomplished by masking only the
1669 exposed areas of the old fish. Random up-down factor can move fish 1/4 a
1670 fish height in either direction, if no collisions are caused.
1671 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1672 void
1673 move_fish()
1674 {
1675 register int i, j, x, y, ofx, ofy, ofd, done;
1676 register fish *f;
1677
1678 for (i = 0; i < flimit; i++) {
1679 f = &finfo[i];
1680 if (f->d) {
1681 ofx = f->x;
1682 ofy = f->y;
1683 ofd = f->d;
1684
1685 if (f->d == 1) {
1686 done = ((f->x -= f->i) < -rwidth[f->type]);
1687 x = f->x + rwidth[f->type];
1688 } else if (f->d == 2) {
1689 done = ((f->x += f->i) > width);
1690 x = f->x - f->i;
1691 }
1692
1693 if (!collide_fish(f, 1)) {
1694 if (!done) {
1695 j = rand();
1696 if (j < RAND_I_1_4) {
1697 y = f->i / 4;
1698 } else if (j > RAND_I_3_4) {
1699 y = f->i / -4;
1700 } else {
1701 y = 0;
1702 }
1703
1704 if (y) {
1705 f->y += y;
1706 if (collide_fish(f, 1)) {
1707 f->y -= y;
1708 y = 0;
1709 } else {
1710 if (y > 0) {
1711 j = f->y - y;
1712 } else {
1713 j = f->y + rheight[f->type];
1714 y *= -1;
1715 }
1716 }
1717 }
1718 if (DoClipping) {
1719 movefish(f, ofx, ofy, ofd);
1720 } else {
1721 putfish(f);
1722 XClearArea(Dpy, wid, x, ofy, f->i, rheight[f->type], 0);
1723 if (y) {
1724 XClearArea(Dpy, wid, ofx, j, rwidth[f->type], y, 0);
1725 }
1726 }
1727
1728 } else {
1729 XClearArea(Dpy, wid, x, f->y, f->i, rheight[f->type], 0);
1730 new_fish(f);
1731 }
1732 } else {
1733 if ((f->d = 3 - f->d) == 1) {
1734 f->x = f->x - 2 * f->i;
1735 x = f->x + rwidth[f->type];
1736 } else {
1737 f->x = f->x + 2 * f->i;
1738 x = f->x - f->i;
1739 }
1740 if (DoClipping) {
1741 movefish(f, ofx, ofy, ofd);
1742 } else {
1743 putfish(f);
1744 XClearArea(Dpy, wid, x, f->y, f->i, rheight[f->type], 0);
1745 }
1746 }
1747 if ((!DoClipping) || (picname[0] == '\0')) {
1748 collide_bubbles(f, ofx, ofy);
1749 }
1750 } else {
1751 new_fish(f);
1752 }
1753 }
1754 }
1755
1756
1757 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1758 Higher-resolution sleep
1759 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1760 void
1761 high_res_sleep(seconds)
1762 double seconds;
1763 {
1764 struct timeval timeout;
1765
1766 timeout.tv_sec = seconds;
1767 timeout.tv_usec = (seconds - timeout.tv_sec) * 1000000.0;
1768 select(0, NULL, NULL, NULL, &timeout);
1769 }
1770
1771
1772 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1773 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1774 int
1775 main(argc, argv)
1776 int argc;
1777 char **argv;
1778 {
1779 int i;
1780 XEvent ev;
1781
1782 parse(argc, argv);
1783 if ((Dpy = XOpenDisplay(sname)) == 0)
1784 msgdie("XOpenDisplay failed");
1785 screen = DefaultScreen(Dpy);
1786
1787 white = WhitePixel(Dpy, screen);
1788 black = BlackPixel(Dpy, screen);
1789 initialize();
1790
1791 srand((unsigned) getpid());
1792
1793 Init_B = 1;
1794 for (i = 0; i < blimit; i++)
1795 new_bubble(&binfo[i]);
1796 for (i = 0; i < flimit; i++) {
1797 finfo[i].x = 0;
1798 finfo[i].y = 0;
1799 finfo[i].type = 0;
1800 }
1801 for (i = 0; i < flimit; i++)
1802 new_fish(&finfo[i]);
1803 if (pmode)
1804 XLowerWindow(Dpy, wid);
1805 else
1806 XRaiseWindow(Dpy, wid);
1807 XFlush(Dpy);
1808
1809 Init_B = 0;
1810
1811 for (;;) {
1812 if (XPending(Dpy))
1813 XNextEvent(Dpy, &ev);
1814
1815 high_res_sleep(rate);
1816
1817 move_fish();
1818
1819 step_bubbles();
1820
1821 if (pmode)
1822 XLowerWindow(Dpy, wid);
1823 else
1824 XRaiseWindow(Dpy, wid);
1825 }
1826
1827 return 0;
1828 }
This page took 0.079311 seconds and 4 git commands to generate.