Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
5 Display *display;
6 Font *font;
7 Image *screen;
8 int _drawdebug;
10 static char deffontname[] = "*default*";
11 Screen *_screen;
13 int debuglockdisplay = 1;
14 char *winsize;
16 /*
17 static void
18 drawshutdown(void)
19 {
20 Display *d;
22 d = display;
23 if(d){
24 display = nil;
25 closedisplay(d);
26 }
27 }
28 */
30 int
31 geninitdraw(char *devdir, void(*error)(Display*, char*), char *fontname, char *label, char *windir, int ref)
32 {
33 Subfont *df;
34 char buf[128];
36 if(label == nil)
37 label = argv0;
38 display = _initdisplay(error, label);
39 if(display == nil)
40 return -1;
42 /*
43 * Set up default font
44 */
45 df = getdefont(display);
46 display->defaultsubfont = df;
47 if(df == nil){
48 fprint(2, "imageinit: can't open default subfont: %r\n");
49 Error:
50 closedisplay(display);
51 display = nil;
52 return -1;
53 }
54 if(fontname == nil)
55 fontname = getenv("font");
57 /*
58 * Build fonts with caches==depth of screen, for speed.
59 * If conversion were faster, we'd use 0 and save memory.
60 */
61 if(fontname == nil){
62 snprint(buf, sizeof buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,
63 df->n-1, deffontname);
64 //BUG: Need something better for this installsubfont("*default*", df);
65 font = buildfont(display, buf, deffontname);
66 if(font == nil){
67 fprint(2, "imageinit: can't open default font: %r\n");
68 goto Error;
69 }
70 }else{
71 font = openfont(display, fontname); /* BUG: grey fonts */
72 if(font == nil){
73 fprint(2, "imageinit: can't open font %s: %r\n", fontname);
74 goto Error;
75 }
76 }
77 display->defaultfont = font;
79 _screen = allocscreen(display->image, display->white, 0);
80 display->screenimage = display->image; /* _allocwindow wants screenimage->chan */
81 screen = _allocwindow(nil, _screen, display->image->r, Refnone, DWhite);
82 if(screen == nil){
83 fprint(2, "_allocwindow: %r\n");
84 goto Error;
85 }
86 display->screenimage = screen;
87 draw(screen, screen->r, display->white, nil, ZP);
88 flushimage(display, 1);
90 /*
91 * I don't see any reason to go away gracefully,
92 * and if some other proc exits holding the display
93 * lock, this atexit call never finishes.
94 *
95 * atexit(drawshutdown);
96 */
97 return 1;
98 }
100 int
101 initdraw(void (*error)(Display*, char*), char *fontname, char *label)
103 return geninitdraw("/dev", error, fontname, label, "/dev", Refnone);
106 extern int _freeimage1(Image*);
108 static Image*
109 getimage0(Display *d, Image *image)
111 char info[12*12+1];
112 uchar *a;
113 int n;
115 /*
116 * If there's an old screen, it has id 0. The 'J' request below
117 * will try to install the new screen as id 0, so the old one
118 * must be freed first.
119 */
120 if(image){
121 _freeimage1(image);
122 memset(image, 0, sizeof(Image));
125 a = bufimage(d, 2);
126 a[0] = 'J';
127 a[1] = 'I';
128 if(flushimage(d, 0) < 0){
129 fprint(2, "cannot read screen info: %r\n");
130 return nil;
133 n = _displayrddraw(d, info, sizeof info);
134 if(n != 12*12){
135 fprint(2, "short screen info\n");
136 return nil;
139 if(image == nil){
140 image = mallocz(sizeof(Image), 1);
141 if(image == nil){
142 fprint(2, "cannot allocate image: %r\n");
143 return nil;
147 image->display = d;
148 image->id = 0;
149 image->chan = strtochan(info+2*12);
150 image->depth = chantodepth(image->chan);
151 image->repl = atoi(info+3*12);
152 image->r.min.x = atoi(info+4*12);
153 image->r.min.y = atoi(info+5*12);
154 image->r.max.x = atoi(info+6*12);
155 image->r.max.y = atoi(info+7*12);
156 image->clipr.min.x = atoi(info+8*12);
157 image->clipr.min.y = atoi(info+9*12);
158 image->clipr.max.x = atoi(info+10*12);
159 image->clipr.max.y = atoi(info+11*12);
160 return image;
163 /*
164 * Attach, or possibly reattach, to window.
165 * If reattaching, maintain value of screen pointer.
166 */
167 int
168 getwindow(Display *d, int ref)
170 Image *i, *oi;
172 /* XXX check for destroyed? */
174 /*
175 * Libdraw promises not to change the value of "screen",
176 * so we have to reuse the image structure
177 * memory we already have.
178 */
179 oi = d->image;
180 i = getimage0(d, oi);
181 if(i == nil)
182 sysfatal("getwindow failed");
183 d->image = i;
184 /* fprint(2, "getwindow %p -> %p\n", oi, i); */
186 freescreen(_screen);
187 _screen = allocscreen(i, d->white, 0);
188 _freeimage1(screen);
189 screen = _allocwindow(screen, _screen, i->r, ref, DWhite);
190 d->screenimage = screen;
191 return 0;
194 Display*
195 _initdisplay(void (*error)(Display*, char*), char *label)
197 Display *disp;
198 Image *image;
200 fmtinstall('P', Pfmt);
201 fmtinstall('R', Rfmt);
203 disp = mallocz(sizeof(Display), 1);
204 if(disp == nil){
205 Error1:
206 return nil;
208 disp->srvfd = -1;
209 image = nil;
210 if(0){
211 Error2:
212 free(image);
213 free(disp);
214 goto Error1;
216 disp->bufsize = 65500;
217 disp->buf = malloc(disp->bufsize+5); /* +5 for flush message */
218 disp->bufp = disp->buf;
219 disp->error = error;
220 qlock(&disp->qlock);
222 if(disp->buf == nil)
223 goto Error2;
224 if(0){
225 Error3:
226 free(disp->buf);
227 goto Error2;
230 if(_displaymux(disp) < 0
231 || _displayconnect(disp) < 0
232 || _displayinit(disp, label, winsize) < 0)
233 goto Error3;
234 if(0){
235 Error4:
236 close(disp->srvfd);
237 goto Error3;
240 image = getimage0(disp, nil);
241 if(image == nil)
242 goto Error4;
244 disp->image = image;
245 disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
246 disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
247 if(disp->white == nil || disp->black == nil){
248 free(disp->white);
249 free(disp->black);
250 goto Error4;
253 disp->opaque = disp->white;
254 disp->transparent = disp->black;
256 return disp;
259 /*
260 * Call with d unlocked.
261 * Note that disp->defaultfont and defaultsubfont are not freed here.
262 */
263 void
264 closedisplay(Display *disp)
266 int fd;
267 char buf[128];
269 if(disp == nil)
270 return;
271 if(disp == display)
272 display = nil;
273 if(disp->oldlabel[0]){
274 snprint(buf, sizeof buf, "%s/label", disp->windir);
275 fd = open(buf, OWRITE);
276 if(fd >= 0){
277 write(fd, disp->oldlabel, strlen(disp->oldlabel));
278 close(fd);
282 free(disp->devdir);
283 free(disp->windir);
284 if(disp->white)
285 freeimage(disp->white);
286 if(disp->black)
287 freeimage(disp->black);
288 if(disp->srvfd >= 0)
289 close(disp->srvfd);
290 free(disp);
293 void
294 lockdisplay(Display *disp)
296 if(debuglockdisplay){
297 /* avoid busy looping; it's rare we collide anyway */
298 while(!canqlock(&disp->qlock)){
299 fprint(1, "proc %d waiting for display lock...\n", getpid());
300 sleep(1000);
302 }else
303 qlock(&disp->qlock);
306 void
307 unlockdisplay(Display *disp)
309 qunlock(&disp->qlock);
312 void
313 drawerror(Display *d, char *s)
315 char err[ERRMAX];
317 if(d->error)
318 d->error(d, s);
319 else{
320 errstr(err, sizeof err);
321 fprint(2, "draw: %s: %s\n", s, err);
322 exits(s);
326 static
327 int
328 doflush(Display *d)
330 int n;
332 n = d->bufp-d->buf;
333 if(n <= 0)
334 return 1;
336 if(_displaywrdraw(d, d->buf, n) != n){
337 if(_drawdebug)
338 fprint(2, "flushimage fail: d=%p: %r\n", d); /**/
339 d->bufp = d->buf; /* might as well; chance of continuing */
340 return -1;
342 d->bufp = d->buf;
343 return 1;
346 int
347 flushimage(Display *d, int visible)
349 if(visible){
350 *d->bufp++ = 'v'; /* five bytes always reserved for this */
351 if(d->_isnewdisplay){
352 BPLONG(d->bufp, d->screenimage->id);
353 d->bufp += 4;
356 return doflush(d);
359 uchar*
360 bufimage(Display *d, int n)
362 uchar *p;
364 if(n<0 || d == nil || n>d->bufsize){
365 abort();
366 werrstr("bad count in bufimage");
367 return 0;
369 if(d->bufp+n > d->buf+d->bufsize)
370 if(doflush(d) < 0)
371 return 0;
372 p = d->bufp;
373 d->bufp += n;
374 return p;