tinit.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tinit.c (9140B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <draw.h> | |
4 #include <mouse.h> | |
5 | |
6 Display *display; | |
7 Font *font; | |
8 Image *screen; | |
9 int _drawdebug; | |
10 | |
11 Screen *_screen; | |
12 | |
13 int debuglockdisplay = 1; | |
14 char *winsize; | |
15 | |
16 int visibleclicks = 0; | |
17 Image *mousebuttons; | |
18 Image *mousesave; | |
19 Mouse _drawmouse; | |
20 | |
21 void | |
22 needdisplay(void) | |
23 { | |
24 } | |
25 | |
26 /* | |
27 static void | |
28 drawshutdown(void) | |
29 { | |
30 Display *d; | |
31 | |
32 d = display; | |
33 if(d){ | |
34 display = nil; | |
35 closedisplay(d); | |
36 } | |
37 } | |
38 */ | |
39 | |
40 int | |
41 geninitdraw(char *devdir, void(*error)(Display*, char*), char *fontname,… | |
42 { | |
43 char *p; | |
44 | |
45 if(label == nil) | |
46 label = argv0; | |
47 display = _initdisplay(error, label); | |
48 if(display == nil) | |
49 return -1; | |
50 | |
51 /* | |
52 * Set up default font | |
53 */ | |
54 if(openfont(display, "*default*") == 0) { | |
55 fprint(2, "imageinit: can't open default subfont: %r\n"); | |
56 Error: | |
57 closedisplay(display); | |
58 display = nil; | |
59 return -1; | |
60 } | |
61 if(fontname == nil) | |
62 fontname = getenv("font"); | |
63 | |
64 /* | |
65 * Build fonts with caches==depth of screen, for speed. | |
66 * If conversion were faster, we'd use 0 and save memory. | |
67 */ | |
68 if(fontname == nil) | |
69 fontname = strdup("*default*"); | |
70 | |
71 font = openfont(display, fontname); | |
72 if(font == nil){ | |
73 fprint(2, "imageinit: can't open font %s: %r\n", fontnam… | |
74 goto Error; | |
75 } | |
76 display->defaultfont = font; | |
77 | |
78 _screen = allocscreen(display->image, display->white, 0); | |
79 display->screenimage = display->image; /* _allocwindow wa… | |
80 screen = _allocwindow(nil, _screen, display->image->r, Refnone, … | |
81 if(screen == nil){ | |
82 fprint(2, "_allocwindow: %r\n"); | |
83 goto Error; | |
84 } | |
85 display->screenimage = screen; | |
86 draw(screen, screen->r, display->white, nil, ZP); | |
87 flushimage(display, 1); | |
88 | |
89 p = getenv("visibleclicks"); | |
90 visibleclicks = p != nil && *p == '1'; | |
91 if(visibleclicks) { | |
92 Font *f; | |
93 | |
94 f = display->defaultfont; | |
95 mousebuttons = allocimage(display, Rect(0,0,64,22), scre… | |
96 border(mousebuttons, mousebuttons->r, 1, display->black,… | |
97 border(mousebuttons, Rect(0, 0, 22, 22), 1, display->bla… | |
98 border(mousebuttons, Rect(42, 0, 64, 22), 1, display->bl… | |
99 string(mousebuttons, Pt(10-stringwidth(display->defaultf… | |
100 string(mousebuttons, Pt(21+10-stringwidth(display->defau… | |
101 string(mousebuttons, Pt(42+10-stringwidth(display->defau… | |
102 mousesave = allocimage(display, Rect(0,0,64,22), screen-… | |
103 } | |
104 | |
105 /* | |
106 * I don't see any reason to go away gracefully, | |
107 * and if some other proc exits holding the display | |
108 * lock, this atexit call never finishes. | |
109 * | |
110 * atexit(drawshutdown); | |
111 */ | |
112 return 1; | |
113 } | |
114 | |
115 int | |
116 initdraw(void (*error)(Display*, char*), char *fontname, char *label) | |
117 { | |
118 return geninitdraw("/dev", error, fontname, label, "/dev", Refno… | |
119 } | |
120 | |
121 extern int _freeimage1(Image*); | |
122 | |
123 static Image* | |
124 getimage0(Display *d, Image *image) | |
125 { | |
126 char info[12*12+1]; | |
127 uchar *a; | |
128 int n; | |
129 | |
130 /* | |
131 * If there's an old screen, it has id 0. The 'J' request below | |
132 * will try to install the new screen as id 0, so the old one | |
133 * must be freed first. | |
134 */ | |
135 if(image){ | |
136 _freeimage1(image); | |
137 memset(image, 0, sizeof(Image)); | |
138 } | |
139 | |
140 a = bufimage(d, 2); | |
141 a[0] = 'J'; | |
142 a[1] = 'I'; | |
143 if(flushimage(d, 0) < 0){ | |
144 fprint(2, "cannot read screen info: %r\n"); | |
145 return nil; | |
146 } | |
147 | |
148 n = _displayrddraw(d, info, sizeof info); | |
149 if(n != 12*12){ | |
150 fprint(2, "short screen info\n"); | |
151 return nil; | |
152 } | |
153 | |
154 if(image == nil){ | |
155 image = mallocz(sizeof(Image), 1); | |
156 if(image == nil){ | |
157 fprint(2, "cannot allocate image: %r\n"); | |
158 return nil; | |
159 } | |
160 } | |
161 | |
162 image->display = d; | |
163 image->id = 0; | |
164 image->chan = strtochan(info+2*12); | |
165 image->depth = chantodepth(image->chan); | |
166 image->repl = atoi(info+3*12); | |
167 image->r.min.x = atoi(info+4*12); | |
168 image->r.min.y = atoi(info+5*12); | |
169 image->r.max.x = atoi(info+6*12); | |
170 image->r.max.y = atoi(info+7*12); | |
171 image->clipr.min.x = atoi(info+8*12); | |
172 image->clipr.min.y = atoi(info+9*12); | |
173 image->clipr.max.x = atoi(info+10*12); | |
174 image->clipr.max.y = atoi(info+11*12); | |
175 | |
176 a = bufimage(d, 3); | |
177 a[0] = 'q'; | |
178 a[1] = 1; | |
179 a[2] = 'd'; | |
180 d->dpi = 100; | |
181 if(flushimage(d, 0) >= 0 && _displayrddraw(d, info, 12) == 12) | |
182 d->dpi = atoi(info); | |
183 | |
184 return image; | |
185 } | |
186 | |
187 /* | |
188 * Attach, or possibly reattach, to window. | |
189 * If reattaching, maintain value of screen pointer. | |
190 */ | |
191 int | |
192 getwindow(Display *d, int ref) | |
193 { | |
194 Image *i, *oi; | |
195 Font *f; | |
196 | |
197 /* XXX check for destroyed? */ | |
198 | |
199 /* | |
200 * Libdraw promises not to change the value of "screen", | |
201 * so we have to reuse the image structure | |
202 * memory we already have. | |
203 */ | |
204 oi = d->image; | |
205 i = getimage0(d, oi); | |
206 if(i == nil) | |
207 sysfatal("getwindow failed"); | |
208 d->image = i; | |
209 /* fprint(2, "getwindow %p -> %p\n", oi, i); */ | |
210 | |
211 freescreen(_screen); | |
212 _screen = allocscreen(i, d->white, 0); | |
213 _freeimage1(screen); | |
214 screen = _allocwindow(screen, _screen, i->r, ref, DWhite); | |
215 d->screenimage = screen; | |
216 | |
217 | |
218 if(d->dpi >= DefaultDPI*3/2) { | |
219 for(f=d->firstfont; f != nil; f=f->next) | |
220 loadhidpi(f); | |
221 } else { | |
222 for(f=d->firstfont; f != nil; f=f->next) | |
223 if(f->lodpi != nil && f->lodpi != f) | |
224 swapfont(f, &f->hidpi, &f->lodpi); | |
225 } | |
226 | |
227 return 0; | |
228 } | |
229 | |
230 Display* | |
231 _initdisplay(void (*error)(Display*, char*), char *label) | |
232 { | |
233 Display *disp; | |
234 Image *image; | |
235 | |
236 fmtinstall('P', Pfmt); | |
237 fmtinstall('R', Rfmt); | |
238 | |
239 disp = mallocz(sizeof(Display), 1); | |
240 if(disp == nil){ | |
241 Error1: | |
242 return nil; | |
243 } | |
244 disp->srvfd = -1; | |
245 image = nil; | |
246 if(0){ | |
247 Error2: | |
248 free(image); | |
249 free(disp); | |
250 goto Error1; | |
251 } | |
252 disp->bufsize = 65500; | |
253 disp->buf = malloc(disp->bufsize+5); /* +5 for flush mess… | |
254 disp->bufp = disp->buf; | |
255 disp->error = error; | |
256 qlock(&disp->qlock); | |
257 | |
258 if(disp->buf == nil) | |
259 goto Error2; | |
260 if(0){ | |
261 Error3: | |
262 free(disp->buf); | |
263 goto Error2; | |
264 } | |
265 | |
266 if(_displaymux(disp) < 0 | |
267 || _displayconnect(disp) < 0 | |
268 || _displayinit(disp, label, winsize) < 0) | |
269 goto Error3; | |
270 if(0){ | |
271 Error4: | |
272 close(disp->srvfd); | |
273 goto Error3; | |
274 } | |
275 | |
276 image = getimage0(disp, nil); | |
277 if(image == nil) | |
278 goto Error4; | |
279 | |
280 disp->image = image; | |
281 disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhit… | |
282 disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlac… | |
283 if(disp->white == nil || disp->black == nil){ | |
284 free(disp->white); | |
285 free(disp->black); | |
286 goto Error4; | |
287 } | |
288 | |
289 disp->opaque = disp->white; | |
290 disp->transparent = disp->black; | |
291 | |
292 return disp; | |
293 } | |
294 | |
295 /* | |
296 * Call with d unlocked. | |
297 * Note that disp->defaultfont is not freed here. | |
298 */ | |
299 void | |
300 closedisplay(Display *disp) | |
301 { | |
302 int fd; | |
303 char buf[128]; | |
304 | |
305 if(disp == nil) | |
306 return; | |
307 if(disp == display) | |
308 display = nil; | |
309 if(disp->oldlabel[0]){ | |
310 snprint(buf, sizeof buf, "%s/label", disp->windir); | |
311 fd = open(buf, OWRITE); | |
312 if(fd >= 0){ | |
313 write(fd, disp->oldlabel, strlen(disp->oldlabel)… | |
314 close(fd); | |
315 } | |
316 } | |
317 | |
318 free(disp->devdir); | |
319 free(disp->windir); | |
320 if(disp->white) | |
321 freeimage(disp->white); | |
322 if(disp->black) | |
323 freeimage(disp->black); | |
324 if(disp->srvfd >= 0) | |
325 close(disp->srvfd); | |
326 free(disp); | |
327 } | |
328 | |
329 void | |
330 lockdisplay(Display *disp) | |
331 { | |
332 if(debuglockdisplay){ | |
333 /* avoid busy looping; it's rare we collide anyway */ | |
334 while(!canqlock(&disp->qlock)){ | |
335 fprint(1, "proc %d waiting for display lock...\n… | |
336 sleep(1000); | |
337 } | |
338 }else | |
339 qlock(&disp->qlock); | |
340 } | |
341 | |
342 void | |
343 unlockdisplay(Display *disp) | |
344 { | |
345 qunlock(&disp->qlock); | |
346 } | |
347 | |
348 void | |
349 drawerror(Display *d, char *s) | |
350 { | |
351 char err[ERRMAX]; | |
352 | |
353 if(d->error) | |
354 d->error(d, s); | |
355 else{ | |
356 errstr(err, sizeof err); | |
357 fprint(2, "draw: %s: %s\n", s, err); | |
358 exits(s); | |
359 } | |
360 } | |
361 | |
362 static | |
363 int | |
364 doflush(Display *d) | |
365 { | |
366 int n; | |
367 | |
368 n = d->bufp-d->buf; | |
369 if(n <= 0) | |
370 return 1; | |
371 | |
372 if(_displaywrdraw(d, d->buf, n) != n){ | |
373 if(_drawdebug) | |
374 fprint(2, "flushimage fail: d=%p: %r\n", d); /**/ | |
375 d->bufp = d->buf; /* might as well; chance of con… | |
376 return -1; | |
377 } | |
378 d->bufp = d->buf; | |
379 return 1; | |
380 } | |
381 | |
382 int | |
383 flushimage(Display *d, int visible) | |
384 { | |
385 if(visible == 1 && visibleclicks && mousebuttons && _drawmouse.b… | |
386 Rectangle r, r1; | |
387 int ret; | |
388 | |
389 r = mousebuttons->r; | |
390 r = rectaddpt(r, _drawmouse.xy); | |
391 r = rectaddpt(r, Pt(-Dx(mousebuttons->r)/2, -Dy(mousebut… | |
392 drawop(mousesave, mousesave->r, screen, nil, r.min, S); | |
393 | |
394 r1 = rectaddpt(Rect(0, 0, 22, 22), r.min); | |
395 if(_drawmouse.buttons & 1) | |
396 drawop(screen, r1, mousebuttons, nil, ZP, S); | |
397 r1 = rectaddpt(r1, Pt(21, 0)); | |
398 if(_drawmouse.buttons & 2) | |
399 drawop(screen, r1, mousebuttons, nil, Pt(21, 0),… | |
400 r1 = rectaddpt(r1, Pt(21, 0)); | |
401 if(_drawmouse.buttons & 4) | |
402 drawop(screen, r1, mousebuttons, nil, Pt(42, 0),… | |
403 ret = flushimage(d, 2); | |
404 drawop(screen, r, mousesave, nil, ZP, S); | |
405 return ret; | |
406 } | |
407 | |
408 if(visible){ | |
409 *d->bufp++ = 'v'; /* five bytes always reserved f… | |
410 if(d->_isnewdisplay){ | |
411 BPLONG(d->bufp, d->screenimage->id); | |
412 d->bufp += 4; | |
413 } | |
414 } | |
415 return doflush(d); | |
416 } | |
417 | |
418 uchar* | |
419 bufimage(Display *d, int n) | |
420 { | |
421 uchar *p; | |
422 | |
423 if(n<0 || d == nil || n>d->bufsize){ | |
424 abort(); | |
425 werrstr("bad count in bufimage"); | |
426 return 0; | |
427 } | |
428 if(d->bufp+n > d->buf+d->bufsize) | |
429 if(doflush(d) < 0) | |
430 return 0; | |
431 p = d->bufp; | |
432 d->bufp += n; | |
433 return p; | |
434 } | |
435 | |
436 int | |
437 scalesize(Display *d, int n) | |
438 { | |
439 if(d == nil || d->dpi <= DefaultDPI) | |
440 return n; | |
441 return (n*d->dpi+DefaultDPI/2)/DefaultDPI; | |
442 } |