/* -*- mode: C; mode: folding -*- */
/*****************************************************************************/
/* ascd - AfterStep CD                                                       */
/* Version 0.7                                                              */
/* By Rob Malda                                                              */
/* malda@cs.hope.edu                                                         */
/* http://www.cs.hope.edu/~malda/                                            */
/*                                                                           */
/* This is an 'AfterStep Look & Feel' Wharf style applet that can be         */
/* used to control an IDE CD Changer.                                        */
/*****************************************************************************/

/* --------------------------------------------------------------------------
 * version "0.4+": (denis) a lot of changes to allow ascd to compile on
 * several OS, not only Linux. Added some new functions, see the CHANGES
 * --------------------------------------------------------------------------
 * version "0.6+": (denis, 97/09/04) took the Window Maker code changes
 * from ascd 0.6 and fixed some stupid little bugs, again see CHANGES
 * --------------------------------------------------------------------------
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>

#include <errno.h>
#include <unistd.h>

#ifndef FALSE
#  define FALSE 0
#endif
#ifndef TRUE
#  define TRUE 1
#endif

#include "struct.h"

/* XPM struct and icons ******************************/

/*{{{*/
typedef struct _XpmIcon {
    Pixmap pixmap;
    Pixmap mask;
    XpmAttributes attributes;
} XpmIcon;

XpmIcon cdplayerXPM,  ledXPM, cdpausedXPM, currentXPM;
XpmIcon barXPM;

#include "cdplayer.xpm"
#include "cdpaused.xpm"
#include "bar.xpm"
/*}}}*/

/* Functions ***************************************/

/*{{{*/
void	Help(void);
void	CreateWindow(int, char **);
void	ParseCmdLine(int argc, char *argv[]);
void	MainLoop();
void	GetXPM(char *);
int FlushExpose(Window w);
void	RedrawWindow( XpmIcon *v);
Pixel GetColor(char *name);
void	cdcontrol(int control);
void   cd_volume(int vol, int bal, int max);
/*}}}*/

/* Global stuff *****************************************/

/*{{{*/
#define DEFAULTDEVICE "/dev/cdrom"

#define PLAY 0
#define PAUSE 1
#define STOP 2
#define UPTRACK 3
#define DNTRACK 4
#define CUE 5
#define REV 6
#define FIRST 7
#define LAST 8
#define LOOP 9
#define DIRECTACCESS 10
#define INTROSCAN 11
#define INTRONEXT 12
#define LOCACCESS 13

int lasttime=-1;
Display *Disp;
Window Root;
Window Iconwin;
Window Win;
char *Geometry = 0;
char device[128]=DEFAULTDEVICE;
int withdrawn=FALSE;

int currenttrack=0;
int maxtracks=31;

int paused=FALSE;
int playing=FALSE;

GC WinGC;
int CarrierOn = FALSE;

/* (denis) globals from Workman src: */

extern cd_status();
extern play_cd();
extern stop_cd();
extern eject_cd();
extern pause_cd();

extern int cur_track, cur_index, cur_lasttrack, cur_firsttrack, cur_pos_abs ;
extern int cur_frame, cur_pos_rel, cur_tracklen, cur_cdlen, cur_ntracks ;
extern int cur_nsections, cur_listno, cur_stopmode, exit_on_eject, cur_balance ;
extern enum cd_modes cur_cdmode;
extern char *cur_artist, *cur_cdname, *cur_trackname;
extern char cur_contd, cur_avoid;
extern char *cd_device;
extern struct cdinfo_wm thiscd, *cd;

int cur_balance = 10;
int info_modified = 0;

/* (denis) my globals : */

#define MAX_VOL 256
#define DEFAULT_COLOUR "#1faf9f"

unsigned int time_mode = 0;     /* display mode for the counter. see function RedrawWindow() */
unsigned int cue_time = 10;     /* nbr of seconds for cue -> see -c command line option */
unsigned int vol_step = 5;      /* Volume to set when right click on display */
unsigned int autoplay = 0;      /* if set, play a disk when it is inserted -> see -a c.l. option  */
unsigned int datatrack = 0;     /* is the current track a data track ? */
unsigned int direct_access = 0; /* pos. to reach with the ruler */

unsigned int volume = MAX_VOL ; /* CD volume */

char led_colour[60];

