/*****************************************************************************/
/* ascd - AfterStep and WindowMaker CD Player + Mixer                        */
/* By Rob Malda                                                              */
/* malda@slashdot.org                                                        */
/*                                                                           */
/* This is an 'AfterStep Look & Feel' Wharf style applet that can be         */
/* used to control an IDE CD Changer.                                        */
/*****************************************************************************/
/*          developped by Denis Bourez (denis@rsn.fdn.fr) since 0.7          */
/*****************************************************************************/

#include <stdio.h>
#include <sys/param.h>
#include <sys/types.h>

#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <X11/Xlib.h>

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

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

#include "ascd.h"
#include "../lib/struct.h"

#ifdef MIXER
# if defined (__FreeBSD__)
#  include <machine/soundcard.h>
# else
#  include <sys/mount.h>
#  include <linux/soundcard.h>
# endif
#endif

/* XPM stuff                                                      */

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

XpmIcon cdplayerXPM;  /* XPM screen when CD is stopped    */
XpmIcon cdpausedXPM;  /* XPM screen while playing CD      */
XpmIcon currentXPM;   /* current XPM : one of the 2 above */
XpmIcon ledXPM;       /* the LED digits                   */
XpmIcon barXPM;       /* Progression bar                  */
XpmIcon alphaXPM;     /* ABCDEF............               */

#ifdef MIXER
XpmIcon cdmixerXPM;   /* the Mixer page                   */
XpmIcon cursorXPM;    /* Only background -> mixer mask    */
#endif

/* Functions                                                      */

void	Help(void);
void	CreateWindow(int, char **);
void	ParseCmdLine(int argc, char *argv[]);
void	MainLoop();
void	GetXPM(char *, char *);
int 	FlushExpose(Window w);
void	newtext (char *);
void	text (char *);
void	RedrawWindow(XpmIcon *v);
void	redraw_infos();
Pixel 	GetColor(char *name);
void	cdcontrol(int control);
void	infos_cd();

#ifdef MIXER
void	setvol(int control, int setto, unsigned int);
void	getvol();
#endif

/* Global stuff - ascd                                            */

#define RDTIME 20000L

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;

/* Global stuff - WorkMan                                         */

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;

int big_spaces = 0;

/* Global stuff - ascd+                                           */

#define MAX_VOL 256

char global_mode = 'c';          /* 'c' for CD Player, 'm' for Mixer */

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 autoplay = 0;       /* if set, play a disk when it is inserted -> see -a c.l. option  */
unsigned int autorepeat = FALSE; /* zzzzzzzzzzzzz */
unsigned int datatrack = 0;      /* is the current track a data track ? */
unsigned int direct_access = 0;  /* pos. to reach with the ruler */
unsigned int direct_track = 0;

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

char led_colour[60];             /* foreground colour for LEDs */
char led_bgcolour[60];           /* back " " " " " " " " " " " */

char led_text[8];
long text_timeout = 1;
long text_start = 0;

unsigned int loop_mode = 0;      /* loop from loop_1 to loop_2 */
unsigned int loop_start_track = 0, /* tracks to loop */
             loop_end_track =0;
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 redraw=TRUE;

/* from/for WorkMan database code: */

int mark_a = 0;
int mark_b = 0;
int cur_stopmode = 0;
int cur_playnew = 0;

/* Mixer global vars */

#ifdef MIXER
int volbutloc[3];
int voldev[3];
int volold[3];
int vol[3];

int changedmask=TRUE;
int mouseDown=FALSE;

char mixer_device[128]=DEFAULTMIXERDEVICE;
#endif

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

int main(int argc, char *argv[]) 
{
    extern char *rcfile, *dbfiles;  
    
    /* CD device: */

#ifndef NO_D_DEVICE
    cd_device = malloc(strlen(DEFAULTDEVICE) + 1);
    strcpy(cd_device, DEFAULTDEVICE);
#endif

    strcpy(led_text, "");
    
    /* prepares the LED colors variables: */
    
    strcpy(led_colour, "X c ");
    strcpy(led_bgcolour, "  c ");

#ifdef MIXER
    voldev[0]=SOUND_MIXER_VOLUME;
    voldev[1]=SOUND_MIXER_CD;
    voldev[2]=SOUND_MIXER_PCM;
#endif

    /* the WorkMan database. It's still not used in ascd, but we need this
       to start the WorkMan code
    */

    rcfile = getenv("WORKMANRC");
    if (rcfile)
      rcfile = WMstrdup(rcfile);
    dbfiles = getenv("WORKMANDB");
    if (dbfiles)
      dbfiles = WMstrdup(dbfiles);
    
    split_workmandb();
    
    /* load the command line options */
    
    ParseCmdLine(argc, argv);

    /* if none specified, default colours for LEDs */

    if (strlen(led_colour) == 4) strcat(led_colour, DEFAULT_COLOUR);
    if (strlen(led_bgcolour) == 4) strcat(led_bgcolour, DEFAULT_BGCOLOUR);

    cd_status();

    /* Olly patch */

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

    maxtracks=thiscd.ntracks+1;

#ifdef MIXER
    getvol();
#endif
    
    CreateWindow(argc, argv);

    newtext("ASCD");

    MainLoop();
    return 0;
} 

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

