/*
 *	Mouse and keyboard event handling for T3X programs.
 *	Plan9-specific routines.
 *	Copyright (C) 1997,1998 Nils M. Holm
 *	See the file LICENSE for conditions of use.
 */

#include <u.h>
#include <libc.h>
#include <stdio.h>

#include "gfx.h"


void	g_error(char *s);


/*
 * Due to a totally different approach, Plan9 has no rename system call.
 * Somehow, the simulation thereof also went here...
 */
int rename(old, new)
char	*old, *new;
{
	Dir	d;
	int	k, p = 0;

	if (dirstat(old, &d) < 0) return(-1);
	k = strlen(new);
	if (k >= NAMELEN) {
		p = new[NAMELEN-1];
		new[NAMELEN-1] = 0;
	}
	memmove(d.name, new, k);
	if (p) new[NAMELEN-1] = p;
	return(dirwstat(old, &d));
}


#ifdef GRAPHICS_EXT

#include <libg.h>


int	X0, Y0, Xn, Yn, Fx, Fy;
Bitmap	*Clear, *Set;
int	Shape_changed;

extern uchar	*Data;


void ereshaped(Rectangle r);
void ereshaped(r)
Rectangle	r;
{
	screen.r = bscreenrect(&screen.clipr);
	texture(&screen, screen.r, Clear, S);
	X0 = screen.clipr.min.x;
	Y0 = screen.clipr.min.y;
	Xn = screen.clipr.max.x - X0;
	Yn = screen.clipr.max.y - Y0;
	Fx = XLIM*2 / Xn;
	Fy = YLIM*2 / Yn;
	Shape_changed = 1;
}


voide_init(void);
void e_init() {
}


int _g_init(void);
int _g_init() {
	static uchar	s[] = { 0xFF };

	binit(0, 0, "TXX");
	Clear = balloc(Rect(0, 0, 1, 1), 0);
	Set = balloc(Rect(0, 0, 1, 1), 0);
	if(!Clear || !Set) g_error("balloc() failed");
	wrbitmap(Set, 0, 1, s);
	einit(Ekeyboard|Emouse);
	ereshaped(Rect(0, 0, 0, 0));
	Shape_changed = 0;
	return(0);
}


void g_end(void);
void g_end() {
}


int g_event(struct event *e, int block);
int g_event(e, block)
struct event	*e;
int		block;
{
	static Mouse	m = { 0, 0, 0, 0 };
	short		ob;

	bflush();
	e->x = (m.xy.x - X0) * Fx - XLIM;
	e->y = (m.xy.y - Y0) * Fy - YLIM;
	e->key = -1;
	ob = m.buttons & 7;
	e->buttons = ob;
	for (;;) {
		if (ecanmouse()) {
			m = emouse();
			e->buttons = (m.buttons & 7);
			e->x = (m.xy.x - X0) * Fx - XLIM;
			e->y = (m.xy.y - Y0) * Fy - YLIM;
		}
		if (ecankbd()) {
			e->key = ekbd();
		}
		if (e->key != -1 || e->buttons != ob)
			return(-1);
		if (!block || Shape_changed) break;
	}
	return(0);
}


ulong mtime() {
	int		devmsec;
	char		buffer[20];

	if ((devmsec = open("/dev/msec", OREAD)) < 0)
		return((ulong) -1);
	read(devmsec, buffer, 20);
	close(devmsec);
	return(atol(buffer));
}


void g_wait(int msec);
void g_wait(msec) {
	unsigned	t0, t1;

	t0 = t1 = mtime();
	while (t1 - t0 < msec) {
		if ((t1 = mtime()) == (ulong)-1) return;
	}
}


int flags(int f);
int flags(f) {
	switch(f) {
	case 0:	return(Zero);
	case 1: return(S);
	case 2: return(D|S);
	case 3: return(DxorS);
	default:g_error("bad flags in graphics request");
	}
}


void g_point(int x, int y, int f);
void g_point(x, y, f) {
	x = (x + XLIM) / Fx + X0;
	y = (y + YLIM) / Fy + Y0;
	f = flags(f);
	point(&screen, Pt(x, y), 1, f);
}


void g_line(int x, int y, int dx, int dy, int f);
void g_line(x, y, dx, dy, f) {
	x = (x + XLIM) / Fx + X0;
	y = (y + YLIM) / Fy + Y0;	
	dx = (dx + XLIM) / Fx + X0;
	dy = (dy + YLIM) / Fy + Y0;
	f = flags(f);
	segment(&screen, Pt(x, y), Pt(dx, dy), 1, f);
	point(&screen, Pt(dx, dy), 1, f);
}


void g_box(int x, int y, int dx, int dy, int f);
void g_box(x, y, dx, dy, f) {
	x = (x + XLIM) / Fx + X0;
	y = (y + YLIM) / Fy + Y0;	
	dx = (dx + XLIM) / Fx + X0 + 1;
	dy = (dy + YLIM) / Fy + Y0 + 1;
	f = flags(f);
	texture(&screen, Rect(x, y, dx, dy), Set, f);	
}


voidg_clear(int m);
void g_clear(m) {
	g_box(-XLIM, -YLIM, XLIM, YLIM, m);
}


int g_reshaped(void);
int g_reshaped() {
	int	sc = Shape_changed;

	Shape_changed = 0;
	return(sc);
}


void g_sync(void);
void g_sync() {
	bflush();
}

#endif /* GRAPHICS_EXT */
