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