X-Git-Url: http://git.ieval.ro/?p=xfishtank.git;a=blobdiff_plain;f=src%2Fmain.c;fp=src%2Fmain.c;h=752b31f9a8808430d654d0ee8523570bcc0c359f;hp=0000000000000000000000000000000000000000;hb=4c1bd65b5f48075ff80be1e401beb5ff21b4b89e;hpb=4deccbc95c1e3e86669d84c2f6922ee6a5f5180a diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..752b31f --- /dev/null +++ b/src/main.c @@ -0,0 +1,1037 @@ +/* -copyright- +#-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan, +#-# Vincent Renardias, Willem Vermin +#-# +#-# Permission is hereby granted, free of charge, to any person +#-# obtaining a copy of this software and associated documentation +#-# files (the “Software”), to deal in the Software without +#-# restriction, including without limitation the rights to use, +#-# copy, modify, merge, publish, distribute, sublicense, and/or +#-# sell copies of the Software, and to permit persons to whom +#-# the Software is furnished to do so, subject to the following +#-# conditions: +#-# +#-# The above copyright notice and this permission notice shall +#-# be included in all copies or substantial portions of the Software. +#-# +#-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +#-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +#-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +#-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +#-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +#-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +#-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +#-# OTHER DEALINGS IN THE SOFTWARE. +#-# +*/ + +/* + + * Original Author Unknow. + + * 8/10/88 - Ported from X10 to X11R3 by: + + Jonathan Greenblatt (jonnyg@rover.umd.edu) + + * Cleaned up by Dave Lemke (lemke@sun.com) + + * Ported to monocrome by Jonathan Greenblatt (jonnyg@rover.umd.edu) + + * 05/02/1996 Added TrueColor support by TJ Phan (phan@aur.alcatel.com) + +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xfishtank.h" +#include "vroot.h" +#include "bubbles.h" +#include "debug.h" +#include "transwindow.h" +#include "utils.h" +#include "fishes.h" +#include "ixpm.h" +#include "ui.h" + + +#ifdef DOUBLE_BUFFER +#include +static int UseXdbe; +static XdbeSwapAction BMETHOD; +static int XdbeAvailable = -42; +#endif + +extern unsigned char *ReadBitmap(); + +/* externals for pixmap and bimaps from xfishy.h */ + + +/* typedefs for bubble and fish structures, also caddr_t (not used in X.h) */ +typedef struct _bubble { + float x; + float y; + int size; // size of bubble + float bstep; // increment in placement +} bubble; + +typedef struct _fish { + float x; + float y; + int direction; // direction: 0: r->l + int frame; // animation frames: 0 .. NUM_FRAMES + int type; + float fstep; // increment in placement + int animtime; // # drawings between change of frame +} fish; + +typedef struct _fishtype { + Pixmap pix; + GC gc; + int w; + int h; +} fishtype; + + +static int binc[] = { 0, 64, 56, 48, 40, 32, 24, 16, 8 }; /* bubble increment and yes check tables */ +static int DoubleBuf = 0; /* Should we use double buffering */ +static int width; /* width of initial window in pixels */ +static int height; /* height of initial window in pixels */ +static int screen; /* Default screen of this display */ +static int inxscreensaver = 0; /* are we running in xscreensaver? */ +static float smooth = 0.02; /* smoothness increment multiplier */ +static bubble *binfo = NULL; /* bubble info structures, allocated dynamically */ +static fish *finfo = NULL; /* fish info structures, allocated dynamically */ +static Window root_window; +static fishtype xfish[NUM_FISH][2][NUM_FRAMES]; /* [type][left/right][frame] */ + +static Pixmap xbubbles[9]; /* bubbles bitmaps (1 to 8, by size in pixels) */ +static Window wid; /* aquarium window */ +static Window wid1; +static Window UserWindow = 0; +static Pixel white; +static Pixel black; +static Pixel bcolor; +static Pixel bgcolor; +//static GC pgc; +//static GC gc; +static GC bgc; +//static GC draw_gc; +static int xfishtank_trans = 0; +//static int rwidth[NUM_FISH]; +//static int rheight[NUM_FISH]; +static XdbeBackBuffer backbuf = 0; +static int WantXdbe = 1; +static const int maxanimtime = 20; +static int nomenu = 0; +static int ForceRoot = 0; +static int HaltedByInterrupt = 0; +static int Done = 0; + +static Pixel AllocNamedColor(Display *display, char *colorName, Pixel dfltPix); +static char *display_name=NULL; +static int do_move(void *dummy); +static int do_testfish(void *dummy); +static int do_write_flags(void *dummy); +static void erasebubble(bubble *b); +static void erasefish(fish *f); +static void init_pixmap(void); +static void init_signals(void); +static void initialize(void); +static void move_fish(void); +static void movefish(fish *f); +static void new_bubble(bubble *b, int init); +static void new_fish(fish *f0, int init); +static void parse(int argc, char **argv); +static void putbubble(bubble *b, unsigned long c); +static void remove_all_bubbles(void); +static void remove_all_fishes(void); +static void setanimtime(fish*f); +static void step_bubbles(void); +static void Usage(void); +static void Thanks(void); +static void SigHandler(int signum); +static void print_changelog(void); +static void selfrep(void); + + +Display *Dpy = NULL; +Window xfishtankWin; +int counter; +int blimit = 32; /* bubble limit */ +int flimit = 10; /* fish limit */ +char *bcolorstring = NULL; +char *bgcolorstring = NULL; +float speedfactor; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + parse command line + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void parse(int argc, char *argv[]) +{ + + int p = 0; + +#define CHECK do{if(++p >= argc){ Usage(); Thanks(); exit(1);}}while(0) + while (++p < argc) + { + P("argv[p] %s\n",argv[p]); + if (!strcmp(argv[p],"-b")) + { + CHECK; + blimit = strtod(argv[p],NULL); + } + else if (!strcmp(argv[p],"-f")) + { + CHECK; + flimit = strtod(argv[p],NULL); + } + else if (!strcmp(argv[p],"-display")) + { + CHECK; + display_name = strdup(argv[p]); + } + else if (!strcmp(argv[p],"-bc")) + { + CHECK; + if(bcolorstring) + free(bcolorstring); + bcolorstring = strdup(argv[p]); + } + else if (!strcmp(argv[p],"-bgc")) + { + CHECK; + if(bgcolorstring) + free(bgcolorstring); + bgcolorstring = strdup(argv[p]); + } + else if (!strcmp(argv[p],"-double")) + { + CHECK; + WantXdbe = (strtod(argv[p],NULL)>0); + } + else if (!strcmp(argv[p],"-speed")) + { + CHECK; + speedfactor = (strtod(argv[p],NULL)/100.0); + } + else if (!strcmp(argv[p],"-h")) + { + Usage(); + Thanks(); + } + else if (!strcmp(argv[p],"-defaults")) + { + set_defaults(); + } + else if (!strcmp(argv[p],"-nomenu")) + { + nomenu = 1; + } + else if (!strcmp(argv[p],"-root")) + { + ForceRoot = 1; + } + else if (!strcmp(argv[p],"-window-id")) + { + CHECK; + UserWindow = strtod(argv[p],NULL); + } + else if (!strcmp(argv[p],"-changelog")) + { + print_changelog(); + Thanks(); + } +#ifdef SELFREP + else if (!strcmp(argv[p],"-selfrep")) + { + selfrep(); + exit(0); + } +#endif + else + { + printf("Not understood: %s\n",argv[p]); + Usage(); + Thanks(); + } + } +} + +void set_defaults() +{ + flimit = 10; + blimit = 32; + if(bcolorstring) + free(bcolorstring); + bcolorstring = strdup("lightblue"); + if(bgcolorstring) + free(bgcolorstring); + bgcolorstring = strdup("darkblue"); + speedfactor = 1.0; +} + +void Usage() +{ + printf("\nUsage: xfishtank [options]\n\n"); + printf("Options:\n"); + printf(" -b n number of bubbles (default 32)\n"); + printf(" -f n number of fish (default 10)\n"); + printf(" -bc color color of bubbles (default \"lightblue\")\n"); + printf(" -double n 1: double buffering, 0: do not use (default: 1)\n"); + printf(" -speed speed of fishes (default: 100)\n"); + printf(" -defaults all options to default\n"); + printf(" -nomenu do not show menu\n"); + printf(" -display DISPLAY to draw on (default \"\")\n"); + printf(" -root use root-window or xscreensaver-provided window to draw in\n"); + printf(" -window-id window to draw on\n"); + printf(" -h show this info\n"); + printf(" -changelog show ChangeLog and exit\n"); + printf(" -selfrep output gzipped tarfile of the source and exit\n"); + printf("\n"); +} + +int do_write_flags(void *dummy) +{ + if (FlagsChanged) + { + FlagsChanged = 0; + WriteFlags(); + } + return TRUE; + (void)dummy; +} + + +void erasefish(fish *f) +{ + /* + * for something as small as a bubble, it was never worth the + * effort of using clipmasks to only turn of the bubble itself, so + * we just clear the whole rectangle. + */ + //XClearArea(Dpy, wid, f->x, f->y, rwidth[f->type], rheight[f->type], False); + fishtype *ft = &xfish[f->type][f->direction][f->frame]; + XClearArea(Dpy, wid, f->x, f->y, ft->w, ft->h, False); +} + + +/* + * This function can only be called if DoClipping is True. It is used to + * move a clipmasked fish. First the area under the fish is cleared, + * and then the new fish is masked in. + * The parameters x, y, amd d are from the old fish that is being + * erased before the new fish is drawn. + */ +void movefish(fish *f) +{ + fishtype *ft = &xfish[f->type][f->direction][f->frame]; + XSetClipOrigin(Dpy, ft->gc, f->x, f->y); + XCopyArea(Dpy, ft->pix, wid,ft->gc,0,0, ft->w, ft->h, f->x, f->y); + + 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); + f->animtime --; + if (f->animtime <= 0) + { + setanimtime(f); + f->frame = (f->frame + 1)%NUM_FRAMES; + } +} + +void setanimtime(fish*f) +{ + f->animtime = 0.75*(drand48()+0.333)*maxanimtime; +} + +void erasebubble(bubble *b) +{ + XClearArea(Dpy, wid, b->x, b->y, b->size, b->size, 0); + P("erasebubble: %d %d %d\n",b->x, b->y, b->size); +} + + +void putbubble(bubble *b, unsigned long c) +{ + XGCValues gcv; + + int s = b->size; + gcv.foreground = c; + gcv.clip_mask = xbubbles[s]; + gcv.clip_x_origin = b->x; + gcv.clip_y_origin = b->y; + XChangeGC(Dpy, bgc, GCForeground | GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv); + XFillRectangle(Dpy, wid, bgc, b->x, b->y, s, s); + P("putbubble: %d %d\n", b->x, b->y); +} + + +/* + Allocate a color by name. + */ +Pixel AllocNamedColor(Display *display, char *colorName, Pixel dfltPix) +{ + Pixel pix; + XColor exactcolor; + XColor scrncolor; + + if (XAllocNamedColor(display, + DefaultColormap(display, DefaultScreen(Dpy)), + colorName, + &scrncolor, + &exactcolor)) + pix = scrncolor.pixel; + else + pix = dfltPix; + + return pix; +} + + + +//static unsigned char bits[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Calibrate the pixmaps and bitmaps. The right-fish data is coded in xfishy.h, + this is transformed to create the left-fish. The eight bubbles are coded + in bubbles.h as a two dimensional array. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void init_pixmap() +{ + + XWindowAttributes attr; + XGetWindowAttributes(Dpy, wid, &attr); + + XpmAttributes attributes; + attributes.valuemask = ( + XpmExactColors | XpmCloseness | XpmDepth); + + attributes.exactColors = False; // does not matter, true or false + attributes.closeness = 40000; // recommended in xpm manual + attributes.depth = attr.depth; // essential + + int k; + // debugging : print all fishes + if(0) + for (k=0; kpix, &pix, &attributes, i); + ft->gc = XCreateGC(Dpy, wid, 0, NULL); + //XChangeGC(Dpy, draw_gc, gmask, &gc_values); + XSetClipMask(Dpy, ft->gc, pix); + XFreePixmap(Dpy,pix); + sscanf(fishes[2*k][0],"%d %d",&(ft->w),&(ft->h)); + } + } + } + + int i; + for (i = 1; i <= 8; i++) + xbubbles[i] = XCreateBitmapFromData(Dpy, wid, (char *) xbBits[i], i, i); +} + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Initialize signal so that SIGUSR1 causes secure mode to toggle. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void init_signals() +{ +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Variety of initialization calls, including getting the window up and running. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void initialize() +{ + XWindowAttributes winfo; + XSetWindowAttributes attr; + (void)attr; + XGCValues vals; + int i,j,k; + + root_window = VirtualRootWindowOfScreen(DefaultScreenOfDisplay(Dpy)); + + XGetWindowAttributes(Dpy, root_window, &winfo); + width = winfo.width; + height = winfo.height; + + DoubleBuf=0; + + int x,y; + unsigned int w,h,b,depth; + Window root, searchWin; + GtkWidget *gtkwin; + XGetGeometry(Dpy,root_window,&root, + &x, &y, &w, &h, &b, &depth); + gtkwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW(gtkwin),"Xfishtank-A"); + gtk_window_set_skip_taskbar_hint (GTK_WINDOW(gtkwin),TRUE); + gtk_window_set_skip_pager_hint (GTK_WINDOW(gtkwin),TRUE); + + if (ForceRoot) + { + searchWin = DefaultRootWindow(Dpy); + // Are we started by xscreensaver? + if (getenv("XSCREENSAVER_WINDOW")) + { + searchWin = strtol(getenv("XSCREENSAVER_WINDOW"),NULL,0); + inxscreensaver = 1; + } + } + else if(UserWindow) + { + searchWin = UserWindow; + } + else + { + int HaveTrans = make_trans_window(gtkwin, + 1 /*fullscreen*/, + 1 /*sticky*/, + 1 /* below*/, + 1 /* dock*/ , + NULL, + &searchWin); + if (HaveTrans) + { + xfishtank_trans = 1; + } + else + { + searchWin = root_window; + // Maybe, it is LXDE: find window with name pcmanfm + char *DesktopSession = NULL; + if (getenv("DESKTOP_SESSION")) + { + DesktopSession = strdup(getenv("DESKTOP_SESSION")); + char *a = DesktopSession; + while (*a) { *a = toupper(*a); a++; } + if (!strncmp(DesktopSession,"LXDE",4)) + { + Window w = Window_With_Name(Dpy, root_window, "pcmanfm"); + if(w) + { + searchWin = w; + printf("LXDE session found, using window pcmanfm\n"); + } + } + } + if(DesktopSession) + free(DesktopSession); + } + if(xfishtank_trans) + { + XMoveWindow(Dpy,searchWin,0,0); + XSetWindowBackground(Dpy,searchWin,0); + } + } + + P("searchWin: %#lx\n",searchWin); + + wid = searchWin; + + xfishtankWin = searchWin; + + + vals.foreground = vals.background = bcolor; + vals.graphics_exposures = False; + //gc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals); + //pgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals); + bgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures, &vals); + //draw_gc = XCreateGC(Dpy, wid, 0, NULL); + //XGCValues gc_values; + //gc_values.function = GXcopy; + //gc_values.graphics_exposures = False; + //gc_values.fill_style = FillTiled; + //XChangeGC(Dpy, draw_gc, GCFunction | GCFillStyle | GCGraphicsExposures, &gc_values); + + for (i = 0; i < NUM_FISH; i++) + for (j=0; j<2; j++) + for (k=0; kpix = 0; + ft->gc = 0; + ft->w = 42; + ft->h = 42; + } + + init_pixmap(); + init_signals(); + + binfo = (bubble *) malloc(blimit * sizeof(bubble)); + //finfo = (fish *) malloc(flimit * sizeof(fish)); + + wid1 = wid; +#ifdef DOUBLE_BUFFER + int xdbemajor; + int xdbeminor; + if (XdbeAvailable == -42) + XdbeAvailable = XdbeQueryExtension(Dpy,&xdbemajor,&xdbeminor); +#else + XdbeAvailable = 0; +#endif + UseXdbe = XdbeAvailable && WantXdbe; + +#ifdef DOUBLE_BUFFER + //BMETHOD = XdbeBackground; + BMETHOD = XdbeBackground; + // BMETHOD = XdbeUndefined; + // BMETHOD = XdbeUntouched; + // BMETHOD = XdbeCopied; // use this to check if dbe works; fishes and bubbles will not be erased + + if (UseXdbe) + { + if (backbuf) + XdbeDeallocateBackBufferName(Dpy,backbuf); + backbuf = XdbeAllocateBackBufferName(Dpy, wid1, BMETHOD); + wid = backbuf; + printf("Using double buffer: %#lx window: %#lx\n",backbuf,wid1); + } + else + printf("Using window: %#lx\n",wid); +#endif + + if(xfishtank_trans) + printf("This is a new transparent window.\n"); + else + { + if(UserWindow) + printf("This is an existing window.\n"); + else + printf("This is an existing window, probably the root window.\n"); + } + XClearWindow(Dpy,wid1); + + // drawing on wid, XClearWindow, XSetWindowBackground on wid1 +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Create a new bubble. Placement along the x axis is random, as is the size of + the bubble. Increment value is determined by speed. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void new_bubble(bubble *b, int init) // init=0: postions at bottom, else random +{ + int s; + + b->x = 5+(width-10) * drand48(); + if (init) + b->y = (height / 16) * (16*drand48() + 1) - 1; + else + b->y = height - 1; + b->size = s = 1.0 + 8*drand48(); + if ((b->bstep = smooth * height / (float) binc[s]) == 0) + b->bstep = 1; + P("newbubble %d %d\n",b->x, b->y); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Erase old bubbles, move and draw new bubbles. Random left-right factor + can move bubble one size-unit in either direction. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void step_bubbles() +{ + int i, j, s; + (void)j; + (void)s; + bubble *b; + + for (i = 0; i < blimit; i++) + { + b = &binfo[i]; + s = b->size; + /* clear */ + /* + if ((b->y > 0) && (b->erased == 0)) + { + erasebubble(b, s); + } + */ + if ((b->y -= b->bstep) > 0) + { + double r = drand48(); + if (r < 0.25) { + b->x -= 1; + } else if (r > 0.75) { + b->x += 1; + } + putbubble(b, bcolor); + } else { + if (drand48() < 0.25) { + new_bubble(b,0); + } + } + } + XFlush(Dpy); +} + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Create a new fish. Placement along the y axis is random, as is the side + >from which the fish appears. Direction is determined from side. Increment + is also random. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void new_fish(fish *f0, int init) // init 0: position at edge, else position at random +{ + int i, collide; + fish *f = f0; + + f->type = drand48() * NUM_FISH; + fishtype *ft = &xfish[f->type][0][0]; + for (i = 0, collide = 1; (i < 16) && (collide); i++) + { + f->y = (height - ft->h) * drand48(); + if ((f->fstep = smooth * width / (8.0 * (1.0 + 8*drand48()))) == 0) + f->fstep = 1; + } + if (drand48() < 0.5) + { + f->direction = 0; + if (init) + f->x = ft->w + drand48()*width; + else + f->x = width; + } + else + { + f->direction = 1; + if (init) + f->x = drand48()*width-ft->w; + else + f->x = -ft->w; + } + + f->frame = 0; + setanimtime(f); + P("newfish %d %d\n",(int)f->x,(int)f->y); +} + +void remove_all_fishes() +{ + int i; + for (i = 0; i < flimit; i++) + erasefish(&finfo[i]); + XFlush(Dpy); +} + +void remove_all_bubbles() +{ + int i; + for (i = 0; i < blimit; i++) + erasebubble(&binfo[i]); + XFlush(Dpy); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Move all the fish. Clearing old fish is accomplished by masking only the + exposed areas of the old fish. Random up-down factor can move fish 1/4 a + fish height in either direction, if no collisions are caused. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void move_fish() +{ + int i, y, done = 0; + fish *f; + + for (i = 0; i < flimit; i++) + { + f = &finfo[i]; + fishtype *ft = &xfish[f->type][f->direction][f->frame]; + if (f->direction == 0) + done = ((f->x -= speedfactor*f->fstep) < -ft->w); + else if (f->direction == 1) + done = ((f->x += speedfactor*f->fstep) > width); + + if(0) // spontaneous change direction now and then + if (f->x > ft->w && f->x < width - 2*ft->w && drand48() < 0.001) + { + f->direction = 1-f->direction; + P("direction: %d\n",f->direction); + } + if (1) + { + if (!done) + { + double r = drand48(); + if (r < 0.25) + y = f->fstep / 4; + else if (r > 0.75) + y = f->fstep / -4; + else + y = 0; + + if (y) + f->y += y; + movefish(f); + } + else + { + erasefish(f); + new_fish(f,0); + } + } + } + XFlush(Dpy); +} + +int do_move(void *dummy) +{ + (void)dummy; + + if (Done) + { + gtk_main_quit(); + return FALSE; + } + +#ifdef DOUBLE_BUFFER + if (UseXdbe) + { + XdbeSwapInfo swapInfo; + swapInfo.swap_window = wid1; + swapInfo.swap_action = BMETHOD; + XdbeSwapBuffers(Dpy, &swapInfo, 1); + if(xfishtank_trans) + XSetWindowBackground(Dpy,wid1,0); + } + else + { + XFlush(Dpy); + remove_all_bubbles(); + remove_all_fishes(); + } +#else + XFlush(Dpy); + remove_all_bubbles(); + remove_all_fishes(); +#endif + move_fish(); + step_bubbles(); + return TRUE; + +} + +int do_testfish(void *dummy) +{ + (void)dummy; + + static int x = 100; + static int y = 100; + int w = 64; + int h = 41; + w= 64; + h=59; + XClearArea(Dpy, wid, x,y,w,h,0); + x += 1; + y += 1; + if (x > 500) + { + x = 100; + y = 100; + } + + GC gc = xfish[0][1][0].gc; + XSetClipOrigin(Dpy, gc, x, y); + XCopyArea(Dpy, xfish[0][1][0].pix, wid, gc,0,0,w,h,x,y); + XFlush(Dpy); + return TRUE; +} + +void create_fishes(int n) +{ + int i; + static int prev = 0; + flimit = n; + finfo = (fish *)realloc(finfo,sizeof(fish)*flimit); + for (i = prev; i < flimit; i++) + new_fish(&finfo[i],1); + prev = flimit; +} + +void create_bubbles(int n) +{ + int i; + static int prev = 0; + blimit = n; + binfo = (bubble *)realloc(binfo,sizeof(bubble)*blimit); + for (i = prev; i < blimit; i++) + new_bubble(&binfo[i],1); + prev = blimit; +} + +void setspeed(float s) +{ + speedfactor = s; +} + +void setbcolor() +{ + bcolor = AllocNamedColor(Dpy,bcolorstring,white)|0xff000000; +} + +void setbgcolor() +{ + if (inxscreensaver && !xfishtank_trans && bgcolorstring && strlen(bgcolorstring)) + { + P("bgcolorstring '%s'\n",bgcolorstring); + bgcolor = AllocNamedColor(Dpy,bgcolorstring,black)|0xff000000; + XSetWindowBackground(Dpy, wid1, bgcolor); + XClearWindow(Dpy,wid1); + } +} + + +void Thanks() +{ + if (HaltedByInterrupt) + printf("\nxfishtank: Caught signal %d\n",HaltedByInterrupt); + if (Dpy) + { + XClearWindow(Dpy,wid1); + XFlush(Dpy); + } + printf("\nThank you for using xfishtank\n"); + exit(0); +} + +void SigHandler(int signum) +{ + HaltedByInterrupt = signum; + Done = 1; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +int main(int argc, char *argv[]) +{ + // Circumvent wayland problems:before starting gtk: make sure that the + // gdk-x11 backend is used. + + setenv("GDK_BACKEND","x11",1); + signal(SIGINT, SigHandler); + signal(SIGTERM, SigHandler); + signal(SIGHUP, SigHandler); + + parse(argc, argv); + printf("xfishtank version %s\n",VERSION); + printf("Comments to: %s\n",PACKAGE_BUGREPORT); + printf("Url: %s\n",PACKAGE_URL); + srand48(time(NULL)); + counter = 0; + gtk_init(&argc, &argv); + set_defaults(); + ReadFlags(); + Dpy = XOpenDisplay(display_name); + if(!Dpy) + { + char *name = display_name; + if (!display_name) + { + if(getenv("DISPLAY")) + name = getenv("DISPLAY"); + } + printf("Cannot open display: '%s'\n",name); + Thanks(); + exit(1); + } + screen = DefaultScreen(Dpy); + + white = WhitePixel(Dpy, screen); + black = BlackPixel(Dpy, screen); + + initialize(); + + setbcolor(); + setbgcolor(); + + srand((unsigned) getpid()); + + create_bubbles(blimit); + + create_fishes(flimit); + + ui(); + + g_timeout_add_full(G_PRIORITY_DEFAULT, 30, do_move ,NULL, NULL); + g_timeout_add_full(G_PRIORITY_DEFAULT, 500, do_write_flags ,NULL, NULL); + + if(0) + g_timeout_add_full(G_PRIORITY_DEFAULT, 40, do_testfish ,NULL, NULL); + + if (nomenu) + iconify(); + gtk_main(); + + Thanks(); + + return 0; +} + +void print_changelog() +{ +#include "changelog.inc" +} + +#ifdef SELFREP +static unsigned char tarfile[] = { +#include "tarfile.inc" +}; +void selfrep() +{ + if(sizeof(tarfile) > 1000 && isatty(fileno(stdout))) + { + printf("Not sending tar file to terminal.\n"); + printf("Try redirecting to a file (e.g: xpenguins -selfrep > xpenguins.tar.gz),\n"); + printf("or use a pipe (e.g: xpenguins -selfrep | tar zxf -).\n"); + } + else + { + ssize_t rc = mywrite(fileno(stdout),tarfile,sizeof(tarfile)); + if (rc < 0) + fprintf(stderr,"xpenguins: Problems encountered during production of the tar ball.\n"); + } +} +#endif +