unsigned int loop_mode = 0;  /* loop from loop_1 to loop_2 */
unsigned int loop_track = 0; /* track to loop */
unsigned int loop_1 = 0;     /* pos. 1 */
unsigned int loop_2 = 0;     /* pos. 2 */

unsigned int intro_mode = 0; /* play only the beginning of the tracks */
/*}}}*/

/*****************************************************************************/

int main(int argc, char *argv[]) /*{{{*/
{
    cd_device = malloc(strlen(DEFAULTDEVICE) + 1);
    strcpy(cd_device, DEFAULTDEVICE);

    strcpy(led_colour, ". c ");
    ParseCmdLine(argc, argv);
    if (strlen(led_colour) == 4) strcat(led_colour, DEFAULT_COLOUR);
    
    cd_status(); 

    /* Olly patch */

    switch (cur_cdmode) {
	case PLAYING: 
	   playing = TRUE; 
	   break;
	case PAUSED: 
	   paused = TRUE; 
	   break;
	default:
	   break;
    }

    maxtracks=thiscd.ntracks+1;
    CreateWindow(argc, argv);
    MainLoop();
    return 0;
} /*}}}*/

/*****************************************************************************/

void cdcontrol(int order) /*{{{*/
{
    static int pos_changed = FALSE;
    
    if (cd_status() != 1) return;
    lasttime = -1;

    if (cur_cdmode != EJECTED) {
	   if (cd->trk[currenttrack].data) datatrack = 1;
	   else datatrack = 0;
    }
    
    switch(order)
	 {
	  case PLAY: 
		loop_mode = 0;
		intro_mode = 0;
		cd_status();
		maxtracks = thiscd.ntracks+1;
		/* don't play data tracks : */
		if (! cd->trk[currenttrack].data) {
		    if (currenttrack == 0) currenttrack = 1;
		    if (cur_cdmode != EJECTED) {
			   if (! paused) { 
				  play_cd (currenttrack, 0, maxtracks);
			   }
			   playing = TRUE;
			   paused = FALSE;
		    }
		}
		break;
		
	  case PAUSE:
		loop_mode = 0;
		intro_mode = 0;
		pause_cd();
		if (cur_cdmode == PAUSED) {
		    paused = TRUE;
		    playing = FALSE;
		} else if (cur_cdmode == PLAYING) {
		    paused = FALSE;
		    pos_changed = FALSE;
		    playing = TRUE;
		}
		break;
		
	  case STOP:
		loop_mode = 0;
		intro_mode = 0;
		if (playing)
		  {
			 currenttrack = 0;
			 cur_cdmode = 3;
			 stop_cd();
		  }
		else 
		  { 
			 currenttrack = 0;
			 eject_cd();
		  }
		currenttrack=0;
		playing=FALSE;
		paused=FALSE;
		pos_changed = FALSE;
		break;
		
	  case UPTRACK:
		loop_mode = 0;
		intro_mode = 0;
		if (paused) pos_changed = TRUE;
		currenttrack++;
		if(currenttrack >= maxtracks) currenttrack = 1;
		if(playing) play_cd(currenttrack, 0, maxtracks);
		/* If Playing, Stop, Uptrack, Play */
		/* If Paused  */
		break;

	  case DNTRACK:
		loop_mode = 0;
		intro_mode = 0;
		
		/* added from ascd 0.6 : */
		if(paused)
		  {
			 if(cur_pos_rel < 2 || pos_changed)
			   currenttrack--;
			 cur_pos_rel = 0;
			 pos_changed = TRUE;
		  }
		else if(cur_pos_rel < 2)
		  currenttrack--;
		/* end of added code */
		
		/*currenttrack--;*/
		
		if(currenttrack < 1) currenttrack = maxtracks - 1;
		if(playing) play_cd(currenttrack, 0, maxtracks);
		break;

	  case CUE:
		loop_mode = 0;
		intro_mode = 0;
		if (playing) play_cd(currenttrack, cur_pos_rel + cue_time, maxtracks);
		break;
		
	  case REV:
		loop_mode = 0;
		intro_mode = 0;
		if ( (playing) && ( (cur_pos_rel - cue_time) >= 0 ) )
		  play_cd(currenttrack, cur_pos_rel - cue_time, maxtracks);
		break;
		
	  case FIRST:
		loop_mode = 0;
		intro_mode = 0;
		currenttrack = 1;
		if (playing) play_cd(currenttrack, 0, maxtracks);
		break;
		
	  case LAST:
		loop_mode = 0;
		intro_mode = 0;
		currenttrack = maxtracks - 1;
		if (playing) play_cd(currenttrack, 0, maxtracks);
		break;
		
	  case LOOP:
		if ( (loop_2 > loop_1) && (loop_1 != 0) && (loop_2 != 0) && (loop_track > 0) ) {
		    intro_mode = 0;
		    currenttrack = loop_track;
		    playing = TRUE;
		    paused = FALSE;
		    play_cd(loop_track, loop_1, maxtracks);
		    loop_mode = 1;
		}
		break;
		
	  case DIRECTACCESS:
		if (direct_access != 0) {
		    loop_mode = 0;
		    intro_mode = 0;
		    playing = TRUE;
		    paused = FALSE;
		    play_cd(currenttrack, (int)((float)direct_access / 31.0 * (float)cur_tracklen), maxtracks);
		}
		break;
		
	  case INTROSCAN:
		intro_mode = 1;
		currenttrack = 1;
		playing = TRUE;
		paused = FALSE;
		play_cd(currenttrack, 0, maxtracks);
		break;
		
	  case INTRONEXT:
		pause_cd();
		currenttrack++;
		if (currenttrack >= maxtracks) currenttrack = 1;
		play_cd(currenttrack, 0, maxtracks);
		cur_pos_rel = 0;
		break;
		
	  case LOCACCESS:
		if ( (loop_1 > 0) && (loop_track > 0) ) {
		    intro_mode = 0;
		    loop_mode = 0;
		    currenttrack = loop_track;
		    playing = TRUE;
		    paused = FALSE;
		    play_cd(loop_track, loop_1, maxtracks);
		}
		break;
	 }

    RedrawWindow(&currentXPM);
} /*}}}*/

