tdevdraw: multiclient mode - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 892b3c4687eacf6b090bb9a5196ce882e113c423
 (DIR) parent 2cb85891ba58a83263ef30dc9799d1fda9fb71af
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Sat, 11 Jan 2020 06:10:14 -0500
       
       devdraw: multiclient mode
       
       Diffstat:
         M src/cmd/devdraw/devdraw.h           |       3 +++
         M src/cmd/devdraw/mac-screen.m        |      15 ++++++++-------
         M src/cmd/devdraw/srv.c               |     139 +++++++++++++++++++++++--------
       
       3 files changed, 115 insertions(+), 42 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/devdraw/devdraw.h b/src/cmd/devdraw/devdraw.h
       t@@ -54,6 +54,8 @@ struct Client
                uchar*        mbuf;
                int                nmbuf;
        
       +        char*        wsysid;
       +
                // drawlk protects the draw data structures.
                // It can be acquired by an RPC thread or a graphics thread
                // but must not be held on one thread while waiting for the other.
       t@@ -219,3 +221,4 @@ int latin1(Rune*, int);
        int mouseswap(int);
        int parsewinsize(char*, Rectangle*, int*);
        
       +extern Client *client0; // set in single-client mode
 (DIR) diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m
       t@@ -30,6 +30,8 @@ AUTOFRAMEWORK(QuartzCore)
        
        #define LOG        if(0)NSLog
        
       +// TODO: Maintain list of views for dock menu.
       +
        static void setprocname(const char*);
        static uint keycvt(uint);
        static uint msec(void);
       t@@ -45,7 +47,8 @@ static AppDelegate *myApp = NULL;
        void
        gfx_main(void)
        {
       -        setprocname(argv0);
       +        if(client0)
       +                setprocname(argv0);
        
                @autoreleasepool{
                        [NSApplication sharedApplication];
       t@@ -99,7 +102,7 @@ rpc_shutdown(void)
        }
        
        - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
       -        return YES;
       +        return client0 != nil;
        }
        @end
        
       t@@ -232,10 +235,7 @@ rpc_attach(Client *c, char *label, char *winsize)
                r = [[NSScreen mainScreen] visibleFrame];
        
                LOG(@"makewin(%s)", s);
       -        if(s && *s){
       -                if(parsewinsize(s, &wr, &set) < 0)
       -                        sysfatal("%r");
       -        }else{
       +        if(s == nil || *s == '\0' || parsewinsize(s, &wr, &set) < 0) {
                        wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
                        set = 0;
                }
       t@@ -344,7 +344,8 @@ rpc_setlabel(Client *client, char *label)
                @autoreleasepool{
                        NSString *s = [[NSString alloc] initWithUTF8String:label];
                        [self.win setTitle:s];
       -                [[NSApp dockTile] setBadgeLabel:s]; // TODO: Not with multiple windows
       +                if(client0)
       +                        [[NSApp dockTile] setBadgeLabel:s];
                }
        }
        
 (DIR) diff --git a/src/cmd/devdraw/srv.c b/src/cmd/devdraw/srv.c
       t@@ -18,10 +18,14 @@ static void runmsg(Client*, Wsysmsg*);
        static void replymsg(Client*, Wsysmsg*);
        static void matchkbd(Client*);
        static void matchmouse(Client*);
       -static void serve(void*);
       -static Client *client0;
       +static void serveproc(void*);
       +static void listenproc(void*);
       +Client *client0;
        
        int trace = 0;
       +static char *srvname;
       +static int afd;
       +static char adir[40];
        
        static void
        usage(void)
       t@@ -33,17 +37,6 @@ usage(void)
        void
        threadmain(int argc, char **argv)
        {
       -        /*
       -         * Move the protocol off stdin/stdout so that
       -         * any inadvertent prints don't screw things up.
       -         */
       -        dup(0,3);
       -        dup(1,4);
       -        close(0);
       -        close(1);
       -        open("/dev/null", OREAD);
       -        open("/dev/null", OWRITE);
       -
                ARGBEGIN{
                case 'D':                /* for good ps -a listings */
                        break;
       t@@ -51,32 +44,89 @@ threadmain(int argc, char **argv)
                case 'g':
                case 'b':
                        break;
       +        case 's':
       +                // TODO: Update usage, man page.
       +                srvname = EARGF(usage());
       +                break;
                default:
                        usage();
                }ARGEND
        
       -        fmtinstall('W', drawfcallfmt);
       +        if(srvname == nil) {
       +                client0 = mallocz(sizeof(Client), 1);
       +                if(client0 == nil){
       +                        fprint(2, "initdraw: allocating client0: out of memory");
       +                        abort();
       +                }
       +                client0->displaydpi = 100;
       +                client0->rfd = 3;
       +                client0->wfd = 4;
        
       -        client0 = mallocz(sizeof(Client), 1);
       -        if(client0 == nil){
       -                fprint(2, "initdraw: allocating client0: out of memory");
       -                abort();
       +                /*
       +                 * Move the protocol off stdin/stdout so that
       +                 * any inadvertent prints don't screw things up.
       +                 */
       +                dup(0,3);
       +                dup(1,4);
       +                close(0);
       +                close(1);
       +                open("/dev/null", OREAD);
       +                open("/dev/null", OWRITE);
                }
       -        client0->displaydpi = 100;
       -        client0->rfd = 3;
       -        client0->wfd = 4;
        
       +        fmtinstall('W', drawfcallfmt);
                gfx_main();
        }
        
        void
        gfx_started(void)
        {
       -        proccreate(serve, client0, 0);
       +        char *addr;
       +
       +        if(srvname == nil) {
       +                // Legacy mode: serving single client on pipes.
       +                proccreate(serveproc, client0, 0);
       +                return;
       +        }
       +
       +        // Server mode.
       +        addr = smprint("unix!%s/%s", getns(), srvname);
       +        if(addr == nil)
       +                sysfatal("out of memory");
       +
       +        if((afd = announce(addr, adir)) < 0)
       +                sysfatal("announce %s: %r", addr);
       +
       +        proccreate(listenproc, nil, 0);
       +}
       +
       +static void
       +listenproc(void *v)
       +{
       +        Client *c;
       +        int fd;
       +        char dir[40];
       +
       +        USED(v);
       +
       +        for(;;) {
       +                fd = listen(adir, dir);
       +                if(fd < 0)
       +                        sysfatal("listen: %r");
       +                c = mallocz(sizeof(Client), 1);
       +                if(c == nil){
       +                        fprint(2, "initdraw: allocating client0: out of memory");
       +                        abort();
       +                }
       +                c->displaydpi = 100;
       +                c->rfd = fd;
       +                c->wfd = fd;
       +                proccreate(serveproc, c, 0);
       +        }
        }
        
        static void
       -serve(void *v)
       +serveproc(void *v)
        {
                Client *c;
                uchar buf[4], *mbuf;
       t@@ -92,23 +142,29 @@ serve(void *v)
                                free(mbuf);
                                mbuf = malloc(4+n);
                                if(mbuf == nil)
       -                                sysfatal("malloc: %r");
       +                                sysfatal("out of memory");
                                nmbuf = n;
                        }
                        memmove(mbuf, buf, 4);
                        nn = readn(c->rfd, mbuf+4, n-4);
       -                if(nn != n-4)
       -                        sysfatal("eof during message");
       +                if(nn != n-4) {
       +                        fprint(2, "serveproc: eof during message\n");
       +                        break;
       +                }
        
                        /* pick off messages one by one */
       -                if(convM2W(mbuf, nn+4, &m) <= 0)
       -                        sysfatal("cannot convert message");
       +                if(convM2W(mbuf, nn+4, &m) <= 0) {
       +                        fprint(2, "serveproc: cannot convert message\n");
       +                        break;
       +                }
                        if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
                        runmsg(c, &m);
                }
        
       -        rpc_shutdown();
       -        threadexitsall(nil);
       +        if(c == client0) {
       +                rpc_shutdown();
       +                threadexitsall(nil);
       +        }
        }
        
        static void
       t@@ -134,6 +190,11 @@ runmsg(Client *c, Wsysmsg *m)
                Memimage *i;
        
                switch(m->type){
       +        case Tctxt:
       +                c->wsysid = strdup(m->id);
       +                replymsg(c, m);
       +                break;
       +
                case Tinit:
                        memimageinit();
                        i = rpc_attach(c, m->label, m->winsize);
       t@@ -143,11 +204,15 @@ runmsg(Client *c, Wsysmsg *m)
        
                case Trdmouse:
                        qlock(&c->eventlk);
       +                if((c->mousetags.wi+1)%nelem(c->mousetags.t) == c->mousetags.ri) {
       +                        qunlock(&c->eventlk);
       +                        werrstr("too many queued mouse reads");
       +                        replyerror(c, m);
       +                        break;
       +                }
                        c->mousetags.t[c->mousetags.wi++] = m->tag;
                        if(c->mousetags.wi == nelem(c->mousetags.t))
                                c->mousetags.wi = 0;
       -                if(c->mousetags.wi == c->mousetags.ri)
       -                        sysfatal("too many queued mouse reads");
                        c->mouse.stall = 0;
                        matchmouse(c);
                        qunlock(&c->eventlk);
       t@@ -155,11 +220,15 @@ runmsg(Client *c, Wsysmsg *m)
        
                case Trdkbd:
                        qlock(&c->eventlk);
       +                if((c->kbdtags.wi+1)%nelem(c->kbdtags.t) == c->kbdtags.ri) {
       +                        qunlock(&c->eventlk);
       +                        werrstr("too many queued keyboard reads");
       +                        replyerror(c, m);
       +                        break;
       +                }
                        c->kbdtags.t[c->kbdtags.wi++] = m->tag;
                        if(c->kbdtags.wi == nelem(c->kbdtags.t))
                                c->kbdtags.wi = 0;
       -                if(c->kbdtags.wi == c->kbdtags.ri)
       -                        sysfatal("too many queued keyboard reads");
                        c->kbd.stall = 0;
                        matchkbd(c);
                        qunlock(&c->eventlk);
       t@@ -268,7 +337,7 @@ replymsg(Client *c, Wsysmsg *m)
                }
                convW2M(m, c->mbuf, n);
                if(write(c->wfd, c->mbuf, n) != n)
       -                sysfatal("write: %r");
       +                fprint(2, "client write: %r\n");
                qunlock(&c->wfdlk);
        }