/*
 * screen resolution and color depth
 */

#include "xf86config.h"
#include "util.h"
#include <assert.h>

static const ListItem modestring[] =
{
#ifdef RIDICULOUSLY_LOW_RESOLUTION
    { "320x200",	(char*)  (320*200), },
    { "320x240",	(char*)  (320*240), },
    { "400x300",	(char*)  (400*300), },
    { "512x384",	(char*)  (512*384), }, 
    { "640x400",	(char*)  (640*400), },
#endif
    { "640x480",	(char*)  (640*480), },
    { "800x600",	(char*)  (800*600), },
    { "1024x768",	(char*) (1024*768), },
    { "1152x864",	(char*) (1152*864), },
    { "1280x1024",	(char*)(1280*1024), },
    { "1600x1200",	(char*)(1600*1200), }, 
    /*{ "1800x1400",	(char*)(1800*1400), },*/
};
#define NR_MODESTRING	(sizeof modestring/sizeof modestring[0])

int
VideoMode::getmaxres(int memory)
{
    int i;

    for (i=0; i < NR_MODESTRING; i++)
	if ( ((long)(modestring[i].item)) * (_bpp / 8) > (memory * 1024) )
	    return (i==0) ? i : (i-1);
    return NR_MODESTRING-1;
} /* getmaxres */


int
VideoMode::allmodes(int memory)
{
    int size;
    int i, lowest_rez;

    if (_modes)
	free(_modes);
    _modes = 0;
    maxres = getmaxres(memory);
    sscanf(modestring[maxres].id, "%dx%d", &virtualX, &virtualY);

    lowest_rez = 0;
    for (size = 0, i = maxres; i >= 0; --i) {
	size += strlen(modestring[i].id) + 6;
	if (size > 80) { /* Xfree86 chokes on long resolution strings */
	    lowest_rez = i;
	    break;
	}
    }

    _modes = (char*)calloc(size, 1);

    for (i = maxres; i >= lowest_rez; --i) {
	if (_modes[0])
	    strcat(_modes, " ");
	sprintf(END(_modes), "\"%s\"", modestring[i].id);
    }
    return 0;
} /* allmodes */


int
Geometry::sizescreen(int memory)
{
    bpp8.allmodes(memory);
    bpp16.allmodes(memory);
    bpp24.allmodes(memory);
    bpp32.allmodes(memory);
}


int
Geometry::askvirtual()
{
    int rc;
    char mesg[2000];

    if (_stage2) {
	isvirtual = 0;
	done();
	return 1;
    }
    while (1) {
	rc = dialog_yesno(TITLE,
"If your monitor is unable to display the maximum screen resolution,\n"
"you can have a virtual screen (desktop) which is a screen area that\n"
"is larger than the physical screen and which is panned by moving the\n"
"mouse to the edge of the screen.\n"
"\n"
"Would you like to use virtual screens?", -1, -1);

	if (rc < 0)
	    return 0;

	isvirtual = (rc == 0);
	done();
	return 1;
    }
} /* askvirtual */


int
Geometry::configure(int stage2, VideoCard *v, Display *d)
{
    int rc;
    int i;
    char mesg[2000];

    static struct ListItem bpp[] =  {
	{ "256 colors", 0 },
	{ "high color", 0 },
	{ "true color (24bpp)", 0 },
	{ "true color (32bpp)", 0 },
    };
    #define NR_BPP (sizeof bpp / sizeof bpp[0])

    while (1) {
	if ( !d->configured())
	    if (!d->configure(stage2))
		return 0;
	if ( v->configured() )
	    break;
	else
	    if ( v->configure(stage2) )
		break;
	    else
		return 0;
    }

    doing();
    _stage2 = stage2;
    /*
     * For the mono and vga16 server, no further configuration is
     * required.
     */
    if (v->servertype == VGA16 || v->servertype == MONO) {
	Xmesg(TITLE, "The Mono and Vga16 servers run at 640x480 resolution\n"
		     "so no resolution configuration is needed");
	return 1;
    }

    sizescreen(v->memory);

    bpp[0].item = modestring[bpp8.maxres].id;
    bpp[1].item = modestring[bpp16.maxres].id;
    bpp[2].item = modestring[bpp24.maxres].id;
    bpp[3].item = modestring[bpp32.maxres].id;

    do {
	/*
	 * Configure the modes order.
	 */
	for (i=0; i < NR_BPP; i++)
	    bpp[i].selected = (i == (bpp_default/8)-1);

	rc = Xmenu(TITLE,
    "Please choose the default number of colors that you wish to display\n"
    "on your system.  The screen resolution listed for each color depth is\n"
    "the maximum allowed by the amount of memory on your video card.  The\n"
    "resolution that the server will start up with will be the highest\n"
    "one that can be supported by both the monitor and the card",
			    NR_BPP, bpp, NR_BPP, 1, 0);

	if (rc < 0)
	    return 0;

	bpp_default = (rc+1)*8;

	return askvirtual();
    } while (rc == 0);
    return 0;
} /* Geometry::configure */
