2 #-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan,
3 #-# Vincent Renardias, Willem Vermin
5 #-# Permission is hereby granted, free of charge, to any person
6 #-# obtaining a copy of this software and associated documentation
7 #-# files (the “Software”), to deal in the Software without
8 #-# restriction, including without limitation the rights to use,
9 #-# copy, modify, merge, publish, distribute, sublicense, and/or
10 #-# sell copies of the Software, and to permit persons to whom
11 #-# the Software is furnished to do so, subject to the following
14 #-# The above copyright notice and this permission notice shall
15 #-# be included in all copies or substantial portions of the Software.
17 #-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
18 #-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 #-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 #-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 #-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 #-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 #-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 #-# OTHER DEALINGS IN THE SOFTWARE.
30 * Original Author Unknow.
32 * 8/10/88 - Ported from X10 to X11R3 by:
34 Jonathan Greenblatt (jonnyg@rover.umd.edu)
36 * Cleaned up by Dave Lemke (lemke@sun.com)
38 * Ported to monocrome by Jonathan Greenblatt (jonnyg@rover.umd.edu)
40 * 05/02/1996 Added TrueColor support by TJ Phan (phan@aur.alcatel.com)
44 #include <sys/types.h>
54 #include <X11/Xutil.h>
59 #include "xfishtank.h"
63 #include "transwindow.h"
71 #include <X11/extensions/Xdbe.h>
73 static XdbeSwapAction BMETHOD
;
74 static int XdbeAvailable
= -42;
77 extern unsigned char *ReadBitmap();
79 /* externals for pixmap and bimaps from xfishy.h */
82 /* typedefs for bubble and fish structures, also caddr_t (not used in X.h) */
83 typedef struct _bubble
{
86 int size
; // size of bubble
87 float bstep
; // increment in placement
90 typedef struct _fish
{
93 int direction
; // direction: 0: r->l
94 int frame
; // animation frames: 0 .. NUM_FRAMES
96 float fstep
; // increment in placement
97 int animtime
; // # drawings between change of frame
100 typedef struct _fishtype
{
108 static int binc
[] = { 0, 64, 56, 48, 40, 32, 24, 16, 8 }; /* bubble increment and yes check tables */
109 static int DoubleBuf
= 0; /* Should we use double buffering */
110 static int width
; /* width of initial window in pixels */
111 static int height
; /* height of initial window in pixels */
112 static int screen
; /* Default screen of this display */
113 static int inxscreensaver
= 0; /* are we running in xscreensaver? */
114 static float smooth
= 0.02; /* smoothness increment multiplier */
115 static bubble
*binfo
= NULL
; /* bubble info structures, allocated dynamically */
116 static fish
*finfo
= NULL
; /* fish info structures, allocated dynamically */
117 static Window root_window
;
118 static fishtype xfish
[NUM_FISH
][2][NUM_FRAMES
]; /* [type][left/right][frame] */
120 static Pixmap xbubbles
[9]; /* bubbles bitmaps (1 to 8, by size in pixels) */
121 static Window wid
; /* aquarium window */
123 static Window UserWindow
= 0;
127 static Pixel bgcolor
;
132 static int xfishtank_trans
= 0;
133 //static int rwidth[NUM_FISH];
134 //static int rheight[NUM_FISH];
135 static XdbeBackBuffer backbuf
= 0;
136 static int WantXdbe
= 1;
137 static const int maxanimtime
= 20;
138 static int nomenu
= 0;
139 static int ForceRoot
= 0;
140 static int HaltedByInterrupt
= 0;
143 static Pixel
AllocNamedColor(Display
*display
, char *colorName
, Pixel dfltPix
);
144 static char *display_name
=NULL
;
145 static int do_move(void *dummy
);
146 static int do_testfish(void *dummy
);
147 static int do_write_flags(void *dummy
);
148 static void erasebubble(bubble
*b
);
149 static void erasefish(fish
*f
);
150 static void init_pixmap(void);
151 static void init_signals(void);
152 static void initialize(void);
153 static void move_fish(void);
154 static void movefish(fish
*f
);
155 static void new_bubble(bubble
*b
, int init
);
156 static void new_fish(fish
*f0
, int init
);
157 static void parse(int argc
, char **argv
);
158 static void putbubble(bubble
*b
, unsigned long c
);
159 static void remove_all_bubbles(void);
160 static void remove_all_fishes(void);
161 static void setanimtime(fish
*f
);
162 static void step_bubbles(void);
163 static void Usage(void);
164 static void Thanks(void);
165 static void SigHandler(int signum
);
166 static void print_changelog(void);
167 static void selfrep(void);
173 int blimit
= 32; /* bubble limit */
174 int flimit
= 10; /* fish limit */
175 char *bcolorstring
= NULL
;
176 char *bgcolorstring
= NULL
;
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
183 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
184 void parse(int argc
, char *argv
[])
189 #define CHECK do{if(++p >= argc){ Usage(); Thanks(); exit(1);}}while(0)
192 P("argv[p] %s\n",argv
[p
]);
193 if (!strcmp(argv
[p
],"-b"))
196 blimit
= strtod(argv
[p
],NULL
);
198 else if (!strcmp(argv
[p
],"-f"))
201 flimit
= strtod(argv
[p
],NULL
);
203 else if (!strcmp(argv
[p
],"-display"))
206 display_name
= strdup(argv
[p
]);
208 else if (!strcmp(argv
[p
],"-bc"))
213 bcolorstring
= strdup(argv
[p
]);
215 else if (!strcmp(argv
[p
],"-bgc"))
220 bgcolorstring
= strdup(argv
[p
]);
222 else if (!strcmp(argv
[p
],"-double"))
225 WantXdbe
= (strtod(argv
[p
],NULL
)>0);
227 else if (!strcmp(argv
[p
],"-speed"))
230 speedfactor
= (strtod(argv
[p
],NULL
)/100.0);
232 else if (!strcmp(argv
[p
],"-h"))
237 else if (!strcmp(argv
[p
],"-defaults"))
241 else if (!strcmp(argv
[p
],"-nomenu"))
245 else if (!strcmp(argv
[p
],"-root"))
249 else if (!strcmp(argv
[p
],"-window-id"))
252 UserWindow
= strtod(argv
[p
],NULL
);
254 else if (!strcmp(argv
[p
],"-changelog"))
260 else if (!strcmp(argv
[p
],"-selfrep"))
268 printf("Not understood: %s\n",argv
[p
]);
281 bcolorstring
= strdup("lightblue");
284 bgcolorstring
= strdup("darkblue");
290 printf("\nUsage: xfishtank [options]\n\n");
291 printf("Options:\n");
292 printf(" -b n number of bubbles (default 32)\n");
293 printf(" -f n number of fish (default 10)\n");
294 printf(" -bc color color of bubbles (default \"lightblue\")\n");
295 printf(" -double n 1: double buffering, 0: do not use (default: 1)\n");
296 printf(" -speed speed of fishes (default: 100)\n");
297 printf(" -defaults all options to default\n");
298 printf(" -nomenu do not show menu\n");
299 printf(" -display DISPLAY to draw on (default \"\")\n");
300 printf(" -root use root-window or xscreensaver-provided window to draw in\n");
301 printf(" -window-id window to draw on\n");
302 printf(" -h show this info\n");
303 printf(" -changelog show ChangeLog and exit\n");
304 printf(" -selfrep output gzipped tarfile of the source and exit\n");
308 int do_write_flags(void *dummy
)
320 void erasefish(fish
*f
)
323 * for something as small as a bubble, it was never worth the
324 * effort of using clipmasks to only turn of the bubble itself, so
325 * we just clear the whole rectangle.
327 //XClearArea(Dpy, wid, f->x, f->y, rwidth[f->type], rheight[f->type], False);
328 fishtype
*ft
= &xfish
[f
->type
][f
->direction
][f
->frame
];
329 XClearArea(Dpy
, wid
, f
->x
, f
->y
, ft
->w
, ft
->h
, False
);
334 * This function can only be called if DoClipping is True. It is used to
335 * move a clipmasked fish. First the area under the fish is cleared,
336 * and then the new fish is masked in.
337 * The parameters x, y, amd d are from the old fish that is being
338 * erased before the new fish is drawn.
340 void movefish(fish
*f
)
342 fishtype
*ft
= &xfish
[f
->type
][f
->direction
][f
->frame
];
343 XSetClipOrigin(Dpy
, ft
->gc
, f
->x
, f
->y
);
344 XCopyArea(Dpy
, ft
->pix
, wid
,ft
->gc
,0,0, ft
->w
, ft
->h
, f
->x
, f
->y
);
346 P("movefish: %#lx %d %d %d %d %d %d %d\n",wid
,f
->type
,f
->direction
,f
->frame
,(int)f
->x
,(int)f
->y
,ft
->w
,ft
->h
);
348 if (f
->animtime
<= 0)
351 f
->frame
= (f
->frame
+ 1)%NUM_FRAMES
;
355 void setanimtime(fish
*f
)
357 f
->animtime
= 0.75*(drand48()+0.333)*maxanimtime
;
360 void erasebubble(bubble
*b
)
362 XClearArea(Dpy
, wid
, b
->x
, b
->y
, b
->size
, b
->size
, 0);
363 P("erasebubble: %d %d %d\n",b
->x
, b
->y
, b
->size
);
367 void putbubble(bubble
*b
, unsigned long c
)
373 gcv
.clip_mask
= xbubbles
[s
];
374 gcv
.clip_x_origin
= b
->x
;
375 gcv
.clip_y_origin
= b
->y
;
376 XChangeGC(Dpy
, bgc
, GCForeground
| GCClipMask
| GCClipXOrigin
| GCClipYOrigin
, &gcv
);
377 XFillRectangle(Dpy
, wid
, bgc
, b
->x
, b
->y
, s
, s
);
378 P("putbubble: %d %d\n", b
->x
, b
->y
);
383 Allocate a color by name.
385 Pixel
AllocNamedColor(Display
*display
, char *colorName
, Pixel dfltPix
)
391 if (XAllocNamedColor(display
,
392 DefaultColormap(display
, DefaultScreen(Dpy
)),
396 pix
= scrncolor
.pixel
;
405 //static unsigned char bits[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
407 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
408 Calibrate the pixmaps and bitmaps. The right-fish data is coded in xfishy.h,
409 this is transformed to create the left-fish. The eight bubbles are coded
410 in bubbles.h as a two dimensional array.
411 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
415 XWindowAttributes attr
;
416 XGetWindowAttributes(Dpy
, wid
, &attr
);
418 XpmAttributes attributes
;
419 attributes
.valuemask
= (
420 XpmExactColors
| XpmCloseness
| XpmDepth
);
422 attributes
.exactColors
= False
; // does not matter, true or false
423 attributes
.closeness
= 40000; // recommended in xpm manual
424 attributes
.depth
= attr
.depth
; // essential
427 // debugging : print all fishes
429 for (k
=0; k
<NUM_FISH
*2; k
++)
432 sscanf(fishes
[k
][0],"%d %d %d %d",&w
,&h
,&c
,&m
);
433 printf("k %d %d %d %d %d\n",k
,w
,h
,c
,m
);
434 for (i
=0; i
<h
+c
+1; i
++)
435 printf("k i: %d %d %s\n",k
,i
,fishes
[k
][i
]);
437 //XGCValues gc_values;
438 //gc_values.function = GXcopy;
439 //gc_values.graphics_exposures = False;
440 //gc_values.fill_style = FillTiled;
441 //int gmask = GCFunction | GCFillStyle | GCGraphicsExposures;
444 for (k
= 0; k
< NUM_FISH
; k
++)
450 for(j
=0; j
<NUM_FRAMES
; j
++)
453 fishtype
*ft
= &xfish
[k
][i
][j
];
454 iXpmCreatePixmapFromData(Dpy
, wid
, fishes
[2*k
+j
], &ft
->pix
, &pix
, &attributes
, i
);
455 ft
->gc
= XCreateGC(Dpy
, wid
, 0, NULL
);
456 //XChangeGC(Dpy, draw_gc, gmask, &gc_values);
457 XSetClipMask(Dpy
, ft
->gc
, pix
);
458 XFreePixmap(Dpy
,pix
);
459 sscanf(fishes
[2*k
][0],"%d %d",&(ft
->w
),&(ft
->h
));
465 for (i
= 1; i
<= 8; i
++)
466 xbubbles
[i
] = XCreateBitmapFromData(Dpy
, wid
, (char *) xbBits
[i
], i
, i
);
472 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
473 Initialize signal so that SIGUSR1 causes secure mode to toggle.
474 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
480 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
481 Variety of initialization calls, including getting the window up and running.
482 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
485 XWindowAttributes winfo
;
486 XSetWindowAttributes attr
;
491 root_window
= VirtualRootWindowOfScreen(DefaultScreenOfDisplay(Dpy
));
493 XGetWindowAttributes(Dpy
, root_window
, &winfo
);
495 height
= winfo
.height
;
500 unsigned int w
,h
,b
,depth
;
501 Window root
, searchWin
;
503 XGetGeometry(Dpy
,root_window
,&root
,
504 &x
, &y
, &w
, &h
, &b
, &depth
);
505 gtkwin
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
506 gtk_window_set_title (GTK_WINDOW(gtkwin
),"Xfishtank-A");
507 gtk_window_set_skip_taskbar_hint (GTK_WINDOW(gtkwin
),TRUE
);
508 gtk_window_set_skip_pager_hint (GTK_WINDOW(gtkwin
),TRUE
);
512 searchWin
= DefaultRootWindow(Dpy
);
513 // Are we started by xscreensaver?
514 if (getenv("XSCREENSAVER_WINDOW"))
516 searchWin
= strtol(getenv("XSCREENSAVER_WINDOW"),NULL
,0);
522 searchWin
= UserWindow
;
526 int HaveTrans
= make_trans_window(gtkwin
,
539 searchWin
= root_window
;
540 // Maybe, it is LXDE: find window with name pcmanfm
541 char *DesktopSession
= NULL
;
542 if (getenv("DESKTOP_SESSION"))
544 DesktopSession
= strdup(getenv("DESKTOP_SESSION"));
545 char *a
= DesktopSession
;
546 while (*a
) { *a
= toupper(*a
); a
++; }
547 if (!strncmp(DesktopSession
,"LXDE",4))
549 Window w
= Window_With_Name(Dpy
, root_window
, "pcmanfm");
553 printf("LXDE session found, using window pcmanfm\n");
558 free(DesktopSession
);
562 XMoveWindow(Dpy
,searchWin
,0,0);
563 XSetWindowBackground(Dpy
,searchWin
,0);
567 P("searchWin: %#lx\n",searchWin
);
571 xfishtankWin
= searchWin
;
574 vals
.foreground
= vals
.background
= bcolor
;
575 vals
.graphics_exposures
= False
;
576 //gc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals);
577 //pgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals);
578 bgc
= XCreateGC(Dpy
, wid
, GCForeground
| GCBackground
| GCGraphicsExposures
, &vals
);
579 //draw_gc = XCreateGC(Dpy, wid, 0, NULL);
580 //XGCValues gc_values;
581 //gc_values.function = GXcopy;
582 //gc_values.graphics_exposures = False;
583 //gc_values.fill_style = FillTiled;
584 //XChangeGC(Dpy, draw_gc, GCFunction | GCFillStyle | GCGraphicsExposures, &gc_values);
586 for (i
= 0; i
< NUM_FISH
; i
++)
588 for (k
=0; k
<NUM_FRAMES
; k
++)
590 fishtype
*ft
= &xfish
[i
][j
][k
];
600 binfo
= (bubble
*) malloc(blimit
* sizeof(bubble
));
601 //finfo = (fish *) malloc(flimit * sizeof(fish));
607 if (XdbeAvailable
== -42)
608 XdbeAvailable
= XdbeQueryExtension(Dpy
,&xdbemajor
,&xdbeminor
);
612 UseXdbe
= XdbeAvailable
&& WantXdbe
;
615 //BMETHOD = XdbeBackground;
616 BMETHOD
= XdbeBackground
;
617 // BMETHOD = XdbeUndefined;
618 // BMETHOD = XdbeUntouched;
619 // BMETHOD = XdbeCopied; // use this to check if dbe works; fishes and bubbles will not be erased
624 XdbeDeallocateBackBufferName(Dpy
,backbuf
);
625 backbuf
= XdbeAllocateBackBufferName(Dpy
, wid1
, BMETHOD
);
627 printf("Using double buffer: %#lx window: %#lx\n",backbuf
,wid1
);
630 printf("Using window: %#lx\n",wid
);
634 printf("This is a new transparent window.\n");
638 printf("This is an existing window.\n");
640 printf("This is an existing window, probably the root window.\n");
642 XClearWindow(Dpy
,wid1
);
644 // drawing on wid, XClearWindow, XSetWindowBackground on wid1
648 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
649 Create a new bubble. Placement along the x axis is random, as is the size of
650 the bubble. Increment value is determined by speed.
651 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
652 void new_bubble(bubble
*b
, int init
) // init=0: postions at bottom, else random
656 b
->x
= 5+(width
-10) * drand48();
658 b
->y
= (height
/ 16) * (16*drand48() + 1) - 1;
661 b
->size
= s
= 1.0 + 8*drand48();
662 if ((b
->bstep
= smooth
* height
/ (float) binc
[s
]) == 0)
664 P("newbubble %d %d\n",b
->x
, b
->y
);
667 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
668 Erase old bubbles, move and draw new bubbles. Random left-right factor
669 can move bubble one size-unit in either direction.
670 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
678 for (i
= 0; i
< blimit
; i
++)
684 if ((b->y > 0) && (b->erased == 0))
689 if ((b
->y
-= b
->bstep
) > 0)
691 double r
= drand48();
694 } else if (r
> 0.75) {
697 putbubble(b
, bcolor
);
699 if (drand48() < 0.25) {
710 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
711 Create a new fish. Placement along the y axis is random, as is the side
712 >from which the fish appears. Direction is determined from side. Increment
714 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
715 void new_fish(fish
*f0
, int init
) // init 0: position at edge, else position at random
720 f
->type
= drand48() * NUM_FISH
;
721 fishtype
*ft
= &xfish
[f
->type
][0][0];
722 for (i
= 0, collide
= 1; (i
< 16) && (collide
); i
++)
724 f
->y
= (height
- ft
->h
) * drand48();
725 if ((f
->fstep
= smooth
* width
/ (8.0 * (1.0 + 8*drand48()))) == 0)
732 f
->x
= ft
->w
+ drand48()*width
;
740 f
->x
= drand48()*width
-ft
->w
;
747 P("newfish %d %d\n",(int)f
->x
,(int)f
->y
);
750 void remove_all_fishes()
753 for (i
= 0; i
< flimit
; i
++)
754 erasefish(&finfo
[i
]);
758 void remove_all_bubbles()
761 for (i
= 0; i
< blimit
; i
++)
762 erasebubble(&binfo
[i
]);
766 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
767 Move all the fish. Clearing old fish is accomplished by masking only the
768 exposed areas of the old fish. Random up-down factor can move fish 1/4 a
769 fish height in either direction, if no collisions are caused.
770 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
776 for (i
= 0; i
< flimit
; i
++)
779 fishtype
*ft
= &xfish
[f
->type
][f
->direction
][f
->frame
];
780 if (f
->direction
== 0)
781 done
= ((f
->x
-= speedfactor
*f
->fstep
) < -ft
->w
);
782 else if (f
->direction
== 1)
783 done
= ((f
->x
+= speedfactor
*f
->fstep
) > width
);
785 if(0) // spontaneous change direction now and then
786 if (f
->x
> ft
->w
&& f
->x
< width
- 2*ft
->w
&& drand48() < 0.001)
788 f
->direction
= 1-f
->direction
;
789 P("direction: %d\n",f
->direction
);
795 double r
= drand48();
817 int do_move(void *dummy
)
830 XdbeSwapInfo swapInfo
;
831 swapInfo
.swap_window
= wid1
;
832 swapInfo
.swap_action
= BMETHOD
;
833 XdbeSwapBuffers(Dpy
, &swapInfo
, 1);
835 XSetWindowBackground(Dpy
,wid1
,0);
840 remove_all_bubbles();
845 remove_all_bubbles();
854 int do_testfish(void *dummy
)
864 XClearArea(Dpy
, wid
, x
,y
,w
,h
,0);
873 GC gc
= xfish
[0][1][0].gc
;
874 XSetClipOrigin(Dpy
, gc
, x
, y
);
875 XCopyArea(Dpy
, xfish
[0][1][0].pix
, wid
, gc
,0,0,w
,h
,x
,y
);
880 void create_fishes(int n
)
885 finfo
= (fish
*)realloc(finfo
,sizeof(fish
)*flimit
);
886 for (i
= prev
; i
< flimit
; i
++)
887 new_fish(&finfo
[i
],1);
891 void create_bubbles(int n
)
896 binfo
= (bubble
*)realloc(binfo
,sizeof(bubble
)*blimit
);
897 for (i
= prev
; i
< blimit
; i
++)
898 new_bubble(&binfo
[i
],1);
902 void setspeed(float s
)
909 bcolor
= AllocNamedColor(Dpy
,bcolorstring
,white
)|0xff000000;
914 if (inxscreensaver
&& !xfishtank_trans
&& bgcolorstring
&& strlen(bgcolorstring
))
916 P("bgcolorstring '%s'\n",bgcolorstring
);
917 bgcolor
= AllocNamedColor(Dpy
,bgcolorstring
,black
)|0xff000000;
918 XSetWindowBackground(Dpy
, wid1
, bgcolor
);
919 XClearWindow(Dpy
,wid1
);
926 if (HaltedByInterrupt
)
927 printf("\nxfishtank: Caught signal %d\n",HaltedByInterrupt
);
930 XClearWindow(Dpy
,wid1
);
933 printf("\nThank you for using xfishtank\n");
937 void SigHandler(int signum
)
939 HaltedByInterrupt
= signum
;
945 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
946 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
947 int main(int argc
, char *argv
[])
949 // Circumvent wayland problems:before starting gtk: make sure that the
950 // gdk-x11 backend is used.
952 setenv("GDK_BACKEND","x11",1);
953 signal(SIGINT
, SigHandler
);
954 signal(SIGTERM
, SigHandler
);
955 signal(SIGHUP
, SigHandler
);
958 printf("xfishtank version %s\n",VERSION
);
959 printf("Comments to: %s\n",PACKAGE_BUGREPORT
);
960 printf("Url: %s\n",PACKAGE_URL
);
963 gtk_init(&argc
, &argv
);
966 Dpy
= XOpenDisplay(display_name
);
969 char *name
= display_name
;
972 if(getenv("DISPLAY"))
973 name
= getenv("DISPLAY");
975 printf("Cannot open display: '%s'\n",name
);
979 screen
= DefaultScreen(Dpy
);
981 white
= WhitePixel(Dpy
, screen
);
982 black
= BlackPixel(Dpy
, screen
);
989 srand((unsigned) getpid());
991 create_bubbles(blimit
);
993 create_fishes(flimit
);
997 g_timeout_add_full(G_PRIORITY_DEFAULT
, 30, do_move
,NULL
, NULL
);
998 g_timeout_add_full(G_PRIORITY_DEFAULT
, 500, do_write_flags
,NULL
, NULL
);
1001 g_timeout_add_full(G_PRIORITY_DEFAULT
, 40, do_testfish
,NULL
, NULL
);
1012 void print_changelog()
1014 #include "changelog.inc"
1018 static unsigned char tarfile
[] = {
1019 #include "tarfile.inc"
1023 if(sizeof(tarfile
) > 1000 && isatty(fileno(stdout
)))
1025 printf("Not sending tar file to terminal.\n");
1026 printf("Try redirecting to a file (e.g: xpenguins -selfrep > xpenguins.tar.gz),\n");
1027 printf("or use a pipe (e.g: xpenguins -selfrep | tar zxf -).\n");
1031 ssize_t rc
= mywrite(fileno(stdout
),tarfile
,sizeof(tarfile
));
1033 fprintf(stderr
,"xpenguins: Problems encountered during production of the tar ball.\n");