void cdcontrol(int order) 
{
    static int pos_changed = FALSE;

    if (cd_status() != 1) {
	if ((!playing) && (order == STOP)) {
	    eject_cd();
	}
	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;*/
	  maxtracks = cur_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;

	  if(paused)
	    {
		if(cur_pos_rel < 2 || pos_changed)
		  currenttrack--;
		cur_pos_rel = 0;
		pos_changed = TRUE;
	    }
	  else if(cur_pos_rel < 2)
	    currenttrack--;
	  
	  if(currenttrack < 1) currenttrack = maxtracks - 1;
	  if(playing) play_cd(currenttrack, 0, maxtracks);
	  break;

       case DIRECTTRACK:
	  loop_mode = 0;
	  intro_mode = 0;
	  if (paused) pos_changed = TRUE;
	  currenttrack = direct_track;
	  if(currenttrack >= maxtracks) currenttrack = 1;
	  if(playing) play_cd(currenttrack, 0, maxtracks);
	  /* If Playing, Stop, Uptrack, Play */
	  /* If Paused  */
	  newtext("GOTO");
	  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);
	  newtext("FIRST");
	  break;

       case LAST:
	  loop_mode = 0;
	  intro_mode = 0;
	  currenttrack = maxtracks - 1;
	  if (playing) play_cd(currenttrack, 0, maxtracks);
	  newtext("LAST");
	  break;

       case LOOP:
	  if ((loop_2 != 0) && (loop_2 > loop_1)) {
	      if (loop_start_track == 0) loop_start_track = 1;
	      intro_mode = 0;
	      playing = TRUE;
	      paused = FALSE;
	      if ( ( loop_2 > loop_1 ) 
		  || ( loop_start_track != loop_end_track ) )
		currenttrack = loop_start_track;
	      else {
		  loop_end_track = thiscd.ntracks;
		  currenttrack = loop_start_track = 1;
		  loop_1 = 0;
		  loop_2 = 
		    thiscd.trk[ loop_end_track - 1 ].length - 1;
	      }
	      play_cd(loop_start_track, loop_1, maxtracks);
	      loop_mode = 1;
	      strcpy(led_text, "LOOP");
	  } else {
	      newtext("ERROR");
	  }
	  break;

       case DIRECTACCESS:
	  if (direct_access != 0) {
	      loop_mode = 0;
	      intro_mode = 0;
	      playing = TRUE;
	      paused = FALSE;
	      if ((time_mode == 2) || (time_mode == 3)) {
		  play_cd(1, (int)((float)direct_access / 31.0 * (float)cur_cdlen), maxtracks);
	      } else {
		  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);
	  newtext("INTRO");
	  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_start_track > 0) ) {
 	      intro_mode = 0;
	      loop_mode = 0;
	      currenttrack = loop_start_track;
	      playing = TRUE;
	      paused = FALSE;
	      stop_cd();
	      play_cd(loop_start_track, loop_1, maxtracks);
 	  }
	  break;
      }

    RedrawWindow(&currentXPM);
} 

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

void Help() 
{
    fprintf(stderr, "ascd - Version %s\n\n", VERSION);

    fprintf(stderr, "Maintained by Rob Malda      Email: malda@slashdot.org\n");
    fprintf(stderr, "                             WWW:   http://slashdot.org/malda/\n");
    fprintf(stderr, "           &  Denis Bourez   Email: denis@rsn.fdn.fr\n");
    fprintf(stderr, "                             WWW:   http://worldserver.oleane.com/rsn/\n\n");

    fprintf(stderr,"Usage:  ascd [-options ...] \n");
    fprintf(stderr,"Options:\n");
    fprintf(stderr,"\n");
    fprintf(stderr,"Command/Parameter:   Default:    Why:\n");
    fprintf(stderr,"-------------------------------- GENERAL -----------------------------------\n");
    fprintf(stderr,"g Geometry           none        Standard X Location\n");
    fprintf(stderr,"w                    No          Withdrawn State (WindowMaker) \n");
    fprintf(stderr,"b LED bg color       black       Standard X color to use for LEDs background\n");
    fprintf(stderr,"f LED fg color       green       Standard X color to use for LEDs\n");
    fprintf(stderr,"i Text Disp. Time    1           Texts displaying timeout (in seconds)\n");
    fprintf(stderr,"-------------------------------- CDPLAYER ----------------------------------\n");
    fprintf(stderr,"a                    No          Auto play inserted disks (buggy!)\n");
    fprintf(stderr,"t                    No          Auto repeat\n");
    fprintf(stderr,"c Cue Time           10          Cue Time in seconds\n");
#ifdef NO_D_DEVICE
    fprintf(stderr,"d Device             No          CDROM drive device, autoprobe mode\n");
#else
    fprintf(stderr,"d Device             /dev/cdrom  CDROM drive device\n");
#endif	
#ifdef MIXER
    fprintf(stderr,"-------------------------------- MIXER -------------------------------------\n");
    fprintf(stderr,"1 Control 1          VOLUME      Assignation of the mixer control 1\n");
    fprintf(stderr,"2 Control 2          CD          Assignation of the mixer control 2\n");
    fprintf(stderr,"3 Control 3          PCM         Assignation of the mixer control 3\n");
    fprintf(stderr,"v rate (0-100)       none        Set default value for mixer control 1\n");

    fprintf(stderr,"\n(for -1, -2, -3 parameter must be one of VOLUME, BASS, TREBLE, SYNTH, PCM,\n");
    fprintf(stderr,"SPEAKER, LINE, MIC, CD, IMIX, ALTPCM, RECLEV, IGAIN, OGAIN, LINE1, LINE2,\n");
    fprintf(stderr,"or LINE3.)\n");

    fprintf(stderr,"\nSample: ascd -a -w -c 5 -f yellow -d /dev/wcd0a -2 SYNTH -v 100\n\n");
#else
    fprintf(stderr,"\nSample: ascd -a -w -c 5 -f yellow -d /dev/wcd0a\n\n");
#endif
    exit(1);
} 

#define MAX_LINE_NAME 16

