/* ------------------------------------------------------------------------
   ascd - an AfterStep and Window Maker CD Player, with an optional mixer.
   ------------------------------------------------------------------------
   by Rob Malda (malda@slashdot.org) and Denis Bourez (denis@rsn.fdn.fr)
   ------------------------------------------------------------------------ */

#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 <grp.h>
#include <pwd.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 alphaXPM;
XpmIcon backXPM;
XpmIcon barXPM;
XpmIcon ejectXPM;
XpmIcon fwdXPM;
XpmIcon ledXPM;
XpmIcon pauseXPM;
XpmIcon playXPM;
XpmIcon rewXPM;
XpmIcon stopXPM;

/* Functions */

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

#ifdef MIXER
int check_mixer();
void setvol();
void getvol();
#endif

/* External functions */

extern time();
extern open();
extern cd_control(int);

/* The ascd global variables: */

#define RDTIME 10000L
#define RDTIME2 800000L
#define MAX_VOL 100

int lasttime=-1;

Display *Disp;
Window Root;
Window Iconwin;
Window Win;
char *Geometry = 0;
char device[128]=DEFAULTDEVICE;
int withdrawn=FALSE;
GC WinGC;
int CarrierOn = FALSE;

unsigned int global_mode = 0;      /* 0=CD player ; 1->3=reserved ; 4=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 intro_mode = 0;       /* play only the beginning of the tracks */
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 loop_mode = 0;        /* loop from loop_1 to loop_2 */
unsigned int loop_start_track = 0; /* track of the beggining of the loop */
unsigned int loop_end_track =0;    /* track of the end of the loop */
unsigned int loop_1 = 0;           /* pos. 1 */
unsigned int loop_2 = 0;           /* pos. 2 */
unsigned int wanna_play = FALSE;
unsigned int do_autorepeat = FALSE;
int wanted_track = 0;

unsigned int anomalie = 0; /* cd_control return value */

unsigned int volume = MAX_VOL ;    /* CD volume */
unsigned int muted_volume = 5;     /* CD volume in muted mode */
unsigned int muted = 0;            /* is the CD muted? */

char led_color[60];                /* foreground color for LEDs */
char led_bgcolor[60];              /* back " " " " "  " " " " " */
char led_mcolor[60];               /* foreground color for LEDs in mixer mode */
char led_mbgcolor[60];             /* back " " " " "  " " " " " in mixer mode */
char led_text[8];                  /* the 'help' messages */
unsigned int text_timeout = 1;     /* messages timemout in seconds */
long text_start = 0;               /* timeout */
int redraw = TRUE;

int mixer_changed = FALSE;         /* should not bein the #ifdef.... */

/* Mixer global vars */

#ifdef MIXER
char mixer_device[128]=DEFAULTMIXERDEVICE;
int mixer_ok = 1;
int mixer_control;
int mixer_vol;
int mixer_but;
int mixer_old;
#endif

/* The WorkMan stuff: */

extern cd_status();
extern play_cd();
extern stop_cd();
extern eject_cd();
extern pause_cd();
extern cd_volume();
extern split_workmandb();
extern WMstrdup();

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;

/* from/for WorkMan database code: */

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

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

void Help() 
{
    fprintf(stderr, "ascd %s (c) 1999 Rob Malda and Denis Bourez\n", VERSION);
    fprintf(stderr, "Primary web site: http://worldserver.oleane.com/rsn/\n\n");

    fprintf(stderr, "Usage:  ascd [-options ...] where the options are:\n\n");

    fprintf(stderr, "-version                 Print the version number\n");
    fprintf(stderr, "-help                    Display this help screen\n");
    fprintf(stderr, "+/-withdrawn             Turn on/off withdrawn mode for WindowMaker\n");
    fprintf(stderr, "-geometry geom           Standard X Location\n");
    fprintf(stderr, "-bg color                Background LED color for CD Player\n");
    fprintf(stderr, "-fg color                Foreground LED color for CD Player\n");
#ifdef MIXER
    fprintf(stderr, "-mbg color               Background LED color for the mixer\n");
    fprintf(stderr, "-mfg color               Foreground LED color for the mixer\n");
#endif
    fprintf(stderr, "-ti time                 Texts display timeout in seconds (default = 1)\n");
    fprintf(stderr, "-cue time                Cue Time in seconds (default = 10)\n");
    fprintf(stderr, "+/-a                     Turn on/off Autoplay mode\n");
    fprintf(stderr, "+/-t                     Turn on/off Autorepeat mode\n");
    fprintf(stderr, "-volume value            CD Drive volume, from 0 to 100\n");
    fprintf(stderr, "-mvolume value           CD Drive volume in mute mode, from 0 to 100\n");
    fprintf(stderr, "-device device_driver    CDROM drive device\n");
#ifdef MIXER
    fprintf(stderr, "-mixer control           Assignation of the default mixer controller (*)\n");
    fprintf(stderr, "-load                    Load the mixer settings in ~/ascdrc\n");
    fprintf(stderr,"\n(*) parameter must be one of VOLUME, BASS, TREBLE, SYNTH, PCM, SPEAKER, LINE\n");
    fprintf(stderr,"    MIC, CD, IMIX, ALTPCM, RECLEV, IGAIN, OGAIN, LINE1, LINE2, LINE3\n");
#endif

    fprintf(stderr,"Please check the ascd(1) man page for more details.\n\n");
    exit(1);
} 

