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 /*
23 static void
24 drawshutdown(void)
25 {
26 Display *d;
28 d = display;
29 if(d){
30 display = nil;
31 closedisplay(d);
32 }
33 }
34 */
36 int
37 geninitdraw(char *devdir, void(*error)(Display*, char*), char *fontname, char *label, char *windir, int ref)
38 {
39 Subfont *df;
40 char buf[128], *p;
42 if(label == nil)
43 label = argv0;
44 display = _initdisplay(error, label);
45 if(display == nil)
46 return -1;
48 /*
49 * Set up default font
50 */
51 df = getdefont(display);
52 display->defaultsubfont = df;
53 if(df == nil){
54 fprint(2, "imageinit: can't open default subfont: %r\n");
55 Error:
56 closedisplay(display);
57 display = nil;
58 return -1;
59 }
60 if(fontname == nil)
61 fontname = getenv("font");
63 /*
64 * Build fonts with caches==depth of screen, for speed.
65 * If conversion were faster, we'd use 0 and save memory.
66 */
67 if(fontname == nil){
68 snprint(buf, sizeof buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,
69 df->n-1, deffontname);
70 //BUG: Need something better for this installsubfont("*default*", df);
71 font = buildfont(display, buf, deffontname);
72 if(font == nil){
73 fprint(2, "imageinit: can't open default font: %r\n");
74 goto Error;
75 }
76 }else{
77 font = openfont(display, fontname); /* BUG: grey fonts */
78 if(font == nil){
79 fprint(2, "imageinit: can't open font %s: %r\n", fontname);
80 goto Error;
81 }
82 }
83 display->defaultfont = font;
85 _screen = allocscreen(display->image, display->white, 0);
86 display->screenimage = display->image; /* _allocwindow wants screenimage->chan */
87 screen = _allocwindow(nil, _screen, display->image->r, Refnone, DWhite);
88 if(screen == nil){
89 fprint(2, "_allocwindow: %r\n");
90 goto Error;
91 }
92 display->screenimage = screen;
93 draw(screen, screen->r, display->white, nil, ZP);
94 flushimage(display, 1);
96 p = getenv("visibleclicks");
97 visibleclicks = p != nil && *p == '1';
98 if(visibleclicks) {
99 Font *f;
101 f = display->defaultfont;
102 mousebuttons = allocimage(display, Rect(0,0,64,22), screen->chan, 0, DWhite);
103 border(mousebuttons, mousebuttons->r, 1, display->black, ZP);
104 border(mousebuttons, Rect(0, 0, 22, 22), 1, display->black, ZP);
105 border(mousebuttons, Rect(42, 0, 64, 22), 1, display->black, ZP);
106 string(mousebuttons, Pt(10-stringwidth(display->defaultfont, "1")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "1");
107 string(mousebuttons, Pt(21+10-stringwidth(display->defaultfont, "2")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "2");
108 string(mousebuttons, Pt(42+10-stringwidth(display->defaultfont, "3")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "3");
109 mousesave = allocimage(display, Rect(0,0,64,22), screen->chan, 0, 0);
112 /*
113 * I don't see any reason to go away gracefully,
114 * and if some other proc exits holding the display
115 * lock, this atexit call never finishes.
117 * atexit(drawshutdown);
118 */
119 return 1;
122 int
123 initdraw(void (*error)(Display*, char*), char *fontname, char *label)
125 return geninitdraw("/dev", error, fontname, label, "/dev", Refnone);
128 extern int _freeimage1(Image*);
130 static Image*
131 getimage0(Display *d, Image *image)
133 char info[12*12+1];
134 uchar *a;
135 int n;
137 /*
138 * If there's an old screen, it has id 0. The 'J' request below
139 * will try to install the new screen as id 0, so the old one
140 * must be freed first.
141 */
142 if(image){
143 _freeimage1(image);
144 memset(image, 0, sizeof(Image));
147 a = bufimage(d, 2);
148 a[0] = 'J';
149 a[1] = 'I';
150 if(flushimage(d, 0) < 0){
151 fprint(2, "cannot read screen info: %r\n");
152 return nil;
155 n = _displayrddraw(d, info, sizeof info);
156 if(n != 12*12){
157 fprint(2, "short screen info\n");
158 return nil;
161 if(image == nil){
162 image = mallocz(sizeof(Image), 1);
163 if(image == nil){
164 fprint(2, "cannot allocate image: %r\n");
165 return nil;
169 image->display = d;
170 image->id = 0;
171 image->chan = strtochan(info+2*12);
172 image->depth = chantodepth(image->chan);
173 image->repl = atoi(info+3*12);
174 image->r.min.x = atoi(info+4*12);
175 image->r.min.y = atoi(info+5*12);
176 image->r.max.x = atoi(info+6*12);
177 image->r.max.y = atoi(info+7*12);
178 image->clipr.min.x = atoi(info+8*12);
179 image->clipr.min.y = atoi(info+9*12);
180 image->clipr.max.x = atoi(info+10*12);
181 image->clipr.max.y = atoi(info+11*12);
183 a = bufimage(d, 3);
184 a[0] = 'q';
185 a[1] = 1;
186 a[2] = 'd';
187 d->dpi = 100;
188 if(flushimage(d, 0) >= 0 && _displayrddraw(d, info, 12) == 12)
189 d->dpi = atoi(info);
191 return image;
194 /*
195 * Attach, or possibly reattach, to window.
196 * If reattaching, maintain value of screen pointer.
197 */
198 int
199 getwindow(Display *d, int ref)
201 Image *i, *oi;
203 /* XXX check for destroyed? */
205 /*
206 * Libdraw promises not to change the value of "screen",
207 * so we have to reuse the image structure
208 * memory we already have.
209 */
210 oi = d->image;
211 i = getimage0(d, oi);
212 if(i == nil)
213 sysfatal("getwindow failed");
214 d->image = i;
215 /* fprint(2, "getwindow %p -> %p\n", oi, i); */
217 freescreen(_screen);
218 _screen = allocscreen(i, d->white, 0);
219 _freeimage1(screen);
220 screen = _allocwindow(screen, _screen, i->r, ref, DWhite);
221 d->screenimage = screen;
222 return 0;
225 Display*
226 _initdisplay(void (*error)(Display*, char*), char *label)
228 Display *disp;
229 Image *image;
231 fmtinstall('P', Pfmt);
232 fmtinstall('R', Rfmt);
234 disp = mallocz(sizeof(Display), 1);
235 if(disp == nil){
236 Error1:
237 return nil;
239 disp->srvfd = -1;
240 image = nil;
241 if(0){
242 Error2:
243 free(image);
244 free(disp);
245 goto Error1;
247 disp->bufsize = 65500;
248 disp->buf = malloc(disp->bufsize+5); /* +5 for flush message */
249 disp->bufp = disp->buf;
250 disp->error = error;
251 qlock(&disp->qlock);
253 if(disp->buf == nil)
254 goto Error2;
255 if(0){
256 Error3:
257 free(disp->buf);
258 goto Error2;
261 if(_displaymux(disp) < 0
262 || _displayconnect(disp) < 0
263 || _displayinit(disp, label, winsize) < 0)
264 goto Error3;
265 if(0){
266 Error4:
267 close(disp->srvfd);
268 goto Error3;
271 image = getimage0(disp, nil);
272 if(image == nil)
273 goto Error4;
275 disp->image = image;
276 disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
277 disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
278 if(disp->white == nil || disp->black == nil){
279 free(disp->white);
280 free(disp->black);
281 goto Error4;
284 disp->opaque = disp->white;
285 disp->transparent = disp->black;
287 return disp;
290 /*
291 * Call with d unlocked.
292 * Note that disp->defaultfont and defaultsubfont are not freed here.
293 */
294 void
295 closedisplay(Display *disp)
297 int fd;
298 char buf[128];
300 if(disp == nil)
301 return;
302 if(disp == display)
303 display = nil;
304 if(disp->oldlabel[0]){
305 snprint(buf, sizeof buf, "%s/label", disp->windir);
306 fd = open(buf, OWRITE);
307 if(fd >= 0){
308 write(fd, disp->oldlabel, strlen(disp->oldlabel));
309 close(fd);
313 free(disp->devdir);
314 free(disp->windir);
315 if(disp->white)
316 freeimage(disp->white);
317 if(disp->black)
318 freeimage(disp->black);
319 if(disp->srvfd >= 0)
320 close(disp->srvfd);
321 free(disp);
324 void
325 lockdisplay(Display *disp)
327 if(debuglockdisplay){
328 /* avoid busy looping; it's rare we collide anyway */
329 while(!canqlock(&disp->qlock)){
330 fprint(1, "proc %d waiting for display lock...\n", getpid());
331 sleep(1000);
333 }else
334 qlock(&disp->qlock);
337 void
338 unlockdisplay(Display *disp)
340 qunlock(&disp->qlock);
343 void
344 drawerror(Display *d, char *s)
346 char err[ERRMAX];
348 if(d->error)
349 d->error(d, s);
350 else{
351 errstr(err, sizeof err);
352 fprint(2, "draw: %s: %s\n", s, err);
353 exits(s);
357 static
358 int
359 doflush(Display *d)
361 int n;
363 n = d->bufp-d->buf;
364 if(n <= 0)
365 return 1;
367 if(_displaywrdraw(d, d->buf, n) != n){
368 if(_drawdebug)
369 fprint(2, "flushimage fail: d=%p: %r\n", d); /**/
370 d->bufp = d->buf; /* might as well; chance of continuing */
371 return -1;
373 d->bufp = d->buf;
374 return 1;
377 int
378 flushimage(Display *d, int visible)
380 if(visible == 1 && visibleclicks && mousebuttons && _drawmouse.buttons) {
381 Rectangle r, r1;
382 int ret;
384 r = mousebuttons->r;
385 r = rectaddpt(r, _drawmouse.xy);
386 r = rectaddpt(r, Pt(-Dx(mousebuttons->r)/2, -Dy(mousebuttons->r)-3));
387 drawop(mousesave, mousesave->r, screen, nil, r.min, S);
389 r1 = rectaddpt(Rect(0, 0, 22, 22), r.min);
390 if(_drawmouse.buttons & 1)
391 drawop(screen, r1, mousebuttons, nil, ZP, S);
392 r1 = rectaddpt(r1, Pt(21, 0));
393 if(_drawmouse.buttons & 2)
394 drawop(screen, r1, mousebuttons, nil, Pt(21, 0), S);
395 r1 = rectaddpt(r1, Pt(21, 0));
396 if(_drawmouse.buttons & 4)
397 drawop(screen, r1, mousebuttons, nil, Pt(42, 0), S);
398 ret = flushimage(d, 2);
399 drawop(screen, r, mousesave, nil, ZP, S);
400 return ret;
403 if(visible){
404 *d->bufp++ = 'v'; /* five bytes always reserved for this */
405 if(d->_isnewdisplay){
406 BPLONG(d->bufp, d->screenimage->id);
407 d->bufp += 4;
410 return doflush(d);
413 uchar*
414 bufimage(Display *d, int n)
416 uchar *p;
418 if(n<0 || d == nil || n>d->bufsize){
419 abort();
420 werrstr("bad count in bufimage");
421 return 0;
423 if(d->bufp+n > d->buf+d->bufsize)
424 if(doflush(d) < 0)
425 return 0;
426 p = d->bufp;
427 d->bufp += n;
428 return p;
431 int
432 scalesize(Display *d, int n)
434 if(d == nil || d->dpi <= DefaultDPI)
435 return n;
436 return (n*d->dpi+DefaultDPI/2)/DefaultDPI;