/*
 * xf86config; menuing X configuration program, built on the bones of
 * the grotty old text mode xf86config.
 *
 * Copyright (c) 1997-2000 David L Parsons 
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
 * to endorse or promote products derived from this software without
 * specific prior written permission.  THIS SOFTWARE IS PROVIDED
 * ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 *
 * I do not know which copyright came with the original program; I pulled
 * it from the XFree86 3.3.1 distribution, and it comes with RCS tags
 * identifying it as a X Consortium program.  I _PRESUME_ it's shipped
 * under the X copyright, but here is the comment header for the
 * original program:
 */

/*
TODO: * Monitor database
      * A way to specify resolution and bpp.
      * it would be nice to be able to read existing XF86Configs.
 */

/* $XFree86: xc/programs/Xserver/hw/xfree86/xf86config/xf86config.c,v 3.37.2.4 1997/07/19 04:59:37 dawes Exp $ */

/*
 * This is a configuration program that will create a base XF86Config
 * file based on menu choices. Its main feature is that clueless users
 * may be less inclined to select crazy sync rates way over monitor spec,
 * by presenting a menu with standard monitor types. Also some people
 * don't read docs unless an executable that they can run tells them to.
 */
/* $XConsortium: xf86config.c /main/21 1996/10/28 05:43:57 kaleb $ */

extern "C" {
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

#include <ndialog.h>
#include <dialog.h>

#include <nd/indexed_menu.h>

#include "Card.h"
#include "Monitor.h"
}

#if STAGE2
#include "buttons.h"
#define TITLE	"X setup"
#include <basis/Sysconfig.H>	/* to get mouse definitions from /etc/rc.d/sysconfig */
#else
#define	TITLE	"Xconfig"
#endif

extern jmp_buf finish;


/*
 * Define the following to 310 to remove references to XFree86 features that
 * have been added since XFree86 3.1 (e.g. DoubleScan modes).
 * or to 311 to remove certain new modelines
 */
#define XFREE86_VERSION 330

/*
 * This is the filename of the temporary XF86Config file that is written
 * when the program is told to probe clocks (which can only happen for
 * root).
 */
#ifndef __EMX__
#define TMP_XF86CONFIG "/tmp/XF86Config.tmp"
#else		/* put in root dir, would have to find TMP dir first else */
#define TMP_XF86CONFIG "\\XConfig.tmp"
#endif

/*
 * Define this to have /etc/XF86Config prompted for as the default
 * location to write the XF86Config file to.
 */
#define PREFER_XF86CONFIG_IN_ETC
/*
 * Define this to force the user to go through XKB configuration section.
 *
#define FORCE_XKB_DIALOG
 */
/*
 * Configuration variables.
 */
#define MAX_CLOCKS 16

/* some more vars to make path names in texts more flexible. OS/2 users
 * may be more irritated than Unix users
 */
#define TREEROOT "/usr/X11R6"
#define TREEROOTLX "/usr/X11R6/lib/X11"
#define MODULEPATH "/usr/X11R6/lib/modules"
#define CONFIGNAME "XF86Config"

extern int tested;

class Core {
    int _configured;
    int _modified;
public:
    int key0, key1;
    inline int configured() { return _configured; }
    inline int touched() { return _modified; }
    inline void done() { _modified = _configured = 1; }
    inline void doing(){ _configured = 0; }
};


enum __mousetype { NOMOUSE=0,SYSMOUSE, MICROSOFT, MOUSESYSTEMS,
		   BUSMOUSE, PS2MOUSE, LOGIMOUSE, MOUSEMAN,
		   MMSERIES, MMHITAB,  INTELLIMOUSE };

class Mouse: public Core {
    int _mousetype;
public:
    int emulate3buttons;
    int chordmiddle;
    int cleardtrrts;
    char device[80];

    inline void is(enum __mousetype t, int em, int ch, int clrdtr, char *dev) {
		    _mousetype = t;
		    emulate3buttons = em;
		    chordmiddle = ch;
		    cleardtrrts = clrdtr;
		    strncpy(device, dev, sizeof device);
		    Core::done();
		}
    inline Mouse() { _mousetype = -1; }
    char *protocol();
    char *description();
    inline int configured() { return _mousetype >= 0; }
    int print(FILE *f);
    int configure(int stage2);
};

class KeyBoard: public Core {
private:
    int xmodmap_configuration(void);
    int composekeymaps(void);

    int blurb;

    int altmeta;
    int disable;
    char *keymap;
    char *keycodes;
    char *types;
    char *compat;
    char *symbols;
    char *geometry;
public:
    inline void is(int a, int d, char *m, char *c = 0,
		   char *t = 0, char *co = 0,
		   char *s = 0, char *g = 0) {
			altmeta = a;
			disable = d;
			keymap = m;
			keycodes = c;
			types = t;
			compat = co;
			symbols = s;
			geometry = g;
			Core::done();
		    }
    KeyBoard();
    int configure(int stage2);
    int print(FILE *f);
};