void SHelp() 
{
    fprintf(stderr, "ascd: bad command line syntax.\n");
    fprintf(stderr, "Type 'ascd -help' for a list of command line options.\n");
    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;
    char WhichLine[MAX_LINE_NAME];
#endif
    int i;
    char *Argument;
    int sw;

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

	if ((Argument[0] == '-') || (Argument[0] == '+')) {
	    if (Argument[0] == '-') {
		sw = FALSE;
	    } else if (Argument[0] == '+') {
		sw = TRUE;
	    }

	    if ((strcmp(Argument + 1, "w") == 0) || (strcmp(Argument + 1, "withdrawn") == 0)) {
		if (sw) withdrawn = TRUE;
		else withdrawn = FALSE;
	    }

	    else if ((strcmp(Argument + 1, "g") == 0) || (strcmp(Argument + 1, "geometry") == 0)) {
		if(++i >= argc) SHelp();
		Geometry = argv[i];
	    }
	    
	    else if ((strcmp(Argument + 1, "d") == 0) || (strcmp(Argument + 1, "device") == 0)) {
		if(++i >= argc) SHelp();
		cd_device = malloc(strlen(argv[i]) + 1);
		strcpy(cd_device, argv[i]);
	    }

	    else if ((strcmp(Argument + 1, "f") == 0) || (strcmp(Argument + 1, "fg") == 0)) {
		if(++i >= argc) SHelp();
		strcat(led_color, argv[i]);
	    }

	    else if ((strcmp(Argument + 1, "b") == 0) || (strcmp(Argument + 1, "bg") == 0)) {
		if(++i >= argc) SHelp();
		strcat(led_bgcolor, argv[i]);
	    }

	    else if ((strcmp(Argument + 1, "mfg") == 0)) {
		if(++i >= argc) SHelp();
		strcat(led_mcolor, argv[i]);
	    }

	    else if ((strcmp(Argument + 1, "mbg") == 0)) {
		if(++i >= argc) SHelp();
		strcat(led_mbgcolor, argv[i]);
	    }

	    else if ((strcmp(Argument + 1, "c") == 0) || (strcmp(Argument + 1, "cue") == 0)) {
		if(++i >= argc) SHelp();
		cue_time = atoi(argv[i]);
	    }

	    else if ((strcmp(Argument + 1, "i") == 0) || (strcmp(Argument + 1, "ti") == 0)) {
		if(++i >= argc) SHelp();
		text_timeout = atoi(argv[i]);
	    }

	    else if ((strcmp(Argument + 1, "a") == 0) || (strcmp(Argument + 1, "autoplay") == 0)) {
		if (sw) autoplay = TRUE;
		else autoplay = FALSE;
	    }

	    else if ((strcmp(Argument + 1, "t") == 0) || (strcmp(Argument + 1, "autorepeat") == 0)) {
		if (sw) autorepeat = TRUE;
		else autorepeat = FALSE;
	    }

	    else if (strcmp(Argument + 1, "mvolume") == 0) {
		if(++i >= argc) SHelp();
		muted_volume = atoi(argv[i]);
	    }

	    else if (strcmp(Argument + 1, "volume") == 0) {
		if(++i >= argc) SHelp();
		volume = atoi(argv[i]);
	    }

#ifdef MIXER
	    else if (strcmp(Argument + 1, "load") == 0) {
		load_rc_file(TRUE);
	    }

	    else if (strcmp(Argument + 1, "mixer") == 0) {
		if(++i >= argc) SHelp();
		strncpy(WhichLine, argv[i], MAX_LINE_NAME-1);
		for(j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
		    if(strcasecmp(mixernames[j].name, WhichLine) == 0) {
			mixer_control = mixernames[j].dev;
			break;
		    }
		}
	    }
#endif

	    else if (strcmp(Argument + 1, "version") == 0) {
		fprintf(stderr, "ascd %s\n", VERSION);
		exit(0);
	    }

	    else if ((strcmp(Argument + 1, "h") == 0) || (strcmp(Argument + 1, "help") == 0)) {
		Help();
	    } else {
		SHelp();
	    }
	} else {
	    SHelp();
	}

    }
    
} 

