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