/*****************************************************************************/

void Help() /*{{{*/
{
    fprintf(stderr, "ascd - Version 0.7\n\n");
    fprintf(stderr, "MAINTAINED BY Rob Malda\n");
    fprintf(stderr, "  - email: malda@cs.hope.edu\n");
    fprintf(stderr, "  - WWW:   http://www.cs.hope.edu/~malda/\n\n");
    fprintf(stderr, "    And Denis Bourez:\n");
    fprintf(stderr, "  - email: dbourez@dial.oleane.com\n");
    fprintf(stderr, "  - WWW:   http://worldserver.oleane.com/rsn/\n");
    fprintf(stderr,"\nusage:  ascd [-options ...] \n");
    fprintf(stderr,"options:\n");
    fprintf(stderr,"\n");
    fprintf(stderr,"  Command                 Default     Why\n");
    fprintf(stderr,"a Autoplay                No          Auto play inserted disks (buggy!)\n");
    fprintf(stderr,"c Cue Time                10          Cue Time in seconds\n");
    fprintf(stderr,"d Device                  /dev/cdrom  IDE or SCSI Device of the Drive\n");
    fprintf(stderr,"g Geometry                none        Standard X Location\n");
    fprintf(stderr,"l LED colour              green       Standard X colour to use for LEDs\n");
    fprintf(stderr,"v Low volume              5           Volume Cut when right click on display\n");
    fprintf(stderr,"w Withdrawn               No          Withdrawn more (for WindowMaker)\n");
    fprintf(stderr,"\n\n");
    fprintf(stderr,"Example: ascd -a -w -c 5 -v 20 -d /dev/wcd0a\n\n");
    exit(1);
} /*}}}*/

/*****************************************************************************/

