typedef	struct	Box Box;
typedef	struct	Cimage Cimage;
typedef	struct	Column Column;
typedef	struct	Exec Exec;
typedef	struct	Line Line;
typedef	struct	Page Page;
typedef	struct	Row Row;
typedef	struct	Runestr Runestr;
typedef	struct	Text	Text;
typedef	struct	Timer Timer;
typedef	struct	Url Url;
typedef	struct	Window Window;

struct Runestr
{
	Rune	*r;
	int	nr;
};

enum
{
	Rowtag,
	Columntag,
	Tag,
	Urltag,
	Statustag,
	Entry,
	Textarea,
};

struct Text
{
	union {
	struct {
		Font		*font;		/* of chars in the frame */
		Display		*display;	/* on which frame appears */
		Image		*b;		/* on which frame appears */
		Image		*cols[NCOL];	/* text and background colors */
		Rectangle	r;		/* in which text appears */
		Rectangle	entire;		/* of full frame */
		void			(*scroll)(Frame*, int);	/* scroll function provided by application */
		Frbox		*box;
		ulong		p0, p1;		/* selection */
		ushort		nbox, nalloc;
		ushort		maxtab;		/* max size of tab, in pixels */
		ushort		nchars;		/* # runes in frame */
		ushort		nlines;		/* # lines with text */
		ushort		maxlines;	/* total # lines in frame */
		ushort		lastlinefull;	/* last line fills frame */
		ushort		modified;	/* changed since frselect() */
		Image		*tick;	/* typing tick */
		Image		*tickback;	/* saved image under tick */
		int			ticked;	/* flag: is tick onscreen? */
		int			noredraw;	/* don't draw on the screen */
	};
	Frame Frame;
	};
	uint		org;
	uint		q0;
	uint		q1;
	int		what;
	Window	*w;
	Rectangle scrollr;
	Rectangle lastsr;
	Rectangle all;
	Row		*row;
	Column	*col;
	Runestr	rs;
};

uint		textbacknl(Text*, uint, uint);
int		textbswidth(Text*, Rune);
int		textclickmatch(Text*, int, int, int, uint*);
void		textclose(Text*);
void		textdelete(Text*, uint, uint);
void		textdoubleclick(Text*, uint*, uint*);
void		textfill(Text*);
void		textframescroll(Text*, int);
void		textinit(Text *, Image *, Rectangle, Font *, Image **);
void		textinsert(Text*, uint, Rune*, uint);
void		textredraw(Text *, Rectangle, Font *, Image *);
int		textresize(Text *, Image *, Rectangle);
void		textscrdraw(Text*);
void		textscroll(Text*, int);
void		textselect(Text*);
int		textselect2(Text *, uint *, uint *, Text **);
int		textselect3(Text *, uint *, uint *);
void		textset(Text *, Rune *, int);
void		textsetorigin(Text*, uint, int);
void		textsetselect(Text*, uint, uint);
void		textshow(Text*, uint, uint, int);
void		texttype(Text*, Rune);
void		textmouse(Text *, Point, int);

struct Line
{
	Rectangle	r;
	int		state;
	int		hastext;
	int		hastable;
	Box		*boxes;
	Box		*lastbox;
	Line		*prev;
	Line		*next;
};

struct Box
{
	Item 	*i;
	Rectangle	 r;

	void		(*draw)(Box *, Page *, Image *);
	void		(*mouse)(Box *, Page *, int);
	void		(*key)(Box *, Page *, Rune);
	Box		*prev;
	Box		*next;
};

Box*		boxalloc(Line *, Item *, Rectangle);
void		boxinit(Box *);

struct Lay
{
	Rectangle	r;
	int		width;
	int		xwall;
	Line		*lines;
	Line		*lastline;
	Font		*font;
	Ifloat	*floats;
	int		laying;
};

void		laypage(Page *p);
Lay*		layitems(Item *, Rectangle, int);
void		laydraw(Page *, Image *, Lay *);
void		layfree(Lay *);

struct Cimage
{
	Ref ref;
	Image	*i;
	Memimage *mi;
	Url		*url;
	Cimage	*next;
};

struct Url
{
	Ref ref;		/* urls in window.url[] are not freed */
	int		id;
	int		method;	/* HGet or HPost */
	Runestr	src;		/* requested url */
	Runestr	act;		/* actual url (redirection) */
	Runestr	post;		/* only set if method==HPost */
	Runestr	ctype;	/* content type */
};

Url*		urlalloc(Runestr *, Runestr *, int);
void		urlfree(Url *);
Url*		urldup(Url *);
int		urlopen(Url *);

struct Page
{
	Url		*url;
	Runestr	title;
	Window	*w;
	Image	*b;

	Rectangle	r;
	Rectangle all;
	Rectangle	vscrollr;
	Rectangle	hscrollr;
	Row		*row;
	Column	*col;

