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;
15 /*
16 static void
17 drawshutdown(void)
18 {
19 Display *d;
21 d = display;
22 if(d){
23 display = nil;
24 closedisplay(d);
25 }
26 }
27 */
29 int
30 initdraw(void (*error)(Display*, char*), char *fontname, char *label)
31 {
32 Subfont *df;
33 char buf[128];
35 display = _initdisplay(error, label); /* sets screen too */
36 if(display == nil)
37 return -1;
39 lockdisplay(display);
40 display->screenimage = display->image;
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"); /* leak */
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, "initdraw: 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, "initdraw: can't open font %s: %r\n", fontname);
74 goto Error;
75 }
76 }
77 display->defaultfont = font;
79 display->white = allocimage(display, Rect(0,0,1,1), GREY1, 1, DWhite);
80 display->black = allocimage(display, Rect(0,0,1,1), GREY1, 1, DBlack);
81 if(display->white == nil || display->black == nil){
82 fprint(2, "initdraw: can't allocate white and black");
83 goto Error;
84 }
85 display->opaque = display->white;
86 display->transparent = display->black;
88 _screen = allocscreen(display->image, display->white, 0);
89 screen = _allocwindow(nil, _screen, display->image->r, Refnone, DWhite);
90 display->screenimage = screen;
91 draw(screen, screen->r, display->white, nil, ZP);
92 flushimage(display, 1);
94 /*
95 * I don't see any reason to go away gracefully,
96 * and if some other proc exits holding the display
97 * lock, this atexit call never finishes.
98 *
99 * atexit(drawshutdown);
100 */
101 return 1;
104 /*
105 * Call with d unlocked.
106 * Note that disp->defaultfont and defaultsubfont are not freed here.
107 */
108 void
109 closedisplay(Display *disp)
111 int fd;
112 char buf[128];
114 if(disp == nil)
115 return;
116 if(disp == display)
117 display = nil;
118 if(disp->oldlabel[0]){
119 snprint(buf, sizeof buf, "%s/label", disp->windir);
120 fd = open(buf, OWRITE);
121 if(fd >= 0){
122 write(fd, disp->oldlabel, strlen(disp->oldlabel));
123 close(fd);
127 free(disp->devdir);
128 free(disp->windir);
129 if(disp->white)
130 freeimage(disp->white);
131 if(disp->black)
132 freeimage(disp->black);
133 free(disp);
136 void
137 lockdisplay(Display *disp)
139 if(debuglockdisplay){
140 /* avoid busy looping; it's rare we collide anyway */
141 while(!canqlock(&disp->qlock)){
142 fprint(1, "proc %d waiting for display lock...\n", getpid());
143 sleep(1000);
145 }else
146 qlock(&disp->qlock);
149 void
150 unlockdisplay(Display *disp)
152 qunlock(&disp->qlock);
155 void
156 drawerror(Display *d, char *s)
158 char err[ERRMAX];
160 if(d->error)
161 d->error(d, s);
162 else{
163 errstr(err, sizeof err);
164 fprint(2, "draw: %s: %s\n", s, err);
165 exits(s);
169 static
170 int
171 doflush(Display *d)
173 int n;
175 n = d->bufp-d->buf;
176 if(n <= 0)
177 return 1;
179 if(_drawmsgwrite(d, d->buf, n) != n){
180 if(_drawdebug)
181 fprint(2, "flushimage fail: d=%p: %r\n", d); /**/
182 d->bufp = d->buf; /* might as well; chance of continuing */
183 return -1;
185 d->bufp = d->buf;
186 return 1;
189 int
190 flushimage(Display *d, int visible)
192 if(visible){
193 *d->bufp++ = 'v'; /* five bytes always reserved for this */
194 if(d->_isnewdisplay){
195 BPLONG(d->bufp, d->screenimage->id);
196 d->bufp += 4;
199 return doflush(d);
202 uchar*
203 bufimage(Display *d, int n)
205 uchar *p;
207 if(n<0 || d == nil || n>d->bufsize){
208 abort();
209 werrstr("bad count in bufimage");
210 return 0;
212 if(d->bufp+n > d->buf+d->bufsize)
213 if(doflush(d) < 0)
214 return 0;
215 p = d->bufp;
216 d->bufp += n;
217 return p;