4 * Original Author Unknow.
6 * 8/10/88 - Ported from X10 to X11R3 by:
8 Jonathan Greenblatt (jonnyg@rover.umd.edu)
10 * Cleaned up by Dave Lemke (lemke@sun.com)
12 * Ported to monocrome by Jonathan Greenblatt (jonnyg@rover.umd.edu)
14 * 05/02/1996 Added TrueColor support by TJ Phan (phan@aur.alcatel.com)
18 Parameter parsing needs to be redone.
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)
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)
30 #include <sys/types.h>
46 #include <X11/Xutil.h>
54 /* constants are based on rand(3C) returning an integer between 0 and 32767 */
56 #if defined(ultrix) || defined(sun) || defined(linux)
57 #define RAND_I_1_16 134217728
58 #define RAND_F_1_8 268435455.875
59 #define RAND_I_1_4 536870911
60 #define RAND_I_1_2 1073741823
61 #define RAND_I_3_4 1610612735
62 #define RAND_F_MAX 2147483647.0
63 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
64 #define RAND_I_1_16 (RAND_MAX>>4)
65 #define RAND_F_1_8 ((float)(RAND_MAX>>3))
66 #define RAND_I_1_4 (RAND_MAX>>2)
67 #define RAND_I_1_2 (RAND_MAX>>1)
68 #define RAND_I_3_4 ((RAND_MAX>>2)*3)
69 #define RAND_F_MAX ((float)RAND_MAX)
71 #define RAND_I_1_16 2048
72 #define RAND_F_1_8 4096.0
73 #define RAND_I_1_4 8096
74 #define RAND_I_1_2 16384
75 #define RAND_I_3_4 24575
76 #define RAND_F_MAX 32767.0
80 extern unsigned char *ReadBitmap();
83 /* externals for pixmap and bimaps from xfishy.h */
86 /* typedefs for bubble and fish structures, also caddr_t (not used in X.h) */
88 int x
, y
, s
, erased
, i
;
91 int x
, y
, d
, frame
, type
, i
;
93 typedef unsigned char *caddrt
;
96 /* bubble increment and yes check tables */
97 int binc
[] = { 0, 64, 56, 48, 40, 32, 24, 16, 8 };
98 char *yess
[] = { "yes", "Yes", "YES", "on", "On", "ON" };
101 char *pname
, /* program name from argv[0] */
102 sname
[64], /* host:display specification */
103 cname
[64]; /* colorname specification */
104 char picname
[256]; /* name of the background picture file */
105 int *Allocated
; /* mark the used colors */
106 int AllocCnt
; /* count number of colors used */
107 int mlimit
= 0; /* num colors to median cut to. 0 = no limit */
108 int climit
= 0; /* limit on color use. 0 = no limit */
109 int DoubleBuf
= 0; /* Should we use double buffering */
110 int Overlap
= 0; /* Should fish swim over each other */
111 int DoClipping
= 0; /* Should clip masks be used. */
112 int blimit
= 32, /* bubble limit */
113 flimit
= 10, /* fish limit */
114 pmode
= 1, /* pop mode, (1 for lower, 0 for raise) */
115 width
, /* width of initial window in pixels */
116 height
, /* height of initial window in pixels */
117 screen
, /* Default screen of this display */
118 Init_B
, *cmap
; /* Initialize bubbles with random y value */
119 int Pwidth
; /* width of background picture */
120 int Pheight
; /* height of background picture */
121 int Pcnt
; /* number of colors in background picture */
122 unsigned char *Pdata
; /* data from background picture */
123 double rate
= 0.2, /* update interval in seconds */
124 smooth
= 0.2; /* smoothness increment multiplier */
125 bubble
*binfo
; /* bubble info structures, allocated
127 fish
*finfo
; /* fish info structures, allocated dynamically */
130 XImage
*xfishA
[NUM_FISH
][3]; /* fish pixmaps (1 is left-fish, 2 is
132 XImage
*xfishB
[NUM_FISH
][3]; /* fish pixmaps (1 is left-fish, 2 is
134 Pixmap pfishA
[NUM_FISH
][3];
135 Pixmap pfishB
[NUM_FISH
][3];
137 Pixmap mfishA
[NUM_FISH
][3]; /* masking pixmaps for fish to use as */
138 Pixmap mfishB
[NUM_FISH
][3]; /* clipmasks */
140 Pixmap PicMap
; /* pixmap for background picture */
142 Pixmap PixBuf
; /* Pixmap buffer for double buffering */
143 Pixmap ClipBuf
; /* Clipmask buffer for double buffering */
145 Pixmap xbubbles
[9]; /* bubbles bitmaps (1 to 8, by size in pixels) */
146 Window wid
; /* aqaurium window */
147 unsigned long white
, black
, bcolor
;
149 GC c0gc
, cpgc
; /* GCs to operateon the Clipmask buffer */
154 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
155 Output desired error message and exit.
156 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
161 fprintf(stderr
, "%s: %s\n", pname
, message
);
166 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
167 Set up program defaults, get X defaults, parse command line using getopts.
168 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
175 const char *display
= getenv("DISPLAY");
178 extern double atof();
182 strncpy(sname
, display
, sizeof(sname
) - 1);
183 strcpy(cname
, "MediumAquamarine");
185 while ((c
= getopt(argc
, argv
, "dDob:C:c:p:m:f:i:r:s")) != EOF
) {
197 blimit
= atoi(optarg
);
200 climit
= atoi(optarg
);
203 mlimit
= atoi(optarg
);
206 strncpy(cname
, optarg
, sizeof(cname
) - 1);
209 strncpy(picname
, optarg
, sizeof(picname
) - 1);
212 flimit
= atoi(optarg
);
215 smooth
= atof(optarg
);
224 fprintf(stderr
, "usage: %s\n", pname
);
225 fprintf(stderr
, "\t\t[-c color] background color\n");
226 fprintf(stderr
, "\t\t[-b limit] number of bubbles (default 32)\n");
227 fprintf(stderr
, "\t\t[-f limit] number of fish (default 10)\n");
228 fprintf(stderr
, "\t\t[-i mult] move interval (default 0.2)\n");
229 fprintf(stderr
, "\t\t[-r rate] move frequency (default 0.2)\n");
230 fprintf(stderr
, "\t\t[-m num] median cut to this many colors\n");
231 fprintf(stderr
, "\t\t[-C num] use only this many color cells\n");
232 fprintf(stderr
, "\t\t[-d] clip fish, swim on root window\n");
233 fprintf(stderr
, "\t\t[-p file] fish swim on picture in file\n");
234 fprintf(stderr
, "\t\t[host:display]\n");
242 strncpy(sname
, argv
[optind
], sizeof(sname
) - 1);
243 display
= (char *) malloc(strlen(sname
) + 9);
244 snprintf(display
, sizeof(display
) - 1, "DISPLAY=%s", sname
);
251 erasefish(f
, x
, y
, d
)
256 * for something as small as a bubble, it was never worth the
257 * effort of using clipmasks to only turn of the bubble itself, so
258 * we just clear the whole rectangle.
260 XClearArea(Dpy
, wid
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
], False
);
265 gcv
.foreground
= cmap
[0];
266 gcv
.fill_style
= FillTiled
;
267 gcv
.fill_style
= FillSolid
;
268 gcv
.tile
= pfishB
[f
->type
][d
];
269 gcv
.ts_x_origin
= f
->x
;
270 gcv
.ts_y_origin
= f
->y
;
271 gcv
.clip_mask
= mfishB
[f
->type
][d
];
272 gcv
.clip_x_origin
= x
;
273 gcv
.clip_y_origin
= y
;
274 XChangeGC(Dpy
, gc
, GCForeground
| GCClipMask
|
275 GCTile
| GCTileStipXOrigin
| GCTileStipYOrigin
|
276 GCFillStyle
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
277 XCopyPlane(Dpy
, mfishB
[f
->type
][d
], wid
, gc
, 0, 0,
278 rwidth
[f
->type
], rheight
[f
->type
], x
, y
, (unsigned long) 1);
280 gcv
.foreground
= cmap
[0];
281 gcv
.fill_style
= FillTiled
;
282 gcv
.fill_style
= FillSolid
;
283 gcv
.tile
= pfishA
[f
->type
][d
];
284 gcv
.ts_x_origin
= f
->x
;
285 gcv
.ts_y_origin
= f
->y
;
286 gcv
.clip_mask
= mfishA
[f
->type
][d
];
287 gcv
.clip_x_origin
= x
;
288 gcv
.clip_y_origin
= y
;
289 XChangeGC(Dpy
, gc
, GCForeground
| GCClipMask
|
290 GCTile
| GCTileStipXOrigin
| GCTileStipYOrigin
|
291 GCFillStyle
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
292 XCopyPlane(Dpy
, mfishA
[f
->type
][d
], wid
, gc
, 0, 0,
293 rwidth
[f
->type
], rheight
[f
->type
], x
, y
, (unsigned long) 1);
300 * Just places a fish. Normally this is all you need for animation, since
301 * placeing the fish places an entire rectangle which erases most of the old
302 * fish (the rest being cleaned up by the function that called putfish.
303 * If DoClipping is set, this function is only called when placing a new
304 * fish, otherwise newfish is called.
314 * If we have a pixmap of the fish use it, otherwise use
315 * the XImage of the fish. In reality we will never use
316 * the XImage since X dies if the pixmap create failed
318 if (pfishA
[f
->type
][f
->d
]) {
320 * Clipping overrides background picture because
321 * the clipping prevents the drawing of any background
323 * DoClipping says just print a fish leaving the
324 * background unchanged.
325 * If there is a background picture, we use a buffer
326 * to prevent flashing, we combine the background
327 * picture and the fish, and then copy the
328 * whole rectangle in.
329 * Default is just copy in fish in with a background
333 gcv
.clip_mask
= mfishA
[f
->type
][f
->d
];
334 gcv
.clip_x_origin
= f
->x
;
335 gcv
.clip_y_origin
= f
->y
;
336 XChangeGC(Dpy
, gc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
337 XCopyArea(Dpy
, pfishA
[f
->type
][f
->d
], wid
, gc
,
338 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
339 } else if (picname
[0] != '\0') {
340 gcv
.fill_style
= FillTiled
;
342 gcv
.ts_x_origin
= -(f
->x
);
343 gcv
.ts_y_origin
= -(f
->y
);
344 gcv
.clip_mask
= None
;
345 XChangeGC(Dpy
, pgc
, (GCFillStyle
|
346 GCTile
| GCTileStipXOrigin
|
347 GCTileStipYOrigin
| GCClipMask
), &gcv
);
348 XFillRectangle(Dpy
, PixBuf
, pgc
, 0, 0, rwidth
[f
->type
], rheight
[f
->type
]);
350 gcv
.clip_mask
= mfishA
[f
->type
][f
->d
];
351 gcv
.clip_x_origin
= 0;
352 gcv
.clip_y_origin
= 0;
353 XChangeGC(Dpy
, pgc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
354 XCopyArea(Dpy
, pfishA
[f
->type
][f
->d
], PixBuf
, pgc
,
355 0, 0, rwidth
[f
->type
], rheight
[f
->type
], 0, 0);
357 XCopyArea(Dpy
, PixBuf
, wid
, gc
,
358 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
360 XCopyArea(Dpy
, pfishA
[f
->type
][f
->d
], wid
, gc
,
361 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
364 XPutImage(Dpy
, wid
, gc
, xfishA
[f
->type
][f
->d
], 0, 0,
365 f
->x
, f
->y
, rwidth
[f
->type
], rheight
[f
->type
]);
370 * same as the above, only for the second frame of animation
372 if (pfishB
[f
->type
][f
->d
]) {
374 gcv
.clip_mask
= mfishB
[f
->type
][f
->d
];
375 gcv
.clip_x_origin
= f
->x
;
376 gcv
.clip_y_origin
= f
->y
;
377 XChangeGC(Dpy
, gc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
378 XCopyArea(Dpy
, pfishB
[f
->type
][f
->d
], wid
, gc
,
379 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
380 } else if (picname
[0] != '\0') {
381 gcv
.fill_style
= FillTiled
;
383 gcv
.ts_x_origin
= -(f
->x
);
384 gcv
.ts_y_origin
= -(f
->y
);
385 gcv
.clip_mask
= None
;
386 XChangeGC(Dpy
, pgc
, (GCFillStyle
|
387 GCTile
| GCTileStipXOrigin
|
388 GCTileStipYOrigin
| GCClipMask
), &gcv
);
389 XFillRectangle(Dpy
, PixBuf
, pgc
, 0, 0, rwidth
[f
->type
], rheight
[f
->type
]);
391 gcv
.clip_mask
= mfishB
[f
->type
][f
->d
];
392 gcv
.clip_x_origin
= 0;
393 gcv
.clip_y_origin
= 0;
394 XChangeGC(Dpy
, pgc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
395 XCopyArea(Dpy
, pfishB
[f
->type
][f
->d
], PixBuf
, pgc
,
396 0, 0, rwidth
[f
->type
], rheight
[f
->type
], 0, 0);
398 XCopyArea(Dpy
, PixBuf
, wid
, gc
,
399 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
401 XCopyArea(Dpy
, pfishB
[f
->type
][f
->d
], wid
, gc
,
402 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
405 XPutImage(Dpy
, wid
, gc
, xfishB
[f
->type
][f
->d
], 0, 0,
406 f
->x
, f
->y
, rwidth
[f
->type
], rheight
[f
->type
]);
414 * This function can only be called if DoClipping is True. It is used to
415 * move a clipmasked fish. First the area under the fish is cleared,
416 * and then the new fish is masked in.
417 * The parameters x, y, amd d are from the old fish that is being
418 * erased before the new fish is drawn.
429 * If we are going to double buffer, we need to find the bounding
430 * rectangle of the overlap of the bounding rectangles of the old
436 bw
= f
->x
- x
+ rwidth
[f
->type
];
439 bw
= x
- f
->x
+ rwidth
[f
->type
];
443 bh
= f
->y
- y
+ rheight
[f
->type
];
446 bh
= y
- f
->y
+ rheight
[f
->type
];
452 * If there is a pixmap use it.
453 * This branchis always taken since right now, if the pixmap
454 * allocation failed, the program dies.
456 if (pfishA
[f
->type
][f
->d
]) {
458 * A pointless if, you now only come here if
459 * DoClipping is set, I've just been too lazy to
464 * Set up the masked gc for when we eventually
465 * draw the fish. Origin is different for
466 * whether we are drawing into the buffer
469 gcv
.clip_mask
= mfishA
[f
->type
][f
->d
];
471 gcv
.clip_x_origin
= f
->x
- bx
;
472 gcv
.clip_y_origin
= f
->y
- by
;
474 gcv
.clip_x_origin
= f
->x
;
475 gcv
.clip_y_origin
= f
->y
;
477 XChangeGC(Dpy
, gc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
480 * If we have a background picture we want to
481 * clear to that background, otherwise we just
482 * do an XCleararea, and let the root restore
485 if (picname
[0] != '\0') {
486 gcv
.fill_style
= FillTiled
;
488 gcv
.clip_mask
= mfishB
[f
->type
][d
];
490 gcv
.ts_x_origin
= 0 - bx
;
491 gcv
.ts_y_origin
= 0 - by
;
492 gcv
.clip_x_origin
= x
- bx
;
493 gcv
.clip_y_origin
= y
- by
;
497 gcv
.clip_x_origin
= x
;
498 gcv
.clip_y_origin
= y
;
500 XChangeGC(Dpy
, pgc
, (GCFillStyle
|
501 GCTile
| GCTileStipXOrigin
|
502 GCTileStipYOrigin
| GCClipMask
|
503 GCClipXOrigin
| GCClipYOrigin
), &gcv
);
506 * if bouble buffering we clear the buffer
507 * to the backgound picture, and then
508 * shape the clip buffer to the shape of
509 * the fish being erased.
512 XFillRectangle(Dpy
, PixBuf
, pgc
,
513 x
- bx
, y
- by
, rwidth
[f
->type
], rheight
[f
->type
]);
514 XFillRectangle(Dpy
, ClipBuf
, c0gc
, 0, 0, 500, 500);
515 XCopyArea(Dpy
, mfishB
[f
->type
][d
],
517 rwidth
[f
->type
], rheight
[f
->type
], x
- bx
, y
- by
);
519 XFillRectangle(Dpy
, wid
, pgc
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
]);
522 XClearArea(Dpy
, wid
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
], 0);
526 * Now we just copy in the new fish with a clipmasked gc.
527 * But if we doublebuffered, we copy the new fish into
528 * the buffer, combine the new fishes clipmask in, and
529 * then mask the whole lot from the buffer to the window.
532 XCopyArea(Dpy
, pfishA
[f
->type
][f
->d
], PixBuf
, gc
, 0, 0,
533 rwidth
[f
->type
], rheight
[f
->type
], f
->x
- bx
, f
->y
- by
);
534 XCopyArea(Dpy
, mfishA
[f
->type
][f
->d
], ClipBuf
, cpgc
,
535 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
- bx
, f
->y
- by
);
536 gcv
.clip_mask
= ClipBuf
;
537 gcv
.clip_x_origin
= bx
;
538 gcv
.clip_y_origin
= by
;
539 XChangeGC(Dpy
, gc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
540 XCopyArea(Dpy
, PixBuf
, wid
, gc
, 0, 0, bw
, bh
, bx
, by
);
542 XCopyArea(Dpy
, pfishA
[f
->type
][f
->d
], wid
, gc
, 0, 0,
543 rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
547 if (picname
[0] != '\0') {
548 gcv
.fill_style
= FillTiled
;
552 gcv
.clip_mask
= mfishB
[f
->type
][d
];
553 gcv
.clip_x_origin
= x
;
554 gcv
.clip_y_origin
= y
;
555 XChangeGC(Dpy
, pgc
, (GCFillStyle
|
556 GCTile
| GCTileStipXOrigin
|
557 GCTileStipYOrigin
| GCClipMask
|
558 GCClipXOrigin
| GCClipYOrigin
), &gcv
);
559 XFillRectangle(Dpy
, wid
, pgc
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
]);
561 XClearArea(Dpy
, wid
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
], 0);
564 XPutImage(Dpy
, wid
, gc
, xfishA
[f
->type
][f
->d
], 0, 0,
565 f
->x
, f
->y
, rwidth
[f
->type
], rheight
[f
->type
]);
570 * Same as above, only for the second frame of animation.
572 if (pfishB
[f
->type
][f
->d
]) {
574 gcv
.clip_mask
= mfishB
[f
->type
][f
->d
];
576 gcv
.clip_x_origin
= f
->x
- bx
;
577 gcv
.clip_y_origin
= f
->y
- by
;
579 gcv
.clip_x_origin
= f
->x
;
580 gcv
.clip_y_origin
= f
->y
;
582 XChangeGC(Dpy
, gc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
583 if (picname
[0] != '\0') {
584 gcv
.fill_style
= FillTiled
;
586 gcv
.clip_mask
= mfishA
[f
->type
][d
];
588 gcv
.ts_x_origin
= 0 - bx
;
589 gcv
.ts_y_origin
= 0 - by
;
590 gcv
.clip_x_origin
= x
- bx
;
591 gcv
.clip_y_origin
= y
- by
;
595 gcv
.clip_x_origin
= x
;
596 gcv
.clip_y_origin
= y
;
598 XChangeGC(Dpy
, pgc
, (GCFillStyle
|
599 GCTile
| GCTileStipXOrigin
|
600 GCTileStipYOrigin
| GCClipMask
|
601 GCClipXOrigin
| GCClipYOrigin
), &gcv
);
603 XFillRectangle(Dpy
, PixBuf
, pgc
,
604 x
- bx
, y
- by
, rwidth
[f
->type
], rheight
[f
->type
]);
605 XFillRectangle(Dpy
, ClipBuf
, c0gc
, 0, 0, 500, 500);
606 XCopyArea(Dpy
, mfishA
[f
->type
][d
],
608 rwidth
[f
->type
], rheight
[f
->type
], x
- bx
, y
- by
);
610 XFillRectangle(Dpy
, wid
, pgc
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
]);
613 XClearArea(Dpy
, wid
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
], 0);
617 XCopyArea(Dpy
, pfishB
[f
->type
][f
->d
], PixBuf
, gc
, 0, 0,
618 rwidth
[f
->type
], rheight
[f
->type
], f
->x
- bx
, f
->y
- by
);
619 XCopyArea(Dpy
, mfishB
[f
->type
][f
->d
], ClipBuf
, cpgc
,
620 0, 0, rwidth
[f
->type
], rheight
[f
->type
], f
->x
- bx
, f
->y
- by
);
621 gcv
.clip_mask
= ClipBuf
;
622 gcv
.clip_x_origin
= bx
;
623 gcv
.clip_y_origin
= by
;
624 XChangeGC(Dpy
, gc
, GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
625 XCopyArea(Dpy
, PixBuf
, wid
, gc
, 0, 0, bw
, bh
, bx
, by
);
627 XCopyArea(Dpy
, pfishB
[f
->type
][f
->d
], wid
, gc
, 0, 0,
628 rwidth
[f
->type
], rheight
[f
->type
], f
->x
, f
->y
);
632 if (picname
[0] != '\0') {
633 gcv
.fill_style
= FillTiled
;
637 gcv
.clip_mask
= mfishA
[f
->type
][d
];
638 gcv
.clip_x_origin
= x
;
639 gcv
.clip_y_origin
= y
;
640 XChangeGC(Dpy
, pgc
, (GCFillStyle
|
641 GCTile
| GCTileStipXOrigin
|
642 GCTileStipYOrigin
| GCClipMask
|
643 GCClipXOrigin
| GCClipYOrigin
), &gcv
);
644 XFillRectangle(Dpy
, wid
, pgc
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
]);
646 XClearArea(Dpy
, wid
, x
, y
, rwidth
[f
->type
], rheight
[f
->type
], 0);
649 XPutImage(Dpy
, wid
, gc
, xfishB
[f
->type
][f
->d
], 0, 0,
650 f
->x
, f
->y
, rwidth
[f
->type
], rheight
[f
->type
]);
662 XClearArea(Dpy
, wid
, b
->x
, b
->y
, s
, s
, 0);
675 gcv
.clip_mask
= xbubbles
[s
];
676 gcv
.clip_x_origin
= b
->x
;
677 gcv
.clip_y_origin
= b
->y
;
678 XChangeGC(Dpy
, bgc
, GCForeground
| GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
679 XFillRectangle(Dpy
, wid
, bgc
, b
->x
, b
->y
, s
, s
);
684 * Find the closest color by allocating it, or picking an already allocated
687 Visual(*visual_info
) = NULL
;
688 int r_mask
, g_mask
, b_mask
;
689 int r_shift
= 0, g_shift
= 0, b_shift
= 0;
690 int r_bits
= 0, g_bits
= 0, b_bits
= 0;
692 FindColor(Dpy
, colormap
, colr
)
698 double rd
, gd
, bd
, dist
, mindist
;
700 XColor def_colrs
[256];
703 if (visual_info
== NULL
&& DefaultDepth(Dpy
, DefaultScreen(Dpy
)) > 8) {
704 visual_info
= DefaultVisual(Dpy
, DefaultScreen(Dpy
));
705 r_mask
= visual_info
->red_mask
;
706 while (!(r_mask
& 1)) {
715 g_mask
= visual_info
->green_mask
;
716 while (!(g_mask
& 1)) {
725 b_mask
= visual_info
->blue_mask
;
726 while (!(b_mask
& 1)) {
736 if (DefaultDepth(Dpy
, DefaultScreen(Dpy
)) > 8) {
737 colr
->red
>>= 16 - r_bits
;
738 colr
->green
>>= 16 - g_bits
;
739 colr
->blue
>>= 16 - b_bits
;
741 colr
->pixel
= ((colr
->red
<< r_shift
) & visual_info
->red_mask
) |
742 ((colr
->green
<< g_shift
) & visual_info
->green_mask
) |
743 ((colr
->blue
<< b_shift
) & visual_info
->blue_mask
);
747 if (AllocCnt
< climit
) {
748 match
= XAllocColor(Dpy
, colormap
, colr
);
753 NumCells
= DisplayCells(Dpy
, DefaultScreen(Dpy
));
754 for (i
= 0; i
< NumCells
; i
++) {
755 def_colrs
[i
].pixel
= i
;
757 XQueryColors(Dpy
, colormap
, def_colrs
, NumCells
);
758 mindist
= 65536.0 * 65536.0;
760 for (i
= 0; i
< NumCells
; i
++) {
761 rd
= (def_colrs
[i
].red
- colr
->red
) / 256.0;
762 gd
= (def_colrs
[i
].green
- colr
->green
) / 256.0;
763 bd
= (def_colrs
[i
].blue
- colr
->blue
) / 256.0;
764 dist
= (rd
* rd
* rd
* rd
) + (gd
* gd
* gd
* gd
) + (bd
* bd
* bd
* bd
);
765 if (dist
< mindist
) {
767 cindx
= def_colrs
[i
].pixel
;
771 colr
->red
= def_colrs
[cindx
].red
;
772 colr
->green
= def_colrs
[cindx
].green
;
773 colr
->blue
= def_colrs
[cindx
].blue
;
775 if (Allocated
[colr
->pixel
] == 0) {
776 Allocated
[colr
->pixel
] = 1;
784 ColorUsage(data
, width
, height
, colrs
)
787 struct colr_data
*colrs
;
793 struct colr_data newcol
[256];
795 for (i
= 0; i
< 256; i
++) {
799 size
= width
* height
;
802 for (i
= 0; i
< size
; i
++) {
804 if (mapping
[indx
] == -1) {
806 newcol
[cnt
].red
= colrs
[indx
].red
;
807 newcol
[cnt
].green
= colrs
[indx
].green
;
808 newcol
[cnt
].blue
= colrs
[indx
].blue
;
815 for (i
= 0; i
< size
; i
++) {
817 *ptr
= (unsigned char) mapping
[indx
];
821 for (i
= 0; i
< cnt
; i
++) {
822 colrs
[i
].red
= newcol
[i
].red
;
823 colrs
[i
].green
= newcol
[i
].green
;
824 colrs
[i
].blue
= newcol
[i
].blue
;
826 for (i
= cnt
; i
< 256; i
++) {
836 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
837 Initialize colormap for background color and required fish colors.
838 The fish colors are coded in xfishy.h as a trio of tables.
839 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
846 struct colr_data
*cdp
;
847 struct colr_data colrs
[256];
849 colormap
= XDefaultColormap(Dpy
, screen
);
851 NumCells
= DisplayCells(Dpy
, DefaultScreen(Dpy
));
852 Allocated
= (int *) malloc(NumCells
* sizeof(int));
853 for (i
= 0; i
< NumCells
; i
++) {
857 if ((climit
<= 0) || (climit
> NumCells
)) {
862 if (picname
[0] != '\0') {
863 Imlib_Image image
= imlib_load_image(picname
);
865 fprintf(stderr
, "Cannot load image %s\n", picname
);
868 imlib_context_set_image(image
);
869 imlib_context_set_display(Dpy
);
870 imlib_context_set_visual(DefaultVisual(Dpy
, screen
));
871 Pwidth
= imlib_image_get_width();
872 Pheight
= imlib_image_get_height();
873 DATA32
*image_data
= imlib_image_get_data_for_reading_only();
874 Pdata
= malloc(4 * Pwidth
* Pheight
);
875 for (i
= 0; i
< Pwidth
* Pheight
; i
++) {
876 Pdata
[4 * i
] = image_data
[i
] & 0xFF;
877 Pdata
[4 * i
+ 1] = image_data
[i
] & 0xFF00;
878 Pdata
[4 * i
+ 2] = image_data
[i
] & 0xFF0000;
879 Pdata
[4 * i
+ 3] = image_data
[i
] & 0xFF000000;
881 Pcnt
= ColorUsage(Pdata
, Pwidth
, Pheight
, colrs
);
887 for (i
= 0; i
< NUM_FISH
; i
++) {
890 cmap
= (int *) malloc((cnt
+ 1) * sizeof(int));
892 XLookupColor(Dpy
, colormap
, cname
, &hdef
, &edef
);
893 hdef
.flags
= DoRed
| DoGreen
| DoBlue
;
894 FindColor(Dpy
, colormap
, &hdef
);
895 cmap
[0] = hdef
.pixel
;
902 if (picname
[0] != '\0') {
903 MedianCount(Pdata
, Pwidth
, Pheight
, colrs
);
905 for (j
= 0; j
< NUM_FISH
; j
++) {
908 cdp
= (struct colr_data
*) malloc(rcolors
[j
] * sizeof(struct colr_data
));
912 for (i
= 0; i
< rcolors
[j
]; i
++) {
914 cdp
[i
].green
= *gp
++;
917 MedianCount((unsigned char *) xfishRasterA
[j
],
918 (int) rwidth
[j
], (int) rheight
[j
], cdp
);
925 if (picname
[0] != '\0') {
926 for (i
= 0; i
< Pcnt
; i
++) {
934 ConvertColor(&rv
, &gv
, &bv
);
940 hdef
.flags
= DoRed
| DoGreen
| DoBlue
;
941 FindColor(Dpy
, colormap
, &hdef
);
942 cmap
[cnt
] = hdef
.pixel
;
946 for (j
= 0; j
< NUM_FISH
; j
++) {
952 for (i
= 0; i
< rcolors
[j
]; i
++) {
960 ConvertColor(&rv
, &gv
, &bv
);
966 hdef
.flags
= DoRed
| DoGreen
| DoBlue
;
967 FindColor(Dpy
, colormap
, &hdef
);
968 cmap
[cnt
] = hdef
.pixel
;
981 * Make am image of appropriate depth for display from image data.
984 MakeImage(data
, width
, height
)
988 int linepad
, shiftnum
;
989 int shiftstart
, shiftstop
, shiftinc
;
994 unsigned char *bit_data
, *bitp
, *datap
;
996 depth
= DefaultDepth(Dpy
, DefaultScreen(Dpy
));
997 if ((depth
!= 1) && (depth
!= 2) && (depth
!= 4) && (depth
!= 8)) {
998 fprintf(stderr
, "Don't know how to format image for display of depth %d\n", depth
);
1002 if (BitmapBitOrder(Dpy
) == LSBFirst
) {
1007 shiftstart
= 8 - depth
;
1011 linepad
= 8 - (width
% 8);
1012 bit_data
= (unsigned char *) malloc(((width
+ linepad
) * height
) + 1);
1016 shiftnum
= shiftstart
;
1017 for (h
= 0; h
< height
; h
++) {
1018 for (w
= 0; w
< width
; w
++) {
1019 temp
= *datap
++ << shiftnum
;
1020 *bitp
= *bitp
| temp
;
1021 shiftnum
= shiftnum
+ shiftinc
;
1022 if (shiftnum
== shiftstop
) {
1023 shiftnum
= shiftstart
;
1028 for (w
= 0; w
< linepad
; w
++) {
1029 shiftnum
= shiftnum
+ shiftinc
;
1030 if (shiftnum
== shiftstop
) {
1031 shiftnum
= shiftstart
;
1038 bytesperline
= (width
* depth
/ 8 + linepad
);
1039 newimage
= XCreateImage(Dpy
, DefaultVisual(Dpy
, screen
), depth
,
1040 ZPixmap
, 0, (char *) bit_data
,
1041 (width
+ linepad
), height
, 8, bytesperline
);
1048 static unsigned char bits
[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1050 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1051 Calibrate the pixmaps and bimaps. The right-fish data is coded in xfishy.h,
1052 this is transformed to create the left-fish. The eight bubbles are coded
1053 in bubbles.h as a two dimensional array.
1054 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1058 register caddrt p
, q
, x1A
, x1B
, x2A
, x2B
;
1059 unsigned char *data
;
1060 register int i
, j
, k
;
1065 for (k
= 0; k
< NUM_FISH
; k
++) {
1068 * The clipmasks must be created before we remap colors.
1069 * otherwise an opaque color might get remapped to a
1070 * transparent color.
1072 if ((DoClipping
) || (picname
[0] != '\0')) {
1073 data
= (unsigned char *) malloc((rwidth
[k
] + 7) / 8 * rheight
[k
]);
1075 p
= (caddrt
) xfishRasterA
[k
];
1078 for (i
= 0; i
< ((rwidth
[k
] + 7) / 8 * rheight
[k
]); i
++) {
1079 unsigned char bt
= 0x00;
1080 for (j
= 0; j
< 8; j
++) {
1081 if (*p
!= rback
[k
]) {
1086 if (wcnt
== rwidth
[k
]) {
1093 mfishA
[k
][2] = XCreateBitmapFromData(Dpy
, wid
,
1094 (char *) data
, rwidth
[k
], rheight
[k
]);
1096 p
= (caddrt
) xfishRasterA
[k
];
1097 p
= p
+ rwidth
[k
] - 1;
1100 for (i
= 0; i
< ((rwidth
[k
] + 7) / 8 * rheight
[k
]); i
++) {
1101 unsigned char bt
= 0x00;
1102 for (j
= 0; j
< 8; j
++) {
1103 if (*p
!= rback
[k
]) {
1108 if (wcnt
== rwidth
[k
]) {
1110 p
= p
+ (2 * rwidth
[k
]);
1116 mfishA
[k
][1] = XCreateBitmapFromData(Dpy
, wid
,
1117 (char *) data
, rwidth
[k
], rheight
[k
]);
1119 p
= (caddrt
) xfishRasterB
[k
];
1122 for (i
= 0; i
< ((rwidth
[k
] + 7) / 8 * rheight
[k
]); i
++) {
1123 unsigned char bt
= 0x00;
1124 for (j
= 0; j
< 8; j
++) {
1125 if (*p
!= rback
[k
]) {
1130 if (wcnt
== rwidth
[k
]) {
1137 mfishB
[k
][2] = XCreateBitmapFromData(Dpy
, wid
,
1138 (char *) data
, rwidth
[k
], rheight
[k
]);
1140 p
= (caddrt
) xfishRasterB
[k
];
1141 p
= p
+ rwidth
[k
] - 1;
1144 for (i
= 0; i
< ((rwidth
[k
] + 7) / 8 * rheight
[k
]); i
++) {
1145 unsigned char bt
= 0x00;
1146 for (j
= 0; j
< 8; j
++) {
1147 if (*p
!= rback
[k
]) {
1152 if (wcnt
== rwidth
[k
]) {
1154 p
= p
+ (2 * rwidth
[k
]);
1160 mfishB
[k
][1] = XCreateBitmapFromData(Dpy
, wid
,
1161 (char *) data
, rwidth
[k
], rheight
[k
]);
1163 free((char *) data
);
1166 if (DisplayPlanes(Dpy
, screen
) < 8) {
1168 j
= rwidth
[k
] * rheight
[k
];
1169 x1A
= (caddrt
) malloc(rwidth
[k
] * rheight
[k
]);
1170 p
= (caddrt
) xfishRasterA
[k
];
1174 for (i
= 0; i
< j
; i
++) {
1175 *q
= cmap
[cnt
+ (int) (*p
)];
1180 x1B
= (caddrt
) malloc(rwidth
[k
] * rheight
[k
]);
1181 p
= (caddrt
) xfishRasterB
[k
];
1183 for (i
= 0; i
< j
; i
++) {
1184 *q
= cmap
[cnt
+ (int) (*p
)];
1189 x2A
= (caddrt
) malloc(rwidth
[k
] * rheight
[k
]);
1190 for (i
= 0; i
< rheight
[k
]; i
++) {
1191 p
= x1A
+ i
* rwidth
[k
];
1192 q
= x2A
+ (i
+ 1) * rwidth
[k
] - 1;
1193 for (j
= 0; j
< rwidth
[k
]; j
++) {
1198 x2B
= (caddrt
) malloc(rwidth
[k
] * rheight
[k
]);
1199 for (i
= 0; i
< rheight
[k
]; i
++) {
1200 p
= x1B
+ i
* rwidth
[k
];
1201 q
= x2B
+ (i
+ 1) * rwidth
[k
] - 1;
1202 for (j
= 0; j
< rwidth
[k
]; j
++) {
1207 xfishA
[k
][2] = MakeImage(x1A
, rwidth
[k
], rheight
[k
]);
1208 xfishA
[k
][1] = MakeImage(x2A
, rwidth
[k
], rheight
[k
]);
1209 xfishB
[k
][2] = MakeImage(x1B
, rwidth
[k
], rheight
[k
]);
1210 xfishB
[k
][1] = MakeImage(x2B
, rwidth
[k
], rheight
[k
]);
1217 i
= DisplayPlanes(Dpy
, screen
);
1220 XGetImage(Dpy
, root_window
, 0, 0, rwidth
[k
], rheight
[k
], 0, ZPixmap
);
1222 p
= (caddrt
) xfishRasterA
[k
];
1224 for (j
= 0; j
< rheight
[k
]; j
++) {
1225 for (i
= 0; i
< rwidth
[k
]; i
++) {
1226 XPutPixel(xfishA
[k
][2], i
, j
, cmap
[cnt
+ (int) (*p
)]);
1232 XGetImage(Dpy
, root_window
, 0, 0, rwidth
[k
], rheight
[k
], 0, ZPixmap
);
1234 p
= (caddrt
) xfishRasterB
[k
];
1236 for (j
= 0; j
< rheight
[k
]; j
++) {
1237 for (i
= 0; i
< rwidth
[k
]; i
++) {
1238 XPutPixel(xfishB
[k
][2], i
, j
, cmap
[cnt
+ (int) (*p
)]);
1244 XGetImage(Dpy
, root_window
, 0, 0, rwidth
[k
], rheight
[k
], 0, ZPixmap
);
1246 for (j
= 0; j
< rheight
[k
]; j
++) {
1247 for (i
= 0; i
< rwidth
[k
]; i
++) {
1248 XPutPixel(xfishA
[k
][1], i
, j
,
1249 XGetPixel(xfishA
[k
][2], rwidth
[k
] - i
- 1, j
));
1254 XGetImage(Dpy
, root_window
, 0, 0, rwidth
[k
], rheight
[k
], 0, ZPixmap
);
1256 for (j
= 0; j
< rheight
[k
]; j
++) {
1257 for (i
= 0; i
< rwidth
[k
]; i
++) {
1258 XPutPixel(xfishB
[k
][1], i
, j
,
1259 XGetPixel(xfishB
[k
][2], rwidth
[k
] - i
- 1, j
));
1266 i
= DisplayPlanes(Dpy
, screen
);
1268 pfishA
[k
][1] = XCreatePixmap(Dpy
, wid
, rwidth
[k
], rheight
[k
], i
);
1269 pfishA
[k
][2] = XCreatePixmap(Dpy
, wid
, rwidth
[k
], rheight
[k
], i
);
1270 pfishB
[k
][1] = XCreatePixmap(Dpy
, wid
, rwidth
[k
], rheight
[k
], i
);
1271 pfishB
[k
][2] = XCreatePixmap(Dpy
, wid
, rwidth
[k
], rheight
[k
], i
);
1274 XPutImage(Dpy
, pfishA
[k
][1], gc
, xfishA
[k
][1], 0, 0, 0, 0, rwidth
[k
], rheight
[k
]);
1277 XPutImage(Dpy
, pfishA
[k
][2], gc
, xfishA
[k
][2], 0, 0, 0, 0, rwidth
[k
], rheight
[k
]);
1280 XPutImage(Dpy
, pfishB
[k
][1], gc
, xfishB
[k
][1], 0, 0, 0, 0, rwidth
[k
], rheight
[k
]);
1283 XPutImage(Dpy
, pfishB
[k
][2], gc
, xfishB
[k
][2], 0, 0, 0, 0, rwidth
[k
], rheight
[k
]);
1289 for (i
= 1; i
<= 8; i
++) {
1290 xbubbles
[i
] = XCreateBitmapFromData(Dpy
, wid
, (char *) xbBits
[i
], i
, i
);
1295 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1296 Toggle secure mode on receipt of signal
1297 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1307 XLowerWindow(Dpy
, wid
);
1309 XRaiseWindow(Dpy
, wid
);
1317 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1318 Initialize signal so that SIGUSR1 causes secure mode to toggle.
1319 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1324 signal(SIGUSR1
, toggle_secure
);
1325 #elif defined(MOTOROLA) || defined(SCO)
1326 sigset(SIGUSR1
, toggle_secure
);
1330 vec
.sv_handler
= toggle_secure
;
1335 sigvec(SIGUSR1
, &vec
, &vec
);
1337 sigvector(SIGUSR1
, &vec
, &vec
);
1344 set_window_type_desktop(Display
*dpy
, Window wid
)
1346 Atom _NET_WM_WINDOW_TYPE
, _NET_WM_WINDOW_TYPE_DESKTOP
;
1348 _NET_WM_WINDOW_TYPE
= XInternAtom(dpy
, "_NET_WM_WINDOW_TYPE", False
);
1349 _NET_WM_WINDOW_TYPE_DESKTOP
= XInternAtom(dpy
, "_NET_WM_WINDOW_TYPE_DESKTOP", False
);
1351 XChangeProperty(dpy
, wid
, _NET_WM_WINDOW_TYPE
, XA_ATOM
, 32,
1352 PropModeReplace
, (unsigned char *) &_NET_WM_WINDOW_TYPE_DESKTOP
, 1);
1356 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1357 Variety of initialization calls, including getting the window up and running.
1358 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1362 XWindowAttributes winfo
;
1363 XSetWindowAttributes attr
;
1369 root_window
= VirtualRootWindowOfScreen(DefaultScreenOfDisplay(Dpy
));
1371 XGetWindowAttributes(Dpy
, root_window
, &winfo
);
1372 width
= winfo
.width
;
1373 height
= winfo
.height
;
1375 if ((p
= XGetDefault(Dpy
, pname
, "BubbleLimit")) != NULL
)
1377 if ((p
= XGetDefault(Dpy
, pname
, "ColorLimit")) != NULL
)
1379 if ((p
= XGetDefault(Dpy
, pname
, "MedianCutLimit")) != NULL
)
1381 if ((p
= XGetDefault(Dpy
, pname
, "DoClipping")) != NULL
)
1382 DoClipping
= atoi(p
);
1383 if ((p
= XGetDefault(Dpy
, pname
, "DoubleBuffer")) != NULL
)
1384 DoubleBuf
= atoi(p
);
1385 if ((p
= XGetDefault(Dpy
, pname
, "Overlap")) != NULL
)
1387 if ((p
= XGetDefault(Dpy
, pname
, "Color")) != NULL
)
1389 if ((p
= XGetDefault(Dpy
, pname
, "Picture")) != NULL
)
1391 if ((p
= XGetDefault(Dpy
, pname
, "FishLimit")) != NULL
)
1393 if ((p
= XGetDefault(Dpy
, pname
, "IncMult")) != NULL
)
1395 if ((p
= XGetDefault(Dpy
, pname
, "Rate")) != NULL
)
1397 if ((p
= XGetDefault(Dpy
, pname
, "Secure")) != NULL
)
1398 for (i
= 0; i
< 6; i
++)
1399 if (strcmp(p
, yess
[i
]) == 0)
1403 * DoubleBuf is only useful if we are doing clipping on our
1404 * own background picture, otherwise turn it off.
1406 if ((DoubleBuf
) && ((!DoClipping
) || (picname
[0] == '\0'))) {
1412 if (picname
[0] != '\0') {
1413 imlib_context_set_colormap(colormap
);
1414 PicMap
= XCreatePixmap(Dpy
, root_window
, Pwidth
, Pheight
, DisplayPlanes(Dpy
, screen
));
1415 imlib_context_set_drawable(PicMap
);
1416 imlib_render_image_on_drawable(0, 0);
1420 if ((DoubleBuf
) || (picname
[0] != '\0')) {
1421 i
= DisplayPlanes(Dpy
, screen
);
1422 PixBuf
= XCreatePixmap(Dpy
, root_window
, 500, 500, i
);
1423 ClipBuf
= XCreatePixmap(Dpy
, root_window
, 500, 500, 1);
1424 c0gc
= XCreateGC(Dpy
, ClipBuf
, 0, NULL
);
1425 XSetForeground(Dpy
, c0gc
, (unsigned long) 0);
1426 XSetFunction(Dpy
, c0gc
, GXcopy
);
1427 cpgc
= XCreateGC(Dpy
, ClipBuf
, 0, NULL
);
1428 XSetFunction(Dpy
, cpgc
, GXor
);
1431 attr
.override_redirect
= True
;
1432 attr
.background_pixel
= cmap
[0];
1434 if (!DoClipping
|| picname
[0] != '\0') {
1435 wid
= XCreateWindow(Dpy
, root_window
,
1436 1, 1, width
- 2, height
- 2, 0,
1437 CopyFromParent
, CopyFromParent
, CopyFromParent
,
1438 CWBackPixel
| CWOverrideRedirect
, &attr
);
1441 msgdie("XCreateWindow failed");
1442 set_window_type_desktop(Dpy
, wid
);
1445 XClearArea(Dpy
, wid
, 0, 0, 0, 0, False
);
1448 vals
.foreground
= vals
.background
= cmap
[0];
1449 vals
.graphics_exposures
= False
;
1450 gc
= XCreateGC(Dpy
, wid
, GCForeground
| GCBackground
| GCGraphicsExposures
, &vals
);
1451 pgc
= XCreateGC(Dpy
, wid
, GCForeground
| GCBackground
| GCGraphicsExposures
, &vals
);
1452 bgc
= XCreateGC(Dpy
, wid
, GCForeground
| GCBackground
| GCGraphicsExposures
, &vals
);
1454 for (i
= 0; i
< NUM_FISH
; i
++) {
1473 if (!DoClipping
|| picname
[0] != '\0') {
1474 XStoreName(Dpy
, wid
, pname
);
1476 xsh
.flags
= USSize
| USPosition
| PPosition
| PSize
;
1479 xsh
.height
= height
;
1480 XSetNormalHints(Dpy
, wid
, &xsh
);
1482 if (picname
[0] != '\0') {
1483 XSetWindowBackgroundPixmap(Dpy
, wid
, PicMap
);
1486 XMapWindow(Dpy
, wid
);
1489 binfo
= (bubble
*) malloc(blimit
* sizeof(bubble
));
1490 finfo
= (fish
*) malloc(flimit
* sizeof(fish
));
1494 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1495 Create a new bubble. Placement along the x axis is random, as is the size of
1496 the bubble. Increment value is determined by speed.
1497 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1503 register bubble
*b
= b0
;
1505 b
->x
= width
* (rand() / RAND_F_MAX
);
1507 b
->y
= (height
/ 16) * (rand() / RAND_I_1_16
+ 1) - 1;
1510 b
->s
= s
= 1.0 + rand() / RAND_F_1_8
;
1511 if ((b
->i
= smooth
* height
/ (float) binc
[s
]) == 0)
1514 putbubble(b
, s
, bcolor
);
1517 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1518 Erase old bubbles, move and draw new bubbles. Random left-right factor
1519 can move bubble one size-unit in either direction.
1520 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1524 register int i
, j
, s
;
1527 for (i
= 0; i
< blimit
; i
++) {
1531 if ((b
->y
> 0) && (b
->erased
== 0)) {
1532 if ((DoClipping
) || (picname
[0] != '\0')) {
1535 putbubble(b
, s
, cmap
[0]);
1538 if ((b
->y
-= b
->i
) > 0) {
1540 if (j
< RAND_I_1_4
) {
1542 } else if (j
> RAND_I_3_4
) {
1545 putbubble(b
, s
, bcolor
);
1547 if (rand() < RAND_I_1_4
) {
1556 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1557 Fish over bubble collision detection. The specified fish is checked against
1558 all bubbles for overlap. This way we don't try and erase bubbles that are
1560 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1562 collide_bubbles(f0
, ofx
, ofy
)
1567 register fish
*f
= f0
;
1570 for (i
= 0; i
< blimit
; i
++) {
1573 if ((delta
>= 0) && (delta
<= (rwidth
[f
->type
] - b
->s
))) {
1575 if ((delta
>= 0) && (delta
<= (rheight
[f
->type
] - b
->s
))) {
1580 delta
= b
->x
- f
->x
;
1581 if ((delta
>= 0) && (delta
<= (rwidth
[f
->type
] - b
->s
))) {
1582 delta
= b
->y
- f
->y
;
1583 if ((delta
>= 0) && (delta
<= (rheight
[f
->type
] - b
->s
))) {
1591 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1592 Fish collision detection. The specified fish is checked against all other
1593 fish for overlap. The xt parameter specifies a x axis multiplier for overlap.
1594 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1596 collide_fish(f0
, xt
)
1601 register fish
*f
= f0
;
1607 for (i
= 0; i
< flimit
; i
++) {
1608 if (&finfo
[i
] != f
) {
1609 j
= finfo
[i
].y
- f
->y
;
1610 if ((j
> -rheight
[finfo
[i
].type
]) && (j
< rheight
[f
->type
])) {
1611 j
= finfo
[i
].x
- f
->x
;
1612 if ((j
> -xt
* rwidth
[finfo
[i
].type
]) && (j
< xt
* rwidth
[f
->type
])) {
1622 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1623 Create a new fish. Placement along the y axis is random, as is the side
1624 >from which the fish appears. Direction is determined from side. Increment
1626 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1634 f
->type
= rand() % NUM_FISH
;
1635 for (i
= 0, collide
= 1; (i
< 16) && (collide
); i
++) {
1636 f
->y
= (height
- rheight
[f
->type
]) * (rand() / RAND_F_MAX
);
1637 if ((f
->i
= smooth
* width
/ (8.0 * (1.0 + rand() / RAND_F_1_8
))) == 0) {
1640 if (rand() < RAND_I_1_2
) {
1645 f
->x
= -rwidth
[f
->type
];
1647 collide
= collide_fish(f
, 2);
1660 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1661 Move all the fish. Clearing old fish is accomplished by masking only the
1662 exposed areas of the old fish. Random up-down factor can move fish 1/4 a
1663 fish height in either direction, if no collisions are caused.
1664 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1668 register int i
, j
, x
, y
, ofx
, ofy
, ofd
, done
;
1671 for (i
= 0; i
< flimit
; i
++) {
1679 done
= ((f
->x
-= f
->i
) < -rwidth
[f
->type
]);
1680 x
= f
->x
+ rwidth
[f
->type
];
1681 } else if (f
->d
== 2) {
1682 done
= ((f
->x
+= f
->i
) > width
);
1686 if (!collide_fish(f
, 1)) {
1689 if (j
< RAND_I_1_4
) {
1691 } else if (j
> RAND_I_3_4
) {
1699 if (collide_fish(f
, 1)) {
1706 j
= f
->y
+ rheight
[f
->type
];
1712 movefish(f
, ofx
, ofy
, ofd
);
1715 XClearArea(Dpy
, wid
, x
, ofy
, f
->i
, rheight
[f
->type
], 0);
1717 XClearArea(Dpy
, wid
, ofx
, j
, rwidth
[f
->type
], y
, 0);
1722 XClearArea(Dpy
, wid
, x
, f
->y
, f
->i
, rheight
[f
->type
], 0);
1726 if ((f
->d
= 3 - f
->d
) == 1) {
1727 f
->x
= f
->x
- 2 * f
->i
;
1728 x
= f
->x
+ rwidth
[f
->type
];
1730 f
->x
= f
->x
+ 2 * f
->i
;
1734 movefish(f
, ofx
, ofy
, ofd
);
1737 XClearArea(Dpy
, wid
, x
, f
->y
, f
->i
, rheight
[f
->type
], 0);
1740 if ((!DoClipping
) || (picname
[0] == '\0')) {
1741 collide_bubbles(f
, ofx
, ofy
);
1750 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1751 Higher-resolution sleep
1752 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1754 high_res_sleep(seconds
)
1757 struct timeval timeout
;
1759 timeout
.tv_sec
= seconds
;
1760 timeout
.tv_usec
= (seconds
- timeout
.tv_sec
) * 1000000.0;
1761 select(0, NULL
, NULL
, NULL
, &timeout
);
1765 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1766 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1776 if ((Dpy
= XOpenDisplay(sname
)) == 0)
1777 msgdie("XOpenDisplay failed");
1778 screen
= DefaultScreen(Dpy
);
1780 white
= WhitePixel(Dpy
, screen
);
1781 black
= BlackPixel(Dpy
, screen
);
1784 srand((unsigned) getpid());
1787 for (i
= 0; i
< blimit
; i
++)
1788 new_bubble(&binfo
[i
]);
1789 for (i
= 0; i
< flimit
; i
++) {
1794 for (i
= 0; i
< flimit
; i
++)
1795 new_fish(&finfo
[i
]);
1797 XLowerWindow(Dpy
, wid
);
1799 XRaiseWindow(Dpy
, wid
);
1806 XNextEvent(Dpy
, &ev
);
1808 high_res_sleep(rate
);
1815 XLowerWindow(Dpy
, wid
);
1817 XRaiseWindow(Dpy
, wid
);