838 lines
26 KiB
C++
838 lines
26 KiB
C++
// wmcdplay - A cd player designed for WindowMaker
|
|
// Copyright (C) 1998 Sam Hawker <shawkie@geocities.com>
|
|
// This software comes with ABSOLUTELY NO WARRANTY
|
|
// This software is free software, and you are welcome to redistribute it
|
|
// under certain conditions
|
|
// See the README file for a more complete notice.
|
|
|
|
|
|
// Defines, includes and global variables
|
|
// --------------------------------------
|
|
|
|
// User defines - standard
|
|
#define WINDOWMAKER false
|
|
#define USESHAPE false
|
|
#define AFTERSTEP false
|
|
#define NORMSIZE 64
|
|
#define ASTEPSIZE 56
|
|
#define NAME "wmcdplay"
|
|
#define CLASS "WMCDPlay"
|
|
|
|
// User defines - custom
|
|
#define CDDEV "/dev/cdrom"
|
|
#define BACKCOLOR "#282828"
|
|
#define LEDCOLOR "green"
|
|
#define POSRELABS 0 // 0=relative position, 1=absolute position
|
|
#define UINTERVAL_N 1 // 20ths of a second
|
|
#define UINTERVAL_E 20 // 20ths of a second
|
|
|
|
// Includes - standard
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
// Includes - custom
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
#include "cdctl_freebsd.h"
|
|
#else
|
|
#include "cdctl.h"
|
|
#endif
|
|
|
|
// X-Windows includes - standard
|
|
#include <X11/X.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/xpm.h>
|
|
#include <X11/extensions/shape.h>
|
|
|
|
// Pixmaps - standard
|
|
Pixmap pm_tile;
|
|
Pixmap pm_disp;
|
|
Pixmap pm_mask;
|
|
|
|
// Pixmaps - artwork
|
|
Pixmap pm_cd;
|
|
Pixmap pm_cdmask;
|
|
Pixmap pm_sym;
|
|
Pixmap pm_symmask;
|
|
Pixmap pm_led;
|
|
Pixmap pm_sled;
|
|
Pixmap pm_tled;
|
|
|
|
// Xpm images - standard
|
|
#include "XPM/tile.xpm"
|
|
|
|
// Xpm images - artwork
|
|
#include "XPM/standard.art"
|
|
|
|
// Variables for command-line arguments - standard
|
|
bool wmaker=WINDOWMAKER;
|
|
bool ushape=USESHAPE;
|
|
bool astep=AFTERSTEP;
|
|
char display[256]="";
|
|
char position[256]="";
|
|
int winsize;
|
|
|
|
// Variables for command-line arguments - custom
|
|
char cddev[256]=CDDEV;
|
|
char backcolor[256]=BACKCOLOR;
|
|
char ledcolor[256]=LEDCOLOR;
|
|
bool artwrk=false;
|
|
char artwrkf[256]="";
|
|
int tsel=1;
|
|
int vol=-1; // -1 means don't set volume
|
|
int uinterval_e=UINTERVAL_E;
|
|
|
|
// X-Windows basics - standard
|
|
Atom _XA_GNUSTEP_WM_FUNC;
|
|
Atom deleteWin;
|
|
Display *d_display;
|
|
Window w_icon;
|
|
Window w_main;
|
|
Window w_root;
|
|
Window w_activewin;
|
|
|
|
// X-Windows basics - custom
|
|
GC gc_gc, gc_bitgc;
|
|
unsigned long color[4];
|
|
|
|
|
|
// Misc custom global variables
|
|
// ----------------------------
|
|
|
|
// For artwork loading
|
|
int **art_btnlist;
|
|
int *art_btnptr;
|
|
int *art_actptr;
|
|
int art_symsize[2];
|
|
int art_ledsize[6];
|
|
|
|
int mode=-1, track=-1, pos=-1;
|
|
int tdisplay=POSRELABS;
|
|
int ucount=0;
|
|
char trackstr[8]="";
|
|
char timestr[8]="";
|
|
char chrset[]="00112233445566778899 DDAATTNNOOCC--PPEE:;_";
|
|
|
|
CDCtl *cdctl;
|
|
|
|
|
|
// Procedures and functions
|
|
// ------------------------
|
|
|
|
// Procedures and functions - standard
|
|
void initXWin(int argc, char **argv);
|
|
void freeXWin();
|
|
void createWin(Window *win, int x, int y);
|
|
unsigned long getColor(char *colorname);
|
|
unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2);
|
|
|
|
// Procedures and functions - custom
|
|
void scanArgs(int argc, char **argv);
|
|
void checkStatus(bool forced);
|
|
void pressEvent(XButtonEvent *xev);
|
|
void repaint();
|
|
void update();
|
|
void drawText(int x, int y, char *text);
|
|
|
|
// Procedures and functions - artwork basics
|
|
bool readArtwork(char *artfilen);
|
|
char *readBlock(FILE *dfile);
|
|
int arrayItems(char *buf);
|
|
void readArrayInt(char *buf, int *array, int n);
|
|
void readArrayBool(char *buf, bool *array, int n);
|
|
|
|
// Procedures and functions - artwork specials
|
|
void createPixmap(const char **data, char *buf, Pixmap *image, Pixmap *mask, int *width, int *height);
|
|
void setBtnList(int *bset);
|
|
bool inPolygon(int *points, int px, int py);
|
|
|
|
|
|
// Implementation
|
|
// --------------
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
scanArgs(argc, argv);
|
|
initXWin(argc, argv);
|
|
|
|
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);
|
|
|
|
if(artwrk)
|
|
artwrk=readArtwork(artwrkf);
|
|
if(!artwrk){
|
|
int w, h;
|
|
createPixmap(cdplayer_xpm, NULL, &pm_cd, &pm_cdmask, NULL, NULL);
|
|
createPixmap(symbols_xpm, NULL, &pm_sym, &pm_symmask, &w, &h);
|
|
art_symsize[0]=(w+1)/11-1;
|
|
art_symsize[1]=h;
|
|
createPixmap(led_xpm, NULL, &pm_led, NULL, &w, &h);
|
|
art_ledsize[0]=(w+1)/strlen(chrset)-1;
|
|
art_ledsize[1]=h;
|
|
createPixmap(ledsym_xpm, NULL, &pm_sled, NULL, &w, &h);
|
|
art_ledsize[2]=(w+1)/6-1;
|
|
art_ledsize[3]=h;
|
|
createPixmap(ledtsel_xpm, NULL, &pm_tled, NULL, &w, &h);
|
|
art_ledsize[4]=(w+1)/5-1;
|
|
art_ledsize[5]=h;
|
|
art_btnptr=art_btns;
|
|
art_actptr=art_actions;
|
|
}
|
|
setBtnList(art_btnptr);
|
|
createPixmap(tile_xpm, NULL, &pm_tile, NULL, NULL, NULL);
|
|
pm_disp = XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, DefaultScreen(d_display)));
|
|
pm_mask = XCreatePixmap(d_display, w_root, 64, 64, 1);
|
|
|
|
XGCValues gcv;
|
|
unsigned long gcm;
|
|
gcm=GCGraphicsExposures;
|
|
gcv.graphics_exposures=false;
|
|
gc_gc=XCreateGC(d_display, w_root, gcm, &gcv);
|
|
gc_bitgc=XCreateGC(d_display, pm_mask, gcm, &gcv);
|
|
|
|
cdctl=new CDCtl(cddev);
|
|
|
|
if(!cdctl->openOK())
|
|
fprintf(stderr, "%s : Unable to open cdrom device '%s'.\n", NAME, cddev);
|
|
else{
|
|
if(vol!=-1)
|
|
cdctl->setVolume(vol, vol);
|
|
int tsels[] = { tsNone, tsNext, tsRepeat, tsRepeatCD, tsRandom };
|
|
cdctl->setTrackSelection(tsels[tsel]);
|
|
|
|
checkStatus(true);
|
|
|
|
XEvent xev;
|
|
XSelectInput(d_display, w_activewin, ButtonPress | ExposureMask);
|
|
XMapWindow(d_display, w_main);
|
|
|
|
bool done=false;
|
|
while(!done){
|
|
while(XPending(d_display)){
|
|
XNextEvent(d_display, &xev);
|
|
switch(xev.type){
|
|
case Expose:
|
|
repaint();
|
|
break;
|
|
case ButtonPress:
|
|
pressEvent(&xev.xbutton);
|
|
break;
|
|
case ClientMessage:
|
|
if((Atom) xev.xclient.data.l[0]==deleteWin)
|
|
done=true;
|
|
break;
|
|
}
|
|
}
|
|
ucount++;
|
|
if(ucount>=((mode==ssNoCD || mode==ssTrayOpen) ? uinterval_e : UINTERVAL_N))
|
|
checkStatus(false);
|
|
XFlush(d_display);
|
|
usleep(50000);
|
|
}
|
|
}
|
|
XFreeGC(d_display, gc_gc);
|
|
XFreeGC(d_display, gc_bitgc);
|
|
XFreePixmap(d_display, pm_tile);
|
|
XFreePixmap(d_display, pm_disp);
|
|
XFreePixmap(d_display, pm_mask);
|
|
XFreePixmap(d_display, pm_cd);
|
|
XFreePixmap(d_display, pm_cdmask);
|
|
XFreePixmap(d_display, pm_sym);
|
|
XFreePixmap(d_display, pm_symmask);
|
|
XFreePixmap(d_display, pm_led);
|
|
XFreePixmap(d_display, pm_sled);
|
|
XFreePixmap(d_display, pm_tled);
|
|
freeXWin();
|
|
if(artwrk){
|
|
free(art_btnptr);
|
|
free(art_actptr);
|
|
}
|
|
free(art_btnlist);
|
|
delete cdctl;
|
|
return 0;
|
|
}
|
|
|
|
void initXWin(int argc, char **argv){
|
|
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", false);
|
|
deleteWin=XInternAtom(d_display, "WM_DELETE_WINDOW", false);
|
|
|
|
w_root=DefaultRootWindow(d_display);
|
|
|
|
XWMHints wmhints;
|
|
XSizeHints shints;
|
|
shints.x=0;
|
|
shints.y=0;
|
|
shints.flags=0;
|
|
bool 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=const_cast<char *>(NAME);
|
|
classHint.res_class=const_cast<char *>(CLASS);
|
|
XSetClassHint(d_display, *win, &classHint);
|
|
}
|
|
|
|
unsigned long getColor(char *colorname){
|
|
XColor color;
|
|
XWindowAttributes winattr;
|
|
XGetWindowAttributes(d_display, w_root, &winattr);
|
|
color.pixel=0;
|
|
XParseColor(d_display, winattr.colormap, colorname, &color);
|
|
color.flags=DoRed | DoGreen | DoBlue;
|
|
XAllocColor(d_display, winattr.colormap, &color);
|
|
return color.pixel;
|
|
}
|
|
|
|
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 scanArgs(int argc, char **argv){
|
|
for(int i=1;i<argc;i++){
|
|
if(strcmp(argv[i], "-h")==0 || strcmp(argv[i], "-help")==0 || strcmp(argv[i], "--help")==0){
|
|
fprintf(stderr, "wmcdplay - A cd player designed for WindowMaker\nRelease "VERSION"\n");
|
|
fprintf(stderr, "Copyright (C) 1998 Sam Hawker <shawkie@geocities.com>\n");
|
|
fprintf(stderr, "This software comes with ABSOLUTELY NO WARRANTY\n");
|
|
fprintf(stderr, "This software is free software, and you are welcome to redistribute it\n");
|
|
fprintf(stderr, "under certain conditions\n");
|
|
fprintf(stderr, "See the README file for a more complete notice.\n\n");
|
|
fprintf(stderr, "usage:\n\n %s [options]\n\noptions:\n\n",argv[0]);
|
|
fprintf(stderr, " -h | -help | --help display this help screen\n");
|
|
fprintf(stderr, " -w use WithdrawnState (for WindowMaker)\n");
|
|
fprintf(stderr, " -s shaped window\n");
|
|
fprintf(stderr, " -a use smaller window (for AfterStep Wharf)\n");
|
|
fprintf(stderr, " -f artwork_file load the specified artwork file\n");
|
|
fprintf(stderr, " -t track_selection set track selection (between 0 and 4)\n");
|
|
fprintf(stderr, " -v volume set the cdrom volume (between 0 and 255)\n");
|
|
fprintf(stderr, " -i interval interval in 1/20 seconds between cd polls when empty\n");
|
|
fprintf(stderr, " -l led_color use the specified color for led displays\n");
|
|
fprintf(stderr, " -b back_color use the specified color for backgrounds\n");
|
|
fprintf(stderr, " -d cd_device use specified device (rather than /dev/cdrom)\n");
|
|
fprintf(stderr, " -position position set window position (see X manual pages)\n");
|
|
fprintf(stderr, " -display display select target display (see X manual pages)\n\n");
|
|
exit(0);
|
|
}
|
|
if(strcmp(argv[i], "-w")==0)
|
|
wmaker=!wmaker;
|
|
if(strcmp(argv[i], "-s")==0)
|
|
ushape=!ushape;
|
|
if(strcmp(argv[i], "-a")==0)
|
|
astep=!astep;
|
|
if(strcmp(argv[i], "-t")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sscanf(argv[i], "%i", &tsel);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-v")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sscanf(argv[i], "%i", &vol);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-i")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sscanf(argv[i], "%i", &uinterval_e);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-f")==0){
|
|
artwrk=true;
|
|
if(i<argc-1){
|
|
i++;
|
|
sprintf(artwrkf, "%s", argv[i]);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-d")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sprintf(cddev, "%s", argv[i]);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-l")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sprintf(ledcolor, "%s", argv[i]);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-b")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sprintf(backcolor, "%s", argv[i]);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-position")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sprintf(position, "%s", argv[i]);
|
|
}
|
|
continue;
|
|
}
|
|
if(strcmp(argv[i], "-display")==0){
|
|
if(i<argc-1){
|
|
i++;
|
|
sprintf(display, "%s", argv[i]);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
void checkStatus(bool forced){
|
|
ucount=0;
|
|
int oldmode=mode;
|
|
int oldpos=pos;
|
|
int oldtrack=track;
|
|
|
|
cdctl->doStatus();
|
|
mode=cdctl->getStatusState();
|
|
track=cdctl->getStatusTrack();
|
|
|
|
if(mode==ssStopped){
|
|
if(tdisplay==0)
|
|
pos=0;
|
|
if(tdisplay==1)
|
|
pos=cdctl->getTrackStart(track);
|
|
}
|
|
if(mode==ssPlaying || mode==ssPaused){
|
|
if(tdisplay==0)
|
|
pos=cdctl->getStatusPosRel();
|
|
if(tdisplay==1)
|
|
pos=cdctl->getStatusPosAbs();
|
|
}
|
|
|
|
bool umode=mode!=oldmode || forced;
|
|
bool utrack=umode || (!(mode==ssNoCD || mode==ssTrayOpen) && track!=oldtrack);
|
|
bool utimer=utrack || ((mode==ssPlaying || mode==ssPaused || mode==ssStopped) && (int)(pos/75)!=(int)(oldpos/75));
|
|
|
|
if(utimer){
|
|
if(umode)
|
|
update();
|
|
if(utrack){
|
|
if(mode==ssNoCD || mode==ssTrayOpen)
|
|
sprintf(trackstr, " ");
|
|
else
|
|
sprintf(trackstr, "%2d", cdctl->getStatusTrack());
|
|
if(art_showled[1])
|
|
drawText(art_ledpos[1][0], art_ledpos[1][1], trackstr);
|
|
}
|
|
if(mode==ssPlaying || mode==ssPaused || mode==ssStopped){
|
|
int remain = 0;
|
|
if(tdisplay==0)
|
|
remain=cdctl->getTrackLen(cdctl->getStatusTrack())-pos;
|
|
if(tdisplay==1)
|
|
remain=cdctl->getCDLen()-pos;
|
|
if(remain<2250)
|
|
sprintf(timestr, " -;%02d", remain/75);
|
|
else
|
|
sprintf(timestr, "%2d:%02d", (pos/75)/60, (pos/75)%60);
|
|
}
|
|
if(art_showled[0])
|
|
drawText(art_ledpos[0][0], art_ledpos[0][1], timestr);
|
|
repaint();
|
|
}
|
|
}
|
|
|
|
void pressEvent(XButtonEvent *xev){
|
|
int x=xev->x-(winsize/2-32);
|
|
int y=xev->y-(winsize/2-32);
|
|
int btn=-1;
|
|
for(int i=0;i<art_nbtns;i++){
|
|
if(inPolygon(&art_btnlist[i][2], x, y))
|
|
btn=i;
|
|
}
|
|
if(btn==-1){
|
|
if(art_showled[3]){
|
|
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]){
|
|
int tsels[] = { tsNone, tsNext, tsRepeat, tsRepeatCD, tsRandom };
|
|
tsel++;
|
|
if(tsel>=5)
|
|
tsel=0;
|
|
cdctl->setTrackSelection(tsels[tsel]);
|
|
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]);
|
|
repaint();
|
|
return;
|
|
}
|
|
}
|
|
if(art_showled[0]){
|
|
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]){
|
|
tdisplay++;
|
|
if(tdisplay>=2)
|
|
tdisplay=0;
|
|
checkStatus(false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
int action=art_actptr[6*btn+mode];
|
|
int acmds[]={ acStop, acPlay, acPause, acResume, acPrev, acNext, acRewd, acFFwd, acEject, acClose };
|
|
if(action>0){
|
|
int acmd=acmds[action-1];
|
|
cdctl->doAudioCommand(acmd);
|
|
checkStatus(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void repaint(){
|
|
XCopyArea(d_display, pm_disp, w_activewin, gc_gc, 0, 0, 64, 64, winsize/2-32, winsize/2-32);
|
|
XEvent xev;
|
|
while(XCheckTypedEvent(d_display, Expose, &xev));
|
|
}
|
|
|
|
void update(){
|
|
if(mode==ssData)
|
|
sprintf(timestr, "DA_TA");
|
|
if(mode==ssNoCD)
|
|
sprintf(timestr, "NO;CD");
|
|
if(mode==ssTrayOpen)
|
|
sprintf(timestr, "OP_EN");
|
|
|
|
XPoint mply[art_nbtns];
|
|
if(pm_cdmask!=None){
|
|
XSetForeground(d_display, gc_bitgc, 0);
|
|
XCopyArea(d_display, pm_cdmask, pm_mask, gc_bitgc, 0, 0, 64, 64, 0, 0);
|
|
for(int i=0; i<art_nbtns; i++){
|
|
if(art_actptr[6*i+mode]==0 && art_hidebtns){
|
|
for(int k=0;k<art_btnlist[i][2];k++){
|
|
mply[k].x=art_btnlist[i][k*2+3];
|
|
mply[k].y=art_btnlist[i][k*2+4];
|
|
}
|
|
XFillPolygon(d_display, pm_mask, gc_bitgc, (XPoint *)mply, art_btnlist[i][2], Convex, CoordModeOrigin);
|
|
}
|
|
}
|
|
if(!(wmaker || ushape || astep)){
|
|
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_cd, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
|
|
if(pm_symmask!=None){
|
|
XSetClipMask(d_display, gc_gc, pm_symmask);
|
|
XSetClipMask(d_display, gc_bitgc, pm_symmask);
|
|
}
|
|
XSetForeground(d_display, gc_bitgc, 1);
|
|
for(int i=0;i<art_nbtns;i++){
|
|
if(!(art_actptr[6*i+mode]==0 && art_hidebtns)){
|
|
int sympos=(art_symsize[0]+1)*(art_actptr[6*i+mode]);
|
|
XSetClipOrigin(d_display, gc_gc, art_btnlist[i][0]-sympos, art_btnlist[i][1]);
|
|
XSetClipOrigin(d_display, gc_bitgc, art_btnlist[i][0]-sympos, art_btnlist[i][1]);
|
|
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]);
|
|
XFillRectangle(d_display, pm_mask, gc_bitgc, art_btnlist[i][0], art_btnlist[i][1], art_symsize[0], art_symsize[1]);
|
|
}
|
|
}
|
|
if(wmaker || ushape || astep)
|
|
XShapeCombineMask(d_display, w_activewin, ShapeBounding, winsize/2-32, winsize/2-32, pm_mask, ShapeSet);
|
|
XSetClipOrigin(d_display, gc_gc, 0, 0);
|
|
XSetClipOrigin(d_display, gc_bitgc, 0, 0);
|
|
XSetClipMask(d_display, gc_gc, None);
|
|
XSetClipMask(d_display, gc_bitgc, None);
|
|
if(art_showled[2])
|
|
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]);
|
|
if(art_showled[3])
|
|
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]);
|
|
}
|
|
|
|
void drawText(int x, int y, char *text){
|
|
int drawx=x;
|
|
for(size_t i=0;i<strlen(text);i++){
|
|
char *chrptr=strchr(chrset,text[i]);
|
|
if(chrptr!=NULL){
|
|
int chrindex=chrptr-chrset;
|
|
int chrwidth=art_ledsize[0];
|
|
if(chrset[chrindex+1]==text[i])
|
|
chrwidth=2*art_ledsize[0]+1;
|
|
XCopyArea(d_display, pm_led, pm_disp, gc_gc, chrindex*(art_ledsize[0]+1), 0, chrwidth, art_ledsize[1], drawx, y);
|
|
drawx+=chrwidth+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool readArtwork(char *artfilen){
|
|
FILE *artfile;
|
|
char artfilenbuf[256];
|
|
artfile=fopen(artfilen, "r");
|
|
if(artfile==NULL){
|
|
if(strchr(artfilen, '/')!=NULL){
|
|
fprintf(stderr, "%s : Unable to open artwork file '%s'.\n", NAME, artfilen);
|
|
return false;
|
|
}
|
|
sprintf(artfilenbuf, "%s/.wmcdplay/%s", getenv("HOME"), artfilen);
|
|
artfile=fopen(artfilenbuf, "r");
|
|
if(artfile==NULL){
|
|
sprintf(artfilenbuf, "%s%s", SYSARTDIR, artfilen);
|
|
artfile=fopen(artfilenbuf, "r");
|
|
if(artfile==NULL){
|
|
fprintf(stderr,"%s : Tried to find artwork file, but failed.\n", NAME);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
char buf[256];
|
|
bool done=false;
|
|
while(!done){
|
|
if (fgets(buf, 250, artfile) == NULL) {
|
|
fprintf(stderr,"%s : Error reading artwork file.\n", NAME);
|
|
return false;
|
|
}
|
|
done=(feof(artfile)!=0);
|
|
if(!done){
|
|
|
|
int keynum=0;
|
|
const char *keystr[]={ "int art_nbtns=",
|
|
"bool art_hidebtns=",
|
|
"bool art_showled[4]=",
|
|
"int art_ledpos[4][2]=",
|
|
"int art_btns[]=",
|
|
"int art_actions[]=",
|
|
"/* XPM */" };
|
|
for(int i=0;i<7;i++){
|
|
if(strncmp(buf, keystr[i], strlen(keystr[i]))==0){
|
|
keynum=i+1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(keynum==1)
|
|
sscanf(buf+strlen(keystr[keynum-1]), "%d", &art_nbtns);
|
|
|
|
if(keynum==2)
|
|
art_hidebtns=(strstr(buf+strlen(keystr[keynum-1]), "true")!=NULL);
|
|
|
|
if(keynum==3)
|
|
readArrayBool((char *)buf, (bool *)art_showled, 4);
|
|
|
|
if(keynum==4)
|
|
readArrayInt((char *)buf, (int *)art_ledpos, 8);
|
|
|
|
if(keynum>=5){
|
|
fseek(artfile, -strlen(buf), SEEK_CUR);
|
|
char *block=readBlock(artfile);
|
|
|
|
if(keynum==5){
|
|
int items=arrayItems(block);
|
|
art_btnptr=(int *)malloc(sizeof(int)*items);
|
|
readArrayInt(block, art_btnptr, items);
|
|
}
|
|
|
|
if(keynum==6){
|
|
int items=arrayItems(block);
|
|
art_actptr=(int *)malloc(sizeof(int)*items);
|
|
readArrayInt(block, art_actptr, items);
|
|
}
|
|
|
|
if(keynum==7){
|
|
|
|
strncpy(buf, strchr(block+strlen(keystr[keynum-1]), '\n')+1, 250);
|
|
*strchr(buf, '\n')='\0';
|
|
|
|
int w,h;
|
|
if(strncmp(buf, "static const char * cdplayer_xpm", strlen("static const char * cdplayer_xpm"))==0)
|
|
createPixmap(NULL, block, &pm_cd, &pm_cdmask, NULL, NULL);
|
|
if(strncmp(buf, "static const char * symbols_xpm", strlen("static const char * symbols_xpm"))==0){
|
|
createPixmap(NULL, block, &pm_sym, &pm_symmask, &w, &h);
|
|
art_symsize[0]=(w+1)/11-1;
|
|
art_symsize[1]=h;
|
|
}
|
|
if(strncmp(buf, "static const char * led_xpm", strlen("static const char * led_xpm"))==0){
|
|
createPixmap(NULL, block, &pm_led, NULL, &w, &h);
|
|
art_ledsize[0]=(w+1)/strlen(chrset)-1;
|
|
art_ledsize[1]=h;
|
|
}
|
|
if(strncmp(buf, "static const char * ledsym_xpm", strlen("static const char * ledsym_xpm"))==0){
|
|
createPixmap(NULL, block, &pm_sled, NULL, &w, &h);
|
|
art_ledsize[2]=(w+1)/6-1;
|
|
art_ledsize[3]=h;
|
|
}
|
|
if(strncmp(buf, "static const char * ledtsel_xpm", strlen("static const char * ledtsel_xpm"))==0){
|
|
createPixmap(NULL, block, &pm_tled, NULL, &w, &h);
|
|
art_ledsize[4]=(w+1)/5-1;
|
|
art_ledsize[5]=h;
|
|
}
|
|
|
|
}
|
|
free(block);
|
|
}
|
|
}
|
|
}
|
|
fclose(artfile);
|
|
return true;
|
|
}
|
|
|
|
char *readBlock(FILE *dfile){
|
|
char buf[256];
|
|
long bytes=0;
|
|
char *block=NULL;
|
|
do{
|
|
if (fgets(buf, 250, dfile) == NULL) {
|
|
fprintf(stderr,"%s : Error reading artwork file.\n", NAME);
|
|
return NULL;
|
|
}
|
|
int buflen=strlen(buf);
|
|
block=(char *)realloc(block, sizeof(char)*(bytes+buflen+1));
|
|
strcpy(block+bytes, buf);
|
|
bytes+=buflen;
|
|
} while(strstr(buf, "}")==NULL);
|
|
return block;
|
|
}
|
|
|
|
int arrayItems(char *buf){
|
|
int items=1;
|
|
char *bufptr=buf;
|
|
while((bufptr=strstr(bufptr, ","))!=NULL){
|
|
bufptr++;
|
|
items++;
|
|
};
|
|
return items;
|
|
}
|
|
|
|
void readArrayInt(char *buf, int *array, int n){
|
|
char *bufptr;
|
|
bufptr=strtok(buf, "{,}");
|
|
for(int i=0;i<n;i++){
|
|
bufptr=strtok(NULL, "{,}");
|
|
sscanf(bufptr, "%d", &array[i]);
|
|
}
|
|
}
|
|
|
|
void readArrayBool(char *buf, bool *array, int n){
|
|
char *bufptr;
|
|
bufptr=strtok(buf, "{,}");
|
|
for(int i=0;i<n;i++){
|
|
bufptr=strtok(NULL, "{,}");
|
|
array[i]=(strstr(bufptr, "true")!=NULL);
|
|
}
|
|
}
|
|
|
|
void createPixmap(const char **data, char *buf, Pixmap *image, Pixmap *mask, int *width, int *height){
|
|
XpmAttributes xpmattr;
|
|
XpmColorSymbol xpmcsym[4]={
|
|
{const_cast<char *>("back_color"), NULL, color[0]},
|
|
{const_cast<char *>("led_color_high"), NULL, color[1]},
|
|
{const_cast<char *>("led_color_med"), NULL, color[2]},
|
|
{const_cast<char *>("led_color_low"), NULL, color[3]}};
|
|
xpmattr.numsymbols=4;
|
|
xpmattr.colorsymbols=xpmcsym;
|
|
xpmattr.exactColors=false;
|
|
xpmattr.closeness=40000;
|
|
xpmattr.valuemask=XpmColorSymbols | XpmExactColors | XpmCloseness | XpmSize;
|
|
if(data!=NULL)
|
|
XpmCreatePixmapFromData(d_display, w_root, const_cast<char **>(data),
|
|
image, mask, &xpmattr);
|
|
else
|
|
XpmCreatePixmapFromBuffer(d_display, w_root, buf, image, mask, &xpmattr);
|
|
if(width!=NULL)
|
|
*width=xpmattr.width;
|
|
if(height!=NULL)
|
|
*height=xpmattr.height;
|
|
}
|
|
|
|
void setBtnList(int *bset){
|
|
// Create a list of pointers to button data.
|
|
// So, for example, data for button 2 can be accessed as art_btnlist[2];
|
|
// Also, the y co-ordinate of its symbol would be art_btnlist[2][1]
|
|
|
|
art_btnlist=(int **)malloc(art_nbtns*sizeof(int *));
|
|
int curpos=0;
|
|
for(int i=0;i<art_nbtns;i++){
|
|
art_btnlist[i]=&bset[0+curpos];
|
|
curpos+=2*art_btnlist[i][2]+3;
|
|
}
|
|
}
|
|
|
|
bool inPolygon(int *points, int px, int py){
|
|
int lx=points[1];
|
|
int ly=points[2];
|
|
int x,y;
|
|
for(int i=1;i<=points[0];i++){
|
|
if(i==points[0]){
|
|
x=points[1];
|
|
y=points[2];
|
|
}
|
|
else{
|
|
x=points[i*2+1];
|
|
y=points[i*2+2];
|
|
}
|
|
int a=ly-y;
|
|
int b=x-lx;
|
|
int c=-a*x-b*y;
|
|
if(a*px+b*py+c<0)
|
|
return false;
|
|
lx=x;
|
|
ly=y;
|
|
}
|
|
return true;
|
|
}
|