void CreateWindow(int argc, char **argv) /*{{{*/
{
    int i;
    unsigned int borderwidth ;
    char *display_name = NULL;
    char *wname = "ascd";
    XGCValues gcv;
    unsigned long gcm;
    XTextProperty name;
    Pixel back_pix, fore_pix;
    /*Pixmap pixmask;*/
    int screen;
    int x_fd;
    int d_depth;
    int ScreenWidth, ScreenHeight;
    XSizeHints SizeHints;
    XWMHints WmHints;
    XClassHint classHint;

    /* Open display */
    if (!(Disp = XOpenDisplay(display_name)))
	 {
		fprintf(stderr,"ascd: can't open display %s\n", XDisplayName(display_name));
		exit (1);
	 }

    screen = DefaultScreen(Disp);
    Root = RootWindow(Disp, screen);
    d_depth = DefaultDepth(Disp, screen);
    x_fd = XConnectionNumber(Disp);
    ScreenHeight = DisplayHeight(Disp,screen);
    ScreenWidth = DisplayWidth(Disp,screen);

    GetXPM(led_colour);

    SizeHints.flags= USSize|USPosition;
    SizeHints.x = 0;
    SizeHints.y = 0;
    back_pix = GetColor("white");
    fore_pix = GetColor("black");

    XWMGeometry(Disp, screen, Geometry, NULL, (borderwidth =1), &SizeHints,
			 &SizeHints.x,&SizeHints.y,&SizeHints.width,
			 &SizeHints.height, &i);

    SizeHints.width = cdplayerXPM.attributes.width;
    SizeHints.height= cdplayerXPM.attributes.height;
    
    Win = XCreateSimpleWindow(Disp,Root,SizeHints.x,SizeHints.y,
						SizeHints.width,SizeHints.height,
						borderwidth,fore_pix,back_pix);
    
    Iconwin = XCreateSimpleWindow(Disp,Win,SizeHints.x,SizeHints.y,
						    SizeHints.width,SizeHints.height,
						    borderwidth,fore_pix,back_pix);
    XSetWMNormalHints(Disp, Win, &SizeHints);
    
    classHint.res_name = "ascd" ;
    classHint.res_class = "AScd"; 
    
    XSetClassHint (Disp, Win, &classHint);
    
    XSelectInput(Disp, Win, (ExposureMask | ButtonPressMask |
					    StructureNotifyMask));
    XSelectInput(Disp, Iconwin, (ExposureMask | ButtonPressMask |
						   StructureNotifyMask));

    if (XStringListToTextProperty(&wname, 1, &name) ==0)
	 {
		fprintf(stderr, "ascd: can't allocate window name\n");
		exit(-1);
	 }
    XSetWMName(Disp, Win, &name);

    /* Create WinGC */
    gcm = GCForeground|GCBackground|GCGraphicsExposures;
    gcv.foreground = fore_pix;
    gcv.background = back_pix;
    gcv.graphics_exposures = False;
    WinGC = XCreateGC(Disp, Root, gcm, &gcv);


   /* 
	XShapeCombineMask(Disp, Win, ShapeBounding, 0, 0,
				   cdplayerXPM.mask, ShapeSet);
	XShapeCombineMask(Disp, Iconwin, ShapeBounding, 0, 0,
				   cdplayerXPM.mask, ShapeSet);
    */	

    WmHints.initial_state = withdrawn ? WithdrawnState : NormalState ;
    WmHints.icon_window = Iconwin;
    WmHints.window_group = Win;
    WmHints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
    WmHints.icon_x = SizeHints.x;
    WmHints.icon_y = SizeHints.y;
    XSetWMHints(Disp, Win, &WmHints);
    XSetCommand(Disp, Win, argv, argc);
    XMapWindow(Disp,Win);
    RedrawWindow(&currentXPM);
} /*}}}*/

/*****************************************************************************/

void ParseCmdLine(int argc, char *argv[]) /*{{{*/
{

    char *Argument;
    int i;

    for(i = 1; i < argc; i++)
	 {
		Argument = argv[i];

		if (Argument[0] == '-')
		  {
			 switch(Argument[1])
			   {
			    case 'w' : /* withdrawn, for Window Maker */
				  withdrawn = TRUE;
				  continue;
			    case 'g': /* Geometry */
				  if(++i >= argc) Help();
				  Geometry = argv[i];
				  continue;
			    case 'd': /* Device */
				  if(++i >= argc) Help();
				  cd_device = malloc(strlen(argv[i]) + 1);
				  strcpy(cd_device, argv[i]);
				  continue;
			    case 'l': /* Colour */
				  if(++i >= argc) Help();
				  strcat(led_colour, argv[i]);
				  continue;
			    case 'c': /* Cue Time */
				  if(++i >= argc) Help();
				  cue_time = atoi(argv[i]);
				  continue;
			    case 'v': /* Volume stepping */
				  if(++i >= argc) Help();
				  vol_step = atoi(argv[i]);
				  continue;
			    case 'a': /* AutoPlay */
				  autoplay = TRUE;
				  continue;
			    case 'h':  /* Help */
				  if(++i >= argc) Help();
				  continue;
			    default:
				  Help();
			   }
		  }
		else
		  Help();
	 }

} /*}}}*/