/* The rc file functions, taken from xfascd: */

void load_rc_file(int mx)
{
    FILE *in;
    struct passwd *pw;
    char st[256];
#ifdef MIXER
    char dv[3];
#endif

    if (NULL == (pw = getpwuid(getuid()))) {
        return;
    } else {
        sprintf(st, "%s/.ascdrc", pw->pw_dir);
        if ((in = fopen(st, "r"))) {
            while ( fgets(st, 255, in) ) {
                if (strlen(st) > 0) st[strlen(st) - 1] = 0;

		if (!mx) {
#ifndef NO_D_DEVICE
		    if (strncmp(st, "CD_DEVICE=", 10) == 0) strcpy(cd_device, st + 10);
		    else if (strncmp(st, "AUTOREPEAT=", 11) == 0) autorepeat = atoi(st + 11);
#else
		    if (strncmp(st, "AUTOREPEAT=", 11) == 0) autorepeat = atoi(st + 11);
#endif
		    else if (strncmp(st, "AUTOPLAY=", 9) == 0) autoplay = atoi(st + 9);
		    else if (strncmp(st, "CUE_TIME=", 9) == 0) cue_time = atoi(st + 9);
		    else if (strncmp(st, "TI=", 3) == 0) text_timeout = atoi(st + 3);
		    else if (strncmp(st, "BGCOLOR=", 8) == 0) strcat(led_bgcolor, st + 8);
		    else if (strncmp(st, "FGCOLOR=", 8) == 0) strcat(led_color, st + 8);
		    else if (strncmp(st, "MBGCOLOR=", 9) == 0) strcat(led_mbgcolor, st + 9);
		    else if (strncmp(st, "MFGCOLOR=", 9) == 0) strcat(led_mcolor, st + 9);
		    else if (strncmp(st, "TIMEMODE=", 9) == 0) time_mode = atoi(st + 9);
		    else if (strcmp(st, "WITHDRAWN") == 0) withdrawn = TRUE;
		}
#ifdef MIXER
		if ((strncmp(st, "MIXER", 5) == 0) && (mx)) {
		    strncpy(dv, st + 5, 2);
		    dv[2] = 0;
		    setvol(atoi(dv), atoi(st + 8), 100);
		}
#endif
            }
            fclose(in);
            return;
        } else {
            return;
        }
    }
}

void save_rc_file()
{
    FILE *out;
    struct passwd *pw;
    char st[128];
#ifdef MIXER
    unsigned int i=0;
#endif

    if (NULL == (pw = getpwuid(getuid()))) {
	/* hum... big problem... */
        return;
    } else {
        sprintf(st, "%s/.ascdrc", pw->pw_dir);
        if ((out = fopen(st, "w"))) {
            fprintf(out, "#### generated by ascd version %s ####\n", VERSION);
#ifndef NO_D_DEVICE
	    fprintf(out, "CD_DEVICE=%s\n", cd_device);
#endif	   
            fprintf(out, "AUTOREPEAT=%d\n", autorepeat);
            fprintf(out, "AUTOPLAY=%d\n", autoplay);
            fprintf(out, "CUE_TIME=%d\n", cue_time);
            fprintf(out, "TI=%d\n", text_timeout);
	    fprintf(out, "BGCOLOR=%s\n", led_bgcolor + 4);
	    fprintf(out, "FBGCOLOR=%s\n", led_color + 4);
	    fprintf(out, "MBGCOLOR=%s\n", led_mbgcolor + 4);
	    fprintf(out, "MFGCOLOR=%s\n", led_mcolor + 4);
	    fprintf(out, "TIMEMODE=%d\n", time_mode);
	    if (withdrawn) {
		fprintf(out, "WITHDRAWN\n");
	    }

#ifdef MIXER
	    for (i = 0; i <= 16; i++) {
		getvol(i);
		fprintf(out, "MIXER%02d=%d\n", i, mixer_vol);
	    }
	    
	    getvol(mixer_control);
#endif

            fclose(out);
            return;
        } else {
            return;
        }
    }
}


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

