wmcdplay: Remove extra argument to format in fprintf.
[dockapps.git] / wmcdplay / wmcdplay.cc
blob3ca2f0bd19ef0479c9e06247892b072cf891eb41
1 // wmcdplay - A cd player designed for WindowMaker
2 // 05/09/98 Release 1.0 Beta1
3 // Copyright (C) 1998 Sam Hawker <shawkie@geocities.com>
4 // This software comes with ABSOLUTELY NO WARRANTY
5 // This software is free software, and you are welcome to redistribute it
6 // under certain conditions
7 // See the README file for a more complete notice.
10 // Defines, includes and global variables
11 // --------------------------------------
13 // User defines - standard
14 #define WINDOWMAKER false
15 #define USESHAPE false
16 #define AFTERSTEP false
17 #define NORMSIZE 64
18 #define ASTEPSIZE 56
19 #define NAME "wmcdplay"
20 #define CLASS "WMCDPlay"
22 // User defines - custom
23 #define SYSARTDIR "/usr/X11R6/lib/X11/wmcdplay/"
24 #define CDDEV "/dev/cdrom"
25 #define BACKCOLOR "#282828"
26 #define LEDCOLOR "green"
27 #define POSRELABS 0 // 0=relative position, 1=absolute position
28 #define UINTERVAL_N 1 // 20ths of a second
29 #define UINTERVAL_E 20 // 20ths of a second
31 // Includes - standard
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
37 // Includes - custom
38 #include "cdctl.h"
40 // X-Windows includes - standard
41 #include <X11/X.h>
42 #include <X11/Xlib.h>
43 #include <X11/Xutil.h>
44 #include <X11/Xproto.h>
45 #include <X11/xpm.h>
46 #include <X11/extensions/shape.h>
48 // Pixmaps - standard
49 Pixmap pm_tile;
50 Pixmap pm_disp;
51 Pixmap pm_mask;
53 // Pixmaps - artwork
54 Pixmap pm_cd;
55 Pixmap pm_cdmask;
56 Pixmap pm_sym;
57 Pixmap pm_symmask;
58 Pixmap pm_led;
59 Pixmap pm_sled;
60 Pixmap pm_tled;
62 // Xpm images - standard
63 #include "XPM/tile.xpm"
65 // Xpm images - artwork
66 #include "XPM/standard.art"
68 // Variables for command-line arguments - standard
69 bool wmaker=WINDOWMAKER;
70 bool ushape=USESHAPE;
71 bool astep=AFTERSTEP;
72 char display[256]="";
73 char position[256]="";
74 int winsize;
76 // Variables for command-line arguments - custom
77 char cddev[256]=CDDEV;
78 char backcolor[256]=BACKCOLOR;
79 char ledcolor[256]=LEDCOLOR;
80 bool artwrk=false;
81 char artwrkf[256]="";
82 int tsel=1;
83 int vol=-1; // -1 means don't set volume
84 int uinterval_e=UINTERVAL_E;
86 // X-Windows basics - standard
87 Atom _XA_GNUSTEP_WM_FUNC;
88 Atom deleteWin;
89 Display *d_display;
90 Window w_icon;
91 Window w_main;
92 Window w_root;
93 Window w_activewin;
95 // X-Windows basics - custom
96 GC gc_gc, gc_bitgc;
97 unsigned long color[4];
100 // Misc custom global variables
101 // ----------------------------
103 // For artwork loading
104 int **art_btnlist;
105 int *art_btnptr;
106 int *art_actptr;
107 int art_symsize[2];
108 int art_ledsize[6];
110 int mode=-1, track=-1, pos=-1;
111 int tdisplay=POSRELABS;
112 int ucount=0;
113 char trackstr[8]="";
114 char timestr[8]="";
115 char chrset[]="00112233445566778899 DDAATTNNOOCC--PPEE:;_";
117 CDCtl *cdctl;
120 // Procedures and functions
121 // ------------------------
123 // Procedures and functions - standard
124 void initXWin(int argc, char **argv);
125 void freeXWin();
126 void createWin(Window *win, int x, int y);
127 unsigned long getColor(char *colorname);
128 unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2);
130 // Procedures and functions - custom
131 void scanArgs(int argc, char **argv);
132 void checkStatus(bool forced);
133 void pressEvent(XButtonEvent *xev);
134 void repaint();
135 void update();
136 void drawText(int x, int y, char *text);
138 // Procedures and functions - artwork basics
139 bool readArtwork(char *artfilen);
140 char *readBlock(FILE *dfile);
141 int arrayItems(char *buf);
142 void readArrayInt(char *buf, int *array, int n);
143 void readArrayBool(char *buf, bool *array, int n);
145 // Procedures and functions - artwork specials
146 void createPixmap(char **data, char *buf, Pixmap *image, Pixmap *mask, int *width, int *height);
147 void setBtnList(int *bset);
148 bool inPolygon(int *points, int px, int py);
151 // Implementation
152 // --------------
154 int main(int argc, char **argv)
156 scanArgs(argc, argv);
157 initXWin(argc, argv);
159 color[0]=mixColor(ledcolor, 0, backcolor, 100);
160 color[1]=mixColor(ledcolor, 100, backcolor, 0);
161 color[2]=mixColor(ledcolor, 60, backcolor, 40);
162 color[3]=mixColor(ledcolor, 25, backcolor, 75);
164 if(artwrk)
165 artwrk=readArtwork(artwrkf);
166 if(!artwrk){
167 int w, h;
168 createPixmap(cdplayer_xpm, NULL, &pm_cd, &pm_cdmask, NULL, NULL);
169 createPixmap(symbols_xpm, NULL, &pm_sym, &pm_symmask, &w, &h);
170 art_symsize[0]=(w+1)/11-1;
171 art_symsize[1]=h;
172 createPixmap(led_xpm, NULL, &pm_led, NULL, &w, &h);
173 art_ledsize[0]=(w+1)/strlen(chrset)-1;
174 art_ledsize[1]=h;
175 createPixmap(ledsym_xpm, NULL, &pm_sled, NULL, &w, &h);
176 art_ledsize[2]=(w+1)/6-1;
177 art_ledsize[3]=h;
178 createPixmap(ledtsel_xpm, NULL, &pm_tled, NULL, &w, &h);
179 art_ledsize[4]=(w+1)/5-1;
180 art_ledsize[5]=h;
181 art_btnptr=art_btns;
182 art_actptr=art_actions;
184 setBtnList(art_btnptr);
185 createPixmap(tile_xpm, NULL, &pm_tile, NULL, NULL, NULL);
186 pm_disp = XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, DefaultScreen(d_display)));
187 pm_mask = XCreatePixmap(d_display, w_root, 64, 64, 1);
189 XGCValues gcv;
190 unsigned long gcm;
191 gcm=GCGraphicsExposures;
192 gcv.graphics_exposures=false;
193 gc_gc=XCreateGC(d_display, w_root, gcm, &gcv);
194 gc_bitgc=XCreateGC(d_display, pm_mask, gcm, &gcv);
196 cdctl=new CDCtl(cddev);
198 if(!cdctl->openOK())
199 fprintf(stderr, "%s : Unable to open cdrom device '%s'.\n", NAME, cddev);
200 else{
201 if(vol!=-1)
202 cdctl->setVolume(vol, vol);
203 int tsels[] = { tsNone, tsNext, tsRepeat, tsRepeatCD, tsRandom };
204 cdctl->setTrackSelection(tsels[tsel]);
206 checkStatus(true);
208 XEvent xev;
209 XSelectInput(d_display, w_activewin, ButtonPress | ExposureMask);
210 XMapWindow(d_display, w_main);
212 bool done=false;
213 while(!done){
214 while(XPending(d_display)){
215 XNextEvent(d_display, &xev);
216 switch(xev.type){
217 case Expose:
218 repaint();
219 break;
220 case ButtonPress:
221 pressEvent(&xev.xbutton);
222 break;
223 case ClientMessage:
224 if(xev.xclient.data.l[0]==deleteWin)
225 done=true;
226 break;
229 ucount++;
230 if(ucount>=((mode==ssNoCD || mode==ssTrayOpen) ? uinterval_e : UINTERVAL_N))
231 checkStatus(false);
232 XFlush(d_display);
233 usleep(50000);
236 XFreeGC(d_display, gc_gc);
237 XFreeGC(d_display, gc_bitgc);
238 XFreePixmap(d_display, pm_tile);
239 XFreePixmap(d_display, pm_disp);
240 XFreePixmap(d_display, pm_mask);
241 XFreePixmap(d_display, pm_cd);
242 XFreePixmap(d_display, pm_cdmask);
243 XFreePixmap(d_display, pm_sym);
244 XFreePixmap(d_display, pm_symmask);
245 XFreePixmap(d_display, pm_led);
246 XFreePixmap(d_display, pm_sled);
247 XFreePixmap(d_display, pm_tled);
248 freeXWin();
249 if(artwrk){
250 free(art_btnptr);
251 free(art_actptr);
253 free(art_btnlist);
254 delete cdctl;
255 return 0;
258 void initXWin(int argc, char **argv){
259 winsize=astep ? ASTEPSIZE : NORMSIZE;
261 if((d_display=XOpenDisplay(display))==NULL){
262 fprintf(stderr,"%s : Unable to open X display '%s'.\n", NAME, XDisplayName(display));
263 exit(1);
265 _XA_GNUSTEP_WM_FUNC=XInternAtom(d_display, "_GNUSTEP_WM_FUNCTION", false);
266 deleteWin=XInternAtom(d_display, "WM_DELETE_WINDOW", false);
268 w_root=DefaultRootWindow(d_display);
270 XWMHints wmhints;
271 XSizeHints shints;
272 shints.x=0;
273 shints.y=0;
274 shints.flags=0;
275 bool pos=(XWMGeometry(d_display, DefaultScreen(d_display), position, NULL, 0, &shints, &shints.x, &shints.y,
276 &shints.width, &shints.height, &shints.win_gravity) & (XValue | YValue));
277 shints.min_width=winsize;
278 shints.min_height=winsize;
279 shints.max_width=winsize;
280 shints.max_height=winsize;
281 shints.base_width=winsize;
282 shints.base_height=winsize;
283 shints.flags=PMinSize | PMaxSize | PBaseSize;
285 createWin(&w_main, shints.x, shints.y);
287 if(wmaker || astep || pos)
288 shints.flags |= USPosition;
289 if(wmaker){
290 wmhints.initial_state=WithdrawnState;
291 wmhints.flags=WindowGroupHint | StateHint | IconWindowHint;
292 createWin(&w_icon, shints.x, shints.y);
293 w_activewin=w_icon;
294 wmhints.icon_window=w_icon;
296 else{
297 wmhints.initial_state=NormalState;
298 wmhints.flags=WindowGroupHint | StateHint;
299 w_activewin=w_main;
301 wmhints.window_group=w_main;
302 XSetWMHints(d_display, w_main, &wmhints);
303 XSetWMNormalHints(d_display, w_main, &shints);
304 XSetCommand(d_display, w_main, argv, argc);
305 XStoreName(d_display, w_main, NAME);
306 XSetIconName(d_display, w_main, NAME);
307 XSetWMProtocols(d_display, w_activewin, &deleteWin, 1);
310 void freeXWin(){
311 XDestroyWindow(d_display, w_main);
312 if(wmaker)
313 XDestroyWindow(d_display, w_icon);
314 XCloseDisplay(d_display);
317 void createWin(Window *win, int x, int y){
318 XClassHint classHint;
319 *win=XCreateSimpleWindow(d_display, w_root, x, y, winsize, winsize, 0, 0, 0);
320 classHint.res_name=NAME;
321 classHint.res_class=CLASS;
322 XSetClassHint(d_display, *win, &classHint);
325 unsigned long getColor(char *colorname){
326 XColor color;
327 XWindowAttributes winattr;
328 XGetWindowAttributes(d_display, w_root, &winattr);
329 color.pixel=0;
330 XParseColor(d_display, winattr.colormap, colorname, &color);
331 color.flags=DoRed | DoGreen | DoBlue;
332 XAllocColor(d_display, winattr.colormap, &color);
333 return color.pixel;
336 unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2){
337 XColor color, color1, color2;
338 XWindowAttributes winattr;
339 XGetWindowAttributes(d_display, w_root, &winattr);
340 XParseColor(d_display, winattr.colormap, colorname1, &color1);
341 XParseColor(d_display, winattr.colormap, colorname2, &color2);
342 color.pixel=0;
343 color.red=(color1.red*prop1+color2.red*prop2)/(prop1+prop2);
344 color.green=(color1.green*prop1+color2.green*prop2)/(prop1+prop2);
345 color.blue=(color1.blue*prop1+color2.blue*prop2)/(prop1+prop2);
346 color.flags=DoRed | DoGreen | DoBlue;
347 XAllocColor(d_display, winattr.colormap, &color);
348 return color.pixel;
351 void scanArgs(int argc, char **argv){
352 for(int i=1;i<argc;i++){
353 if(strcmp(argv[i], "-h")==0 || strcmp(argv[i], "-help")==0 || strcmp(argv[i], "--help")==0){
354 fprintf(stderr, "wmcdplay - A cd player designed for WindowMaker\n05/09/98 Release 1.0 Beta1\n");
355 fprintf(stderr, "Copyright (C) 1998 Sam Hawker <shawkie@geocities.com>\n");
356 fprintf(stderr, "This software comes with ABSOLUTELY NO WARRANTY\n");
357 fprintf(stderr, "This software is free software, and you are welcome to redistribute it\n");
358 fprintf(stderr, "under certain conditions\n");
359 fprintf(stderr, "See the README file for a more complete notice.\n\n");
360 fprintf(stderr, "usage:\n\n %s [options]\n\noptions:\n\n",argv[0]);
361 fprintf(stderr, " -h | -help | --help display this help screen\n");
362 fprintf(stderr, " -w use WithdrawnState (for WindowMaker)\n");
363 fprintf(stderr, " -s shaped window\n");
364 fprintf(stderr, " -a use smaller window (for AfterStep Wharf)\n");
365 fprintf(stderr, " -f artwork_file load the specified artwork file\n");
366 fprintf(stderr, " -t track_selection set track selection (between 0 and 4)\n");
367 fprintf(stderr, " -v volume set the cdrom volume (between 0 and 255)\n");
368 fprintf(stderr, " -i interval interval in 1/20 seconds between cd polls when empty\n");
369 fprintf(stderr, " -l led_color use the specified color for led displays\n");
370 fprintf(stderr, " -b back_color use the specified color for backgrounds\n");
371 fprintf(stderr, " -d cd_device use specified device (rather than /dev/cdrom)\n");
372 fprintf(stderr, " -position position set window position (see X manual pages)\n");
373 fprintf(stderr, " -display display select target display (see X manual pages)\n\n");
374 exit(0);
376 if(strcmp(argv[i], "-w")==0)
377 wmaker=!wmaker;
378 if(strcmp(argv[i], "-s")==0)
379 ushape=!ushape;
380 if(strcmp(argv[i], "-a")==0)
381 astep=!astep;
382 if(strcmp(argv[i], "-t")==0){
383 if(i<argc-1){
384 i++;
385 sscanf(argv[i], "%i", &tsel);
387 continue;
389 if(strcmp(argv[i], "-v")==0){
390 if(i<argc-1){
391 i++;
392 sscanf(argv[i], "%i", &vol);
394 continue;
396 if(strcmp(argv[i], "-i")==0){
397 if(i<argc-1){
398 i++;
399 sscanf(argv[i], "%i", &uinterval_e);
401 continue;
403 if(strcmp(argv[i], "-f")==0){
404 artwrk=true;
405 if(i<argc-1){
406 i++;
407 sprintf(artwrkf, "%s", argv[i]);
409 continue;
411 if(strcmp(argv[i], "-d")==0){
412 if(i<argc-1){
413 i++;
414 sprintf(cddev, "%s", argv[i]);
416 continue;
418 if(strcmp(argv[i], "-l")==0){
419 if(i<argc-1){
420 i++;
421 sprintf(ledcolor, "%s", argv[i]);
423 continue;
425 if(strcmp(argv[i], "-b")==0){
426 if(i<argc-1){
427 i++;
428 sprintf(backcolor, "%s", argv[i]);
430 continue;
432 if(strcmp(argv[i], "-position")==0){
433 if(i<argc-1){
434 i++;
435 sprintf(position, "%s", argv[i]);
437 continue;
439 if(strcmp(argv[i], "-display")==0){
440 if(i<argc-1){
441 i++;
442 sprintf(display, "%s", argv[i]);
444 continue;
449 void checkStatus(bool forced){
450 ucount=0;
451 int oldmode=mode;
452 int oldpos=pos;
453 int oldtrack=track;
455 cdctl->doStatus();
456 mode=cdctl->getStatusState();
457 track=cdctl->getStatusTrack();
459 if(mode==ssStopped){
460 if(tdisplay==0)
461 pos=0;
462 if(tdisplay==1)
463 pos=cdctl->getTrackStart(track);
465 if(mode==ssPlaying || mode==ssPaused){
466 if(tdisplay==0)
467 pos=cdctl->getStatusPosRel();
468 if(tdisplay==1)
469 pos=cdctl->getStatusPosAbs();
472 bool umode=mode!=oldmode || forced;
473 bool utrack=umode || (!(mode==ssNoCD || mode==ssTrayOpen) && track!=oldtrack);
474 bool utimer=utrack || ((mode==ssPlaying || mode==ssPaused || mode==ssStopped) && (int)(pos/75)!=(int)(oldpos/75));
476 if(utimer){
477 if(umode)
478 update();
479 if(utrack){
480 if(mode==ssNoCD || mode==ssTrayOpen)
481 sprintf(trackstr, " ");
482 else
483 sprintf(trackstr, "%2d", cdctl->getStatusTrack());
484 if(art_showled[1])
485 drawText(art_ledpos[1][0], art_ledpos[1][1], trackstr);
487 if(mode==ssPlaying || mode==ssPaused || mode==ssStopped){
488 int remain = 0;
489 if(tdisplay==0)
490 remain=cdctl->getTrackLen(cdctl->getStatusTrack())-pos;
491 if(tdisplay==1)
492 remain=cdctl->getCDLen()-pos;
493 if(remain<2250)
494 sprintf(timestr, " -;%02d", remain/75);
495 else
496 sprintf(timestr, "%2d:%02d", (pos/75)/60, (pos/75)%60);
498 if(art_showled[0])
499 drawText(art_ledpos[0][0], art_ledpos[0][1], timestr);
500 repaint();
504 void pressEvent(XButtonEvent *xev){
505 int x=xev->x-(winsize/2-32);
506 int y=xev->y-(winsize/2-32);
507 int btn=-1;
508 for(int i=0;i<art_nbtns;i++){
509 if(inPolygon(&art_btnlist[i][2], x, y))
510 btn=i;
512 if(btn==-1){
513 if(art_showled[3]){
514 if(x>=art_ledpos[3][0] && y>=art_ledpos[3][1] && x<=art_ledpos[3][0]+art_ledsize[4] && y<=art_ledpos[3][1]+art_ledsize[5]){
515 int tsels[] = { tsNone, tsNext, tsRepeat, tsRepeatCD, tsRandom };
516 tsel++;
517 if(tsel>=5)
518 tsel=0;
519 cdctl->setTrackSelection(tsels[tsel]);
520 XCopyArea(d_display, pm_tled, pm_disp, gc_gc, (art_ledsize[4]+1)*tsel, 0, art_ledsize[4], art_ledsize[5], art_ledpos[3][0], art_ledpos[3][1]);
521 repaint();
522 return;
525 if(art_showled[0]){
526 if(x>=art_ledpos[0][0] && y>=art_ledpos[0][1] && x<=art_ledpos[0][0]+(art_ledsize[0]+1)*9-1 && y<=art_ledpos[0][1]+art_ledsize[1]){
527 tdisplay++;
528 if(tdisplay>=2)
529 tdisplay=0;
530 checkStatus(false);
531 return;
535 else{
536 int action=art_actptr[6*btn+mode];
537 int acmds[]={ acStop, acPlay, acPause, acResume, acPrev, acNext, acRewd, acFFwd, acEject, acClose };
538 if(action>0){
539 int acmd=acmds[action-1];
540 cdctl->doAudioCommand(acmd);
541 checkStatus(false);
546 void repaint(){
547 XCopyArea(d_display, pm_disp, w_activewin, gc_gc, 0, 0, 64, 64, winsize/2-32, winsize/2-32);
548 XEvent xev;
549 while(XCheckTypedEvent(d_display, Expose, &xev));
552 void update(){
553 if(mode==ssData)
554 sprintf(timestr, "DA_TA");
555 if(mode==ssNoCD)
556 sprintf(timestr, "NO;CD");
557 if(mode==ssTrayOpen)
558 sprintf(timestr, "OP_EN");
560 XPoint mply[art_nbtns];
561 if(pm_cdmask!=None){
562 XSetForeground(d_display, gc_bitgc, 0);
563 XCopyArea(d_display, pm_cdmask, pm_mask, gc_bitgc, 0, 0, 64, 64, 0, 0);
564 for(int i=0; i<art_nbtns; i++){
565 if(art_actptr[6*i+mode]==0 && art_hidebtns){
566 for(int k=0;k<art_btnlist[i][2];k++){
567 mply[k].x=art_btnlist[i][k*2+3];
568 mply[k].y=art_btnlist[i][k*2+4];
570 XFillPolygon(d_display, pm_mask, gc_bitgc, (XPoint *)mply, art_btnlist[i][2], Convex, CoordModeOrigin);
573 if(!(wmaker || ushape || astep)){
574 XCopyArea(d_display, pm_tile, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
575 XSetClipMask(d_display, gc_gc, pm_mask);
578 XCopyArea(d_display, pm_cd, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
579 if(pm_symmask!=None){
580 XSetClipMask(d_display, gc_gc, pm_symmask);
581 XSetClipMask(d_display, gc_bitgc, pm_symmask);
583 XSetForeground(d_display, gc_bitgc, 1);
584 for(int i=0;i<art_nbtns;i++){
585 if(!(art_actptr[6*i+mode]==0 && art_hidebtns)){
586 int sympos=(art_symsize[0]+1)*(art_actptr[6*i+mode]);
587 XSetClipOrigin(d_display, gc_gc, art_btnlist[i][0]-sympos, art_btnlist[i][1]);
588 XSetClipOrigin(d_display, gc_bitgc, art_btnlist[i][0]-sympos, art_btnlist[i][1]);
589 XCopyArea(d_display, pm_sym, pm_disp, gc_gc, sympos, 0, art_symsize[0], art_symsize[1], art_btnlist[i][0], art_btnlist[i][1]);
590 XFillRectangle(d_display, pm_mask, gc_bitgc, art_btnlist[i][0], art_btnlist[i][1], art_symsize[0], art_symsize[1]);
593 if(wmaker || ushape || astep)
594 XShapeCombineMask(d_display, w_activewin, ShapeBounding, winsize/2-32, winsize/2-32, pm_mask, ShapeSet);
595 XSetClipOrigin(d_display, gc_gc, 0, 0);
596 XSetClipOrigin(d_display, gc_bitgc, 0, 0);
597 XSetClipMask(d_display, gc_gc, None);
598 XSetClipMask(d_display, gc_bitgc, None);
599 if(art_showled[2])
600 XCopyArea(d_display, pm_sled, pm_disp, gc_gc, (art_ledsize[2]+1)*mode, 0, art_ledsize[2], art_ledsize[3], art_ledpos[2][0], art_ledpos[2][1]);
601 if(art_showled[3])
602 XCopyArea(d_display, pm_tled, pm_disp, gc_gc, (art_ledsize[4]+1)*tsel, 0, art_ledsize[4], art_ledsize[5], art_ledpos[3][0], art_ledpos[3][1]);
605 void drawText(int x, int y, char *text){
606 int drawx=x;
607 for(int i=0;i<strlen(text);i++){
608 char *chrptr=strchr(chrset,text[i]);
609 if(chrptr!=NULL){
610 int chrindex=chrptr-chrset;
611 int chrwidth=art_ledsize[0];
612 if(chrset[chrindex+1]==text[i])
613 chrwidth=2*art_ledsize[0]+1;
614 XCopyArea(d_display, pm_led, pm_disp, gc_gc, chrindex*(art_ledsize[0]+1), 0, chrwidth, art_ledsize[1], drawx, y);
615 drawx+=chrwidth+1;
620 bool readArtwork(char *artfilen){
621 FILE *artfile;
622 char artfilenbuf[256];
623 artfile=fopen(artfilen, "r");
624 if(artfile==NULL){
625 if(strchr(artfilen, '/')!=NULL){
626 fprintf(stderr, "%s : Unable to open artwork file '%s'.\n", NAME, artfilen);
627 return false;
629 sprintf(artfilenbuf, "%s/.wmcdplay/%s", getenv("HOME"), artfilen);
630 artfile=fopen(artfilenbuf, "r");
631 if(artfile==NULL){
632 sprintf(artfilenbuf, "%s%s", SYSARTDIR, artfilen);
633 artfile=fopen(artfilenbuf, "r");
634 if(artfile==NULL){
635 fprintf(stderr,"%s : Tried to find artwork file, but failed.\n", NAME);
636 return false;
641 char buf[256];
642 bool done=false;
643 while(!done){
644 fgets(buf, 250, artfile);
645 done=(feof(artfile)!=0);
646 if(!done){
648 int keynum=0;
649 char *keystr[]={ "int art_nbtns=",
650 "bool art_hidebtns=",
651 "bool art_showled[4]=",
652 "int art_ledpos[4][2]=",
653 "int art_btns[]=",
654 "int art_actions[]=",
655 "/* XPM */" };
656 for(int i=0;i<7;i++){
657 if(strncmp(buf, keystr[i], strlen(keystr[i]))==0){
658 keynum=i+1;
659 break;
663 if(keynum==1)
664 sscanf(buf+strlen(keystr[keynum-1]), "%d", &art_nbtns);
666 if(keynum==2)
667 art_hidebtns=(strstr(buf+strlen(keystr[keynum-1]), "true")!=NULL);
669 if(keynum==3)
670 readArrayBool((char *)buf, (bool *)art_showled, 4);
672 if(keynum==4)
673 readArrayInt((char *)buf, (int *)art_ledpos, 8);
675 if(keynum>=5){
676 fseek(artfile, -strlen(buf), SEEK_CUR);
677 char *block=readBlock(artfile);
679 if(keynum==5){
680 int items=arrayItems(block);
681 art_btnptr=(int *)malloc(sizeof(int)*items);
682 readArrayInt(block, art_btnptr, items);
685 if(keynum==6){
686 int items=arrayItems(block);
687 art_actptr=(int *)malloc(sizeof(int)*items);
688 readArrayInt(block, art_actptr, items);
691 if(keynum==7){
693 strncpy(buf, strchr(block+strlen(keystr[keynum-1]), '\n')+1, 250);
694 *strchr(buf, '\n')='\0';
696 int w,h;
697 if(strncmp(buf, "static char * cdplayer_xpm", strlen("static char * cdplayer_xpm"))==0)
698 createPixmap(NULL, block, &pm_cd, &pm_cdmask, NULL, NULL);
699 if(strncmp(buf, "static char * symbols_xpm", strlen("static char * symbols_xpm"))==0){
700 createPixmap(NULL, block, &pm_sym, &pm_symmask, &w, &h);
701 art_symsize[0]=(w+1)/11-1;
702 art_symsize[1]=h;
704 if(strncmp(buf, "static char * led_xpm", strlen("static char * led_xpm"))==0){
705 createPixmap(NULL, block, &pm_led, NULL, &w, &h);
706 art_ledsize[0]=(w+1)/strlen(chrset)-1;
707 art_ledsize[1]=h;
709 if(strncmp(buf, "static char * ledsym_xpm", strlen("static char * ledsym_xpm"))==0){
710 createPixmap(NULL, block, &pm_sled, NULL, &w, &h);
711 art_ledsize[2]=(w+1)/6-1;
712 art_ledsize[3]=h;
714 if(strncmp(buf, "static char * ledtsel_xpm", strlen("static char * ledtsel_xpm"))==0){
715 createPixmap(NULL, block, &pm_tled, NULL, &w, &h);
716 art_ledsize[4]=(w+1)/5-1;
717 art_ledsize[5]=h;
721 free(block);
725 fclose(artfile);
726 return true;
729 char *readBlock(FILE *dfile){
730 char buf[256];
731 long bytes=0;
732 char *block=NULL;
734 fgets(buf, 250, dfile);
735 int buflen=strlen(buf);
736 block=(char *)realloc(block, sizeof(char)*(bytes+buflen+1));
737 strcpy(block+bytes, buf);
738 bytes+=buflen;
739 } while(strstr(buf, "}")==NULL);
740 return block;
743 int arrayItems(char *buf){
744 int items=1;
745 char *bufptr=buf;
746 while((bufptr=strstr(bufptr, ","))!=NULL){
747 bufptr++;
748 items++;
750 return items;
753 void readArrayInt(char *buf, int *array, int n){
754 char *bufptr;
755 bufptr=strtok(buf, "{,}");
756 for(int i=0;i<n;i++){
757 bufptr=strtok(NULL, "{,}");
758 sscanf(bufptr, "%d", &array[i]);
762 void readArrayBool(char *buf, bool *array, int n){
763 char *bufptr;
764 bufptr=strtok(buf, "{,}");
765 for(int i=0;i<n;i++){
766 bufptr=strtok(NULL, "{,}");
767 array[i]=(strstr(bufptr, "true")!=NULL);
771 void createPixmap(char **data, char *buf, Pixmap *image, Pixmap *mask, int *width, int *height){
772 XpmAttributes xpmattr;
773 XpmColorSymbol xpmcsym[4]={{"back_color", NULL, color[0]},
774 {"led_color_high", NULL, color[1]},
775 {"led_color_med", NULL, color[2]},
776 {"led_color_low", NULL, color[3]}};
777 xpmattr.numsymbols=4;
778 xpmattr.colorsymbols=xpmcsym;
779 xpmattr.exactColors=false;
780 xpmattr.closeness=40000;
781 xpmattr.valuemask=XpmColorSymbols | XpmExactColors | XpmCloseness | XpmSize;
782 if(data!=NULL)
783 XpmCreatePixmapFromData(d_display, w_root, data, image, mask, &xpmattr);
784 else
785 XpmCreatePixmapFromBuffer(d_display, w_root, buf, image, mask, &xpmattr);
786 if(width!=NULL)
787 *width=xpmattr.width;
788 if(height!=NULL)
789 *height=xpmattr.height;
792 void setBtnList(int *bset){
793 // Create a list of pointers to button data.
794 // So, for example, data for button 2 can be accessed as art_btnlist[2];
795 // Also, the y co-ordinate of its symbol would be art_btnlist[2][1]
797 art_btnlist=(int **)malloc(art_nbtns*sizeof(int *));
798 int curpos=0;
799 for(int i=0;i<art_nbtns;i++){
800 art_btnlist[i]=&bset[0+curpos];
801 curpos+=2*art_btnlist[i][2]+3;
805 bool inPolygon(int *points, int px, int py){
806 int lx=points[1];
807 int ly=points[2];
808 int x,y;
809 for(int i=1;i<=points[0];i++){
810 if(i==points[0]){
811 x=points[1];
812 y=points[2];
814 else{
815 x=points[i*2+1];
816 y=points[i*2+2];
818 int a=ly-y;
819 int b=x-lx;
820 int c=-a*x-b*y;
821 if(a*px+b*py+c<0)
822 return false;
823 lx=x;
824 ly=y;
826 return true;