/*****************************************************************************/

void MainLoop() /*{{{*/
{
    unsigned int no_disk = 0;
    
    XEvent Event;

    /* Main loop */
    while(1)
	 {
		if (cur_cdmode == EJECTED) no_disk = 1;

		if (no_disk == 1) {
		    if (autoplay) cd_status();
		    if (cur_cdmode != EJECTED) no_disk = 0;
		    if ( (cur_cdmode == STOPPED) && (autoplay) )  cdcontrol(PLAY);
		}
		
		/* The Loop Mode : */
		if ( (cur_pos_rel >= loop_2) && (loop_mode) ) cdcontrol(LOOP);
		
		/* The Intro Scan Mode : */
		if ( (cur_pos_rel > cue_time) && (intro_mode) ) cdcontrol(INTRONEXT);

		/* Check events */
		
		while (XPending(Disp))
		  {
			 XNextEvent(Disp,&Event);
			 switch(Event.type)
			   {
			    case Expose:		/* Redraw window */
				  if(Event.xexpose.count == 0) { 
					 lasttime=01; 
					 RedrawWindow(&currentXPM); 
				  }
				  break;
			    case ButtonPress:	/* Mouseclick */
				  
				  cd_status();

				  /* the progress bar */
				  
				  if ( (Event.xbutton.y >= 17) && (Event.xbutton.x > 39) ) {
					 switch(Event.xbutton.button) {
					  case 3:
						cdcontrol(LOCACCESS);
						break;
					  default:
						direct_access = Event.xbutton.y - 17;
						cdcontrol(DIRECTACCESS);
						break;
					 }
				  }
				  
				  /* the display */
				  
				  else if( Event.xbutton.y < 15) {
					 switch (Event.xbutton.button) {
					  case 2:
						time_mode = 0;
						break;
					  case 3:
						if (volume == MAX_VOL) volume = vol_step;
						else volume = MAX_VOL;
						cd_volume(volume, 20, MAX_VOL);
						break;
					  default:
						time_mode++ ;
						if (time_mode > 3) time_mode = 0;
						break;
					 }
				  }
				  
				  /* play/pause */
				  
				  else if(Event.xbutton.y < 34) {
					 if(Event.xbutton.x < 18) {
						if (playing || paused)
						  cdcontrol(PAUSE);
						else if (Event.xbutton.button == 3)
						  cdcontrol(INTROSCAN);
						else
						  cdcontrol(PLAY);
					 }
					 else if (Event.xbutton.x <=39)
					   cdcontrol(STOP);
				  } else {
					 if (Event.xbutton.x < 15) {
						if (Event.xbutton.y < 41) {
						    
						    /* down */
						    
						    if (Event.xbutton.button == 1) {
							   cdcontrol(DNTRACK);
						    } else if (Event.xbutton.button == 3) {
							   cdcontrol(REV);
						    } else if (Event.xbutton.button == 2) {
							   cdcontrol(FIRST);
						    }
						} else {
						    
						    /* up */
						    
						    if (Event.xbutton.button == 1) {
							   cdcontrol(UPTRACK);
						    } else if (Event.xbutton.button == 3) {
							   cdcontrol(CUE);
						    } else if (Event.xbutton.button == 2) {
							   cdcontrol(LAST);
						    }
						}
					 } else if ( (playing) || (paused) ) {
						if (Event.xbutton.button == 1) {
						    loop_1 = cur_pos_rel;
						    loop_track = currenttrack;
						}
						if (Event.xbutton.button == 3) loop_2 = cur_pos_rel;
						if (Event.xbutton.button == 2) {
						    if (loop_mode) loop_mode = 0;
						    else cdcontrol(LOOP);
						}
					 }
				  }
				  break;
			    case DestroyNotify:	/* Destroy window */
				  XFreeGC(Disp, WinGC);
				  XDestroyWindow(Disp, Win);
				  XDestroyWindow(Disp, Iconwin);
				  XCloseDisplay(Disp);
				  exit(0);
				  break;
			   }

			 XFlush(Disp);
			 RedrawWindow(&currentXPM);
		  }
		usleep(50000L);
		RedrawWindow(&currentXPM);
	 }
} /*}}}*/

/*****************************************************************************/