/* The mixer functions, based on asmixer: */

#ifdef MIXER
int check_mixer()
{
    int fd;
    if ((fd = open(mixer_device,0))) {
	close(fd);
    } else {
	return FALSE;
    }
    return TRUE;
}

void getvol(int control) /* read the mixer value for 'ct' slide */
{
    int fd;
    int status = 0;

    if (mixer_ok) {
	if ((fd = open(mixer_device,0))) {
	    if (ioctl(fd, MIXER_READ(control), &mixer_vol) < 0) status = -1;
	    mixer_vol = mixer_vol >> 8;
	    mixer_but = (30 - (mixer_vol * 30) / 100);
	    close(fd);
	}
    }
}

void setvol(int control, int setto, int maximum)
{
    int fd;

    if (setto > maximum) setto = maximum;
    if (setto < 0) setto = 0;

    if ((fd = open(mixer_device, 0))) {
	mixer_vol = ((float)setto / (float)maximum) * 100;
	mixer_old = mixer_vol << 8;
	mixer_vol = mixer_old | mixer_vol;
	ioctl(fd, MIXER_WRITE(control), &mixer_vol);
	close(fd);
    }
}
#endif

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

void cdplayer_mouse_events(XEvent Event) 
{
    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) {
	case 2: /* Mid button: (un)mute volume */
	    if (muted) {
		muted = 0;
		cd_volume(volume, 10, 100);
	    } else {
		newtext("MUTE");
		muted = 1;
		cd_volume(muted_volume, 10, 100);
	    }
	    break;
#ifdef MIXER
	case 3: /* Right clic: change to mixer mode */
	    if (global_mode == 4) {
		global_mode = 0;
		GetLEDS(led_color, led_bgcolor);
		mixer_changed = TRUE;
	    } else {
		global_mode = 4;
		/*FreeLEDS();*/
		GetLEDS(led_mcolor, led_mbgcolor);
		mixer_changed = TRUE;
	    }
	    redraw = TRUE;
	    break;
#endif
	default: /* Left: 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! */

	if (global_mode < 4) {
	    switch(Event.xbutton.button) {
	    case 3:
		
		/* Loc Access:
		   We move to the starting point of the loop. */
		
		cd_control(LOCACCESS);
		RedrawWindow(&backXPM);
		cd_status();
		if (!anomalie) newtext("LOC");
		else newtext("ERROR");
		break;
	    default:
		
		/* Direct Access:
		   we have to compute the offset to pass it to cd_control. We also have to
		   check if we want to move inside the current track or in the whole CD */
		
		if (cur_track < 1) cur_track = 1;
		
		if ((time_mode == 2) || (time_mode == 3)) {
		    direct_access = (int)((float)(Event.xbutton.y - 17) / 31.0 * (float)cur_cdlen);
		    cd_control(GLOBALACCESS);
		} else {
		    direct_access = (int)((float)(Event.xbutton.y - 17) / 31.0 * (float)cur_tracklen);
		    cd_control(DIRECTACCESS);
		}
		cd_status();
		RedrawWindow(&backXPM);
		break;
	    }
	} else {
#ifdef MIXER
	    /* Mixer slide change */
	    switch(Event.xbutton.button) {
	    case 2: /* middle = 100% */
		setvol(mixer_control, 100, 100);
		break;
	    case 3: /* right = 50% */
		setvol(mixer_control, 50, 100);
		break;
	    default: /* set */
		setvol(mixer_control, 30 - (Event.xbutton.y - 17), 30);
		break;
	    }
	    getvol(mixer_control);
#endif
	}
    }
    
    /* play/pause and stop/eject */
    
    else if ((Event.xbutton.y > 16) && (Event.xbutton.y < 33)) {
	if(Event.xbutton.x < 19) {
	    
	    /* Play/Pause */
	    
	    if ((cur_cdmode == PLAYING) || (cur_cdmode == PAUSED)) {
		cd_control(PAUSE);
	    } else if (Event.xbutton.button == 3) {
		cd_control(INTROSCAN);
		cd_status();
		newtext("INTRO");
	    } else {
		if (cur_track < 1) cur_track = 1;
		cd_control(PLAY);
		cd_status();
	    }
	    
	    RedrawWindow(&backXPM);
	} else if (Event.xbutton.x <= 39) {
	    
	    /* the STOP button */
	    
	    switch(Event.xbutton.button) {
	    case 3: /* RButton: kill the app */
		exit(0);
		break;
	    case 2:
		break;
	    default: /* STOP or EJECT */
		cd_control(STOP);
		cd_status();
		cur_track = 0;
		redraw = TRUE;
		RedrawWindow(&backXPM);
		break;
	    }
	}
	
	
    } else {
	if (Event.xbutton.x < 18) {
	    if (Event.xbutton.y > 33) {
		if (Event.xbutton.y < 41) {

		    redraw = TRUE;
		    
		    /* down */
		    
		    if (Event.xbutton.button == 1) {
			if (global_mode == 4) {
#ifdef MIXER
			    if (mixer_control > 0) {
				mixer_control--;
			    } else {
				mixer_control = 16;
			    }
			    mixer_changed = TRUE;
#endif
			} else {
			    cd_control(DNTRACK);
			}
		    } else if (Event.xbutton.button == 3) {
			if (global_mode == 4) {
#ifdef MIXER
			    mixer_control = 0;
			    mixer_changed = TRUE;
#endif
			} else {
			    cd_control(REV);
			}
		    } else if (Event.xbutton.button == 2) {
			if (global_mode == 4) {
#ifdef MIXER
			    mixer_control = 8;
			    mixer_changed = TRUE;
#endif
			} else {
			    newtext("FIRST");
			    cd_control(FIRST);
			}
		    }

		} else {

		    redraw = TRUE;
		    
		    /* up */
		    if (Event.xbutton.button == 1) {
			if (global_mode == 4) {
#ifdef MIXER
			    if (mixer_control < 16) {
				mixer_control++;
			    } else {
				mixer_control = 0;
			    }
			    mixer_changed = TRUE;
#endif
			} else {
			    cd_control(UPTRACK);
			}
		    } else if (Event.xbutton.button == 3) {
			if (global_mode == 4) {
#ifdef MIXER
			    mixer_control = 16;
			    mixer_changed = TRUE;
#endif
			} else {
			    cd_control(CUE);
			}
		    } else if (Event.xbutton.button == 2) {
			if (global_mode == 4) {
#ifdef MIXER
			    mixer_control = 8;
			    mixer_changed = TRUE;
#endif
			} else {
			    newtext("LAST");
			    cd_control(LAST);
			}
		    }
		    
		    
		}

		RedrawWindow(&backXPM);
	    }
	} else if ( (cur_cdmode == PLAYING) || (cur_cdmode == PAUSED) ) {
	    
	    /* the track nbr display */

	    if (global_mode < 4) {
		switch(Event.xbutton.button) {
		case 2:
		    if (loop_mode) {
			loop_mode = 0;
			newtext("L OFF");
		    } else {
			cd_control(LOOP);
			if (!anomalie) newtext("LOOP");
			else newtext("ERROR");
		    }
		    break;
		case 3:
		    loop_2 = cur_pos_rel;
		    loop_end_track = cur_track;
		    newtext("L_END");
		    break;
		default:
		    loop_1 = cur_pos_rel;
		    newtext("L_STA");
		    loop_start_track = cur_track;
		    break;
		}
	    } else {
#ifdef MIXER
		switch(Event.xbutton.button) {
		case 2:
		    break;
		case 3:
		    load_rc_file(TRUE);
		    newtext("LOAD");
		    break;
		default:
		    save_rc_file();
		    newtext("SAVE");
		    break;
		}
#endif
	    }

	    RedrawWindow(&backXPM);
	}
    }
} 