extern ModeLine VESA[];
extern int nr_VESA;

class Display: public Core {
    int _key;		/* < 0 : not configured; >= 0 look in monitor table */

    int select_from_menu(void);
    int set_identity(void);
    int set_vsync(void);
    int set_hsync(void);
    int autodetect(void);

public:
    int vesa;		/* also include VESA[] modes */

    inline int configured()     {
				    if (_key >= 0)
					if (entry().custom())
					    return Core::configured();
					else
					    return 1;
				    return 0;
				}
    inline Display():Core()	{ _key = -1; }
    inline Monitor &entry()     { return monitor[_key]; }
    inline Monitor &entry(int k){ _key = k; return entry(); }
    inline int key()		{ return _key; }

    inline void is(int k)	{ entry(k); }
    int configure(int stage2);
    int print(FILE *f);
};

class VideoMode {
    int _bpp;
    char *_modes;
public:
    int maxres;
    int virtualX, virtualY;

    inline VideoMode() { _modes = 0; _bpp = maxres = 0; }
    inline VideoMode(int bpp) { _modes = 0; _bpp = bpp; maxres = 0; }
    inline void bits(int bpp) { _bpp = bpp; }
    inline void Erase() { if (_modes) free(_modes); _modes = 0; maxres = 0; }
    inline VideoMode &is(char *m, int mr, int vx, int vy) {
			    _modes = strdup(m);
			    maxres = mr;
			    virtualX = vx;
			    virtualY = vy; }
    inline ~VideoMode() { Erase(); }
    inline char *modes() {  if (_modes)
				return _modes;
			    else
				return "\"640x480\""; }
    int getmaxres(int memory);
    int allmodes(int memory);
};

enum __videotype { MONO=0, VGA16=1, SVGA, FIRST_ACCEL };

class VideoCard: public Core {
private:
    int _key;
    int _stage2;
    char bfr[80];

    int askcardid(void);
    int askclockchip(void);
    int askforserver(void);
    int askmemory(void);
    int askramdac(void);
    int clockprobe(void);
    int choosevideo(void);
    int find_server_for_card(int didauto);
    int memory_probe(void);
    int screen_configuration(int didauto);
    int select_card(int key);
public:
    char *ramdac;		/* our settings for ramdac */
    char *clockchip;		/* and clockchip */
    int   memory;		/* memory this card has */
    int   servertype;		/* which server to use */
    int   numberofclocks;	/* number of clocks on this card */
    char *clocks[MAX_CLOCKS];

    int accelerated();
    char *server();

    inline VideoCard()    { memory = _key = -1; }
    inline ~VideoCard()   { for (int i = 0; i < numberofclocks; i++)
				free(clocks[i]);
			    if (ramdac)
				free(ramdac);
			    if (clockchip)
				free(clockchip); }

    inline int key(int k) { return _key = k; }
    inline int key()	  { return _key; }
    inline Card &entry()  { return card[_key]; }
    inline int configured()   { if (_key < 0)
				return 0;
			    if (card[_key].custom()) return Core::configured();
			    return 1; }
    inline char *identifier() {
			    if (configured()) {
				sprintf(bfr, "%s %s",
					    card[_key].vendor(),
					    card[_key].product());
				return bfr;
			    }
			    return "unconfigured"; }

    int configure(int stage2);
    int print(FILE *f);
};

class Geometry: public Core {
private:
    int sizescreen(int memory);
    int askvirtual(void);
    int _stage2;
public:
    int   isvirtual;		/* virtual screen? */
    int   bpp_default;		/* DefaultColorDepth; in screen section */
    int   memory;
    VideoMode bpp8;
    VideoMode bpp16;
    VideoMode bpp24;
    VideoMode bpp32;		/* modes for different color depths */

    inline Geometry() { isvirtual = bpp_default = 0;
			bpp8.bits(8);
			bpp16.bits(16);
			bpp24.bits(24);
			bpp32.bits(32); }

    int is(int bpp, int memory) { bpp_default = bpp; sizescreen(memory); }
    int configure(int stage2, VideoCard *, Display *);
} ;


/*
 * These are from the selected card definition. Parameters from the
 * definition are offered during the questioning about the video card.
 */
extern int Incomplete(char*);
extern void write_XF86Config(char*, VideoCard*, Display*, Geometry*, KeyBoard*, Mouse*);
extern void write_configuration();
extern void mouse_configuration();
extern int test_configuration();
extern void setXlink();
extern char * ask_XF86Config_location();
extern int Xmenu(char *title, char *prompt, int listdepth, ListItem *list, int nrlist, int vis, char *button);
extern int Xmesg(char *title, char *prompt);

extern const unsigned char intro_text[];
extern const unsigned char finalcomment_text[];

extern Mouse generic_mouse;
extern KeyBoard generic_kb;
extern Display generic_display;
extern Geometry generic_geometry;