void GetXPM(char *colour) /*{{{*/
{
    XWindowAttributes Attributes;
    int Ret;
    char col_string[40];
    
    char *led[14] = {
	   "122 11 2 1",
	   "   c Black",
	   NULL,
	   "    ....        .     ....     ....    .    .     ....     ....    ....     ....     ....                                 ",
	   "   .    .       .         .        .   .    .    .        .            .   .    .   .    .                                ",
	   "   .    .       .         .        .   .    .    .        .            .   .    .   .    .                                ",
	   "  .    .       .         .        .   .    .    .        .            .   .    .   .    .   .                             ",
	   "  .    .       .         .        .   .    .    .        .            .   .    .   .    .   .                             ",
	   "                     ...      ...      ...       ...      ...              ...      ...          ........   ..            ",
	   " .    .       .    .             .        .         .   .    .       .   .    .        .                   .  .           ",
	   " .    .       .    .             .        .         .   .    .       .   .    .        .  .                .  .           ",
	   ".    .       .    .             .        .         .   .    .       .   .    .        .   .                 ..            ",
	   ".    .       .    .             .        .         .   .    .       .   .    .        .                                   ",
	   " ....        .     ....     ....         .     ....     ....        .    ....     ....                                    "
    };

    led[2] = colour;

    XGetWindowAttributes(Disp,Root,&Attributes);

    cdplayerXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    
    Ret = XpmCreatePixmapFromData(Disp, Root, cdplayer, &cdplayerXPM.pixmap,
						    &cdplayerXPM.mask, &cdplayerXPM.attributes);

    ledXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    
    Ret = XpmCreatePixmapFromData(Disp, Root, led, &ledXPM.pixmap,
						    &ledXPM.mask, &ledXPM.attributes);

    cdpausedXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    
    Ret = XpmCreatePixmapFromData(Disp, Root, cdpaused, &cdpausedXPM.pixmap,
						    &cdpausedXPM.mask, &cdpausedXPM.attributes);
    
    barXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    
    Ret = XpmCreatePixmapFromData(Disp, Root, bar, &barXPM.pixmap,
						    &barXPM.mask, &barXPM.attributes);

    currentXPM=cdplayerXPM;
    if(Ret != XpmSuccess)
	 {
		fprintf(stderr, "ascd: not enough free color cells\n");
		exit(1);
	 }
} /*}}}*/

/*****************************************************************************/

int FlushExpose(Window w) /*{{{*/
{
    XEvent dummy;
    int i=0;

    while (XCheckTypedWindowEvent (Disp, w, Expose, &dummy))i++;
    return i;
} /*}}}*/

/*****************************************************************************/