	Docinfo	*doc;
	Kidinfo	*kidinfo;
	Item		*items;
	Lay		*lay;
	Point		pos;

	int		selecting;
	Point		top, bot;
	Box		*topbx, *botbx;

	int		aborting;
	int		changed;
	int		loading;
	Rune		*status;

	Page		*parent;
	Page		*child;
	Page		*next;

	Cimage 	**cimage;
	int		ncimage;
};

void		pageget(Page *, Runestr *, Runestr *, int, int);
void		pageload(Page *, Url *, int);
void		pageclose(Page *);
void		pageredraw(Page *);
void		pagerender(Page *);
void		pagemouse(Page *, Point, int);
void		pagetype(Page *, Rune, Point);
void		pagescrldraw(Page *);
void		pagescroll(Page *, int, int);
int		pagescrollxy(Page *, int, int);
int		pageabort(Page *);
void		pagesnarf(Page *);
void		pagerefresh(Page *);

struct Window
{
		Ref ref;
		QLock lock;
	Text		tag;
	Text		url;
	Page		page;
	Text		status;
	int		owner;
	int		inpage;
	Rectangle	r;
	Column	*col;
	struct{
		Url	**url;
		int	nurl;
		int	cid;
	}history;
};

void		wininit(Window *, Window *, Rectangle);
int		winclean(Window *, int);
void		winclose(Window *);
int		winresize(Window *, Rectangle, int);
Text*	wintext(Window *, Point);
void		winlock(Window *, int);
void		winunlock(Window *);
void		winaddhist(Window *, Url *);
void		winsettag(Window *);
void		winseturl(Window *);
void		winsetstatus(Window *, Rune *);
Text*	wintype(Window *, Point, Rune);
Text*	winmouse(Window *, Point, int);
void		winmousebut(Window *w);
void		windebug(Window *w);

struct Column
{
	Rectangle r;
	Text	tag;
	Row		*row;
	Window	**w;
	int		nw;
	int		safe;
};

void		colinit(Column*, Rectangle);
Window*	coladd(Column*, Window*, Window*, int);
void		colclose(Column*, Window*, int);
void		colcloseall(Column*);
void		colresize(Column*, Rectangle);
Text*	colwhich(Column*, Point, Rune, int);
void		coldragwin(Column*, Window*, int);
void		colgrow(Column*, Window*, int);
int		colclean(Column*);
void		colsort(Column*);
void		colmousebut(Column*);

struct Row
{
	QLock lock;
	Rectangle r;
	Text	tag;
	Column	**col;
	int		ncol;

};

void		rowinit(Row*, Rectangle);
Column*	rowadd(Row*, Column *c, int);
void		rowclose(Row*, Column*, int);
Text*	rowwhich(Row*, Point, Rune, int);
Column*	rowwhichcol(Row*, Point);
void		rowresize(Row*, Rectangle);
void		rowdragcol(Row*, Column*, int but);

struct Exec
{
	char		*cmd;
	int		p[2];		/* p[1] is write to program; p[0] set to prog fd 0*/
	int		q[2];		/* q[0] is read from program; q[1] set to prog fd 1 */
	Channel	*sync;	/* chan(ulong) */
};

struct Timer
{
	int		dt;
	int		cancel;
	Channel	*c;		/* chan(int) */
	Timer	*next;
};

enum
{
	Scrollsize	=	12,
	Scrollgap	=	4,
	Margin =		4,
	Border =		2,
	Space  =		2,
	Tabspace =	30,
	Boxsize =		12,
	WFont =		FntR*NumSize+Tiny,

	Panspeed = 	4,
	Maxtab =		8,

	BUFSIZE =		1024*8,
	RBUFSIZE =	BUFSIZE/sizeof(Rune),
	STACK =		64*1024,
};

enum
{
	FALSE,
	TRUE,
	XXX,
};

enum
{
	Light = 0xEEEEEE,
	Dark = 0x666666,
	Red = 0xBB0000,
	Back = 0xCCCCCC,
};

Mouse		*mouse;
Mousectl		*mousectl;
Keyboardctl	*keyboardctl;
Image		*tagcols[NCOL];
Image		*textcols[NCOL];
Image		*but2col;
Image		*but3col;
Image		*button;
Image		*colbutton;
Font			*passfont;
Cursor		boxcursor;
Row			row;
Text			*argtext;
Text			*seltext;
Text			*typetext;
Page			*selpage;
Column		*activecol;
CFid			*plumbsendfid;
CFsys			*webfs;
CFid			*webctlfid;
char			*charset;
int			procstderr;

enum
{
	Kscrolloneup		= KF|0x20,
	Kscrollonedown	= KF|0x21,
};

Channel		*cplumb;		/* chan(Plumbmsg*) */
Channel		*cexit;		/* chan(int) */
Channel		*crefresh;		/* chan(page *) */
