wmmixer-alsa: Add to repository.
[dockapps.git] / wmmixer-alsa / wmmixer-alsa.c
blob13dba796ee62ca04f365b18cd93ef23415caede4
1 #include "wmmixer-alsa.h"
3 int main(int argc, char **argv)
5 XGCValues gcv;
6 unsigned long gcm;
7 int exact,left,right,device_index,i;
8 XpmAttributes xpmattr;
9 XpmColorSymbol xpmcsym[4];
10 elementinfo *e;
12 scanArgs(argc, argv);
13 initXWin(argc, argv);
14 exact=left=right=device_index=-1;
16 init_mixer();
17 cure=element;
18 e=element;
19 while(e)
21 if(!strcasecmp(e->info.eid.name,"Master Volume"))
22 e->icon=0;
23 else if(!strcasecmp(e->info.eid.name,"PCM Volume"))
24 e->icon=1;
25 else if(!strcasecmp(e->info.eid.name,"MIC Volume"))
26 e->icon=5;
27 else if(!strcasecmp(e->info.eid.name,"Line Volume"))
28 e->icon=4;
29 else if(!strcasecmp(e->info.eid.name,"CD Volume"))
30 e->icon=3;
31 else if(!strcasecmp(e->info.eid.name,"Synth Volume"))
32 e->icon=2;
33 else if(!strcasecmp(e->info.eid.name,"PC Speaker Volume"))
34 e->icon=6;
36 * bass = 7
37 * treble = 8
39 else
40 e->icon=9;
41 e=e->next;
44 gcm=GCGraphicsExposures;
45 gcv.graphics_exposures=0;
46 gc_gc=XCreateGC(d_display, w_root, gcm, &gcv);
48 color[0]=mixColor(ledcolor, 0, backcolor, 100);
49 color[1]=mixColor(ledcolor, 100, backcolor, 0);
50 color[2]=mixColor(ledcolor, 60, backcolor, 40);
51 color[3]=mixColor(ledcolor, 25, backcolor, 75);
53 xpmcsym[0].name="back_color";
54 xpmcsym[0].value=NULL;;
55 xpmcsym[0].pixel=color[0];
56 xpmcsym[1].name="led_color_high";
57 xpmcsym[1].value=NULL;;
58 xpmcsym[1].pixel=color[1];
59 xpmcsym[2].name="led_color_med";
60 xpmcsym[2].value=NULL;;
61 xpmcsym[2].pixel=color[2];
62 xpmcsym[3].name="led_color_low";
63 xpmcsym[3].value=NULL;;
64 xpmcsym[3].pixel=color[3];
65 xpmattr.numsymbols=4;
66 xpmattr.colorsymbols=xpmcsym;
67 xpmattr.exactColors=0;
68 xpmattr.closeness=40000;
69 xpmattr.valuemask=XpmColorSymbols | XpmExactColors | XpmCloseness;
70 XpmCreatePixmapFromData(d_display, w_root, wmmixer_xpm, &pm_main, &pm_mask, &xpmattr);
71 XpmCreatePixmapFromData(d_display, w_root, tile_xpm, &pm_tile, NULL, &xpmattr);
72 XpmCreatePixmapFromData(d_display, w_root, icons_xpm, &pm_icon, NULL, &xpmattr);
73 pm_disp=XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, DefaultScreen(d_display)));
75 if(wmaker || ushape || astep)
76 XShapeCombineMask(d_display, w_activewin, ShapeBounding, winsize/2-32, winsize/2-32, pm_mask, ShapeSet);
77 else
78 XCopyArea(d_display, pm_tile, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
80 XSetClipMask(d_display, gc_gc, pm_mask);
81 XCopyArea(d_display, pm_main, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
82 XSetClipMask(d_display, gc_gc, None);
84 if(count==0)
85 fprintf(stderr,"%s : Sorry, no supported channels found.\n", NAME);
86 else
88 int done=0;
89 XEvent xev;
91 checkVol();
92 XSelectInput(d_display, w_activewin, ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
93 XMapWindow(d_display, w_main);
95 while(!done)
97 while(XPending(d_display))
99 XNextEvent(d_display, &xev);
100 switch(xev.type)
102 case Expose:
103 repaint();
104 break;
105 case ButtonPress:
106 pressEvent(&xev.xbutton);
107 break;
108 case ButtonRelease:
109 releaseEvent(&xev.xbutton);
110 break;
111 case MotionNotify:
112 motionEvent(&xev.xmotion);
113 break;
114 case ClientMessage:
115 if(xev.xclient.data.l[0]==deleteWin)
116 done=1;
117 break;
121 if(btnstate & (BTNPREV | BTNNEXT))
123 rpttimer++;
124 if(rpttimer>=RPTINTERVAL)
126 if(btnstate & BTNNEXT)
128 cure=cure->next;
129 if(!cure)
130 cure=element;
132 else
134 cure=cure->prev;
135 if(!cure)
137 elementinfo *e;
138 e=element;
139 while(e->next)
140 e=e->next;
141 cure=e;
144 checkVol();
145 rpttimer=0;
148 else
149 checkVol();
150 XFlush(d_display);
151 usleep(50000);
154 XFreeGC(d_display, gc_gc);
155 XFreePixmap(d_display, pm_main);
156 XFreePixmap(d_display, pm_tile);
157 XFreePixmap(d_display, pm_disp);
158 XFreePixmap(d_display, pm_mask);
159 XFreePixmap(d_display, pm_icon);
160 freeXWin();
161 return 0;
164 void initXWin(int argc, char **argv)
166 int pos;
167 XWMHints wmhints;
168 XSizeHints shints;
170 winsize=astep ? ASTEPSIZE : NORMSIZE;
172 if((d_display=XOpenDisplay(display))==NULL)
174 fprintf(stderr,"%s : Unable to open X display '%s'.\n", NAME, XDisplayName(display));
175 exit(1);
177 _XA_GNUSTEP_WM_FUNC=XInternAtom(d_display, "_GNUSTEP_WM_FUNCTION", 0);
178 deleteWin=XInternAtom(d_display, "WM_DELETE_WINDOW", 0);
180 w_root=DefaultRootWindow(d_display);
182 shints.x=0;
183 shints.y=0;
184 shints.flags=0;
185 pos=(XWMGeometry(d_display, DefaultScreen(d_display), position, NULL, 0, &shints, &shints.x, &shints.y, &shints.width, &shints.height, &shints.win_gravity) & (XValue | YValue));
186 shints.min_width=winsize;
187 shints.min_height=winsize;
188 shints.max_width=winsize;
189 shints.max_height=winsize;
190 shints.base_width=winsize;
191 shints.base_height=winsize;
192 shints.flags=PMinSize | PMaxSize | PBaseSize;
194 createWin(&w_main, shints.x, shints.y);
196 if(wmaker || astep || pos)
197 shints.flags |= USPosition;
198 if(wmaker)
200 wmhints.initial_state=WithdrawnState;
201 wmhints.flags=WindowGroupHint | StateHint | IconWindowHint;
202 createWin(&w_icon, shints.x, shints.y);
203 w_activewin=w_icon;
204 wmhints.icon_window=w_icon;
206 else
208 wmhints.initial_state=NormalState;
209 wmhints.flags=WindowGroupHint | StateHint;
210 w_activewin=w_main;
212 wmhints.window_group=w_main;
213 XSetWMHints(d_display, w_main, &wmhints);
214 XSetWMNormalHints(d_display, w_main, &shints);
215 XSetCommand(d_display, w_main, argv, argc);
216 XStoreName(d_display, w_main, NAME);
217 XSetIconName(d_display, w_main, NAME);
218 XSetWMProtocols(d_display, w_activewin, &deleteWin, 1);
221 void freeXWin()
223 XDestroyWindow(d_display, w_main);
224 if(wmaker)
225 XDestroyWindow(d_display, w_icon);
226 XCloseDisplay(d_display);
229 void createWin(Window *win, int x, int y)
231 XClassHint classHint;
232 *win=XCreateSimpleWindow(d_display, w_root, x, y, winsize, winsize, 0, 0, 0);
233 classHint.res_name=NAME;
234 classHint.res_class=CLASS;
235 XSetClassHint(d_display, *win, &classHint);
238 unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2){
239 XColor color, color1, color2;
240 XWindowAttributes winattr;
241 XGetWindowAttributes(d_display, w_root, &winattr);
242 XParseColor(d_display, winattr.colormap, colorname1, &color1);
243 XParseColor(d_display, winattr.colormap, colorname2, &color2);
244 color.pixel=0;
245 color.red=(color1.red*prop1+color2.red*prop2)/(prop1+prop2);
246 color.green=(color1.green*prop1+color2.green*prop2)/(prop1+prop2);
247 color.blue=(color1.blue*prop1+color2.blue*prop2)/(prop1+prop2);
248 color.flags=DoRed | DoGreen | DoBlue;
249 XAllocColor(d_display, winattr.colormap, &color);
250 return color.pixel;
253 void show_params(void)
255 fprintf(stdout,"wmmixer-alsa %s\t\tby Sam Hawker\n"
256 "\t\t\tAdded support for ALSA by\n"
257 "\t\t\tMartin Dahl <dahlm@vf.telia.no>\n\n"
258 "Usage: wmmixer-alsa [options]\n\n"
259 "\t-h\t\tDisplay this help screen\n"
260 "\t-w\t\tUse WithdrawnState\n"
261 "\t-s\t\tShaped window\n"
262 "\t-a\t\tUse smaller window\n"
263 "\t-l <color>\t\tColor for led display\n"
264 "\t-b <color>\t\tColor for background\n"
265 "\t-p <position>\t\tWindow position\n"
266 "\t-d <display>\t\tTarget display\n",VERSION);
267 exit(0);
270 void scanArgs(int argc, char **argv)
272 int x;
274 memset(backcolor,0,32);
275 memset(ledcolor,0,32);
276 memset(display,0,32);
277 memset(position,0,32);
278 strncpy(ledcolor,LEDCOLOR,32);
279 strncpy(backcolor,BACKCOLOR,32);
280 strcpy(display,"");
281 strcpy(position,"");
282 wmaker=ushape=astep=0;
283 btnstate=rpttimer=0;
284 dragging=count=0;
286 for(x=1;x<argc;x++)
288 if(argv[x][0]!='-') show_params();
289 else switch(argv[x][1])
291 case 'w':
292 wmaker=1;
293 break;
294 case 's':
295 ushape=1;
296 break;
297 case 'a':
298 astep=1;
299 break;
300 case 'l':
301 strncpy(ledcolor,argv[x+1],32);
302 x++;
303 break;
304 case 'b':
305 strncpy(backcolor,argv[x+1],32);
306 x++;
307 break;
308 case 'p':
309 strncpy(position,argv[x+1],32);
310 x++;
311 break;
312 case 'd':
313 strncpy(display,argv[x+1],32);
314 x++;
315 break;
316 default:
317 show_params();
318 break;
321 return;
324 void checkVol(void)
326 int nl=0,nr=0;
327 nl=convert_range(cure->element.data.volume1.pvoices[0],cure->info.data.volume1.prange[0].min,cure->info.data.volume1.prange[0].max,0,100);
328 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);
330 if(1)
332 curleft=nl;
333 curright=nr;
335 else
337 if(nl!=curleft||nr!=curright)
339 if(nl!=curleft)
341 curleft=nl;
342 drawLeft();
344 if(nr!=curright)
346 curright=nr;
347 drawRight();
351 update();
352 repaint();
355 void setVol(int left, int right)
357 int err;
358 callbacks();
359 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);
360 if(cure->element.data.volume1.pvoices[0]>cure->info.data.volume1.prange[0].max)
361 cure->element.data.volume1.pvoices[0]=cure->info.data.volume1.prange[0].max;
362 if(cure->element.data.volume1.pvoices[0]<cure->info.data.volume1.prange[0].min)
363 cure->element.data.volume1.pvoices[0]=cure->info.data.volume1.prange[0].min;
364 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);
365 if(cure->element.data.volume1.pvoices[1]>cure->info.data.volume1.prange[1].max)
366 cure->element.data.volume1.pvoices[1]=cure->info.data.volume1.prange[1].max;
367 if((err=snd_mixer_element_write(mixer_handle,&cure->element))<0)
368 fprintf(stderr,"Mixer element write error: %s\n",snd_strerror(err));
369 return;
372 void callbacks(void)
374 int err;
375 snd_mixer_callbacks_t callbacks;
376 memset(&callbacks,0,sizeof(callbacks));
377 callbacks.rebuild=NULL;
378 callbacks.element=NULL;
379 callbacks.group=NULL;
380 if((err=snd_mixer_read(mixer_handle,&callbacks))<0)
382 fprintf(stderr,"Callbacks error: %s\n",snd_strerror(err));
383 return;
385 return;
388 int convert_range(int val, int omin, int omax, int nmin, int nmax)
390 int orange=omax-omin, nrange=nmax-nmin;
391 if(orange==0)
392 return 0;
393 return rint((((double)nrange*((double)val-(double)omin))+((double)orange/2.0))/(double)orange+(double)nmin);
396 void pressEvent(XButtonEvent *xev)
398 int x=xev->x-(winsize/2-32);
399 int y=xev->y-(winsize/2-32);
400 if(x>=5 && y>=33 && x<=16 && y<=43)
402 cure=cure->prev;
403 if(!cure)
405 elementinfo *e;
406 e=element;
407 while(e->next)
408 e=e->next;
409 cure=e;
411 btnstate |= BTNPREV;
412 rpttimer=0;
413 drawBtns(BTNPREV);
414 checkVol();
415 return;
417 if(x>=17 && y>=33 && x<=28 && y<=43)
419 cure=cure->next;
420 if(!cure)
421 cure=element;
422 btnstate|=BTNNEXT;
423 rpttimer=0;
424 drawBtns(BTNNEXT);
425 checkVol();
426 return;
428 if(x>=37 && x<=56 && y>=8 && y<=56)
430 int v=((60-y)*100)/(2*25);
431 dragging=1;
432 if(x<=50)
433 setVol(v,curright);
434 if(x>=45)
435 setVol(curleft,v);
436 checkVol();
437 return;
439 /* if(x>=5 && y>=47 && x<=28 && y<=57)
441 int nl,nr,flags;
442 mixer.DeviceSet(channel[curchannel]);
443 mixer.Read(&nl,&nr,&flags);
444 if(flags & SND_MIXER_DFLG_MUTE)
446 btnstate &= ~BTNREC;
447 flags &= ~SND_MIXER_DFLG_MUTE;
449 else
451 btnstate |= BTNREC;
452 flags |= SND_MIXER_DFLG_MUTE;
454 mixer.Write(nl,nr,flags);
455 checkVol();
456 return;
460 void releaseEvent(XButtonEvent *xev)
462 dragging=0;
463 btnstate &= ~(BTNPREV | BTNNEXT);
464 drawBtns(BTNPREV | BTNNEXT);
465 repaint();
468 void motionEvent(XMotionEvent *xev)
470 int x=xev->x-(winsize/2-32);
471 int y=xev->y-(winsize/2-32);
472 if(x>=37 && x<=56 && y>=8 && dragging)
474 int v=((60-y)*100)/(2*25);
475 if(v<0)
476 v=0;
477 if(x<=50)
478 setVol(v,curright);
479 if(x>=45)
480 setVol(curleft,v);
481 checkVol();
485 void repaint()
487 XEvent xev;
488 XCopyArea(d_display, pm_disp, w_activewin, gc_gc, 0, 0, 64, 64, winsize/2-32, winsize/2-32);
489 while(XCheckTypedEvent(d_display, Expose, &xev));
492 void update()
494 XCopyArea(d_display, pm_icon, pm_disp, gc_gc, cure->icon*22, 0, 22, 22, 6, 5);
495 drawLeft();
496 drawRight();
497 drawBtns(BTNREC);
500 void drawLeft()
502 int i;
503 XSetForeground(d_display, gc_gc, color[1]);
504 for(i=0;i<25;i++)
506 if(i==(curleft*25)/100)
507 XSetForeground(d_display, gc_gc, color[3]);
508 XFillRectangle(d_display, pm_disp, gc_gc, 37, 55-2*i, 9, 1);
512 void drawRight()
514 int i;
515 XSetForeground(d_display, gc_gc, color[1]);
516 for(i=0;i<25;i++)
518 if(i==(curright*25)/100)
519 XSetForeground(d_display, gc_gc, color[3]);
520 XFillRectangle(d_display, pm_disp, gc_gc, 48, 55-2*i, 9, 1);
524 void drawBtns(int btns)
526 if(btns & BTNPREV)
527 drawBtn(5, 33, 12, 11, (btnstate & BTNPREV));
528 if(btns & BTNNEXT)
529 drawBtn(17, 33, 12, 11, (btnstate & BTNNEXT));
530 if(btns & BTNREC)
531 drawBtn(5, 47, 24, 11, (btnstate & BTNREC));
534 void drawBtn(int x, int y, int w, int h, int down)
536 if(!down)
537 XCopyArea(d_display, pm_main, pm_disp, gc_gc, x, y, w, h, x, y);
538 else
540 XCopyArea(d_display, pm_main, pm_disp, gc_gc, x, y, 1, h-1, x+w-1, y+1);
541 XCopyArea(d_display, pm_main, pm_disp, gc_gc, x+w-1, y+1, 1, h-1, x, y);
542 XCopyArea(d_display, pm_main, pm_disp, gc_gc, x, y, w-1, 1, x+1, y+h-1);
543 XCopyArea(d_display, pm_main, pm_disp, gc_gc, x+1, y+h-1, w-1, 1, x, y);