#include "wmmixer-alsa.h" int main(int argc, char **argv) { XGCValues gcv; unsigned long gcm; int exact,left,right,device_index,i; XpmAttributes xpmattr; XpmColorSymbol xpmcsym[4]; elementinfo *e; scanArgs(argc, argv); initXWin(argc, argv); exact=left=right=device_index=-1; init_mixer(); cure=element; e=element; while(e) { if(!strcasecmp(e->info.eid.name,"Master Volume")) e->icon=0; else if(!strcasecmp(e->info.eid.name,"PCM Volume")) e->icon=1; else if(!strcasecmp(e->info.eid.name,"MIC Volume")) e->icon=5; else if(!strcasecmp(e->info.eid.name,"Line Volume")) e->icon=4; else if(!strcasecmp(e->info.eid.name,"CD Volume")) e->icon=3; else if(!strcasecmp(e->info.eid.name,"Synth Volume")) e->icon=2; else if(!strcasecmp(e->info.eid.name,"PC Speaker Volume")) e->icon=6; /* * bass = 7 * treble = 8 */ else e->icon=9; e=e->next; } gcm=GCGraphicsExposures; gcv.graphics_exposures=0; gc_gc=XCreateGC(d_display, w_root, gcm, &gcv); color[0]=mixColor(ledcolor, 0, backcolor, 100); color[1]=mixColor(ledcolor, 100, backcolor, 0); color[2]=mixColor(ledcolor, 60, backcolor, 40); color[3]=mixColor(ledcolor, 25, backcolor, 75); xpmcsym[0].name="back_color"; xpmcsym[0].value=NULL;; xpmcsym[0].pixel=color[0]; xpmcsym[1].name="led_color_high"; xpmcsym[1].value=NULL;; xpmcsym[1].pixel=color[1]; xpmcsym[2].name="led_color_med"; xpmcsym[2].value=NULL;; xpmcsym[2].pixel=color[2]; xpmcsym[3].name="led_color_low"; xpmcsym[3].value=NULL;; xpmcsym[3].pixel=color[3]; xpmattr.numsymbols=4; xpmattr.colorsymbols=xpmcsym; xpmattr.exactColors=0; xpmattr.closeness=40000; xpmattr.valuemask=XpmColorSymbols | XpmExactColors | XpmCloseness; XpmCreatePixmapFromData(d_display, w_root, wmmixer_xpm, &pm_main, &pm_mask, &xpmattr); XpmCreatePixmapFromData(d_display, w_root, tile_xpm, &pm_tile, NULL, &xpmattr); XpmCreatePixmapFromData(d_display, w_root, icons_xpm, &pm_icon, NULL, &xpmattr); pm_disp=XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, DefaultScreen(d_display))); if(wmaker || ushape || astep) XShapeCombineMask(d_display, w_activewin, ShapeBounding, winsize/2-32, winsize/2-32, pm_mask, ShapeSet); else XCopyArea(d_display, pm_tile, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0); XSetClipMask(d_display, gc_gc, pm_mask); XCopyArea(d_display, pm_main, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0); XSetClipMask(d_display, gc_gc, None); if(count==0) fprintf(stderr,"%s : Sorry, no supported channels found.\n", NAME); else { int done=0; XEvent xev; checkVol(); XSelectInput(d_display, w_activewin, ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask); XMapWindow(d_display, w_main); while(!done) { while(XPending(d_display)) { XNextEvent(d_display, &xev); switch(xev.type) { case Expose: repaint(); break; case ButtonPress: pressEvent(&xev.xbutton); break; case ButtonRelease: releaseEvent(&xev.xbutton); break; case MotionNotify: motionEvent(&xev.xmotion); break; case ClientMessage: if(xev.xclient.data.l[0]==deleteWin) done=1; break; } } if(btnstate & (BTNPREV | BTNNEXT)) { rpttimer++; if(rpttimer>=RPTINTERVAL) { if(btnstate & BTNNEXT) { cure=cure->next; if(!cure) cure=element; } else { cure=cure->prev; if(!cure) { elementinfo *e; e=element; while(e->next) e=e->next; cure=e; } } checkVol(); rpttimer=0; } } else checkVol(); XFlush(d_display); usleep(50000); } } XFreeGC(d_display, gc_gc); XFreePixmap(d_display, pm_main); XFreePixmap(d_display, pm_tile); XFreePixmap(d_display, pm_disp); XFreePixmap(d_display, pm_mask); XFreePixmap(d_display, pm_icon); freeXWin(); return 0; } void initXWin(int argc, char **argv) { int pos; XWMHints wmhints; XSizeHints shints; winsize=astep ? ASTEPSIZE : NORMSIZE; if((d_display=XOpenDisplay(display))==NULL) { fprintf(stderr,"%s : Unable to open X display '%s'.\n", NAME, XDisplayName(display)); exit(1); } _XA_GNUSTEP_WM_FUNC=XInternAtom(d_display, "_GNUSTEP_WM_FUNCTION", 0); deleteWin=XInternAtom(d_display, "WM_DELETE_WINDOW", 0); w_root=DefaultRootWindow(d_display); shints.x=0; shints.y=0; shints.flags=0; pos=(XWMGeometry(d_display, DefaultScreen(d_display), position, NULL, 0, &shints, &shints.x, &shints.y, &shints.width, &shints.height, &shints.win_gravity) & (XValue | YValue)); shints.min_width=winsize; shints.min_height=winsize; shints.max_width=winsize; shints.max_height=winsize; shints.base_width=winsize; shints.base_height=winsize; shints.flags=PMinSize | PMaxSize | PBaseSize; createWin(&w_main, shints.x, shints.y); if(wmaker || astep || pos) shints.flags |= USPosition; if(wmaker) { wmhints.initial_state=WithdrawnState; wmhints.flags=WindowGroupHint | StateHint | IconWindowHint; createWin(&w_icon, shints.x, shints.y); w_activewin=w_icon; wmhints.icon_window=w_icon; } else { wmhints.initial_state=NormalState; wmhints.flags=WindowGroupHint | StateHint; w_activewin=w_main; } wmhints.window_group=w_main; XSetWMHints(d_display, w_main, &wmhints); XSetWMNormalHints(d_display, w_main, &shints); XSetCommand(d_display, w_main, argv, argc); XStoreName(d_display, w_main, NAME); XSetIconName(d_display, w_main, NAME); XSetWMProtocols(d_display, w_activewin, &deleteWin, 1); } void freeXWin() { XDestroyWindow(d_display, w_main); if(wmaker) XDestroyWindow(d_display, w_icon); XCloseDisplay(d_display); } void createWin(Window *win, int x, int y) { XClassHint classHint; *win=XCreateSimpleWindow(d_display, w_root, x, y, winsize, winsize, 0, 0, 0); classHint.res_name=NAME; classHint.res_class=CLASS; XSetClassHint(d_display, *win, &classHint); } unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2){ XColor color, color1, color2; XWindowAttributes winattr; XGetWindowAttributes(d_display, w_root, &winattr); XParseColor(d_display, winattr.colormap, colorname1, &color1); XParseColor(d_display, winattr.colormap, colorname2, &color2); color.pixel=0; color.red=(color1.red*prop1+color2.red*prop2)/(prop1+prop2); color.green=(color1.green*prop1+color2.green*prop2)/(prop1+prop2); color.blue=(color1.blue*prop1+color2.blue*prop2)/(prop1+prop2); color.flags=DoRed | DoGreen | DoBlue; XAllocColor(d_display, winattr.colormap, &color); return color.pixel; } void show_params(void) { fprintf(stdout,"wmmixer-alsa %s\t\tby Sam Hawker\n" "\t\t\tAdded support for ALSA by\n" "\t\t\tMartin Dahl \n\n" "Usage: wmmixer-alsa [options]\n\n" "\t-h\t\tDisplay this help screen\n" "\t-w\t\tUse WithdrawnState\n" "\t-s\t\tShaped window\n" "\t-a\t\tUse smaller window\n" "\t-l \t\tColor for led display\n" "\t-b \t\tColor for background\n" "\t-p \t\tWindow position\n" "\t-d \t\tTarget display\n",VERSION); exit(0); } void scanArgs(int argc, char **argv) { int x; memset(backcolor,0,32); memset(ledcolor,0,32); memset(display,0,32); memset(position,0,32); strncpy(ledcolor,LEDCOLOR,32); strncpy(backcolor,BACKCOLOR,32); strcpy(display,""); strcpy(position,""); wmaker=ushape=astep=0; btnstate=rpttimer=0; dragging=count=0; for(x=1;xelement.data.volume1.pvoices[0],cure->info.data.volume1.prange[0].min,cure->info.data.volume1.prange[0].max,0,100); nr=convert_range(cure->element.data.volume1.pvoices[1],cure->info.data.volume1.prange[1].min,cure->info.data.volume1.prange[1].max,0,100); if(1) { curleft=nl; curright=nr; } else { if(nl!=curleft||nr!=curright) { if(nl!=curleft) { curleft=nl; drawLeft(); } if(nr!=curright) { curright=nr; drawRight(); } } } update(); repaint(); } void setVol(int left, int right) { int err; callbacks(); cure->element.data.volume1.pvoices[0]=convert_range(left,0,100,cure->info.data.volume1.prange[0].min,cure->info.data.volume1.prange[0].max); if(cure->element.data.volume1.pvoices[0]>cure->info.data.volume1.prange[0].max) cure->element.data.volume1.pvoices[0]=cure->info.data.volume1.prange[0].max; if(cure->element.data.volume1.pvoices[0]info.data.volume1.prange[0].min) cure->element.data.volume1.pvoices[0]=cure->info.data.volume1.prange[0].min; cure->element.data.volume1.pvoices[1]=convert_range(right,0,100,cure->info.data.volume1.prange[1].min,cure->info.data.volume1.prange[1].max); if(cure->element.data.volume1.pvoices[1]>cure->info.data.volume1.prange[1].max) cure->element.data.volume1.pvoices[1]=cure->info.data.volume1.prange[1].max; if((err=snd_mixer_element_write(mixer_handle,&cure->element))<0) fprintf(stderr,"Mixer element write error: %s\n",snd_strerror(err)); return; } void callbacks(void) { int err; snd_mixer_callbacks_t callbacks; memset(&callbacks,0,sizeof(callbacks)); callbacks.rebuild=NULL; callbacks.element=NULL; callbacks.group=NULL; if((err=snd_mixer_read(mixer_handle,&callbacks))<0) { fprintf(stderr,"Callbacks error: %s\n",snd_strerror(err)); return; } return; } int convert_range(int val, int omin, int omax, int nmin, int nmax) { int orange=omax-omin, nrange=nmax-nmin; if(orange==0) return 0; return rint((((double)nrange*((double)val-(double)omin))+((double)orange/2.0))/(double)orange+(double)nmin); } void pressEvent(XButtonEvent *xev) { int x=xev->x-(winsize/2-32); int y=xev->y-(winsize/2-32); if(x>=5 && y>=33 && x<=16 && y<=43) { cure=cure->prev; if(!cure) { elementinfo *e; e=element; while(e->next) e=e->next; cure=e; } btnstate |= BTNPREV; rpttimer=0; drawBtns(BTNPREV); checkVol(); return; } if(x>=17 && y>=33 && x<=28 && y<=43) { cure=cure->next; if(!cure) cure=element; btnstate|=BTNNEXT; rpttimer=0; drawBtns(BTNNEXT); checkVol(); return; } if(x>=37 && x<=56 && y>=8 && y<=56) { int v=((60-y)*100)/(2*25); dragging=1; if(x<=50) setVol(v,curright); if(x>=45) setVol(curleft,v); checkVol(); return; } /* if(x>=5 && y>=47 && x<=28 && y<=57) { int nl,nr,flags; mixer.DeviceSet(channel[curchannel]); mixer.Read(&nl,&nr,&flags); if(flags & SND_MIXER_DFLG_MUTE) { btnstate &= ~BTNREC; flags &= ~SND_MIXER_DFLG_MUTE; } else { btnstate |= BTNREC; flags |= SND_MIXER_DFLG_MUTE; } mixer.Write(nl,nr,flags); checkVol(); return; }*/ } void releaseEvent(XButtonEvent *xev) { dragging=0; btnstate &= ~(BTNPREV | BTNNEXT); drawBtns(BTNPREV | BTNNEXT); repaint(); } void motionEvent(XMotionEvent *xev) { int x=xev->x-(winsize/2-32); int y=xev->y-(winsize/2-32); if(x>=37 && x<=56 && y>=8 && dragging) { int v=((60-y)*100)/(2*25); if(v<0) v=0; if(x<=50) setVol(v,curright); if(x>=45) setVol(curleft,v); checkVol(); } } void repaint() { XEvent xev; XCopyArea(d_display, pm_disp, w_activewin, gc_gc, 0, 0, 64, 64, winsize/2-32, winsize/2-32); while(XCheckTypedEvent(d_display, Expose, &xev)); } void update() { XCopyArea(d_display, pm_icon, pm_disp, gc_gc, cure->icon*22, 0, 22, 22, 6, 5); drawLeft(); drawRight(); drawBtns(BTNREC); } void drawLeft() { int i; XSetForeground(d_display, gc_gc, color[1]); for(i=0;i<25;i++) { if(i==(curleft*25)/100) XSetForeground(d_display, gc_gc, color[3]); XFillRectangle(d_display, pm_disp, gc_gc, 37, 55-2*i, 9, 1); } } void drawRight() { int i; XSetForeground(d_display, gc_gc, color[1]); for(i=0;i<25;i++) { if(i==(curright*25)/100) XSetForeground(d_display, gc_gc, color[3]); XFillRectangle(d_display, pm_disp, gc_gc, 48, 55-2*i, 9, 1); } } void drawBtns(int btns) { if(btns & BTNPREV) drawBtn(5, 33, 12, 11, (btnstate & BTNPREV)); if(btns & BTNNEXT) drawBtn(17, 33, 12, 11, (btnstate & BTNNEXT)); if(btns & BTNREC) drawBtn(5, 47, 24, 11, (btnstate & BTNREC)); } void drawBtn(int x, int y, int w, int h, int down) { if(!down) XCopyArea(d_display, pm_main, pm_disp, gc_gc, x, y, w, h, x, y); else { XCopyArea(d_display, pm_main, pm_disp, gc_gc, x, y, 1, h-1, x+w-1, y+1); XCopyArea(d_display, pm_main, pm_disp, gc_gc, x+w-1, y+1, 1, h-1, x, y); XCopyArea(d_display, pm_main, pm_disp, gc_gc, x, y, w-1, 1, x+1, y+h-1); XCopyArea(d_display, pm_main, pm_disp, gc_gc, x+1, y+h-1, w-1, 1, x, y); } }