plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

init.c (9140B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <draw.h>
      4 #include <mouse.h>
      5 
      6 Display	*display;
      7 Font	*font;
      8 Image	*screen;
      9 int	_drawdebug;
     10 
     11 Screen	*_screen;
     12 
     13 int		debuglockdisplay = 1;
     14 char	*winsize;
     15 
     16 int		visibleclicks = 0;
     17 Image	*mousebuttons;
     18 Image	*mousesave;
     19 Mouse	_drawmouse;
     20 
     21 void
     22 needdisplay(void)
     23 {
     24 }
     25 
     26 /*
     27 static void
     28 drawshutdown(void)
     29 {
     30 	Display *d;
     31 
     32 	d = display;
     33 	if(d){
     34 		display = nil;
     35 		closedisplay(d);
     36 	}
     37 }
     38 */
     39 
     40 int
     41 geninitdraw(char *devdir, void(*error)(Display*, char*), char *fontname, char *label, char *windir, int ref)
     42 {
     43 	char *p;
     44 
     45 	if(label == nil)
     46 		label = argv0;
     47 	display = _initdisplay(error, label);
     48 	if(display == nil)
     49 		return -1;
     50 
     51 	/*
     52 	 * Set up default font
     53 	 */
     54 	if(openfont(display, "*default*") == 0) {
     55 		fprint(2, "imageinit: can't open default subfont: %r\n");
     56     Error:
     57 		closedisplay(display);
     58 		display = nil;
     59 		return -1;
     60 	}
     61 	if(fontname == nil)
     62 		fontname = getenv("font");
     63 
     64 	/*
     65 	 * Build fonts with caches==depth of screen, for speed.
     66 	 * If conversion were faster, we'd use 0 and save memory.
     67 	 */
     68 	if(fontname == nil)
     69 		fontname = strdup("*default*");
     70 
     71 	font = openfont(display, fontname);
     72 	if(font == nil){
     73 		fprint(2, "imageinit: can't open font %s: %r\n", fontname);
     74 		goto Error;
     75 	}
     76 	display->defaultfont = font;
     77 
     78 	_screen = allocscreen(display->image, display->white, 0);
     79 	display->screenimage = display->image;	/* _allocwindow wants screenimage->chan */
     80 	screen = _allocwindow(nil, _screen, display->image->r, Refnone, DWhite);
     81 	if(screen == nil){
     82 		fprint(2, "_allocwindow: %r\n");
     83 		goto Error;
     84 	}
     85 	display->screenimage = screen;
     86 	draw(screen, screen->r, display->white, nil, ZP);
     87 	flushimage(display, 1);
     88 
     89 	p = getenv("visibleclicks");
     90 	visibleclicks = p != nil && *p == '1';
     91 	if(visibleclicks) {
     92 		Font *f;
     93 
     94 		f = display->defaultfont;
     95 		mousebuttons = allocimage(display, Rect(0,0,64,22), screen->chan, 0, DWhite);
     96 		border(mousebuttons, mousebuttons->r, 1, display->black, ZP);
     97 		border(mousebuttons, Rect(0, 0, 22, 22), 1, display->black, ZP);
     98 		border(mousebuttons, Rect(42, 0, 64, 22), 1, display->black, ZP);
     99 		string(mousebuttons, Pt(10-stringwidth(display->defaultfont, "1")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "1");
    100 		string(mousebuttons, Pt(21+10-stringwidth(display->defaultfont, "2")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "2");
    101 		string(mousebuttons, Pt(42+10-stringwidth(display->defaultfont, "3")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "3");
    102 		mousesave = allocimage(display, Rect(0,0,64,22), screen->chan, 0, 0);
    103 	}
    104 
    105 	/*
    106 	 * I don't see any reason to go away gracefully,
    107 	 * and if some other proc exits holding the display
    108 	 * lock, this atexit call never finishes.
    109 	 *
    110 	 * atexit(drawshutdown);
    111 	 */
    112 	return 1;
    113 }
    114 
    115 int
    116 initdraw(void (*error)(Display*, char*), char *fontname, char *label)
    117 {
    118 	return geninitdraw("/dev", error, fontname, label, "/dev", Refnone);
    119 }
    120 
    121 extern int _freeimage1(Image*);
    122 
    123 static Image*
    124 getimage0(Display *d, Image *image)
    125 {
    126 	char info[12*12+1];
    127 	uchar *a;
    128 	int n;
    129 
    130 	/*
    131 	 * If there's an old screen, it has id 0.  The 'J' request below
    132 	 * will try to install the new screen as id 0, so the old one
    133 	 * must be freed first.
    134 	 */
    135 	if(image){
    136 		_freeimage1(image);
    137 		memset(image, 0, sizeof(Image));
    138 	}
    139 
    140 	a = bufimage(d, 2);
    141 	a[0] = 'J';
    142 	a[1] = 'I';
    143 	if(flushimage(d, 0) < 0){
    144 		fprint(2, "cannot read screen info: %r\n");
    145 		return nil;
    146 	}
    147 
    148 	n = _displayrddraw(d, info, sizeof info);
    149 	if(n != 12*12){
    150 		fprint(2, "short screen info\n");
    151 		return nil;
    152 	}
    153 
    154 	if(image == nil){
    155 		image = mallocz(sizeof(Image), 1);
    156 		if(image == nil){
    157 			fprint(2, "cannot allocate image: %r\n");
    158 			return nil;
    159 		}
    160 	}
    161 
    162 	image->display = d;
    163 	image->id = 0;
    164 	image->chan = strtochan(info+2*12);
    165 	image->depth = chantodepth(image->chan);
    166 	image->repl = atoi(info+3*12);
    167 	image->r.min.x = atoi(info+4*12);
    168 	image->r.min.y = atoi(info+5*12);
    169 	image->r.max.x = atoi(info+6*12);
    170 	image->r.max.y = atoi(info+7*12);
    171 	image->clipr.min.x = atoi(info+8*12);
    172 	image->clipr.min.y = atoi(info+9*12);
    173 	image->clipr.max.x = atoi(info+10*12);
    174 	image->clipr.max.y = atoi(info+11*12);
    175 
    176 	a = bufimage(d, 3);
    177 	a[0] = 'q';
    178 	a[1] = 1;
    179 	a[2] = 'd';
    180 	d->dpi = 100;
    181 	if(flushimage(d, 0) >= 0 && _displayrddraw(d, info, 12) == 12)
    182 		d->dpi = atoi(info);
    183 
    184 	return image;
    185 }
    186 
    187 /*
    188  * Attach, or possibly reattach, to window.
    189  * If reattaching, maintain value of screen pointer.
    190  */
    191 int
    192 getwindow(Display *d, int ref)
    193 {
    194 	Image *i, *oi;
    195 	Font *f;
    196 
    197 	/* XXX check for destroyed? */
    198 
    199 	/*
    200 	 * Libdraw promises not to change the value of "screen",
    201 	 * so we have to reuse the image structure
    202 	 * memory we already have.
    203 	 */
    204 	oi = d->image;
    205 	i = getimage0(d, oi);
    206 	if(i == nil)
    207 		sysfatal("getwindow failed");
    208 	d->image = i;
    209 	/* fprint(2, "getwindow %p -> %p\n", oi, i); */
    210 
    211 	freescreen(_screen);
    212 	_screen = allocscreen(i, d->white, 0);
    213 	_freeimage1(screen);
    214 	screen = _allocwindow(screen, _screen, i->r, ref, DWhite);
    215 	d->screenimage = screen;
    216 
    217 
    218 	if(d->dpi >= DefaultDPI*3/2) {
    219 		for(f=d->firstfont; f != nil; f=f->next)
    220 			loadhidpi(f);
    221 	} else {
    222 		for(f=d->firstfont; f != nil; f=f->next)
    223 			if(f->lodpi != nil && f->lodpi != f)
    224 				swapfont(f, &f->hidpi, &f->lodpi);
    225 	}
    226 
    227 	return 0;
    228 }
    229 
    230 Display*
    231 _initdisplay(void (*error)(Display*, char*), char *label)
    232 {
    233 	Display *disp;
    234 	Image *image;
    235 
    236 	fmtinstall('P', Pfmt);
    237 	fmtinstall('R', Rfmt);
    238 
    239 	disp = mallocz(sizeof(Display), 1);
    240 	if(disp == nil){
    241     Error1:
    242 		return nil;
    243 	}
    244 	disp->srvfd = -1;
    245 	image = nil;
    246 	if(0){
    247     Error2:
    248 		free(image);
    249 		free(disp);
    250 		goto Error1;
    251 	}
    252 	disp->bufsize = 65500;
    253 	disp->buf = malloc(disp->bufsize+5);	/* +5 for flush message */
    254 	disp->bufp = disp->buf;
    255 	disp->error = error;
    256 	qlock(&disp->qlock);
    257 
    258 	if(disp->buf == nil)
    259 		goto Error2;
    260 	if(0){
    261     Error3:
    262 		free(disp->buf);
    263 		goto Error2;
    264 	}
    265 
    266 	if(_displaymux(disp) < 0
    267 	|| _displayconnect(disp) < 0
    268 	|| _displayinit(disp, label, winsize) < 0)
    269 		goto Error3;
    270 	if(0){
    271     Error4:
    272 		close(disp->srvfd);
    273 		goto Error3;
    274 	}
    275 
    276 	image = getimage0(disp, nil);
    277 	if(image == nil)
    278 		goto Error4;
    279 
    280 	disp->image = image;
    281 	disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
    282 	disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
    283 	if(disp->white == nil || disp->black == nil){
    284 		free(disp->white);
    285 		free(disp->black);
    286 		goto Error4;
    287 	}
    288 
    289 	disp->opaque = disp->white;
    290 	disp->transparent = disp->black;
    291 
    292 	return disp;
    293 }
    294 
    295 /*
    296  * Call with d unlocked.
    297  * Note that disp->defaultfont is not freed here.
    298  */
    299 void
    300 closedisplay(Display *disp)
    301 {
    302 	int fd;
    303 	char buf[128];
    304 
    305 	if(disp == nil)
    306 		return;
    307 	if(disp == display)
    308 		display = nil;
    309 	if(disp->oldlabel[0]){
    310 		snprint(buf, sizeof buf, "%s/label", disp->windir);
    311 		fd = open(buf, OWRITE);
    312 		if(fd >= 0){
    313 			write(fd, disp->oldlabel, strlen(disp->oldlabel));
    314 			close(fd);
    315 		}
    316 	}
    317 
    318 	free(disp->devdir);
    319 	free(disp->windir);
    320 	if(disp->white)
    321 		freeimage(disp->white);
    322 	if(disp->black)
    323 		freeimage(disp->black);
    324 	if(disp->srvfd >= 0)
    325 		close(disp->srvfd);
    326 	free(disp);
    327 }
    328 
    329 void
    330 lockdisplay(Display *disp)
    331 {
    332 	if(debuglockdisplay){
    333 		/* avoid busy looping; it's rare we collide anyway */
    334 		while(!canqlock(&disp->qlock)){
    335 			fprint(1, "proc %d waiting for display lock...\n", getpid());
    336 			sleep(1000);
    337 		}
    338 	}else
    339 		qlock(&disp->qlock);
    340 }
    341 
    342 void
    343 unlockdisplay(Display *disp)
    344 {
    345 	qunlock(&disp->qlock);
    346 }
    347 
    348 void
    349 drawerror(Display *d, char *s)
    350 {
    351 	char err[ERRMAX];
    352 
    353 	if(d->error)
    354 		d->error(d, s);
    355 	else{
    356 		errstr(err, sizeof err);
    357 		fprint(2, "draw: %s: %s\n", s, err);
    358 		exits(s);
    359 	}
    360 }
    361 
    362 static
    363 int
    364 doflush(Display *d)
    365 {
    366 	int n;
    367 
    368 	n = d->bufp-d->buf;
    369 	if(n <= 0)
    370 		return 1;
    371 
    372 	if(_displaywrdraw(d, d->buf, n) != n){
    373 		if(_drawdebug)
    374 			fprint(2, "flushimage fail: d=%p: %r\n", d); /**/
    375 		d->bufp = d->buf;	/* might as well; chance of continuing */
    376 		return -1;
    377 	}
    378 	d->bufp = d->buf;
    379 	return 1;
    380 }
    381 
    382 int
    383 flushimage(Display *d, int visible)
    384 {
    385 	if(visible == 1 && visibleclicks && mousebuttons && _drawmouse.buttons) {
    386 		Rectangle r, r1;
    387 		int ret;
    388 
    389 		r = mousebuttons->r;
    390 		r = rectaddpt(r, _drawmouse.xy);
    391 		r = rectaddpt(r, Pt(-Dx(mousebuttons->r)/2, -Dy(mousebuttons->r)-3));
    392 		drawop(mousesave, mousesave->r, screen, nil, r.min, S);
    393 
    394 		r1 = rectaddpt(Rect(0, 0, 22, 22), r.min);
    395 		if(_drawmouse.buttons & 1)
    396 			drawop(screen, r1, mousebuttons, nil, ZP, S);
    397 		r1 = rectaddpt(r1, Pt(21, 0));
    398 		if(_drawmouse.buttons & 2)
    399 			drawop(screen, r1, mousebuttons, nil, Pt(21, 0), S);
    400 		r1 = rectaddpt(r1, Pt(21, 0));
    401 		if(_drawmouse.buttons & 4)
    402 			drawop(screen, r1, mousebuttons, nil, Pt(42, 0), S);
    403 		ret = flushimage(d, 2);
    404 		drawop(screen, r, mousesave, nil, ZP, S);
    405 		return ret;
    406 	}
    407 
    408 	if(visible){
    409 		*d->bufp++ = 'v';	/* five bytes always reserved for this */
    410 		if(d->_isnewdisplay){
    411 			BPLONG(d->bufp, d->screenimage->id);
    412 			d->bufp += 4;
    413 		}
    414 	}
    415 	return doflush(d);
    416 }
    417 
    418 uchar*
    419 bufimage(Display *d, int n)
    420 {
    421 	uchar *p;
    422 
    423 	if(n<0 || d == nil || n>d->bufsize){
    424 		abort();
    425 		werrstr("bad count in bufimage");
    426 		return 0;
    427 	}
    428 	if(d->bufp+n > d->buf+d->bufsize)
    429 		if(doflush(d) < 0)
    430 			return 0;
    431 	p = d->bufp;
    432 	d->bufp += n;
    433 	return p;
    434 }
    435 
    436 int
    437 scalesize(Display *d, int n)
    438 {
    439 	if(d == nil || d->dpi <= DefaultDPI)
    440 		return n;
    441 	return (n*d->dpi+DefaultDPI/2)/DefaultDPI;
    442 }