URI:
       tdrawclient.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdrawclient.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 }