/* ------------------------------------------------------------------------
   GUI control
   ------------------------------------------------------------------------ */

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

void GetLEDS(char *foreground, char *background) 
{
    int Ret;

#include "pixmaps/default/alpha.xpm"
#include "pixmaps/default/led.xpm"
#include "pixmaps/default/bar.xpm"

    /* the displays: */
    
    ledXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    Ret = XpmCreatePixmapFromData(Disp, Root, led_xpm, &ledXPM.pixmap,
				  &ledXPM.mask, &ledXPM.attributes);

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

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

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

/* got to check this....
void FreeLEDS()
{
    XpmFree(&ledXPM);
    XpmFree(&barXPM);
    XpmFree(&alphaXPM);
}
*/

void GetXPM(char *foreground, char *background) 
{
    XWindowAttributes Attributes;
    int Ret;

    /* The pixmap definition files: */

#include "pixmaps/default/back.xpm"
#include "pixmaps/default/eject.xpm"
#include "pixmaps/default/fwd.xpm"
#include "pixmaps/default/pause.xpm"
#include "pixmaps/default/play.xpm"
#include "pixmaps/default/rew.xpm"
#include "pixmaps/default/stop.xpm"

    XGetWindowAttributes(Disp,Root,&Attributes);

    /* background: */

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

    /* buttons: */

    fwdXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    Ret = XpmCreatePixmapFromData(Disp, Root, fwd_xpm, &fwdXPM.pixmap,
				  &fwdXPM.mask, &fwdXPM.attributes);
    
    rewXPM.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
    Ret = XpmCreatePixmapFromData(Disp, Root, rew_xpm, &rewXPM.pixmap,
				  &rewXPM.mask, &rewXPM.attributes);


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

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

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

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

    if (Ret != XpmSuccess) {
	fprintf(stderr, "ascd: not enough free color cells\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_color, led_bgcolor);
    GetLEDS(led_color, led_bgcolor);

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

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

    SizeHints.width = backXPM.attributes.width;
    SizeHints.height= backXPM.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(&backXPM);
} 

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;

    while (strlen(txt) < 5) strcat(txt, " ");

    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);
	  } else if (txt[x] == 32) {
	      XCopyArea(Disp, alphaXPM.pixmap, Win, WinGC,
			9 * (26), 0, 9, 11, (x * 9), 2);
	      
	      XCopyArea(Disp, alphaXPM.pixmap, Iconwin, WinGC,
			9 * (26), 0, 9, 11, (x * 9), 2);
	  } else if (txt[x] == '_') {
	      XCopyArea(Disp, alphaXPM.pixmap, Win, WinGC,
			9 * (27), 0, 9, 11, (x * 9), 2);
	      
	      XCopyArea(Disp, alphaXPM.pixmap, Iconwin, WinGC,
			9 * (27), 0, 9, 11, (x * 9), 2);
	  }
      }
    
} 

