356 lines · 6.6 KB · C
RawDownload
/* * Draw and manage a text terminal on the screen, * before the window manager has taken over. */#include	"u.h"#include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h" #define Image IMAGE#include	<draw.h>#include	<memdraw.h>#include	<cursor.h>#include	"screen.h" enum{	Border = 4}; static struct {	Lock	lk;	int printing;	Memsubfont *font;	int tabx;	/* width of tab */	int spacex;	/* width of space */	int xpos;	Memimage *fg;	/* text color */	Memimage *bg;	/* background color */	Memimage *screen;	/* screen image - can change! */	Memimage *grey;	Rectangle flushr;	/* rectangle needs flushing */	Rectangle text;	/* rectangle holding text */	Rectangle maxtext;	/* total space for text */	Rectangle line;	/* remainder of current output line */} term; static void termputs(char*, int);static void showkmesg(void);static void kickscreen(void); voidterminit(int printing){	Memimage *grey; 	lock(&term.lk);	_memimageinit();	term.printing = printing;	term.font = getmemdefont();	term.fg = memblack;	term.bg = memwhite;		term.spacex = memsubfontwidth(term.font, " ").x;	term.tabx = term.spacex * 8; 	/* a lot of work to get a grey color */	grey = allocmemimage(Rect(0,0,1,1), CMAP8);	grey->flags |= Frepl;	grey->clipr = Rect(-100000, -100000, 100000, 100000);	memfillcolor(grey, 0x770000FF);	term.grey = grey; 	term.flushr = Rect(0, 0, 0, 0);	/* x11 will call termreplacescreenimage when it is ready */	unlock(&term.lk);		/* maybe it already has */	if(term.screen)		termreplacescreenimage(term.screen); 	/* If we're the output mechanism, set it up and kick off the screen. */	if(printing)		screenputs = termputs;	if(conf.monitor)		kickscreen();	/* make x11 ready */} static voidaddflush(Rectangle r){	if(term.flushr.min.x >= term.flushr.max.x)		term.flushr = r;	else		combinerect(&term.flushr, r);} static voidtermcursor(int on){	Rectangle r; 	if(!term.printing)		return;	r = term.line;	r.max.x = r.min.x+2;	if(on)		memimagedraw(term.screen, r, term.grey, ZP, memopaque, ZP, S);	else		memimagedraw(term.screen, r, term.bg, ZP, memopaque, ZP, S);	addflush(r);} static void_termreplacescreenimage(Memimage *m){	int h;	Rectangle r, r0; 	if(term.bg == nil){		/* not yet init */		term.screen = m;		return;	} 	/* white background */	if(!mouse.open)		memimagedraw(m, m->r, term.bg, ZP, memopaque, ZP, S);		/* grey heading: Plan 9 VX */	r = m->r;	h = term.font->height;	r.max.y = r.min.y + Border + h + Border;	if(!mouse.open){		memimagedraw(m, r, term.grey, ZP, memopaque, ZP, S);		memimagestring(m, addpt(r.min, Pt(Border, Border)),			memwhite, ZP, term.font, "Plan 9 VX");	}	r.min.y = r.max.y;	r.max.y += 2;	if(!mouse.open){		memimagedraw(m, r, memblack, ZP, memopaque, ZP, S);	} 	/* text area */	r.min.x += Border;	r.max.x -= Border;	r.min.y = r.max.y;	r.max.y = m->r.max.y;	r.max.y = r.min.y + Dy(r)/h*h;	term.maxtext = r; 	/* occupied text area - just one blank line */	r0 = r;	r0.max.y = r0.min.y + h;	term.text = r0;	term.line = r0; 	/* ready to commit */	term.screen = m;	if(!mouse.open){		showkmesg();		termcursor(1);		flushmemscreen(m->r);	}} voidtermreplacescreenimage(Memimage *m){	if(up){		drawqlock();		lock(&term.lk);		_termreplacescreenimage(m);		unlock(&term.lk);		drawqunlock();		return;	}	lock(&term.lk);	_termreplacescreenimage(m);	unlock(&term.lk);} voidtermredraw(void){	Memimage *m; 	if(!term.screen)		return; 	drawqlock();	lock(&term.lk);	m = term.screen;	term.screen = nil;	if(m)		_termreplacescreenimage(m);	unlock(&term.lk);	drawqunlock();} static voidtermscroll(void){	Rectangle r0, r1;	int dy, h;		dy = Dy(term.maxtext) / 2;	h = term.font->height;	dy = dy/h*h;	if(dy < term.font->height)		dy = term.font->height;	r0 = term.text;	r1 = term.text;	r0.max.y -= dy;	r1.min.y += dy;	memimagedraw(term.screen, r0, term.screen, r1.min,		memopaque, ZP, S);	r1.min.y = r0.max.y;	memimagedraw(term.screen, r1, term.bg, ZP, memopaque, ZP, S);	addflush(r0);	addflush(r1);	term.text = r0;} static voidtermputc(Rune r){	int dx, n;	Rectangle rect;	char buf[UTFmax+1];	Memsubfont *font;		font = term.font; 	switch(r){	case '\n':		if(term.text.max.y >= term.maxtext.max.y)			termscroll();		term.text.max.y += font->height;		/* fall through */	case '\r':		term.line = term.text;		term.line.min.y = term.line.max.y - font->height;		break;	case '\t':		dx = term.tabx - (term.line.min.x - term.text.min.x) % term.tabx;		if(term.line.min.x+dx >= term.line.max.x)			termputc('\n');		else{			/* white out the space, just because */			rect = term.line;			rect.max.x = rect.min.x + dx;			memimagedraw(term.screen, rect, term.bg, ZP, memopaque, ZP, S);			term.line.min.x += dx;			addflush(rect);		}		break;	case '\b':		if(term.line.min.x <= term.text.min.x)			break;		/* white out the backspaced letter */		term.line.min.x -= term.spacex;		rect = term.line;		rect.max.x = rect.min.x + term.spacex;		memimagedraw(term.screen, rect, term.bg, ZP, memopaque, ZP, S);		addflush(rect);		break;	default:		n = runetochar(buf, &r);		buf[n] = 0;		dx = memsubfontwidth(term.font, buf).x;		if(term.line.min.x+dx > term.line.max.x)			termputc('\n');		rect = term.line;		term.line.min.x += dx;		rect.max.x = term.line.min.x;		memimagedraw(term.screen, rect, term.bg, ZP, memopaque, ZP, S);		memimagestring(term.screen, rect.min, term.fg, ZP, term.font, buf);		addflush(rect);		break;	}} static void_termputs(char *s, int n){	int i, locked;	Rune r;	int nb;	char *p, *ep; 	if(term.screen == nil || !term.printing)		return;	locked = 0;	for(i=0; i<100; i++){		locked = drawcanqlock();		if(locked)			break;		microdelay(100);	}	if(!mouse.open)		termcursor(0);	for(p=s, ep=s+n; p<ep; p+=nb){		nb = chartorune(&r, p);		if(nb <= 0){			nb = 1;			continue;		}		termputc(r);	}	if(!mouse.open)		termcursor(1);	flushmemscreen(term.flushr);	term.flushr = Rect(10000, 10000, -10000, -10000);	if(locked)		drawqunlock();} static voidtermputs(char *s, int n){	lock(&term.lk);	_termputs(s, n);	unlock(&term.lk);}	 static voidshowkmesg(void){	int n, nb;	char buf[512], *p, *ep;	Rune r; 	n = tailkmesg(buf, sizeof buf);	if(n > 0){		if(n < sizeof buf || (p = memchr(buf, '\n', n)) == nil)			p = buf;		/* can't call termputs - drawqlock is held */		for(ep=p+n; p<ep; p+=nb){			nb = chartorune(&r, p);			if(nb <= 0){				nb = 1;				continue;			}			termputc(r);		}	}} static voidkickscreen(void){	Rectangle r;	ulong chan;	int depth;	int width;	int softscreen;	void *x;		attachscreen(&r, &chan, &depth, &width, &softscreen, &x);}