xref: /inferno-os/libdraw/init.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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