/* ------------------------------------------------------------------------
   The big deal: We have to redraw the pixmaps, and update all leds. But
   there a few cd_control() calls also.
   ------------------------------------------------------------------------ */

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 (strlen(led_text) > 0) {
	if (text_start == 0) {
	    text_start = time(NULL);
	    text(led_text);
	}
	
	if (time(NULL) - text_start > text_timeout) {
	    text_start = 0;
	    strcpy(led_text, "");
	    redraw = TRUE;
	} else { 
	    return;
	}
    }

#ifdef MIXER
    if (mixer_changed) {
	if (global_mode == 4) {
	    switch(mixer_control) {
	    case 0:	    newtext("VOLUM"); 	    break;
	    case 1:	    newtext("BASS");	    break;
	    case 2:	    newtext("TREBL");	    break;
	    case 3:	    newtext("SYNTH");	    break;
	    case 4:	    newtext("WAVE");	    break;
	    case 5:	    newtext("SPKER");	    break;
	    case 6:	    newtext("LINE");	    break;
	    case 7:	    newtext("MIC");	    break;
	    case 8:	    newtext("CD");	    break;
	    case 9:	    newtext("IMIX");	    break;
	    case 10:    newtext("APCM");	    break;
	    case 11:    newtext("REC");	    break;
	    case 12:    newtext("IGAIN");	    break;
	    case 13:    newtext("OGAIN");	    break;
	    case 14:    newtext("LINEA");	    break;
	    case 15:    newtext("LINEB");	    break;
	    case 16:    newtext("LINEC");	    break;
	    default:    newtext("_____");	    break;
	    }
	} else {
	    newtext("CD PL");
	}
	mixer_changed = FALSE;
    }