void ParseCmdLine(int argc, char *argv[]) {
#ifdef MIXER
    struct {
	char name[MAX_LINE_NAME];
	int dev;
    } mixernames[SOUND_MIXER_NRDEVICES] = { 
	  { "VOLUME", SOUND_MIXER_VOLUME },
	  { "BASS", SOUND_MIXER_BASS },
	  { "TREBLE", SOUND_MIXER_TREBLE },
	  { "SYNTH", SOUND_MIXER_SYNTH },
	  { "PCM", SOUND_MIXER_PCM },
	  { "SPEAKER", SOUND_MIXER_SPEAKER },
	  { "LINE", SOUND_MIXER_LINE },
	  { "MIC", SOUND_MIXER_MIC },
	  { "CD", SOUND_MIXER_CD },
	  { "IMIX", SOUND_MIXER_IMIX },
	  { "ALTPCM", SOUND_MIXER_ALTPCM },
	  { "RECLEV", SOUND_MIXER_RECLEV },
	  { "IGAIN", SOUND_MIXER_IGAIN },
	  { "OGAIN", SOUND_MIXER_OGAIN },
	  { "LINE1", SOUND_MIXER_LINE1 },
	  { "LINE2", SOUND_MIXER_LINE2 },
	  { "LINE3", SOUND_MIXER_LINE3 }
    };
    
    int j, CmdVol;
    char WhichLine[MAX_LINE_NAME];
#endif
    int i;
    char *Argument;

    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 'f': /* LEDs foreground color */
		      if(++i >= argc) Help();
		      strcat(led_colour, argv[i]);
		      continue;
		   case 'b': /* LEDs background color */
		      if(++i >= argc) Help();
		      strcat(led_bgcolour, argv[i]);
		      continue;
		   case 'c': /* Cue Time */
		      if(++i >= argc) Help();
		      cue_time = atoi(argv[i]);
		      continue;
		   case 'i': /* Text Timeout */
		      if(++i >= argc) Help();
		      text_timeout = atoi(argv[i]);
		      continue;
		   case 'a': /* AutoPlay */
		      autoplay = TRUE;
		      continue;
		   case 't' : /* AutoRepeat */
		      autorepeat = TRUE;
		      continue;
		   case 'h':  /* Help */
		      if(++i >= argc) Help();
		      continue;
#ifdef MIXER
		   case '1': /* Mixer args */
		   case '2':
		   case '3':
		      if(++i >= argc) Help();
		      strncpy(WhichLine, argv[i], MAX_LINE_NAME-1);
		      for(j = 0; j < SOUND_MIXER_NRDEVICES; j++)
			{
			    if(strcasecmp(mixernames[j].name, WhichLine) == 0)
			      {
				  voldev[Argument[1]-'1'] = mixernames[j].dev;
				  break;
			      }
			}
		      continue;
		   case 'v': /* Default volume By Alen Salamun*/
		      if(++i >= argc) Help();
		      CmdVol = 0;
		      strncpy(WhichLine, argv[i], MAX_LINE_NAME-1);
		      for(j = 1; j <= strlen(WhichLine); j++)
			CmdVol = CmdVol + (WhichLine[j - 1] - 48) * pow(10, strlen(WhichLine) - j);
		      if (CmdVol > 100) CmdVol = 100;
		      if (CmdVol < 0) CmdVol = 0;
		      CmdVol = 35 - CmdVol * 35 / 100;
		      setvol(0, CmdVol, 0);
		      continue;
#endif
		   default:
		      Help();
		  }
	    }
	  else
	    Help();
      }

} 

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

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, led_bgcolour);

    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 = cdpausedXPM.attributes.width;
    SizeHints.height= cdpausedXPM.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);

    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 cdplayer_mouse_events(XEvent Event) 
{
    int i = 0;
    char txt[24];
    char dummy[256];

    if ((Event.xbutton.y <= 2) || (Event.xbutton.y >= 48) ||
	(Event.xbutton.x <= 2) || (Event.xbutton.x >= 48)) {
	
	/* outside... Do nothing!!! */
	
    } else if( Event.xbutton.y < 14) {
	
	/* the display */
	
	switch (Event.xbutton.button) {
#ifdef MIXER
	case 3: /* Right clic: change to mixer mode */
	    global_mode = 'm';
	    newtext("MIXER");
	    redraw = TRUE;
	    break;
#endif
	default: /* Left or Middle: toggle display mode */
	    time_mode++ ;
	    if (time_mode > 3) time_mode = 0;
	    break;
	}
    }
    
    else if ( (Event.xbutton.y >= 14) && (Event.xbutton.x > 40) ) {
	
	/* We're in the progress bar. Direct Access! */
	
	switch(Event.xbutton.button) {
	case 3:
	    cdcontrol(LOCACCESS);
	    break;
	default:
	    direct_access = Event.xbutton.y - 17;
	    cdcontrol(DIRECTACCESS);
	    break;
	}
    }
    
    /* play/pause and stop/eject */
    
    else if ((Event.xbutton.y > 16) && (Event.xbutton.y < 33)) {
	if(Event.xbutton.x < 19) {
	    
	    /* Play/Pause */
	    
	    if (playing || paused)
		cdcontrol(PAUSE);
	    else if (Event.xbutton.button == 3)
		cdcontrol(INTROSCAN);
	    else
		cdcontrol(PLAY);
	    
	} else if (Event.xbutton.x <= 39) {
	    
	    /* the STOP button */
	    
	    switch(Event.xbutton.button) {
	    case 3:
		exit(0);
		break;
	    default:
		cdcontrol(STOP);
		break;
	    }
	}
	
	
    } else {
	if (Event.xbutton.x < 18) {
	    if (Event.xbutton.y > 33) {
		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) ) {
	    
	    /* the track nbr display */
	    
	    switch(Event.xbutton.button) {
	    case 2:
		if (loop_mode) loop_mode = 0;
		else cdcontrol(LOOP);
		break;
	    case 3:
		loop_2 = cur_pos_rel;
		loop_end_track = currenttrack;
		newtext("L END");
		break;
	    default:
		loop_1 = cur_pos_rel;
		newtext("L STA");
		loop_start_track = currenttrack;
		break;
	    }
	}
    }
} 




