wmclockmon: handle fgets NULL returns and zero-length lines
[dockapps.git] / wmcdplay / wmcdplay.cc
blob675b5dc4986d2c3a8b9196422c241a5c35cf78e4
1 // wmcdplay - A cd player designed for WindowMaker
2 // Copyright (C) 1998 Sam Hawker <shawkie@geocities.com>
3 // This software comes with ABSOLUTELY NO WARRANTY
4 // This software is free software, and you are welcome to redistribute it
5 // under certain conditions
6 // See the README file for a more complete notice.
9 // Defines, includes and global variables
10 // --------------------------------------
12 // User defines - standard
13 #define WINDOWMAKER false
14 #define USESHAPE false
15 #define AFTERSTEP false
16 #define NORMSIZE 64
17 #define ASTEPSIZE 56
18 #define NAME "wmcdplay"
19 #define CLASS "WMCDPlay"
21 // User defines - custom
22 #define CDDEV "/dev/cdrom"
23 #define BACKCOLOR "#282828"
24 #define LEDCOLOR "green"
25 #define POSRELABS 0 // 0=relative position, 1=absolute position
26 #define UINTERVAL_N 1 // 20ths of a second
27 #define UINTERVAL_E 20 // 20ths of a second
29 // Includes - standard
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
35 // Includes - custom
36 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
37 #include "cdctl_freebsd.h"
38 #else
39 #include "cdctl.h"
40 #endif
42 // X-Windows includes - standard
43 #include <X11/X.h>
44 #include <X11/Xlib.h>
45 #include <X11/Xutil.h>
46 #include <X11/Xproto.h>
47 #include <X11/xpm.h>
48 #include <X11/extensions/shape.h>
50 // Pixmaps - standard
51 Pixmap pm_tile;
52 Pixmap pm_disp;
53 Pixmap pm_mask;
55 // Pixmaps - artwork
56 Pixmap pm_cd;
57 Pixmap pm_cdmask;
58 Pixmap pm_sym;
59 Pixmap pm_symmask;
60 Pixmap pm_led;
61 Pixmap pm_sled;
62 Pixmap pm_tled;
64 // Xpm images - standard
65 #include "XPM/tile.xpm"
67 // Xpm images - artwork
68 #include "XPM/standard.art"
70 // Variables for command-line arguments - standard
71 bool wmaker=WINDOWMAKER;
72 bool ushape=USESHAPE;
73 bool astep=AFTERSTEP;
74 char display[256]="";
75 char position[256]="";
76 int winsize;
78 // Variables for command-line arguments - custom
79 char cddev[256]=CDDEV;
80 char backcolor[256]=BACKCOLOR;
81 char ledcolor[256]=LEDCOLOR;
82 bool artwrk=false;
83 char artwrkf[256]="";
84 int tsel=1;
85 int vol=-1; // -1 means don't set volume
86 int uinterval_e=UINTERVAL_E;
88 // X-Windows basics - standard
89 Atom _XA_GNUSTEP_WM_FUNC;
90 Atom deleteWin;
91 Display *d_display;
92 Window w_icon;
93 Window w_main;
94 Window w_root;
95 Window w_activewin;
97 // X-Windows basics - custom
98 GC gc_gc, gc_bitgc;
99 unsigned long color[4];
102 // Misc custom global variables
103 // ----------------------------
105 // For artwork loading
106 int **art_btnlist;
107 int *art_btnptr;
108 int *art_actptr;
109 int art_symsize[2];
110 int art_ledsize[6];
112 int mode=-1, track=-1, pos=-1;
113 int tdisplay=POSRELABS;
114 int ucount=0;
115 char trackstr[8]="";
116 char timestr[8]="";
117 char chrset[]="00112233445566778899 DDAATTNNOOCC--PPEE:;_";
119 CDCtl *cdctl;
122 // Procedures and functions
123 // ------------------------
125 // Procedures and functions - standard
126 void initXWin(int argc, char **argv);
127 void freeXWin();
128 void createWin(Window *win, int x, int y);
129 unsigned long getColor(char *colorname);
130 unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2);
132 // Procedures and functions - custom
133 void scanArgs(int argc, char **argv);
134 void checkStatus(bool forced);
135 void pressEvent(XButtonEvent *xev);
136 void repaint();
137 void update();
138 void drawText(int x, int y, char *text);
140 // Procedures and functions - artwork basics
141 bool readArtwork(char *artfilen);
142 char *readBlock(FILE *dfile);
143 int arrayItems(char *buf);
144 void readArrayInt(char *buf, int *array, int n);
145 void readArrayBool(char *buf, bool *array, int n);
147 // Procedures and functions - artwork specials
148 void createPixmap(const char **data, char *buf, Pixmap *image, Pixmap *mask, int *width, int *height);
149 void setBtnList(int *bset);
150 bool inPolygon(int *points, int px, int py);
153 // Implementation
154 // --------------
156 int main(int argc, char **argv)
158 scanArgs(argc, argv);
159 initXWin(argc, argv);
161 color[0]=mixColor(ledcolor, 0, backcolor, 100);
162 color[1]=mixColor(ledcolor, 100, backcolor, 0);
163 color[2]=mixColor(ledcolor, 60, backcolor, 40);
164 color[3]=mixColor(ledcolor, 25, backcolor, 75);
166 if(artwrk)
167 artwrk=readArtwork(artwrkf);
168 if(!artwrk){
169 int w, h;
170 createPixmap(cdplayer_xpm, NULL, &pm_cd, &pm_cdmask, NULL, NULL);
171 createPixmap(symbols_xpm, NULL, &pm_sym, &pm_symmask, &w, &h);
172 art_symsize[0]=(w+1)/11-1;
173 art_symsize[1]=h;
174 createPixmap(led_xpm, NULL, &pm_led, NULL, &w, &h);
175 art_ledsize[0]=(w+1)/strlen(chrset)-1;
176 art_ledsize[1]=h;
177 createPixmap(ledsym_xpm, NULL, &pm_sled, NULL, &w, &h);
178 art_ledsize[2]=(w+1)/6-1;
179 art_ledsize[3]=h;
180 createPixmap(ledtsel_xpm, NULL, &pm_tled, NULL, &w, &h);
181 art_ledsize[4]=(w+1)/5-1;
182 art_ledsize[5]=h;
183 art_btnptr=art_btns;
184 art_actptr=art_actions;
186 setBtnList(art_btnptr);
187 createPixmap(tile_xpm, NULL, &pm_tile, NULL, NULL, NULL);
188 pm_disp = XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, DefaultScreen(d_display)));
189 pm_mask = XCreatePixmap(d_display, w_root, 64, 64, 1);
191 XGCValues gcv;
192 unsigned long gcm;
193 gcm=GCGraphicsExposures;
194 gcv.graphics_exposures=false;
195 gc_gc=XCreateGC(d_display, w_root, gcm, &gcv);
196 gc_bitgc=XCreateGC(d_display, pm_mask, gcm, &gcv);
198 cdctl=new CDCtl(cddev);
200 if(!cdctl->openOK())
201 fprintf(stderr, "%s : Unable to open cdrom device '%s'.\n", NAME, cddev);
202 else{
203 if(vol!=-1)
204 cdctl->setVolume(vol, vol);
205 int tsels[] = { tsNone, tsNext, tsRepeat, tsRepeatCD, tsRandom };
206 cdctl->setTrackSelection(tsels[tsel]);
208 checkStatus(true);
210 XEvent xev;
211 XSelectInput(d_display, w_activewin, ButtonPress | ExposureMask);
212 XMapWindow(d_display, w_main);
214 bool done=false;
215 while(!done){
216 while(XPending(d_display)){
217 XNextEvent(d_display, &xev);
218 switch(xev.type){
219 case Expose:
220 repaint();
221 break;
222 case ButtonPress:
223 pressEvent(&xev.xbutton);
224 break;
225 case ClientMessage:
226 if((Atom) xev.xclient.data.l[0]==deleteWin)
227 done=true;
228 break;
231 ucount++;
232 if(ucount>=((mode==ssNoCD || mode==ssTrayOpen) ? uinterval_e : UINTERVAL_N))
233 checkStatus(false);
234 XFlush(d_display);
235 usleep(50000);
238 XFreeGC(d_display, gc_gc);
239 XFreeGC(d_display, gc_bitgc);
240 XFreePixmap(d_display, pm_tile);
241 XFreePixmap(d_display, pm_disp);
242 XFreePixmap(d_display, pm_mask);
243 XFreePixmap(d_display, pm_cd);
244 XFreePixmap(d_display, pm_cdmask);
245 XFreePixmap(d_display, pm_sym);
246 XFreePixmap(d_display, pm_symmask);
247 XFreePixmap(d_display, pm_led);
248 XFreePixmap(d_display, pm_sled);
249 XFreePixmap(d_display, pm_tled);
250 freeXWin();
251 if(artwrk){
252 free(art_btnptr);
253 free(art_actptr);
255 free(art_btnlist);
256 delete cdctl;
257 return 0;
260 void initXWin(int argc, char **argv){
261 winsize=astep ? ASTEPSIZE : NORMSIZE;
263 if((d_display=XOpenDisplay(display))==NULL){
264 fprintf(stderr,"%s : Unable to open X display '%s'.\n", NAME, XDisplayName(display));
265 exit(1);
267 _XA_GNUSTEP_WM_FUNC=XInternAtom(d_display, "_GNUSTEP_WM_FUNCTION", false);
268 deleteWin=XInternAtom(d_display, "WM_DELETE_WINDOW", false);
270 w_root=DefaultRootWindow(d_display);
272 XWMHints wmhints;
273 XSizeHints shints;
274 shints.x=0;
275 shints.y=0;
276 shints.flags=0;
277 bool pos=(XWMGeometry(d_display, DefaultScreen(d_display), position, NULL, 0, &shints, &shints.x, &shints.y,
278 &shints.width, &shints.height, &shints.win_gravity) & (XValue | YValue));
279 shints.min_width=winsize;
280 shints.min_height=winsize;
281 shints.max_width=winsize;
282 shints.max_height=winsize;
283 shints.base_width=winsize;
284 shints.base_height=winsize;
285 shints.flags=PMinSize | PMaxSize | PBaseSize;
287 createWin(&w_main, shints.x, shints.y);
289 if(wmaker || astep || pos)
290 shints.flags |= USPosition;
291 if(wmaker){
292 wmhints.initial_state=WithdrawnState;
293 wmhints.flags=WindowGroupHint | StateHint | IconWindowHint;
294 createWin(&w_icon, shints.x, shints.y);
295 w_activewin=w_icon;
296 wmhints.icon_window=w_icon;
298 else{
299 wmhints.initial_state=NormalState;
300 wmhints.flags=WindowGroupHint | StateHint;
301 w_activewin=w_main;
303 wmhints.window_group=w_main;
304 XSetWMHints(d_display, w_main, &wmhints);
305 XSetWMNormalHints(d_display, w_main, &shints);
306 XSetCommand(d_display, w_main, argv, argc);
307 XStoreName(d_display, w_main, NAME);
308 XSetIconName(d_display, w_main, NAME);
309 XSetWMProtocols(d_display, w_activewin, &deleteWin, 1);
312 void freeXWin(){
313 XDestroyWindow(d_display, w_main);
314 if(wmaker)
315 XDestroyWindow(d_display, w_icon);
316 XCloseDisplay(d_display);
319 void createWin(Window *win, int x, int y){
320 XClassHint classHint;
321 *win=XCreateSimpleWindow(d_display, w_root, x, y, winsize, winsize, 0, 0, 0);
322 classHint.res_name=const_cast<char *>(NAME);
323 classHint.res_class=const_cast<char *>(CLASS);
324 XSetClassHint(d_display, *win, &classHint);
327 unsigned long getColor(char *colorname){
328 XColor color;
329 XWindowAttributes winattr;
330 XGetWindowAttributes(d_display, w_root, &winattr);
331 color.pixel=0;
332 XParseColor(d_display, winattr.colormap, colorname, &color);
333 color.flags=DoRed | DoGreen | DoBlue;
334 XAllocColor(d_display, winattr.colormap, &color);
335 return color.pixel;
338 unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2){
339 XColor color, color1, color2;
340 XWindowAttributes winattr;
341 XGetWindowAttributes(d_display, w_root, &winattr);
342 XParseColor(d_display, winattr.colormap, colorname1, &color1);
343 XParseColor(d_display, winattr.colormap, colorname2, &color2);
344 color.pixel=0;
345 color.red=(color1.red*prop1+color2.red*prop2)/(prop1+prop2);
346 color.green=(color1.green*prop1+color2.green*prop2)/(prop1+prop2);
347 color.blue=(color1.blue*prop1+color2.blue*prop2)/(prop1+prop2);
348 color.flags=DoRed | DoGreen | DoBlue;
349 XAllocColor(d_display, winattr.colormap, &color);
350 return color.pixel;
353 void scanArgs(int argc, char **argv){
354 for(int i=1;i<argc;i++){
355 if(strcmp(argv[i], "-h")==0 || strcmp(argv[i], "-help")==0 || strcmp(argv[i], "--help")==0){
356 fprintf(stderr, "wmcdplay - A cd player designed for WindowMaker\nRelease " VERSION "\n");
357 fprintf(stderr, "Copyright (C) 1998 Sam Hawker <shawkie@geocities.com>\n");
358 fprintf(stderr, "This software comes with ABSOLUTELY NO WARRANTY\n");
359 fprintf(stderr, "This software is free software, and you are welcome to redistribute it\n");
360 fprintf(stderr, "under certain conditions\n");
361 fprintf(stderr, "See the README file for a more complete notice.\n\n");
362 fprintf(stderr, "usage:\n\n %s [options]\n\noptions:\n\n",argv[0]);
363 fprintf(stderr, " -h | -help | --help display this help screen\n");
364 fprintf(stderr, " -w use WithdrawnState (for WindowMaker)\n");
365 fprintf(stderr, " -s shaped window\n");
366 fprintf(stderr, " -a use smaller window (for AfterStep Wharf)\n");
367 fprintf(stderr, " -f artwork_file load the specified artwork file\n");
368 fprintf(stderr, " -t track_selection set track selection (between 0 and 4)\n");
369 fprintf(stderr, " -v volume set the cdrom volume (between 0 and 255)\n");
370 fprintf(stderr, " -i interval interval in 1/20 seconds between cd polls when empty\n");
371 fprintf(stderr, " -l led_color use the specified color for led displays\n");
372 fprintf(stderr, " -b back_color use the specified color for backgrounds\n");
373 fprintf(stderr, " -d cd_device use specified device (rather than /dev/cdrom)\n");
374 fprintf(stderr, " -position position set window position (see X manual pages)\n");
375 fprintf(stderr, " -display display select target display (see X manual pages)\n\n");
376 exit(0);
378 if(strcmp(argv[i], "-w")==0)
379 wmaker=!wmaker;
380 if(strcmp(argv[i], "-s")==0)
381 ushape=!ushape;
382 if(strcmp(argv[i], "-a")==0)
383 astep=!astep;
384 if(strcmp(argv[i], "-t")==0){
385 if(i<argc-1){
386 i++;
387 sscanf(argv[i], "%i", &tsel);
389 continue;
391 if(strcmp(argv[i], "-v")==0){
392 if(i<argc-1){
393 i++;
394 sscanf(argv[i], "%i", &vol);
396 continue;
398 if(strcmp(argv[i], "-i")==0){
399 if(i<argc-1){
400 i++;
401 sscanf(argv[i], "%i", &uinterval_e);
403 continue;
405 if(strcmp(argv[i], "-f")==0){
406 artwrk=true;
407 if(i<argc-1){
408 i++;
409 sprintf(artwrkf, "%s", argv[i]);
411 continue;
413 if(strcmp(argv[i], "-d")==0){
414 if(i<argc-1){
415 i++;
416 sprintf(cddev, "%s", argv[i]);
418 continue;
420 if(strcmp(argv[i], "-l")==0){
421 if(i<argc-1){
422 i++;
423 sprintf(ledcolor, "%s", argv[i]);
425 continue;
427 if(strcmp(argv[i], "-b")==0){
428 if(i<argc-1){
429 i++;
430 sprintf(backcolor, "%s", argv[i]);
432 continue;
434 if(strcmp(argv[i], "-position")==0){
435 if(i<argc-1){
436 i++;
437 sprintf(position, "%s", argv[i]);
439 continue;
441 if(strcmp(argv[i], "-display")==0){
442 if(i<argc-1){
443 i++;
444 sprintf(display, "%s", argv[i]);
446 continue;
451 void checkStatus(bool forced){
452 ucount=0;
453 int oldmode=mode;
454 int oldpos=pos;
455 int oldtrack=track;
457 cdctl->doStatus();
458 mode=cdctl->getStatusState();
459 track=cdctl->getStatusTrack();
461 if(mode==ssStopped){
462 if(tdisplay==0)
463 pos=0;
464 if(tdisplay==1)
465 pos=cdctl->getTrackStart(track);
467 if(mode==ssPlaying || mode==ssPaused){
468 if(tdisplay==0)
469 pos=cdctl->getStatusPosRel();
470 if(tdisplay==1)
471 pos=cdctl->getStatusPosAbs();
474 bool umode=mode!=oldmode || forced;
475 bool utrack=umode || (!(mode==ssNoCD || mode==ssTrayOpen) && track!=oldtrack);
476 bool utimer=utrack || ((mode==ssPlaying || mode==ssPaused || mode==ssStopped) && (int)(pos/75)!=(int)(oldpos/75));
478 if(utimer){
479 if(umode)
480 update();
481 if(utrack){
482 if(mode==ssNoCD || mode==ssTrayOpen)
483 sprintf(trackstr, " ");
484 else
485 sprintf(trackstr, "%2d", cdctl->getStatusTrack());
486 if(art_showled[1])
487 drawText(art_ledpos[1][0], art_ledpos[1][1], trackstr);
489 if(mode==ssPlaying || mode==ssPaused || mode==ssStopped){
490 int remain = 0;
491 if(tdisplay==0)
492 remain=cdctl->getTrackLen(cdctl->getStatusTrack())-pos;
493 if(tdisplay==1)
494 remain=cdctl->getCDLen()-pos;
495 if(remain<2250)
496 sprintf(timestr, " -;%02d", remain/75);
497 else
498 sprintf(timestr, "%2d:%02d", (pos/75)/60, (pos/75)%60);
500 if(art_showled[0])
501 drawText(art_ledpos[0][0], art_ledpos[0][1], timestr);
502 repaint();
506 void pressEvent(XButtonEvent *xev){
507 int x=xev->x-(winsize/2-32);
508 int y=xev->y-(winsize/2-32);
509 int btn=-1;
510 for(int i=0;i<art_nbtns;i++){
511 if(inPolygon(&art_btnlist[i][2], x, y))
512 btn=i;
514 if(btn==-1){
515 if(art_showled[3]){
516 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]){
517 int tsels[] = { tsNone, tsNext, tsRepeat, tsRepeatCD, tsRandom };
518 tsel++;
519 if(tsel>=5)
520 tsel=0;
521 cdctl->setTrackSelection(tsels[tsel]);
522 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]);
523 repaint();
524 return;
527 if(art_showled[0]){
528 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]){
529 tdisplay++;
530 if(tdisplay>=2)
531 tdisplay=0;
532 checkStatus(false);
533 return;
537 else{
538 int action=art_actptr[6*btn+mode];
539 int acmds[]={ acStop, acPlay, acPause, acResume, acPrev, acNext, acRewd, acFFwd, acEject, acClose };
540 if(action>0){
541 int acmd=acmds[action-1];
542 cdctl->doAudioCommand(acmd);
543 checkStatus(false);
548 void repaint(){
549 XCopyArea(d_display, pm_disp, w_activewin, gc_gc, 0, 0, 64, 64, winsize/2-32, winsize/2-32);
550 XEvent xev;
551 while(XCheckTypedEvent(d_display, Expose, &xev));
554 void update(){
555 if(mode==ssData)
556 sprintf(timestr, "DA_TA");
557 if(mode==ssNoCD)
558 sprintf(timestr, "NO;CD");
559 if(mode==ssTrayOpen)
560 sprintf(timestr, "OP_EN");
562 XPoint mply[art_nbtns];
563 if(pm_cdmask!=None){
564 XSetForeground(d_display, gc_bitgc, 0);
565 XCopyArea(d_display, pm_cdmask, pm_mask, gc_bitgc, 0, 0, 64, 64, 0, 0);
566 for(int i=0; i<art_nbtns; i++){
567 if(art_actptr[6*i+mode]==0 && art_hidebtns){
568 for(int k=0;k<art_btnlist[i][2];k++){
569 mply[k].x=art_btnlist[i][k*2+3];
570 mply[k].y=art_btnlist[i][k*2+4];
572 XFillPolygon(d_display, pm_mask, gc_bitgc, (XPoint *)mply, art_btnlist[i][2], Convex, CoordModeOrigin);
575 if(!(wmaker || ushape || astep)){
576 XCopyArea(d_display, pm_tile, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
577 XSetClipMask(d_display, gc_gc, pm_mask);
580 XCopyArea(d_display, pm_cd, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
581 if(pm_symmask!=None){
582 XSetClipMask(d_display, gc_gc, pm_symmask);
583 XSetClipMask(d_display, gc_bitgc, pm_symmask);
585 XSetForeground(d_display, gc_bitgc, 1);
586 for(int i=0;i<art_nbtns;i++){
587 if(!(art_actptr[6*i+mode]==0 && art_hidebtns)){
588 int sympos=(art_symsize[0]+1)*(art_actptr[6*i+mode]);
589 XSetClipOrigin(d_display, gc_gc, art_btnlist[i][0]-sympos, art_btnlist[i][1]);
590 XSetClipOrigin(d_display, gc_bitgc, art_btnlist[i][0]-sympos, art_btnlist[i][1]);
591 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]);
592 XFillRectangle(d_display, pm_mask, gc_bitgc, art_btnlist[i][0], art_btnlist[i][1], art_symsize[0], art_symsize[1]);
595 if(wmaker || ushape || astep)
596 XShapeCombineMask(d_display, w_activewin, ShapeBounding, winsize/2-32, winsize/2-32, pm_mask, ShapeSet);
597 XSetClipOrigin(d_display, gc_gc, 0, 0);
598 XSetClipOrigin(d_display, gc_bitgc, 0, 0);
599 XSetClipMask(d_display, gc_gc, None);
600 XSetClipMask(d_display, gc_bitgc, None);
601 if(art_showled[2])
602 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]);
603 if(art_showled[3])
604 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]);
607 void drawText(int x, int y, char *text){
608 int drawx=x;
609 for(size_t i=0;i<strlen(text);i++){
610 char *chrptr=strchr(chrset,text[i]);
611 if(chrptr!=NULL){
612 int chrindex=chrptr-chrset;
613 int chrwidth=art_ledsize[0];
614 if(chrset[chrindex+1]==text[i])
615 chrwidth=2*art_ledsize[0]+1;
616 XCopyArea(d_display, pm_led, pm_disp, gc_gc, chrindex*(art_ledsize[0]+1), 0, chrwidth, art_ledsize[1], drawx, y);
617 drawx+=chrwidth+1;
622 bool readArtwork(char *artfilen){
623 FILE *artfile;
624 char artfilenbuf[256];
625 artfile=fopen(artfilen, "r");
626 if(artfile==NULL){
627 if(strchr(artfilen, '/')!=NULL){
628 fprintf(stderr, "%s : Unable to open artwork file '%s'.\n", NAME, artfilen);
629 return false;
631 sprintf(artfilenbuf, "%s/.wmcdplay/%s", getenv("HOME"), artfilen);
632 artfile=fopen(artfilenbuf, "r");
633 if(artfile==NULL){
634 sprintf(artfilenbuf, "%s%s", SYSARTDIR, artfilen);
635 artfile=fopen(artfilenbuf, "r");
636 if(artfile==NULL){
637 fprintf(stderr,"%s : Tried to find artwork file, but failed.\n", NAME);
638 return false;
643 char buf[256];
644 bool done=false;
645 while(!done){
646 if (fgets(buf, 250, artfile) == NULL) {
647 fprintf(stderr,"%s : Error reading artwork file.\n", NAME);
648 return false;
650 done=(feof(artfile)!=0);
651 if(!done){
653 int keynum=0;
654 const char *keystr[]={ "int art_nbtns=",
655 "bool art_hidebtns=",
656 "bool art_showled[4]=",
657 "int art_ledpos[4][2]=",
658 "int art_btns[]=",
659 "int art_actions[]=",
660 "/* XPM */" };
661 for(int i=0;i<7;i++){
662 if(strncmp(buf, keystr[i], strlen(keystr[i]))==0){
663 keynum=i+1;
664 break;
668 if(keynum==1)
669 sscanf(buf+strlen(keystr[keynum-1]), "%d", &art_nbtns);
671 if(keynum==2)
672 art_hidebtns=(strstr(buf+strlen(keystr[keynum-1]), "true")!=NULL);
674 if(keynum==3)
675 readArrayBool((char *)buf, (bool *)art_showled, 4);
677 if(keynum==4)
678 readArrayInt((char *)buf, (int *)art_ledpos, 8);
680 if(keynum>=5){
681 fseek(artfile, -strlen(buf), SEEK_CUR);
682 char *block=readBlock(artfile);
684 if(keynum==5){
685 int items=arrayItems(block);
686 art_btnptr=(int *)malloc(sizeof(int)*items);
687 readArrayInt(block, art_btnptr, items);
690 if(keynum==6){
691 int items=arrayItems(block);
692 art_actptr=(int *)malloc(sizeof(int)*items);
693 readArrayInt(block, art_actptr, items);
696 if(keynum==7){
698 strncpy(buf, strchr(block+strlen(keystr[keynum-1]), '\n')+1, 250);
699 *strchr(buf, '\n')='\0';
701 int w,h;
702 if(strncmp(buf, "static const char * cdplayer_xpm", strlen("static const char * cdplayer_xpm"))==0)
703 createPixmap(NULL, block, &pm_cd, &pm_cdmask, NULL, NULL);
704 if(strncmp(buf, "static const char * symbols_xpm", strlen("static const char * symbols_xpm"))==0){
705 createPixmap(NULL, block, &pm_sym, &pm_symmask, &w, &h);
706 art_symsize[0]=(w+1)/11-1;
707 art_symsize[1]=h;
709 if(strncmp(buf, "static const char * led_xpm", strlen("static const char * led_xpm"))==0){
710 createPixmap(NULL, block, &pm_led, NULL, &w, &h);
711 art_ledsize[0]=(w+1)/strlen(chrset)-1;
712 art_ledsize[1]=h;
714 if(strncmp(buf, "static const char * ledsym_xpm", strlen("static const char * ledsym_xpm"))==0){
715 createPixmap(NULL, block, &pm_sled, NULL, &w, &h);
716 art_ledsize[2]=(w+1)/6-1;
717 art_ledsize[3]=h;
719 if(strncmp(buf, "static const char * ledtsel_xpm", strlen("static const char * ledtsel_xpm"))==0){
720 createPixmap(NULL, block, &pm_tled, NULL, &w, &h);
721 art_ledsize[4]=(w+1)/5-1;
722 art_ledsize[5]=h;
726 free(block);
730 fclose(artfile);
731 return true;
734 char *readBlock(FILE *dfile){
735 char buf[256];
736 long bytes=0;
737 char *block=NULL;
739 if (fgets(buf, 250, dfile) == NULL) {
740 fprintf(stderr,"%s : Error reading artwork file.\n", NAME);
741 return NULL;
743 int buflen=strlen(buf);
744 block=(char *)realloc(block, sizeof(char)*(bytes+buflen+1));
745 strcpy(block+bytes, buf);
746 bytes+=buflen;
747 } while(strstr(buf, "}")==NULL);
748 return block;
751 int arrayItems(char *buf){
752 int items=1;
753 char *bufptr=buf;
754 while((bufptr=strstr(bufptr, ","))!=NULL){
755 bufptr++;
756 items++;
758 return items;
761 void readArrayInt(char *buf, int *array, int n){
762 char *bufptr;
763 bufptr=strtok(buf, "{,}");
764 for(int i=0;i<n;i++){
765 bufptr=strtok(NULL, "{,}");
766 sscanf(bufptr, "%d", &array[i]);
770 void readArrayBool(char *buf, bool *array, int n){
771 char *bufptr;
772 bufptr=strtok(buf, "{,}");
773 for(int i=0;i<n;i++){
774 bufptr=strtok(NULL, "{,}");
775 array[i]=(strstr(bufptr, "true")!=NULL);
779 void createPixmap(const char **data, char *buf, Pixmap *image, Pixmap *mask, int *width, int *height){
780 XpmAttributes xpmattr;
781 XpmColorSymbol xpmcsym[4]={
782 {const_cast<char *>("back_color"), NULL, color[0]},
783 {const_cast<char *>("led_color_high"), NULL, color[1]},
784 {const_cast<char *>("led_color_med"), NULL, color[2]},
785 {const_cast<char *>("led_color_low"), NULL, color[3]}};
786 xpmattr.numsymbols=4;
787 xpmattr.colorsymbols=xpmcsym;
788 xpmattr.exactColors=false;
789 xpmattr.closeness=40000;
790 xpmattr.valuemask=XpmColorSymbols | XpmExactColors | XpmCloseness | XpmSize;
791 if(data!=NULL)
792 XpmCreatePixmapFromData(d_display, w_root, const_cast<char **>(data),
793 image, mask, &xpmattr);
794 else
795 XpmCreatePixmapFromBuffer(d_display, w_root, buf, image, mask, &xpmattr);
796 if(width!=NULL)
797 *width=xpmattr.width;
798 if(height!=NULL)
799 *height=xpmattr.height;
802 void setBtnList(int *bset){
803 // Create a list of pointers to button data.
804 // So, for example, data for button 2 can be accessed as art_btnlist[2];
805 // Also, the y co-ordinate of its symbol would be art_btnlist[2][1]
807 art_btnlist=(int **)malloc(art_nbtns*sizeof(int *));
808 int curpos=0;
809 for(int i=0;i<art_nbtns;i++){
810 art_btnlist[i]=&bset[0+curpos];
811 curpos+=2*art_btnlist[i][2]+3;
815 bool inPolygon(int *points, int px, int py){
816 int lx=points[1];
817 int ly=points[2];
818 int x,y;
819 for(int i=1;i<=points[0];i++){
820 if(i==points[0]){
821 x=points[1];
822 y=points[2];
824 else{
825 x=points[i*2+1];
826 y=points[i*2+2];
828 int a=ly-y;
829 int b=x-lx;
830 int c=-a*x-b*y;
831 if(a*px+b*py+c<0)
832 return false;
833 lx=x;
834 ly=y;
836 return true;