/* speyes Copywrite (c) 1999, Audin Malmin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING); if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA */ #define VERSION "1.2.0" #include #include #include #include #include #include #include #include #include #include #include #include #include "getopt.h" #include "XPM/pup3.xbm" #include "XPM/kenny.xpm" /* Color images of the dudes. */ #include "XPM/kyle.xpm" #include "XPM/stan.xpm" #include "XPM/cartman.xpm" #include "XPM/kenny_mask.xbm" /* Mask for above images. */ #include "XPM/kyle_mask.xbm" #include "XPM/stan_mask.xbm" #include "XPM/cartman_mask.xbm" #include "XPM/kyle_eyemask.xbm" /* Mask for the dude's eyes. */ #include "XPM/stan_eyemask.xbm" #include "XPM/kenny_eyemask.xbm" #include "XPM/cartman_eyemask.xbm" #include "XPM/kyle_out0.xbm" /* Poorly named. */ #include "XPM/kyle_out1.xbm" #include "XPM/kyle_out2.xbm" #include "XPM/kyle_out3.xbm" #include "XPM/kyle_out4.xbm" #include "XPM/kyle_out5.xbm" #include "XPM/kyle_out6.xbm" #include "XPM/kyle_out7.xbm" Pixmap out[11]; Pixmap eyespupil; Pixmap currpmap; Pixmap shapemask; unsigned long eyecolor,outcolor,incolor,skincolor; typedef struct xbms_struct { char ** face; int mask_h, mask_w; unsigned char *mask; int emask_h, emask_w; unsigned char *emask; char skincol[129]; unsigned long skincolor; Pixmap facemask; Pixmap eyemask; Pixmap faceimage; } xbms_struct; struct xbms_struct pics[] = { { kenny_xpm, kenny_mask_height, kenny_mask_width, kenny_mask_bits, kenny_eyemask_height, kenny_eyemask_width, kenny_eyemask_bits, "#F7DEA5", 0L }, { kyle_xpm, kyle_mask_height, kyle_mask_width, kyle_mask_bits, kyle_eyemask_height, kyle_eyemask_width, kyle_eyemask_bits, "#F7DEA5", 0L }, { stan_xpm, stan_mask_height, stan_mask_width, stan_mask_bits, stan_eyemask_height, stan_eyemask_width, stan_eyemask_bits, "#F7DEA5", 0L }, { cartman_xpm, cartman_mask_height, cartman_mask_width, cartman_mask_bits, cartman_eyemask_height, cartman_eyemask_width, cartman_eyemask_bits, "#F7DEA5", 0L } }; typedef struct eyes_struct { float height; float left; float right; float len; } eyes_struct; /* height left right len */ struct eyes_struct eyes[] = { { 35.5, 27.5, 40.5, 3.0 }, /* Kenny */ { 36.5, 27.5, 40.5, 3.0 }, /* Kyle */ { 41.5, 27.5, 40.5, 3.0 }, /* Stan */ { 35.5, 27.5, 40.5, 3.0 } }; /* Cartman */ int who = 0; /* Kenny by default. */ typedef char bool; #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define EYECOLOR "#000000" #define OUTCOLOR "black" #define INCOLOR "white" #define WINDOWMAKER FALSE #define USESHAPE FALSE #define REPTIME 125 bool wmaker = WINDOWMAKER; bool ushape = USESHAPE; char dispname[256] = ""; char eyecol[256] = EYECOLOR; char outcol[256] = OUTCOLOR; char incol[256] = INCOLOR; long repmsec = REPTIME; Atom _XA_GNUSTEP_WM_FUNC; Atom deleteWin; Display *dpy; Window Win[2]; Window Root; XWMHints *hints; GC WinGC; GC mGC; int activeWin; void createWin(Window *win); void repaint(XExposeEvent *ee); void update(); void scanArgs(int argc,char *argv[]); unsigned long getColor(char *colorName); void deletedude(int dude, XpmAttributes pixatt); void loaddude(int dude, XpmAttributes pixatt); void do_nothing() { #if (defined linux || defined sparc) signal(SIGALRM,do_nothing); #endif } int main(int argc, char *argv[]) { XWMHints hints; XSizeHints shints; XGCValues gcv; unsigned long gcm; bool finished=FALSE; XpmAttributes pixatt; XEvent event; struct itimerval loopdelay; int i; srand(time(NULL)); who = (int) (4.0*rand()/(RAND_MAX+1.0)); scanArgs(argc,argv); if((dpy = XOpenDisplay(dispname)) == NULL) { fprintf(stderr,"Unable to open display: %s\n", dispname); exit(1); } _XA_GNUSTEP_WM_FUNC = XInternAtom(dpy, "_GNUSTEP_WM_FUNCTION", False); deleteWin = XInternAtom(dpy, "WM_DELETE_WINDOW", False); Root=DefaultRootWindow(dpy); createWin(&Win[0]); createWin(&Win[1]); hints.window_group = Win[0]; shints.min_width=64; shints.min_height=64; shints.max_width=64; shints.max_height=64; shints.x=0; shints.y=0; if (wmaker) { hints.initial_state = WithdrawnState; hints.icon_window = Win[1]; hints.flags = WindowGroupHint | StateHint | IconWindowHint; shints.flags = PMinSize | PMaxSize | PPosition; activeWin=1; } else { hints.initial_state = NormalState; hints.flags = WindowGroupHint | StateHint; shints.flags = PMinSize | PMaxSize; activeWin=0; } XSetWMHints(dpy, Win[0], &hints); XSetWMNormalHints(dpy, Win[0], &shints); XSetCommand(dpy, Win[0], argv, argc); XStoreName(dpy, Win[0], "speyes"); XSetIconName(dpy, Win[0], "speyes"); gcm = GCForeground|GCBackground|GCGraphicsExposures; gcv.graphics_exposures = False; WinGC = XCreateGC(dpy, Root, gcm, &gcv); XSelectInput(dpy, Win[activeWin], ExposureMask | ButtonPressMask); XSetWMProtocols(dpy, Win[activeWin], &deleteWin, 1); eyecolor=getColor(eyecol); outcolor=getColor(outcol); incolor=getColor(incol); for(i=0; i < 4; i++) pics[i].skincolor = getColor(pics[i].skincol); pixatt.exactColors=FALSE; pixatt.closeness=40000; pixatt.valuemask=XpmExactColors | XpmCloseness; loaddude(who, pixatt); out[0] = XCreateBitmapFromData(dpy, Root, kyle_out0_bits, kyle_out0_width, kyle_out0_height); out[1] = XCreateBitmapFromData(dpy, Root, kyle_out1_bits, kyle_out1_width, kyle_out1_height); out[2] = XCreateBitmapFromData(dpy, Root, kyle_out2_bits, kyle_out2_width, kyle_out2_height); out[3] = XCreateBitmapFromData(dpy, Root, kyle_out3_bits, kyle_out3_width, kyle_out3_height); out[4] = XCreateBitmapFromData(dpy, Root, kyle_out4_bits, kyle_out4_width, kyle_out4_height); out[5] = XCreateBitmapFromData(dpy, Root, kyle_out5_bits, kyle_out5_width, kyle_out5_height); out[6] = XCreateBitmapFromData(dpy, Root, kyle_out6_bits, kyle_out6_width, kyle_out6_height); out[7] = XCreateBitmapFromData(dpy, Root, kyle_out7_bits, kyle_out7_width, kyle_out7_height); eyespupil = XCreateBitmapFromData(dpy, Root, pup2_bits, pup2_width, pup2_height); currpmap = XCreatePixmap(dpy, Root, 64, 64, DefaultDepth(dpy,DefaultScreen(dpy))); shapemask = XCreatePixmap(dpy, Root, 64, 64, 1); mGC = XCreateGC(dpy, shapemask, gcm, &gcv); update(); XMapWindow(dpy, Win[0]); signal(SIGALRM, do_nothing); timerclear(&loopdelay.it_interval); timerclear(&loopdelay.it_value); loopdelay.it_interval.tv_sec = repmsec / 1000; loopdelay.it_interval.tv_usec = (repmsec % 1000) * 1000; loopdelay.it_value.tv_sec = repmsec / 1000; loopdelay.it_value.tv_usec = (repmsec % 1000) * 1000; setitimer(ITIMER_REAL, &loopdelay, 0); while (!finished) { while (XPending(dpy)) { XNextEvent(dpy,&event); switch (event.type) { case Expose: repaint((XExposeEvent *)&event); break; case ClientMessage: if (event.xclient.data.l[0] == deleteWin) { finished=TRUE; } break; case ButtonPress: if(event.xbutton.button == 3 || event.xbutton.button == 2) { deletedude(who,pixatt); who = (who == 3) ? 0 : who+1; loaddude(who, pixatt); } break; } } update(); pause(); } XFreeGC(dpy, WinGC); XFreeGC(dpy, mGC); deletedude(who, pixatt); XFreePixmap(dpy, currpmap); XFreePixmap(dpy, shapemask); XFreePixmap(dpy, out[0]); XFreePixmap(dpy, out[1]); XFreePixmap(dpy, out[2]); XFreePixmap(dpy, out[3]); XFreePixmap(dpy, out[4]); XFreePixmap(dpy, out[5]); XFreePixmap(dpy, out[6]); XFreePixmap(dpy, out[7]); XFreePixmap(dpy, eyespupil); XDestroyWindow(dpy, Win[0]); XDestroyWindow(dpy, Win[1]); XCloseDisplay(dpy); exit(0); } void deletedude(int dude, XpmAttributes pixatt) { XFreePixmap(dpy, pics[dude].eyemask); XFreePixmap(dpy, pics[dude].facemask); XFreePixmap(dpy,pics[dude].faceimage); } void loaddude(int dude, XpmAttributes pixatt) { pics[dude].eyemask = XCreateBitmapFromData(dpy, Root, pics[dude].mask, pics[dude].mask_w, pics[dude].mask_h); pics[dude].facemask = XCreateBitmapFromData(dpy, Root, pics[dude].emask, pics[dude].emask_w, pics[dude].emask_h); XpmCreatePixmapFromData(dpy, Root, pics[dude].face, &pics[dude].faceimage, NULL, &pixatt); } void createWin(Window *win) { XClassHint classHint; *win = XCreateSimpleWindow(dpy, Root, 10, 10, 64, 64,0,0,0); classHint.res_name = "speyes"; classHint.res_class = "speyes"; XSetClassHint(dpy, *win, &classHint); } void repaint(XExposeEvent *ee) { if (ee == NULL) { XCopyArea(dpy,currpmap,Win[activeWin],WinGC,0,0,64,64,0,0); } else { XCopyArea(dpy,currpmap,Win[activeWin],WinGC,ee->x,ee->y,ee->width,ee->height,ee->x,ee->y); } } void update() { Window wroot, wchild; int absx, absy; int relx, rely; static int oldrelx=-1000; static int oldrely=-1000; static int idletime=0; static int masknum=0; static int sleeping=0; unsigned int modmask; int eyex,eyey,len; XQueryPointer(dpy,Win[activeWin],&wroot,&wchild,&absx,&absy,&relx,&rely, &modmask); if (oldrelx == relx && oldrely == rely) { idletime++; } else { idletime = 0; } oldrelx = relx; oldrely = rely; if (idletime > 480) { sleeping = 1; if (masknum < 7) masknum++; } else { sleeping = 0; if (masknum > 0) masknum--; } XCopyArea(dpy, pics[who].eyemask, shapemask, mGC, 0,0,64,64,0,0); if(!(wmaker || ushape)) { XCopyArea(dpy, pics[who].faceimage, currpmap, WinGC, 0,0,64,64,0,0); XSetClipMask(dpy, WinGC, shapemask); } else { XCopyArea(dpy, pics[who].faceimage, currpmap, WinGC, 0,0,64,64,0,0); XShapeCombineMask(dpy, Win[activeWin], ShapeBounding, 0, 0, shapemask, ShapeSet); } XSetClipMask(dpy, WinGC, pics[who].facemask); XSetForeground(dpy, WinGC, pics[who].skincolor); XSetBackground(dpy, WinGC, -1L); XCopyPlane(dpy, out[masknum], currpmap, WinGC, 0,0,64,64,0,0,1); XSetClipMask(dpy, WinGC, None); XSetForeground(dpy, WinGC, eyecolor); len = sqrt((relx-eyes[who].left)*(relx-eyes[who].left) + ((rely-eyes[who].height)*(rely-eyes[who].height)/4.0)); if (len > eyes[who].len) { eyex = (int) (eyes[who].left + (eyes[who].len * (relx - eyes[who].left))/len); eyey = (int) (eyes[who].height + (eyes[who].len*(rely - eyes[who].height))/len); } else { eyex = relx; eyey = rely; } if(masknum == 0) XCopyPlane(dpy, eyespupil, currpmap, WinGC, 0,0,3,4,eyex-3,eyey-4,1); len = (int) sqrt((relx-eyes[who].right)*(relx-eyes[who].right) + ((rely-eyes[who].height)*(rely-eyes[who].height)/4.0)); if (len > eyes[who].len) { eyex = (int) (eyes[who].right + (eyes[who].len*(relx-eyes[who].right))/len); eyey = (int) (eyes[who].height + (eyes[who].len*(rely-eyes[who].right))/len); } else { eyex = relx; eyey = rely; } if(masknum == 0) XCopyPlane(dpy, eyespupil, currpmap, WinGC, 0,0,3,4,eyex-3,eyey-4,1); XSetClipMask(dpy, WinGC, pics[who].facemask); /* XSetForeground(dpy, WinGC, outcolor); XCopyPlane(dpy, eyesout[masknum], currpmap, WinGC, 0,0,64,64,0,0,1); XCopyArea(dpy, eyesout[masknum], currpmap, WinGC, 0,0,64,64,0,0); */ XSetClipMask(dpy, WinGC, None); repaint(NULL); } void scanArgs(int argc, char *argv[]) { int c,i; int opt_index; bool helpflag = FALSE; bool errflag = FALSE; static char *names[] = { "kenny", "kyle", "stan", "cartman", NULL }; static struct option long_opts[] = { {"help", no_argument, NULL, 'h'}, {"withdrawn", no_argument, NULL, 'w'}, {"shape", no_argument, NULL, 's'}, {"pupil", required_argument, NULL, 'p'}, {"face", required_argument, NULL, 'f'}, {"time", required_argument, NULL, 't'}, {"display", required_argument, NULL, 'd'}, {0, 0, 0, 0} }; while(1) { opt_index = 0; c = getopt_long_only(argc, argv, "hwsp:f:t:d:", long_opts, &opt_index); if (c == -1) break; switch (c) { case 'h': helpflag = TRUE; break; case 'w': wmaker = TRUE; break; case 's': ushape = TRUE; break; case 'p': strncpy(eyecol, optarg, 255); eyecol[255] = '\0'; break; case 'f': for(i = 0; names[i]; i++) if(strcasecmp(optarg, names[i]) == 0) break; if(i < 4) who = i; break; case 'o': strncpy(outcol, optarg, 255); outcol[255] = '\0'; break; case 't': repmsec = atol(optarg); break; case 'd': strncpy(dispname, optarg, 255); dispname[255] = '\0'; break; default: errflag = TRUE; break; } } if (errflag) { fprintf(stderr, "Usage: %s [-h] [-ws] [-f face] [-p pupclr] [-display disp]\n", argv[0]); exit(1); } if (helpflag) { fprintf(stderr,"speyes %s - The world's most useless WindowMaker dock app.\n", VERSION); fprintf(stderr,"by Audin Malmin (amalmin@halcyon.com)\n\n"); fprintf(stderr,"Usage: %s [-h] [-ws] [-p pupclr] [-o outclr] [-i inclr] [-display disp]\n", argv[0]); fprintf(stderr,"short long argument description\n"); fprintf(stderr," -h --help display this help screen\n"); fprintf(stderr," -w --withdrawn withdraw window (for WindowMaker)\n"); fprintf(stderr," -s --shape use shaped window\n"); fprintf(stderr," -f --face set face: kenny, kyle, stan, cartman (default is random)\n"); fprintf(stderr," -p --pupil pupclr set the colour of the eyes' pupils (default %s)\n", EYECOLOR); fprintf(stderr," -t --time msec set the interation time in msec (default %d)\n", REPTIME); fprintf(stderr," -d --display disp set the X display to use\n"); fprintf(stderr," -display disp set the X display to use\n"); exit(0); } } unsigned long getColor(char *colorName) { XColor Color; XWindowAttributes Attributes; XGetWindowAttributes(dpy, Root, &Attributes); Color.pixel = 0; XParseColor (dpy, Attributes.colormap, colorName, &Color); Color.flags=DoRed | DoGreen | DoBlue; XAllocColor (dpy, Attributes.colormap, &Color); return Color.pixel; }