/* x
 *
 */

#include <stdio.h>
#include <X/Xlib.h>

#define	FAILURE	0			    /*Failure return code */
#define AllEvents 0xffff		    /*Select all events  */

#define NO_ARG -1
#define ALL_ARG -2

#define CMD_NOARG 1             /* Command can't an argument */
#define CMD_ARG 2               /* Command must have an argument */
#define CMD_ALLARG 4            /* Command can accept all argument */

#define CMD_ARGALL 6

char cmd[80];
int mousex, mousey;			    /* initial mouse coords */
Window w0, w1;
int num;
extern int done;              /* Global signal handling routines */
int done=0;

struct {
	char *str;
	int num;
	int type;
} cmds[] = {
		{"q",0,CMD_NOARG},
		{"quit",0,CMD_NOARG},
		{"map",1,CMD_ARGALL},
		{"unmap",2,CMD_ARGALL},
		{"destroy",3,CMD_ARGALL},
		{"refresh",4,CMD_NOARG},		
		{"l",5,CMD_NOARG},
		{"bitrot",6,CMD_ARG},
		{"grab",7,0},
		{"g",7,0},
		{"bounce",8,CMD_ARG},
		{"",-1}
	};

struct {
  Window window;
  Window parent;
} wlist[100];

Display *Dply;

void PRS(), GetCommand();

main(argc, argv)
	int argc;
	char *argv[];
{
	int arg,func,type;
	int update;
	int i;
	
	PRS(argc,argv);

	update = 1;
	while (1) {
		if (update) {
			num=0;
			XGetInfo(RootWindow,&num);
			XWindowStats();
			update = 0;
		}
		GetCommand(&func,&arg,&type);
		if ((type & CMD_NOARG) && (arg != NO_ARG)) {
			puts("No arguments allowed");
			continue;
		}
		if ((type & CMD_ARG) && ((arg<0) || (arg>num))) {
			puts("Bad argument.");
			continue;
		}
		if ((arg == ALL_ARG) && !(type & CMD_ALLARG)) {
			puts("Can't specify all windows here.");
			continue;
		}
		switch (func) {
		case 0:
			exit(0);
		case 1:
			if (arg == ALL_ARG) 
				for (i=0;i<num;i++)
					XMapWindow(wlist[i].window);
			else
				XMapWindow(wlist[arg].window);
			XFlush();
			break;
		case 2:
			if (arg == ALL_ARG)
				for (i=0;i<num;i++)
					XUnmapWindow(wlist[i].window);
			else
				XUnmapWindow(wlist[arg].window);
			XFlush();
			break;
		case 3:
			if (arg == ALL_ARG)
				for (i=0;i<num;i++)
					XDestroyWindow(wlist[i].window);
			else
				XDestroyWindow(wlist[arg].window);
			XFlush();
			break;
		
		
		case 4:
			Xrefresh();
			break;
		case 5:
			update = 1;
			break;		
		case 6:
			bitrot(Dply,wlist[arg].window);
			break;
		case 7:
			if (arg == NO_ARG)
				arg=0;
			grab(Dply,wlist[arg].window);
			break;
		case 8:
			bounce(Dply,wlist[arg].window);
			break;
		case -1:
			puts("Undefined command.\n");
			break;
		default:
			puts("Undefined function code.\n");
			break;
		}
		    
	}

}

void PRS(argc,argv)
int argc;
char **argv;
{
	char display[80];

	display[0]='\0';
	if (argc>=2)
		strncpy(display,argv[1],80);
	
	/* open the user's display */
	if ((Dply = XOpenDisplay(display)) == NULL) 
		Error("Unable to open display");
}


void GetCommand(func,arg,type)
	int *func,*arg,*type;
{
	int i,stat;
	char key[40];

	stat=0;
	key[0]='\0';
	while (!key[0]) {
		printf("Command: ");
		gets(cmd);
		if feof(stdin) {
			printf("\n");
			*arg = NO_ARG;
			*func = 0;
			return;
		}
		stat=sscanf(cmd,"%s %d",key,arg);
		if (stat==1)
			*arg = NO_ARG;
	}
	i=0;
	while (cmds[i].str[0] && strcmp(key,cmds[i].str))
		i++;
	if (!cmds[i].str[0]) 
		*func= -1;
	else {
		*func=cmds[i].num;
		*type=cmds[i].type;
	}
}
        

XGetInfo(w,n)
Window w;
int *n;
{      
	Window parent,**children;
	int num,i;
	char *name;
	WindowInfo info;
	
	XQueryTree(w,&parent,&num,&children);
	wlist[*n].window=w;
	wlist[*n].parent=parent;
	(*n)++;
	for (i = 0; i < num; i++)
		XGetInfo(children[i],n);
	free(children);
}

long int GetWindowNum(w)
Window w;
{
	int i;
	
	for (i=0;i<num;i++)
		if (wlist[i].window == w)
			return(i);
	return((long int) w);
}

char GetMappedType(mapped)
short mapped;
{
	switch (mapped) {
	case IsUnmapped:
		return('u');
	case IsMapped:
		return('m');
	case IsInvisible:
		return('v');
	default:
		return('?');
	}
}
char GetWindowType(type)
short type;
{
	switch (type) {
	case IsTransparent:
		return('T');
	case IsOpaque:
		return('O');
	case IsIcon:
		return('I');
	default:
		return('?');
	}
}

			
XWindowStats()
{
	int i;
	Window w;
	WindowInfo info;
	char *name;

	for (i=0;i<num;i++) {
		w=wlist[i].window;
		XQueryWindow(w,&info);
		XFetchName(w, &name);
		printf("%d id#%0lx7 %ld (%d,%d) (%d,%d) %c%c ==> %ld - %s\n",
		       i, w, GetWindowNum(wlist[i].parent),
		       info.x, info.y,
		       info.width,info.height,
		       GetWindowType(info.type),GetMappedType(info.mapped),
		       GetWindowNum(info.assoc_wind),name);
		free(name);
	}
}

Xrefresh()
{
	Window w;
	
	w = XCreateWindow(RootWindow,0,0,DisplayWidth(),DisplayHeight(),
			0, (Pixmap) 0, (Pixmap) 0);
	XMapWindow(w);
	XDestroyWindow(w);
	XFlush();
}


/* Error - print out and error message, and exit */
Error(arg)
	char	*arg;
{
	printf("%s\n",arg);
	exit(1);
}
	
void SetDone()
{
	done=1;
}
