1 #include "lib9.h"
2 #include "draw.h"
3 #include "kernel.h"
4 #include "interp.h"
5
6 int _drawdebug;
7
8 enum {
9 CHECKLOCKING = 0
10 };
11
12 /*
13 * Attach, or possibly reattach, to window.
14 * If reattaching, maintain value of screen pointer.
15 */
16 int
gengetwindow(Display * d,char * winname,Image ** winp,Screen ** scrp,int ref)17 gengetwindow(Display *d, char *winname, Image **winp, Screen **scrp, int ref)
18 {
19 int n, fd;
20 char buf[64+1];
21 Image *image;
22
23 fd = libopen(winname, OREAD);
24 if(fd<0 || (n=libread(fd, buf, sizeof buf-1))<=0){
25 *winp = d->image;
26 assert(*winp && (*winp)->chan != 0);
27 return 1;
28 }
29 libclose(fd);
30 buf[n] = '\0';
31 if(*winp != nil){
32 _freeimage1(*winp);
33 freeimage((*scrp)->image);
34 freescreen(*scrp);
35 *scrp = nil;
36 }
37 image = namedimage(d, buf);
38 if(image == 0){
39 *winp = nil;
40 return -1;
41 }
42 assert(image->chan != 0);
43
44 *scrp = allocscreen(image, d->white, 0);
45 if(*scrp == nil){
46 *winp = nil;
47 return -1;
48 }
49
50 *winp = _allocwindow(*winp, *scrp, insetrect(image->r, Borderwidth), ref, DWhite);
51 if(*winp == nil)
52 return -1;
53 assert((*winp)->chan != 0);
54 return 1;
55 }
56
57 #define NINFO 12*12
58
59 Display*
initdisplay(char * dev,char * win,void (* error)(Display *,char *))60 initdisplay(char *dev, char *win, void(*error)(Display*, char*))
61 {
62 char buf[128], info[NINFO+1], *t;
63 int datafd, ctlfd, reffd;
64 Display *disp;
65 Image *image;
66 Dir *dir;
67 void *q;
68 ulong chan;
69
70 fmtinstall('P', Pfmt);
71 fmtinstall('R', Rfmt);
72 if(dev == 0)
73 dev = "/dev";
74 if(win == 0)
75 win = "/dev";
76 if(strlen(dev)>sizeof buf-25 || strlen(win)>sizeof buf-25){
77 kwerrstr("initdisplay: directory name too long");
78 return nil;
79 }
80 t = strdup(win);
81 if(t == nil)
82 return nil;
83
84 q = libqlalloc();
85 if(q == nil)
86 return nil;
87
88 sprint(buf, "%s/draw/new", dev);
89 ctlfd = libopen(buf, ORDWR);
90 if(ctlfd < 0){
91 if(libbind("#i", dev, MBEFORE) < 0){
92 Error1:
93 libqlfree(q);
94 free(t);
95 kwerrstr("initdisplay: %s: %r", buf);
96 return 0;
97 }
98 ctlfd = libopen(buf, ORDWR);
99 }
100 if(ctlfd < 0)
101 goto Error1;
102 if(libread(ctlfd, info, sizeof info) < NINFO){
103 Error2:
104 libclose(ctlfd);
105 goto Error1;
106 }
107
108 if((chan=strtochan(info+2*12)) == 0){
109 kwerrstr("bad channel in %s", buf);
110 goto Error2;
111 }
112
113 sprint(buf, "%s/draw/%d/data", dev, atoi(info+0*12));
114 datafd = libopen(buf, ORDWR);
115 if(datafd < 0)
116 goto Error2;
117 sprint(buf, "%s/draw/%d/refresh", dev, atoi(info+0*12));
118 reffd = libopen(buf, OREAD);
119 if(reffd < 0){
120 Error3:
121 libclose(datafd);
122 goto Error2;
123 }
124 strcpy(buf, "allocation failed");
125 disp = malloc(sizeof(Display));
126 if(disp == 0){
127 Error4:
128 libclose(reffd);
129 goto Error3;
130 }
131 image = malloc(sizeof(Image));
132 if(image == 0){
133 Error5:
134 free(disp);
135 goto Error4;
136 }
137 memset(image, 0, sizeof(Image));
138 memset(disp, 0, sizeof(Display));
139 image->display = disp;
140 image->id = 0;
141 image->chan = chan;
142 image->depth = chantodepth(chan);
143 image->repl = atoi(info+3*12);
144 image->r.min.x = atoi(info+4*12);
145 image->r.min.y = atoi(info+5*12);
146 image->r.max.x = atoi(info+6*12);
147 image->r.max.y = atoi(info+7*12);
148 image->clipr.min.x = atoi(info+8*12);
149 image->clipr.min.y = atoi(info+9*12);
150 image->clipr.max.x = atoi(info+10*12);
151 image->clipr.max.y = atoi(info+11*12);
152 disp->dirno = atoi(info+0*12);
153 disp->datachan = libfdtochan(datafd, ORDWR);
154 disp->refchan = libfdtochan(reffd, OREAD);
155 disp->ctlchan = libfdtochan(ctlfd, ORDWR);
156 if(disp->datachan == nil || disp->refchan == nil || disp->ctlchan == nil)
157 goto Error4;
158 disp->bufsize = Displaybufsize; /* TO DO: iounit(datafd) */
159 if(disp->bufsize <= 0)
160 disp->bufsize = Displaybufsize;
161 if(disp->bufsize < 512){
162 kwerrstr("iounit %d too small", disp->bufsize);
163 goto Error5;
164 }
165 /* TO DO: allocate buffer */
166
167 libclose(datafd);
168 libclose(reffd);
169 disp->image = image;
170 disp->bufp = disp->buf;
171 disp->error = error;
172 disp->chan = image->chan;
173 disp->depth = image->depth;
174 disp->windir = t;
175 disp->devdir = strdup(dev);
176 disp->qlock = q;
177 libqlock(q);
178 disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
179 disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
180 disp->opaque = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
181 disp->transparent = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
182 if(disp->white == nil || disp->black == nil || disp->opaque == nil || disp->transparent == nil){
183 free(image);
184 free(disp->devdir);
185 free(disp->white);
186 free(disp->black);
187 libclose(ctlfd);
188 goto Error5;
189 }
190 if((dir = libdirfstat(ctlfd))!=nil && dir->type=='i'){
191 disp->local = 1;
192 disp->dataqid = dir->qid.path;
193 }
194 free(dir);
195 libclose(ctlfd);
196
197 if(CHECKLOCKING)
198 disp->local = 0; /* force display locking even for local access */
199
200 assert(disp->chan != 0 && image->chan != 0);
201 return disp;
202 }
203
204 /*
205 * Call with d unlocked.
206 * Note that disp->defaultfont and defaultsubfont are not freed here.
207 */
208 void
closedisplay(Display * disp)209 closedisplay(Display *disp)
210 {
211 int fd;
212 char buf[128];
213
214 if(disp == nil)
215 return;
216 libqlock(disp->qlock);
217 if(disp->oldlabel[0]){
218 snprint(buf, sizeof buf, "%s/label", disp->windir);
219 fd = libopen(buf, OWRITE);
220 if(fd >= 0){
221 libwrite(fd, disp->oldlabel, strlen(disp->oldlabel));
222 libclose(fd);
223 }
224 }
225
226 free(disp->devdir);
227 free(disp->windir);
228 freeimage(disp->white);
229 freeimage(disp->black);
230 freeimage(disp->opaque);
231 freeimage(disp->transparent);
232 free(disp->image);
233 libchanclose(disp->datachan);
234 libchanclose(disp->refchan);
235 libchanclose(disp->ctlchan);
236 /* should cause refresh slave to shut down */
237 libqunlock(disp->qlock);
238 libqlfree(disp->qlock);
239 free(disp);
240 }
241
242 int
lockdisplay(Display * disp)243 lockdisplay(Display *disp)
244 {
245 if(disp->local)
246 return 0;
247 if(libqlowner(disp->qlock) != currun()){
248 libqlock(disp->qlock);
249 return 1;
250 }
251 return 0;
252 }
253
254 void
unlockdisplay(Display * disp)255 unlockdisplay(Display *disp)
256 {
257 if(disp->local)
258 return;
259 libqunlock(disp->qlock);
260 }
261
262 /* use static buffer to avoid stack bloat */
263 int
_drawprint(int fd,char * fmt,...)264 _drawprint(int fd, char *fmt, ...)
265 {
266 int n;
267 va_list arg;
268 char buf[128];
269 // static QLock l;
270
271 // qlock(&l);
272 va_start(arg, fmt);
273 vseprint(buf, buf+sizeof buf, fmt, arg);
274 va_end(arg);
275 n = libwrite(fd, buf, strlen(buf));
276 // qunlock(&l);
277 return n;
278 }
279
280 #ifdef YYY
281 void
drawerror(Display * d,char * s)282 drawerror(Display *d, char *s)
283 {
284 char err[ERRMAX];
285
286 if(d->error)
287 d->error(d, s);
288 else{
289 err[0] = 0;
290 errstr(err, sizeof err);
291 _drawprint(2, "draw: %s: %s\n", s, err);
292 exits(s);
293 }
294 }
295
296 static
297 int
doflush(Display * d)298 doflush(Display *d)
299 {
300 int n;
301
302 n = d->bufp-d->buf;
303 if(n <= 0)
304 return 1;
305
306 if(kchanio(d->datachan, d->buf, n, OWRITE) != n){
307 if(_drawdebug)
308 _drawprint(2, "flushimage fail: d=%p: %r\n", d); /**/
309 d->bufp = d->buf; /* might as well; chance of continuing */
310 return -1;
311 }
312 d->bufp = d->buf;
313 return 1;
314 }
315
316 int
flushimage(Display * d,int visible)317 flushimage(Display *d, int visible)
318 {
319 if(visible)
320 *d->bufp++ = 'v'; /* one byte always reserved for this */
321 return doflush(d);
322 }
323
324 uchar*
bufimage(Display * d,int n)325 bufimage(Display *d, int n)
326 {
327 uchar *p;
328
329 if(n<0 || n>Displaybufsize){
330 kwerrstr("bad count in bufimage");
331 return 0;
332 }
333 if(d->bufp+n > d->buf+Displaybufsize)
334 if(doflush(d) < 0)
335 return 0;
336 p = d->bufp;
337 d->bufp += n;
338 return p;
339 }
340
341 #endif
342