term.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) 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