vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

term.c (6724B)


      1 /*
      2  * Draw and manage a text terminal on the screen,
      3  * before the window manager has taken over.
      4  */
      5 #include	"u.h"
      6 #include	"lib.h"
      7 #include	"mem.h"
      8 #include	"dat.h"
      9 #include	"fns.h"
     10 #include	"error.h"
     11 
     12 #define Image IMAGE
     13 #include	<draw.h>
     14 #include	<memdraw.h>
     15 #include	<cursor.h>
     16 #include	"screen.h"
     17 
     18 enum
     19 {
     20 	Border = 4
     21 };
     22 
     23 static struct {
     24 	Lock	lk;
     25 	int printing;
     26 	Memsubfont *font;
     27 	int tabx;	/* width of tab */
     28 	int spacex;	/* width of space */
     29 	int xpos;
     30 	Memimage *fg;	/* text color */
     31 	Memimage *bg;	/* background color */
     32 	Memimage *screen;	/* screen image - can change! */
     33 	Memimage *grey;
     34 	Rectangle flushr;	/* rectangle needs flushing */
     35 	Rectangle text;	/* rectangle holding text */
     36 	Rectangle maxtext;	/* total space for text */
     37 	Rectangle line;	/* remainder of current output line */
     38 } term;
     39 
     40 static void termputs(char*, int);
     41 static void showkmesg(void);
     42 static void kickscreen(void);
     43 
     44 void
     45 terminit(int printing)
     46 {
     47 	Memimage *grey;
     48 
     49 	lock(&term.lk);
     50 	_memimageinit();
     51 	term.printing = printing;
     52 	term.font = getmemdefont();
     53 	term.fg = memblack;
     54 	term.bg = memwhite;
     55 	
     56 	term.spacex = memsubfontwidth(term.font, " ").x;
     57 	term.tabx = term.spacex * 8;
     58 
     59 	/* a lot of work to get a grey color */
     60 	grey = allocmemimage(Rect(0,0,1,1), CMAP8);
     61 	grey->flags |= Frepl;
     62 	grey->clipr = Rect(-100000, -100000, 100000, 100000);
     63 	memfillcolor(grey, 0x770000FF);
     64 	term.grey = grey;
     65 
     66 	term.flushr = Rect(0, 0, 0, 0);
     67 	/* x11 will call termreplacescreenimage when it is ready */
     68 	unlock(&term.lk);
     69 	
     70 	/* maybe it already has */
     71 	if(term.screen)
     72 		termreplacescreenimage(term.screen);
     73 
     74 	/* If we're the output mechanism, set it up and kick off the screen. */
     75 	if(printing)
     76 		screenputs = termputs;
     77 	if(conf.monitor)
     78 		kickscreen();	/* make x11 ready */
     79 }
     80 
     81 static void
     82 addflush(Rectangle r)
     83 {
     84 	if(term.flushr.min.x >= term.flushr.max.x)
     85 		term.flushr = r;
     86 	else
     87 		combinerect(&term.flushr, r);
     88 }
     89 
     90 static void
     91 termcursor(int on)
     92 {
     93 	Rectangle r;
     94 
     95 	if(!term.printing)
     96 		return;
     97 	r = term.line;
     98 	r.max.x = r.min.x+2;
     99 	if(on)
    100 		memimagedraw(term.screen, r, term.grey, ZP, memopaque, ZP, S);
    101 	else
    102 		memimagedraw(term.screen, r, term.bg, ZP, memopaque, ZP, S);
    103 	addflush(r);
    104 }
    105 
    106 static void
    107 _termreplacescreenimage(Memimage *m)
    108 {
    109 	int h;
    110 	Rectangle r, r0;
    111 
    112 	if(term.bg == nil){
    113 		/* not yet init */
    114 		term.screen = m;
    115 		return;
    116 	}
    117 
    118 	/* white background */
    119 	if(!mouse.open)
    120 		memimagedraw(m, m->r, term.bg, ZP, memopaque, ZP, S);
    121 	
    122 	/* grey heading: Plan 9 VX */
    123 	r = m->r;
    124 	h = term.font->height;
    125 	r.max.y = r.min.y + Border + h + Border;
    126 	if(!mouse.open){
    127 		memimagedraw(m, r, term.grey, ZP, memopaque, ZP, S);
    128 		memimagestring(m, addpt(r.min, Pt(Border, Border)),
    129 			memwhite, ZP, term.font, "Plan 9 VX");
    130 	}
    131 	r.min.y = r.max.y;
    132 	r.max.y += 2;
    133 	if(!mouse.open){
    134 		memimagedraw(m, r, memblack, ZP, memopaque, ZP, S);
    135 	}
    136 
    137 	/* text area */
    138 	r.min.x += Border;
    139 	r.max.x -= Border;
    140 	r.min.y = r.max.y;
    141 	r.max.y = m->r.max.y;
    142 	r.max.y = r.min.y + Dy(r)/h*h;
    143 	term.maxtext = r;
    144 
    145 	/* occupied text area - just one blank line */
    146 	r0 = r;
    147 	r0.max.y = r0.min.y + h;
    148 	term.text = r0;
    149 	term.line = r0;
    150 
    151 	/* ready to commit */
    152 	term.screen = m;
    153 	if(!mouse.open){
    154 		showkmesg();
    155 		termcursor(1);
    156 		flushmemscreen(m->r);
    157 	}
    158 }
    159 
    160 void
    161 termreplacescreenimage(Memimage *m)
    162 {
    163 	if(up){
    164 		drawqlock();
    165 		lock(&term.lk);
    166 		_termreplacescreenimage(m);
    167 		unlock(&term.lk);
    168 		drawqunlock();
    169 		return;
    170 	}
    171 	lock(&term.lk);
    172 	_termreplacescreenimage(m);
    173 	unlock(&term.lk);
    174 }
    175 
    176 void
    177 termredraw(void)
    178 {
    179 	Memimage *m;
    180 
    181 	if(!term.screen)
    182 		return;
    183 
    184 	drawqlock();
    185 	lock(&term.lk);
    186 	m = term.screen;
    187 	term.screen = nil;
    188 	if(m)
    189 		_termreplacescreenimage(m);
    190 	unlock(&term.lk);
    191 	drawqunlock();
    192 }
    193 
    194 static void
    195 termscroll(void)
    196 {
    197 	Rectangle r0, r1;
    198 	int dy, h;
    199 	
    200 	dy = Dy(term.maxtext) / 2;
    201 	h = term.font->height;
    202 	dy = dy/h*h;
    203 	if(dy < term.font->height)
    204 		dy = term.font->height;
    205 	r0 = term.text;
    206 	r1 = term.text;
    207 	r0.max.y -= dy;
    208 	r1.min.y += dy;
    209 	memimagedraw(term.screen, r0, term.screen, r1.min,
    210 		memopaque, ZP, S);
    211 	r1.min.y = r0.max.y;
    212 	memimagedraw(term.screen, r1, term.bg, ZP, memopaque, ZP, S);
    213 	addflush(r0);
    214 	addflush(r1);
    215 	term.text = r0;
    216 }
    217 
    218 static void
    219 termputc(Rune r)
    220 {
    221 	int dx, n;
    222 	Rectangle rect;
    223 	char buf[UTFmax+1];
    224 	Memsubfont *font;
    225 	
    226 	font = term.font;
    227 
    228 	switch(r){
    229 	case '\n':
    230 		if(term.text.max.y >= term.maxtext.max.y)
    231 			termscroll();
    232 		term.text.max.y += font->height;
    233 		/* fall through */
    234 	case '\r':
    235 		term.line = term.text;
    236 		term.line.min.y = term.line.max.y - font->height;
    237 		break;
    238 	case '\t':
    239 		dx = term.tabx - (term.line.min.x - term.text.min.x) % term.tabx;
    240 		if(term.line.min.x+dx >= term.line.max.x)
    241 			termputc('\n');
    242 		else{
    243 			/* white out the space, just because */
    244 			rect = term.line;
    245 			rect.max.x = rect.min.x + dx;
    246 			memimagedraw(term.screen, rect, term.bg, ZP, memopaque, ZP, S);
    247 			term.line.min.x += dx;
    248 			addflush(rect);
    249 		}
    250 		break;
    251 	case '\b':
    252 		if(term.line.min.x <= term.text.min.x)
    253 			break;
    254 		/* white out the backspaced letter */
    255 		term.line.min.x -= term.spacex;
    256 		rect = term.line;
    257 		rect.max.x = rect.min.x + term.spacex;
    258 		memimagedraw(term.screen, rect, term.bg, ZP, memopaque, ZP, S);
    259 		addflush(rect);
    260 		break;
    261 	default:
    262 		n = runetochar(buf, &r);
    263 		buf[n] = 0;
    264 		dx = memsubfontwidth(term.font, buf).x;
    265 		if(term.line.min.x+dx > term.line.max.x)
    266 			termputc('\n');
    267 		rect = term.line;
    268 		term.line.min.x += dx;
    269 		rect.max.x = term.line.min.x;
    270 		memimagedraw(term.screen, rect, term.bg, ZP, memopaque, ZP, S);
    271 		memimagestring(term.screen, rect.min, term.fg, ZP, term.font, buf);
    272 		addflush(rect);
    273 		break;
    274 	}
    275 }
    276 
    277 static void
    278 _termputs(char *s, int n)
    279 {
    280 	int i, locked;
    281 	Rune r;
    282 	int nb;
    283 	char *p, *ep;
    284 
    285 	if(term.screen == nil || !term.printing)
    286 		return;
    287 	locked = 0;
    288 	for(i=0; i<100; i++){
    289 		locked = drawcanqlock();
    290 		if(locked)
    291 			break;
    292 		microdelay(100);
    293 	}
    294 	if(!mouse.open)
    295 		termcursor(0);
    296 	for(p=s, ep=s+n; p<ep; p+=nb){
    297 		nb = chartorune(&r, p);
    298 		if(nb <= 0){
    299 			nb = 1;
    300 			continue;
    301 		}
    302 		termputc(r);
    303 	}
    304 	if(!mouse.open)
    305 		termcursor(1);
    306 	flushmemscreen(term.flushr);
    307 	term.flushr = Rect(10000, 10000, -10000, -10000);
    308 	if(locked)
    309 		drawqunlock();
    310 }
    311 
    312 static void
    313 termputs(char *s, int n)
    314 {
    315 	lock(&term.lk);
    316 	_termputs(s, n);
    317 	unlock(&term.lk);
    318 }	
    319 
    320 static void
    321 showkmesg(void)
    322 {
    323 	int n, nb;
    324 	char buf[512], *p, *ep;
    325 	Rune r;
    326 
    327 	n = tailkmesg(buf, sizeof buf);
    328 	if(n > 0){
    329 		if(n < sizeof buf || (p = memchr(buf, '\n', n)) == nil)
    330 			p = buf;
    331 		/* can't call termputs - drawqlock is held */
    332 		for(ep=p+n; p<ep; p+=nb){
    333 			nb = chartorune(&r, p);
    334 			if(nb <= 0){
    335 				nb = 1;
    336 				continue;
    337 			}
    338 			termputc(r);
    339 		}
    340 	}
    341 }
    342 
    343 static void
    344 kickscreen(void)
    345 {
    346 	Rectangle r;
    347 	ulong chan;
    348 	int depth;
    349 	int width;
    350 	int softscreen;
    351 	void *x;
    352 	
    353 	attachscreen(&r, &chan, &depth, &width, &softscreen, &x);
    354 }
    355 
    356