#ifdef MIXER
void mixer_mouse_events(XEvent Event) /*{{{*/
{
    int i = 0;
    char txt[24];
    
    /*printf("x=%d y=%d\n", Event.xbutton.x, Event.xbutton.y);*/
	
    if ((Event.xbutton.y <= 2) || (Event.xbutton.y >= 48) ||
	(Event.xbutton.x <= 2) || (Event.xbutton.x >= 48)) {
	
	/* again, do nothing... */
    }
    
    
    else if( Event.xbutton.y < 14) {
	
	/* the display */
	
	switch (Event.xbutton.button) {
	case 3: /* change to CD player mode */
	    global_mode = 'c';
	    newtext("CD");
	    redraw = TRUE;
	    break;
	default:
	    time_mode++ ;
	    if (time_mode > 3) time_mode = 0;
	    break;
	}
    }
    
    else if ( (Event.xbutton.y >= 14) && (Event.xbutton.x > 40) ) {
	
	/* the progress bar */
	
	switch(Event.xbutton.button) {
	case 3:
	    cdcontrol(LOCACCESS);
	    break;
	default:
	    direct_access = Event.xbutton.y - 17;
	    cdcontrol(DIRECTACCESS);
	    break;
	}
    }
    
    else {
	setvol(Event.xbutton.x / 14, Event.xbutton.y - 18, 0);
    }
}
#endif





void MainLoop() 
{
    unsigned int no_disk = 0;
    int i = 0;
    char txt[24];
    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 ( (currenttrack == loop_end_track )
	      && (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);

		/* ============================ CD PLAYER =========================== */
		
		if (global_mode == 'c') {
		
		    switch(Event.type) {

			/* ---------------------- Redraw Window --------------------- */
			
		    case Expose:
			if(Event.xexpose.count == 0) {
			    lasttime=01;
			    RedrawWindow(&currentXPM);
			}
			break;
			
			/* ----------------------- Mouse Click ---------------------- */
			
		    case ButtonPress:
			
			cd_status();
			cdplayer_mouse_events(Event);
			break;
			
			/* ------------------------ Destroy Window ------------------- */
			
		    case DestroyNotify:
			XFreeGC(Disp, WinGC);
			XDestroyWindow(Disp, Win);
			XDestroyWindow(Disp, Iconwin);
			XCloseDisplay(Disp);
			exit(0);
			break;
		    }

		/* ============================ THE MIXER =========================== */
		    
		} else if (global_mode == 'm') {
#ifdef MIXER		    
		    /* the Mixer */
		    
		    switch(Event.type)
		      {
		       case Expose:           /* Redraw window */
			  if(Event.xexpose.count == 0) {
			      lasttime=01;
			      RedrawWindow(&currentXPM);
			  }
			  break;

		       case ButtonPress:      /* Mouseclick */
			  
			  cd_status();
			  mixer_mouse_events(Event);
			  break;
			  
		       case DestroyNotify:    /* Destroy window */
			  XFreeGC(Disp, WinGC);
			  XDestroyWindow(Disp, Win);
			  XDestroyWindow(Disp, Iconwin);
			  XCloseDisplay(Disp);
			  exit(0);
			  break;
		      }
#endif

		}
		
		
		XFlush(Disp);
	    } /* check event */
	  
	  usleep(RDTIME);

	  /* ----------------- now we have to redraw the screen: ---------------- */
	  
	  RedrawWindow(&currentXPM);
      }
} 

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