#endif

    if ((cur_cdmode == PLAYING) || (wanna_play)) cd_status();

    if ((cur_track == cur_ntracks) &&
	(wanna_play) && 
	(cur_cdmode != PAUSED) && 
	(cur_cdmode != PLAYING)
	) {

	if (autorepeat) {
	    newtext("REPT");
	    do_autorepeat = TRUE;
	    cd_control(PLAY);
	} else {
	    cur_cdmode = STOPPED;
	    cd_status();
	    cur_track = 0;
	    redraw = TRUE;
	}
    } else {
	/* 
	   no redraw needed? In this case, we leave the function here,
	   to avoid a flashy screen
	*/
	if(((cur_cdmode != PAUSED) && lasttime == cur_pos_rel) && (!redraw) && (text_start == 0)) return;
    }


    if (redraw) redraw = FALSE;

    if (cur_cdmode == 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;
    }
    
    if (cur_track > 0) {
	if (time_mode != 3) {
	    track[1] = (cur_track % 10);
	    track[0] = (cur_track / 10);
	} else {
	    track[1] = ((cur_ntracks - cur_track) % 10);
	    track[0] = ((cur_ntracks - cur_track) / 10);
	}
    } else {
	track[1] = (cur_ntracks % 10);
	track[0] = (cur_ntracks / 10);
    }

    lasttime = cur_pos_rel;

    switch(time_mode) {
    case 0:
	disp_time = cur_pos_rel;
	break;
    case 1:
	disp_time = cur_tracklen - cur_pos_rel ;
	break;
    case 2:
	disp_time = cur_pos_abs;
	break;
    default:
	disp_time = cur_cdlen - cur_pos_abs;
	break;
    }
 
    if ((cur_cdmode == PLAYING) || (cur_cdmode == 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);
    }
    
    /* Draw the background */
    
    FlushExpose(Win);
    FlushExpose(Iconwin);

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

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

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

    /* 0.9: let's draw the buttons */

    XCopyArea(Disp, rewXPM.pixmap, Win, WinGC,
	      0, 0, rewXPM.attributes.width, rewXPM.attributes.height, 1, 32);

    XCopyArea(Disp, rewXPM.pixmap, Iconwin, WinGC,
	      0, 0, rewXPM.attributes.width, rewXPM.attributes.height, 1, 32);

    XCopyArea(Disp, fwdXPM.pixmap, Win, WinGC,
	      0, 0, fwdXPM.attributes.width, fwdXPM.attributes.height, 1, 40);

    XCopyArea(Disp, fwdXPM.pixmap, Iconwin, WinGC,
	      0, 0, fwdXPM.attributes.width, fwdXPM.attributes.height, 1, 40);

    /* Play or pause? */

    if (cur_cdmode != PLAYING) {
	XCopyArea(Disp, playXPM.pixmap, Win, WinGC,
		  0, 0, playXPM.attributes.width, playXPM.attributes.height, 1, 17);
	
	XCopyArea(Disp, playXPM.pixmap, Iconwin, WinGC,
		  0, 0, playXPM.attributes.width, playXPM.attributes.height, 1, 17);
    } else {
	XCopyArea(Disp, pauseXPM.pixmap, Win, WinGC,
		  0, 0, pauseXPM.attributes.width, pauseXPM.attributes.height, 1, 17);
	
	XCopyArea(Disp, pauseXPM.pixmap, Iconwin, WinGC,
		  0, 0, pauseXPM.attributes.width, pauseXPM.attributes.height, 1, 17);
    }

    if ((cur_cdmode == PLAYING) || (cur_cdmode == PAUSED)) {
	XCopyArea(Disp, stopXPM.pixmap, Win, WinGC,
		  0, 0, stopXPM.attributes.width, stopXPM.attributes.height, 20, 17);
	
	XCopyArea(Disp, stopXPM.pixmap, Iconwin, WinGC,
		  0, 0, stopXPM.attributes.width, stopXPM.attributes.height, 20, 17);
    } else {
	XCopyArea(Disp, ejectXPM.pixmap, Win, WinGC,
		  0, 0, ejectXPM.attributes.width, ejectXPM.attributes.height, 20, 17);
	
	XCopyArea(Disp, ejectXPM.pixmap, Iconwin, WinGC,
		  0, 0, ejectXPM.attributes.width, ejectXPM.attributes.height, 20, 17);

    }

    /* track nbr */

    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);
    }
    
    /* time leds */

	if ((cur_cdmode != 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, 4 + 1 + time_offset, 2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			      98, 0, 9, 11, 4 + 1 + time_offset, 2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Win, WinGC,
			      98, 0, 9, 11, 13 + 1 + time_offset, 2);
		    
		    XCopyArea(Disp, ledXPM.pixmap, Iconwin, WinGC,
			      98, 0, 9, 11, 13 + 1 + time_offset, 2);
	    }
	    
	    if (strlen(led_text) == 0) {
		
		if ((! datatrack) && (cur_cdmode != EJECTED)) {
		    
		    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 (global_mode < 4) { /* we're in CD player mode */
	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);
	    }
	}
    } else { /* we're in mixer mode */
#ifdef MIXER
	getvol(mixer_control);
	XCopyArea(Disp, barXPM.pixmap, Win, WinGC,
		  0, 0, 5, 30 - mixer_but, 40, 17 + mixer_but);

	XCopyArea(Disp, barXPM.pixmap, Iconwin, WinGC,
		  0, 0, 5, 30 - mixer_but, 40, 17 + mixer_but);
#endif
    }
} 

