Blob


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