void RedrawWindow(XpmIcon *Icon) /*{{{*/
{
    int track[2];
    int cdtime[4];
    int disp_time;
    int time_offset = 0;
    static time_t last_flash_time;
    static flash=0;

    
    if (playing || paused) {
	   cd_status();
    }

    if(playing) currenttrack=cur_track;

    if((cur_track==maxtracks-1) &&
	  (playing) && (!paused) && (cur_cdmode != PLAYING))
	 cdcontrol(STOP);
    else
	 if(!paused && lasttime==cur_pos_rel) return;

    if(paused)
	 {
		time_t flash_time = time(NULL);
		if (flash_time == last_flash_time) return;
		last_flash_time = flash_time;
		flash = !flash;
	 } else {
		/* reset these if not paused, so next pause goes smoothly */
		last_flash_time = 0;
		flash = 1;
	 }

    track[1]= (currenttrack % 10);
    track[0]= (currenttrack / 10);

    lasttime=cur_pos_rel;
    
    if (time_mode == 0) disp_time = cur_pos_rel;
    else if (time_mode == 1) disp_time = cur_tracklen - cur_pos_rel ;
    else if (time_mode == 2) disp_time = cur_pos_abs;
    else disp_time = cur_cdlen - cur_pos_abs;
    
    if (playing || paused)
	 {
		cdtime[0] = 0;
		cdtime[1] = (disp_time / 60);
		if (cdtime[1] >= 10) {
		    cdtime[0] = cdtime[1] / 10;
		    cdtime[1] = cdtime[1] % 10;
		}
		cdtime[2] = ((disp_time % 60) / 10);
		cdtime[3] = (disp_time % 10);
	 } else {
		cdtime[0] = 0;
		cdtime[1] = 0;
		cdtime[2] = 0;
		cdtime[3] = 0;
	 }

    if (playing) currentXPM=cdpausedXPM;
    else currentXPM=cdplayerXPM;
    
    FlushExpose(Win);
    FlushExpose(Iconwin);

    XShapeCombineMask(Disp, Win, ShapeBounding, 0, 0,
				  currentXPM.mask, ShapeSet);
    XShapeCombineMask(Disp, Iconwin, ShapeBounding, 0, 0,
				  currentXPM.mask, ShapeSet);

    XCopyArea(Disp,currentXPM.pixmap,Win,WinGC,
		    0,0,currentXPM.attributes.width, currentXPM.attributes.height,0,0);
    
    XCopyArea(Disp,currentXPM.pixmap,Iconwin,WinGC,
		    0,0,currentXPM.attributes.width, currentXPM.attributes.height,0,0);

    /* track nbr */
    
    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		    9*track[0],0, 9,11, 15,36);
    
    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		    9*track[0],0, 9,11, 15,36);
    
    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		    9*track[1],0, 9,11, 24,36);
    
    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		    9*track[1],0, 9,11, 24,36);
    
    /* time leds */
    
    if (!paused || flash) 
	 {
		if (! datatrack) {
		    
		    if ((time_mode == 1) || (time_mode == 3) || (time_mode == 2) ) {
			   
			   /* The '-' for the remaining times */
			   
			   if (time_mode != 2) {
				  XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
						  98, 5, 4, 2, 1, 7);
				  
				  XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
						  98, 5, 4, 2, 1, 7);
			   }
			   
			   /* The 'o' for global CD times */
			   
			   if ((time_mode == 2) || (time_mode == 3)) {
				  XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
						  107, 5, 4, 4, 1, 2);
				  
				  XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
						  107, 5, 4, 4, 1, 2);
			   }
			   
			   /* if we show a remaining time, we should move the
			    * counter to the right
			    */
			   time_offset = 4;
		    } else {
			   time_offset = 2;
		    }
		    
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    9*cdtime[0],0, 9,11, 2 + time_offset, 2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    9*cdtime[0],0, 9,11, 2 + time_offset, 2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    9*cdtime[1],0, 9,11, 11 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    9*cdtime[1],0, 9,11, 11 + time_offset,2);
		} else {
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    98,0, 9,11, 2 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    98,0, 9,11, 2 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    98,0, 9,11, 11 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    98,0, 9,11, 11 + time_offset,2);
		}
		
		XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				9*10,0, 6,11, 20 + time_offset,2);

		XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				9*10,0, 4,11, 20 + time_offset,2);
		
		if (! datatrack) {
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    9*cdtime[2],0, 9,11, 24 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    9*cdtime[2],0, 9,11, 24 + time_offset,2);
		
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    9*cdtime[3],0, 9,11, 33 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    9*cdtime[3],0, 9,11, 33 + time_offset,2);
		} else {
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    98,0, 9,11, 24 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    98,0, 9,11, 24 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				    98,0, 9,11, 33 + time_offset,2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				    98,0, 9,11, 33 + time_offset,2);
		}


	 }
 
    if ( (cur_cdmode != STOPPED) && (cur_cdmode != EJECTED) ) {
	   XCopyArea(Disp, barXPM.pixmap, Win, WinGC,
			   0,0, 8,2 + (int)((float)cur_pos_rel / (float)cur_tracklen * 31.0), 38, 16 );
	   XCopyArea(Disp, barXPM.pixmap, Iconwin, WinGC,
			   0,0, 8,2 + (int)((float)cur_pos_rel / (float)cur_tracklen * 31.0), 38, 16 );
    }

} /*}}}*/

/*****************************************************************************/

Pixel GetColor(char *ColorName) /*{{{*/
{
    XColor Color;
    XWindowAttributes Attributes;

    XGetWindowAttributes(Disp,Root,&Attributes);
    Color.pixel = 0;

    if (!XParseColor (Disp, Attributes.colormap, ColorName, &Color))
	 fprintf(stderr,"ascd: can't parse %s\n", ColorName);
    else if(!XAllocColor (Disp, Attributes.colormap, &Color))
	 fprintf(stderr,"ascd: can't allocate %s\n", ColorName);

    return Color.pixel;
} /*}}}*/

