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 Screen *_screen;
13 int debuglockdisplay = 1;
14 char *winsize;
16 int visibleclicks = 0;
17 Image *mousebuttons;
18 Image *mousesave;
19 Mouse _drawmouse;
21 void
22 needdisplay(void)
23 {
24 }
26 /*
27 static void
28 drawshutdown(void)
29 {
30 Display *d;
32 d = display;
33 if(d){
34 display = nil;
35 closedisplay(d);
36 }
37 }
38 */
40 int
41 geninitdraw(char *devdir, void(*error)(Display*, char*), char *fontname, char *label, char *windir, int ref)
42 {
43 char *p;
45 if(label == nil)
46 label = argv0;
47 display = _initdisplay(error, label);
48 if(display == nil)
49 return -1;
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");
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*");
71 font = openfont(display, fontname);
72 if(font == nil){
73 fprint(2, "imageinit: can't open font %s: %r\n", fontname);
74 goto Error;
75 }
76 display->defaultfont = font;
78 _screen = allocscreen(display->image, display->white, 0);
79 display->screenimage = display->image; /* _allocwindow wants screenimage->chan */
80 screen = _allocwindow(nil, _screen, display->image->r, Refnone, DWhite);
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);
89 p = getenv("visibleclicks");
90 visibleclicks = p != nil && *p == '1';
91 if(visibleclicks) {
92 Font *f;
94 f = display->defaultfont;
95 mousebuttons = allocimage(display, Rect(0,0,64,22), screen->chan, 0, DWhite);
96 border(mousebuttons, mousebuttons->r, 1, display->black, ZP);
97 border(mousebuttons, Rect(0, 0, 22, 22), 1, display->black, ZP);
98 border(mousebuttons, Rect(42, 0, 64, 22), 1, display->black, ZP);
99 string(mousebuttons, Pt(10-stringwidth(display->defaultfont, "1")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "1");
100 string(mousebuttons, Pt(21+10-stringwidth(display->defaultfont, "2")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "2");
101 string(mousebuttons, Pt(42+10-stringwidth(display->defaultfont, "3")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "3");
102 mousesave = allocimage(display, Rect(0,0,64,22), screen->chan, 0, 0);
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.
110 * atexit(drawshutdown);
111 */
112 return 1;
115 int
116 initdraw(void (*error)(Display*, char*), char *fontname, char *label)
118 return geninitdraw("/dev", error, fontname, label, "/dev", Refnone);
121 extern int _freeimage1(Image*);
123 static Image*
124 getimage0(Display *d, Image *image)
126 char info[12*12+1];
127 uchar *a;
128 int n;
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));
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;
148 n = _displayrddraw(d, info, sizeof info);
149 if(n != 12*12){
150 fprint(2, "short screen info\n");
151 return nil;
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;
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);
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);
184 return image;
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)
194 Image *i, *oi;
195 Font *f;
197 /* XXX check for destroyed? */
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); */
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;
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);
227 return 0;
230 Display*
231 _initdisplay(void (*error)(Display*, char*), char *label)
233 Display *disp;
234 Image *image;
236 fmtinstall('P', Pfmt);
237 fmtinstall('R', Rfmt);
239 disp = mallocz(sizeof(Display), 1);
240 if(disp == nil){
241 Error1:
242 return nil;
244 disp->srvfd = -1;
245 image = nil;
246 if(0){
247 Error2:
248 free(image);
249 free(disp);
250 goto Error1;
252 disp->bufsize = 65500;
253 disp->buf = malloc(disp->bufsize+5); /* +5 for flush message */
254 disp->bufp = disp->buf;
255 disp->error = error;
256 qlock(&disp->qlock);
258 if(disp->buf == nil)
259 goto Error2;
260 if(0){
261 Error3:
262 free(disp->buf);
263 goto Error2;
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;
276 image = getimage0(disp, nil);
277 if(image == nil)
278 goto Error4;
280 disp->image = image;
281 disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
282 disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
283 if(disp->white == nil || disp->black == nil){
284 free(disp->white);
285 free(disp->black);
286 goto Error4;
289 disp->opaque = disp->white;
290 disp->transparent = disp->black;
292 return disp;
295 /*
296 * Call with d unlocked.
297 * Note that disp->defaultfont is not freed here.
298 */
299 void
300 closedisplay(Display *disp)
302 int fd;
303 char buf[128];
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);
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);
329 void
330 lockdisplay(Display *disp)
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", getpid());
336 sleep(1000);
338 }else
339 qlock(&disp->qlock);
342 void
343 unlockdisplay(Display *disp)
345 qunlock(&disp->qlock);
348 void
349 drawerror(Display *d, char *s)
351 char err[ERRMAX];
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);
362 static
363 int
364 doflush(Display *d)
366 int n;
368 n = d->bufp-d->buf;
369 if(n <= 0)
370 return 1;
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 continuing */
376 return -1;
378 d->bufp = d->buf;
379 return 1;
382 int
383 flushimage(Display *d, int visible)
385 if(visible == 1 && visibleclicks && mousebuttons && _drawmouse.buttons) {
386 Rectangle r, r1;
387 int ret;
389 r = mousebuttons->r;
390 r = rectaddpt(r, _drawmouse.xy);
391 r = rectaddpt(r, Pt(-Dx(mousebuttons->r)/2, -Dy(mousebuttons->r)-3));
392 drawop(mousesave, mousesave->r, screen, nil, r.min, S);
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), S);
400 r1 = rectaddpt(r1, Pt(21, 0));
401 if(_drawmouse.buttons & 4)
402 drawop(screen, r1, mousebuttons, nil, Pt(42, 0), S);
403 ret = flushimage(d, 2);
404 drawop(screen, r, mousesave, nil, ZP, S);
405 return ret;
408 if(visible){
409 *d->bufp++ = 'v'; /* five bytes always reserved for this */
410 if(d->_isnewdisplay){
411 BPLONG(d->bufp, d->screenimage->id);
412 d->bufp += 4;
415 return doflush(d);
418 uchar*
419 bufimage(Display *d, int n)
421 uchar *p;
423 if(n<0 || d == nil || n>d->bufsize){
424 abort();
425 werrstr("bad count in bufimage");
426 return 0;
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;
436 int
437 scalesize(Display *d, int n)
439 if(d == nil || d->dpi <= DefaultDPI)
440 return n;
441 return (n*d->dpi+DefaultDPI/2)/DefaultDPI;