void GetXPM(char *foreground, char *background) 
{
    XWindowAttributes Attributes;
    int Ret;
    char col_string[40];

    /* First, define the XPMs.... */

    char *led[] = {
	"122 11 2 1",
	background,
	foreground,
	" XXXXXX      XXX  XXXXXXX   XXXXXX      XXXX XXXXXXXX  XXXXXX  XXXXXXXX  XXXXXX   XXXXXX                                  ",
	"XXXXXXXX    XXXX  XXXXXXXX  XXXXXXX    XXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX                                 ",
	"XX    XX   XXXXX        XX       XX   XX  XX XX       XX             XX XX    XX XX    XX                                 ",
	"XX    XX  XXX XX        XX       XX  XX   XX XX       XX             XX XX    XX XX    XX XXX                             ",
	"XX    XX XXX  XX   XXXXXXX   XXXXXX XXXXXXXX XXXXXX   XXXXXXX        XX  XXXXXX  XXXXXXXX XXX    XXXXXXXX                 ",
	"XX    XX      XX   XXXXXX    XXXXX  XXXXXXXX XXXXXXX  XXXXXXXX      XX   XXXXXX   XXXXXXX        XXXXXXXX   XX            ",
	"XX    XX      XX  XX             XX       XX       XX XX    XX      XX  XX    XX       XX XXX              XX X           ",
	"XX    XX      XX  XX             XX       XX       XX XX    XX      XX  XX    XX       XX XXX              X XX           ",
	"XX    XX      XX  XX             XX       XX       XX XX    XX     XX   XX    XX       XX                   XX            ",
	"XXXXXXXX      XX  XXXXXXX  XXXXXXXX       XX XXXXXXX  XXXXXXXX     XX   XXXXXXXX  XXXXXXX                                 ",
	" XXXXXX       XX   XXXXXX  XXXXXXX        XX XXXXXX    XXXXXX      XX    XXXXXX  XXXXXXX                                  "
    };

    char *alpha[] = {
	"234 11 2 1",
	background,
	foreground,
	" XXXXXX  XXXXXX    XXXXXX  XXXXX    XXXXXXX  XXXXXXX   XXXXXX  X      X  XXXXX   XXXXXXXX X     X  X        X      X X      X   XXXX   XXXXXX     XXXX   XXXXXXX   XXXXXX    XXXXX  X      X X      X X      X X      X X      X XXXXXXXX ",
	"X      X X     X  X        X    X   X        X        X        X      X    X            X X    X   X        XX    XX X      X  X    X  X     X   X    X  X      X X            X    X      X X      X X      X X      X X      X        X ",
	"X      X X      X X        X     X  X        X        X        X      X    X            X X   X    X        X X  X X XX     X X      X X      X X      X X      X X            X    X      X  X    X  X      X  X    X   X    X        X  ",
	"X      X X      X X        X     X  X        X        X        X      X    X            X X  X     X        X  XX  X X X    X X      X X      X X      X X      X X            X    X      X  X    X  X      X   X  X     X  X        X   ",
	"X      X X     X  X        X      X X        X        X        X      X    X            X X X      X        X      X X  X   X X      X X     X  X      X X      X X            X    X      X   X  X   X      X    XX       XX        X    ",
	"XXXXXXXX XXXXXX   X        X      X XXXXX    XXXXX    X XXXXX  XXXXXXXX    X            X XXX      X        X      X X   X  X X      X XXXXXX   X      X XXXXXXX   XXXXXX      X    X      X   X  X   X      X    XX       XX       XX    ",
	"X      X X     X  X        X      X X        X        X      X X      X    X            X X  X     X        X      X X    X X X      X X        X  X   X X  X            X     X    X      X    XX    X      X    XX       XX       X     ",
	"X      X X      X X        X     X  X        X        X      X X      X    X     X      X X   X    X        X      X X     XX X      X X        X   X  X X   X           X     X    X      X    XX    X  XX  X   X  X      XX      X      ",
	"X      X X      X X        X     X  X        X        X      X X      X    X      X     X X    X   X        X      X X      X X      X X        X    X X X    X          X     X    X      X    XX    X X  X X  X    X     XX     X       ",
	"X      X X     X  X        X    X   X        X        X      X X      X    X       X   X  X     X  X        X      X X      X  X    X  X         X    X  X     X         X     X     X    X     XX    XX    XX X      X    XX    X        ",
	"X      X XXXXXX    XXXXXX  XXXXX    XXXXXXX  X         XXXXXX  X      X  XXXXX      XXX   X      X XXXXXXX  X      X X      X   XXXX   X          XXXX X X      X  XXXXXX      X      XXXX      XX    X      X X      X    XX    XXXXXXXX "
    };

    char *bar[] = {
	"8 36 2 1",
	background,
	foreground,
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX",
	"        ",
	"XXXXXXXX"
    };
    
    char *cursor[] = {
	/* width height num_colors chars_per_pixel */
	"    12    5      11     1",
	/* colors */
	". c #000000",
	"# c #202420",
	"f c None",
	"A c #40403f",
	"B c #a9a9aa",
	"C c #585857",
	"D c #313132",
	"E c #9c9c9b",
	"F c #cececc",
	"G c #0f0f10",
	"H c #7a7a7a",
	/* pixels */
	"f##########f",
	"####AACCHHE#",
	"##AACCHHHEE#",
	"#AACCHHEEEE#",
	"f##########f"
    };

    char *cdpaused[] = {
	/* width height num_colors chars_per_pixel */
	"    48    48       20     1",
	/* colors */
	". c #000000",
	"# c #202420",
	background,
	"b c #404040",
	"c c #484848",
	"d c #606060",
	"e c #606460",
	"f c None",
	"g c #818181",
	"h c #c0c0c0",
	"i c #cccccc",
	"j c #FFFFFF",
	"A c #40403f",
	"B c #a9a9aa",
	"C c #585857",
	"D c #313132",
	"E c #9c9c9b",
	"F c #cececc",
	"G c #0f0f10",
	"H c #7a7a7a",
	/* pixels */
	"ffffffffffffffffffffffffffffffffffffffffffffffff",
	"                                               C",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCH",
	"ffffffffffffffffffffffffffffffffffffffffffffffff",
	"fCHHHHHHHfHHHHHHHCffCHHHHHHHHHHHHHHHCfffffffffff",
	"fHBBBEBECHEBEBEBECffHEBBBEBBBEBEBEBECff       Cf",
	"fHBBEEEEEHBBEEBHHDffHBBBEEEEEEEEEBHHDff       Hf",
	"fHBEHHHCHHBEHHCADGffHBBEHHHCHHCHHCADGff       Hf",
	"fHEHCAAAAHEHAADGGDffHEEHCAAAAAAAADGGDff       Hf",
	"fHEHADADAHEHDDGGGAffHEEHADADADADDGGGAff       Hf",
	"fHEHADADDHEHDDGGGAffHEEHADADDDDDDGGGAff       Hf",
	"fHEHADDDDHEHADDGGAffHEEHADDDDDDDDGGGAff       Hf",
	"fHEHADDDDHEHDDGGGAffHEEHADDDDDDDDGGGAff       Hf",
	"fHEHAADDDHEHDDGGGAffHEEHAADDDDDDDGGGAff       Hf",
	"fHEHADDDDHEHDDGGGAffHEEHADDDDDDDDGGGAff       Hf",
	"fHECDGGGGHECGGGGGAffHEECDGGGGGGGGGGGAff       Hf",
	"fHHAGGGGGHEAGGGGGAffHEHAGGGGGGGGGGGGAff       Hf",
	"fHHDGGGGGHHDGGGGDCffHHHDGGGGGGGGGGGDCff       Hf",
	"fHAGDDAAAHCAAAAACCfffHAGDDAAAAAAAAACCff       Hf",
	"fffffffffffffffffffffffffffffffffffffff       Hf",
	"fHHHHHHHHHHHHHHCff                   Cf       Hf",
	"fHCACACACACACCACff                   Hf       Hf",
	"fHAAAAAAAiAAAAGAff                   Hf       Hf",
	"fHDDDDDDhDDDDDGAff                   Hf       Hf",
	"fHDDDDDBDDDDDDGAff                   Hf       Hf",
	"fHDDDDDDBDDDDDGCff                   Hf       Hf",
	"fHDDDDDDDBDDDDGCff                   Hf       Hf",
	"fHAAAAAAAAAAAACCff                   Hf       Hf",
	"fHHHHHHHHHHHHHHCff                   Hf       Hf",
	"fHCACACACACACCACff                   Hf       Hf",
	"fHAAAAABAAAAAAGAff                   Hf       Hf",
	"fHDDDDDDBDDDDDGAff                   Hf       Hf",
	"fHDDDDDDDBDDDDGAff                   Hf       Hf",
	"fHDDDDDDhDDDDDGCff                   Hf       Hf",
	"fHDDDDDiDDDDDDGCff                   Hf       Hf",
	"fHAAAAAAAAAAAACCffCHHHHHHHHHHHHHHHHHHHfCHHHHHHHf"
    };

    char *cdplayer[] = {
	/* width height num_colors chars_per_pixel */
	"    48    48       20      1",
	/* colors */
	". c #000000",
	"# c #202420",
	background,
	"b c #404040",
	"c c #484848",
	"d c #606060",
	"e c #606460",
	"f c None",
	"g c #818181",
	"h c #c0c0c0",
	"i c #cccccc",
	"j c #FFFFFF",
	"A c #40403f",
	"B c #a9a9aa",
	"C c #585857",
	"D c #313132",
	"E c #9c9c9b",
	"F c #cececc",
	"G c #0f0f10",
	"H c #7a7a7a",
	/* pixels */
	"ffffffffffffffffffffffffffffffffffffffffffffffff",
	"                                               C",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCH",
	"ffffffffffffffffffffffffffffffffffffffffffffffff",
	"fCHHHHHHfffffffffffCHHHHHHHHHHHHHHHCffffffffffff",
	"fHBBEEEEBHCffffffffHBBBEEEEEEEEEBHHDfff       Hf",
	"fHBEHHCHCEHCfffffffHBHCHHHCHHCHHCADGfff       Hf",
	"fHEHCAAACHHHCffffffHEHCCAAAAAAAADGGDfff       Hf",
	"fHEHAADADACEHHfffffHEHDADADADADDGGGAfff       Hf",
	"fHEHADDDDDDDEHHCfffHEHCCCCCCCCCCCCCCfff       Hf",
	"fHEHADDDDDDDDEHHCffffffffffffffffffffff       Hf",
	"fHEHADDDDDDDDDEHHCffHBBBBBBBBBBBBBBBfff       Hf",
	"fHEHADDDDDDDADDCfffffCHCHCHCCHCHCHCffff       Hf",
	"fHEHADDDDDDDDDCfffffffCCCCCCCCCCCCfffff       Hf",
	"fHEHADDDDDDDDDfffffffffCDCDCCDCDCffffff       Hf",
	"fHEHADDDDDDDCfffffffffffDDDDDDDCfffffff       Hf",
	"fHECDGGGDDADfffffffffffffGGGGGCffffffff       Hf",
	"fHHAGGGGDDCfffffffffffffffGGGCfffffffff       Hf",
	"fHAGDAAACffffffffffffffffffGGffffffffff       Hf",
	"fffffffffffffffffffffffffffffffffffffff       Hf",
	"fHHHHHHHHHHHHHHCff                   Cf       Hf",
	"fHCACACACACACCACff                   Hf       Hf",
	"fHAAAAAAAiAAAAGAff                   Hf       Hf",
	"fHDDDDDDhDDDDDGAff                   Hf       Hf",
	"fHDDDDDBDDDDDDGAff                   Hf       Hf",
	"fHDDDDDDBDDDDDGCff                   Hf       Hf",
	"fHDDDDDDDBDDDDGCff                   Hf       Hf",
	"fHAAAAAAAAAAAACCff                   Hf       Hf",
	"fHHHHHHHHHHHHHHCff                   Hf       Hf",
	"fHCACACACACACCACff                   Hf       Hf",
	"fHAAAAABAAAAAAGAff                   Hf       Hf",
	"fHDDDDDDBDDDDDGAff                   Hf       Hf",
	"fHDDDDDDDBDDDDGAff                   Hf       Hf",
	"fHDDDDDDhDDDDDGCff                   Hf       Hf",
	"fHDDDDDiDDDDDDGCff                   Hf       Hf",
	"fHAAAAAAAAAAAACCffCHHHHHHHHHHHHHHHHHHHfCHHHHHHHf"
    };
    
#ifdef MIXER    
    char *cdmixer[] = {
	/* width height num_colors chars_per_pixel */
	"    48    48       38         1",
	/* colors */
	". c #000000",
	"# c #202420",
	background,
	"b c #404040",
	"c c #484848",
	"d c #606060",
	"e c #606460",
	"f c None",
	"g c #818181",
	"h c #c0c0c0",
	"i c #cccccc",
	"j c #FFFFFF",
	"A c #40403f",
	"B c #a9a9aa",
	"C c #585857",
	"D c #313132",
	"E c #9c9c9b",
	"F c #cececc",
	"G c #0f0f10",
	"H c #7a7a7a",
	
	"I c #707070",
	"J c #757575",
	"K c #808080",
	"L c #858585",
	"M c #909090",
	"O c #959595",
	"P c #a0a0a0",
	"0 c #a5a5a5",
	"1 c #B0B0B0",
	"2 c #B5B5B5",
	"3 c #C0C0C0",
	"4 c #C5C5C5",
	"5 c #D0D0D0",
	"6 c #D5D5D5",
	"7 c #E0E0E0",
	"8 c #E5E5E5",
	"9 c #F0F0F0",

	"N c #a0ffa0",
	/* pixels */
	"ffffffffffffffffffffffffffffffffffffffffffffffff",
	"                                               C",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"                                               H",
	"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCH",
	"ffffffffffffffffffffffffffffffffffffffffffffffff",
	"ffffffffffffffffffffffffffffffffffffffffffffffff",
	"f88888888888ff88888888888ff88888888888f       Hf",
	"f88888888888ff88888888888ff88888888888f       Hf",
	"f77777777777ff77777777777ff77777777777f       Hf",
	"f77777777777ff77777777777ff77777777777f       Hf",
	"f66666666666ff66666666666ff66666666666f       Hf",
	"f66666666666ff66666666666ff66666666666f       Hf",
	"f55555555555ff55555555555ff55555555555f       Hf",
	"f55555555555ff55555555555ff55555555555f       Hf",
	"f44444444444ff44444444444ff44444444444f       Hf",
	"f44444444444ff44444444444ff44444444444f       Hf",
	"f33333333333ff33333333333ff33333333333f       Hf",
	"f33333333333ff33333333333ff33333333333f       Hf",
	"f22222222222ff22222222222ff22222222222f       Hf",
	"f22222222222ff22222222222ff22222222222f       Hf",
	"f11111111111ff11111111111ff11111111111f       Hf",
	"f11111111111ff11111111111ff11111111111f       Hf",
	"f00000000000ff00000000000ff00000000000f       Hf",
	"f00000000000ff00000000000ff00000000000f       Hf",
	"fPPPPPPPPPPPffPPPPPPPPPPPffPPPPPPPPPPPf       Hf",
	"fPPPPPPPPPPPffPPPPPPPPPPPffPPPPPPPPPPPf       Hf",
	"fOOOOOOOOOOOffOOOOOOOOOOOffOOOOOOOOOOOf       Hf",
	"fOOOOOOOOOOOffOOOOOOOOOOOffOOOOOOOOOOOf       Hf",
	"fMMMMMMMMMMMffMMMMMMMMMMMffMMMMMMMMMMMf       Hf",
	"fMMMMMMMMMMMffMMMMMMMMMMMffMMMMMMMMMMMf       Hf",
	"fLLLLLLLLLLLffLLLLLLLLLLLffLLLLLLLLLLLf       Hf",
	"fLLLLLLLLLLLffLLLLLLLLLLLffLLLLLLLLLLLf       Hf",
	"fKKKKKKKKKKKffKKKKKKKKKKKffKKKKKKKKKKKf       Hf",
	"fKKKKKKKKKKKffKKKKKKKKKKKffKKKKKKKKKKKf       Hf",
	"fJJJJJJJJJJJffJJJJJJJJJJJffJJJJJJJJJJJf       Hf",
	"fJJJJJJJJJJJffJJJJJJJJJJJffJJJJJJJJJJJf       Hf",
	"fCHHHHHHHHHHffCHHHHHHHHHHffCHHHHHHHHHHfCHHHHHHHf"
    };
#endif
    
    /* ---------------------------------------------------------------------- */

    XGetWindowAttributes(Disp,Root,&Attributes);

    
    cdplayerXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    Ret = XpmCreatePixmapFromData(Disp, Root, cdplayer, &cdplayerXPM.pixmap,
				  &cdplayerXPM.mask, &cdplayerXPM.attributes);
   
    cdpausedXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    Ret = XpmCreatePixmapFromData(Disp, Root, cdpaused, &cdpausedXPM.pixmap,
				  &cdpausedXPM.mask, &cdpausedXPM.attributes);
    
#ifdef MIXER
    cdmixerXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    Ret = XpmCreatePixmapFromData(Disp, Root, cdmixer, &cdmixerXPM.pixmap,
				  &cdmixerXPM.mask, &cdmixerXPM.attributes);

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

    alphaXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    Ret = XpmCreatePixmapFromData(Disp, Root, alpha, &alphaXPM.pixmap,
				  &alphaXPM.mask, &alphaXPM.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 newtext(char *txt) { 
    strcpy(led_text, txt);
    text_start = 0;
} 

void text(char *txt) { 
    unsigned int x = 0;
    
    for(x = 0; x < strlen(txt); x++)
      {
	  if ((txt[x] >= 65) && (txt[x] <= 91)) {
	      XCopyArea(Disp, alphaXPM.pixmap, Win, WinGC,
			9 * (txt[x] - 65), 0, 9, 11, (x * 9), 2);
	      
	      XCopyArea(Disp, alphaXPM.pixmap, Iconwin, WinGC,
			9 * (txt[x] - 65), 0, 9, 11, (x * 9), 2);
	  }
      }
    
} 

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

    if (strlen(led_text) > 0) {
	if (text_start == 0) text_start = time(NULL);

	if (time(NULL) - text_start > text_timeout) {
	    text_start = 0;
	    strcpy(led_text, "");
	    redraw = TRUE;
	}
    }

    if (playing || paused) {
	cd_status();
    }
    
    if (playing) currenttrack = cur_track;

    if((cur_track == maxtracks - 1) &&
       (playing) && (!paused) && 
       (cur_cdmode != PLAYING)) {
	cdcontrol(STOP);
	if (autorepeat) cdcontrol(PLAY);
    } else {
	if((!paused && lasttime == cur_pos_rel) && (!redraw) && (text_start == 0)) return;
	if (redraw) redraw = FALSE;
    }

    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] = (cur_cdlen / 60);
	if (cdtime[1] >= 10) {
	    cdtime[0] = cdtime[1] / 10;
	    cdtime[1] = cdtime[1] % 10;
	}
	cdtime[2] = ((cur_cdlen % 60) / 10);
	cdtime[3] = (cur_cdlen % 10);
    }
    
    
    /* find which XPM to display.... */

