URI:
       tsrv.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
       ---
       tsrv.c (10538B)
       ---
            1 /*
            2  * Window system protocol server.
            3  */
            4 
            5 #include <u.h>
            6 #include <libc.h>
            7 #include <thread.h>
            8 #include <draw.h>
            9 #include <memdraw.h>
           10 #include <memlayer.h>
           11 #include <keyboard.h>
           12 #include <mouse.h>
           13 #include <cursor.h>
           14 #include <drawfcall.h>
           15 #include "devdraw.h"
           16 
           17 static void runmsg(Client*, Wsysmsg*);
           18 static void replymsg(Client*, Wsysmsg*);
           19 static void matchkbd(Client*);
           20 static void matchmouse(Client*);
           21 static void serveproc(void*);
           22 static void listenproc(void*);
           23 Client *client0;
           24 
           25 int trace = 0;
           26 static char *srvname;
           27 static int afd;
           28 static char adir[40];
           29 
           30 static void
           31 usage(void)
           32 {
           33         fprint(2, "usage: devdraw (don't run directly)\n");
           34         threadexitsall("usage");
           35 }
           36 
           37 void
           38 threadmain(int argc, char **argv)
           39 {
           40         char *p;
           41 
           42         ARGBEGIN{
           43         case 'D':                /* for good ps -a listings */
           44                 break;
           45         case 'f':                /* fall through for backward compatibility */
           46         case 'g':
           47         case 'b':
           48                 break;
           49         case 's':
           50                 // TODO: Update usage, man page.
           51                 srvname = EARGF(usage());
           52                 break;
           53         default:
           54                 usage();
           55         }ARGEND
           56 
           57         memimageinit();
           58         fmtinstall('H', encodefmt);
           59         if((p = getenv("DEVDRAWTRACE")) != nil)
           60                 trace = atoi(p);
           61 
           62         if(srvname == nil) {
           63                 client0 = mallocz(sizeof(Client), 1);
           64                 if(client0 == nil){
           65                         fprint(2, "initdraw: allocating client0: out of memory");
           66                         abort();
           67                 }
           68                 client0->displaydpi = 100;
           69                 client0->rfd = 3;
           70                 client0->wfd = 4;
           71 
           72                 /*
           73                  * Move the protocol off stdin/stdout so that
           74                  * any inadvertent prints don't screw things up.
           75                  */
           76                 dup(0,3);
           77                 dup(1,4);
           78                 close(0);
           79                 close(1);
           80                 open("/dev/null", OREAD);
           81                 open("/dev/null", OWRITE);
           82         }
           83 
           84         fmtinstall('W', drawfcallfmt);
           85         gfx_main();
           86 }
           87 
           88 void
           89 gfx_started(void)
           90 {
           91         char *ns, *addr;
           92 
           93         if(srvname == nil) {
           94                 // Legacy mode: serving single client on pipes.
           95                 proccreate(serveproc, client0, 0);
           96                 return;
           97         }
           98 
           99         // Server mode.
          100         if((ns = getns()) == nil)
          101                 sysfatal("out of memory");
          102 
          103         addr = smprint("unix!%s/%s", ns, srvname);
          104         free(ns);
          105         if(addr == nil)
          106                 sysfatal("out of memory");
          107 
          108         if((afd = announce(addr, adir)) < 0)
          109                 sysfatal("announce %s: %r", addr);
          110 
          111         proccreate(listenproc, nil, 0);
          112 }
          113 
          114 static void
          115 listenproc(void *v)
          116 {
          117         Client *c;
          118         int fd;
          119         char dir[40];
          120 
          121         USED(v);
          122 
          123         for(;;) {
          124                 fd = listen(adir, dir);
          125                 if(fd < 0)
          126                         sysfatal("listen: %r");
          127                 c = mallocz(sizeof(Client), 1);
          128                 if(c == nil){
          129                         fprint(2, "initdraw: allocating client0: out of memory");
          130                         abort();
          131                 }
          132                 c->displaydpi = 100;
          133                 c->rfd = fd;
          134                 c->wfd = fd;
          135                 proccreate(serveproc, c, 0);
          136         }
          137 }
          138 
          139 static void
          140 serveproc(void *v)
          141 {
          142         Client *c;
          143         uchar buf[4], *mbuf;
          144         int nmbuf, n, nn;
          145         Wsysmsg m;
          146 
          147         c = v;
          148         mbuf = nil;
          149         nmbuf = 0;
          150         while((n = read(c->rfd, buf, 4)) == 4){
          151                 GET(buf, n);
          152                 if(n > nmbuf){
          153                         free(mbuf);
          154                         mbuf = malloc(4+n);
          155                         if(mbuf == nil)
          156                                 sysfatal("out of memory");
          157                         nmbuf = n;
          158                 }
          159                 memmove(mbuf, buf, 4);
          160                 nn = readn(c->rfd, mbuf+4, n-4);
          161                 if(nn != n-4) {
          162                         fprint(2, "serveproc: eof during message\n");
          163                         break;
          164                 }
          165 
          166                 /* pick off messages one by one */
          167                 if(convM2W(mbuf, nn+4, &m) <= 0) {
          168                         fprint(2, "serveproc: cannot convert message\n");
          169                         break;
          170                 }
          171                 if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
          172                 runmsg(c, &m);
          173         }
          174 
          175         if(c == client0) {
          176                 rpc_shutdown();
          177                 threadexitsall(nil);
          178         }
          179 }
          180 
          181 static void
          182 replyerror(Client *c, Wsysmsg *m)
          183 {
          184         char err[256];
          185 
          186         rerrstr(err, sizeof err);
          187         m->type = Rerror;
          188         m->error = err;
          189         replymsg(c, m);
          190 }
          191 
          192 /*
          193  * Handle a single wsysmsg.
          194  * Might queue for later (kbd, mouse read)
          195  */
          196 static void
          197 runmsg(Client *c, Wsysmsg *m)
          198 {
          199         static uchar buf[65536];
          200         int n;
          201         Memimage *i;
          202 
          203         switch(m->type){
          204         case Tctxt:
          205                 c->wsysid = strdup(m->id);
          206                 replymsg(c, m);
          207                 break;
          208 
          209         case Tinit:
          210                 i = rpc_attach(c, m->label, m->winsize);
          211                 if(i == nil) {
          212                         replyerror(c, m);
          213                         break;
          214                 }
          215                 draw_initdisplaymemimage(c, i);
          216                 replymsg(c, m);
          217                 break;
          218 
          219         case Trdmouse:
          220                 qlock(&c->eventlk);
          221                 if((c->mousetags.wi+1)%nelem(c->mousetags.t) == c->mousetags.ri) {
          222                         qunlock(&c->eventlk);
          223                         werrstr("too many queued mouse reads");
          224                         replyerror(c, m);
          225                         break;
          226                 }
          227                 c->mousetags.t[c->mousetags.wi++] = m->tag;
          228                 if(c->mousetags.wi == nelem(c->mousetags.t))
          229                         c->mousetags.wi = 0;
          230                 c->mouse.stall = 0;
          231                 matchmouse(c);
          232                 qunlock(&c->eventlk);
          233                 break;
          234 
          235         case Trdkbd:
          236         case Trdkbd4:
          237                 qlock(&c->eventlk);
          238                 if((c->kbdtags.wi+1)%nelem(c->kbdtags.t) == c->kbdtags.ri) {
          239                         qunlock(&c->eventlk);
          240                         werrstr("too many queued keyboard reads");
          241                         replyerror(c, m);
          242                         break;
          243                 }
          244                 c->kbdtags.t[c->kbdtags.wi++] = (m->tag<<1) | (m->type==Trdkbd4);
          245                 if(c->kbdtags.wi == nelem(c->kbdtags.t))
          246                         c->kbdtags.wi = 0;
          247                 c->kbd.stall = 0;
          248                 matchkbd(c);
          249                 qunlock(&c->eventlk);
          250                 break;
          251 
          252         case Tmoveto:
          253                 c->impl->rpc_setmouse(c, m->mouse.xy);
          254                 replymsg(c, m);
          255                 break;
          256 
          257         case Tcursor:
          258                 if(m->arrowcursor)
          259                         c->impl->rpc_setcursor(c, nil, nil);
          260                 else {
          261                         scalecursor(&m->cursor2, &m->cursor);
          262                         c->impl->rpc_setcursor(c, &m->cursor, &m->cursor2);
          263                 }
          264                 replymsg(c, m);
          265                 break;
          266 
          267         case Tcursor2:
          268                 if(m->arrowcursor)
          269                         c->impl->rpc_setcursor(c, nil, nil);
          270                 else
          271                         c->impl->rpc_setcursor(c, &m->cursor, &m->cursor2);
          272                 replymsg(c, m);
          273                 break;
          274 
          275         case Tbouncemouse:
          276                 c->impl->rpc_bouncemouse(c, m->mouse);
          277                 replymsg(c, m);
          278                 break;
          279 
          280         case Tlabel:
          281                 c->impl->rpc_setlabel(c, m->label);
          282                 replymsg(c, m);
          283                 break;
          284 
          285         case Trdsnarf:
          286                 m->snarf = rpc_getsnarf();
          287                 replymsg(c, m);
          288                 free(m->snarf);
          289                 break;
          290 
          291         case Twrsnarf:
          292                 rpc_putsnarf(m->snarf);
          293                 replymsg(c, m);
          294                 break;
          295 
          296         case Trddraw:
          297                 n = m->count;
          298                 if(n > sizeof buf)
          299                         n = sizeof buf;
          300                 n = draw_dataread(c, buf, n);
          301                 if(n < 0)
          302                         replyerror(c, m);
          303                 else{
          304                         m->count = n;
          305                         m->data = buf;
          306                         replymsg(c, m);
          307                 }
          308                 break;
          309 
          310         case Twrdraw:
          311                 if(draw_datawrite(c, m->data, m->count) < 0)
          312                         replyerror(c, m);
          313                 else
          314                         replymsg(c, m);
          315                 break;
          316 
          317         case Ttop:
          318                 c->impl->rpc_topwin(c);
          319                 replymsg(c, m);
          320                 break;
          321 
          322         case Tresize:
          323                 c->impl->rpc_resizewindow(c, m->rect);
          324                 replymsg(c, m);
          325                 break;
          326         }
          327 }
          328 
          329 /*
          330  * Reply to m.
          331  */
          332 static void
          333 replymsg(Client *c, Wsysmsg *m)
          334 {
          335         int n;
          336 
          337         /* T -> R msg */
          338         if(m->type%2 == 0)
          339                 m->type++;
          340 
          341         if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
          342         /* copy to output buffer */
          343         n = sizeW2M(m);
          344 
          345         qlock(&c->wfdlk);
          346         if(n > c->nmbuf){
          347                 free(c->mbuf);
          348                 c->mbuf = malloc(n);
          349                 if(c->mbuf == nil)
          350                         sysfatal("out of memory");
          351                 c->nmbuf = n;
          352         }
          353         convW2M(m, c->mbuf, n);
          354         if(write(c->wfd, c->mbuf, n) != n)
          355                 fprint(2, "client write: %r\n");
          356         qunlock(&c->wfdlk);
          357 }
          358 
          359 /*
          360  * Match queued kbd reads with queued kbd characters.
          361  */
          362 static void
          363 matchkbd(Client *c)
          364 {
          365         int tag;
          366         Wsysmsg m;
          367 
          368         if(c->kbd.stall)
          369                 return;
          370         while(c->kbd.ri != c->kbd.wi && c->kbdtags.ri != c->kbdtags.wi){
          371                 tag = c->kbdtags.t[c->kbdtags.ri++];
          372                 m.type = Rrdkbd;
          373                 if(tag&1)
          374                         m.type = Rrdkbd4;
          375                 m.tag = tag>>1;
          376                 if(c->kbdtags.ri == nelem(c->kbdtags.t))
          377                         c->kbdtags.ri = 0;
          378                 m.rune = c->kbd.r[c->kbd.ri++];
          379                 if(c->kbd.ri == nelem(c->kbd.r))
          380                         c->kbd.ri = 0;
          381                 replymsg(c, &m);
          382         }
          383 }
          384 
          385 // matchmouse matches queued mouse reads with queued mouse events.
          386 // It must be called with c->eventlk held.
          387 static void
          388 matchmouse(Client *c)
          389 {
          390         Wsysmsg m;
          391 
          392         if(canqlock(&c->eventlk)) {
          393                 fprint(2, "misuse of matchmouse\n");
          394                 abort();
          395         }
          396 
          397         while(c->mouse.ri != c->mouse.wi && c->mousetags.ri != c->mousetags.wi){
          398                 m.type = Rrdmouse;
          399                 m.tag = c->mousetags.t[c->mousetags.ri++];
          400                 if(c->mousetags.ri == nelem(c->mousetags.t))
          401                         c->mousetags.ri = 0;
          402                 m.mouse = c->mouse.m[c->mouse.ri];
          403                 m.resized = c->mouse.resized;
          404                 c->mouse.resized = 0;
          405                 /*
          406                 if(m.resized)
          407                         fprint(2, "sending resize\n");
          408                 */
          409                 c->mouse.ri++;
          410                 if(c->mouse.ri == nelem(c->mouse.m))
          411                         c->mouse.ri = 0;
          412                 replymsg(c, &m);
          413         }
          414 }
          415 
          416 void
          417 gfx_mouseresized(Client *c)
          418 {
          419         gfx_mousetrack(c, -1, -1, -1, -1);
          420 }
          421 
          422 void
          423 gfx_mousetrack(Client *c, int x, int y, int b, uint ms)
          424 {
          425         Mouse *m;
          426 
          427         qlock(&c->eventlk);
          428         if(x == -1 && y == -1 && b == -1 && ms == -1) {
          429                 Mouse *copy;
          430                 // repeat last mouse event for resize
          431                 if(c->mouse.ri == 0)
          432                         copy = &c->mouse.m[nelem(c->mouse.m)-1];
          433                 else
          434                         copy = &c->mouse.m[c->mouse.ri-1];
          435                 x = copy->xy.x;
          436                 y = copy->xy.y;
          437                 b = copy->buttons;
          438                 ms = copy->msec;
          439                 c->mouse.resized = 1;
          440         }
          441         if(x < c->mouserect.min.x)
          442                 x = c->mouserect.min.x;
          443         if(x > c->mouserect.max.x)
          444                 x = c->mouserect.max.x;
          445         if(y < c->mouserect.min.y)
          446                 y = c->mouserect.min.y;
          447         if(y > c->mouserect.max.y)
          448                 y = c->mouserect.max.y;
          449 
          450         // If reader has stopped reading, don't bother.
          451         // If reader is completely caught up, definitely queue.
          452         // Otherwise, queue only button change events.
          453         if(!c->mouse.stall)
          454         if(c->mouse.wi == c->mouse.ri || c->mouse.last.buttons != b){
          455                 m = &c->mouse.last;
          456                 m->xy.x = x;
          457                 m->xy.y = y;
          458                 m->buttons = b;
          459                 m->msec = ms;
          460 
          461                 c->mouse.m[c->mouse.wi] = *m;
          462                 if(++c->mouse.wi == nelem(c->mouse.m))
          463                         c->mouse.wi = 0;
          464                 if(c->mouse.wi == c->mouse.ri){
          465                         c->mouse.stall = 1;
          466                         c->mouse.ri = 0;
          467                         c->mouse.wi = 1;
          468                         c->mouse.m[0] = *m;
          469                 }
          470                 matchmouse(c);
          471         }
          472         qunlock(&c->eventlk);
          473 }
          474 
          475 // kputc adds ch to the keyboard buffer.
          476 // It must be called with c->eventlk held.
          477 static void
          478 kputc(Client *c, int ch)
          479 {
          480         if(canqlock(&c->eventlk)) {
          481                 fprint(2, "misuse of kputc\n");
          482                 abort();
          483         }
          484 
          485         c->kbd.r[c->kbd.wi++] = ch;
          486         if(c->kbd.wi == nelem(c->kbd.r))
          487                 c->kbd.wi = 0;
          488         if(c->kbd.ri == c->kbd.wi)
          489                 c->kbd.stall = 1;
          490         matchkbd(c);
          491 }
          492 
          493 // gfx_abortcompose stops any pending compose sequence,
          494 // because a mouse button has been clicked.
          495 // It is called from the graphics thread with no locks held.
          496 void
          497 gfx_abortcompose(Client *c)
          498 {
          499         qlock(&c->eventlk);
          500         if(c->kbd.alting) {
          501                 c->kbd.alting = 0;
          502                 c->kbd.nk = 0;
          503         }
          504         qunlock(&c->eventlk);
          505 }
          506 
          507 // gfx_keystroke records a single-rune keystroke.
          508 // It is called from the graphics thread with no locks held.
          509 void
          510 gfx_keystroke(Client *c, int ch)
          511 {
          512         int i;
          513 
          514         qlock(&c->eventlk);
          515         if(ch == Kalt){
          516                 c->kbd.alting = !c->kbd.alting;
          517                 c->kbd.nk = 0;
          518                 qunlock(&c->eventlk);
          519                 return;
          520         }
          521         if(ch == Kcmd+'r') {
          522                 if(c->forcedpi)
          523                         c->forcedpi = 0;
          524                 else if(c->displaydpi >= 200)
          525                         c->forcedpi = 100;
          526                 else
          527                         c->forcedpi = 225;
          528                 qunlock(&c->eventlk);
          529                 c->impl->rpc_resizeimg(c);
          530                 return;
          531         }
          532         if(!c->kbd.alting){
          533                 kputc(c, ch);
          534                 qunlock(&c->eventlk);
          535                 return;
          536         }
          537         if(c->kbd.nk >= nelem(c->kbd.k))      // should not happen
          538                 c->kbd.nk = 0;
          539         c->kbd.k[c->kbd.nk++] = ch;
          540         ch = latin1(c->kbd.k, c->kbd.nk);
          541         if(ch > 0){
          542                 c->kbd.alting = 0;
          543                 kputc(c, ch);
          544                 c->kbd.nk = 0;
          545                 qunlock(&c->eventlk);
          546                 return;
          547         }
          548         if(ch == -1){
          549                 c->kbd.alting = 0;
          550                 for(i=0; i<c->kbd.nk; i++)
          551                         kputc(c, c->kbd.k[i]);
          552                 c->kbd.nk = 0;
          553                 qunlock(&c->eventlk);
          554                 return;
          555         }
          556         // need more input
          557         qunlock(&c->eventlk);
          558         return;
          559 }