/* Copyright (C) 1999 Neil Moore <neil@cs.uky.edu>
 *
 *
 */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/extensions/xf86vmode.h>

Display *display;

int  list_modes(int screen);
int  to_int(const char *str);
void die(const char *message);
void help(void);

int main(int argc, char *argv[]) 
{
	const char *disptext;
	char *errmsg;
	int dolist=0;  /* 0=list modes, nonzero=change mode */
	int zoom=0;  /* 1=next mode, -1=prev mode */
	int screen=0;
	int i;

	disptext=getenv("DISPLAY");
	
	if (argc < 2) {
		help();
		exit(1);
	}
	
	for(i=1; i < argc; i++) {
		if (!strcmp(argv[i], "-display")) {
			if (i == argc-1)
				die("invalid command line");
			else 
				disptext = argv[++i];
		} else if(!strcmp(argv[i], "-s")
		       || !strcmp(argv[i], "-screen")
		       || !strcmp(argv[i], "--screen"))
		{
			screen = to_int(argv[++i]);
			if(screen < 0) {
				die("-screen takes a positive integer argument");
			}
		} else if(!strcmp(argv[i], "-h") 
		       || !strcmp(argv[i], "-help") 
		       || !strcmp(argv[i], "--help"))
		{
			help();
			exit(0);
		} else if(!strcmp(argv[i], "-l") 
		       || !strcmp(argv[i], "-list")
		       || !strcmp(argv[i], "--list"))
		{
			dolist = 1;
		} else if(!strcmp(argv[i], "+")) {
			zoom = 1;
		} else if(!strcmp(argv[i], "-")) {
			zoom = -1;
		} else {
			help();
			die("invalid command line");
		}
	}
	
	if(disptext == NULL) {
		disptext = ":0";
	}

	if((display=XOpenDisplay(disptext))==NULL) {
		errmsg = malloc(strlen(disptext) +
		         strlen("could not open display ") + 1);
		if(errmsg == NULL)
			die("could not open display");
		strcpy(errmsg, "could not open display ");
		strcpy(errmsg + strlen("could not open display "), disptext);
		errmsg[strlen(disptext) +
		       strlen("could not open display ")] = 0;
		die(errmsg);
	}
	
	if(dolist) {
		if(!list_modes(screen)) {
			die("could not get mode list");
		}
	} else if(zoom) {
		XF86VidModeSwitchMode(display,0,zoom);
	}

	XCloseDisplay(display);
	
	return 0;
}

int list_modes(int screen) {
	XF86VidModeModeInfo **modes;
	int count, i;

	if(!XF86VidModeGetAllModeLines(display, screen, &count, &modes)) {
		return 0;
	}

	for(i=0; i<count; ++i) {
		int h = modes[i]->hdisplay;
		int v = modes[i]->vdisplay;
		Status rv = XF86VidModeValidateModeLine(display, screen, modes[i]);
		printf("%dx%d:  %d\n", h, v, rv);
	}
	/* don't bother freeing modes, since this program is not long-lived */
	return 1;
}

int to_int(const char *str)
{
	long result;
	char *end=NULL;
	if(str == NULL)
		return 0;
	
	result = strtol(str, &end, 0);

	if(*str != '\0' && *end == '\0')
		return (int)result;
	else
		return -1;
}

void die(const char *message) 
{
	fprintf(stderr,"xf86vidmode: %s\n",message);
	exit(1);
}

void help(void) {
	fprintf(stderr,"usage: xf86vidmode [+|-]\n");
}