#ifdef MIXER
    if (global_mode == 'c') {
#endif
	if (playing) 
	    currentXPM = cdpausedXPM; 	
	else 
	    currentXPM = cdplayerXPM;
#ifdef MIXER
    } else if (global_mode == 'm') {
	currentXPM = cdmixerXPM;
    }
#endif

    /* do it */
    
    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 */

    if (global_mode == 'c') {
	if (cur_cdmode != EJECTED) {
	    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		      9*track[0], 0, 9, 11, 19, 34);
	    
	    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		      9*track[0], 0, 9, 11, 19, 34); /* -3 -6 */
	    
	    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		      9*track[1], 0, 9, 11, 28, 34);
	    
	    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		      9*track[1], 0, 9, 11, 28, 34);
	    
	} else {
	    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		      98, 0, 9, 11, 19, 34);
	    
	    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		      98, 0, 9, 11, 19, 34);
	    
	    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		      98, 0, 9, 11, 28, 34);
	    
	    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		      98, 0, 9, 11, 28, 34);
	}
    } else if (global_mode == 'm') {
#ifdef MIXER
	for(x = 0; x < 3; x++)
	  {
	      XCopyArea(Disp, cursorXPM.pixmap, Win, WinGC,
			0, 0, 12, 5, (13 * x) + 1, 16 + volbutloc[x]);
	      XCopyArea(Disp, cursorXPM.pixmap, Iconwin, WinGC,
			0, 0, 12, 5, (13 * x) + 1, 16 + volbutloc[x]);
	  }
#endif
    }
    
    /* time leds */

    if (!paused || flash) {

	if ((! datatrack) && (cur_cdmode != EJECTED)) {
	    
	    if (strlen(led_text) == 0) {

		if ((time_mode == 1) || (time_mode == 3) || (time_mode == 2) || (cur_cdmode == STOPPED) ) {

		    /* The '-' for the remaining times */
		    
		    if ((time_mode != 2) || (cur_cdmode == STOPPED)) {
			XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
				  98, 5, 4, 2, 1, 8);
			
			XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
				  98, 5, 4, 2, 1, 8);
		    }
		    
		    /* The 'o' for global CD times */
		    
		    if ((time_mode == 2) || (time_mode == 3) || (cur_cdmode == STOPPED)) {
			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 = 5; /* -2 */
		} else {
		    time_offset = 3; /* -1 */
		}
		
		XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
			  9*cdtime[0],0, 9,11, 1 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			  9*cdtime[0],0, 9,11, 1 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
			  9*cdtime[1],0, 9,11, 10 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			  9*cdtime[1],0, 9,11, 10 + time_offset, 2);
	    } else {
		text(led_text);
	    }
	} else { /* if datatrack, show --:-- */

	    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		      98, 0, 9,11, 2 + 1 + time_offset, 2);

	    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		      98, 0, 9,11, 2 + 1 + time_offset, 2);

	    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		      98, 0, 9,11, 11 + 1 + time_offset, 2);

	    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		      98, 0, 9,11, 11 + 1 + time_offset, 2);
	}

	if (strlen(led_text) == 0) {
	    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
		      9*10, 0, 6,11, 19 + time_offset, 2);
	    
	    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
		      9*10, 0, 4,11, 19 + time_offset, 2);
	    
	    if ((! datatrack) && (cur_cdmode != EJECTED)) {
		XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
			  9*cdtime[2],0, 9,11, 23 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			  9*cdtime[2],0, 9,11, 23 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
			  9*cdtime[3],0, 9,11, 32 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			  9*cdtime[3],0, 9,11, 32 + time_offset, 2);
	    } else {
		XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
			  98,0, 9, 11, 24 + 1 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			  98,0, 9, 11, 24 + 1 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
			  98,0, 9, 11, 33 + 1 + time_offset, 2);
		
		XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			  98,0, 9, 11, 33 + 1 + time_offset, 2);
	    }
	}
    }
    
    /* the status bar */

    if ( (cur_cdmode != STOPPED) && (cur_cdmode != EJECTED) ) {
	if ((time_mode == 2) || (time_mode == 3)) {
	    XCopyArea(Disp, barXPM.pixmap, Win, WinGC,
		      0,0, 5, 2 + (int)((float)cur_pos_abs / (float)cur_cdlen * 30.0), 40, 17);
	    XCopyArea(Disp, barXPM.pixmap, Iconwin, WinGC,
		      0,0, 5, 2 + (int)((float)cur_pos_abs / (float)cur_cdlen * 30.0), 40, 17);
	} else {
	    XCopyArea(Disp, barXPM.pixmap, Win, WinGC,
		      0,0, 5, 2 + (int)((float)cur_pos_rel / (float)cur_tracklen * 30.0), 40, 17);
	    XCopyArea(Disp, barXPM.pixmap, Iconwin, WinGC,
		      0,0, 5, 2 + (int)((float)cur_pos_rel / (float)cur_tracklen * 30.0), 40, 17);
	}
    }

} 


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

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;
} 

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

