/*\ ||| Written By Fredrik Hübinette ||| All rights reserved. No warrenties, use at your own risk. ||| This source is distributed under the GNU GENERAL PUBLIC LICENCE, ||| see the file "COPYING" for more information. \*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "plugger.h" Display *dpy=0; static Window topLevel; int buttonsize=10; #define STATE_PLAY 1 #define STATE_PAUSE 2 #define STATE_STOP 3 int state=STATE_STOP; int pid=-1; int repeats=0; GC gc_white; GC gc_black; GC gc_gray; int bx; int by; int windowed=0; XPoint coord(int x, int y) { XPoint ret; ret.x=(x+1) * buttonsize / 16 + bx; ret.y=y * buttonsize / 16 + by; return ret; } void redraw() { static int old_buttonsize = -1; XWindowAttributes attr; XPoint points[5]; if(windowed && state == STATE_PLAY) return; XGetWindowAttributes(dpy, topLevel, &attr); buttonsize = attr.width/3; if(attr.height < buttonsize) buttonsize=attr.height; if(old_buttonsize != buttonsize) { old_buttonsize=buttonsize; XFillRectangle(dpy, topLevel, gc_white, 0,0,attr.width, attr.height); } bx=(attr.width - buttonsize*3)/2; by=(attr.height - buttonsize)/2; /* play */ points[0]=coord(4,2); points[1]=coord(5,2); points[2]=coord(10,7); points[3]=coord(10,8); points[4]=coord(5,13); points[5]=coord(4,13); XFillPolygon(dpy, topLevel, state==STATE_PLAY ? gc_gray : gc_black, points, 6, Convex, CoordModeOrigin); /* pause */ XFillRectangle(dpy, topLevel, state==STATE_PAUSE ? gc_gray : gc_black, bx + buttonsize + buttonsize*3/16, by + buttonsize * 2/16, buttonsize * 3/16, buttonsize * 11/16); XFillRectangle(dpy, topLevel, state==STATE_PAUSE ? gc_gray : gc_black, bx + buttonsize + buttonsize*9/16, by + buttonsize * 2/16, buttonsize * 3/16, buttonsize * 11/16); /* stop */ XFillRectangle(dpy, topLevel, state==STATE_STOP ? gc_gray : gc_black, bx+buttonsize*2 + buttonsize*3/16, by+buttonsize * 3/16, buttonsize * 9/16, buttonsize * 9/16); } int igetenv(char *var, int def) { char *tmp=getenv(var); if(!tmp) return def; return atoi(tmp); } void my_play(char **argv) { if(state != STATE_STOP) { if(!kill(-pid, SIGCONT)) { state=STATE_PLAY; return; } } pid=fork(); if(pid == -1) { state=STATE_STOP; return; } if(!pid) { char *cmd[4]; MY_SETPGRP(); cmd[0]="/bin/sh"; cmd[1]="-c"; cmd[2]=argv[1]; cmd[3]=0; execvp(cmd[0], cmd); exit(EX_UNAVAILABLE); }else{ state=STATE_PLAY; if(!repeats) repeats=igetenv("repeats",1); repeats--; } } void my_pause(char **argv) { if(state != STATE_STOP) { if(!kill(-pid, SIGSTOP)) state = STATE_PAUSE; else state = STATE_STOP; return; } } void low_die() { if(pid > 0) plugger_kill_group(pid, 0); _exit(0); } void my_stop(char **argv) { if(state == STATE_PAUSE) my_play(argv); if(state == STATE_PLAY) { if(pid > 0) plugger_kill_group(pid, 0); state=STATE_STOP; repeats=0; } } int die(Display *dpy, XErrorEvent *ev) { low_die(); } int die2(Display *dpy) { low_die(); } void sigdie(int sig) { low_die(); } Bool AllXEventsPredicate(Display *dpy, XEvent *ev, char *arg) { return True; } char *geometry; int main(int argc, char **argv) { int old_state; XColor colour; XClassHint classhint; XSetWindowAttributes attr; XSizeHints wmHints; char defaultGeometry[256]; if(argc < 2) { fprintf(stderr,"Please run plugger-controller from plugger only.\n"); exit(1); } if(!(dpy = XOpenDisplay(getenv("DISPLAY")))) { fprintf(stderr,"%s: unable to open display %s\n", argv[0], XDisplayName(getenv("DISPLAY"))); return False; } if(plugger_strstr(argv[1],"$window") || plugger_strstr(argv[1],"$hexwindow")) windowed=1; wmHints.x=9000; wmHints.y=9000; wmHints.min_width = 48; wmHints.min_height = 16; wmHints.base_width = 60; wmHints.base_height = 20; wmHints.flags=PPosition | USPosition | PMinSize; attr.border_pixel = 0; attr.background_pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)); attr.event_mask = ExposureMask; if(!windowed) attr.event_mask |= ButtonPressMask; attr.override_redirect=0; topLevel = XCreateWindow(dpy, DefaultRootWindow(dpy), wmHints.x, wmHints.y, 60, 20, 1, CopyFromParent, InputOutput, CopyFromParent, (CWBorderPixel| CWEventMask| CWOverrideRedirect| CWBackPixel), &attr); gc_black=XCreateGC(dpy,topLevel,0,0); XSetForeground(dpy,gc_black,BlackPixel(dpy,DefaultScreen(dpy))); gc_white=XCreateGC(dpy,topLevel,0,0); XSetForeground(dpy,gc_white,WhitePixel(dpy,DefaultScreen(dpy))); gc_gray=XCreateGC(dpy,topLevel,0,0); colour.red=0x0000; colour.green=0xa000; colour.blue=0x0000; colour.pixel=0; colour.flags=0; XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &colour); XSetForeground(dpy,gc_gray,colour.pixel); XSetWMNormalHints(dpy, topLevel, &wmHints); classhint.res_name = "plugger-controller"; classhint.res_class = "plugger-controller"; XSetClassHint(dpy, topLevel, &classhint); XMapRaised(dpy, topLevel); XSetIOErrorHandler(die2); XSetErrorHandler(die); old_state=state; { static char buffer[128]; char *tmp; sprintf(buffer,"window=%ld",(long)topLevel); putenv(buffer); tmp=buffer+strlen(buffer)+1; sprintf(tmp,"hexwindow=0x%lx",(long)topLevel); putenv(tmp); } signal(SIGHUP, sigdie); signal(SIGINT, sigdie); signal(SIGTERM, sigdie); if(igetenv("autostart",1)) my_play(argv); while(1) { struct timeval tv; fd_set fds; XEvent ev; if(state != old_state) { redraw(); old_state=state; } FD_ZERO(&fds); FD_SET(ConnectionNumber(dpy),&fds); tv.tv_sec=0; tv.tv_usec=1000000/5; /* Check if the subprocess died 5 times / sec */ select(ConnectionNumber(dpy)+1, &fds, NULL, NULL, &tv); if(pid != -1) { int status; if(waitpid(pid, &status, WNOHANG) > 0) { pid=-1; if(state == STATE_PLAY) { state = STATE_STOP; if(repeats) my_play(argv); } } } while(XCheckIfEvent(dpy, &ev, AllXEventsPredicate, NULL)) { switch(ev.type) { case ButtonPress: if(ev.xbutton.button == 1) { int button = (ev.xbutton.x - bx) / buttonsize; switch(button) { case 0: /* play */ my_play(argv); break; case 1: /* pause*/ my_pause(argv);break; case 2: /* stop */ my_stop(argv); break; } } break; case Expose: if(ev.xexpose.count) break; case ResizeRequest: case MapNotify: redraw(); break; #ifdef DEBUG default: fprintf(stderr,"Unknown event %d\n",ev.type); #endif } } } }