plan9port

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

drawclient.c (8966B)


      1 /* Copyright (c) 2006 Russ Cox */
      2 
      3 #include <u.h>
      4 #include <sys/select.h>
      5 #include <libc.h>
      6 #include <draw.h>
      7 #include <mouse.h>
      8 #include <cursor.h>
      9 #include <drawfcall.h>
     10 #include <mux.h>
     11 
     12 extern Mouse _drawmouse;
     13 int chattydrawclient = 0;
     14 
     15 static int	drawgettag(Mux *mux, void *vmsg);
     16 static void*	drawrecv(Mux *mux);
     17 static int	drawnbrecv(Mux *mux, void**);
     18 static int	drawsend(Mux *mux, void *vmsg);
     19 static int	drawsettag(Mux *mux, void *vmsg, uint tag);
     20 static int canreadfd(int);
     21 
     22 int
     23 _displayconnect(Display *d)
     24 {
     25 	int pid, p[2], fd, nbuf, n;
     26 	char *wsysid, *ns, *addr, *id;
     27 	uchar *buf;
     28 	Wsysmsg w;
     29 
     30 	fmtinstall('W', drawfcallfmt);
     31 	fmtinstall('H', encodefmt);
     32 
     33 	wsysid = getenv("wsysid");
     34 	if(wsysid != nil) {
     35 		// Connect to running devdraw service.
     36 		// wsysid=devdrawname/id
     37 		id = strchr(wsysid, '/');
     38 		if(id == nil) {
     39 			werrstr("invalid $wsysid");
     40 			return -1;
     41 		}
     42 		*id++ = '\0';
     43 		if((ns = getns()) == nil)
     44 			return -1;
     45 		addr = smprint("unix!%s/%s", ns, wsysid);
     46 		free(ns);
     47 		if(addr == nil)
     48 			return -1;
     49 		fd = dial(addr, 0, 0, 0);
     50 		free(addr);
     51 		if(fd < 0)
     52 			return -1;
     53 		nbuf = strlen(id) + 500;
     54 		buf = malloc(nbuf);
     55 		if(buf == nil) {
     56 			close(fd);
     57 			return -1;
     58 		}
     59 		memset(&w, 0, sizeof w);
     60 		w.type = Tctxt;
     61 		w.id = id;
     62 		n = convW2M(&w, buf, nbuf);
     63 		if(write(fd, buf, n) != n) {
     64 			close(fd);
     65 			werrstr("wsys short write: %r");
     66 			return -1;
     67 		}
     68 		n = readwsysmsg(fd, buf, nbuf);
     69 		if(n < 0) {
     70 			close(fd);
     71 			werrstr("wsys short read: %r");
     72 			return -1;
     73 		}
     74 		if(convM2W(buf, n, &w) <= 0) {
     75 			close(fd);
     76 			werrstr("wsys decode error");
     77 			return -1;
     78 		}
     79 		if(w.type != Rctxt) {
     80 			close(fd);
     81 			if(w.type == Rerror)
     82 				werrstr("%s", w.error);
     83 			else
     84 				werrstr("wsys rpc phase error (%d)", w.type);
     85 			return -1;
     86 		}
     87 		d->srvfd = fd;
     88 		return 0;
     89 	}
     90 
     91 	if(pipe(p) < 0)
     92 		return -1;
     93 	if((pid=fork()) < 0){
     94 		close(p[0]);
     95 		close(p[1]);
     96 		return -1;
     97 	}
     98 	if(pid == 0){
     99 		char *devdraw;
    100 
    101 		devdraw = getenv("DEVDRAW");
    102 		if(devdraw == nil)
    103 			devdraw = "devdraw";
    104 		close(p[0]);
    105 		dup(p[1], 0);
    106 		dup(p[1], 1);
    107 		/* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */
    108 		/*
    109 		 * The argv0 has no meaning to devdraw.
    110 		 * Pass it along only so that the various
    111 		 * devdraws in psu -a can be distinguished.
    112 		 * The NOLIBTHREADDAEMONIZE keeps devdraw from
    113 		 * forking before threadmain. OS X hates it when
    114 		 * guis fork.
    115 		 *
    116 		 * If client didn't use ARGBEGIN, argv0 == nil.
    117 		 * Can't send nil through because OS X expects
    118 		 * argv[0] to be non-nil.  Also, OS X apparently
    119 		 * expects argv[0] to be a valid executable name,
    120 		 * so "(argv0)" is not okay.  Use "devdraw"
    121 		 * instead.
    122 		 */
    123 		putenv("NOLIBTHREADDAEMONIZE", "1");
    124 		devdraw = getenv("DEVDRAW");
    125 		if(devdraw == nil)
    126 			devdraw = "devdraw";
    127 		if(argv0 == nil)
    128 			argv0 = devdraw;
    129 		execl(devdraw, argv0, argv0, "(devdraw)", nil);
    130 		sysfatal("exec devdraw: %r");
    131 	}
    132 	close(p[1]);
    133 	d->srvfd = p[0];
    134 	return 0;
    135 }
    136 
    137 int
    138 _displaymux(Display *d)
    139 {
    140 	if((d->mux = mallocz(sizeof(*d->mux), 1)) == nil)
    141 		return -1;
    142 
    143 	d->mux->mintag = 1;
    144 	d->mux->maxtag = 255;
    145 	d->mux->send = drawsend;
    146 	d->mux->recv = drawrecv;
    147 	d->mux->nbrecv = drawnbrecv;
    148 	d->mux->gettag = drawgettag;
    149 	d->mux->settag = drawsettag;
    150 	d->mux->aux = d;
    151 	muxinit(d->mux);
    152 
    153 	return 0;
    154 }
    155 
    156 static int
    157 drawsend(Mux *mux, void *vmsg)
    158 {
    159 	int n;
    160 	uchar *msg;
    161 	Display *d;
    162 
    163 	msg = vmsg;
    164 	GET(msg, n);
    165 	d = mux->aux;
    166 	return write(d->srvfd, msg, n);
    167 }
    168 
    169 static int
    170 _drawrecv(Mux *mux, int canblock, void **vp)
    171 {
    172 	int n;
    173 	uchar buf[4], *p;
    174 	Display *d;
    175 
    176 	d = mux->aux;
    177 	*vp = nil;
    178 	if(!canblock && !canreadfd(d->srvfd))
    179 		return 0;
    180 	if((n=readn(d->srvfd, buf, 4)) != 4)
    181 		return 1;
    182 	GET(buf, n);
    183 	p = malloc(n);
    184 	if(p == nil){
    185 		fprint(2, "out of memory allocating %d in drawrecv\n", n);
    186 		return 1;
    187 	}
    188 	memmove(p, buf, 4);
    189 	if(readn(d->srvfd, p+4, n-4) != n-4){
    190 		free(p);
    191 		return 1;
    192 	}
    193 	*vp = p;
    194 	return 1;
    195 }
    196 
    197 static void*
    198 drawrecv(Mux *mux)
    199 {
    200 	void *p;
    201 	_drawrecv(mux, 1, &p);
    202 	return p;
    203 }
    204 
    205 static int
    206 drawnbrecv(Mux *mux, void **vp)
    207 {
    208 	return _drawrecv(mux, 0, vp);
    209 }
    210 
    211 static int
    212 drawgettag(Mux *mux, void *vmsg)
    213 {
    214 	uchar *msg;
    215 	USED(mux);
    216 
    217 	msg = vmsg;
    218 	return msg[4];
    219 }
    220 
    221 static int
    222 drawsettag(Mux *mux, void *vmsg, uint tag)
    223 {
    224 	uchar *msg;
    225 	USED(mux);
    226 
    227 	msg = vmsg;
    228 	msg[4] = tag;
    229 	return 0;
    230 }
    231 
    232 static int
    233 displayrpc(Display *d, Wsysmsg *tx, Wsysmsg *rx, void **freep)
    234 {
    235 	int n, nn;
    236 	void *tpkt, *rpkt;
    237 
    238 	n = sizeW2M(tx);
    239 	tpkt = malloc(n);
    240 	if(freep)
    241 		*freep = nil;
    242 	if(tpkt == nil)
    243 		return -1;
    244 	tx->tag = 0;
    245 	if(chattydrawclient)
    246 		fprint(2, "<- %W\n", tx);
    247 	nn = convW2M(tx, tpkt, n);
    248 	if(nn != n){
    249 		free(tpkt);
    250 		werrstr("drawclient: sizeW2M convW2M mismatch");
    251 		fprint(2, "%r\n");
    252 		return -1;
    253 	}
    254 	/*
    255 	 * This is the only point where we might reschedule.
    256 	 * Muxrpc might need to acquire d->mux->lk, which could
    257 	 * be held by some other proc (e.g., the one reading from
    258 	 * the keyboard via Trdkbd messages).  If we need to wait
    259 	 * for the lock, don't let other threads from this proc
    260 	 * run.  This keeps up the appearance that writes to /dev/draw
    261 	 * don't cause rescheduling.  If you *do* allow rescheduling
    262 	 * here, then flushimage(display, 1) happening in two different
    263 	 * threads in the same proc can cause a buffer of commands
    264 	 * to be written out twice, leading to interesting results
    265 	 * on the screen.
    266 	 *
    267 	 * Threadpin and threadunpin were added to the thread library
    268 	 * to solve exactly this problem.  Be careful!  They are dangerous.
    269 	 *
    270 	 * _pin and _unpin are aliases for threadpin and threadunpin
    271 	 * in a threaded program and are no-ops in unthreaded programs.
    272 	 */
    273 	_pin();
    274 	rpkt = muxrpc(d->mux, tpkt);
    275 	_unpin();
    276 	free(tpkt);
    277 	if(rpkt == nil){
    278 		werrstr("muxrpc: %r");
    279 		return -1;
    280 	}
    281 	GET((uchar*)rpkt, n);
    282 	nn = convM2W(rpkt, n, rx);
    283 	if(nn != n){
    284 		free(rpkt);
    285 		werrstr("drawclient: convM2W packet size mismatch %d %d %.*H", n, nn, n, rpkt);
    286 		fprint(2, "%r\n");
    287 		return -1;
    288 	}
    289 	if(chattydrawclient)
    290 		fprint(2, "-> %W\n", rx);
    291 	if(rx->type == Rerror){
    292 		werrstr("%s", rx->error);
    293 		free(rpkt);
    294 		return -1;
    295 	}
    296 	if(rx->type != tx->type+1){
    297 		werrstr("packet type mismatch -- tx %d rx %d",
    298 			tx->type, rx->type);
    299 		free(rpkt);
    300 		return -1;
    301 	}
    302 	if(freep)
    303 		*freep = rpkt;
    304 	else
    305 		free(rpkt);
    306 	return 0;
    307 }
    308 
    309 int
    310 _displayinit(Display *d, char *label, char *winsize)
    311 {
    312 	Wsysmsg tx, rx;
    313 
    314 	tx.type = Tinit;
    315 	tx.label = label;
    316 	tx.winsize = winsize;
    317 	return displayrpc(d, &tx, &rx, nil);
    318 }
    319 
    320 int
    321 _displayrdmouse(Display *d, Mouse *m, int *resized)
    322 {
    323 	Wsysmsg tx, rx;
    324 
    325 	tx.type = Trdmouse;
    326 	if(displayrpc(d, &tx, &rx, nil) < 0)
    327 		return -1;
    328 	_drawmouse = rx.mouse;
    329 	*m = rx.mouse;
    330 	*resized = rx.resized;
    331 	return 0;
    332 }
    333 
    334 int
    335 _displayrdkbd(Display *d, Rune *r)
    336 {
    337 	Wsysmsg tx, rx;
    338 
    339 	tx.type = Trdkbd4;
    340 	if(displayrpc(d, &tx, &rx, nil) < 0)
    341 		return -1;
    342 	*r = rx.rune;
    343 	return 0;
    344 }
    345 
    346 int
    347 _displaymoveto(Display *d, Point p)
    348 {
    349 	Wsysmsg tx, rx;
    350 
    351 	tx.type = Tmoveto;
    352 	tx.mouse.xy = p;
    353 	if(displayrpc(d, &tx, &rx, nil) < 0)
    354 		return -1;
    355 	_drawmouse.xy = p;
    356 	return flushimage(d, 1);
    357 }
    358 
    359 int
    360 _displaycursor(Display *d, Cursor *c, Cursor2 *c2)
    361 {
    362 	Wsysmsg tx, rx;
    363 
    364 	tx.type = Tcursor2;
    365 	if(c == nil){
    366 		memset(&tx.cursor, 0, sizeof tx.cursor);
    367 		memset(&tx.cursor2, 0, sizeof tx.cursor2);
    368 		tx.arrowcursor = 1;
    369 	}else{
    370 		tx.arrowcursor = 0;
    371 		tx.cursor = *c;
    372 		if(c2 != nil)
    373 			tx.cursor2 = *c2;
    374 		else
    375 			scalecursor(&tx.cursor2, c);
    376 	}
    377 	return displayrpc(d, &tx, &rx, nil);
    378 }
    379 
    380 int
    381 _displaybouncemouse(Display *d, Mouse *m)
    382 {
    383 	Wsysmsg tx, rx;
    384 
    385 	tx.type = Tbouncemouse;
    386 	tx.mouse = *m;
    387 	return displayrpc(d, &tx, &rx, nil);
    388 }
    389 
    390 int
    391 _displaylabel(Display *d, char *label)
    392 {
    393 	Wsysmsg tx, rx;
    394 
    395 	tx.type = Tlabel;
    396 	tx.label = label;
    397 	return displayrpc(d, &tx, &rx, nil);
    398 }
    399 
    400 char*
    401 _displayrdsnarf(Display *d)
    402 {
    403 	void *p;
    404 	char *s;
    405 	Wsysmsg tx, rx;
    406 
    407 	tx.type = Trdsnarf;
    408 	if(displayrpc(d, &tx, &rx, &p) < 0)
    409 		return nil;
    410 	s = strdup(rx.snarf);
    411 	free(p);
    412 	return s;
    413 }
    414 
    415 int
    416 _displaywrsnarf(Display *d, char *snarf)
    417 {
    418 	Wsysmsg tx, rx;
    419 
    420 	tx.type = Twrsnarf;
    421 	tx.snarf = snarf;
    422 	return displayrpc(d, &tx, &rx, nil);
    423 }
    424 
    425 int
    426 _displayrddraw(Display *d, void *v, int n)
    427 {
    428 	void *p;
    429 	Wsysmsg tx, rx;
    430 
    431 	tx.type = Trddraw;
    432 	tx.count = n;
    433 	if(displayrpc(d, &tx, &rx, &p) < 0)
    434 		return -1;
    435 	memmove(v, rx.data, rx.count);
    436 	free(p);
    437 	return rx.count;
    438 }
    439 
    440 int
    441 _displaywrdraw(Display *d, void *v, int n)
    442 {
    443 	Wsysmsg tx, rx;
    444 
    445 	tx.type = Twrdraw;
    446 	tx.count = n;
    447 	tx.data = v;
    448 	if(displayrpc(d, &tx, &rx, nil) < 0)
    449 		return -1;
    450 	return rx.count;
    451 }
    452 
    453 int
    454 _displaytop(Display *d)
    455 {
    456 	Wsysmsg tx, rx;
    457 
    458 	tx.type = Ttop;
    459 	return displayrpc(d, &tx, &rx, nil);
    460 }
    461 
    462 int
    463 _displayresize(Display *d, Rectangle r)
    464 {
    465 	Wsysmsg tx, rx;
    466 
    467 	tx.type = Tresize;
    468 	tx.rect = r;
    469 	return displayrpc(d, &tx, &rx, nil);
    470 }
    471 
    472 static int
    473 canreadfd(int fd)
    474 {
    475 	fd_set rs, ws, xs;
    476 	struct timeval tv;
    477 
    478 	FD_ZERO(&rs);
    479 	FD_ZERO(&ws);
    480 	FD_ZERO(&xs);
    481 	FD_SET(fd, &rs);
    482 	FD_SET(fd, &xs);
    483 	tv.tv_sec = 0;
    484 	tv.tv_usec = 0;
    485 	if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
    486 		return 0;
    487 	if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
    488 		return 1;
    489 	return 0;
    490 }