/* Taken from asmixer: */

#ifdef MIXER
void getvol()
{
    int fd;
    int status=0;
    int x;

    fd=open(mixer_device,0);
    
    if(fd < 0)
      {
	  fprintf(stderr,"ascd: unable to grab %s\n", mixer_device);
	  return;
      }
    for(x=0;x<3;x++)
      {
	  if (ioctl(fd,MIXER_READ(voldev[x]),&vol[x]) < 0)
	    status = -1;
	  vol[x]=vol[x] >> 8;
	  volbutloc[x]=37 - (vol[x] * 37) / 100;
      }
    close(fd);
    if(status < 0)
      {
	  fprintf(stderr,"asmixer:error reading from %s\n", mixer_device);
	  return;
      }
#ifdef DEBUG
    fprintf(stderr, "vol %i old %i \n",vol[0], volold[1]);
#endif
    for(x=0;x<3;x++)
      if(volold[x]!=vol[x]) changedmask=redraw=TRUE;

}

void setvol(int control, int setto, unsigned int rd_window)
{
    int fd;

    /* denis: added those 2 tests on 'control' to avoid crash with
     * clicks outside the faders */
    if (control < 0) control = 0;
    if (control > 2) control = 2;
      
    if (setto > 35) setto = 35;
    if (setto < 0) setto = 0;

    fd = open(mixer_device, 0);

    vol[control] = 100 - ((setto * 100) / 35);
    volold[control]=vol[control] << 8;
    vol[control]=volold[control] | vol[control];
    
    ioctl(fd, MIXER_WRITE(voldev[control]), &vol[control]);

    volbutloc[control] = setto;
    
    close(fd);

    if (rd_window) RedrawWindow(&currentXPM);
}
#endif

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

/* dumb functions: do nothing, but need to be present if we don't
 * want to change anything in the WorkMan code */

void disable_save() { }
int get_playnew() { return autoplay; }
void set_abtimer(int a, int b) { }
void about_set_drivetype(char *vendor, char *model, char *rev) { }
