#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #define UNUSED __attribute__((__unused__)) static XrmDatabase db; static const char *defaults_common = "\ *Foreground: white\n\ *Background: black\n\ *BorderColor: white\n\ "; static const char *defaults_message = "\ *Font: fixed\n\ *BorderWidth: 1\n\ *BorderMargin: 5\n\ "; static const char *defaults_bitmap = "\ *BorderWidth: 0\n\ *BorderMargin: 0\n\ "; static char *displayname; static char *geometryspec; static char *fontname; static char *foreground; static char *background; static char *bordercstr; static char *borderwstr; static char *bordermstr; static char *visualstr; static int synch; static const char *message; static const char *bitmapfile; static const char *maskfile; static int blank; static int expose; static int autoraise; static int dodge; static int nograb; static int debug; static int autofork; static int printid; static int timeout; static int argc; static char **argv; static Display *disp; static Screen *scr; static int scrwidth; static int scrheight; static int depth; static Window rootwin; static Colormap wincmap; static int defcmap; static GC gc; static XVisualInfo visinfo; static XFontStruct *font; static XColor fgcolour; static XColor bgcolour; static XColor bdcolour; static int margin; static int borderwidth; static XCharStruct msgbbox; static int msgw; static int msgh; static int xbytes; static unsigned char *pic; static unsigned char *mpic; static XImage *ximg; static Window parent = None; static Window win; static GC wingc; static int fontspace; static int fontendspace; static int winx; static int winy; static int winw; static int winh; static XTextProperty wn_prop; static XTextProperty in_prop; static XSizeHints *normal_hints; static XWMHints *wm_hints; static XClassHint *class_hints; typedef struct rect RECT; typedef struct rectband RECTBAND; typedef struct ratelimit RATELIMIT; struct ratelimit { int nsec; int limit; int val; time_t last; } ; #define RATELIMIT_INIT(nsec,credit) { (nsec), (credit), 0, 0 } struct rect { RECT *rectright; RECTBAND *band; int x1; int x2; } ; struct rectband { RECTBAND *bandbelow; RECT *thisband; int y1; int y2; } ; typedef RECTBAND *RECTSHAPE; static char *deconst(const char *s) { char *rv; bcopy(&s,&rv,sizeof(rv)); return(rv); } #define ALLOCPKG(name,TYPE) \ static void *name##_freelist = 0; \ \ static TYPE *new_##name(void) \ { \ TYPE *rv; \ \ if (name##_freelist) \ { rv = (TYPE *) name##_freelist; \ name##_freelist = * (char **) name##_freelist; \ } \ else \ { rv = malloc(sizeof(TYPE)); \ } \ return(rv); \ } \ \ static void free_##name(TYPE *obj) \ { \ void *ovp; \ \ ovp = obj; \ * (void **) ovp = name##_freelist; \ name##_freelist = ovp; \ } \ ALLOCPKG(rect,RECT) ALLOCPKG(rectband,RECTBAND) #undef ALLOCPKG static void print_rectshape(RECTSHAPE s) { RECTBAND *b; RECT *r; for (b=s;b;b=b->bandbelow) { printf("\ty=[%d..%d)\n",b->y1,b->y2); for (r=b->thisband;r;r=r->rectright) { printf("\t\tx=[%d..%d)\n",r->x1,r->x2); } } } static void destroy_rectshape(RECTSHAPE s) { RECTBAND *b; RECTBAND *b2; RECT *r; RECT *r2; for (b=s;b;b=b2) { b2 = b->bandbelow; for (r=b->thisband;r;r=r2) { r2 = r->rectright; free_rect(r); } free_rectband(b); } } static RECTSHAPE onerect(int x, int y, int w, int h) { RECTSHAPE rv; rv = new_rectband(); rv->bandbelow = 0; rv->thisband = new_rect(); rv->thisband->rectright = 0; rv->thisband->band = rv; rv->thisband->x1 = x; rv->thisband->x2 = x + w; rv->y1 = y; rv->y2 = y + h; return(rv); } static void splitband(RECTBAND *b, int y) { RECT *r; RECTBAND *b2; RECT *newr; RECT **newrp; b2 = new_rectband(); b2->bandbelow = b->bandbelow; b->bandbelow = b2; newrp = &b2->thisband; b2->y1 = y; b2->y2 = b->y2; b->y2 = y; for (r=b->thisband;r;r=r->rectright) { newr = new_rect(); newr->band = b2; newr->x1 = r->x1; newr->x2 = r->x2; *newrp = newr; newrp = &newr->rectright; } *newrp = 0; } static void splitrect(RECT *r, int x) { RECT *r2; r2 = new_rect(); r2->rectright = r->rectright; r->rectright = r2; r2->band = r->band; r2->x1 = x; r2->x2 = r->x2; r->x2 = x; } static RECTSHAPE subrect(RECTSHAPE s, int x, int y, int w, int h) { int x1; int y1; int x2; int y2; RECTBAND *b; RECTBAND **bp; RECT *r; RECT **rp; x1 = x; y1 = y; x2 = x + w; y2 = y + h; for (bp=(&s);(b=(*bp))&&(b->y2<=y1);bp=(&b->bandbelow)) ; if (b == 0) return(0); while (1) { b = *bp; if (b == 0) break; if (b->y1 >= y2) break; if (b->y1 < y1) { splitband(b,y1); bp = &b->bandbelow; b = *bp; } if (b->y2 > y2) { splitband(b,y2); } for (rp=(&b->thisband);(r=(*rp))&&(r->x2<=x1);rp=(&r->rectright)) ; if (r) { while (1) { r = *rp; if (r == 0) break; if (r->x1 >= x2) break; if (r->x1 < x1) { splitrect(r,x1); rp = &r->rectright; r = *rp; } if (r->x2 > x2) { splitrect(r,x2); } *rp = r->rectright; free_rect(r); } } if (b->thisband == 0) { *bp = b->bandbelow; free_rectband(b); } else { bp = &b->bandbelow; } } return(s); } static RECTSHAPE merge(RECTSHAPE s) { if (s == 0) return(0); { RECTBAND *b; RECT *r1; RECT *r2; for (b=s;b;b=b->bandbelow) { for (r1=b->thisband;r1->rectright;r1=r2) { r2 = r1->rectright; if (r2->x1 != r1->x2) continue; r1->rectright = r2->rectright; r1->x2 = r2->x2; free_rect(r2); r2 = r1; } } } { RECTBAND *b1; RECTBAND *b2; RECT *r1; RECT *r2; for (b1=s;b1->bandbelow;b1=b2) { b2 = b1->bandbelow; if (b2->y1 != b1->y2) continue; for ( r1 = b1->thisband , r2 = b2->thisband; r1 && r2 && (r1->x1 == r2->x1) && (r1->x2 == r2->x2); r1 = r1->rectright , r2 = r2->rectright ) ; if (r1 || r2) continue; b1->bandbelow = b2->bandbelow; b1->y2 = b2->y2; for (r1=b2->thisband;r1;r1=r2) { r2 = r1->rectright; free_rect(r1); } free_rectband(b2); b2 = b1; } } return(s); } static void saveargv(int ac, char **av) { int i; int nc; char *abuf; argc = ac; argv = (char **) malloc((ac+1)*sizeof(char *)); nc = 1; for (i=0;i { #define FOO(c) if (!strcasecmp(visualstr,#c)) { class = c; classname = #c; } else FOO(StaticGray) FOO(StaticColor) FOO(TrueColor) FOO(GrayScale) FOO(PseudoColor) FOO(DirectColor) #undef FOO { unsigned long int id; char *cp; id = strtol(visualstr,&cp,0); if (*cp) { fprintf(stderr,"%s: %s: invalid visual option\n",__progname,visualstr); exit(1); } template.visualid = (VisualID) id; xvi = XGetVisualInfo(disp,VisualIDMask,&template,&nvi); if (xvi == 0) { fprintf(stderr,"%s: no such visual found\n",__progname); exit(1); } if (nvi == 0) { fprintf(stderr,"%s: what? XGetVisualInfo returned non-nil but zero count?\n",__progname); exit(1); } visinfo = xvi[0]; if (visinfo.screen != XDefaultScreen(disp)) { fprintf(stderr,"%s: warning: visual %s is on screen %d\n",__progname,visualstr,(int)visinfo.screen); } break <"vis">; } template.class = class; xvi = XGetVisualInfo(disp,VisualClassMask,&template,&nvi); best = -1; best_onscr = -1; for (i=0;i xvi[best_onscr].depth) || ( (xvi[i].depth == xvi[best_onscr].depth) && (xvi[i].visual == XDefaultVisual(disp,xvi[i].screen)) ) ) { best_onscr = i; } } if ( (best < 0) || (xvi[i].depth > xvi[best].depth) || ( (xvi[i].depth == xvi[best].depth) && (xvi[i].visual == XDefaultVisual(disp,xvi[i].screen)) ) ) { best = i; } } if (best < 0) { fprintf(stderr,"%s: no %s visual available\n",__progname,classname); exit(1); } if (best_onscr < 0) { fprintf(stderr,"%s: no %s visual on screen %d, using screen %d\n",__progname,classname,XDefaultScreen(disp),xvi[best].screen); } else { best = best_onscr; } visinfo = xvi[best]; } while (0); } } static void setup_db(void) { char *str; char *home; char hostname[256]; XrmDatabase db2; db = XrmGetStringDatabase(defaults_common); if (message) { db2 = XrmGetStringDatabase(defaults_message); XrmMergeDatabases(db2,&db); } if (bitmapfile) { db2 = XrmGetStringDatabase(defaults_bitmap); XrmMergeDatabases(db2,&db); } str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } home = getenv("HOME"); if (home) { str = malloc(strlen(home)+1+10+1); sprintf(str,"%s/.Xdefaults",home); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); gethostname(&hostname[0],(sizeof(hostname)/sizeof(hostname[0]))-1); hostname[(sizeof(hostname)/sizeof(hostname[0]))-1] = '\0'; str = malloc(strlen(home)+1+11+strlen(&hostname[0])+1); sprintf(str,"%s/.Xdefaults-%s",home,&hostname[0]); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); } } static char *get_default_value(const char *name, const char *class) { char *type; XrmValue value; if (XrmGetResource(db,name,class,&type,&value) == False) return(0); return(value.addr); } static void setup_gc(void) { if (depth == XDefaultDepthOfScreen(scr)) { gc = XDefaultGCOfScreen(scr); } else { Pixmap p; p = XCreatePixmap(disp,rootwin,1,1,depth); gc = XCreateGC(disp,p,0,0); XFreePixmap(disp,p); } } static void setup_cmap(void) { if (visinfo.visual == XDefaultVisualOfScreen(scr)) { wincmap = XDefaultColormapOfScreen(scr); defcmap = 1; } else { wincmap = XCreateColormap(disp,rootwin,visinfo.visual,AllocNone); defcmap = 0; } } static void setup_font(void) { unsigned long int fontprop; font = XLoadQueryFont(disp,fontname); if (font == 0) { font = XQueryFont(disp,XGContextFromGC(gc)); if (font == 0) { fprintf(stderr,"%s: can't query the server default font, sorry\n",__progname); exit(1); } fprintf(stderr,"%s: can't load font %s, using server default\n",__progname,fontname); } fontspace = -1; fontendspace = -1; if (XGetFontProperty(font,XA_NORM_SPACE,&fontprop)) { fontspace = fontprop; } else { fontspace = XTextWidth(font,"0",1); } if (XGetFontProperty(font,XA_END_SPACE,&fontprop)) { fontendspace = fontprop; } else { fontendspace = 1.5 * fontspace; } } static void setup_colour(char *str, XColor *col) { if (XParseColor(disp,wincmap,str,col) == 0) { fprintf(stderr,"%s: bad colour `%s'\n",__progname,str); exit(1); } if (XAllocColor(disp,wincmap,col) == 0) { if (! defcmap) { fprintf(stderr,"%s: can't allocate colormap cell for colour `%s'\n",__progname,str); exit(1); } wincmap = XCopyColormapAndFree(disp,wincmap); defcmap = 0; if (XAllocColor(disp,wincmap,col) == 0) { fprintf(stderr,"%s: can't allocate colormap cell for colour `%s'\n",__progname,str); exit(1); } } } static void setup_colours(void) { XGCValues v; setup_colour(foreground,&fgcolour); setup_colour(background,&bgcolour); setup_colour(bordercstr,&bdcolour); v.foreground = fgcolour.pixel; v.background = bgcolour.pixel; XChangeGC(disp,gc,GCForeground|GCBackground,&v); } static void setup_numbers(void) { if (bordermstr) margin = atoi(bordermstr); if (borderwstr) borderwidth = atoi(borderwstr); } static void setup_message(void) { int junki1; int junki2; int junki3; const char *cp; msgbbox.lbearing = 0x7fff; /* ghaa */ msgbbox.rbearing = 0x8000; msgbbox.ascent = 0x8000; msgbbox.descent = 0x8000; msgbbox.width = 0; for (cp=message;*cp;cp++) { if (*cp == ' ') { int s; s = ((cp>message)&&index(".!?",cp[-1])) ? fontendspace : fontspace; while (cp[1] == ' ') cp ++; if (cp[1]) { msgbbox.width += s; } } else { XCharStruct bb; XTextExtents(font,cp,1,&junki1,&junki2,&junki3,&bb); if (msgbbox.width+bb.lbearing < msgbbox.lbearing) msgbbox.lbearing = msgbbox.width + bb.lbearing; if (msgbbox.width+bb.rbearing > msgbbox.rbearing) msgbbox.rbearing = msgbbox.width + bb.rbearing; if (bb.ascent > msgbbox.ascent) msgbbox.ascent = bb.ascent; if (bb.descent > msgbbox.descent) msgbbox.descent = bb.descent; msgbbox.width += bb.width; } } msgw = msgbbox.rbearing - msgbbox.lbearing; msgh = msgbbox.ascent + msgbbox.descent; } static void loadpbm(FILE *f, int *wp, int *xbp, int *hp, unsigned char **pp) { int raw; int push; int pushed = 0; int xsize; int ysize; int xbytes; unsigned char *pic; static int get(void) { if (pushed) { pushed = 0; return(push); } return(getc(f)); } static void unget(int v) { push = v; pushed = 1; } static int getcomm(void) { int c; c = get(); if (c == '#') do c = get(); while ((c != '\n') && (c != EOF)); return(c); } static void noinput(const char *why) { fprintf(stderr,"%s: can't read input: %s\n",__progname,why); exit(1); } static int readn(void) { int c; int v; v = 0; while (1) { c = getcomm(); if (c == EOF) noinput("unexpected error/eof"); if (isascii(c) && isspace(c)) continue; break; } while (isascii(c) && isdigit(c)) { v = (10 * v) + (c - '0'); c = get(); } unget(c); return(v); } if (get() != 'P') noinput("bad magic number"); switch (get()) { default: noinput("bad magic number"); break; case '1': raw = 0; break; case '4': raw = 1; break; case '2': case '5': noinput("is a pgm file, not a pbm file"); break; case '3': case '6': noinput("is a ppm file, not a pbm file"); break; } xsize = readn(); ysize = readn(); xbytes = (xsize + 7) / 8; pic = (unsigned char *) malloc(xbytes*ysize); if (! pic) noinput("can't malloc space for it"); if (raw) { get(); fread(pic,1,xbytes*ysize,f); } else { int x; int y; int v; int c; unsigned char *pp; v = 0; pp = pic; for (y=0;y> (x & 7); break; case '1': break; default: noinput("bad character in bitmap"); break; } if ((x & 7) == 7) { *pp++ = v; v = 0; } } if (xsize & 7) { *pp++ = v; v = 0; } } } *wp = xsize; *hp = ysize; *xbp = xbytes; *pp = pic; } static void setup_bitmap(void) { FILE *f; f = fopen(bitmapfile,"r"); if (! f) { fprintf(stderr,"%s: can't read %s: %s\n",__progname,bitmapfile,strerror(errno)); exit(1); } loadpbm(f,&msgw,&xbytes,&msgh,&pic); fclose(f); mpic = 0; if (maskfile) { int w; int h; int xb; unsigned char *p; f = fopen(maskfile,"r"); if (! f) { fprintf(stderr,"%s: can't read %s: %s\n",__progname,maskfile,strerror(errno)); exit(1); } loadpbm(f,&w,&xb,&h,&p); fclose(f); if ((w != msgw) || (h != msgh)) { fprintf(stderr,"%s: mask isn't the same size as image\n",__progname); exit(1); } mpic = p; } fclose(f); ximg = XCreateImage(disp,XDefaultVisualOfScreen(scr),1,XYBitmap,0,pic,msgw,msgh,8,xbytes); ximg->byte_order = MSBFirst; ximg->bitmap_unit = 8; ximg->bitmap_bit_order = MSBFirst; ximg->bitmap_pad = 8; ximg->bytes_per_line = xbytes; } static void set_shape(void) { Pixmap spm; XGCValues v; GC gc; spm = XCreatePixmap(disp,rootwin,winw,winh,1); v.foreground = 1; v.background = 0; gc = XCreateGC(disp,spm,GCForeground|GCBackground,&v); ximg->data = mpic; XPutImage(disp,spm,gc,ximg,0,0,0,0,winw,winh); ximg->data = pic; XShapeCombineMask(disp,win,ShapeBounding,0,0,spm,ShapeSet); XFreePixmap(disp,spm); XFreeGC(disp,gc); } static void setup_window(void) { int x; int y; int w; int h; int bits; unsigned long int attrmask; XSetWindowAttributes attr; unsigned long int gcvalmask; XGCValues gcval; w = msgw; h = msgh; if (message) { w += (margin*2) + (borderwidth*2); h += (margin*2) + (borderwidth*2); } x = (scrwidth - w) / 2; y = (scrheight - h) / 2; bits = XParseGeometry(geometryspec,&x,&y,&w,&h); if (bits & XNegative) x = scrwidth + x - w; if (bits & YNegative) y = scrheight + y - h; attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.border_pixel = bdcolour.pixel; attrmask |= CWBorderPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask|StructureNotifyMask|VisibilityChangeMask; attrmask |= CWEventMask; attr.colormap = wincmap; attrmask |= CWColormap; winx = x; winy = y; winw = w; winh = h; w -= 2 * borderwidth; h -= 2 * borderwidth; win = XCreateWindow(disp,parent,x,y,w,h,borderwidth,depth,InputOutput,visinfo.visual,attrmask,&attr); wn_prop.value = (unsigned char *) deconst("killme"); wn_prop.encoding = XA_STRING; wn_prop.format = 8; wn_prop.nitems = strlen(wn_prop.value); in_prop.value = (unsigned char *) deconst("killme"); in_prop.encoding = XA_STRING; in_prop.format = 8; in_prop.nitems = strlen(in_prop.value); normal_hints = XAllocSizeHints(); normal_hints->flags = PMinSize | PResizeInc; normal_hints->x = x; normal_hints->y = y; normal_hints->flags |= (bits & (XValue|YValue)) ? USPosition : PPosition; normal_hints->width = w; normal_hints->height = h; normal_hints->flags |= (bits & (WidthValue|HeightValue)) ? USSize : PSize; normal_hints->min_width = w; normal_hints->min_height = h; normal_hints->width_inc = 1; normal_hints->height_inc = 1; wm_hints = XAllocWMHints(); wm_hints->flags = InputHint; wm_hints->input = False; class_hints = XAllocClassHint(); class_hints->res_name = deconst("killme"); class_hints->res_class = deconst("Random"); XSetWMProperties(disp,win,&wn_prop,&in_prop,argv,argc,normal_hints,wm_hints,class_hints); gcvalmask = 0; if (font) { gcval.font = font->fid; gcvalmask |= GCFont; } gcval.foreground = fgcolour.pixel; gcvalmask |= GCForeground; gcval.background = bgcolour.pixel; gcvalmask |= GCBackground; wingc = XCreateGC(disp,win,gcvalmask,&gcval); if (bitmapfile && mpic) set_shape(); if (expose) { XMapRaised(disp,win); } else { XLowerWindow(disp,win); XMapWindow(disp,win); } } static int ioerror_handler(Display *d UNUSED) { exit(0); } static int error_handler(Display *d UNUSED, XErrorEvent *e UNUSED) { exit(0); } static void setup_error(void) { XSetErrorHandler(error_handler); XSetIOErrorHandler(ioerror_handler); } static void find_and_move(RECTSHAPE s) { int wcx; int wcy; RECTBAND *b; RECT *r; int rcx; int rcy; int dx; int dy; int d2; RECT *bestr; int bestd2; if (debug) { printf("find_and_move: winx=%d winy=%d winw=%d winh=%d; shape is\n",winx,winy,winw,winh); print_rectshape(s); fflush(stdout); } /* should look harder for an appropriate place to go */ wcx = winx + (winw / 2); wcy = winy + (winh / 2); bestd2 = (scrwidth * scrwidth) + (scrheight * scrheight) + 1; bestr = 0; for (b=s;b;b=b->bandbelow) { if (debug) printf("find_and_move: band y[%d..%d)\n",b->y1,b->y2); if (b->y2-b->y1 <= winh) continue; rcy = (b->y1 + b->y2) / 2; dy = wcy - rcy; for (r=b->thisband;r;r=r->rectright) { if (debug) printf("find_and_move: rect x[%d..%d)\n",r->x1,r->x2); if (r->x2-r->x1 <= winw) continue; rcx = (r->x1 + r->x2) / 2; dx = wcx - rcx; d2 = (dx * dx) + (dy * dy); if (debug) printf("find_and_move: dx=%d dy=%d d2=%d bestd2=%d\n",dx,dy,d2,bestd2); if (d2 < bestd2) { bestd2 = d2; bestr = r; if (debug) printf("find_and_move: replaced\n"); } } } if (bestr) { winx += ((bestr->x1 + bestr->x2) / 2) - wcx; winy += ((bestr->band->y1 + bestr->band->y2) / 2) - wcy; XMoveWindow(disp,win,winx,winy); normal_hints->x = winx; normal_hints->y = winy; normal_hints->flags &= ~PPosition; normal_hints->flags |= USPosition; XSetWMProperties(disp,win,&wn_prop,&in_prop,argv,argc,normal_hints,wm_hints,class_hints); } } static void do_dodge(void) { int i; Window w; int nkids; Window *kids; Window root_return; Window parent_return; RECTSHAPE uncovered; XWindowAttributes attr; if (! nograb) XGrabServer(disp); /* XXX necessary to avoid races */ w = win; while (1) { XQueryTree(disp,w,&root_return,&parent_return,&kids,&nkids); XFree(kids); if (parent_return == parent) break; w = parent_return; } XQueryTree(disp,parent,&root_return,&parent_return,&kids,&nkids); uncovered = onerect(0,0,scrwidth,scrheight); for (i=0;imessage)&&index(".!?",cp[-1])) ? fontendspace : fontspace; while (cp[1] == ' ') cp ++; x += s; } else { XDrawString(disp,win,wingc,x,y,cp,1); x += XTextWidth(font,cp,1); } } } if (bitmapfile) { XPutImage(disp,win,gc,ximg,0,0,0,0,winw,winh); } } static int ratelimit(RATELIMIT *rl) { time_t now; int delta; time(&now); if (rl->val == 0) { rl->val = 1; rl->last = now; return(1); } delta = now - rl->last; if (delta >= rl->val*rl->nsec) { rl->val = 1; rl->last = now; return(1); } while (delta >= rl->nsec) { delta -= rl->nsec; rl->last += rl->nsec; rl->val --; } if (rl->val < rl->limit) { rl->val ++; return(1); } else { return(0); } } static void do_raise(void) { XRaiseWindow(disp,win); } static void obscured(void) { static RATELIMIT rl = RATELIMIT_INIT(5,10); if (autoraise && ratelimit(&rl)) { do_raise(); } else if (dodge) { do_dodge(); } } static void handle_event(XEvent *e) { switch (e->type) { default: break; case ConfigureNotify: /* XConfigureEvent - xconfigure */ winw = e->xconfigure.width + (2 * e->xconfigure.border_width); winh = e->xconfigure.height + (2 * e->xconfigure.border_width); redisplay(); break; case Expose: /* XExposeEvent - xexpose */ if (e->xexpose.count == 0) { redisplay(); } break; case GraphicsExpose: /* XGraphicsExposeEvent - xgraphicsexpose */ if (e->xexpose.count == 0) { redisplay(); } break; case VisibilityNotify: /* XVisibilityEvent - xvisibility */ if (e->xvisibility.state != VisibilityUnobscured) { obscured(); } break; } } static void run(void) { XEvent e; while (1) { XNextEvent(disp,&e); handle_event(&e); } } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayname = av[skip]; continue; } if (!strcmp(*av,"-geometry")) { WANTARG(); geometryspec = av[skip]; continue; } if (!strcmp(*av,"-font") || !strcmp(*av,"-fn")) { WANTARG(); fontname = av[skip]; continue; } if (!strcmp(*av,"-foreground") || !strcmp(*av,"-fg")) { WANTARG(); foreground = av[skip]; continue; } if (!strcmp(*av,"-background") || !strcmp(*av,"-bg")) { WANTARG(); background = av[skip]; continue; } if (!strcmp(*av,"-bordercolor") || !strcmp(*av,"-bd")) { WANTARG(); bordercstr = av[skip]; continue; } #if 0 if (!strcmp(*av,"-margincolor") || !strcmp(*av,"-mc")) { WANTARG(); margincstr = av[skip]; continue; } #endif if (!strcmp(*av,"-borderwidth") || !strcmp(*av,"-bw")) { WANTARG(); borderwstr = av[skip]; continue; } if (!strcmp(*av,"-bordermargin") || !strcmp(*av,"-bm")) { WANTARG(); bordermstr = av[skip]; continue; } if (!strcmp(*av,"-visual")) { WANTARG(); visualstr = av[skip]; continue; } if (!strcmp(*av,"-timeout")) { WANTARG(); timeout = atoi(av[skip]); continue; } if (!strcmp(*av,"-parent")) { WANTARG(); parent = (Window)strtol(av[skip],0,0); continue; } if (!strcmp(*av,"-message")) { WANTARG(); message = av[skip]; continue; } if (!strcmp(*av,"-bitmap")) { WANTARG(); bitmapfile = av[skip]; continue; } if (!strcmp(*av,"-blank")) { blank = 1; continue; } if (!strcmp(*av,"-mask")) { WANTARG(); maskfile = av[skip]; continue; } if (!strcmp(*av,"-expose")) { expose = 1; continue; } if (!strcmp(*av,"-autoraise")) { autoraise = 1; continue; } if (!strcmp(*av,"-dodge")) { dodge = 1; continue; } if (!strcmp(*av,"-nograb")) { nograb = 1; continue; } if (!strcmp(*av,"-debug")) { debug = 1; nograb = 1; continue; } if (!strcmp(*av,"-fork")) { autofork = 1; continue; } if (!strcmp(*av,"-id")) { printid = 1; continue; } if (!strcmp(*av,"-sync")) { synch = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (!!message+!!bitmapfile+!!blank != 1) { fprintf(stderr,"%s: must give exactly one of -message, -bitmap, -blank\n",__progname); errs ++; } if (errs) exit(1); } static void daemonize(void) { pid_t kid; int fd; fflush(0); fd = open("/dev/null",O_RDWR,0); if (fd < 0) { fprintf(stderr,"%s: /dev/null: %s\n",__progname,strerror(errno)); exit(1); } if (fd != 1) { dup2(fd,1); close(fd); } kid = fork(); if (kid < 0) { fprintf(stderr,"%s: fork: %s\n",__progname,strerror(errno)); exit(1); } if (kid == 0) return; exit(0); } static void setup_sigchld(void) { struct sigaction sa; sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NOCLDWAIT | SA_RESTART; sigaction(SIGCHLD,&sa,0); while (wait3(0,WNOHANG,0) > 0) ; } static void sig_alrm(int sig __attribute__((__unused__))) { _exit(0); } static void setup_timeout(void) { struct sigaction sa; sa.sa_handler = &sig_alrm; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM,&sa,0); alarm(timeout); } int main(int, char **); int main(int ac, char **av) { saveargv(ac,av); handleargs(ac,av); disp = XOpenDisplay(displayname); if (disp == 0) { fprintf(stderr,"%s: can't open display\n",__progname); exit(1); } if (synch) XSynchronize(disp,True); setup_visual(); scr = XScreenOfDisplay(disp,visinfo.screen); scrwidth = XWidthOfScreen(scr); scrheight = XHeightOfScreen(scr); depth = visinfo.depth; rootwin = XRootWindowOfScreen(scr); if (parent == None) parent = rootwin; setup_db(); maybeset(&geometryspec,get_default_value("killme.geometry","Random.Geometry")); maybeset(&fontname,get_default_value("killme.font","Random.Font")); maybeset(&foreground,get_default_value("killme.foreground","Random.Foreground")); maybeset(&background,get_default_value("killme.background","Random.Background")); maybeset(&bordercstr,get_default_value("killme.borderColor","Random.BorderColor")); maybeset(&borderwstr,get_default_value("killme.borderWidth","Random.BorderWidth")); maybeset(&bordermstr,get_default_value("killme.borderMargin","Random.BorderMargin")); setup_gc(); setup_cmap(); setup_colours(); setup_numbers(); if (message) { setup_font(); setup_message(); } if (bitmapfile) setup_bitmap(); setup_window(); setup_error(); setup_sigchld(); if (printid) printf("%#x\n",(unsigned int)win); if (autofork) daemonize(); if (timeout) setup_timeout(); run(); return(0); }