/* ------------------------------------------------------------------------
   The CD player main loop
   ------------------------------------------------------------------------ */

void MainLoop() 
{
    unsigned int no_disk = 0;
    long int dodo = RDTIME;
    XEvent Event;

    while(1)
      {
	  if (cur_cdmode == EJECTED) no_disk = 1;

	  if (no_disk == 1) {
	      if (autoplay) {
		  dodo = RDTIME2;
		  cd_status();
	      }
	      if (cur_cdmode != EJECTED) no_disk = 0;
	      if ( (cur_cdmode == STOPPED) && (autoplay) )  {
		  cd_control(PLAY);
		  cd_status();
		  dodo = RDTIME;
		  RedrawWindow(&backXPM);
	      }
	  }

	  /* The Loop Mode : */
	  if ( (cur_track == loop_end_track ) && (cur_pos_rel >= loop_2) && (loop_mode) ) {
	      cd_control(LOOP);
	      RedrawWindow(&backXPM);
	  }
	  
	  /* The Intro Scan Mode : */
	  if ( (cur_pos_rel > cue_time) && (intro_mode) ) {
	      cd_control(INTRONEXT);
	      RedrawWindow(&backXPM);
	  }

	  /* Check events */

	  while (XPending(Disp))
	    {

		XNextEvent(Disp, &Event);

		    switch(Event.type) {

			/* ---------------------- Redraw Window --------------------- */
			
		    case Expose:
			if(Event.xexpose.count == 0) {
			    lasttime=01;
			    redraw = TRUE;
			    RedrawWindow(&backXPM);
			}
			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;
		    }

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

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

/* ------------------------------------------------------------------------
   dumb functions: do nothing, but they need to be present if we don't
   wanna 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) 
{ 
}

/* ------------------------------------------------------------------------
   So... let's go!
   ------------------------------------------------------------------------ */

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_color, "X c ");
    strcpy(led_bgcolor, "  c ");

    /* the mixer default settings: */
#ifdef MIXER
    strcpy(led_mcolor, "X c ");
    strcpy(led_mbgcolor, "  c ");
    mixer_control = SOUND_MIXER_VOLUME;
#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 = (char *)WMstrdup(rcfile);
    dbfiles = getenv("WORKMANDB");
    if (dbfiles)
      dbfiles = (char *)WMstrdup(dbfiles);
    
    split_workmandb();

    /* load .ascdrc file: */
    load_rc_file(FALSE);

    /* load the command line options */
    ParseCmdLine(argc, argv);

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

    if (strlen(led_color) == 4) strcat(led_color, DEFAULT_COLOR);
    if (strlen(led_bgcolor) == 4) strcat(led_bgcolor, DEFAULT_BGCOLOR);

#ifdef MIXER
    if (strlen(led_mcolor) == 4) strcat(led_mcolor, DEFAULT_MCOLOR);
    if (strlen(led_mbgcolor) == 4) strcat(led_mbgcolor, DEFAULT_MBGCOLOR);
    if (! check_mixer()) {
	fprintf(stderr, "ascd: can't initialize mixer device. Mixing support disabled.\n");
	mixer_ok = 0;
    }
#endif

    CreateWindow(argc, argv);

    cd_status();

    if (cur_cdmode != EJECTED) cd_volume(volume, 10, 100);

    if ((autoplay) && (cur_cdmode == STOPPED)) {
	cd_control(PLAY);
	cd_status();
	RedrawWindow(&backXPM);
    }

    MainLoop();
    return 0;
} 
