tdevdraw: x11 working again - 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 50923426bf684402160dd7748f14560afd447b73
 (DIR) parent 892b3c4687eacf6b090bb9a5196ce882e113c423
 (HTM) Author: Russ Cox <rsc@golang.org>
       Date:   Sun, 12 Jan 2020 14:53:46 -0500
       
       devdraw: x11 working again
       
       Need to think a bit more about locking,
       but overall it's a working devdraw.
       
       Multiclient mode may not be working
       but nothing is using it yet.
       
       Diffstat:
         M src/cmd/devdraw/devdraw.c           |       7 +++++++
         M src/cmd/devdraw/devdraw.h           |      15 ++++++++++-----
         M src/cmd/devdraw/mac-screen.m        |      54 +++++++++++++++++++++----------
         M src/cmd/devdraw/mkfile              |       5 +----
         D src/cmd/devdraw/snarf.c             |     109 -------------------------------
         M src/cmd/devdraw/srv.c               |       2 +-
         M src/cmd/devdraw/x11-alloc.c         |       4 ++--
         M src/cmd/devdraw/x11-inc.h           |       2 --
         D src/cmd/devdraw/x11-init.c          |     738 ------------------------------
         D src/cmd/devdraw/x11-itrans.c        |     741 -------------------------------
         M src/cmd/devdraw/x11-memdraw.h       |      66 +++++++++++++------------------
         A src/cmd/devdraw/x11-screen.c        |    1759 +++++++++++++++++++++++++++++++
         D src/cmd/devdraw/x11-srv.c           |     637 -------------------------------
         D src/cmd/devdraw/x11-wsys.c          |      45 -------------------------------
       
       14 files changed, 1844 insertions(+), 2340 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/devdraw/devdraw.c b/src/cmd/devdraw/devdraw.c
       t@@ -144,9 +144,11 @@ addflush(Client *c, Rectangle r)
                        // Unlock drawlk because rpc_flush may want to run on gfx thread,
                        // and gfx thread might be blocked on drawlk trying to install a new screen
                        // during a resize.
       +                rpc_gfxdrawunlock();
                        qunlock(&c->drawlk);
                        rpc_flush(c, fr);
                        qlock(&c->drawlk);
       +                rpc_gfxdrawlock();
                }
        }
        
       t@@ -187,9 +189,11 @@ drawflush(Client *c)
                        // Unlock drawlk because rpc_flush may want to run on gfx thread,
                        // and gfx thread might be blocked on drawlk trying to install a new screen
                        // during a resize.
       +                rpc_gfxdrawunlock();
                        qunlock(&c->drawlk);
                        rpc_flush(c, r);
                        qlock(&c->drawlk);
       +                rpc_gfxdrawlock();
                }
        }
        
       t@@ -656,6 +660,7 @@ draw_datawrite(Client *client, void *v, int n)
                Refx *refx;
        
                qlock(&client->drawlk);
       +        rpc_gfxdrawlock();
                a = v;
                m = 0;
                oldn = n;
       t@@ -1428,6 +1433,7 @@ draw_datawrite(Client *client, void *v, int n)
                                continue;
                        }
                }
       +        rpc_gfxdrawunlock();
                qunlock(&client->drawlk);
                return oldn - n;
        
       t@@ -1498,6 +1504,7 @@ Ebadarg:
        
        error:
                werrstr("%s", err);
       +        rpc_gfxdrawunlock();
                qunlock(&client->drawlk);
                return -1;
        }
 (DIR) diff --git a/src/cmd/devdraw/devdraw.h b/src/cmd/devdraw/devdraw.h
       t@@ -85,7 +85,7 @@ struct Client
        
                // Only accessed/modified by the graphics thread.
                const void*                view;
       -        
       +
                // eventlk protects the keyboard and mouse events.
                QLock eventlk;
                Kbdbuf kbd;
       t@@ -204,14 +204,19 @@ void        rpc_setmouse(Client*, Point);
        void        rpc_shutdown(void);
        void        rpc_topwin(Client*);
        void        rpc_main(void);
       -
       -// TODO: rpc_flush is called from draw_datawrite,
       -// which holds c->drawlk. Is this OK?
       +void        rpc_bouncemouse(Client*, Mouse);
        void        rpc_flush(Client*, Rectangle);
        
       +// rpc_gfxdrawlock and rpc_gfxdrawunlock
       +// are called around drawing operations to lock and unlock
       +// access to the graphics display, for systems where the
       +// individual memdraw operations use the graphics display (X11, not macOS).
       +void rpc_gfxdrawlock(void);
       +void rpc_gfxdrawunlock(void);
       +
        // draw* routines are called on the RPC thread,
        // invoked by the RPC server to do pixel pushing.
       -// c->drawlk is held on entry.
       +// No locks are held on entry.
        int draw_dataread(Client*, void*, int);
        int draw_datawrite(Client*, void*, int);
        void draw_initdisplaymemimage(Client*, Memimage*);
 (DIR) diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m
       t@@ -88,7 +88,7 @@ rpc_shutdown(void)
                i = [[NSImage alloc] initWithData:d];
                [NSApp setApplicationIconImage:i];
                [[NSApp dockTile] display];
       -        
       +
                gfx_started();
        }
        
       t@@ -124,9 +124,9 @@ rpc_shutdown(void)
                                [self setNeedsDisplay];
                                return;
                        }
       -        
       +
                        LOG(@"display got drawable");
       -        
       +
                        id<MTLCommandBuffer> cbuf = [self.cmd commandBuffer];
                        id<MTLBlitCommandEncoder> blit = [cbuf blitCommandEncoder];
                        [blit copyFromTexture:self.texture
       t@@ -139,7 +139,7 @@ rpc_shutdown(void)
                                destinationLevel:0
                                destinationOrigin:MTLOriginMake(0, 0, 0)];
                        [blit endEncoding];
       -        
       +
                        [cbuf presentDrawable:drawable];
                        drawable = nil;
                        [cbuf addCompletedHandler:^(id<MTLCommandBuffer> cmdBuff){
       t@@ -208,7 +208,7 @@ Memimage*
        rpc_attach(Client *c, char *label, char *winsize)
        {
                LOG(@"attachscreen(%s, %s)", label, winsize);
       -        
       +
                dispatch_sync(dispatch_get_main_queue(), ^(void) {
                        @autoreleasepool {
                                DrawView *view = [[DrawView new] attach:c winsize:winsize label:label];
       t@@ -268,7 +268,7 @@ rpc_attach(Client *c, char *label, char *winsize)
                [win setDelegate:self];
                [self setWantsLayer:YES];
                [self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
       -        
       +
                id<MTLDevice> device = nil;
                allDevices = MTLCopyAllDevices();
                for(id mtlDevice in allDevices) {
       t@@ -304,7 +304,7 @@ rpc_attach(Client *c, char *label, char *winsize)
                [self topwin];
                [self setlabel:label];
                [self setcursor:nil cursor2:nil];
       -        
       +
                return self;
        }
        
       t@@ -430,18 +430,18 @@ rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
                        CGFloat scale;
                        NSSize size;
                        MTLTextureDescriptor *textureDesc;
       -        
       +
                        size = [self convertSizeToBacking:[self bounds].size];
                        self.client->mouserect = Rect(0, 0, size.width, size.height);
       -        
       +
                        LOG(@"initimg %.0f %.0f", size.width, size.height);
       -        
       +
                        self.img = allocmemimage(self.client->mouserect, XRGB32);
                        if(self.img == nil)
                                panic("allocmemimage: %r");
                        if(self.img->data == nil)
                                panic("img->data == nil");
       -        
       +
                        textureDesc = [MTLTextureDescriptor
                                texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
                                width:size.width
       t@@ -451,11 +451,11 @@ rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
                        textureDesc.usage = MTLTextureUsageShaderRead;
                        textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
                        self.dlayer.texture = [self.dlayer.device newTextureWithDescriptor:textureDesc];
       -        
       +
                        scale = [self.win backingScaleFactor];
                        [self.dlayer setDrawableSize:size];
                        [self.dlayer setContentsScale:scale];
       -        
       +
                        // NOTE: This is not really the display DPI.
                        // On retina, scale is 2; otherwise it is 1.
                        // This formula gives us 220 for retina, 110 otherwise.
       t@@ -481,7 +481,7 @@ rpc_flush(Client *client, Rectangle r)
                @autoreleasepool{
                        if(!rectclip(&r, Rect(0, 0, self.dlayer.texture.width, self.dlayer.texture.height)) || !rectclip(&r, self.img->r))
                                return;
       -                
       +
                        // self.client->drawlk protects the pixel data in self.img.
                        // In addition to avoiding a technical data race,
                        // the lock avoids drawing partial updates, which makes
       t@@ -501,12 +501,12 @@ rpc_flush(Client *client, Rectangle r)
                        nr = [self.win convertRectFromBacking:nr];
                        LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", nr.origin.x, nr.origin.y, nr.size.width, nr.size.height);
                        [self.dlayer setNeedsDisplayInRect:nr];
       -        
       +
                        time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC);
                        dispatch_after(time, dispatch_get_main_queue(), ^(void){
                                [self.dlayer setNeedsDisplayInRect:nr];
                        });
       -        
       +
                        [self enlargeLastInputRect:nr];
                }
        }
       t@@ -1031,7 +1031,7 @@ char*
        rpc_getsnarf(void)
        {
                char __block *ret;
       -        
       +
                ret = nil;
                dispatch_sync(dispatch_get_main_queue(), ^(void) {
                        @autoreleasepool {
       t@@ -1063,6 +1063,26 @@ rpc_putsnarf(char *s)
                });
        }
        
       +// rpc_bouncemouse is for sending a mouse event
       +// back to the X11 window manager rio(1).
       +// Does not apply here.
       +void
       +rpc_bouncemouse(Client *c, Mouse m)
       +{
       +}
       +
       +// We don't use the graphics thread state during memimagedraw,
       +// so rpc_gfxdrawlock and rpc_gfxdrawunlock are no-ops.
       +void
       +rpc_gfxdrawlock(void)
       +{
       +}
       +
       +void
       +rpc_gfxdrawunlock(void)
       +{
       +}
       +
        static void
        setprocname(const char *s)
        {
 (DIR) diff --git a/src/cmd/devdraw/mkfile b/src/cmd/devdraw/mkfile
       t@@ -28,9 +28,6 @@ HFILES=\
        $O.drawclient: drawclient.$O
                $LD -o $target $prereq
        
       -$O.snarf: x11-alloc.$O x11-cload.$O x11-draw.$O x11-fill.$O x11-get.$O x11-init.$O x11-itrans.$O x11-keysym2ucs.$O x11-load.$O x11-pixelbits.$O x11-unload.$O x11-wsys.$O snarf.$O latin1.$O devdraw.$O
       -        $LD -o $target $prereq
       -
        $O.mklatinkbd: mklatinkbd.$O
                $LD -o $target $prereq
        
       t@@ -48,7 +45,7 @@ $O.macargv: $MACARGV
        CLEANFILES=$O.devdraw $O.macargv $O.drawclient $O.mklatinkbd latin1.h
        
        install: mklatinkbd.install
       -install:Q: 
       +install:Q:
                if [ $MACARGV ]; then
                        mk $MKFLAGS macargv.install
                fi
 (DIR) diff --git a/src/cmd/devdraw/snarf.c b/src/cmd/devdraw/snarf.c
       t@@ -1,109 +0,0 @@
       -#include <u.h>
       -#include <sys/select.h>
       -#include <errno.h>
       -#include "x11-inc.h"
       -#include <libc.h>
       -#include <draw.h>
       -#include <memdraw.h>
       -#include <memlayer.h>
       -#include <keyboard.h>
       -#include <mouse.h>
       -#include <cursor.h>
       -#include <drawfcall.h>
       -#include "x11-memdraw.h"
       -#include "devdraw.h"
       -
       -#undef time
       -
       -#define MouseMask (\
       -        ButtonPressMask|\
       -        ButtonReleaseMask|\
       -        PointerMotionMask|\
       -        Button1MotionMask|\
       -        Button2MotionMask|\
       -        Button3MotionMask)
       -
       -#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask
       -
       -void runxevent(XEvent*);
       -
       -void
       -usage(void)
       -{
       -        fprint(2, "usage: snarf [-a] [-o | text]\n");
       -        exits("usage");
       -}
       -
       -void
       -main(int argc, char **argv)
       -{
       -        int apple;
       -        int out;
       -
       -        apple = 0;
       -        out = 0;
       -
       -        ARGBEGIN{
       -        case 'a':
       -                apple = 1;
       -                break;
       -        case 'o':
       -                out = 1;
       -                break;
       -        default:
       -                usage();
       -        }ARGEND
       -
       -        if(out && argc != 0)
       -                usage();
       -        if(!out && argc != 1)
       -                usage();
       -
       -        _x.fd = -1;
       -
       -        memimageinit();
       -        _xattach("snarf", "20x20");
       -
       -        XSelectInput(_x.display, _x.drawable, Mask);
       -        XFlush(_x.display);
       -
       -        if(out){
       -                char *s;
       -                if(apple)
       -                        s = _applegetsnarf();
       -                else
       -                        s = _xgetsnarf();
       -                write(1, s, strlen(s));
       -                write(1, "\n", 1);
       -                exits(0);
       -        }else{
       -                _xputsnarf(argv[0]);
       -                for(;;){
       -                        XEvent event;
       -                        XNextEvent(_x.display, &event);
       -                        runxevent(&event);
       -                }
       -        }
       -}
       -
       -/*
       - * Handle an incoming X event.
       - */
       -void
       -runxevent(XEvent *xev)
       -{
       -        switch(xev->type){
       -        case Expose:
       -                _xexpose(xev);
       -                break;
       -
       -        case DestroyNotify:
       -                if(_xdestroy(xev))
       -                        exits(0);
       -                break;
       -
       -        case SelectionRequest:
       -                _xselect(xev);
       -                break;
       -        }
       -}
 (DIR) diff --git a/src/cmd/devdraw/srv.c b/src/cmd/devdraw/srv.c
       t@@ -258,7 +258,7 @@ runmsg(Client *c, Wsysmsg *m)
                        break;
        
                case Tbouncemouse:
       -        //        _xbouncemouse(&m->mouse);
       +                rpc_bouncemouse(c, m->mouse);
                        replymsg(c, m);
                        break;
        
 (DIR) diff --git a/src/cmd/devdraw/x11-alloc.c b/src/cmd/devdraw/x11-alloc.c
       t@@ -21,7 +21,7 @@ _xallocmemimage(Rectangle r, u32int chan, int pixmap)
                m = _allocmemimage(r, chan);
                if(chan != GREY1 && chan != _x.chan)
                        return m;
       -        if(_x.display == 0)
       +        if(_x.display == 0 || _x.windows == nil)
                        return m;
        
                /*
       t@@ -49,7 +49,7 @@ _xallocmemimage(Rectangle r, u32int chan, int pixmap)
                if(pixmap != PMundef)
                        xm->pixmap = pixmap;
                else
       -                xm->pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), d);
       +                xm->pixmap = XCreatePixmap(_x.display, _x.windows->drawable, Dx(r), Dy(r), d);
        
                /*
                 * We want to align pixels on word boundaries.
 (DIR) diff --git a/src/cmd/devdraw/x11-inc.h b/src/cmd/devdraw/x11-inc.h
       t@@ -31,5 +31,3 @@
        #undef Screen
        #undef Visual
        #undef Window
       -
       -void        sendalt(void);
 (DIR) diff --git a/src/cmd/devdraw/x11-init.c b/src/cmd/devdraw/x11-init.c
       t@@ -1,738 +0,0 @@
       -/*
       - * Some of the stuff in this file is not X-dependent and should be elsewhere.
       - */
       -#include <u.h>
       -#include "x11-inc.h"
       -#include <libc.h>
       -#include <draw.h>
       -#include <memdraw.h>
       -#include <memlayer.h>
       -#include <keyboard.h>
       -#include <mouse.h>
       -#include <cursor.h>
       -#include "x11-memdraw.h"
       -#include "devdraw.h"
       -
       -static void        plan9cmap(void);
       -static int        setupcmap(XWindow);
       -static XGC        xgc(XDrawable, int, int);
       -
       -Xprivate _x;
       -
       -static int
       -xerror(XDisplay *d, XErrorEvent *e)
       -{
       -        char buf[200];
       -
       -        if(e->request_code == 42) /* XSetInputFocus */
       -                return 0;
       -        if(e->request_code == 18) /* XChangeProperty */
       -                return 0;
       -        /*
       -         * BadDrawable happens in apps that get resized a LOT,
       -         * e.g. when KDE is configured to resize continuously
       -         * during a window drag.
       -         */
       -        if(e->error_code == 9) /* BadDrawable */
       -                return 0;
       -
       -        fprint(2, "X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
       -                e->error_code, e->request_code, e->minor_code, d);
       -        XGetErrorText(d, e->error_code, buf, sizeof buf);
       -        fprint(2, "%s\n", buf);
       -        return 0;
       -}
       -
       -static int
       -xioerror(XDisplay *d)
       -{
       -        /*print("X I/O error\n"); */
       -        exit(0);
       -        /*sysfatal("X I/O error\n");*/
       -        abort();
       -        return -1;
       -}
       -
       -
       -Memimage*
       -_xattach(char *label, char *winsize)
       -{
       -        char *argv[2], *disp;
       -        int i, havemin, height, mask, n, width, x, xrootid, y;
       -        Rectangle r;
       -        XClassHint classhint;
       -        XDrawable pmid;
       -        XPixmapFormatValues *pfmt;
       -        XScreen *xscreen;
       -        XSetWindowAttributes attr;
       -        XSizeHints normalhint;
       -        XTextProperty name;
       -        XVisualInfo xvi;
       -        XWindow xrootwin;
       -        XWindowAttributes wattr;
       -        XWMHints hint;
       -        Atom atoms[2];
       -
       -        /*
       -        if(XInitThreads() == 0){
       -                fprint(2, "XInitThreads failed\n");
       -                abort();
       -        }
       -        */
       -
       -        /*
       -         * Connect to X server.
       -         */
       -        _x.display = XOpenDisplay(NULL);
       -        if(_x.display == nil){
       -                disp = getenv("DISPLAY");
       -                werrstr("XOpenDisplay %s: %r", disp ? disp : ":0");
       -                free(disp);
       -                return nil;
       -        }
       -        _x.fd = ConnectionNumber(_x.display);
       -        XSetErrorHandler(xerror);
       -        XSetIOErrorHandler(xioerror);
       -        xrootid = DefaultScreen(_x.display);
       -        xrootwin = DefaultRootWindow(_x.display);
       -
       -        /*
       -         * Figure out underlying screen format.
       -         */
       -        if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
       -        || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
       -                _x.vis = xvi.visual;
       -                _x.depth = 24;
       -        }
       -        else
       -        if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
       -        || XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
       -                _x.vis = xvi.visual;
       -                _x.depth = 16;
       -        }
       -        else
       -        if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
       -        || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
       -                _x.vis = xvi.visual;
       -                _x.depth = 15;
       -        }
       -        else
       -        if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
       -        || XMatchVisualInfo(_x.display, xrootid, 8, StaticColor, &xvi)){
       -                if(_x.depth > 8){
       -                        werrstr("can't deal with colormapped depth %d screens",
       -                                _x.depth);
       -                        goto err0;
       -                }
       -                _x.vis = xvi.visual;
       -                _x.depth = 8;
       -        }
       -        else{
       -                _x.depth = DefaultDepth(_x.display, xrootid);
       -                if(_x.depth != 8){
       -                        werrstr("can't understand depth %d screen", _x.depth);
       -                        goto err0;
       -                }
       -                _x.vis = DefaultVisual(_x.display, xrootid);
       -        }
       -
       -        if(DefaultDepth(_x.display, xrootid) == _x.depth)
       -                _x.usetable = 1;
       -
       -        /*
       -         * _x.depth is only the number of significant pixel bits,
       -         * not the total number of pixel bits.  We need to walk the
       -         * display list to find how many actual bits are used
       -         * per pixel.
       -         */
       -        _x.chan = 0;
       -        pfmt = XListPixmapFormats(_x.display, &n);
       -        for(i=0; i<n; i++){
       -                if(pfmt[i].depth == _x.depth){
       -                        switch(pfmt[i].bits_per_pixel){
       -                        case 1:        /* untested */
       -                                _x.chan = GREY1;
       -                                break;
       -                        case 2:        /* untested */
       -                                _x.chan = GREY2;
       -                                break;
       -                        case 4:        /* untested */
       -                                _x.chan = GREY4;
       -                                break;
       -                        case 8:
       -                                _x.chan = CMAP8;
       -                                break;
       -                        case 15:
       -                                _x.chan = RGB15;
       -                                break;
       -                        case 16: /* how to tell RGB15? */
       -                                _x.chan = RGB16;
       -                                break;
       -                        case 24: /* untested (impossible?) */
       -                                _x.chan = RGB24;
       -                                break;
       -                        case 32:
       -                                _x.chan = XRGB32;
       -                                break;
       -                        }
       -                }
       -        }
       -        XFree(pfmt);
       -        if(_x.chan == 0){
       -                werrstr("could not determine screen pixel format");
       -                goto err0;
       -        }
       -
       -        /*
       -         * Set up color map if necessary.
       -         */
       -        xscreen = DefaultScreenOfDisplay(_x.display);
       -        _x.cmap = DefaultColormapOfScreen(xscreen);
       -        if(_x.vis->class != StaticColor){
       -                plan9cmap();
       -                setupcmap(xrootwin);
       -        }
       -
       -        /*
       -         * We get to choose the initial rectangle size.
       -         * This is arbitrary.  In theory we should read the
       -         * command line and allow the traditional X options.
       -         */
       -        mask = 0;
       -        x = 0;
       -        y = 0;
       -        if(winsize && winsize[0]){
       -                if(parsewinsize(winsize, &r, &havemin) < 0)
       -                        sysfatal("%r");
       -        }else{
       -                /*
       -                 * Parse the various X resources.  Thanks to Peter Canning.
       -                 */
       -                char *screen_resources, *display_resources, *geom,
       -                        *geomrestype, *home, *file, *dpitype;
       -                XrmDatabase database;
       -                XrmValue geomres, dpires;
       -
       -                database = XrmGetDatabase(_x.display);
       -                screen_resources = XScreenResourceString(xscreen);
       -                if(screen_resources != nil){
       -                        XrmCombineDatabase(XrmGetStringDatabase(screen_resources), &database, False);
       -                        XFree(screen_resources);
       -                }
       -
       -                display_resources = XResourceManagerString(_x.display);
       -                if(display_resources == nil){
       -                        home = getenv("HOME");
       -                        if(home!=nil && (file=smprint("%s/.Xdefaults", home)) != nil){
       -                                XrmCombineFileDatabase(file, &database, False);
       -                                free(file);
       -                        }
       -                        free(home);
       -                }else
       -                        XrmCombineDatabase(XrmGetStringDatabase(display_resources), &database, False);
       -
       -                if (XrmGetResource(database, "Xft.dpi", "String", &dpitype, &dpires) == True) {
       -                        if (dpires.addr) {
       -                                client0->displaydpi = atoi(dpires.addr);
       -                        }
       -                }
       -                geom = smprint("%s.geometry", label);
       -                if(geom && XrmGetResource(database, geom, nil, &geomrestype, &geomres))
       -                        mask = XParseGeometry(geomres.addr, &x, &y, (uint*)&width, (uint*)&height);
       -                XrmDestroyDatabase(database);
       -                free(geom);
       -
       -                if((mask & WidthValue) && (mask & HeightValue)){
       -                        r = Rect(0, 0, width, height);
       -                }else{
       -                        r = Rect(0, 0, WidthOfScreen(xscreen)*3/4,
       -                                        HeightOfScreen(xscreen)*3/4);
       -                        if(Dx(r) > Dy(r)*3/2)
       -                                r.max.x = r.min.x + Dy(r)*3/2;
       -                        if(Dy(r) > Dx(r)*3/2)
       -                                r.max.y = r.min.y + Dx(r)*3/2;
       -                }
       -                if(mask & XNegative){
       -                        x += WidthOfScreen(xscreen);
       -                }
       -                if(mask & YNegative){
       -                        y += HeightOfScreen(xscreen);
       -                }
       -                havemin = 0;
       -        }
       -        screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen));
       -        windowrect = r;
       -
       -        memset(&attr, 0, sizeof attr);
       -        attr.colormap = _x.cmap;
       -        attr.background_pixel = ~0;
       -        attr.border_pixel = 0;
       -        _x.drawable = XCreateWindow(
       -                _x.display,        /* display */
       -                xrootwin,        /* parent */
       -                x,                /* x */
       -                y,                /* y */
       -                Dx(r),                /* width */
       -                 Dy(r),                /* height */
       -                0,                /* border width */
       -                _x.depth,        /* depth */
       -                InputOutput,        /* class */
       -                _x.vis,                /* visual */
       -                                /* valuemask */
       -                CWBackPixel|CWBorderPixel|CWColormap,
       -                &attr                /* attributes (the above aren't?!) */
       -        );
       -
       -        /*
       -         * Label and other properties required by ICCCCM.
       -         */
       -        memset(&name, 0, sizeof name);
       -        if(label == nil)
       -                label = "pjw-face-here";
       -        name.value = (uchar*)label;
       -        name.encoding = XA_STRING;
       -        name.format = 8;
       -        name.nitems = strlen((char*)name.value);
       -
       -        memset(&normalhint, 0, sizeof normalhint);
       -        normalhint.flags = PSize|PMaxSize;
       -        if(winsize && winsize[0]){
       -                normalhint.flags &= ~PSize;
       -                normalhint.flags |= USSize;
       -                normalhint.width = Dx(r);
       -                normalhint.height = Dy(r);
       -        }else{
       -                if((mask & WidthValue) && (mask & HeightValue)){
       -                        normalhint.flags &= ~PSize;
       -                        normalhint.flags |= USSize;
       -                        normalhint.width = width;
       -                        normalhint.height = height;
       -                }
       -                if((mask & WidthValue) && (mask & HeightValue)){
       -                        normalhint.flags |= USPosition;
       -                        normalhint.x = x;
       -                        normalhint.y = y;
       -                }
       -        }
       -
       -        normalhint.max_width = WidthOfScreen(xscreen);
       -        normalhint.max_height = HeightOfScreen(xscreen);
       -
       -        memset(&hint, 0, sizeof hint);
       -        hint.flags = InputHint|StateHint;
       -        hint.input = 1;
       -        hint.initial_state = NormalState;
       -
       -        memset(&classhint, 0, sizeof classhint);
       -        classhint.res_name = label;
       -        classhint.res_class = label;
       -
       -        argv[0] = label;
       -        argv[1] = nil;
       -
       -        XSetWMProperties(
       -                _x.display,        /* display */
       -                _x.drawable,        /* window */
       -                &name,                /* XA_WM_NAME property */
       -                &name,                /* XA_WM_ICON_NAME property */
       -                argv,                /* XA_WM_COMMAND */
       -                1,                /* argc */
       -                &normalhint,        /* XA_WM_NORMAL_HINTS */
       -                &hint,                /* XA_WM_HINTS */
       -                &classhint        /* XA_WM_CLASSHINTS */
       -        );
       -        XFlush(_x.display);
       -
       -        if(havemin){
       -                XWindowChanges ch;
       -
       -                memset(&ch, 0, sizeof ch);
       -                ch.x = r.min.x;
       -                ch.y = r.min.y;
       -                XConfigureWindow(_x.display, _x.drawable, CWX|CWY, &ch);
       -                /*
       -                 * Must pretend origin is 0,0 for X.
       -                 */
       -                r = Rect(0,0,Dx(r),Dy(r));
       -        }
       -        /*
       -         * Look up clipboard atom.
       -         */
       -        _x.clipboard = XInternAtom(_x.display, "CLIPBOARD", False);
       -        _x.utf8string = XInternAtom(_x.display, "UTF8_STRING", False);
       -        _x.targets = XInternAtom(_x.display, "TARGETS", False);
       -        _x.text = XInternAtom(_x.display, "TEXT", False);
       -        _x.compoundtext = XInternAtom(_x.display, "COMPOUND_TEXT", False);
       -        _x.takefocus = XInternAtom(_x.display, "WM_TAKE_FOCUS", False);
       -        _x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False);
       -        _x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False);
       -
       -        atoms[0] = _x.takefocus;
       -        atoms[1] = _x.losefocus;
       -        XChangeProperty(_x.display, _x.drawable, _x.wmprotos, XA_ATOM, 32,
       -                PropModeReplace, (uchar*)atoms, 2);
       -
       -        /*
       -         * Put the window on the screen, check to see what size we actually got.
       -         */
       -        XMapWindow(_x.display, _x.drawable);
       -        XSync(_x.display, False);
       -
       -        if(!XGetWindowAttributes(_x.display, _x.drawable, &wattr))
       -                fprint(2, "XGetWindowAttributes failed\n");
       -        else if(wattr.width && wattr.height){
       -                if(wattr.width != Dx(r) || wattr.height != Dy(r)){
       -                        r.max.x = wattr.width;
       -                        r.max.y = wattr.height;
       -                }
       -        }else
       -                fprint(2, "XGetWindowAttributes: bad attrs\n");
       -
       -        /*
       -         * Allocate our local backing store.
       -         */
       -        _x.screenr = r;
       -        _x.screenpm = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
       -        _x.nextscreenpm = _x.screenpm;
       -        _x.screenimage = _xallocmemimage(r, _x.chan, _x.screenpm);
       -
       -        /*
       -         * Allocate some useful graphics contexts for the future.
       -         */
       -        _x.gcfill        = xgc(_x.screenpm, FillSolid, -1);
       -        _x.gccopy        = xgc(_x.screenpm, -1, -1);
       -        _x.gcsimplesrc         = xgc(_x.screenpm, FillStippled, -1);
       -        _x.gczero        = xgc(_x.screenpm, -1, -1);
       -        _x.gcreplsrc        = xgc(_x.screenpm, FillTiled, -1);
       -
       -        pmid = XCreatePixmap(_x.display, _x.drawable, 1, 1, 1);
       -        _x.gcfill0        = xgc(pmid, FillSolid, 0);
       -        _x.gccopy0        = xgc(pmid, -1, -1);
       -        _x.gcsimplesrc0        = xgc(pmid, FillStippled, -1);
       -        _x.gczero0        = xgc(pmid, -1, -1);
       -        _x.gcreplsrc0        = xgc(pmid, FillTiled, -1);
       -        XFreePixmap(_x.display, pmid);
       -
       -        return _x.screenimage;
       -
       -err0:
       -        /*
       -         * Should do a better job of cleaning up here.
       -         */
       -        XCloseDisplay(_x.display);
       -        return nil;
       -}
       -
       -int
       -_xsetlabel(char *label)
       -{
       -        XTextProperty name;
       -
       -        /*
       -         * Label and other properties required by ICCCCM.
       -         */
       -        memset(&name, 0, sizeof name);
       -        if(label == nil)
       -                label = "pjw-face-here";
       -        name.value = (uchar*)label;
       -        name.encoding = XA_STRING;
       -        name.format = 8;
       -        name.nitems = strlen((char*)name.value);
       -
       -        XSetWMProperties(
       -                _x.display,        /* display */
       -                _x.drawable,        /* window */
       -                &name,                /* XA_WM_NAME property */
       -                &name,                /* XA_WM_ICON_NAME property */
       -                nil,                /* XA_WM_COMMAND */
       -                0,                /* argc */
       -                nil,                /* XA_WM_NORMAL_HINTS */
       -                nil,                /* XA_WM_HINTS */
       -                nil        /* XA_WM_CLASSHINTS */
       -        );
       -        XFlush(_x.display);
       -        return 0;
       -}
       -
       -/*
       - * Create a GC with a particular fill style and XXX.
       - * Disable generation of GraphicsExpose/NoExpose events in the GC.
       - */
       -static XGC
       -xgc(XDrawable d, int fillstyle, int foreground)
       -{
       -        XGC gc;
       -        XGCValues v;
       -
       -        memset(&v, 0, sizeof v);
       -        v.function = GXcopy;
       -        v.graphics_exposures = False;
       -        gc = XCreateGC(_x.display, d, GCFunction|GCGraphicsExposures, &v);
       -        if(fillstyle != -1)
       -                XSetFillStyle(_x.display, gc, fillstyle);
       -        if(foreground != -1)
       -                XSetForeground(_x.display, gc, 0);
       -        return gc;
       -}
       -
       -
       -/*
       - * Initialize map with the Plan 9 rgbv color map.
       - */
       -static void
       -plan9cmap(void)
       -{
       -        int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
       -        static int once;
       -
       -        if(once)
       -                return;
       -        once = 1;
       -
       -        for(r=0; r!=4; r++)
       -        for(g = 0; g != 4; g++)
       -        for(b = 0; b!=4; b++)
       -        for(v = 0; v!=4; v++){
       -                den=r;
       -                if(g > den)
       -                        den=g;
       -                if(b > den)
       -                        den=b;
       -                /* divide check -- pick grey shades */
       -                if(den==0)
       -                        cr=cg=cb=v*17;
       -                else {
       -                        num=17*(4*den+v);
       -                        cr=r*num/den;
       -                        cg=g*num/den;
       -                        cb=b*num/den;
       -                }
       -                idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
       -                _x.map[idx].red = cr*0x0101;
       -                _x.map[idx].green = cg*0x0101;
       -                _x.map[idx].blue = cb*0x0101;
       -                _x.map[idx].pixel = idx;
       -                _x.map[idx].flags = DoRed|DoGreen|DoBlue;
       -
       -                v7 = v >> 1;
       -                idx7 = r*32 + v7*16 + g*4 + b;
       -                if((v & 1) == v7){
       -                        _x.map7to8[idx7][0] = idx;
       -                        if(den == 0) {                 /* divide check -- pick grey shades */
       -                                cr = ((255.0/7.0)*v7)+0.5;
       -                                cg = cr;
       -                                cb = cr;
       -                        }
       -                        else {
       -                                num=17*15*(4*den+v7*2)/14;
       -                                cr=r*num/den;
       -                                cg=g*num/den;
       -                                cb=b*num/den;
       -                        }
       -                        _x.map7[idx7].red = cr*0x0101;
       -                        _x.map7[idx7].green = cg*0x0101;
       -                        _x.map7[idx7].blue = cb*0x0101;
       -                        _x.map7[idx7].pixel = idx7;
       -                        _x.map7[idx7].flags = DoRed|DoGreen|DoBlue;
       -                }
       -                else
       -                        _x.map7to8[idx7][1] = idx;
       -        }
       -}
       -
       -/*
       - * Initialize and install the rgbv color map as a private color map
       - * for this application.  It gets the best colors when it has the
       - * cursor focus.
       - *
       - * We always choose the best depth possible, but that might not
       - * be the default depth.  On such "suboptimal" systems, we have to allocate an
       - * empty color map anyway, according to Axel Belinfante.
       - */
       -static int
       -setupcmap(XWindow w)
       -{
       -        char buf[30];
       -        int i;
       -        u32int p, pp;
       -        XColor c;
       -
       -        if(_x.depth <= 1)
       -                return 0;
       -
       -        if(_x.depth >= 24) {
       -                if(_x.usetable == 0)
       -                        _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
       -
       -                /*
       -                 * The pixel value returned from XGetPixel needs to
       -                 * be converted to RGB so we can call rgb2cmap()
       -                 * to translate between 24 bit X and our color. Unfortunately,
       -                 * the return value appears to be display server endian
       -                 * dependant. Therefore, we run some heuristics to later
       -                 * determine how to mask the int value correctly.
       -                 * Yeah, I know we can look at _x.vis->byte_order but
       -                 * some displays say MSB even though they run on LSB.
       -                 * Besides, this is more anal.
       -                 */
       -                c = _x.map[19];        /* known to have different R, G, B values */
       -                if(!XAllocColor(_x.display, _x.cmap, &c)){
       -                        werrstr("XAllocColor: %r");
       -                        return -1;
       -                }
       -                p  = c.pixel;
       -                pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
       -                if(pp != _x.map[19].pixel) {
       -                        /* check if endian is other way */
       -                        pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
       -                        if(pp != _x.map[19].pixel){
       -                                werrstr("cannot detect X server byte order");
       -                                return -1;
       -                        }
       -
       -                        switch(_x.chan){
       -                        case RGB24:
       -                                _x.chan = BGR24;
       -                                break;
       -                        case XRGB32:
       -                                _x.chan = XBGR32;
       -                                break;
       -                        default:
       -                                werrstr("cannot byteswap channel %s",
       -                                        chantostr(buf, _x.chan));
       -                                break;
       -                        }
       -                }
       -        }else if(_x.vis->class == TrueColor || _x.vis->class == DirectColor){
       -                /*
       -                 * Do nothing.  We have no way to express a
       -                 * mixed-endian 16-bit screen, so pretend they don't exist.
       -                 */
       -                if(_x.usetable == 0)
       -                        _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
       -        }else if(_x.vis->class == PseudoColor){
       -                if(_x.usetable == 0){
       -                        _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll);
       -                        XStoreColors(_x.display, _x.cmap, _x.map, 256);
       -                        for(i = 0; i < 256; i++){
       -                                _x.tox11[i] = i;
       -                                _x.toplan9[i] = i;
       -                        }
       -                }else{
       -                        for(i = 0; i < 128; i++){
       -                                c = _x.map7[i];
       -                                if(!XAllocColor(_x.display, _x.cmap, &c)){
       -                                        werrstr("can't allocate colors in 7-bit map");
       -                                        return -1;
       -                                }
       -                                _x.tox11[_x.map7to8[i][0]] = c.pixel;
       -                                _x.tox11[_x.map7to8[i][1]] = c.pixel;
       -                                _x.toplan9[c.pixel] = _x.map7to8[i][0];
       -                        }
       -                }
       -        }else{
       -                werrstr("unsupported visual class %d", _x.vis->class);
       -                return -1;
       -        }
       -        return 0;
       -}
       -
       -void
       -_flushmemscreen(Rectangle r)
       -{
       -        if(_x.nextscreenpm != _x.screenpm){
       -                qlock(&_x.screenlock);
       -                XSync(_x.display, False);
       -                XFreePixmap(_x.display, _x.screenpm);
       -                _x.screenpm = _x.nextscreenpm;
       -                qunlock(&_x.screenlock);
       -        }
       -
       -        if(r.min.x >= r.max.x || r.min.y >= r.max.y)
       -                return;
       -        XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
       -                Dx(r), Dy(r), r.min.x, r.min.y);
       -        XFlush(_x.display);
       -}
       -
       -void
       -_xexpose(XEvent *e)
       -{
       -        XExposeEvent *xe;
       -        Rectangle r;
       -
       -        qlock(&_x.screenlock);
       -        if(_x.screenpm != _x.nextscreenpm){
       -                qunlock(&_x.screenlock);
       -                return;
       -        }
       -        xe = (XExposeEvent*)e;
       -        r.min.x = xe->x;
       -        r.min.y = xe->y;
       -        r.max.x = xe->x+xe->width;
       -        r.max.y = xe->y+xe->height;
       -        XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
       -                Dx(r), Dy(r), r.min.x, r.min.y);
       -        XSync(_x.display, False);
       -        qunlock(&_x.screenlock);
       -}
       -
       -int
       -_xdestroy(XEvent *e)
       -{
       -        XDestroyWindowEvent *xe;
       -
       -        xe = (XDestroyWindowEvent*)e;
       -        if(xe->window == _x.drawable){
       -                _x.destroyed = 1;
       -                return 1;
       -        }
       -        return 0;
       -}
       -
       -int
       -_xconfigure(XEvent *e)
       -{
       -        Rectangle r;
       -        XConfigureEvent *xe = (XConfigureEvent*)e;
       -
       -        if(!fullscreen){
       -                int rx, ry;
       -                XWindow w;
       -                if(XTranslateCoordinates(_x.display, _x.drawable, DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &w))
       -                        windowrect = Rect(rx, ry, rx+xe->width, ry+xe->height);
       -        }
       -
       -        if(xe->width == Dx(_x.screenr) && xe->height == Dy(_x.screenr))
       -                return 0;
       -        r = Rect(0, 0, xe->width, xe->height);
       -
       -        qlock(&_x.screenlock);
       -        if(_x.screenpm != _x.nextscreenpm){
       -                XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
       -                        Dx(r), Dy(r), r.min.x, r.min.y);
       -                XSync(_x.display, False);
       -        }
       -        qunlock(&_x.screenlock);
       -        _x.newscreenr = r;
       -        return 1;
       -}
       -
       -int
       -_xreplacescreenimage(void)
       -{
       -        Memimage *m;
       -        XDrawable pixmap;
       -        Rectangle r;
       -
       -        r = _x.newscreenr;
       -
       -        pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
       -        m = _xallocmemimage(r, _x.chan, pixmap);
       -        if(_x.nextscreenpm != _x.screenpm)
       -                XFreePixmap(_x.display, _x.nextscreenpm);
       -        _x.nextscreenpm = pixmap;
       -        _x.screenr = r;
       -        gfx_replacescreenimage(m);
       -        return 1;
       -}
 (DIR) diff --git a/src/cmd/devdraw/x11-itrans.c b/src/cmd/devdraw/x11-itrans.c
       t@@ -1,741 +0,0 @@
       -/* input event and data structure translation */
       -
       -#include <u.h>
       -#include "x11-inc.h"
       -#ifdef __APPLE__
       -#define APPLESNARF
       -#define Boolean AppleBoolean
       -#define Rect AppleRect
       -#define EventMask AppleEventMask
       -#define Point ApplePoint
       -#define Cursor AppleCursor
       -#include <Carbon/Carbon.h>
       -AUTOFRAMEWORK(Carbon)
       -#undef Boolean
       -#undef Rect
       -#undef EventMask
       -#undef Point
       -#undef Cursor
       -#endif
       -#include <libc.h>
       -#include <draw.h>
       -#include <memdraw.h>
       -#include <mouse.h>
       -#include <cursor.h>
       -#include <keyboard.h>
       -#include "x11-memdraw.h"
       -#include "x11-keysym2ucs.h"
       -#undef time
       -
       -static KeySym
       -__xtoplan9kbd(XEvent *e)
       -{
       -        KeySym k;
       -
       -        if(e->xany.type != KeyPress)
       -                return -1;
       -        needstack(64*1024);        /* X has some *huge* buffers in openobject */
       -                /* and they're even bigger on SuSE */
       -        XLookupString((XKeyEvent*)e,NULL,0,&k,NULL);
       -        if(k == NoSymbol)
       -                return -1;
       -
       -        if(k&0xFF00){
       -                switch(k){
       -                case XK_BackSpace:
       -                case XK_Tab:
       -                case XK_Escape:
       -                case XK_Delete:
       -                case XK_KP_0:
       -                case XK_KP_1:
       -                case XK_KP_2:
       -                case XK_KP_3:
       -                case XK_KP_4:
       -                case XK_KP_5:
       -                case XK_KP_6:
       -                case XK_KP_7:
       -                case XK_KP_8:
       -                case XK_KP_9:
       -                case XK_KP_Divide:
       -                case XK_KP_Multiply:
       -                case XK_KP_Subtract:
       -                case XK_KP_Add:
       -                case XK_KP_Decimal:
       -                        k &= 0x7F;
       -                        break;
       -                case XK_Linefeed:
       -                        k = '\r';
       -                        break;
       -                case XK_KP_Space:
       -                        k = ' ';
       -                        break;
       -                case XK_Home:
       -                case XK_KP_Home:
       -                        k = Khome;
       -                        break;
       -                case XK_Left:
       -                case XK_KP_Left:
       -                        k = Kleft;
       -                        break;
       -                case XK_Up:
       -                case XK_KP_Up:
       -                        k = Kup;
       -                        break;
       -                case XK_Down:
       -                case XK_KP_Down:
       -                        k = Kdown;
       -                        break;
       -                case XK_Right:
       -                case XK_KP_Right:
       -                        k = Kright;
       -                        break;
       -                case XK_Page_Down:
       -                case XK_KP_Page_Down:
       -                        k = Kpgdown;
       -                        break;
       -                case XK_End:
       -                case XK_KP_End:
       -                        k = Kend;
       -                        break;
       -                case XK_Page_Up:
       -                case XK_KP_Page_Up:
       -                        k = Kpgup;
       -                        break;
       -                case XK_Insert:
       -                case XK_KP_Insert:
       -                        k = Kins;
       -                        break;
       -                case XK_KP_Enter:
       -                case XK_Return:
       -                        k = '\n';
       -                        break;
       -                case XK_Alt_L:
       -                case XK_Meta_L:        /* Shift Alt on PCs */
       -                case XK_Alt_R:
       -                case XK_Meta_R:        /* Shift Alt on PCs */
       -                case XK_Multi_key:
       -                        return -1;
       -                default:                /* not ISO-1 or tty control */
       -                        if(k>0xff) {
       -                                k = _p9keysym2ucs(k);
       -                                if(k==-1) return -1;
       -                        }
       -                }
       -        }
       -
       -        /* Compensate for servers that call a minus a hyphen */
       -        if(k == XK_hyphen)
       -                k = XK_minus;
       -        /* Do control mapping ourselves if translator doesn't */
       -        if(e->xkey.state&ControlMask)
       -                k &= 0x9f;
       -        if(k == NoSymbol) {
       -                return -1;
       -        }
       -
       -        return k+0;
       -}
       -
       -int alting;
       -
       -void
       -abortcompose(void)
       -{
       -        alting = 0;
       -}
       -
       -static Rune* sendrune(Rune);
       -
       -extern int latin1(Rune*, int);
       -static Rune*
       -xtoplan9latin1(XEvent *e)
       -{
       -        Rune r;
       -
       -        r = __xtoplan9kbd(e);
       -        if(r == -1)
       -                return nil;
       -        return sendrune(r);
       -}
       -
       -void
       -sendalt(void)
       -{
       -        sendrune(Kalt);
       -}
       -
       -static Rune*
       -sendrune(Rune r)
       -{
       -        static Rune k[10];
       -        static int nk;
       -        int n;
       -
       -        if(alting){
       -                /*
       -                 * Kludge for Mac's X11 3-button emulation.
       -                 * It treats Command+Button as button 3, but also
       -                 * ends up sending XK_Meta_L twice.
       -                 */
       -                if(r == Kalt){
       -                        alting = 0;
       -                        return nil;
       -                }
       -                k[nk++] = r;
       -                n = latin1(k, nk);
       -                if(n > 0){
       -                        alting = 0;
       -                        k[0] = n;
       -                        k[1] = 0;
       -                        return k;
       -                }
       -                if(n == -1){
       -                        alting = 0;
       -                        k[nk] = 0;
       -                        return k;
       -                }
       -                /* n < -1, need more input */
       -                return nil;
       -        }else if(r == Kalt){
       -                alting = 1;
       -                nk = 0;
       -                return nil;
       -        }else{
       -                k[0] = r;
       -                k[1] = 0;
       -                return k;
       -        }
       -}
       -
       -int
       -_xtoplan9kbd(XEvent *e)
       -{
       -        static Rune *r;
       -
       -        if(e == (XEvent*)-1){
       -                assert(r);
       -                r--;
       -                return 0;
       -        }
       -        if(e)
       -                r = xtoplan9latin1(e);
       -        if(r && *r)
       -                return *r++;
       -        return -1;
       -}
       -
       -int
       -_xtoplan9mouse(XEvent *e, Mouse *m)
       -{
       -        int s;
       -        XButtonEvent *be;
       -        XMotionEvent *me;
       -
       -        if(_x.putsnarf != _x.assertsnarf){
       -                _x.assertsnarf = _x.putsnarf;
       -                XSetSelectionOwner(_x.display, XA_PRIMARY, _x.drawable, CurrentTime);
       -                if(_x.clipboard != None)
       -                        XSetSelectionOwner(_x.display, _x.clipboard, _x.drawable, CurrentTime);
       -                XFlush(_x.display);
       -        }
       -
       -        switch(e->type){
       -        case ButtonPress:
       -                be = (XButtonEvent*)e;
       -
       -                /*
       -                 * Fake message, just sent to make us announce snarf.
       -                 * Apparently state and button are 16 and 8 bits on
       -                 * the wire, since they are truncated by the time they
       -                 * get to us.
       -                 */
       -                if(be->send_event
       -                && (~be->state&0xFFFF)==0
       -                && (~be->button&0xFF)==0)
       -                        return -1;
       -                /* BUG? on mac need to inherit these from elsewhere? */
       -                m->xy.x = be->x;
       -                m->xy.y = be->y;
       -                s = be->state;
       -                m->msec = be->time;
       -                switch(be->button){
       -                case 1:
       -                        s |= Button1Mask;
       -                        break;
       -                case 2:
       -                        s |= Button2Mask;
       -                        break;
       -                case 3:
       -                        s |= Button3Mask;
       -                        break;
       -                case 4:
       -                        s |= Button4Mask;
       -                        break;
       -                case 5:
       -                        s |= Button5Mask;
       -                        break;
       -                }
       -                break;
       -        case ButtonRelease:
       -                be = (XButtonEvent*)e;
       -                m->xy.x = be->x;
       -                m->xy.y = be->y;
       -                s = be->state;
       -                m->msec = be->time;
       -                switch(be->button){
       -                case 1:
       -                        s &= ~Button1Mask;
       -                        break;
       -                case 2:
       -                        s &= ~Button2Mask;
       -                        break;
       -                case 3:
       -                        s &= ~Button3Mask;
       -                        break;
       -                case 4:
       -                        s &= ~Button4Mask;
       -                        break;
       -                case 5:
       -                        s &= ~Button5Mask;
       -                        break;
       -                }
       -                break;
       -
       -        case MotionNotify:
       -                me = (XMotionEvent*)e;
       -                s = me->state;
       -                m->xy.x = me->x;
       -                m->xy.y = me->y;
       -                m->msec = me->time;
       -                return 0; // do not set buttons
       -
       -        default:
       -                return -1;
       -        }
       -
       -        m->buttons = 0;
       -        if(s & Button1Mask)
       -                m->buttons |= 1;
       -        if(s & Button2Mask)
       -                m->buttons |= 2;
       -        if(s & Button3Mask)
       -                m->buttons |= 4;
       -        if(s & Button4Mask)
       -                m->buttons |= 8;
       -        if(s & Button5Mask)
       -                m->buttons |= 16;
       -        return 0;
       -}
       -
       -void
       -_xmoveto(Point p)
       -{
       -        XWarpPointer(_x.display, None, _x.drawable, 0, 0, 0, 0, p.x, p.y);
       -        XFlush(_x.display);
       -}
       -
       -static int
       -revbyte(int b)
       -{
       -        int r;
       -
       -        r = 0;
       -        r |= (b&0x01) << 7;
       -        r |= (b&0x02) << 5;
       -        r |= (b&0x04) << 3;
       -        r |= (b&0x08) << 1;
       -        r |= (b&0x10) >> 1;
       -        r |= (b&0x20) >> 3;
       -        r |= (b&0x40) >> 5;
       -        r |= (b&0x80) >> 7;
       -        return r;
       -}
       -
       -static void
       -xcursorarrow(void)
       -{
       -        if(_x.cursor != 0){
       -                XFreeCursor(_x.display, _x.cursor);
       -                _x.cursor = 0;
       -        }
       -        XUndefineCursor(_x.display, _x.drawable);
       -        XFlush(_x.display);
       -}
       -
       -
       -void
       -_xsetcursor(Cursor *c)
       -{
       -        XColor fg, bg;
       -        XCursor xc;
       -        Pixmap xsrc, xmask;
       -        int i;
       -        uchar src[2*16], mask[2*16];
       -
       -        if(c == nil){
       -                xcursorarrow();
       -                return;
       -        }
       -        for(i=0; i<2*16; i++){
       -                src[i] = revbyte(c->set[i]);
       -                mask[i] = revbyte(c->set[i] | c->clr[i]);
       -        }
       -
       -        fg = _x.map[0];
       -        bg = _x.map[255];
       -        xsrc = XCreateBitmapFromData(_x.display, _x.drawable, (char*)src, 16, 16);
       -        xmask = XCreateBitmapFromData(_x.display, _x.drawable, (char*)mask, 16, 16);
       -        xc = XCreatePixmapCursor(_x.display, xsrc, xmask, &fg, &bg, -c->offset.x, -c->offset.y);
       -        if(xc != 0) {
       -                XDefineCursor(_x.display, _x.drawable, xc);
       -                if(_x.cursor != 0)
       -                        XFreeCursor(_x.display, _x.cursor);
       -                _x.cursor = xc;
       -        }
       -        XFreePixmap(_x.display, xsrc);
       -        XFreePixmap(_x.display, xmask);
       -        XFlush(_x.display);
       -}
       -
       -struct {
       -        QLock lk;
       -        char buf[SnarfSize];
       -#ifdef APPLESNARF
       -        Rune rbuf[SnarfSize];
       -        PasteboardRef apple;
       -#endif
       -} clip;
       -
       -static uchar*
       -_xgetsnarffrom(XWindow w, Atom clipboard, Atom target, int timeout0, int timeout)
       -{
       -        Atom prop, type;
       -        ulong len, lastlen, dummy;
       -        int fmt, i;
       -        uchar *data, *xdata;
       -
       -        /*
       -         * We should be waiting for SelectionNotify here, but it might never
       -         * come, and we have no way to time out.  Instead, we will clear
       -         * local property #1, request our buddy to fill it in for us, and poll
       -         * until he's done or we get tired of waiting.
       -         */
       -        prop = 1;
       -        XChangeProperty(_x.display, _x.drawable, prop, target, 8, PropModeReplace, (uchar*)"", 0);
       -        XConvertSelection(_x.display, clipboard, target, prop, _x.drawable, CurrentTime);
       -        XFlush(_x.display);
       -        lastlen = 0;
       -        timeout0 = (timeout0 + 9)/10;
       -        timeout = (timeout + 9)/10;
       -        for(i=0; i<timeout0 || (lastlen!=0 && i<timeout); i++){
       -                usleep(10*1000);
       -                XGetWindowProperty(_x.display, _x.drawable, prop, 0, 0, 0, AnyPropertyType,
       -                        &type, &fmt, &dummy, &len, &xdata);
       -                if(lastlen == len && len > 0){
       -                        XFree(xdata);
       -                        break;
       -                }
       -                lastlen = len;
       -                XFree(xdata);
       -        }
       -        if(len == 0)
       -                return nil;
       -
       -        /* get the property */
       -        xdata = nil;
       -        XGetWindowProperty(_x.display, _x.drawable, prop, 0, SnarfSize/sizeof(ulong), 0,
       -                AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
       -        if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){
       -                if(xdata)
       -                        XFree(xdata);
       -                return nil;
       -        }
       -        if(xdata){
       -                data = (uchar*)strdup((char*)xdata);
       -                XFree(xdata);
       -                return data;
       -        }
       -        return nil;
       -}
       -
       -char*
       -_xgetsnarf(void)
       -{
       -        uchar *data;
       -        Atom clipboard;
       -        XWindow w;
       -
       -        qlock(&clip.lk);
       -        /*
       -         * Have we snarfed recently and the X server hasn't caught up?
       -         */
       -        if(_x.putsnarf != _x.assertsnarf)
       -                goto mine;
       -
       -        /*
       -         * Is there a primary selection (highlighted text in an xterm)?
       -         */
       -        clipboard = XA_PRIMARY;
       -        w = XGetSelectionOwner(_x.display, XA_PRIMARY);
       -        if(w == _x.drawable){
       -        mine:
       -                data = (uchar*)strdup(clip.buf);
       -                goto out;
       -        }
       -
       -        /*
       -         * If not, is there a clipboard selection?
       -         */
       -        if(w == None && _x.clipboard != None){
       -                clipboard = _x.clipboard;
       -                w = XGetSelectionOwner(_x.display, _x.clipboard);
       -                if(w == _x.drawable)
       -                        goto mine;
       -        }
       -
       -        /*
       -         * If not, give up.
       -         */
       -        if(w == None){
       -                data = nil;
       -                goto out;
       -        }
       -
       -        if((data = _xgetsnarffrom(w, clipboard, _x.utf8string, 10, 100)) == nil)
       -        if((data = _xgetsnarffrom(w, clipboard, XA_STRING, 10, 100)) == nil){
       -                /* nothing left to do */
       -        }
       -
       -out:
       -        qunlock(&clip.lk);
       -        return (char*)data;
       -}
       -
       -void
       -__xputsnarf(char *data)
       -{
       -        XButtonEvent e;
       -
       -        if(strlen(data) >= SnarfSize)
       -                return;
       -        qlock(&clip.lk);
       -        strcpy(clip.buf, data);
       -        /* leave note for mouse proc to assert selection ownership */
       -        _x.putsnarf++;
       -
       -        /* send mouse a fake event so snarf is announced */
       -        memset(&e, 0, sizeof e);
       -        e.type = ButtonPress;
       -        e.window = _x.drawable;
       -        e.state = ~0;
       -        e.button = ~0;
       -        XSendEvent(_x.display, _x.drawable, True, ButtonPressMask, (XEvent*)&e);
       -        XFlush(_x.display);
       -        qunlock(&clip.lk);
       -}
       -
       -int
       -_xselect(XEvent *e)
       -{
       -        char *name;
       -        XEvent r;
       -        XSelectionRequestEvent *xe;
       -        Atom a[4];
       -
       -        memset(&r, 0, sizeof r);
       -        xe = (XSelectionRequestEvent*)e;
       -if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d (sizeof atom=%d)\n",
       -        xe->target, xe->requestor, xe->property, xe->selection, sizeof a[0]);
       -        r.xselection.property = xe->property;
       -        if(xe->target == _x.targets){
       -                a[0] = _x.utf8string;
       -                a[1] = XA_STRING;
       -                a[2] = _x.text;
       -                a[3] = _x.compoundtext;
       -                XChangeProperty(_x.display, xe->requestor, xe->property, XA_ATOM,
       -                        32, PropModeReplace, (uchar*)a, nelem(a));
       -        }else if(xe->target == XA_STRING
       -        || xe->target == _x.utf8string
       -        || xe->target == _x.text
       -        || xe->target == _x.compoundtext
       -        || ((name = XGetAtomName(_x.display, xe->target)) && strcmp(name, "text/plain;charset=UTF-8") == 0)){
       -                /* text/plain;charset=UTF-8 seems nonstandard but is used by Synergy */
       -                /* if the target is STRING we're supposed to reply with Latin1 XXX */
       -                qlock(&clip.lk);
       -                XChangeProperty(_x.display, xe->requestor, xe->property, xe->target,
       -                        8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
       -                qunlock(&clip.lk);
       -        }else{
       -                if(strcmp(name, "TIMESTAMP") != 0)
       -                        fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
       -                r.xselection.property = None;
       -        }
       -
       -        r.xselection.display = xe->display;
       -        /* r.xselection.property filled above */
       -        r.xselection.target = xe->target;
       -        r.xselection.type = SelectionNotify;
       -        r.xselection.requestor = xe->requestor;
       -        r.xselection.time = xe->time;
       -        r.xselection.send_event = True;
       -        r.xselection.selection = xe->selection;
       -        XSendEvent(_x.display, xe->requestor, False, 0, &r);
       -        XFlush(_x.display);
       -        return 0;
       -}
       -
       -#ifdef APPLESNARF
       -char*
       -_applegetsnarf(void)
       -{
       -        char *s, *t;
       -        CFArrayRef flavors;
       -        CFDataRef data;
       -        CFIndex nflavor, ndata, j;
       -        CFStringRef type;
       -        ItemCount nitem;
       -        PasteboardItemID id;
       -        PasteboardSyncFlags flags;
       -        UInt32 i;
       -
       -/*        fprint(2, "applegetsnarf\n"); */
       -        qlock(&clip.lk);
       -        if(clip.apple == nil){
       -                if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
       -                        fprint(2, "apple pasteboard create failed\n");
       -                        qunlock(&clip.lk);
       -                        return nil;
       -                }
       -        }
       -        flags = PasteboardSynchronize(clip.apple);
       -        if(flags&kPasteboardClientIsOwner){
       -                s = strdup(clip.buf);
       -                qunlock(&clip.lk);
       -                return s;
       -        }
       -        if(PasteboardGetItemCount(clip.apple, &nitem) != noErr){
       -                fprint(2, "apple pasteboard get item count failed\n");
       -                qunlock(&clip.lk);
       -                return nil;
       -        }
       -        for(i=1; i<=nitem; i++){
       -                if(PasteboardGetItemIdentifier(clip.apple, i, &id) != noErr)
       -                        continue;
       -                if(PasteboardCopyItemFlavors(clip.apple, id, &flavors) != noErr)
       -                        continue;
       -                nflavor = CFArrayGetCount(flavors);
       -                for(j=0; j<nflavor; j++){
       -                        type = (CFStringRef)CFArrayGetValueAtIndex(flavors, j);
       -                        if(!UTTypeConformsTo(type, CFSTR("public.utf16-plain-text")))
       -                                continue;
       -                        if(PasteboardCopyItemFlavorData(clip.apple, id, type, &data) != noErr)
       -                                continue;
       -                        ndata = CFDataGetLength(data);
       -                        qunlock(&clip.lk);
       -                        s = smprint("%.*S", ndata/2, (Rune*)CFDataGetBytePtr(data));
       -                        CFRelease(flavors);
       -                        CFRelease(data);
       -                        for(t=s; *t; t++)
       -                                if(*t == '\r')
       -                                        *t = '\n';
       -                        return s;
       -                }
       -                CFRelease(flavors);
       -        }
       -        qunlock(&clip.lk);
       -        return nil;
       -}
       -
       -void
       -_appleputsnarf(char *s)
       -{
       -        CFDataRef cfdata;
       -        PasteboardSyncFlags flags;
       -
       -/*        fprint(2, "appleputsnarf\n"); */
       -
       -        if(strlen(s) >= SnarfSize)
       -                return;
       -        qlock(&clip.lk);
       -        strcpy(clip.buf, s);
       -        runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s);
       -        if(clip.apple == nil){
       -                if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
       -                        fprint(2, "apple pasteboard create failed\n");
       -                        qunlock(&clip.lk);
       -                        return;
       -                }
       -        }
       -        if(PasteboardClear(clip.apple) != noErr){
       -                fprint(2, "apple pasteboard clear failed\n");
       -                qunlock(&clip.lk);
       -                return;
       -        }
       -        flags = PasteboardSynchronize(clip.apple);
       -        if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){
       -                fprint(2, "apple pasteboard cannot assert ownership\n");
       -                qunlock(&clip.lk);
       -                return;
       -        }
       -        cfdata = CFDataCreate(kCFAllocatorDefault,
       -                (uchar*)clip.rbuf, runestrlen(clip.rbuf)*2);
       -        if(cfdata == nil){
       -                fprint(2, "apple pasteboard cfdatacreate failed\n");
       -                qunlock(&clip.lk);
       -                return;
       -        }
       -        if(PasteboardPutItemFlavor(clip.apple, (PasteboardItemID)1,
       -                CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){
       -                fprint(2, "apple pasteboard putitem failed\n");
       -                CFRelease(cfdata);
       -                qunlock(&clip.lk);
       -                return;
       -        }
       -        /* CFRelease(cfdata); ??? */
       -        qunlock(&clip.lk);
       -}
       -#endif        /* APPLESNARF */
       -
       -void
       -_xputsnarf(char *data)
       -{
       -#ifdef APPLESNARF
       -        _appleputsnarf(data);
       -#endif
       -        __xputsnarf(data);
       -}
       -
       -/*
       - * Send the mouse event back to the window manager.
       - * So that 9term can tell rio to pop up its button3 menu.
       - */
       -void
       -_xbouncemouse(Mouse *m)
       -{
       -        XButtonEvent e;
       -        XWindow dw;
       -
       -        e.type = ButtonPress;
       -        e.state = 0;
       -        e.button = 0;
       -        if(m->buttons&1)
       -                e.button = 1;
       -        else if(m->buttons&2)
       -                e.button = 2;
       -        else if(m->buttons&4)
       -                e.button = 3;
       -        e.same_screen = 1;
       -        XTranslateCoordinates(_x.display, _x.drawable,
       -                DefaultRootWindow(_x.display),
       -                m->xy.x, m->xy.y, &e.x_root, &e.y_root, &dw);
       -        e.root = DefaultRootWindow(_x.display);
       -        e.window = e.root;
       -        e.subwindow = None;
       -        e.x = e.x_root;
       -        e.y = e.y_root;
       -#undef time
       -        e.time = CurrentTime;
       -        XUngrabPointer(_x.display, m->msec);
       -        XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);
       -        XFlush(_x.display);
       -}
 (DIR) diff --git a/src/cmd/devdraw/x11-memdraw.h b/src/cmd/devdraw/x11-memdraw.h
       t@@ -4,6 +4,7 @@
        
        typedef struct Xmem Xmem;
        typedef struct Xprivate Xprivate;
       +typedef struct Xwin Xwin;
        
        enum
        {
       t@@ -26,7 +27,6 @@ struct Xprivate {
                XDisplay        *display;
                int                fd;        /* of display */
                int                depth;                                /* of screen */
       -        XDrawable        drawable;
                XColor                map[256];
                XColor                map7[128];
                uchar                map7to8[128][2];
       t@@ -50,12 +50,6 @@ struct Xprivate {
                u32int                gczeropixmap;
                XGC                gczero0;
                u32int                gczero0pixmap;
       -        Rectangle        newscreenr;
       -        Memimage*        screenimage;
       -        QLock                screenlock;
       -        XDrawable        screenpm;
       -        XDrawable        nextscreenpm;
       -        Rectangle        screenr;
                int                toplan9[256];
                int                tox11[256];
                int                usetable;
       t@@ -70,9 +64,35 @@ struct Xprivate {
                Atom                wmprotos;
                uint                putsnarf;
                uint                assertsnarf;
       +        int                kbuttons;
       +        int                kstate;
       +        int                altdown;
       +
       +        Xwin*        windows;
       +};
       +
       +struct Client;
       +
       +struct Xwin
       +{
       +        XDrawable        drawable;
       +        struct Client*        client;
       +        
       +        Rectangle        newscreenr;
       +        Memimage*        screenimage;
       +        XDrawable        screenpm;
       +        XDrawable        nextscreenpm;
       +        Rectangle        screenr;
       +        Rectangle        screenrect;
       +        Rectangle        windowrect;
       +        int                fullscreen;
                int                destroyed;
       +
       +        Xwin*        next;
        };
        
       +void xlock(void);
       +void xunlock(void);
        extern Xprivate _x;
        
        extern Memimage *_xallocmemimage(Rectangle, u32int, int);
       t@@ -83,35 +103,3 @@ extern void        _xfreexdata(Memimage*);
        extern XImage        *_xgetxdata(Memimage*, Rectangle);
        extern void        _xputxdata(Memimage*, Rectangle);
        
       -struct Mouse;
       -extern int        _xtoplan9mouse(XEvent*, struct Mouse*);
       -extern int        _xtoplan9kbd(XEvent*);
       -extern void        _xexpose(XEvent*);
       -extern int        _xselect(XEvent*);
       -extern int        _xconfigure(XEvent*);
       -extern int        _xdestroy(XEvent*);
       -extern void        _flushmemscreen(Rectangle);
       -extern void        _xmoveto(Point);
       -struct Cursor;
       -extern void        _xsetcursor(struct Cursor*);
       -extern void        _xbouncemouse(Mouse*);
       -extern int                _xsetlabel(char*);
       -extern Memimage*        _xattach(char*, char*);
       -extern char*                _xgetsnarf(void);
       -extern void                _xputsnarf(char *data);
       -extern void                _xtopwindow(void);
       -extern void                _xresizewindow(Rectangle);
       -extern void                _xmovewindow(Rectangle);
       -extern int                _xreplacescreenimage(void);
       -
       -#define MouseMask (\
       -        ButtonPressMask|\
       -        ButtonReleaseMask|\
       -        PointerMotionMask|\
       -        Button1MotionMask|\
       -        Button2MotionMask|\
       -        Button3MotionMask)
       -
       -extern Rectangle screenrect;
       -extern Rectangle windowrect;
       -extern int fullscreen;
 (DIR) diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c
       t@@ -0,0 +1,1759 @@
       +#include <u.h>
       +#include "x11-inc.h"
       +#include "x11-keysym2ucs.h"
       +#include <errno.h>
       +#include <libc.h>
       +#include <draw.h>
       +#include <memdraw.h>
       +#include <memlayer.h>
       +#include <keyboard.h>
       +#include <mouse.h>
       +#include <cursor.h>
       +#include <thread.h>
       +#include "x11-memdraw.h"
       +#include "devdraw.h"
       +
       +#undef time
       +
       +static void        plan9cmap(void);
       +static int        setupcmap(XWindow);
       +static XGC        xgc(XDrawable, int, int);
       +#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|EnterWindowMask|LeaveWindowMask|FocusChangeMask
       +
       +#define MouseMask (\
       +        ButtonPressMask|\
       +        ButtonReleaseMask|\
       +        PointerMotionMask|\
       +        Button1MotionMask|\
       +        Button2MotionMask|\
       +        Button3MotionMask)
       +
       +Xprivate _x;
       +
       +static void runxevent(XEvent *xev);
       +static int        _xconfigure(Xwin *w, XEvent *e);
       +static int        _xdestroy(Xwin *w, XEvent *e);
       +static void        _xexpose(Xwin *w, XEvent *e);
       +static int _xreplacescreenimage(Client *client);
       +static int _xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m);
       +static void _xmovewindow(Xwin *w, Rectangle r);
       +static int _xtoplan9kbd(XEvent *e);
       +static int _xselect(XEvent *e);
       +
       +static Xwin*
       +newxwin(Client *c)
       +{
       +        Xwin *w;
       +        
       +        w = mallocz(sizeof *w, 1);
       +        if(w == nil)
       +                sysfatal("out of memory");
       +        w->client = c;
       +        w->next = _x.windows;
       +        _x.windows = w;
       +        c->view = w;
       +        return w;
       +}
       +
       +static Xwin*
       +findxwin(XDrawable d)
       +{
       +        Xwin *w, **l;
       +        
       +        for(l=&_x.windows; (w=*l) != nil; l=&w->next) {
       +                if(w->drawable == d) {
       +                        /* move to front */
       +                        *l = w->next;
       +                        w->next = _x.windows;
       +                        _x.windows = w;
       +                        return w;
       +                }
       +        }
       +        return nil;
       +}
       +
       +static int
       +xerror(XDisplay *d, XErrorEvent *e)
       +{
       +        char buf[200];
       +
       +        if(e->request_code == 42) /* XSetInputFocus */
       +                return 0;
       +        if(e->request_code == 18) /* XChangeProperty */
       +                return 0;
       +        /*
       +         * BadDrawable happens in apps that get resized a LOT,
       +         * e.g. when KDE is configured to resize continuously
       +         * during a window drag.
       +         */
       +        if(e->error_code == 9) /* BadDrawable */
       +                return 0;
       +
       +        fprint(2, "X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
       +                e->error_code, e->request_code, e->minor_code, d);
       +        XGetErrorText(d, e->error_code, buf, sizeof buf);
       +        fprint(2, "%s\n", buf);
       +        return 0;
       +}
       +
       +static int
       +xioerror(XDisplay *d)
       +{
       +        /*print("X I/O error\n"); */
       +        exit(0);
       +        /*sysfatal("X I/O error\n");*/
       +        abort();
       +        return -1;
       +}
       +
       +static void xloop(void);
       +
       +static QLock xlk;
       +
       +void
       +xlock(void)
       +{
       +        qlock(&xlk);
       +}
       +
       +void
       +xunlock(void)
       +{
       +        qunlock(&xlk);
       +}
       +
       +void
       +gfx_main(void)
       +{
       +        char *disp;
       +        int i, n, xrootid;
       +        XPixmapFormatValues *pfmt;
       +        XScreen *xscreen;
       +        XVisualInfo xvi;
       +        XWindow xrootwin;
       +
       +        /*
       +        if(XInitThreads() == 0)
       +                sysfatal("XInitThread: %r");
       +        */
       +
       +        /*
       +         * Connect to X server.
       +         */
       +        _x.display = XOpenDisplay(NULL);
       +        if(_x.display == nil){
       +                disp = getenv("DISPLAY");
       +                werrstr("XOpenDisplay %s: %r", disp ? disp : ":0");
       +                free(disp);
       +                sysfatal("%r");
       +        }
       +        _x.fd = ConnectionNumber(_x.display);
       +        XSetErrorHandler(xerror);
       +        XSetIOErrorHandler(xioerror);
       +        xrootid = DefaultScreen(_x.display);
       +        xrootwin = DefaultRootWindow(_x.display);
       +
       +        /*
       +         * Figure out underlying screen format.
       +         */
       +        if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
       +        || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
       +                _x.vis = xvi.visual;
       +                _x.depth = 24;
       +        }
       +        else
       +        if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
       +        || XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
       +                _x.vis = xvi.visual;
       +                _x.depth = 16;
       +        }
       +        else
       +        if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
       +        || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
       +                _x.vis = xvi.visual;
       +                _x.depth = 15;
       +        }
       +        else
       +        if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
       +        || XMatchVisualInfo(_x.display, xrootid, 8, StaticColor, &xvi)){
       +                if(_x.depth > 8){
       +                        werrstr("can't deal with colormapped depth %d screens",
       +                                _x.depth);
       +                        goto err0;
       +                }
       +                _x.vis = xvi.visual;
       +                _x.depth = 8;
       +        }
       +        else{
       +                _x.depth = DefaultDepth(_x.display, xrootid);
       +                if(_x.depth != 8){
       +                        werrstr("can't understand depth %d screen", _x.depth);
       +                        goto err0;
       +                }
       +                _x.vis = DefaultVisual(_x.display, xrootid);
       +        }
       +
       +        if(DefaultDepth(_x.display, xrootid) == _x.depth)
       +                _x.usetable = 1;
       +
       +        /*
       +         * _x.depth is only the number of significant pixel bits,
       +         * not the total number of pixel bits.  We need to walk the
       +         * display list to find how many actual bits are used
       +         * per pixel.
       +         */
       +        _x.chan = 0;
       +        pfmt = XListPixmapFormats(_x.display, &n);
       +        for(i=0; i<n; i++){
       +                if(pfmt[i].depth == _x.depth){
       +                        switch(pfmt[i].bits_per_pixel){
       +                        case 1:        /* untested */
       +                                _x.chan = GREY1;
       +                                break;
       +                        case 2:        /* untested */
       +                                _x.chan = GREY2;
       +                                break;
       +                        case 4:        /* untested */
       +                                _x.chan = GREY4;
       +                                break;
       +                        case 8:
       +                                _x.chan = CMAP8;
       +                                break;
       +                        case 15:
       +                                _x.chan = RGB15;
       +                                break;
       +                        case 16: /* how to tell RGB15? */
       +                                _x.chan = RGB16;
       +                                break;
       +                        case 24: /* untested (impossible?) */
       +                                _x.chan = RGB24;
       +                                break;
       +                        case 32:
       +                                _x.chan = XRGB32;
       +                                break;
       +                        }
       +                }
       +        }
       +        XFree(pfmt);
       +        if(_x.chan == 0){
       +                werrstr("could not determine screen pixel format");
       +                goto err0;
       +        }
       +
       +        /*
       +         * Set up color map if necessary.
       +         */
       +        xscreen = DefaultScreenOfDisplay(_x.display);
       +        _x.cmap = DefaultColormapOfScreen(xscreen);
       +        if(_x.vis->class != StaticColor){
       +                plan9cmap();
       +                setupcmap(xrootwin);
       +        }
       +        gfx_started();
       +        xloop();
       +
       +err0:
       +        XCloseDisplay(_x.display);
       +        sysfatal("%r");
       +}
       +
       +static void
       +xloop(void)
       +{
       +        fd_set rd, wr, xx;
       +        XEvent event;
       +
       +        xlock();
       +        _x.fd = ConnectionNumber(_x.display);
       +        for(;;) {
       +                FD_ZERO(&rd);
       +                FD_ZERO(&wr);
       +                FD_ZERO(&xx);
       +                FD_SET(_x.fd, &rd);
       +                FD_SET(_x.fd, &xx);
       +                if(_x.windows != nil)
       +                        XSelectInput(_x.display, _x.windows->drawable, Mask); // TODO: when is this needed?
       +                XFlush(_x.display);
       +                xunlock();
       +
       +        again:
       +                if(select(_x.fd+1, &rd, &wr, &xx, nil) < 0) {
       +                        if(errno == EINTR)
       +                                goto again;
       +                        sysfatal("select: %r"); // TODO: quiet exit?
       +                }
       +
       +                xlock();
       +                while(XPending(_x.display)) {
       +                        XNextEvent(_x.display, &event);
       +                        runxevent(&event);
       +                }
       +        }
       +}
       +
       +/*
       + * Handle an incoming X event.
       + */
       +static void
       +runxevent(XEvent *xev)
       +{
       +        int c;
       +        KeySym k;
       +        static Mouse m;
       +        XButtonEvent *be;
       +        XKeyEvent *ke;
       +        Xwin *w;
       +
       +#ifdef SHOWEVENT
       +        static int first = 1;
       +        if(first){
       +                dup(create("/tmp/devdraw.out", OWRITE, 0666), 1);
       +                setbuf(stdout, 0);
       +                first = 0;
       +        }
       +#endif
       +
       +        if(xev == 0)
       +                return;
       +
       +#ifdef SHOWEVENT
       +        print("\n");
       +        ShowEvent(xev);
       +#endif
       +
       +        w = nil;
       +        switch(xev->type){
       +        case Expose:
       +                w = findxwin(((XExposeEvent*)xev)->window);
       +                break;
       +        case DestroyNotify:
       +                w = findxwin(((XDestroyWindowEvent*)xev)->window);
       +                break;
       +        case ConfigureNotify:
       +                w = findxwin(((XConfigureEvent*)xev)->window);
       +                break;
       +        case ButtonPress:
       +        case ButtonRelease:
       +                w = findxwin(((XButtonEvent*)xev)->window);
       +                break;
       +        case MotionNotify:
       +                w = findxwin(((XMotionEvent*)xev)->window);
       +                break;
       +        case KeyRelease:
       +        case KeyPress:
       +                w = findxwin(((XKeyEvent*)xev)->window);
       +                break;
       +        case FocusOut:
       +                w = findxwin(((XFocusChangeEvent*)xev)->window);
       +                break;
       +        }
       +        if(w == nil)
       +                w = _x.windows;
       +
       +        switch(xev->type){
       +        case Expose:
       +                _xexpose(w, xev);
       +                break;
       +
       +        case DestroyNotify:
       +                if(_xdestroy(w, xev))
       +                        threadexitsall(nil);
       +                break;
       +
       +        case ConfigureNotify:
       +                if(_xconfigure(w, xev))
       +                        _xreplacescreenimage(w->client);
       +                break;
       +
       +        case ButtonPress:
       +                be = (XButtonEvent*)xev;
       +                if(be->button == 1) {
       +                        if(_x.kstate & ControlMask)
       +                                be->button = 2;
       +                        else if(_x.kstate & Mod1Mask)
       +                                be->button = 3;
       +                }
       +                // fall through
       +        case ButtonRelease:
       +                _x.altdown = 0;
       +                // fall through
       +        case MotionNotify:
       +                if(_xtoplan9mouse(w, xev, &m) < 0)
       +                        return;
       +                gfx_mousetrack(w->client, m.xy.x, m.xy.y, m.buttons|_x.kbuttons, m.msec);
       +                break;
       +
       +        case KeyRelease:
       +        case KeyPress:
       +                ke = (XKeyEvent*)xev;
       +                XLookupString(ke, NULL, 0, &k, NULL);
       +                c = ke->state;
       +                switch(k) {
       +                case XK_Alt_L:
       +                case XK_Meta_L:        /* Shift Alt on PCs */
       +                case XK_Alt_R:
       +                case XK_Meta_R:        /* Shift Alt on PCs */
       +                case XK_Multi_key:
       +                        if(xev->type == KeyPress)
       +                                _x.altdown = 1;
       +                        else if(_x.altdown) {
       +                                _x.altdown = 0;
       +                                gfx_keystroke(w->client, Kalt);
       +                        }
       +                        break;
       +                }
       +
       +                switch(k) {
       +                case XK_Control_L:
       +                        if(xev->type == KeyPress)
       +                                c |= ControlMask;
       +                        else
       +                                c &= ~ControlMask;
       +                        goto kbutton;
       +                case XK_Alt_L:
       +                case XK_Shift_L:
       +                        if(xev->type == KeyPress)
       +                                c |= Mod1Mask;
       +                        else
       +                                c &= ~Mod1Mask;
       +                kbutton:
       +                        _x.kstate = c;
       +                        if(m.buttons || _x.kbuttons) {
       +                                _x.altdown = 0; // used alt
       +                                _x.kbuttons = 0;
       +                                if(c & ControlMask)
       +                                        _x.kbuttons |= 2;
       +                                if(c & Mod1Mask)
       +                                        _x.kbuttons |= 4;
       +                                gfx_mousetrack(w->client, m.xy.x, m.xy.y, m.buttons|_x.kbuttons, m.msec);
       +                                break;
       +                        }
       +                }
       +
       +                if(xev->type != KeyPress)
       +                        break;
       +                if(k == XK_F11){
       +                        w->fullscreen = !w->fullscreen;
       +                        _xmovewindow(w, w->fullscreen ? w->screenrect : w->windowrect);
       +                        return;
       +                }
       +                if((c = _xtoplan9kbd(xev)) < 0)
       +                        return;
       +                gfx_keystroke(w->client, c);
       +                break;
       +
       +        case FocusOut:
       +                /*
       +                 * Some key combinations (e.g. Alt-Tab) can cause us
       +                 * to see the key down event without the key up event,
       +                 * so clear out the keyboard state when we lose the focus.
       +                 */
       +                _x.kstate = 0;
       +                _x.altdown = 0;
       +                gfx_abortcompose(w->client);
       +                break;
       +
       +        case SelectionRequest:
       +                _xselect(xev);
       +                break;
       +        }
       +}
       +
       +
       +static Memimage*
       +xattach(Client *client, char *label, char *winsize)
       +{
       +        char *argv[2];
       +        int havemin, height, mask, width, x, y;
       +        Rectangle r;
       +        XClassHint classhint;
       +        XDrawable pmid;
       +        XScreen *xscreen;
       +        XSetWindowAttributes attr;
       +        XSizeHints normalhint;
       +        XTextProperty name;
       +        XWindow xrootwin;
       +        XWindowAttributes wattr;
       +        XWMHints hint;
       +        Atom atoms[2];
       +        Xwin *w;
       +
       +        USED(client);
       +        xscreen = DefaultScreenOfDisplay(_x.display);
       +        xrootwin = DefaultRootWindow(_x.display);
       +
       +        /*
       +         * We get to choose the initial rectangle size.
       +         * This is arbitrary.  In theory we should read the
       +         * command line and allow the traditional X options.
       +         */
       +        mask = 0;
       +        x = 0;
       +        y = 0;
       +        if(winsize && winsize[0]){
       +                if(parsewinsize(winsize, &r, &havemin) < 0)
       +                        sysfatal("%r");
       +        }else{
       +                /*
       +                 * Parse the various X resources.  Thanks to Peter Canning.
       +                 */
       +                char *screen_resources, *display_resources, *geom,
       +                        *geomrestype, *home, *file, *dpitype;
       +                XrmDatabase database;
       +                XrmValue geomres, dpires;
       +
       +                database = XrmGetDatabase(_x.display);
       +                screen_resources = XScreenResourceString(xscreen);
       +                if(screen_resources != nil){
       +                        XrmCombineDatabase(XrmGetStringDatabase(screen_resources), &database, False);
       +                        XFree(screen_resources);
       +                }
       +
       +                display_resources = XResourceManagerString(_x.display);
       +                if(display_resources == nil){
       +                        home = getenv("HOME");
       +                        if(home!=nil && (file=smprint("%s/.Xdefaults", home)) != nil){
       +                                XrmCombineFileDatabase(file, &database, False);
       +                                free(file);
       +                        }
       +                        free(home);
       +                }else
       +                        XrmCombineDatabase(XrmGetStringDatabase(display_resources), &database, False);
       +
       +                if (XrmGetResource(database, "Xft.dpi", "String", &dpitype, &dpires) == True) {
       +                        if (dpires.addr) {
       +                                client->displaydpi = atoi(dpires.addr);
       +                        }
       +                }
       +                geom = smprint("%s.geometry", label);
       +                if(geom && XrmGetResource(database, geom, nil, &geomrestype, &geomres))
       +                        mask = XParseGeometry(geomres.addr, &x, &y, (uint*)&width, (uint*)&height);
       +                XrmDestroyDatabase(database);
       +                free(geom);
       +
       +                if((mask & WidthValue) && (mask & HeightValue)){
       +                        r = Rect(0, 0, width, height);
       +                }else{
       +                        r = Rect(0, 0, WidthOfScreen(xscreen)*3/4,
       +                                        HeightOfScreen(xscreen)*3/4);
       +                        if(Dx(r) > Dy(r)*3/2)
       +                                r.max.x = r.min.x + Dy(r)*3/2;
       +                        if(Dy(r) > Dx(r)*3/2)
       +                                r.max.y = r.min.y + Dx(r)*3/2;
       +                }
       +                if(mask & XNegative){
       +                        x += WidthOfScreen(xscreen);
       +                }
       +                if(mask & YNegative){
       +                        y += HeightOfScreen(xscreen);
       +                }
       +                havemin = 0;
       +        }
       +        w = newxwin(client);
       +        w->screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen));
       +        w->windowrect = r;
       +
       +        memset(&attr, 0, sizeof attr);
       +        attr.colormap = _x.cmap;
       +        attr.background_pixel = ~0;
       +        attr.border_pixel = 0;
       +        w->drawable = XCreateWindow(
       +                _x.display,        /* display */
       +                xrootwin,        /* parent */
       +                x,                /* x */
       +                y,                /* y */
       +                Dx(r),                /* width */
       +                 Dy(r),                /* height */
       +                0,                /* border width */
       +                _x.depth,        /* depth */
       +                InputOutput,        /* class */
       +                _x.vis,                /* visual */
       +                                /* valuemask */
       +                CWBackPixel|CWBorderPixel|CWColormap,
       +                &attr                /* attributes (the above aren't?!) */
       +        );
       +
       +        /*
       +         * Label and other properties required by ICCCCM.
       +         */
       +        memset(&name, 0, sizeof name);
       +        if(label == nil)
       +                label = "pjw-face-here";
       +        name.value = (uchar*)label;
       +        name.encoding = XA_STRING;
       +        name.format = 8;
       +        name.nitems = strlen((char*)name.value);
       +
       +        memset(&normalhint, 0, sizeof normalhint);
       +        normalhint.flags = PSize|PMaxSize;
       +        if(winsize && winsize[0]){
       +                normalhint.flags &= ~PSize;
       +                normalhint.flags |= USSize;
       +                normalhint.width = Dx(r);
       +                normalhint.height = Dy(r);
       +        }else{
       +                if((mask & WidthValue) && (mask & HeightValue)){
       +                        normalhint.flags &= ~PSize;
       +                        normalhint.flags |= USSize;
       +                        normalhint.width = width;
       +                        normalhint.height = height;
       +                }
       +                if((mask & WidthValue) && (mask & HeightValue)){
       +                        normalhint.flags |= USPosition;
       +                        normalhint.x = x;
       +                        normalhint.y = y;
       +                }
       +        }
       +
       +        normalhint.max_width = WidthOfScreen(xscreen);
       +        normalhint.max_height = HeightOfScreen(xscreen);
       +
       +        memset(&hint, 0, sizeof hint);
       +        hint.flags = InputHint|StateHint;
       +        hint.input = 1;
       +        hint.initial_state = NormalState;
       +
       +        memset(&classhint, 0, sizeof classhint);
       +        classhint.res_name = label;
       +        classhint.res_class = label;
       +
       +        argv[0] = label;
       +        argv[1] = nil;
       +
       +        XSetWMProperties(
       +                _x.display,        /* display */
       +                w->drawable,        /* window */
       +                &name,                /* XA_WM_NAME property */
       +                &name,                /* XA_WM_ICON_NAME property */
       +                argv,                /* XA_WM_COMMAND */
       +                1,                /* argc */
       +                &normalhint,        /* XA_WM_NORMAL_HINTS */
       +                &hint,                /* XA_WM_HINTS */
       +                &classhint        /* XA_WM_CLASSHINTS */
       +        );
       +        XFlush(_x.display);
       +
       +        if(havemin){
       +                XWindowChanges ch;
       +
       +                memset(&ch, 0, sizeof ch);
       +                ch.x = r.min.x;
       +                ch.y = r.min.y;
       +                XConfigureWindow(_x.display, w->drawable, CWX|CWY, &ch);
       +                /*
       +                 * Must pretend origin is 0,0 for X.
       +                 */
       +                r = Rect(0,0,Dx(r),Dy(r));
       +        }
       +        /*
       +         * Look up clipboard atom.
       +         */
       +         if(_x.clipboard == 0) {
       +                _x.clipboard = XInternAtom(_x.display, "CLIPBOARD", False);
       +                _x.utf8string = XInternAtom(_x.display, "UTF8_STRING", False);
       +                _x.targets = XInternAtom(_x.display, "TARGETS", False);
       +                _x.text = XInternAtom(_x.display, "TEXT", False);
       +                _x.compoundtext = XInternAtom(_x.display, "COMPOUND_TEXT", False);
       +                _x.takefocus = XInternAtom(_x.display, "WM_TAKE_FOCUS", False);
       +                _x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False);
       +                _x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False);
       +        }
       +        
       +        atoms[0] = _x.takefocus;
       +        atoms[1] = _x.losefocus;
       +        XChangeProperty(_x.display, w->drawable, _x.wmprotos, XA_ATOM, 32,
       +                PropModeReplace, (uchar*)atoms, 2);
       +
       +        /*
       +         * Put the window on the screen, check to see what size we actually got.
       +         */
       +        XMapWindow(_x.display, w->drawable);
       +        XSync(_x.display, False);
       +
       +        if(!XGetWindowAttributes(_x.display, w->drawable, &wattr))
       +                fprint(2, "XGetWindowAttributes failed\n");
       +        else if(wattr.width && wattr.height){
       +                if(wattr.width != Dx(r) || wattr.height != Dy(r)){
       +                        r.max.x = wattr.width;
       +                        r.max.y = wattr.height;
       +                }
       +        }else
       +                fprint(2, "XGetWindowAttributes: bad attrs\n");
       +
       +        /*
       +         * Allocate our local backing store.
       +         */
       +        w->screenr = r;
       +        w->screenpm = XCreatePixmap(_x.display, w->drawable, Dx(r), Dy(r), _x.depth);
       +        w->nextscreenpm = w->screenpm;
       +        w->screenimage = _xallocmemimage(r, _x.chan, w->screenpm);
       +        client->mouserect = r;
       +
       +        /*
       +         * Allocate some useful graphics contexts for the future.
       +         * These can be used with any drawable matching w->drawable's
       +         * pixel format (which is all the drawables we create).
       +         */
       +         if(_x.gcfill == 0) {
       +                _x.gcfill        = xgc(w->screenpm, FillSolid, -1);
       +                _x.gccopy        = xgc(w->screenpm, -1, -1);
       +                _x.gcsimplesrc         = xgc(w->screenpm, FillStippled, -1);
       +                _x.gczero        = xgc(w->screenpm, -1, -1);
       +                _x.gcreplsrc        = xgc(w->screenpm, FillTiled, -1);
       +        
       +                pmid = XCreatePixmap(_x.display, w->drawable, 1, 1, 1);
       +                _x.gcfill0        = xgc(pmid, FillSolid, 0);
       +                _x.gccopy0        = xgc(pmid, -1, -1);
       +                _x.gcsimplesrc0        = xgc(pmid, FillStippled, -1);
       +                _x.gczero0        = xgc(pmid, -1, -1);
       +                _x.gcreplsrc0        = xgc(pmid, FillTiled, -1);
       +                XFreePixmap(_x.display, pmid);
       +        }
       +
       +        return w->screenimage;
       +}
       +
       +Memimage*
       +rpc_attach(Client *client, char *label, char *winsize)
       +{
       +        Memimage *m;
       +
       +        xlock();
       +        m = xattach(client, label, winsize);
       +        xunlock();
       +        return m;
       +}
       +
       +void
       +rpc_setlabel(Client *client, char *label)
       +{
       +        Xwin *w = (Xwin*)client->view;
       +        XTextProperty name;
       +        
       +        /*
       +         * Label and other properties required by ICCCCM.
       +         */
       +        xlock();
       +        memset(&name, 0, sizeof name);
       +        if(label == nil)
       +                label = "pjw-face-here";
       +        name.value = (uchar*)label;
       +        name.encoding = XA_STRING;
       +        name.format = 8;
       +        name.nitems = strlen((char*)name.value);
       +
       +        XSetWMProperties(
       +                _x.display,        /* display */
       +                w->drawable,        /* window */
       +                &name,                /* XA_WM_NAME property */
       +                &name,                /* XA_WM_ICON_NAME property */
       +                nil,                /* XA_WM_COMMAND */
       +                0,                /* argc */
       +                nil,                /* XA_WM_NORMAL_HINTS */
       +                nil,                /* XA_WM_HINTS */
       +                nil        /* XA_WM_CLASSHINTS */
       +        );
       +        XFlush(_x.display);
       +        xunlock();
       +}
       +
       +/*
       + * Create a GC with a particular fill style and XXX.
       + * Disable generation of GraphicsExpose/NoExpose events in the GC.
       + */
       +static XGC
       +xgc(XDrawable d, int fillstyle, int foreground)
       +{
       +        XGC gc;
       +        XGCValues v;
       +
       +        memset(&v, 0, sizeof v);
       +        v.function = GXcopy;
       +        v.graphics_exposures = False;
       +        gc = XCreateGC(_x.display, d, GCFunction|GCGraphicsExposures, &v);
       +        if(fillstyle != -1)
       +                XSetFillStyle(_x.display, gc, fillstyle);
       +        if(foreground != -1)
       +                XSetForeground(_x.display, gc, 0);
       +        return gc;
       +}
       +
       +
       +/*
       + * Initialize map with the Plan 9 rgbv color map.
       + */
       +static void
       +plan9cmap(void)
       +{
       +        int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
       +        static int once;
       +
       +        if(once)
       +                return;
       +        once = 1;
       +
       +        for(r=0; r!=4; r++)
       +        for(g = 0; g != 4; g++)
       +        for(b = 0; b!=4; b++)
       +        for(v = 0; v!=4; v++){
       +                den=r;
       +                if(g > den)
       +                        den=g;
       +                if(b > den)
       +                        den=b;
       +                /* divide check -- pick grey shades */
       +                if(den==0)
       +                        cr=cg=cb=v*17;
       +                else {
       +                        num=17*(4*den+v);
       +                        cr=r*num/den;
       +                        cg=g*num/den;
       +                        cb=b*num/den;
       +                }
       +                idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
       +                _x.map[idx].red = cr*0x0101;
       +                _x.map[idx].green = cg*0x0101;
       +                _x.map[idx].blue = cb*0x0101;
       +                _x.map[idx].pixel = idx;
       +                _x.map[idx].flags = DoRed|DoGreen|DoBlue;
       +
       +                v7 = v >> 1;
       +                idx7 = r*32 + v7*16 + g*4 + b;
       +                if((v & 1) == v7){
       +                        _x.map7to8[idx7][0] = idx;
       +                        if(den == 0) {                 /* divide check -- pick grey shades */
       +                                cr = ((255.0/7.0)*v7)+0.5;
       +                                cg = cr;
       +                                cb = cr;
       +                        }
       +                        else {
       +                                num=17*15*(4*den+v7*2)/14;
       +                                cr=r*num/den;
       +                                cg=g*num/den;
       +                                cb=b*num/den;
       +                        }
       +                        _x.map7[idx7].red = cr*0x0101;
       +                        _x.map7[idx7].green = cg*0x0101;
       +                        _x.map7[idx7].blue = cb*0x0101;
       +                        _x.map7[idx7].pixel = idx7;
       +                        _x.map7[idx7].flags = DoRed|DoGreen|DoBlue;
       +                }
       +                else
       +                        _x.map7to8[idx7][1] = idx;
       +        }
       +}
       +
       +/*
       + * Initialize and install the rgbv color map as a private color map
       + * for this application.  It gets the best colors when it has the
       + * cursor focus.
       + *
       + * We always choose the best depth possible, but that might not
       + * be the default depth.  On such "suboptimal" systems, we have to allocate an
       + * empty color map anyway, according to Axel Belinfante.
       + */
       +static int
       +setupcmap(XWindow w)
       +{
       +        char buf[30];
       +        int i;
       +        u32int p, pp;
       +        XColor c;
       +
       +        if(_x.depth <= 1)
       +                return 0;
       +
       +        if(_x.depth >= 24) {
       +                if(_x.usetable == 0)
       +                        _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
       +
       +                /*
       +                 * The pixel value returned from XGetPixel needs to
       +                 * be converted to RGB so we can call rgb2cmap()
       +                 * to translate between 24 bit X and our color. Unfortunately,
       +                 * the return value appears to be display server endian
       +                 * dependant. Therefore, we run some heuristics to later
       +                 * determine how to mask the int value correctly.
       +                 * Yeah, I know we can look at _x.vis->byte_order but
       +                 * some displays say MSB even though they run on LSB.
       +                 * Besides, this is more anal.
       +                 */
       +                c = _x.map[19];        /* known to have different R, G, B values */
       +                if(!XAllocColor(_x.display, _x.cmap, &c)){
       +                        werrstr("XAllocColor: %r");
       +                        return -1;
       +                }
       +                p  = c.pixel;
       +                pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
       +                if(pp != _x.map[19].pixel) {
       +                        /* check if endian is other way */
       +                        pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
       +                        if(pp != _x.map[19].pixel){
       +                                werrstr("cannot detect X server byte order");
       +                                return -1;
       +                        }
       +
       +                        switch(_x.chan){
       +                        case RGB24:
       +                                _x.chan = BGR24;
       +                                break;
       +                        case XRGB32:
       +                                _x.chan = XBGR32;
       +                                break;
       +                        default:
       +                                werrstr("cannot byteswap channel %s",
       +                                        chantostr(buf, _x.chan));
       +                                break;
       +                        }
       +                }
       +        }else if(_x.vis->class == TrueColor || _x.vis->class == DirectColor){
       +                /*
       +                 * Do nothing.  We have no way to express a
       +                 * mixed-endian 16-bit screen, so pretend they don't exist.
       +                 */
       +                if(_x.usetable == 0)
       +                        _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
       +        }else if(_x.vis->class == PseudoColor){
       +                if(_x.usetable == 0){
       +                        _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll);
       +                        XStoreColors(_x.display, _x.cmap, _x.map, 256);
       +                        for(i = 0; i < 256; i++){
       +                                _x.tox11[i] = i;
       +                                _x.toplan9[i] = i;
       +                        }
       +                }else{
       +                        for(i = 0; i < 128; i++){
       +                                c = _x.map7[i];
       +                                if(!XAllocColor(_x.display, _x.cmap, &c)){
       +                                        werrstr("can't allocate colors in 7-bit map");
       +                                        return -1;
       +                                }
       +                                _x.tox11[_x.map7to8[i][0]] = c.pixel;
       +                                _x.tox11[_x.map7to8[i][1]] = c.pixel;
       +                                _x.toplan9[c.pixel] = _x.map7to8[i][0];
       +                        }
       +                }
       +        }else{
       +                werrstr("unsupported visual class %d", _x.vis->class);
       +                return -1;
       +        }
       +        return 0;
       +}
       +
       +void
       +rpc_shutdown(void)
       +{
       +}
       +
       +void
       +rpc_flush(Client *client, Rectangle r)
       +{
       +        Xwin *w = (Xwin*)client->view;
       +
       +        xlock();
       +        if(w->nextscreenpm != w->screenpm){
       +                XSync(_x.display, False);
       +                XFreePixmap(_x.display, w->screenpm);
       +                w->screenpm = w->nextscreenpm;
       +        }
       +
       +        if(r.min.x >= r.max.x || r.min.y >= r.max.y) {
       +                xunlock();
       +                return;
       +        }
       +
       +        XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
       +                Dx(r), Dy(r), r.min.x, r.min.y);
       +        XFlush(_x.display);
       +        xunlock();
       +}
       +
       +static void
       +_xexpose(Xwin *w, XEvent *e)
       +{
       +        XExposeEvent *xe;
       +        Rectangle r;
       +
       +        if(w->screenpm != w->nextscreenpm)
       +                return;
       +        xe = (XExposeEvent*)e;
       +        r.min.x = xe->x;
       +        r.min.y = xe->y;
       +        r.max.x = xe->x+xe->width;
       +        r.max.y = xe->y+xe->height;
       +        XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
       +                Dx(r), Dy(r), r.min.x, r.min.y);
       +        XSync(_x.display, False);
       +}
       +
       +static int
       +_xdestroy(Xwin *w, XEvent *e)
       +{
       +        XDestroyWindowEvent *xe;
       +
       +        xe = (XDestroyWindowEvent*)e;
       +        if(xe->window == w->drawable){
       +                w->destroyed = 1;
       +                return 1;
       +        }
       +        return 0;
       +}
       +
       +static int
       +_xconfigure(Xwin *w, XEvent *e)
       +{
       +        Rectangle r;
       +        XConfigureEvent *xe = (XConfigureEvent*)e;
       +
       +        if(!w->fullscreen){
       +                int rx, ry;
       +                XWindow xw;
       +                if(XTranslateCoordinates(_x.display, w->drawable, DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &xw))
       +                        w->windowrect = Rect(rx, ry, rx+xe->width, ry+xe->height);
       +        }
       +
       +        if(xe->width == Dx(w->screenr) && xe->height == Dy(w->screenr))
       +                return 0;
       +        r = Rect(0, 0, xe->width, xe->height);
       +
       +        if(w->screenpm != w->nextscreenpm){
       +                XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
       +                        Dx(r), Dy(r), r.min.x, r.min.y);
       +                XSync(_x.display, False);
       +        }
       +        w->newscreenr = r;
       +        return 1;
       +}
       +
       +static int
       +_xreplacescreenimage(Client *client)
       +{
       +        Memimage *m;
       +        XDrawable pixmap;
       +        Rectangle r;
       +        Xwin *w;
       +        
       +        w = (Xwin*)client->view;
       +        r = w->newscreenr;
       +        pixmap = XCreatePixmap(_x.display, w->drawable, Dx(r), Dy(r), _x.depth);
       +        m = _xallocmemimage(r, _x.chan, pixmap);
       +        if(w->nextscreenpm != w->screenpm)
       +                XFreePixmap(_x.display, w->nextscreenpm);
       +        w->nextscreenpm = pixmap;
       +        w->screenr = r;
       +        client->mouserect = r;
       +        gfx_replacescreenimage(client, m);
       +        return 1;
       +}
       +
       +void
       +rpc_resizeimg(Client *client)
       +{
       +        xlock();
       +        _xreplacescreenimage(client);
       +        xunlock();
       +}
       +
       +void
       +rpc_gfxdrawlock(void)
       +{
       +        xlock();
       +}
       +
       +void
       +rpc_gfxdrawunlock(void)
       +{
       +        xunlock();
       +}
       +void
       +rpc_topwin(Client *client)
       +{
       +        Xwin *w = (Xwin*)client->view;
       +
       +        xlock();
       +        XMapRaised(_x.display, w->drawable);
       +        XSetInputFocus(_x.display, w->drawable, RevertToPointerRoot,
       +                CurrentTime);
       +        XFlush(_x.display);
       +        xunlock();
       +}
       +
       +void
       +rpc_resizewindow(Client *client, Rectangle r)
       +{
       +        Xwin *w = (Xwin*)client->view;
       +        XWindowChanges e;
       +        int value_mask;
       +
       +        xlock();
       +        memset(&e, 0, sizeof e);
       +        value_mask = CWX|CWY|CWWidth|CWHeight;
       +        e.width = Dx(r);
       +        e.height = Dy(r);
       +        XConfigureWindow(_x.display, w->drawable, value_mask, &e);
       +        XFlush(_x.display);
       +        xunlock();
       +}
       +
       +static void
       +_xmovewindow(Xwin *w, Rectangle r)
       +{
       +        XWindowChanges e;
       +        int value_mask;
       +
       +        memset(&e, 0, sizeof e);
       +        value_mask = CWX|CWY|CWWidth|CWHeight;
       +        e.x = r.min.x;
       +        e.y = r.min.y;
       +        e.width = Dx(r);
       +        e.height = Dy(r);
       +        XConfigureWindow(_x.display, w->drawable, value_mask, &e);
       +        XFlush(_x.display);
       +}
       +
       +static int
       +_xtoplan9kbd(XEvent *e)
       +{
       +        KeySym k;
       +
       +        if(e->xany.type != KeyPress)
       +                return -1;
       +        needstack(64*1024);        /* X has some *huge* buffers in openobject */
       +                /* and they're even bigger on SuSE */
       +        XLookupString((XKeyEvent*)e,NULL,0,&k,NULL);
       +        if(k == NoSymbol)
       +                return -1;
       +
       +        if(k&0xFF00){
       +                switch(k){
       +                case XK_BackSpace:
       +                case XK_Tab:
       +                case XK_Escape:
       +                case XK_Delete:
       +                case XK_KP_0:
       +                case XK_KP_1:
       +                case XK_KP_2:
       +                case XK_KP_3:
       +                case XK_KP_4:
       +                case XK_KP_5:
       +                case XK_KP_6:
       +                case XK_KP_7:
       +                case XK_KP_8:
       +                case XK_KP_9:
       +                case XK_KP_Divide:
       +                case XK_KP_Multiply:
       +                case XK_KP_Subtract:
       +                case XK_KP_Add:
       +                case XK_KP_Decimal:
       +                        k &= 0x7F;
       +                        break;
       +                case XK_Linefeed:
       +                        k = '\r';
       +                        break;
       +                case XK_KP_Space:
       +                        k = ' ';
       +                        break;
       +                case XK_Home:
       +                case XK_KP_Home:
       +                        k = Khome;
       +                        break;
       +                case XK_Left:
       +                case XK_KP_Left:
       +                        k = Kleft;
       +                        break;
       +                case XK_Up:
       +                case XK_KP_Up:
       +                        k = Kup;
       +                        break;
       +                case XK_Down:
       +                case XK_KP_Down:
       +                        k = Kdown;
       +                        break;
       +                case XK_Right:
       +                case XK_KP_Right:
       +                        k = Kright;
       +                        break;
       +                case XK_Page_Down:
       +                case XK_KP_Page_Down:
       +                        k = Kpgdown;
       +                        break;
       +                case XK_End:
       +                case XK_KP_End:
       +                        k = Kend;
       +                        break;
       +                case XK_Page_Up:
       +                case XK_KP_Page_Up:
       +                        k = Kpgup;
       +                        break;
       +                case XK_Insert:
       +                case XK_KP_Insert:
       +                        k = Kins;
       +                        break;
       +                case XK_KP_Enter:
       +                case XK_Return:
       +                        k = '\n';
       +                        break;
       +                case XK_Alt_L:
       +                case XK_Meta_L:        /* Shift Alt on PCs */
       +                case XK_Alt_R:
       +                case XK_Meta_R:        /* Shift Alt on PCs */
       +                case XK_Multi_key:
       +                        return -1;
       +                default:                /* not ISO-1 or tty control */
       +                        if(k>0xff) {
       +                                k = _p9keysym2ucs(k);
       +                                if(k==-1) return -1;
       +                        }
       +                }
       +        }
       +
       +        /* Compensate for servers that call a minus a hyphen */
       +        if(k == XK_hyphen)
       +                k = XK_minus;
       +        /* Do control mapping ourselves if translator doesn't */
       +        if(e->xkey.state&ControlMask)
       +                k &= 0x9f;
       +        if(k == NoSymbol) {
       +                return -1;
       +        }
       +
       +        return k+0;
       +}
       +
       +static int
       +_xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m)
       +{
       +        int s;
       +        XButtonEvent *be;
       +        XMotionEvent *me;
       +
       +        if(_x.putsnarf != _x.assertsnarf){
       +                _x.assertsnarf = _x.putsnarf;
       +                XSetSelectionOwner(_x.display, XA_PRIMARY, w->drawable, CurrentTime);
       +                if(_x.clipboard != None)
       +                        XSetSelectionOwner(_x.display, _x.clipboard, w->drawable, CurrentTime);
       +                XFlush(_x.display);
       +        }
       +
       +        switch(e->type){
       +        case ButtonPress:
       +                be = (XButtonEvent*)e;
       +
       +                /*
       +                 * Fake message, just sent to make us announce snarf.
       +                 * Apparently state and button are 16 and 8 bits on
       +                 * the wire, since they are truncated by the time they
       +                 * get to us.
       +                 */
       +                if(be->send_event
       +                && (~be->state&0xFFFF)==0
       +                && (~be->button&0xFF)==0)
       +                        return -1;
       +                /* BUG? on mac need to inherit these from elsewhere? */
       +                m->xy.x = be->x;
       +                m->xy.y = be->y;
       +                s = be->state;
       +                m->msec = be->time;
       +                switch(be->button){
       +                case 1:
       +                        s |= Button1Mask;
       +                        break;
       +                case 2:
       +                        s |= Button2Mask;
       +                        break;
       +                case 3:
       +                        s |= Button3Mask;
       +                        break;
       +                case 4:
       +                        s |= Button4Mask;
       +                        break;
       +                case 5:
       +                        s |= Button5Mask;
       +                        break;
       +                }
       +                break;
       +        case ButtonRelease:
       +                be = (XButtonEvent*)e;
       +                m->xy.x = be->x;
       +                m->xy.y = be->y;
       +                s = be->state;
       +                m->msec = be->time;
       +                switch(be->button){
       +                case 1:
       +                        s &= ~Button1Mask;
       +                        break;
       +                case 2:
       +                        s &= ~Button2Mask;
       +                        break;
       +                case 3:
       +                        s &= ~Button3Mask;
       +                        break;
       +                case 4:
       +                        s &= ~Button4Mask;
       +                        break;
       +                case 5:
       +                        s &= ~Button5Mask;
       +                        break;
       +                }
       +                break;
       +
       +        case MotionNotify:
       +                me = (XMotionEvent*)e;
       +                s = me->state;
       +                m->xy.x = me->x;
       +                m->xy.y = me->y;
       +                m->msec = me->time;
       +                return 0; // do not set buttons
       +
       +        default:
       +                return -1;
       +        }
       +
       +        m->buttons = 0;
       +        if(s & Button1Mask)
       +                m->buttons |= 1;
       +        if(s & Button2Mask)
       +                m->buttons |= 2;
       +        if(s & Button3Mask)
       +                m->buttons |= 4;
       +        if(s & Button4Mask)
       +                m->buttons |= 8;
       +        if(s & Button5Mask)
       +                m->buttons |= 16;
       +        return 0;
       +}
       +
       +void
       +rpc_setmouse(Client *client, Point p)
       +{
       +        Xwin *w = (Xwin*)client->view;
       +
       +        xlock();
       +        XWarpPointer(_x.display, None, w->drawable, 0, 0, 0, 0, p.x, p.y);
       +        XFlush(_x.display);
       +        xunlock();
       +}
       +
       +static int
       +revbyte(int b)
       +{
       +        int r;
       +
       +        r = 0;
       +        r |= (b&0x01) << 7;
       +        r |= (b&0x02) << 5;
       +        r |= (b&0x04) << 3;
       +        r |= (b&0x08) << 1;
       +        r |= (b&0x10) >> 1;
       +        r |= (b&0x20) >> 3;
       +        r |= (b&0x40) >> 5;
       +        r |= (b&0x80) >> 7;
       +        return r;
       +}
       +
       +static void
       +xcursorarrow(Xwin *w)
       +{
       +        if(_x.cursor != 0){
       +                XFreeCursor(_x.display, _x.cursor);
       +                _x.cursor = 0;
       +        }
       +        XUndefineCursor(_x.display, w->drawable);
       +        XFlush(_x.display);
       +}
       +
       +
       +void
       +rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
       +{
       +        Xwin *w = (Xwin*)client->view;
       +        XColor fg, bg;
       +        XCursor xc;
       +        Pixmap xsrc, xmask;
       +        int i;
       +        uchar src[2*16], mask[2*16];
       +
       +        USED(c2);
       +
       +        xlock();
       +        if(c == nil){
       +                xcursorarrow(w);
       +                xunlock();
       +                return;
       +        }
       +        for(i=0; i<2*16; i++){
       +                src[i] = revbyte(c->set[i]);
       +                mask[i] = revbyte(c->set[i] | c->clr[i]);
       +        }
       +
       +        fg = _x.map[0];
       +        bg = _x.map[255];
       +        xsrc = XCreateBitmapFromData(_x.display, w->drawable, (char*)src, 16, 16);
       +        xmask = XCreateBitmapFromData(_x.display, w->drawable, (char*)mask, 16, 16);
       +        xc = XCreatePixmapCursor(_x.display, xsrc, xmask, &fg, &bg, -c->offset.x, -c->offset.y);
       +        if(xc != 0) {
       +                XDefineCursor(_x.display, w->drawable, xc);
       +                if(_x.cursor != 0)
       +                        XFreeCursor(_x.display, _x.cursor);
       +                _x.cursor = xc;
       +        }
       +        XFreePixmap(_x.display, xsrc);
       +        XFreePixmap(_x.display, xmask);
       +        XFlush(_x.display);
       +        xunlock();
       +}
       +
       +struct {
       +        QLock lk;
       +        char buf[SnarfSize];
       +#ifdef APPLESNARF
       +        Rune rbuf[SnarfSize];
       +        PasteboardRef apple;
       +#endif
       +} clip;
       +
       +static uchar*
       +_xgetsnarffrom(Xwin *w, XWindow xw, Atom clipboard, Atom target, int timeout0, int timeout)
       +{
       +        Atom prop, type;
       +        ulong len, lastlen, dummy;
       +        int fmt, i;
       +        uchar *data, *xdata;
       +
       +        /*
       +         * We should be waiting for SelectionNotify here, but it might never
       +         * come, and we have no way to time out.  Instead, we will clear
       +         * local property #1, request our buddy to fill it in for us, and poll
       +         * until he's done or we get tired of waiting.
       +         */
       +        prop = 1;
       +        XChangeProperty(_x.display, w->drawable, prop, target, 8, PropModeReplace, (uchar*)"", 0);
       +        XConvertSelection(_x.display, clipboard, target, prop, w->drawable, CurrentTime);
       +        XFlush(_x.display);
       +        lastlen = 0;
       +        timeout0 = (timeout0 + 9)/10;
       +        timeout = (timeout + 9)/10;
       +        for(i=0; i<timeout0 || (lastlen!=0 && i<timeout); i++){
       +                usleep(10*1000);
       +                XGetWindowProperty(_x.display, w->drawable, prop, 0, 0, 0, AnyPropertyType,
       +                        &type, &fmt, &dummy, &len, &xdata);
       +                if(lastlen == len && len > 0){
       +                        XFree(xdata);
       +                        break;
       +                }
       +                lastlen = len;
       +                XFree(xdata);
       +        }
       +        if(len == 0)
       +                return nil;
       +
       +        /* get the property */
       +        xdata = nil;
       +        XGetWindowProperty(_x.display, w->drawable, prop, 0, SnarfSize/sizeof(ulong), 0,
       +                AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
       +        if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){
       +                if(xdata)
       +                        XFree(xdata);
       +                return nil;
       +        }
       +        if(xdata){
       +                data = (uchar*)strdup((char*)xdata);
       +                XFree(xdata);
       +                return data;
       +        }
       +        return nil;
       +}
       +
       +char*
       +rpc_getsnarf(void)
       +{
       +        uchar *data;
       +        Atom clipboard;
       +        XWindow xw;
       +        Xwin *w;
       +
       +        qlock(&clip.lk);
       +        xlock();
       +        w = _x.windows;
       +        /*
       +         * Have we snarfed recently and the X server hasn't caught up?
       +         */
       +        if(_x.putsnarf != _x.assertsnarf)
       +                goto mine;
       +
       +        /*
       +         * Is there a primary selection (highlighted text in an xterm)?
       +         */
       +        clipboard = XA_PRIMARY;
       +        xw = XGetSelectionOwner(_x.display, XA_PRIMARY);
       +        // TODO check more
       +        if(xw == w->drawable){
       +        mine:
       +                data = (uchar*)strdup(clip.buf);
       +                goto out;
       +        }
       +
       +        /*
       +         * If not, is there a clipboard selection?
       +         */
       +        if(xw == None && _x.clipboard != None){
       +                clipboard = _x.clipboard;
       +                xw = XGetSelectionOwner(_x.display, _x.clipboard);
       +                if(xw == w->drawable)
       +                        goto mine;
       +        }
       +
       +        /*
       +         * If not, give up.
       +         */
       +        if(xw == None){
       +                data = nil;
       +                goto out;
       +        }
       +
       +        if((data = _xgetsnarffrom(w, xw, clipboard, _x.utf8string, 10, 100)) == nil)
       +        if((data = _xgetsnarffrom(w, xw, clipboard, XA_STRING, 10, 100)) == nil){
       +                /* nothing left to do */
       +        }
       +
       +out:
       +        xunlock();
       +        qunlock(&clip.lk);
       +        return (char*)data;
       +}
       +
       +void
       +__xputsnarf(char *data)
       +{
       +        XButtonEvent e;
       +        Xwin *w;
       +        
       +        if(strlen(data) >= SnarfSize)
       +                return;
       +        qlock(&clip.lk);
       +        xlock();
       +        w = _x.windows;
       +        strcpy(clip.buf, data);
       +        /* leave note for mouse proc to assert selection ownership */
       +        _x.putsnarf++;
       +
       +        /* send mouse a fake event so snarf is announced */
       +        memset(&e, 0, sizeof e);
       +        e.type = ButtonPress;
       +        e.window = w->drawable;
       +        e.state = ~0;
       +        e.button = ~0;
       +        XSendEvent(_x.display, w->drawable, True, ButtonPressMask, (XEvent*)&e);
       +        XFlush(_x.display);
       +        xunlock();
       +        qunlock(&clip.lk);
       +}
       +
       +static int
       +_xselect(XEvent *e)
       +{
       +        char *name;
       +        XEvent r;
       +        XSelectionRequestEvent *xe;
       +        Atom a[4];
       +
       +        memset(&r, 0, sizeof r);
       +        xe = (XSelectionRequestEvent*)e;
       +if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d (sizeof atom=%d)\n",
       +        xe->target, xe->requestor, xe->property, xe->selection, sizeof a[0]);
       +        r.xselection.property = xe->property;
       +        if(xe->target == _x.targets){
       +                a[0] = _x.utf8string;
       +                a[1] = XA_STRING;
       +                a[2] = _x.text;
       +                a[3] = _x.compoundtext;
       +                XChangeProperty(_x.display, xe->requestor, xe->property, XA_ATOM,
       +                        32, PropModeReplace, (uchar*)a, nelem(a));
       +        }else if(xe->target == XA_STRING
       +        || xe->target == _x.utf8string
       +        || xe->target == _x.text
       +        || xe->target == _x.compoundtext
       +        || ((name = XGetAtomName(_x.display, xe->target)) && strcmp(name, "text/plain;charset=UTF-8") == 0)){
       +                /* text/plain;charset=UTF-8 seems nonstandard but is used by Synergy */
       +                /* if the target is STRING we're supposed to reply with Latin1 XXX */
       +                qlock(&clip.lk);
       +                XChangeProperty(_x.display, xe->requestor, xe->property, xe->target,
       +                        8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
       +                qunlock(&clip.lk);
       +        }else{
       +                if(strcmp(name, "TIMESTAMP") != 0)
       +                        fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
       +                r.xselection.property = None;
       +        }
       +
       +        r.xselection.display = xe->display;
       +        /* r.xselection.property filled above */
       +        r.xselection.target = xe->target;
       +        r.xselection.type = SelectionNotify;
       +        r.xselection.requestor = xe->requestor;
       +        r.xselection.time = xe->time;
       +        r.xselection.send_event = True;
       +        r.xselection.selection = xe->selection;
       +        XSendEvent(_x.display, xe->requestor, False, 0, &r);
       +        XFlush(_x.display);
       +        return 0;
       +}
       +
       +#ifdef APPLESNARF
       +char*
       +_applegetsnarf(void)
       +{
       +        char *s, *t;
       +        CFArrayRef flavors;
       +        CFDataRef data;
       +        CFIndex nflavor, ndata, j;
       +        CFStringRef type;
       +        ItemCount nitem;
       +        PasteboardItemID id;
       +        PasteboardSyncFlags flags;
       +        UInt32 i;
       +
       +/*        fprint(2, "applegetsnarf\n"); */
       +        qlock(&clip.lk);
       +        if(clip.apple == nil){
       +                if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
       +                        fprint(2, "apple pasteboard create failed\n");
       +                        qunlock(&clip.lk);
       +                        return nil;
       +                }
       +        }
       +        flags = PasteboardSynchronize(clip.apple);
       +        if(flags&kPasteboardClientIsOwner){
       +                s = strdup(clip.buf);
       +                qunlock(&clip.lk);
       +                return s;
       +        }
       +        if(PasteboardGetItemCount(clip.apple, &nitem) != noErr){
       +                fprint(2, "apple pasteboard get item count failed\n");
       +                qunlock(&clip.lk);
       +                return nil;
       +        }
       +        for(i=1; i<=nitem; i++){
       +                if(PasteboardGetItemIdentifier(clip.apple, i, &id) != noErr)
       +                        continue;
       +                if(PasteboardCopyItemFlavors(clip.apple, id, &flavors) != noErr)
       +                        continue;
       +                nflavor = CFArrayGetCount(flavors);
       +                for(j=0; j<nflavor; j++){
       +                        type = (CFStringRef)CFArrayGetValueAtIndex(flavors, j);
       +                        if(!UTTypeConformsTo(type, CFSTR("public.utf16-plain-text")))
       +                                continue;
       +                        if(PasteboardCopyItemFlavorData(clip.apple, id, type, &data) != noErr)
       +                                continue;
       +                        ndata = CFDataGetLength(data);
       +                        qunlock(&clip.lk);
       +                        s = smprint("%.*S", ndata/2, (Rune*)CFDataGetBytePtr(data));
       +                        CFRelease(flavors);
       +                        CFRelease(data);
       +                        for(t=s; *t; t++)
       +                                if(*t == '\r')
       +                                        *t = '\n';
       +                        return s;
       +                }
       +                CFRelease(flavors);
       +        }
       +        qunlock(&clip.lk);
       +        return nil;
       +}
       +
       +void
       +_appleputsnarf(char *s)
       +{
       +        CFDataRef cfdata;
       +        PasteboardSyncFlags flags;
       +
       +/*        fprint(2, "appleputsnarf\n"); */
       +
       +        if(strlen(s) >= SnarfSize)
       +                return;
       +        qlock(&clip.lk);
       +        strcpy(clip.buf, s);
       +        runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s);
       +        if(clip.apple == nil){
       +                if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
       +                        fprint(2, "apple pasteboard create failed\n");
       +                        qunlock(&clip.lk);
       +                        return;
       +                }
       +        }
       +        if(PasteboardClear(clip.apple) != noErr){
       +                fprint(2, "apple pasteboard clear failed\n");
       +                qunlock(&clip.lk);
       +                return;
       +        }
       +        flags = PasteboardSynchronize(clip.apple);
       +        if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){
       +                fprint(2, "apple pasteboard cannot assert ownership\n");
       +                qunlock(&clip.lk);
       +                return;
       +        }
       +        cfdata = CFDataCreate(kCFAllocatorDefault,
       +                (uchar*)clip.rbuf, runestrlen(clip.rbuf)*2);
       +        if(cfdata == nil){
       +                fprint(2, "apple pasteboard cfdatacreate failed\n");
       +                qunlock(&clip.lk);
       +                return;
       +        }
       +        if(PasteboardPutItemFlavor(clip.apple, (PasteboardItemID)1,
       +                CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){
       +                fprint(2, "apple pasteboard putitem failed\n");
       +                CFRelease(cfdata);
       +                qunlock(&clip.lk);
       +                return;
       +        }
       +        /* CFRelease(cfdata); ??? */
       +        qunlock(&clip.lk);
       +}
       +#endif        /* APPLESNARF */
       +
       +void
       +rpc_putsnarf(char *data)
       +{
       +#ifdef APPLESNARF
       +        _appleputsnarf(data);
       +#endif
       +        __xputsnarf(data);
       +}
       +
       +/*
       + * Send the mouse event back to the window manager.
       + * So that 9term can tell rio to pop up its button3 menu.
       + */
       +void
       +rpc_bouncemouse(Client *c, Mouse m)
       +{
       +        Xwin *w = (Xwin*)c->view;
       +        XButtonEvent e;
       +        XWindow dw;
       +        
       +        xlock();
       +        e.type = ButtonPress;
       +        e.state = 0;
       +        e.button = 0;
       +        if(m.buttons&1)
       +                e.button = 1;
       +        else if(m.buttons&2)
       +                e.button = 2;
       +        else if(m.buttons&4)
       +                e.button = 3;
       +        e.same_screen = 1;
       +        XTranslateCoordinates(_x.display, w->drawable,
       +                DefaultRootWindow(_x.display),
       +                m.xy.x, m.xy.y, &e.x_root, &e.y_root, &dw);
       +        e.root = DefaultRootWindow(_x.display);
       +        e.window = e.root;
       +        e.subwindow = None;
       +        e.x = e.x_root;
       +        e.y = e.y_root;
       +#undef time
       +        e.time = CurrentTime;
       +        XUngrabPointer(_x.display, m.msec);
       +        XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);
       +        XFlush(_x.display);
       +        xunlock();
       +}
 (DIR) diff --git a/src/cmd/devdraw/x11-srv.c b/src/cmd/devdraw/x11-srv.c
       t@@ -1,637 +0,0 @@
       -/*
       - * Window system protocol server.
       - * Use select and a single proc and single stack
       - * to avoid aggravating the X11 library, which is
       - * subtle and quick to anger.
       - */
       -
       -// #define SHOWEVENT
       -
       -#include <u.h>
       -#include <sys/select.h>
       -#include <errno.h>
       -#ifdef SHOWEVENT
       -#include <stdio.h>
       -#endif
       -#include "x11-inc.h"
       -
       -#include <libc.h>
       -#include <draw.h>
       -#include <memdraw.h>
       -#include <memlayer.h>
       -#include <keyboard.h>
       -#include <mouse.h>
       -#include <cursor.h>
       -#include <drawfcall.h>
       -#include "x11-memdraw.h"
       -#include "devdraw.h"
       -
       -#undef time
       -
       -#define MouseMask (\
       -        ButtonPressMask|\
       -        ButtonReleaseMask|\
       -        PointerMotionMask|\
       -        Button1MotionMask|\
       -        Button2MotionMask|\
       -        Button3MotionMask)
       -
       -#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|EnterWindowMask|LeaveWindowMask|FocusChangeMask
       -
       -typedef struct Kbdbuf Kbdbuf;
       -typedef struct Mousebuf Mousebuf;
       -typedef struct Fdbuf Fdbuf;
       -typedef struct Tagbuf Tagbuf;
       -
       -struct Kbdbuf
       -{
       -        Rune r[32];
       -        int ri;
       -        int wi;
       -        int stall;
       -};
       -
       -struct Mousebuf
       -{
       -        Mouse m[32];
       -        int ri;
       -        int wi;
       -        int stall;
       -        int resized;
       -};
       -
       -struct Tagbuf
       -{
       -        int t[32];
       -        int ri;
       -        int wi;
       -};
       -
       -struct Fdbuf
       -{
       -        uchar buf[2*MAXWMSG];
       -        uchar *rp;
       -        uchar *wp;
       -        uchar *ep;
       -};
       -
       -Kbdbuf kbd;
       -Mousebuf mouse;
       -Fdbuf fdin;
       -Fdbuf fdout;
       -Tagbuf kbdtags;
       -Tagbuf mousetags;
       -
       -void fdslide(Fdbuf*);
       -void runmsg(Wsysmsg*);
       -void replymsg(Wsysmsg*);
       -void runxevent(XEvent*);
       -void matchkbd(void);
       -void matchmouse(void);
       -int fdnoblock(int);
       -
       -int chatty;
       -int drawsleep;
       -int fullscreen;
       -
       -Rectangle windowrect;
       -Rectangle screenrect;
       -
       -void
       -usage(void)
       -{
       -        fprint(2, "usage: devdraw (don't run directly)\n");
       -        exits("usage");
       -}
       -
       -void
       -bell(void *v, char *msg)
       -{
       -        if(strcmp(msg, "alarm") == 0)
       -                drawsleep = drawsleep ? 0 : 1000;
       -        noted(NCONT);
       -}
       -
       -void
       -main(int argc, char **argv)
       -{
       -        int n, top, firstx;
       -        fd_set rd, wr, xx;
       -        Wsysmsg m;
       -        XEvent event;
       -
       -        /*
       -         * 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);
       -
       -        /* reopens stdout if debugging */
       -        runxevent(0);
       -
       -        fmtinstall('W', drawfcallfmt);
       -
       -        ARGBEGIN{
       -        case 'D':
       -                chatty++;
       -                break;
       -        default:
       -                usage();
       -        }ARGEND
       -
       -        /*
       -         * Ignore arguments.  They're only for good ps -a listings.
       -         */
       -
       -        notify(bell);
       -
       -        fdin.rp = fdin.wp = fdin.buf;
       -        fdin.ep = fdin.buf+sizeof fdin.buf;
       -
       -        fdout.rp = fdout.wp = fdout.buf;
       -        fdout.ep = fdout.buf+sizeof fdout.buf;
       -
       -        fdnoblock(3);
       -        fdnoblock(4);
       -
       -        firstx = 1;
       -        _x.fd = -1;
       -        for(;;){
       -                /* set up file descriptors */
       -                FD_ZERO(&rd);
       -                FD_ZERO(&wr);
       -                FD_ZERO(&xx);
       -                /*
       -                 * Don't read unless there's room *and* we haven't
       -                 * already filled the output buffer too much.
       -                 */
       -                if(fdout.wp < fdout.buf+MAXWMSG && fdin.wp < fdin.ep)
       -                        FD_SET(3, &rd);
       -                if(fdout.wp > fdout.rp)
       -                        FD_SET(4, &wr);
       -                FD_SET(3, &xx);
       -                FD_SET(4, &xx);
       -                top = 4;
       -                if(_x.fd >= 0){
       -                        if(firstx){
       -                                firstx = 0;
       -                                XSelectInput(_x.display, _x.drawable, Mask);
       -                        }
       -                        FD_SET(_x.fd, &rd);
       -                        FD_SET(_x.fd, &xx);
       -                        XFlush(_x.display);
       -                        if(_x.fd > top)
       -                                top = _x.fd;
       -                }
       -
       -                if(chatty)
       -                        fprint(2, "select %d...\n", top+1);
       -                /* wait for something to happen */
       -            again:
       -                if(select(top+1, &rd, &wr, &xx, NULL) < 0){
       -                        if(errno == EINTR)
       -                                goto again;
       -                        if(chatty)
       -                                fprint(2, "select failure\n");
       -                        exits(0);
       -                }
       -                if(chatty)
       -                        fprint(2, "got select...\n");
       -
       -                {
       -                        /* read what we can */
       -                        n = 1;
       -                        while(fdin.wp < fdin.ep && (n = read(3, fdin.wp, fdin.ep-fdin.wp)) > 0)
       -                                fdin.wp += n;
       -                        if(n == 0){
       -                                if(chatty)
       -                                        fprint(2, "eof\n");
       -                                exits(0);
       -                        }
       -                        if(n < 0 && errno != EAGAIN)
       -                                sysfatal("reading wsys msg: %r");
       -
       -                        /* pick off messages one by one */
       -                        while((n = convM2W(fdin.rp, fdin.wp-fdin.rp, &m)) > 0){
       -                                /* fprint(2, "<- %W\n", &m); */
       -                                runmsg(&m);
       -                                fdin.rp += n;
       -                        }
       -
       -                        /* slide data to beginning of buf */
       -                        fdslide(&fdin);
       -                }
       -                {
       -                        /* write what we can */
       -                        n = 1;
       -                        while(fdout.rp < fdout.wp && (n = write(4, fdout.rp, fdout.wp-fdout.rp)) > 0)
       -                                fdout.rp += n;
       -                        if(n == 0)
       -                                sysfatal("short write writing wsys");
       -                        if(n < 0 && errno != EAGAIN)
       -                                sysfatal("writing wsys msg: %r");
       -
       -                        /* slide data to beginning of buf */
       -                        fdslide(&fdout);
       -                }
       -                {
       -                        /*
       -                         * Read an X message if we can.
       -                         * (XPending actually calls select to make sure
       -                         * the display's fd is readable and then reads
       -                         * in any waiting data before declaring whether
       -                         * there are events on the queue.)
       -                         */
       -                        while(XPending(_x.display)){
       -                                XNextEvent(_x.display, &event);
       -                                runxevent(&event);
       -                        }
       -                }
       -        }
       -}
       -
       -int
       -fdnoblock(int fd)
       -{
       -        return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK);
       -}
       -
       -void
       -fdslide(Fdbuf *fb)
       -{
       -        int n;
       -
       -        n = fb->wp - fb->rp;
       -        if(n > 0)
       -                memmove(fb->buf, fb->rp, n);
       -        fb->rp = fb->buf;
       -        fb->wp = fb->rp+n;
       -}
       -
       -void
       -replyerror(Wsysmsg *m)
       -{
       -        char err[256];
       -
       -        rerrstr(err, sizeof err);
       -        m->type = Rerror;
       -        m->error = err;
       -        replymsg(m);
       -}
       -
       -
       -
       -/*
       - * Handle a single wsysmsg.
       - * Might queue for later (kbd, mouse read)
       - */
       -void
       -runmsg(Wsysmsg *m)
       -{
       -        uchar buf[65536];
       -        int n;
       -        Memimage *i;
       -
       -        switch(m->type){
       -        case Tinit:
       -                memimageinit();
       -                i = _xattach(m->label, m->winsize);
       -                _initdisplaymemimage(i);
       -                replymsg(m);
       -                break;
       -
       -        case Trdmouse:
       -                mousetags.t[mousetags.wi++] = m->tag;
       -                if(mousetags.wi == nelem(mousetags.t))
       -                        mousetags.wi = 0;
       -                if(mousetags.wi == mousetags.ri)
       -                        sysfatal("too many queued mouse reads");
       -                /* fprint(2, "mouse unstall\n"); */
       -                mouse.stall = 0;
       -                matchmouse();
       -                break;
       -
       -        case Trdkbd:
       -                kbdtags.t[kbdtags.wi++] = m->tag;
       -                if(kbdtags.wi == nelem(kbdtags.t))
       -                        kbdtags.wi = 0;
       -                if(kbdtags.wi == kbdtags.ri)
       -                        sysfatal("too many queued keyboard reads");
       -                kbd.stall = 0;
       -                matchkbd();
       -                break;
       -
       -        case Tmoveto:
       -                _xmoveto(m->mouse.xy);
       -                replymsg(m);
       -                break;
       -
       -        case Tcursor:
       -        case Tcursor2:
       -                if(m->arrowcursor)
       -                        _xsetcursor(nil);
       -                else
       -                        _xsetcursor(&m->cursor);
       -                replymsg(m);
       -                break;
       -
       -        case Tbouncemouse:
       -                _xbouncemouse(&m->mouse);
       -                replymsg(m);
       -                break;
       -
       -        case Tlabel:
       -                _xsetlabel(m->label);
       -                replymsg(m);
       -                break;
       -
       -        case Trdsnarf:
       -                m->snarf = _xgetsnarf();
       -                replymsg(m);
       -                free(m->snarf);
       -                break;
       -
       -        case Twrsnarf:
       -                _xputsnarf(m->snarf);
       -                replymsg(m);
       -                break;
       -
       -        case Trddraw:
       -                n = m->count;
       -                if(n > sizeof buf)
       -                        n = sizeof buf;
       -                n = draw_dataread(buf, n);
       -                if(n < 0)
       -                        replyerror(m);
       -                else{
       -                        m->count = n;
       -                        m->data = buf;
       -                        replymsg(m);
       -                }
       -                break;
       -
       -        case Twrdraw:
       -                if(draw_datawrite(m->data, m->count) < 0)
       -                        replyerror(m);
       -                else
       -                        replymsg(m);
       -                break;
       -
       -        case Ttop:
       -                _xtopwindow();
       -                replymsg(m);
       -                break;
       -
       -        case Tresize:
       -                _xresizewindow(m->rect);
       -                replymsg(m);
       -                break;
       -        }
       -}
       -
       -/*
       - * Reply to m.
       - */
       -void
       -replymsg(Wsysmsg *m)
       -{
       -        int n;
       -
       -        /* T -> R msg */
       -        if(m->type%2 == 0)
       -                m->type++;
       -
       -        /* fprint(2, "-> %W\n", m); */
       -        /* copy to output buffer */
       -        n = sizeW2M(m);
       -        if(fdout.wp+n > fdout.ep)
       -                sysfatal("out of space for reply message");
       -        convW2M(m, fdout.wp, n);
       -        fdout.wp += n;
       -}
       -
       -/*
       - * Match queued kbd reads with queued kbd characters.
       - */
       -void
       -matchkbd(void)
       -{
       -        Wsysmsg m;
       -
       -        if(kbd.stall)
       -                return;
       -        while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){
       -                m.type = Rrdkbd;
       -                m.tag = kbdtags.t[kbdtags.ri++];
       -                if(kbdtags.ri == nelem(kbdtags.t))
       -                        kbdtags.ri = 0;
       -                m.rune = kbd.r[kbd.ri++];
       -                if(kbd.ri == nelem(kbd.r))
       -                        kbd.ri = 0;
       -                replymsg(&m);
       -        }
       -}
       -
       -/*
       - * Match queued mouse reads with queued mouse events.
       - */
       -void
       -matchmouse(void)
       -{
       -        Wsysmsg m;
       -
       -        while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){
       -                m.type = Rrdmouse;
       -                m.tag = mousetags.t[mousetags.ri++];
       -                if(mousetags.ri == nelem(mousetags.t))
       -                        mousetags.ri = 0;
       -                m.mouse = mouse.m[mouse.ri];
       -                m.resized = mouse.resized;
       -                /*
       -                if(m.resized)
       -                        fprint(2, "sending resize\n");
       -                */
       -                mouse.resized = 0;
       -                mouse.ri++;
       -                if(mouse.ri == nelem(mouse.m))
       -                        mouse.ri = 0;
       -                replymsg(&m);
       -        }
       -}
       -
       -static int kbuttons;
       -static int altdown;
       -static int kstate;
       -
       -static void
       -sendmouse(Mouse m)
       -{
       -        m.buttons |= kbuttons;
       -        mouse.m[mouse.wi] = m;
       -        mouse.wi++;
       -        if(mouse.wi == nelem(mouse.m))
       -                mouse.wi = 0;
       -        if(mouse.wi == mouse.ri){
       -                mouse.stall = 1;
       -                mouse.ri = 0;
       -                mouse.wi = 1;
       -                mouse.m[0] = m;
       -                /* fprint(2, "mouse stall\n"); */
       -        }
       -        matchmouse();
       -}
       -
       -/*
       - * Handle an incoming X event.
       - */
       -void
       -runxevent(XEvent *xev)
       -{
       -        int c;
       -        KeySym k;
       -        static Mouse m;
       -        XButtonEvent *be;
       -        XKeyEvent *ke;
       -
       -#ifdef SHOWEVENT
       -        static int first = 1;
       -        if(first){
       -                dup(create("/tmp/devdraw.out", OWRITE, 0666), 1);
       -                setbuf(stdout, 0);
       -                first = 0;
       -        }
       -#endif
       -
       -        if(xev == 0)
       -                return;
       -
       -#ifdef SHOWEVENT
       -        print("\n");
       -        ShowEvent(xev);
       -#endif
       -
       -        switch(xev->type){
       -        case Expose:
       -                _xexpose(xev);
       -                break;
       -
       -        case DestroyNotify:
       -                if(_xdestroy(xev))
       -                        exits(0);
       -                break;
       -
       -        case ConfigureNotify:
       -                if(_xconfigure(xev)){
       -                        mouse.resized = 1;
       -                        _xreplacescreenimage();
       -                        sendmouse(m);
       -                }
       -                break;
       -
       -        case ButtonPress:
       -                be = (XButtonEvent*)xev;
       -                if(be->button == 1) {
       -                        if(kstate & ControlMask)
       -                                be->button = 2;
       -                        else if(kstate & Mod1Mask)
       -                                be->button = 3;
       -                }
       -                // fall through
       -        case ButtonRelease:
       -                altdown = 0;
       -                // fall through
       -        case MotionNotify:
       -                if(mouse.stall)
       -                        return;
       -                if(_xtoplan9mouse(xev, &m) < 0)
       -                        return;
       -                sendmouse(m);
       -                break;
       -
       -        case KeyRelease:
       -        case KeyPress:
       -                ke = (XKeyEvent*)xev;
       -                XLookupString(ke, NULL, 0, &k, NULL);
       -                c = ke->state;
       -                switch(k) {
       -                case XK_Alt_L:
       -                case XK_Meta_L:        /* Shift Alt on PCs */
       -                case XK_Alt_R:
       -                case XK_Meta_R:        /* Shift Alt on PCs */
       -                case XK_Multi_key:
       -                        if(xev->type == KeyPress)
       -                                altdown = 1;
       -                        else if(altdown) {
       -                                altdown = 0;
       -                                sendalt();
       -                        }
       -                        break;
       -                }
       -
       -                switch(k) {
       -                case XK_Control_L:
       -                        if(xev->type == KeyPress)
       -                                c |= ControlMask;
       -                        else
       -                                c &= ~ControlMask;
       -                        goto kbutton;
       -                case XK_Alt_L:
       -                case XK_Shift_L:
       -                        if(xev->type == KeyPress)
       -                                c |= Mod1Mask;
       -                        else
       -                                c &= ~Mod1Mask;
       -                kbutton:
       -                        kstate = c;
       -                        if(m.buttons || kbuttons) {
       -                                altdown = 0; // used alt
       -                                kbuttons = 0;
       -                                if(c & ControlMask)
       -                                        kbuttons |= 2;
       -                                if(c & Mod1Mask)
       -                                        kbuttons |= 4;
       -                                sendmouse(m);
       -                                break;
       -                        }
       -                }
       -
       -                if(xev->type != KeyPress)
       -                        break;
       -                if(k == XK_F11){
       -                        fullscreen = !fullscreen;
       -                        _xmovewindow(fullscreen ? screenrect : windowrect);
       -                        return;
       -                }
       -                if(kbd.stall)
       -                        return;
       -                if((c = _xtoplan9kbd(xev)) < 0)
       -                        return;
       -                kbd.r[kbd.wi++] = c;
       -                if(kbd.wi == nelem(kbd.r))
       -                        kbd.wi = 0;
       -                if(kbd.ri == kbd.wi)
       -                        kbd.stall = 1;
       -                matchkbd();
       -                break;
       -
       -        case FocusOut:
       -                /*
       -                 * Some key combinations (e.g. Alt-Tab) can cause us
       -                 * to see the key down event without the key up event,
       -                 * so clear out the keyboard state when we lose the focus.
       -                 */
       -                kstate = 0;
       -                altdown = 0;
       -                abortcompose();
       -                break;
       -
       -        case SelectionRequest:
       -                _xselect(xev);
       -                break;
       -        }
       -}
 (DIR) diff --git a/src/cmd/devdraw/x11-wsys.c b/src/cmd/devdraw/x11-wsys.c
       t@@ -1,45 +0,0 @@
       -#include <u.h>
       -#include "x11-inc.h"
       -#include <libc.h>
       -#include <draw.h>
       -#include <memdraw.h>
       -#include "x11-memdraw.h"
       -
       -void
       -_xtopwindow(void)
       -{
       -        XMapRaised(_x.display, _x.drawable);
       -        XSetInputFocus(_x.display, _x.drawable, RevertToPointerRoot,
       -                CurrentTime);
       -        XFlush(_x.display);
       -}
       -
       -void
       -_xresizewindow(Rectangle r)
       -{
       -        XWindowChanges e;
       -        int value_mask;
       -
       -        memset(&e, 0, sizeof e);
       -        value_mask = CWX|CWY|CWWidth|CWHeight;
       -        e.width = Dx(r);
       -        e.height = Dy(r);
       -        XConfigureWindow(_x.display, _x.drawable, value_mask, &e);
       -        XFlush(_x.display);
       -}
       -
       -void
       -_xmovewindow(Rectangle r)
       -{
       -        XWindowChanges e;
       -        int value_mask;
       -
       -        memset(&e, 0, sizeof e);
       -        value_mask = CWX|CWY|CWWidth|CWHeight;
       -        e.x = r.min.x;
       -        e.y = r.min.y;
       -        e.width = Dx(r);
       -        e.height = Dy(r);
       -        XConfigureWindow(_x.display, _x.drawable, value_mask, &e);
       -        XFlush(_x.display);
       -}