tdevdraw: use consistent mac-* prefix on macOS files - 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 933b98054f40bb224acda134d7bb77a023bcc57f
 (DIR) parent ce27d7babdf2ee09ff6d1f8d4a166c2208995774
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Wed,  8 Jan 2020 20:07:15 -0500
       
       devdraw: use consistent mac-* prefix on macOS files
       
       We were using osx- and cocoa- but it's not even OS X anymore.
       
       Diffstat:
         D src/cmd/devdraw/cocoa-screen.m      |    1249 -------------------------------
         D src/cmd/devdraw/cocoa-srv.c         |     427 -------------------------------
         R src/cmd/devdraw/osx-draw.c -> src/… |       0 
         R src/cmd/devdraw/cocoa-screen.h -> … |       0 
         A src/cmd/devdraw/mac-screen.m        |    1248 +++++++++++++++++++++++++++++++
         A src/cmd/devdraw/mac-srv.c           |     427 +++++++++++++++++++++++++++++++
         M src/cmd/devdraw/mkwsysrules.sh      |       6 +++---
         D src/cmd/devdraw/osx-keycodes.h      |     189 -------------------------------
         R src/cmd/fontsrv/osx.c -> src/cmd/f… |       0 
         M src/cmd/fontsrv/mkfile              |       2 --
         D src/cmd/fontsrv/osx-cocoa.c         |       1 -
         R src/cmd/snarfer/osx-cocoa-snarfer.… |       0 
         M src/cmd/snarfer/mkfile              |       2 +-
         D src/cmd/snarfer/osx-snarfer.c       |       1 -
       
       14 files changed, 1679 insertions(+), 1873 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/devdraw/cocoa-screen.m b/src/cmd/devdraw/cocoa-screen.m
       t@@ -1,1249 +0,0 @@
       -#define Cursor OSXCursor
       -#define Point OSXPoint
       -#define Rect OSXRect
       -
       -#import <Cocoa/Cocoa.h>
       -#import <Metal/Metal.h>
       -#import <QuartzCore/CAMetalLayer.h>
       -
       -#undef Cursor
       -#undef Point
       -#undef Rect
       -
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -#include <draw.h>
       -#include <memdraw.h>
       -#include <keyboard.h>
       -#include <cursor.h>
       -#include "cocoa-screen.h"
       -#include "osx-keycodes.h"
       -#include "devdraw.h"
       -#include "bigarrow.h"
       -#include "glendapng.h"
       -
       -AUTOFRAMEWORK(Cocoa)
       -AUTOFRAMEWORK(Metal)
       -AUTOFRAMEWORK(QuartzCore)
       -
       -#define LOG        if(0)NSLog
       -
       -static void setprocname(const char*);
       -static uint keycvt(uint);
       -static uint msec(void);
       -static Memimage* initimg(void);
       -
       -void
       -usage(void)
       -{
       -        fprint(2, "usage: devdraw (don't run directly)\n");
       -        threadexitsall("usage");
       -}
       -
       -
       -@interface AppDelegate : NSObject<NSApplicationDelegate,NSWindowDelegate>
       -+ (void)makewin:(NSValue *)v;
       -+ (void)callkicklabel:(NSString *)v;
       -+ (void)callsetNeedsDisplayInRect:(NSValue *)v;
       -+ (void)callsetcursor:(NSValue *)v;
       -@end
       -@interface DevDrawView : NSView<NSTextInputClient>
       -- (void)clearInput;
       -- (void)getmouse:(NSEvent *)e;
       -- (void)sendmouse:(NSUInteger)b;
       -- (void)resetLastInputRect;
       -- (void)enlargeLastInputRect:(NSRect)r;
       -@end
       -@interface DrawLayer : CAMetalLayer
       -@end
       -
       -static AppDelegate *myApp = NULL;
       -static DevDrawView *myContent = NULL;
       -static NSWindow *win = NULL;
       -static NSCursor *currentCursor = NULL;
       -
       -static DrawLayer *layer;
       -static id<MTLDevice> device;
       -static id<MTLCommandQueue> commandQueue;
       -static id<MTLTexture> texture;
       -
       -static Memimage *img = NULL;
       -
       -static QLock snarfl;
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        /*
       -         * Move the protocol off stdin/stdout so that
       -         * any inadvertent prints don't screw things up.
       -         */
       -        dup(0,3);
       -        dup(1,4);
       -        close(0);
       -        close(1);
       -        open("/dev/null", OREAD);
       -        open("/dev/null", OWRITE);
       -
       -        ARGBEGIN{
       -        case 'D':                /* for good ps -a listings */
       -                break;
       -        case 'f':                /* fall through for backward compatibility */
       -        case 'g':
       -        case 'b':
       -                break;
       -        default:
       -                usage();
       -        }ARGEND
       -
       -        setprocname(argv0);
       -
       -        @autoreleasepool{
       -                [NSApplication sharedApplication];
       -                [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
       -                myApp = [AppDelegate new];
       -                [NSApp setDelegate:myApp];
       -                [NSApp run];
       -        }
       -}
       -
       -
       -void
       -callservep9p(void *v)
       -{
       -        USED(v);
       -
       -        servep9p();
       -        [NSApp terminate:myApp];
       -}
       -
       -@implementation AppDelegate
       -
       -+ (void)makewin:(NSValue *)v
       -{
       -        NSRect r, sr;
       -        Rectangle wr;
       -        int set;
       -        char *s;
       -        NSArray *allDevices;
       -
       -        const NSWindowStyleMask Winstyle = NSWindowStyleMaskTitled
       -                | NSWindowStyleMaskClosable
       -                | NSWindowStyleMaskMiniaturizable
       -                | NSWindowStyleMaskResizable;
       -
       -        sr = [[NSScreen mainScreen] frame];
       -        r = [[NSScreen mainScreen] visibleFrame];
       -
       -        s = [v pointerValue];
       -        LOG(@"makewin(%s)", s);
       -        if(s && *s){
       -                if(parsewinsize(s, &wr, &set) < 0)
       -                        sysfatal("%r");
       -        }else{
       -                wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
       -                set = 0;
       -        }
       -
       -        r.origin.x = wr.min.x;
       -        r.origin.y = sr.size.height-wr.max.y;        /* winsize is top-left-based */
       -        r.size.width = fmin(Dx(wr), r.size.width);
       -        r.size.height = fmin(Dy(wr), r.size.height);
       -        r = [NSWindow contentRectForFrameRect:r styleMask:Winstyle];
       -
       -        win = [[NSWindow alloc]
       -                initWithContentRect:r
       -                styleMask:Winstyle
       -                backing:NSBackingStoreBuffered defer:NO];
       -        [win setTitle:@"devdraw"];
       -
       -        if(!set)
       -                [win center];
       -        [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
       -        [win setContentMinSize:NSMakeSize(64,64)];
       -        [win setOpaque:YES];
       -        [win setRestorable:NO];
       -        [win setAcceptsMouseMovedEvents:YES];
       -        [win setDelegate:myApp];
       -
       -        myContent = [DevDrawView new];
       -        [win setContentView:myContent];
       -        [myContent setWantsLayer:YES];
       -        [myContent setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
       -        
       -        device = nil;
       -        allDevices = MTLCopyAllDevices();
       -        for(id mtlDevice in allDevices) {
       -                if ([mtlDevice isLowPower] && ![mtlDevice isRemovable]) {
       -                        device = mtlDevice;
       -                        break;
       -                }
       -        }
       -        if(!device)
       -                device = MTLCreateSystemDefaultDevice();
       -
       -        commandQueue = [device newCommandQueue];
       -
       -        layer = (DrawLayer *)[myContent layer];
       -        layer.device = device;
       -        layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
       -        layer.framebufferOnly = YES;
       -        layer.opaque = YES;
       -
       -        // We use a default transparent layer on top of the CAMetalLayer.
       -        // This seems to make fullscreen applications behave.
       -        {
       -                CALayer *stub = [CALayer layer];
       -                stub.frame = CGRectMake(0, 0, 1, 1);
       -                [stub setNeedsDisplay];
       -                [layer addSublayer:stub];
       -        }
       -
       -        [NSEvent setMouseCoalescingEnabled:NO];
       -
       -        topwin();
       -}
       -
       -+ (void)callkicklabel:(NSString *)s
       -{
       -        LOG(@"callkicklabel(%@)", s);
       -        [win setTitle:s];
       -        [[NSApp dockTile] setBadgeLabel:s];
       -}
       -
       -
       -+ (void)callsetNeedsDisplayInRect:(NSValue *)v
       -{
       -        NSRect r;
       -        dispatch_time_t time;
       -
       -        r = [v rectValue];
       -        LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
       -        r = [win convertRectFromBacking:r];
       -        LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
       -        [layer setNeedsDisplayInRect:r];
       -
       -        time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC);
       -        dispatch_after(time, dispatch_get_main_queue(), ^(void){
       -                [layer setNeedsDisplayInRect:r];
       -        });
       -
       -        [myContent enlargeLastInputRect:r];
       -}
       -
       -typedef struct Cursors Cursors;
       -struct Cursors {
       -        Cursor *c;
       -        Cursor2 *c2;
       -};
       -
       -+ (void)callsetcursor:(NSValue *)v
       -{
       -        Cursors *cs;
       -        Cursor *c;
       -        Cursor2 *c2;
       -        NSBitmapImageRep *r, *r2;
       -        NSImage *i;
       -        NSPoint p;
       -        uchar *plane[5], *plane2[5];
       -        uint b;
       -
       -        cs = [v pointerValue];
       -        c = cs->c;
       -        if(!c)
       -                c = &bigarrow;
       -        c2 = cs->c2;
       -        if(!c2)
       -                c2 = &bigarrow2;
       -
       -        r = [[NSBitmapImageRep alloc]
       -                initWithBitmapDataPlanes:nil
       -                pixelsWide:16
       -                pixelsHigh:16
       -                bitsPerSample:1
       -                samplesPerPixel:2
       -                hasAlpha:YES
       -                isPlanar:YES
       -                colorSpaceName:NSDeviceWhiteColorSpace
       -                bytesPerRow:2
       -                bitsPerPixel:0];
       -        [r getBitmapDataPlanes:plane];
       -        for(b=0; b<nelem(c->set); b++){
       -                plane[0][b] = ~c->set[b] & c->clr[b];
       -                plane[1][b] = c->set[b] | c->clr[b];
       -        }
       -
       -        r2 = [[NSBitmapImageRep alloc]
       -                initWithBitmapDataPlanes:nil
       -                pixelsWide:32
       -                pixelsHigh:32
       -                bitsPerSample:1
       -                samplesPerPixel:2
       -                hasAlpha:YES
       -                isPlanar:YES
       -                colorSpaceName:NSDeviceWhiteColorSpace
       -                bytesPerRow:4
       -                bitsPerPixel:0];
       -        [r2 getBitmapDataPlanes:plane2];
       -        for(b=0; b<nelem(c2->set); b++){
       -                plane2[0][b] = ~c2->set[b] & c2->clr[b];
       -                plane2[1][b] = c2->set[b] | c2->clr[b];
       -        }
       -
       -        // For checking out the cursor bitmap image
       -/*
       -        static BOOL saveimg = YES;
       -        if(saveimg){
       -                NSData *data = [r representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
       -                [data writeToFile: @"/tmp/r.bmp" atomically: NO];
       -                data = [r2 representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
       -                [data writeToFile: @"/tmp/r2.bmp" atomically: NO];
       -                saveimg = NO;
       -        }
       -*/
       -
       -        i = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)];
       -        [i addRepresentation:r2];
       -        [i addRepresentation:r];
       -
       -        p = NSMakePoint(-c->offset.x, -c->offset.y);
       -        currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
       -
       -        [win invalidateCursorRectsForView:myContent];
       -}
       -
       -- (void)applicationDidFinishLaunching:(id)arg
       -{
       -        NSMenu *m, *sm;
       -        NSData *d;
       -        NSImage *i;
       -
       -        LOG(@"applicationDidFinishLaunching");
       -
       -        sm = [NSMenu new];
       -        [sm addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
       -        [sm addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"];
       -        [sm addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
       -        m = [NSMenu new];
       -        [m addItemWithTitle:@"DEVDRAW" action:NULL keyEquivalent:@""];
       -        [m setSubmenu:sm forItem:[m itemWithTitle:@"DEVDRAW"]];
       -        [NSApp setMainMenu:m];
       -
       -        d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
       -        i = [[NSImage alloc] initWithData:d];
       -        [NSApp setApplicationIconImage:i];
       -        [[NSApp dockTile] display];
       -
       -        proccreate(callservep9p, nil, 0);
       -}
       -
       -- (NSApplicationPresentationOptions)window:(id)arg
       -                willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions {
       -        NSApplicationPresentationOptions o;
       -        o = proposedOptions;
       -        o &= ~(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar);
       -        o |= NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
       -        return o;
       -}
       -
       -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
       -        return YES;
       -}
       -
       -- (void)windowDidResize:(NSNotification *)notification
       -{
       -        if(![myContent inLiveResize] && img) {
       -                resizeimg();
       -        }
       -}
       -
       -- (void)windowDidBecomeKey:(id)arg
       -{
       -        [myContent sendmouse:0];
       -}
       -
       -@end
       -
       -@implementation DevDrawView
       -{
       -        NSMutableString *_tmpText;
       -        NSRange _markedRange;
       -        NSRange _selectedRange;
       -        NSRect _lastInputRect;        // The view is flipped, this is not.
       -        BOOL _tapping;
       -        NSUInteger _tapFingers;
       -        NSUInteger _tapTime;
       -}
       -
       -- (id)init
       -{
       -        LOG(@"View init");
       -        self = [super init];
       -        [self setAllowedTouchTypes:NSTouchTypeMaskDirect|NSTouchTypeMaskIndirect];
       -        _tmpText = [[NSMutableString alloc] initWithCapacity:2];
       -        _markedRange = NSMakeRange(NSNotFound, 0);
       -        _selectedRange = NSMakeRange(0, 0);
       -        return self;
       -}
       -
       -- (CALayer *)makeBackingLayer
       -{
       -        LOG(@"makeBackingLayer");
       -        return [DrawLayer layer];
       -}
       -
       -- (BOOL)wantsUpdateLayer
       -{
       -        return YES;
       -}
       -
       -- (BOOL)isOpaque
       -{
       -        return YES;
       -}
       -
       -- (BOOL)isFlipped
       -{
       -        return YES;
       -}
       -
       -- (BOOL)acceptsFirstResponder
       -{
       -        return YES;
       -}
       -
       -- (void)mouseMoved:(NSEvent*)e{ [self getmouse:e];}
       -- (void)mouseDown:(NSEvent*)e{ [self getmouse:e];}
       -- (void)mouseDragged:(NSEvent*)e{ [self getmouse:e];}
       -- (void)mouseUp:(NSEvent*)e{ [self getmouse:e];}
       -- (void)otherMouseDown:(NSEvent*)e{ [self getmouse:e];}
       -- (void)otherMouseDragged:(NSEvent*)e{ [self getmouse:e];}
       -- (void)otherMouseUp:(NSEvent*)e{ [self getmouse:e];}
       -- (void)rightMouseDown:(NSEvent*)e{ [self getmouse:e];}
       -- (void)rightMouseDragged:(NSEvent*)e{ [self getmouse:e];}
       -- (void)rightMouseUp:(NSEvent*)e{ [self getmouse:e];}
       -
       -- (void)scrollWheel:(NSEvent*)e
       -{
       -        NSInteger s;
       -
       -        s = [e scrollingDeltaY];
       -        if(s > 0)
       -                [self sendmouse:8];
       -        else if (s < 0)
       -                [self sendmouse:16];
       -}
       -
       -- (void)keyDown:(NSEvent*)e
       -{
       -        LOG(@"keyDown to interpret");
       -
       -        [self interpretKeyEvents:[NSArray arrayWithObject:e]];
       -
       -        [self resetLastInputRect];
       -}
       -
       -- (void)flagsChanged:(NSEvent*)e
       -{
       -        static NSEventModifierFlags omod;
       -        NSEventModifierFlags m;
       -        uint b;
       -
       -        LOG(@"flagsChanged");
       -        m = [e modifierFlags];
       -
       -        b = [NSEvent pressedMouseButtons];
       -        b = (b&~6) | (b&4)>>1 | (b&2)<<1;
       -        if(b){
       -                if(m & ~omod & NSEventModifierFlagControl)
       -                        b |= 1;
       -                if(m & ~omod & NSEventModifierFlagOption)
       -                        b |= 2;
       -                if(m & ~omod & NSEventModifierFlagCommand)
       -                        b |= 4;
       -                [self sendmouse:b];
       -        }else if(m & ~omod & NSEventModifierFlagOption)
       -                keystroke(Kalt);
       -
       -        omod = m;
       -}
       -
       -- (void)magnifyWithEvent:(NSEvent*)e
       -{
       -        if(fabs([e magnification]) > 0.02)
       -                [[self window] toggleFullScreen:nil];
       -}
       -
       -- (void)touchesBeganWithEvent:(NSEvent*)e
       -{
       -        _tapping = YES;
       -        _tapFingers = [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count;
       -        _tapTime = msec();
       -}
       -- (void)touchesMovedWithEvent:(NSEvent*)e
       -{
       -        _tapping = NO;
       -}
       -- (void)touchesEndedWithEvent:(NSEvent*)e
       -{
       -        if(_tapping
       -                && [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count == 0
       -                && msec() - _tapTime < 250){
       -                switch(_tapFingers){
       -                case 3:
       -                        [self sendmouse:2];
       -                        [self sendmouse:0];
       -                        break;
       -                case 4:
       -                        [self sendmouse:2];
       -                        [self sendmouse:1];
       -                        [self sendmouse:0];
       -                        break;
       -                }
       -                _tapping = NO;
       -        }
       -}
       -- (void)touchesCancelledWithEvent:(NSEvent*)e
       -{
       -        _tapping = NO;
       -}
       -
       -- (void)getmouse:(NSEvent *)e
       -{
       -        NSUInteger b;
       -        NSEventModifierFlags m;
       -
       -        b = [NSEvent pressedMouseButtons];
       -        b = b&~6 | (b&4)>>1 | (b&2)<<1;
       -        b = mouseswap(b);
       -
       -        if(b == 1){
       -                m = [e modifierFlags];
       -                if(m & NSEventModifierFlagOption){
       -                        abortcompose();
       -                        b = 2;
       -                }else
       -                if(m & NSEventModifierFlagCommand)
       -                        b = 4;
       -        }
       -        [self sendmouse:b];
       -}
       -
       -- (void)sendmouse:(NSUInteger)b
       -{
       -        NSPoint p;
       -
       -        p = [self.window convertPointToBacking:
       -                [self.window mouseLocationOutsideOfEventStream]];
       -        p.y = Dy(mouserect) - p.y;
       -        // LOG(@"(%g, %g) <- sendmouse(%d)", p.x, p.y, (uint)b);
       -        mousetrack(p.x, p.y, b, msec());
       -        if(b && _lastInputRect.size.width && _lastInputRect.size.height)
       -                [self resetLastInputRect];
       -}
       -
       -- (void)resetCursorRects {
       -        [super resetCursorRects];
       -        [self addCursorRect:self.bounds cursor:currentCursor];
       -}
       -
       -- (void)viewDidEndLiveResize
       -{
       -        [super viewDidEndLiveResize];
       -        if(img)
       -                resizeimg();
       -}
       -
       -- (void)viewDidChangeBackingProperties
       -{
       -        [super viewDidChangeBackingProperties];
       -        if(img)
       -                resizeimg();
       -}
       -
       -// conforms to protocol NSTextInputClient
       -- (BOOL)hasMarkedText
       -{
       -        LOG(@"hasMarkedText");
       -        return _markedRange.location != NSNotFound;
       -}
       -- (NSRange)markedRange
       -{
       -        LOG(@"markedRange");
       -        return _markedRange;
       -}
       -- (NSRange)selectedRange
       -{
       -        LOG(@"selectedRange");
       -        return _selectedRange;
       -}
       -- (void)setMarkedText:(id)string
       -        selectedRange:(NSRange)sRange
       -        replacementRange:(NSRange)rRange
       -{
       -        NSString *str;
       -
       -        LOG(@"setMarkedText: %@ (%ld, %ld) (%ld, %ld)", string,
       -                sRange.location, sRange.length,
       -                rRange.location, rRange.length);
       -
       -        [self clearInput];
       -
       -        if([string isKindOfClass:[NSAttributedString class]])
       -                str = [string string];
       -        else
       -                str = string;
       -
       -        if(rRange.location == NSNotFound){
       -                if(_markedRange.location != NSNotFound){
       -                        rRange = _markedRange;
       -                }else{
       -                        rRange = _selectedRange;
       -                }
       -        }
       -
       -        if(str.length == 0){
       -                [_tmpText deleteCharactersInRange:rRange];
       -                [self unmarkText];
       -        }else{
       -                _markedRange = NSMakeRange(rRange.location, str.length);
       -                [_tmpText replaceCharactersInRange:rRange withString:str];
       -        }
       -        _selectedRange.location = rRange.location + sRange.location;
       -        _selectedRange.length = sRange.length;
       -
       -        if(_tmpText.length){
       -                uint i;
       -                LOG(@"text length %ld", _tmpText.length);
       -                for(i = 0; i <= _tmpText.length; ++i){
       -                        if(i == _markedRange.location)
       -                                keystroke('[');
       -                        if(_selectedRange.length){
       -                                if(i == _selectedRange.location)
       -                                        keystroke('{');
       -                                if(i == NSMaxRange(_selectedRange))
       -                                        keystroke('}');
       -                                }
       -                        if(i == NSMaxRange(_markedRange))
       -                                keystroke(']');
       -                        if(i < _tmpText.length)
       -                                keystroke([_tmpText characterAtIndex:i]);
       -                }
       -                int l;
       -                l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
       -                        + (_selectedRange.length > 0);
       -                LOG(@"move left %d", l);
       -                for(i = 0; i < l; ++i)
       -                        keystroke(Kleft);
       -        }
       -
       -        LOG(@"text: \"%@\"  (%ld,%ld)  (%ld,%ld)", _tmpText,
       -                _markedRange.location, _markedRange.length,
       -                _selectedRange.location, _selectedRange.length);
       -}
       -- (void)unmarkText
       -{
       -        //NSUInteger i;
       -        NSUInteger len;
       -
       -        LOG(@"unmarkText");
       -        len = [_tmpText length];
       -        //for(i = 0; i < len; ++i)
       -        //        keystroke([_tmpText characterAtIndex:i]);
       -        [_tmpText deleteCharactersInRange:NSMakeRange(0, len)];
       -        _markedRange = NSMakeRange(NSNotFound, 0);
       -        _selectedRange = NSMakeRange(0, 0);
       -}
       -- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText
       -{
       -        LOG(@"validAttributesForMarkedText");
       -        return @[];
       -}
       -- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r
       -        actualRange:(NSRangePointer)actualRange
       -{
       -        NSRange sr;
       -        NSAttributedString *s;
       -
       -        LOG(@"attributedSubstringForProposedRange: (%ld, %ld) (%ld, %ld)",
       -                r.location, r.length, actualRange->location, actualRange->length);
       -        sr = NSMakeRange(0, [_tmpText length]);
       -        sr = NSIntersectionRange(sr, r);
       -        if(actualRange)
       -                *actualRange = sr;
       -        LOG(@"use range: %ld, %ld", sr.location, sr.length);
       -        s = nil;
       -        if(sr.length)
       -                s = [[NSAttributedString alloc]
       -                        initWithString:[_tmpText substringWithRange:sr]];
       -        LOG(@"        return %@", s);
       -        return s;
       -}
       -- (void)insertText:(id)s
       -        replacementRange:(NSRange)r
       -{
       -        NSUInteger i;
       -        NSUInteger len;
       -
       -        LOG(@"insertText: %@ replacementRange: %ld, %ld", s, r.location, r.length);
       -
       -        [self clearInput];
       -
       -        len = [s length];
       -        for(i = 0; i < len; ++i)
       -                keystroke([s characterAtIndex:i]);
       -        [_tmpText deleteCharactersInRange:NSMakeRange(0, _tmpText.length)];
       -        _markedRange = NSMakeRange(NSNotFound, 0);
       -        _selectedRange = NSMakeRange(0, 0);
       -}
       -- (NSUInteger)characterIndexForPoint:(NSPoint)point
       -{
       -        LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
       -        return 0;
       -}
       -- (NSRect)firstRectForCharacterRange:(NSRange)r
       -        actualRange:(NSRangePointer)actualRange
       -{
       -        LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
       -                r.location, r.length, actualRange->location, actualRange->length);
       -        if(actualRange)
       -                *actualRange = r;
       -        return [[self window] convertRectToScreen:_lastInputRect];
       -}
       -- (void)doCommandBySelector:(SEL)s
       -{
       -        NSEvent *e;
       -        NSEventModifierFlags m;
       -        uint c, k;
       -
       -        LOG(@"doCommandBySelector (%@)", NSStringFromSelector(s));
       -
       -        e = [NSApp currentEvent];
       -        c = [[e characters] characterAtIndex:0];
       -        k = keycvt(c);
       -        LOG(@"keyDown: character0: 0x%x -> 0x%x", c, k);
       -        m = [e modifierFlags];
       -
       -        if(m & NSEventModifierFlagCommand){
       -                if((m & NSEventModifierFlagShift) && 'a' <= k && k <= 'z')
       -                        k += 'A' - 'a';
       -                if(' '<=k && k<='~')
       -                        k += Kcmd;
       -        }
       -        if(k>0)
       -                keystroke(k);
       -}
       -
       -// Helper for managing input rect approximately
       -- (void)resetLastInputRect
       -{
       -        LOG(@"resetLastInputRect");
       -        _lastInputRect.origin.x = 0.0;
       -        _lastInputRect.origin.y = 0.0;
       -        _lastInputRect.size.width = 0.0;
       -        _lastInputRect.size.height = 0.0;
       -}
       -
       -- (void)enlargeLastInputRect:(NSRect)r
       -{
       -        r.origin.y = [self bounds].size.height - r.origin.y - r.size.height;
       -        _lastInputRect = NSUnionRect(_lastInputRect, r);
       -        LOG(@"update last input rect (%g, %g, %g, %g)",
       -                _lastInputRect.origin.x, _lastInputRect.origin.y,
       -                _lastInputRect.size.width, _lastInputRect.size.height);
       -}
       -
       -- (void)clearInput
       -{
       -        if(_tmpText.length){
       -                uint i;
       -                int l;
       -                l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
       -                        + (_selectedRange.length > 0);
       -                LOG(@"move right %d", l);
       -                for(i = 0; i < l; ++i)
       -                        keystroke(Kright);
       -                l = _tmpText.length+2+2*(_selectedRange.length > 0);
       -                LOG(@"backspace %d", l);
       -                for(uint i = 0; i < l; ++i)
       -                        keystroke(Kbs);
       -        }
       -}
       -
       -@end
       -
       -@implementation DrawLayer
       -
       -- (void)display
       -{
       -        id<MTLCommandBuffer> cbuf;
       -        id<MTLBlitCommandEncoder> blit;
       -
       -        LOG(@"display");
       -
       -        cbuf = [commandQueue commandBuffer];
       -
       -        LOG(@"display query drawable");
       -
       -@autoreleasepool{
       -        id<CAMetalDrawable> drawable;
       -
       -        drawable = [layer nextDrawable];
       -        if(!drawable){
       -                LOG(@"display couldn't get drawable");
       -                [self setNeedsDisplay];
       -                return;
       -        }
       -
       -        LOG(@"display got drawable");
       -
       -        blit = [cbuf blitCommandEncoder];
       -        [blit copyFromTexture:texture
       -                sourceSlice:0
       -                sourceLevel:0
       -                sourceOrigin:MTLOriginMake(0, 0, 0)
       -                sourceSize:MTLSizeMake(texture.width, texture.height, texture.depth)
       -                toTexture:drawable.texture
       -                destinationSlice:0
       -                destinationLevel:0
       -                destinationOrigin:MTLOriginMake(0, 0, 0)];
       -        [blit endEncoding];
       -
       -        [cbuf presentDrawable:drawable];
       -        drawable = nil;
       -}
       -        [cbuf addCompletedHandler:^(id<MTLCommandBuffer> cmdBuff){
       -                if(cmdBuff.error){
       -                        NSLog(@"command buffer finished with error: %@",
       -                                cmdBuff.error.localizedDescription);
       -                }else
       -                        LOG(@"command buffer finishes present drawable");
       -        }];
       -        [cbuf commit];
       -
       -        LOG(@"display commit");
       -}
       -
       -@end
       -
       -static uint
       -msec(void)
       -{
       -        return nsec()/1000000;
       -}
       -
       -static uint
       -keycvt(uint code)
       -{
       -        switch(code){
       -        case '\r': return '\n';
       -        case 127: return '\b';
       -        case NSUpArrowFunctionKey: return Kup;
       -        case NSDownArrowFunctionKey: return Kdown;
       -        case NSLeftArrowFunctionKey: return Kleft;
       -        case NSRightArrowFunctionKey: return Kright;
       -        case NSInsertFunctionKey: return Kins;
       -        case NSDeleteFunctionKey: return Kdel;
       -        case NSHomeFunctionKey: return Khome;
       -        case NSEndFunctionKey: return Kend;
       -        case NSPageUpFunctionKey: return Kpgup;
       -        case NSPageDownFunctionKey: return Kpgdown;
       -        case NSF1FunctionKey: return KF|1;
       -        case NSF2FunctionKey: return KF|2;
       -        case NSF3FunctionKey: return KF|3;
       -        case NSF4FunctionKey: return KF|4;
       -        case NSF5FunctionKey: return KF|5;
       -        case NSF6FunctionKey: return KF|6;
       -        case NSF7FunctionKey: return KF|7;
       -        case NSF8FunctionKey: return KF|8;
       -        case NSF9FunctionKey: return KF|9;
       -        case NSF10FunctionKey: return KF|10;
       -        case NSF11FunctionKey: return KF|11;
       -        case NSF12FunctionKey: return KF|12;
       -        case NSBeginFunctionKey:
       -        case NSPrintScreenFunctionKey:
       -        case NSScrollLockFunctionKey:
       -        case NSF13FunctionKey:
       -        case NSF14FunctionKey:
       -        case NSF15FunctionKey:
       -        case NSF16FunctionKey:
       -        case NSF17FunctionKey:
       -        case NSF18FunctionKey:
       -        case NSF19FunctionKey:
       -        case NSF20FunctionKey:
       -        case NSF21FunctionKey:
       -        case NSF22FunctionKey:
       -        case NSF23FunctionKey:
       -        case NSF24FunctionKey:
       -        case NSF25FunctionKey:
       -        case NSF26FunctionKey:
       -        case NSF27FunctionKey:
       -        case NSF28FunctionKey:
       -        case NSF29FunctionKey:
       -        case NSF30FunctionKey:
       -        case NSF31FunctionKey:
       -        case NSF32FunctionKey:
       -        case NSF33FunctionKey:
       -        case NSF34FunctionKey:
       -        case NSF35FunctionKey:
       -        case NSPauseFunctionKey:
       -        case NSSysReqFunctionKey:
       -        case NSBreakFunctionKey:
       -        case NSResetFunctionKey:
       -        case NSStopFunctionKey:
       -        case NSMenuFunctionKey:
       -        case NSUserFunctionKey:
       -        case NSSystemFunctionKey:
       -        case NSPrintFunctionKey:
       -        case NSClearLineFunctionKey:
       -        case NSClearDisplayFunctionKey:
       -        case NSInsertLineFunctionKey:
       -        case NSDeleteLineFunctionKey:
       -        case NSInsertCharFunctionKey:
       -        case NSDeleteCharFunctionKey:
       -        case NSPrevFunctionKey:
       -        case NSNextFunctionKey:
       -        case NSSelectFunctionKey:
       -        case NSExecuteFunctionKey:
       -        case NSUndoFunctionKey:
       -        case NSRedoFunctionKey:
       -        case NSFindFunctionKey:
       -        case NSHelpFunctionKey:
       -        case NSModeSwitchFunctionKey: return 0;
       -        default: return code;
       -        }
       -}
       -
       -Memimage*
       -attachscreen(char *label, char *winsize)
       -{
       -        LOG(@"attachscreen(%s, %s)", label, winsize);
       -        [AppDelegate
       -                performSelectorOnMainThread:@selector(makewin:)
       -                withObject:[NSValue valueWithPointer:winsize]
       -                waitUntilDone:YES];
       -        kicklabel(label);
       -        setcursor(nil, nil);
       -        mouseresized = 0;
       -        return initimg();
       -}
       -
       -static Memimage*
       -initimg(void)
       -{
       -@autoreleasepool{
       -        CGFloat scale;
       -        NSSize size;
       -        MTLTextureDescriptor *textureDesc;
       -
       -        size = [myContent convertSizeToBacking:[myContent bounds].size];
       -        mouserect = Rect(0, 0, size.width, size.height);
       -
       -        LOG(@"initimg %.0f %.0f", size.width, size.height);
       -
       -        img = allocmemimage(mouserect, XRGB32);
       -        if(img == nil)
       -                panic("allocmemimage: %r");
       -        if(img->data == nil)
       -                panic("img->data == nil");
       -
       -        textureDesc = [MTLTextureDescriptor
       -                texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
       -                width:size.width
       -                height:size.height
       -                mipmapped:NO];
       -        textureDesc.allowGPUOptimizedContents = YES;
       -        textureDesc.usage = MTLTextureUsageShaderRead;
       -        textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
       -        texture = [device newTextureWithDescriptor:textureDesc];
       -
       -        scale = [win backingScaleFactor];
       -        [layer setDrawableSize:size];
       -        [layer 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.
       -        // That's not quite right but it's close to correct.
       -        // https://en.wikipedia.org/wiki/Retina_display#Models
       -        displaydpi = scale * 110;
       -}
       -        LOG(@"initimg return");
       -
       -        return img;
       -}
       -
       -void
       -_flushmemscreen(Rectangle r)
       -{
       -        LOG(@"_flushmemscreen(%d,%d,%d,%d)", r.min.x, r.min.y, Dx(r), Dy(r));
       -        if(!rectinrect(r, Rect(0, 0, texture.width, texture.height))){
       -                LOG(@"Rectangle is out of bounds, return.");
       -                return;
       -        }
       -
       -        @autoreleasepool{
       -                [texture
       -                        replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r))
       -                        mipmapLevel:0
       -                        withBytes:byteaddr(img, Pt(r.min.x, r.min.y))
       -                        bytesPerRow:img->width*sizeof(u32int)];
       -                [AppDelegate
       -                        performSelectorOnMainThread:@selector(callsetNeedsDisplayInRect:)
       -                        withObject:[NSValue valueWithRect:NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r))]
       -                        waitUntilDone:NO];
       -        }
       -}
       -
       -void
       -setmouse(Point p)
       -{
       -        @autoreleasepool{
       -                NSPoint q;
       -
       -                LOG(@"setmouse(%d,%d)", p.x, p.y);
       -                q = [win convertPointFromBacking:NSMakePoint(p.x, p.y)];
       -                LOG(@"(%g, %g) <- fromBacking", q.x, q.y);
       -                q = [myContent convertPoint:q toView:nil];
       -                LOG(@"(%g, %g) <- toWindow", q.x, q.y);
       -                q = [win convertPointToScreen:q];
       -                LOG(@"(%g, %g) <- toScreen", q.x, q.y);
       -                // Quartz has the origin of the "global display
       -                // coordinate space" at the top left of the primary
       -                // screen with y increasing downward, while Cocoa has
       -                // the origin at the bottom left of the primary screen
       -                // with y increasing upward.  We flip the coordinate
       -                // with a negative sign and shift upward by the height
       -                // of the primary screen.
       -                q.y = NSScreen.screens[0].frame.size.height - q.y;
       -                LOG(@"(%g, %g) <- setmouse", q.x, q.y);
       -                CGWarpMouseCursorPosition(NSPointToCGPoint(q));
       -                CGAssociateMouseAndMouseCursorPosition(true);
       -        }
       -}
       -
       -char*
       -getsnarf(void)
       -{
       -        NSPasteboard *pb;
       -        NSString *s;
       -
       -        @autoreleasepool{
       -                pb = [NSPasteboard generalPasteboard];
       -
       -                qlock(&snarfl);
       -                s = [pb stringForType:NSPasteboardTypeString];
       -                qunlock(&snarfl);
       -
       -                if(s)
       -                        return strdup((char *)[s UTF8String]);
       -                else
       -                        return nil;
       -        }
       -}
       -
       -void
       -putsnarf(char *s)
       -{
       -        NSArray *t;
       -        NSPasteboard *pb;
       -        NSString *str;
       -
       -        if(strlen(s) >= SnarfSize)
       -                return;
       -
       -        @autoreleasepool{
       -                t = [NSArray arrayWithObject:NSPasteboardTypeString];
       -                pb = [NSPasteboard generalPasteboard];
       -                str = [[NSString alloc] initWithUTF8String:s];
       -
       -                qlock(&snarfl);
       -                [pb declareTypes:t owner:nil];
       -                [pb setString:str forType:NSPasteboardTypeString];
       -                qunlock(&snarfl);
       -        }
       -}
       -
       -void
       -kicklabel(char *label)
       -{
       -        NSString *s;
       -
       -        LOG(@"kicklabel(%s)", label);
       -        if(label == nil)
       -                return;
       -
       -        @autoreleasepool{
       -                s = [[NSString alloc] initWithUTF8String:label];
       -                [AppDelegate
       -                        performSelectorOnMainThread:@selector(callkicklabel:)
       -                        withObject:s
       -                        waitUntilDone:NO];
       -        }
       -}
       -
       -void
       -setcursor(Cursor *c, Cursor2 *c2)
       -{
       -        Cursors cs;
       -        
       -        cs.c = c;
       -        cs.c2 = c2;
       -
       -        [AppDelegate
       -                performSelectorOnMainThread:@selector(callsetcursor:)
       -                withObject:[NSValue valueWithPointer:&cs]
       -                waitUntilDone:YES];
       -}
       -
       -void
       -topwin(void)
       -{
       -        [win
       -                performSelectorOnMainThread:
       -                @selector(makeKeyAndOrderFront:)
       -                withObject:nil
       -                waitUntilDone:YES];
       -
       -        [NSApp activateIgnoringOtherApps:YES];
       -}
       -
       -void
       -resizeimg(void)
       -{
       -        zlock();
       -        _drawreplacescreenimage(initimg());
       -
       -        mouseresized = 1;
       -        zunlock();
       -        [myContent sendmouse:0];
       -}
       -
       -void
       -resizewindow(Rectangle r)
       -{
       -        LOG(@"resizewindow %d %d %d %d", r.min.x, r.min.y, Dx(r), Dy(r));
       -        dispatch_async(dispatch_get_main_queue(), ^(void){
       -                NSSize s;
       -
       -                s = [myContent convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))];
       -                [win setContentSize:s];
       -        });
       -}
       -
       -static void
       -setprocname(const char *s)
       -{
       -  CFStringRef process_name;
       -
       -  process_name = CFStringCreateWithBytes(nil, (uchar*)s, strlen(s), kCFStringEncodingUTF8, false);
       -
       -  // Adapted from Chrome's mac_util.mm.
       -  // http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm
       -  //
       -  // Copyright (c) 2012 The Chromium Authors. All rights reserved.
       -  //
       -  // Redistribution and use in source and binary forms, with or without
       -  // modification, are permitted provided that the following conditions are
       -  // met:
       -  //
       -  //    * Redistributions of source code must retain the above copyright
       -  // notice, this list of conditions and the following disclaimer.
       -  //    * Redistributions in binary form must reproduce the above
       -  // copyright notice, this list of conditions and the following disclaimer
       -  // in the documentation and/or other materials provided with the
       -  // distribution.
       -  //    * Neither the name of Google Inc. nor the names of its
       -  // contributors may be used to endorse or promote products derived from
       -  // this software without specific prior written permission.
       -  //
       -  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       -  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       -  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       -  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       -  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       -  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       -  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       -  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       -  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       -  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       -  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       -  // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
       -  // plugin host, and could break at any time (although realistically it's only
       -  // likely to break in a new major release).
       -  // When 10.7 is available, check that this still works, and update this
       -  // comment for 10.8.
       -
       -  // Private CFType used in these LaunchServices calls.
       -  typedef CFTypeRef PrivateLSASN;
       -  typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
       -  typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
       -                                                          CFStringRef,
       -                                                          CFStringRef,
       -                                                          CFDictionaryRef*);
       -
       -  static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
       -      NULL;
       -  static LSSetApplicationInformationItemType
       -      ls_set_application_information_item_func = NULL;
       -  static CFStringRef ls_display_name_key = NULL;
       -
       -  static bool did_symbol_lookup = false;
       -  if (!did_symbol_lookup) {
       -    did_symbol_lookup = true;
       -    CFBundleRef launch_services_bundle =
       -        CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
       -    if (!launch_services_bundle) {
       -      fprint(2, "Failed to look up LaunchServices bundle\n");
       -      return;
       -    }
       -
       -    ls_get_current_application_asn_func =
       -        (LSGetCurrentApplicationASNType)(
       -            CFBundleGetFunctionPointerForName(
       -                launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
       -    if (!ls_get_current_application_asn_func)
       -      fprint(2, "Could not find _LSGetCurrentApplicationASN\n");
       -
       -    ls_set_application_information_item_func =
       -        (LSSetApplicationInformationItemType)(
       -            CFBundleGetFunctionPointerForName(
       -                launch_services_bundle,
       -                CFSTR("_LSSetApplicationInformationItem")));
       -    if (!ls_set_application_information_item_func)
       -      fprint(2, "Could not find _LSSetApplicationInformationItem\n");
       -
       -    CFStringRef* key_pointer = (CFStringRef*)(
       -        CFBundleGetDataPointerForName(launch_services_bundle,
       -                                      CFSTR("_kLSDisplayNameKey")));
       -    ls_display_name_key = key_pointer ? *key_pointer : NULL;
       -    if (!ls_display_name_key)
       -      fprint(2, "Could not find _kLSDisplayNameKey\n");
       -
       -    // Internally, this call relies on the Mach ports that are started up by the
       -    // Carbon Process Manager.  In debug builds this usually happens due to how
       -    // the logging layers are started up; but in release, it isn't started in as
       -    // much of a defined order.  So if the symbols had to be loaded, go ahead
       -    // and force a call to make sure the manager has been initialized and hence
       -    // the ports are opened.
       -    ProcessSerialNumber psn;
       -    GetCurrentProcess(&psn);
       -  }
       -  if (!ls_get_current_application_asn_func ||
       -      !ls_set_application_information_item_func ||
       -      !ls_display_name_key) {
       -    return;
       -  }
       -
       -  PrivateLSASN asn = ls_get_current_application_asn_func();
       -  // Constant used by WebKit; what exactly it means is unknown.
       -  const int magic_session_constant = -2;
       -  OSErr err =
       -      ls_set_application_information_item_func(magic_session_constant, asn,
       -                                               ls_display_name_key,
       -                                               process_name,
       -                                               NULL /* optional out param */);
       -  if(err != noErr)
       -    fprint(2, "Call to set process name failed\n");
       -}
 (DIR) diff --git a/src/cmd/devdraw/cocoa-srv.c b/src/cmd/devdraw/cocoa-srv.c
       t@@ -1,427 +0,0 @@
       -/*
       - * Window system protocol server.
       - */
       -
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -#include <draw.h>
       -#include <memdraw.h>
       -#include <keyboard.h>
       -#include <mouse.h>
       -#include <cursor.h>
       -#include <drawfcall.h>
       -#include "cocoa-screen.h"
       -#include "devdraw.h"
       -
       -typedef struct Kbdbuf Kbdbuf;
       -typedef struct Mousebuf Mousebuf;
       -typedef struct Fdbuf Fdbuf;
       -typedef struct Tagbuf Tagbuf;
       -
       -struct Kbdbuf
       -{
       -        Rune r[256];
       -        int ri;
       -        int wi;
       -        int stall;
       -};
       -
       -struct Mousebuf
       -{
       -        Mouse m[256];
       -        Mouse last;
       -        int ri;
       -        int wi;
       -        int stall;
       -};
       -
       -struct Tagbuf
       -{
       -        int t[256];
       -        int ri;
       -        int wi;
       -};
       -
       -Kbdbuf kbd;
       -Mousebuf mouse;
       -Tagbuf kbdtags;
       -Tagbuf mousetags;
       -
       -void runmsg(Wsysmsg*);
       -void replymsg(Wsysmsg*);
       -void matchkbd(void);
       -void matchmouse(void);
       -
       -
       -QLock lk;
       -void
       -zlock(void)
       -{
       -        qlock(&lk);
       -}
       -
       -void
       -zunlock(void)
       -{
       -        qunlock(&lk);
       -}
       -
       -int trace = 0;
       -
       -void
       -servep9p(void)
       -{
       -        uchar buf[4], *mbuf;
       -        int nmbuf, n, nn;
       -        Wsysmsg m;
       -
       -        fmtinstall('W', drawfcallfmt);
       -
       -        mbuf = nil;
       -        nmbuf = 0;
       -        while((n = read(3, buf, 4)) == 4){
       -                GET(buf, n);
       -                if(n > nmbuf){
       -                        free(mbuf);
       -                        mbuf = malloc(4+n);
       -                        if(mbuf == nil)
       -                                sysfatal("malloc: %r");
       -                        nmbuf = n;
       -                }
       -                memmove(mbuf, buf, 4);
       -                nn = readn(3, mbuf+4, n-4);
       -                if(nn != n-4)
       -                        sysfatal("eof during message");
       -
       -                /* pick off messages one by one */
       -                if(convM2W(mbuf, nn+4, &m) <= 0)
       -                        sysfatal("cannot convert message");
       -                if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
       -                runmsg(&m);
       -        }
       -}
       -
       -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)
       -{
       -        static uchar buf[65536];
       -        int n;
       -        Memimage *i;
       -
       -        switch(m->type){
       -        case Tinit:
       -                memimageinit();
       -                i = attachscreen(m->label, m->winsize);
       -                _initdisplaymemimage(i);
       -                replymsg(m);
       -                break;
       -
       -        case Trdmouse:
       -                zlock();
       -                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");
       -                mouse.stall = 0;
       -                matchmouse();
       -                zunlock();
       -                break;
       -
       -        case Trdkbd:
       -                zlock();
       -                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();
       -                zunlock();
       -                break;
       -
       -        case Tmoveto:
       -                setmouse(m->mouse.xy);
       -                replymsg(m);
       -                break;
       -
       -        case Tcursor:
       -                if(m->arrowcursor)
       -                        setcursor(nil, nil);
       -                else
       -                        setcursor(&m->cursor, nil);
       -                replymsg(m);
       -                break;
       -
       -        case Tcursor2:
       -                if(m->arrowcursor)
       -                        setcursor(nil, nil);
       -                else
       -                        setcursor(&m->cursor, &m->cursor2);
       -                replymsg(m);
       -                break;
       -
       -        case Tbouncemouse:
       -        //        _xbouncemouse(&m->mouse);
       -                replymsg(m);
       -                break;
       -
       -        case Tlabel:
       -                kicklabel(m->label);
       -                replymsg(m);
       -                break;
       -
       -        case Trdsnarf:
       -                m->snarf = getsnarf();
       -                replymsg(m);
       -                free(m->snarf);
       -                break;
       -
       -        case Twrsnarf:
       -                putsnarf(m->snarf);
       -                replymsg(m);
       -                break;
       -
       -        case Trddraw:
       -                zlock();
       -                n = m->count;
       -                if(n > sizeof buf)
       -                        n = sizeof buf;
       -                n = _drawmsgread(buf, n);
       -                if(n < 0)
       -                        replyerror(m);
       -                else{
       -                        m->count = n;
       -                        m->data = buf;
       -                        replymsg(m);
       -                }
       -                zunlock();
       -                break;
       -
       -        case Twrdraw:
       -                zlock();
       -                if(_drawmsgwrite(m->data, m->count) < 0)
       -                        replyerror(m);
       -                else
       -                        replymsg(m);
       -                zunlock();
       -                break;
       -
       -        case Ttop:
       -                topwin();
       -                replymsg(m);
       -                break;
       -
       -        case Tresize:
       -                resizewindow(m->rect);
       -                replymsg(m);
       -                break;
       -        }
       -}
       -
       -/*
       - * Reply to m.
       - */
       -QLock replylock;
       -void
       -replymsg(Wsysmsg *m)
       -{
       -        int n;
       -        static uchar *mbuf;
       -        static int nmbuf;
       -
       -        /* T -> R msg */
       -        if(m->type%2 == 0)
       -                m->type++;
       -
       -        if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
       -        /* copy to output buffer */
       -        n = sizeW2M(m);
       -
       -        qlock(&replylock);
       -        if(n > nmbuf){
       -                free(mbuf);
       -                mbuf = malloc(n);
       -                if(mbuf == nil)
       -                        sysfatal("out of memory");
       -                nmbuf = n;
       -        }
       -        convW2M(m, mbuf, n);
       -        if(write(4, mbuf, n) != n)
       -                sysfatal("write: %r");
       -        qunlock(&replylock);
       -}
       -
       -/*
       - * 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 = mouseresized;
       -                mouseresized = 0;
       -                /*
       -                if(m.resized)
       -                        fprint(2, "sending resize\n");
       -                */
       -                mouse.ri++;
       -                if(mouse.ri == nelem(mouse.m))
       -                        mouse.ri = 0;
       -                replymsg(&m);
       -        }
       -}
       -
       -void
       -mousetrack(int x, int y, int b, uint ms)
       -{
       -        Mouse *m;
       -
       -        if(x < mouserect.min.x)
       -                x = mouserect.min.x;
       -        if(x > mouserect.max.x)
       -                x = mouserect.max.x;
       -        if(y < mouserect.min.y)
       -                y = mouserect.min.y;
       -        if(y > mouserect.max.y)
       -                y = mouserect.max.y;
       -
       -        zlock();
       -        // If reader has stopped reading, don't bother.
       -        // If reader is completely caught up, definitely queue.
       -        // Otherwise, queue only button change events.
       -        if(!mouse.stall)
       -        if(mouse.wi == mouse.ri || mouse.last.buttons != b){
       -                m = &mouse.last;
       -                m->xy.x = x;
       -                m->xy.y = y;
       -                m->buttons = b;
       -                m->msec = ms;
       -
       -                mouse.m[mouse.wi] = *m;
       -                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;
       -                }
       -                matchmouse();
       -        }
       -        zunlock();
       -}
       -
       -void
       -kputc(int c)
       -{
       -        zlock();
       -        kbd.r[kbd.wi++] = c;
       -        if(kbd.wi == nelem(kbd.r))
       -                kbd.wi = 0;
       -        if(kbd.ri == kbd.wi)
       -                kbd.stall = 1;
       -        matchkbd();
       -        zunlock();
       -}
       -
       -static int alting;
       -
       -void
       -abortcompose(void)
       -{
       -        if(alting)
       -                keystroke(Kalt);
       -}
       -
       -void
       -keystroke(int c)
       -{
       -        static Rune k[10];
       -        static int nk;
       -        int i;
       -
       -        if(c == Kalt){
       -                alting = !alting;
       -                nk = 0;
       -                return;
       -        }
       -        if(c == Kcmd+'r') {
       -                if(forcedpi)
       -                        forcedpi = 0;
       -                else if(displaydpi >= 200)
       -                        forcedpi = 100;
       -                else
       -                        forcedpi = 225;
       -                resizeimg();
       -                return;
       -        }
       -        if(!alting){
       -                kputc(c);
       -                return;
       -        }
       -        if(nk >= nelem(k))      // should not happen
       -                nk = 0;
       -        k[nk++] = c;
       -        c = _latin1(k, nk);
       -        if(c > 0){
       -                alting = 0;
       -                kputc(c);
       -                nk = 0;
       -                return;
       -        }
       -        if(c == -1){
       -                alting = 0;
       -                for(i=0; i<nk; i++)
       -                        kputc(k[i]);
       -                nk = 0;
       -                return;
       -        }
       -        // need more input
       -        return;
       -}
 (DIR) diff --git a/src/cmd/devdraw/osx-draw.c b/src/cmd/devdraw/mac-draw.c
 (DIR) diff --git a/src/cmd/devdraw/cocoa-screen.h b/src/cmd/devdraw/mac-screen.h
 (DIR) diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m
       t@@ -0,0 +1,1248 @@
       +#define Cursor OSXCursor
       +#define Point OSXPoint
       +#define Rect OSXRect
       +
       +#import <Cocoa/Cocoa.h>
       +#import <Metal/Metal.h>
       +#import <QuartzCore/CAMetalLayer.h>
       +
       +#undef Cursor
       +#undef Point
       +#undef Rect
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <draw.h>
       +#include <memdraw.h>
       +#include <keyboard.h>
       +#include <cursor.h>
       +#include "mac-screen.h"
       +#include "devdraw.h"
       +#include "bigarrow.h"
       +#include "glendapng.h"
       +
       +AUTOFRAMEWORK(Cocoa)
       +AUTOFRAMEWORK(Metal)
       +AUTOFRAMEWORK(QuartzCore)
       +
       +#define LOG        if(0)NSLog
       +
       +static void setprocname(const char*);
       +static uint keycvt(uint);
       +static uint msec(void);
       +static Memimage* initimg(void);
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: devdraw (don't run directly)\n");
       +        threadexitsall("usage");
       +}
       +
       +
       +@interface AppDelegate : NSObject<NSApplicationDelegate,NSWindowDelegate>
       ++ (void)makewin:(NSValue *)v;
       ++ (void)callkicklabel:(NSString *)v;
       ++ (void)callsetNeedsDisplayInRect:(NSValue *)v;
       ++ (void)callsetcursor:(NSValue *)v;
       +@end
       +@interface DevDrawView : NSView<NSTextInputClient>
       +- (void)clearInput;
       +- (void)getmouse:(NSEvent *)e;
       +- (void)sendmouse:(NSUInteger)b;
       +- (void)resetLastInputRect;
       +- (void)enlargeLastInputRect:(NSRect)r;
       +@end
       +@interface DrawLayer : CAMetalLayer
       +@end
       +
       +static AppDelegate *myApp = NULL;
       +static DevDrawView *myContent = NULL;
       +static NSWindow *win = NULL;
       +static NSCursor *currentCursor = NULL;
       +
       +static DrawLayer *layer;
       +static id<MTLDevice> device;
       +static id<MTLCommandQueue> commandQueue;
       +static id<MTLTexture> texture;
       +
       +static Memimage *img = NULL;
       +
       +static QLock snarfl;
       +
       +void
       +threadmain(int argc, char **argv)
       +{
       +        /*
       +         * Move the protocol off stdin/stdout so that
       +         * any inadvertent prints don't screw things up.
       +         */
       +        dup(0,3);
       +        dup(1,4);
       +        close(0);
       +        close(1);
       +        open("/dev/null", OREAD);
       +        open("/dev/null", OWRITE);
       +
       +        ARGBEGIN{
       +        case 'D':                /* for good ps -a listings */
       +                break;
       +        case 'f':                /* fall through for backward compatibility */
       +        case 'g':
       +        case 'b':
       +                break;
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        setprocname(argv0);
       +
       +        @autoreleasepool{
       +                [NSApplication sharedApplication];
       +                [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
       +                myApp = [AppDelegate new];
       +                [NSApp setDelegate:myApp];
       +                [NSApp run];
       +        }
       +}
       +
       +
       +void
       +callservep9p(void *v)
       +{
       +        USED(v);
       +
       +        servep9p();
       +        [NSApp terminate:myApp];
       +}
       +
       +@implementation AppDelegate
       +
       ++ (void)makewin:(NSValue *)v
       +{
       +        NSRect r, sr;
       +        Rectangle wr;
       +        int set;
       +        char *s;
       +        NSArray *allDevices;
       +
       +        const NSWindowStyleMask Winstyle = NSWindowStyleMaskTitled
       +                | NSWindowStyleMaskClosable
       +                | NSWindowStyleMaskMiniaturizable
       +                | NSWindowStyleMaskResizable;
       +
       +        sr = [[NSScreen mainScreen] frame];
       +        r = [[NSScreen mainScreen] visibleFrame];
       +
       +        s = [v pointerValue];
       +        LOG(@"makewin(%s)", s);
       +        if(s && *s){
       +                if(parsewinsize(s, &wr, &set) < 0)
       +                        sysfatal("%r");
       +        }else{
       +                wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
       +                set = 0;
       +        }
       +
       +        r.origin.x = wr.min.x;
       +        r.origin.y = sr.size.height-wr.max.y;        /* winsize is top-left-based */
       +        r.size.width = fmin(Dx(wr), r.size.width);
       +        r.size.height = fmin(Dy(wr), r.size.height);
       +        r = [NSWindow contentRectForFrameRect:r styleMask:Winstyle];
       +
       +        win = [[NSWindow alloc]
       +                initWithContentRect:r
       +                styleMask:Winstyle
       +                backing:NSBackingStoreBuffered defer:NO];
       +        [win setTitle:@"devdraw"];
       +
       +        if(!set)
       +                [win center];
       +        [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
       +        [win setContentMinSize:NSMakeSize(64,64)];
       +        [win setOpaque:YES];
       +        [win setRestorable:NO];
       +        [win setAcceptsMouseMovedEvents:YES];
       +        [win setDelegate:myApp];
       +
       +        myContent = [DevDrawView new];
       +        [win setContentView:myContent];
       +        [myContent setWantsLayer:YES];
       +        [myContent setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
       +        
       +        device = nil;
       +        allDevices = MTLCopyAllDevices();
       +        for(id mtlDevice in allDevices) {
       +                if ([mtlDevice isLowPower] && ![mtlDevice isRemovable]) {
       +                        device = mtlDevice;
       +                        break;
       +                }
       +        }
       +        if(!device)
       +                device = MTLCreateSystemDefaultDevice();
       +
       +        commandQueue = [device newCommandQueue];
       +
       +        layer = (DrawLayer *)[myContent layer];
       +        layer.device = device;
       +        layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
       +        layer.framebufferOnly = YES;
       +        layer.opaque = YES;
       +
       +        // We use a default transparent layer on top of the CAMetalLayer.
       +        // This seems to make fullscreen applications behave.
       +        {
       +                CALayer *stub = [CALayer layer];
       +                stub.frame = CGRectMake(0, 0, 1, 1);
       +                [stub setNeedsDisplay];
       +                [layer addSublayer:stub];
       +        }
       +
       +        [NSEvent setMouseCoalescingEnabled:NO];
       +
       +        topwin();
       +}
       +
       ++ (void)callkicklabel:(NSString *)s
       +{
       +        LOG(@"callkicklabel(%@)", s);
       +        [win setTitle:s];
       +        [[NSApp dockTile] setBadgeLabel:s];
       +}
       +
       +
       ++ (void)callsetNeedsDisplayInRect:(NSValue *)v
       +{
       +        NSRect r;
       +        dispatch_time_t time;
       +
       +        r = [v rectValue];
       +        LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
       +        r = [win convertRectFromBacking:r];
       +        LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
       +        [layer setNeedsDisplayInRect:r];
       +
       +        time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC);
       +        dispatch_after(time, dispatch_get_main_queue(), ^(void){
       +                [layer setNeedsDisplayInRect:r];
       +        });
       +
       +        [myContent enlargeLastInputRect:r];
       +}
       +
       +typedef struct Cursors Cursors;
       +struct Cursors {
       +        Cursor *c;
       +        Cursor2 *c2;
       +};
       +
       ++ (void)callsetcursor:(NSValue *)v
       +{
       +        Cursors *cs;
       +        Cursor *c;
       +        Cursor2 *c2;
       +        NSBitmapImageRep *r, *r2;
       +        NSImage *i;
       +        NSPoint p;
       +        uchar *plane[5], *plane2[5];
       +        uint b;
       +
       +        cs = [v pointerValue];
       +        c = cs->c;
       +        if(!c)
       +                c = &bigarrow;
       +        c2 = cs->c2;
       +        if(!c2)
       +                c2 = &bigarrow2;
       +
       +        r = [[NSBitmapImageRep alloc]
       +                initWithBitmapDataPlanes:nil
       +                pixelsWide:16
       +                pixelsHigh:16
       +                bitsPerSample:1
       +                samplesPerPixel:2
       +                hasAlpha:YES
       +                isPlanar:YES
       +                colorSpaceName:NSDeviceWhiteColorSpace
       +                bytesPerRow:2
       +                bitsPerPixel:0];
       +        [r getBitmapDataPlanes:plane];
       +        for(b=0; b<nelem(c->set); b++){
       +                plane[0][b] = ~c->set[b] & c->clr[b];
       +                plane[1][b] = c->set[b] | c->clr[b];
       +        }
       +
       +        r2 = [[NSBitmapImageRep alloc]
       +                initWithBitmapDataPlanes:nil
       +                pixelsWide:32
       +                pixelsHigh:32
       +                bitsPerSample:1
       +                samplesPerPixel:2
       +                hasAlpha:YES
       +                isPlanar:YES
       +                colorSpaceName:NSDeviceWhiteColorSpace
       +                bytesPerRow:4
       +                bitsPerPixel:0];
       +        [r2 getBitmapDataPlanes:plane2];
       +        for(b=0; b<nelem(c2->set); b++){
       +                plane2[0][b] = ~c2->set[b] & c2->clr[b];
       +                plane2[1][b] = c2->set[b] | c2->clr[b];
       +        }
       +
       +        // For checking out the cursor bitmap image
       +/*
       +        static BOOL saveimg = YES;
       +        if(saveimg){
       +                NSData *data = [r representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
       +                [data writeToFile: @"/tmp/r.bmp" atomically: NO];
       +                data = [r2 representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
       +                [data writeToFile: @"/tmp/r2.bmp" atomically: NO];
       +                saveimg = NO;
       +        }
       +*/
       +
       +        i = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)];
       +        [i addRepresentation:r2];
       +        [i addRepresentation:r];
       +
       +        p = NSMakePoint(-c->offset.x, -c->offset.y);
       +        currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
       +
       +        [win invalidateCursorRectsForView:myContent];
       +}
       +
       +- (void)applicationDidFinishLaunching:(id)arg
       +{
       +        NSMenu *m, *sm;
       +        NSData *d;
       +        NSImage *i;
       +
       +        LOG(@"applicationDidFinishLaunching");
       +
       +        sm = [NSMenu new];
       +        [sm addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
       +        [sm addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"];
       +        [sm addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
       +        m = [NSMenu new];
       +        [m addItemWithTitle:@"DEVDRAW" action:NULL keyEquivalent:@""];
       +        [m setSubmenu:sm forItem:[m itemWithTitle:@"DEVDRAW"]];
       +        [NSApp setMainMenu:m];
       +
       +        d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
       +        i = [[NSImage alloc] initWithData:d];
       +        [NSApp setApplicationIconImage:i];
       +        [[NSApp dockTile] display];
       +
       +        proccreate(callservep9p, nil, 0);
       +}
       +
       +- (NSApplicationPresentationOptions)window:(id)arg
       +                willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions {
       +        NSApplicationPresentationOptions o;
       +        o = proposedOptions;
       +        o &= ~(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar);
       +        o |= NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
       +        return o;
       +}
       +
       +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
       +        return YES;
       +}
       +
       +- (void)windowDidResize:(NSNotification *)notification
       +{
       +        if(![myContent inLiveResize] && img) {
       +                resizeimg();
       +        }
       +}
       +
       +- (void)windowDidBecomeKey:(id)arg
       +{
       +        [myContent sendmouse:0];
       +}
       +
       +@end
       +
       +@implementation DevDrawView
       +{
       +        NSMutableString *_tmpText;
       +        NSRange _markedRange;
       +        NSRange _selectedRange;
       +        NSRect _lastInputRect;        // The view is flipped, this is not.
       +        BOOL _tapping;
       +        NSUInteger _tapFingers;
       +        NSUInteger _tapTime;
       +}
       +
       +- (id)init
       +{
       +        LOG(@"View init");
       +        self = [super init];
       +        [self setAllowedTouchTypes:NSTouchTypeMaskDirect|NSTouchTypeMaskIndirect];
       +        _tmpText = [[NSMutableString alloc] initWithCapacity:2];
       +        _markedRange = NSMakeRange(NSNotFound, 0);
       +        _selectedRange = NSMakeRange(0, 0);
       +        return self;
       +}
       +
       +- (CALayer *)makeBackingLayer
       +{
       +        LOG(@"makeBackingLayer");
       +        return [DrawLayer layer];
       +}
       +
       +- (BOOL)wantsUpdateLayer
       +{
       +        return YES;
       +}
       +
       +- (BOOL)isOpaque
       +{
       +        return YES;
       +}
       +
       +- (BOOL)isFlipped
       +{
       +        return YES;
       +}
       +
       +- (BOOL)acceptsFirstResponder
       +{
       +        return YES;
       +}
       +
       +- (void)mouseMoved:(NSEvent*)e{ [self getmouse:e];}
       +- (void)mouseDown:(NSEvent*)e{ [self getmouse:e];}
       +- (void)mouseDragged:(NSEvent*)e{ [self getmouse:e];}
       +- (void)mouseUp:(NSEvent*)e{ [self getmouse:e];}
       +- (void)otherMouseDown:(NSEvent*)e{ [self getmouse:e];}
       +- (void)otherMouseDragged:(NSEvent*)e{ [self getmouse:e];}
       +- (void)otherMouseUp:(NSEvent*)e{ [self getmouse:e];}
       +- (void)rightMouseDown:(NSEvent*)e{ [self getmouse:e];}
       +- (void)rightMouseDragged:(NSEvent*)e{ [self getmouse:e];}
       +- (void)rightMouseUp:(NSEvent*)e{ [self getmouse:e];}
       +
       +- (void)scrollWheel:(NSEvent*)e
       +{
       +        NSInteger s;
       +
       +        s = [e scrollingDeltaY];
       +        if(s > 0)
       +                [self sendmouse:8];
       +        else if (s < 0)
       +                [self sendmouse:16];
       +}
       +
       +- (void)keyDown:(NSEvent*)e
       +{
       +        LOG(@"keyDown to interpret");
       +
       +        [self interpretKeyEvents:[NSArray arrayWithObject:e]];
       +
       +        [self resetLastInputRect];
       +}
       +
       +- (void)flagsChanged:(NSEvent*)e
       +{
       +        static NSEventModifierFlags omod;
       +        NSEventModifierFlags m;
       +        uint b;
       +
       +        LOG(@"flagsChanged");
       +        m = [e modifierFlags];
       +
       +        b = [NSEvent pressedMouseButtons];
       +        b = (b&~6) | (b&4)>>1 | (b&2)<<1;
       +        if(b){
       +                if(m & ~omod & NSEventModifierFlagControl)
       +                        b |= 1;
       +                if(m & ~omod & NSEventModifierFlagOption)
       +                        b |= 2;
       +                if(m & ~omod & NSEventModifierFlagCommand)
       +                        b |= 4;
       +                [self sendmouse:b];
       +        }else if(m & ~omod & NSEventModifierFlagOption)
       +                keystroke(Kalt);
       +
       +        omod = m;
       +}
       +
       +- (void)magnifyWithEvent:(NSEvent*)e
       +{
       +        if(fabs([e magnification]) > 0.02)
       +                [[self window] toggleFullScreen:nil];
       +}
       +
       +- (void)touchesBeganWithEvent:(NSEvent*)e
       +{
       +        _tapping = YES;
       +        _tapFingers = [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count;
       +        _tapTime = msec();
       +}
       +- (void)touchesMovedWithEvent:(NSEvent*)e
       +{
       +        _tapping = NO;
       +}
       +- (void)touchesEndedWithEvent:(NSEvent*)e
       +{
       +        if(_tapping
       +                && [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count == 0
       +                && msec() - _tapTime < 250){
       +                switch(_tapFingers){
       +                case 3:
       +                        [self sendmouse:2];
       +                        [self sendmouse:0];
       +                        break;
       +                case 4:
       +                        [self sendmouse:2];
       +                        [self sendmouse:1];
       +                        [self sendmouse:0];
       +                        break;
       +                }
       +                _tapping = NO;
       +        }
       +}
       +- (void)touchesCancelledWithEvent:(NSEvent*)e
       +{
       +        _tapping = NO;
       +}
       +
       +- (void)getmouse:(NSEvent *)e
       +{
       +        NSUInteger b;
       +        NSEventModifierFlags m;
       +
       +        b = [NSEvent pressedMouseButtons];
       +        b = b&~6 | (b&4)>>1 | (b&2)<<1;
       +        b = mouseswap(b);
       +
       +        if(b == 1){
       +                m = [e modifierFlags];
       +                if(m & NSEventModifierFlagOption){
       +                        abortcompose();
       +                        b = 2;
       +                }else
       +                if(m & NSEventModifierFlagCommand)
       +                        b = 4;
       +        }
       +        [self sendmouse:b];
       +}
       +
       +- (void)sendmouse:(NSUInteger)b
       +{
       +        NSPoint p;
       +
       +        p = [self.window convertPointToBacking:
       +                [self.window mouseLocationOutsideOfEventStream]];
       +        p.y = Dy(mouserect) - p.y;
       +        // LOG(@"(%g, %g) <- sendmouse(%d)", p.x, p.y, (uint)b);
       +        mousetrack(p.x, p.y, b, msec());
       +        if(b && _lastInputRect.size.width && _lastInputRect.size.height)
       +                [self resetLastInputRect];
       +}
       +
       +- (void)resetCursorRects {
       +        [super resetCursorRects];
       +        [self addCursorRect:self.bounds cursor:currentCursor];
       +}
       +
       +- (void)viewDidEndLiveResize
       +{
       +        [super viewDidEndLiveResize];
       +        if(img)
       +                resizeimg();
       +}
       +
       +- (void)viewDidChangeBackingProperties
       +{
       +        [super viewDidChangeBackingProperties];
       +        if(img)
       +                resizeimg();
       +}
       +
       +// conforms to protocol NSTextInputClient
       +- (BOOL)hasMarkedText
       +{
       +        LOG(@"hasMarkedText");
       +        return _markedRange.location != NSNotFound;
       +}
       +- (NSRange)markedRange
       +{
       +        LOG(@"markedRange");
       +        return _markedRange;
       +}
       +- (NSRange)selectedRange
       +{
       +        LOG(@"selectedRange");
       +        return _selectedRange;
       +}
       +- (void)setMarkedText:(id)string
       +        selectedRange:(NSRange)sRange
       +        replacementRange:(NSRange)rRange
       +{
       +        NSString *str;
       +
       +        LOG(@"setMarkedText: %@ (%ld, %ld) (%ld, %ld)", string,
       +                sRange.location, sRange.length,
       +                rRange.location, rRange.length);
       +
       +        [self clearInput];
       +
       +        if([string isKindOfClass:[NSAttributedString class]])
       +                str = [string string];
       +        else
       +                str = string;
       +
       +        if(rRange.location == NSNotFound){
       +                if(_markedRange.location != NSNotFound){
       +                        rRange = _markedRange;
       +                }else{
       +                        rRange = _selectedRange;
       +                }
       +        }
       +
       +        if(str.length == 0){
       +                [_tmpText deleteCharactersInRange:rRange];
       +                [self unmarkText];
       +        }else{
       +                _markedRange = NSMakeRange(rRange.location, str.length);
       +                [_tmpText replaceCharactersInRange:rRange withString:str];
       +        }
       +        _selectedRange.location = rRange.location + sRange.location;
       +        _selectedRange.length = sRange.length;
       +
       +        if(_tmpText.length){
       +                uint i;
       +                LOG(@"text length %ld", _tmpText.length);
       +                for(i = 0; i <= _tmpText.length; ++i){
       +                        if(i == _markedRange.location)
       +                                keystroke('[');
       +                        if(_selectedRange.length){
       +                                if(i == _selectedRange.location)
       +                                        keystroke('{');
       +                                if(i == NSMaxRange(_selectedRange))
       +                                        keystroke('}');
       +                                }
       +                        if(i == NSMaxRange(_markedRange))
       +                                keystroke(']');
       +                        if(i < _tmpText.length)
       +                                keystroke([_tmpText characterAtIndex:i]);
       +                }
       +                int l;
       +                l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
       +                        + (_selectedRange.length > 0);
       +                LOG(@"move left %d", l);
       +                for(i = 0; i < l; ++i)
       +                        keystroke(Kleft);
       +        }
       +
       +        LOG(@"text: \"%@\"  (%ld,%ld)  (%ld,%ld)", _tmpText,
       +                _markedRange.location, _markedRange.length,
       +                _selectedRange.location, _selectedRange.length);
       +}
       +- (void)unmarkText
       +{
       +        //NSUInteger i;
       +        NSUInteger len;
       +
       +        LOG(@"unmarkText");
       +        len = [_tmpText length];
       +        //for(i = 0; i < len; ++i)
       +        //        keystroke([_tmpText characterAtIndex:i]);
       +        [_tmpText deleteCharactersInRange:NSMakeRange(0, len)];
       +        _markedRange = NSMakeRange(NSNotFound, 0);
       +        _selectedRange = NSMakeRange(0, 0);
       +}
       +- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText
       +{
       +        LOG(@"validAttributesForMarkedText");
       +        return @[];
       +}
       +- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r
       +        actualRange:(NSRangePointer)actualRange
       +{
       +        NSRange sr;
       +        NSAttributedString *s;
       +
       +        LOG(@"attributedSubstringForProposedRange: (%ld, %ld) (%ld, %ld)",
       +                r.location, r.length, actualRange->location, actualRange->length);
       +        sr = NSMakeRange(0, [_tmpText length]);
       +        sr = NSIntersectionRange(sr, r);
       +        if(actualRange)
       +                *actualRange = sr;
       +        LOG(@"use range: %ld, %ld", sr.location, sr.length);
       +        s = nil;
       +        if(sr.length)
       +                s = [[NSAttributedString alloc]
       +                        initWithString:[_tmpText substringWithRange:sr]];
       +        LOG(@"        return %@", s);
       +        return s;
       +}
       +- (void)insertText:(id)s
       +        replacementRange:(NSRange)r
       +{
       +        NSUInteger i;
       +        NSUInteger len;
       +
       +        LOG(@"insertText: %@ replacementRange: %ld, %ld", s, r.location, r.length);
       +
       +        [self clearInput];
       +
       +        len = [s length];
       +        for(i = 0; i < len; ++i)
       +                keystroke([s characterAtIndex:i]);
       +        [_tmpText deleteCharactersInRange:NSMakeRange(0, _tmpText.length)];
       +        _markedRange = NSMakeRange(NSNotFound, 0);
       +        _selectedRange = NSMakeRange(0, 0);
       +}
       +- (NSUInteger)characterIndexForPoint:(NSPoint)point
       +{
       +        LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
       +        return 0;
       +}
       +- (NSRect)firstRectForCharacterRange:(NSRange)r
       +        actualRange:(NSRangePointer)actualRange
       +{
       +        LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
       +                r.location, r.length, actualRange->location, actualRange->length);
       +        if(actualRange)
       +                *actualRange = r;
       +        return [[self window] convertRectToScreen:_lastInputRect];
       +}
       +- (void)doCommandBySelector:(SEL)s
       +{
       +        NSEvent *e;
       +        NSEventModifierFlags m;
       +        uint c, k;
       +
       +        LOG(@"doCommandBySelector (%@)", NSStringFromSelector(s));
       +
       +        e = [NSApp currentEvent];
       +        c = [[e characters] characterAtIndex:0];
       +        k = keycvt(c);
       +        LOG(@"keyDown: character0: 0x%x -> 0x%x", c, k);
       +        m = [e modifierFlags];
       +
       +        if(m & NSEventModifierFlagCommand){
       +                if((m & NSEventModifierFlagShift) && 'a' <= k && k <= 'z')
       +                        k += 'A' - 'a';
       +                if(' '<=k && k<='~')
       +                        k += Kcmd;
       +        }
       +        if(k>0)
       +                keystroke(k);
       +}
       +
       +// Helper for managing input rect approximately
       +- (void)resetLastInputRect
       +{
       +        LOG(@"resetLastInputRect");
       +        _lastInputRect.origin.x = 0.0;
       +        _lastInputRect.origin.y = 0.0;
       +        _lastInputRect.size.width = 0.0;
       +        _lastInputRect.size.height = 0.0;
       +}
       +
       +- (void)enlargeLastInputRect:(NSRect)r
       +{
       +        r.origin.y = [self bounds].size.height - r.origin.y - r.size.height;
       +        _lastInputRect = NSUnionRect(_lastInputRect, r);
       +        LOG(@"update last input rect (%g, %g, %g, %g)",
       +                _lastInputRect.origin.x, _lastInputRect.origin.y,
       +                _lastInputRect.size.width, _lastInputRect.size.height);
       +}
       +
       +- (void)clearInput
       +{
       +        if(_tmpText.length){
       +                uint i;
       +                int l;
       +                l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
       +                        + (_selectedRange.length > 0);
       +                LOG(@"move right %d", l);
       +                for(i = 0; i < l; ++i)
       +                        keystroke(Kright);
       +                l = _tmpText.length+2+2*(_selectedRange.length > 0);
       +                LOG(@"backspace %d", l);
       +                for(uint i = 0; i < l; ++i)
       +                        keystroke(Kbs);
       +        }
       +}
       +
       +@end
       +
       +@implementation DrawLayer
       +
       +- (void)display
       +{
       +        id<MTLCommandBuffer> cbuf;
       +        id<MTLBlitCommandEncoder> blit;
       +
       +        LOG(@"display");
       +
       +        cbuf = [commandQueue commandBuffer];
       +
       +        LOG(@"display query drawable");
       +
       +@autoreleasepool{
       +        id<CAMetalDrawable> drawable;
       +
       +        drawable = [layer nextDrawable];
       +        if(!drawable){
       +                LOG(@"display couldn't get drawable");
       +                [self setNeedsDisplay];
       +                return;
       +        }
       +
       +        LOG(@"display got drawable");
       +
       +        blit = [cbuf blitCommandEncoder];
       +        [blit copyFromTexture:texture
       +                sourceSlice:0
       +                sourceLevel:0
       +                sourceOrigin:MTLOriginMake(0, 0, 0)
       +                sourceSize:MTLSizeMake(texture.width, texture.height, texture.depth)
       +                toTexture:drawable.texture
       +                destinationSlice:0
       +                destinationLevel:0
       +                destinationOrigin:MTLOriginMake(0, 0, 0)];
       +        [blit endEncoding];
       +
       +        [cbuf presentDrawable:drawable];
       +        drawable = nil;
       +}
       +        [cbuf addCompletedHandler:^(id<MTLCommandBuffer> cmdBuff){
       +                if(cmdBuff.error){
       +                        NSLog(@"command buffer finished with error: %@",
       +                                cmdBuff.error.localizedDescription);
       +                }else
       +                        LOG(@"command buffer finishes present drawable");
       +        }];
       +        [cbuf commit];
       +
       +        LOG(@"display commit");
       +}
       +
       +@end
       +
       +static uint
       +msec(void)
       +{
       +        return nsec()/1000000;
       +}
       +
       +static uint
       +keycvt(uint code)
       +{
       +        switch(code){
       +        case '\r': return '\n';
       +        case 127: return '\b';
       +        case NSUpArrowFunctionKey: return Kup;
       +        case NSDownArrowFunctionKey: return Kdown;
       +        case NSLeftArrowFunctionKey: return Kleft;
       +        case NSRightArrowFunctionKey: return Kright;
       +        case NSInsertFunctionKey: return Kins;
       +        case NSDeleteFunctionKey: return Kdel;
       +        case NSHomeFunctionKey: return Khome;
       +        case NSEndFunctionKey: return Kend;
       +        case NSPageUpFunctionKey: return Kpgup;
       +        case NSPageDownFunctionKey: return Kpgdown;
       +        case NSF1FunctionKey: return KF|1;
       +        case NSF2FunctionKey: return KF|2;
       +        case NSF3FunctionKey: return KF|3;
       +        case NSF4FunctionKey: return KF|4;
       +        case NSF5FunctionKey: return KF|5;
       +        case NSF6FunctionKey: return KF|6;
       +        case NSF7FunctionKey: return KF|7;
       +        case NSF8FunctionKey: return KF|8;
       +        case NSF9FunctionKey: return KF|9;
       +        case NSF10FunctionKey: return KF|10;
       +        case NSF11FunctionKey: return KF|11;
       +        case NSF12FunctionKey: return KF|12;
       +        case NSBeginFunctionKey:
       +        case NSPrintScreenFunctionKey:
       +        case NSScrollLockFunctionKey:
       +        case NSF13FunctionKey:
       +        case NSF14FunctionKey:
       +        case NSF15FunctionKey:
       +        case NSF16FunctionKey:
       +        case NSF17FunctionKey:
       +        case NSF18FunctionKey:
       +        case NSF19FunctionKey:
       +        case NSF20FunctionKey:
       +        case NSF21FunctionKey:
       +        case NSF22FunctionKey:
       +        case NSF23FunctionKey:
       +        case NSF24FunctionKey:
       +        case NSF25FunctionKey:
       +        case NSF26FunctionKey:
       +        case NSF27FunctionKey:
       +        case NSF28FunctionKey:
       +        case NSF29FunctionKey:
       +        case NSF30FunctionKey:
       +        case NSF31FunctionKey:
       +        case NSF32FunctionKey:
       +        case NSF33FunctionKey:
       +        case NSF34FunctionKey:
       +        case NSF35FunctionKey:
       +        case NSPauseFunctionKey:
       +        case NSSysReqFunctionKey:
       +        case NSBreakFunctionKey:
       +        case NSResetFunctionKey:
       +        case NSStopFunctionKey:
       +        case NSMenuFunctionKey:
       +        case NSUserFunctionKey:
       +        case NSSystemFunctionKey:
       +        case NSPrintFunctionKey:
       +        case NSClearLineFunctionKey:
       +        case NSClearDisplayFunctionKey:
       +        case NSInsertLineFunctionKey:
       +        case NSDeleteLineFunctionKey:
       +        case NSInsertCharFunctionKey:
       +        case NSDeleteCharFunctionKey:
       +        case NSPrevFunctionKey:
       +        case NSNextFunctionKey:
       +        case NSSelectFunctionKey:
       +        case NSExecuteFunctionKey:
       +        case NSUndoFunctionKey:
       +        case NSRedoFunctionKey:
       +        case NSFindFunctionKey:
       +        case NSHelpFunctionKey:
       +        case NSModeSwitchFunctionKey: return 0;
       +        default: return code;
       +        }
       +}
       +
       +Memimage*
       +attachscreen(char *label, char *winsize)
       +{
       +        LOG(@"attachscreen(%s, %s)", label, winsize);
       +        [AppDelegate
       +                performSelectorOnMainThread:@selector(makewin:)
       +                withObject:[NSValue valueWithPointer:winsize]
       +                waitUntilDone:YES];
       +        kicklabel(label);
       +        setcursor(nil, nil);
       +        mouseresized = 0;
       +        return initimg();
       +}
       +
       +static Memimage*
       +initimg(void)
       +{
       +@autoreleasepool{
       +        CGFloat scale;
       +        NSSize size;
       +        MTLTextureDescriptor *textureDesc;
       +
       +        size = [myContent convertSizeToBacking:[myContent bounds].size];
       +        mouserect = Rect(0, 0, size.width, size.height);
       +
       +        LOG(@"initimg %.0f %.0f", size.width, size.height);
       +
       +        img = allocmemimage(mouserect, XRGB32);
       +        if(img == nil)
       +                panic("allocmemimage: %r");
       +        if(img->data == nil)
       +                panic("img->data == nil");
       +
       +        textureDesc = [MTLTextureDescriptor
       +                texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
       +                width:size.width
       +                height:size.height
       +                mipmapped:NO];
       +        textureDesc.allowGPUOptimizedContents = YES;
       +        textureDesc.usage = MTLTextureUsageShaderRead;
       +        textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
       +        texture = [device newTextureWithDescriptor:textureDesc];
       +
       +        scale = [win backingScaleFactor];
       +        [layer setDrawableSize:size];
       +        [layer 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.
       +        // That's not quite right but it's close to correct.
       +        // https://en.wikipedia.org/wiki/Retina_display#Models
       +        displaydpi = scale * 110;
       +}
       +        LOG(@"initimg return");
       +
       +        return img;
       +}
       +
       +void
       +_flushmemscreen(Rectangle r)
       +{
       +        LOG(@"_flushmemscreen(%d,%d,%d,%d)", r.min.x, r.min.y, Dx(r), Dy(r));
       +        if(!rectinrect(r, Rect(0, 0, texture.width, texture.height))){
       +                LOG(@"Rectangle is out of bounds, return.");
       +                return;
       +        }
       +
       +        @autoreleasepool{
       +                [texture
       +                        replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r))
       +                        mipmapLevel:0
       +                        withBytes:byteaddr(img, Pt(r.min.x, r.min.y))
       +                        bytesPerRow:img->width*sizeof(u32int)];
       +                [AppDelegate
       +                        performSelectorOnMainThread:@selector(callsetNeedsDisplayInRect:)
       +                        withObject:[NSValue valueWithRect:NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r))]
       +                        waitUntilDone:NO];
       +        }
       +}
       +
       +void
       +setmouse(Point p)
       +{
       +        @autoreleasepool{
       +                NSPoint q;
       +
       +                LOG(@"setmouse(%d,%d)", p.x, p.y);
       +                q = [win convertPointFromBacking:NSMakePoint(p.x, p.y)];
       +                LOG(@"(%g, %g) <- fromBacking", q.x, q.y);
       +                q = [myContent convertPoint:q toView:nil];
       +                LOG(@"(%g, %g) <- toWindow", q.x, q.y);
       +                q = [win convertPointToScreen:q];
       +                LOG(@"(%g, %g) <- toScreen", q.x, q.y);
       +                // Quartz has the origin of the "global display
       +                // coordinate space" at the top left of the primary
       +                // screen with y increasing downward, while Cocoa has
       +                // the origin at the bottom left of the primary screen
       +                // with y increasing upward.  We flip the coordinate
       +                // with a negative sign and shift upward by the height
       +                // of the primary screen.
       +                q.y = NSScreen.screens[0].frame.size.height - q.y;
       +                LOG(@"(%g, %g) <- setmouse", q.x, q.y);
       +                CGWarpMouseCursorPosition(NSPointToCGPoint(q));
       +                CGAssociateMouseAndMouseCursorPosition(true);
       +        }
       +}
       +
       +char*
       +getsnarf(void)
       +{
       +        NSPasteboard *pb;
       +        NSString *s;
       +
       +        @autoreleasepool{
       +                pb = [NSPasteboard generalPasteboard];
       +
       +                qlock(&snarfl);
       +                s = [pb stringForType:NSPasteboardTypeString];
       +                qunlock(&snarfl);
       +
       +                if(s)
       +                        return strdup((char *)[s UTF8String]);
       +                else
       +                        return nil;
       +        }
       +}
       +
       +void
       +putsnarf(char *s)
       +{
       +        NSArray *t;
       +        NSPasteboard *pb;
       +        NSString *str;
       +
       +        if(strlen(s) >= SnarfSize)
       +                return;
       +
       +        @autoreleasepool{
       +                t = [NSArray arrayWithObject:NSPasteboardTypeString];
       +                pb = [NSPasteboard generalPasteboard];
       +                str = [[NSString alloc] initWithUTF8String:s];
       +
       +                qlock(&snarfl);
       +                [pb declareTypes:t owner:nil];
       +                [pb setString:str forType:NSPasteboardTypeString];
       +                qunlock(&snarfl);
       +        }
       +}
       +
       +void
       +kicklabel(char *label)
       +{
       +        NSString *s;
       +
       +        LOG(@"kicklabel(%s)", label);
       +        if(label == nil)
       +                return;
       +
       +        @autoreleasepool{
       +                s = [[NSString alloc] initWithUTF8String:label];
       +                [AppDelegate
       +                        performSelectorOnMainThread:@selector(callkicklabel:)
       +                        withObject:s
       +                        waitUntilDone:NO];
       +        }
       +}
       +
       +void
       +setcursor(Cursor *c, Cursor2 *c2)
       +{
       +        Cursors cs;
       +        
       +        cs.c = c;
       +        cs.c2 = c2;
       +
       +        [AppDelegate
       +                performSelectorOnMainThread:@selector(callsetcursor:)
       +                withObject:[NSValue valueWithPointer:&cs]
       +                waitUntilDone:YES];
       +}
       +
       +void
       +topwin(void)
       +{
       +        [win
       +                performSelectorOnMainThread:
       +                @selector(makeKeyAndOrderFront:)
       +                withObject:nil
       +                waitUntilDone:YES];
       +
       +        [NSApp activateIgnoringOtherApps:YES];
       +}
       +
       +void
       +resizeimg(void)
       +{
       +        zlock();
       +        _drawreplacescreenimage(initimg());
       +
       +        mouseresized = 1;
       +        zunlock();
       +        [myContent sendmouse:0];
       +}
       +
       +void
       +resizewindow(Rectangle r)
       +{
       +        LOG(@"resizewindow %d %d %d %d", r.min.x, r.min.y, Dx(r), Dy(r));
       +        dispatch_async(dispatch_get_main_queue(), ^(void){
       +                NSSize s;
       +
       +                s = [myContent convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))];
       +                [win setContentSize:s];
       +        });
       +}
       +
       +static void
       +setprocname(const char *s)
       +{
       +  CFStringRef process_name;
       +
       +  process_name = CFStringCreateWithBytes(nil, (uchar*)s, strlen(s), kCFStringEncodingUTF8, false);
       +
       +  // Adapted from Chrome's mac_util.mm.
       +  // http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm
       +  //
       +  // Copyright (c) 2012 The Chromium Authors. All rights reserved.
       +  //
       +  // Redistribution and use in source and binary forms, with or without
       +  // modification, are permitted provided that the following conditions are
       +  // met:
       +  //
       +  //    * Redistributions of source code must retain the above copyright
       +  // notice, this list of conditions and the following disclaimer.
       +  //    * Redistributions in binary form must reproduce the above
       +  // copyright notice, this list of conditions and the following disclaimer
       +  // in the documentation and/or other materials provided with the
       +  // distribution.
       +  //    * Neither the name of Google Inc. nor the names of its
       +  // contributors may be used to endorse or promote products derived from
       +  // this software without specific prior written permission.
       +  //
       +  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       +  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       +  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       +  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       +  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       +  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       +  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       +  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       +  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       +  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       +  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       +  // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
       +  // plugin host, and could break at any time (although realistically it's only
       +  // likely to break in a new major release).
       +  // When 10.7 is available, check that this still works, and update this
       +  // comment for 10.8.
       +
       +  // Private CFType used in these LaunchServices calls.
       +  typedef CFTypeRef PrivateLSASN;
       +  typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
       +  typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
       +                                                          CFStringRef,
       +                                                          CFStringRef,
       +                                                          CFDictionaryRef*);
       +
       +  static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
       +      NULL;
       +  static LSSetApplicationInformationItemType
       +      ls_set_application_information_item_func = NULL;
       +  static CFStringRef ls_display_name_key = NULL;
       +
       +  static bool did_symbol_lookup = false;
       +  if (!did_symbol_lookup) {
       +    did_symbol_lookup = true;
       +    CFBundleRef launch_services_bundle =
       +        CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
       +    if (!launch_services_bundle) {
       +      fprint(2, "Failed to look up LaunchServices bundle\n");
       +      return;
       +    }
       +
       +    ls_get_current_application_asn_func =
       +        (LSGetCurrentApplicationASNType)(
       +            CFBundleGetFunctionPointerForName(
       +                launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
       +    if (!ls_get_current_application_asn_func)
       +      fprint(2, "Could not find _LSGetCurrentApplicationASN\n");
       +
       +    ls_set_application_information_item_func =
       +        (LSSetApplicationInformationItemType)(
       +            CFBundleGetFunctionPointerForName(
       +                launch_services_bundle,
       +                CFSTR("_LSSetApplicationInformationItem")));
       +    if (!ls_set_application_information_item_func)
       +      fprint(2, "Could not find _LSSetApplicationInformationItem\n");
       +
       +    CFStringRef* key_pointer = (CFStringRef*)(
       +        CFBundleGetDataPointerForName(launch_services_bundle,
       +                                      CFSTR("_kLSDisplayNameKey")));
       +    ls_display_name_key = key_pointer ? *key_pointer : NULL;
       +    if (!ls_display_name_key)
       +      fprint(2, "Could not find _kLSDisplayNameKey\n");
       +
       +    // Internally, this call relies on the Mach ports that are started up by the
       +    // Carbon Process Manager.  In debug builds this usually happens due to how
       +    // the logging layers are started up; but in release, it isn't started in as
       +    // much of a defined order.  So if the symbols had to be loaded, go ahead
       +    // and force a call to make sure the manager has been initialized and hence
       +    // the ports are opened.
       +    ProcessSerialNumber psn;
       +    GetCurrentProcess(&psn);
       +  }
       +  if (!ls_get_current_application_asn_func ||
       +      !ls_set_application_information_item_func ||
       +      !ls_display_name_key) {
       +    return;
       +  }
       +
       +  PrivateLSASN asn = ls_get_current_application_asn_func();
       +  // Constant used by WebKit; what exactly it means is unknown.
       +  const int magic_session_constant = -2;
       +  OSErr err =
       +      ls_set_application_information_item_func(magic_session_constant, asn,
       +                                               ls_display_name_key,
       +                                               process_name,
       +                                               NULL /* optional out param */);
       +  if(err != noErr)
       +    fprint(2, "Call to set process name failed\n");
       +}
 (DIR) diff --git a/src/cmd/devdraw/mac-srv.c b/src/cmd/devdraw/mac-srv.c
       t@@ -0,0 +1,427 @@
       +/*
       + * Window system protocol server.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <draw.h>
       +#include <memdraw.h>
       +#include <keyboard.h>
       +#include <mouse.h>
       +#include <cursor.h>
       +#include <drawfcall.h>
       +#include "mac-screen.h"
       +#include "devdraw.h"
       +
       +typedef struct Kbdbuf Kbdbuf;
       +typedef struct Mousebuf Mousebuf;
       +typedef struct Fdbuf Fdbuf;
       +typedef struct Tagbuf Tagbuf;
       +
       +struct Kbdbuf
       +{
       +        Rune r[256];
       +        int ri;
       +        int wi;
       +        int stall;
       +};
       +
       +struct Mousebuf
       +{
       +        Mouse m[256];
       +        Mouse last;
       +        int ri;
       +        int wi;
       +        int stall;
       +};
       +
       +struct Tagbuf
       +{
       +        int t[256];
       +        int ri;
       +        int wi;
       +};
       +
       +Kbdbuf kbd;
       +Mousebuf mouse;
       +Tagbuf kbdtags;
       +Tagbuf mousetags;
       +
       +void runmsg(Wsysmsg*);
       +void replymsg(Wsysmsg*);
       +void matchkbd(void);
       +void matchmouse(void);
       +
       +
       +QLock lk;
       +void
       +zlock(void)
       +{
       +        qlock(&lk);
       +}
       +
       +void
       +zunlock(void)
       +{
       +        qunlock(&lk);
       +}
       +
       +int trace = 0;
       +
       +void
       +servep9p(void)
       +{
       +        uchar buf[4], *mbuf;
       +        int nmbuf, n, nn;
       +        Wsysmsg m;
       +
       +        fmtinstall('W', drawfcallfmt);
       +
       +        mbuf = nil;
       +        nmbuf = 0;
       +        while((n = read(3, buf, 4)) == 4){
       +                GET(buf, n);
       +                if(n > nmbuf){
       +                        free(mbuf);
       +                        mbuf = malloc(4+n);
       +                        if(mbuf == nil)
       +                                sysfatal("malloc: %r");
       +                        nmbuf = n;
       +                }
       +                memmove(mbuf, buf, 4);
       +                nn = readn(3, mbuf+4, n-4);
       +                if(nn != n-4)
       +                        sysfatal("eof during message");
       +
       +                /* pick off messages one by one */
       +                if(convM2W(mbuf, nn+4, &m) <= 0)
       +                        sysfatal("cannot convert message");
       +                if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
       +                runmsg(&m);
       +        }
       +}
       +
       +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)
       +{
       +        static uchar buf[65536];
       +        int n;
       +        Memimage *i;
       +
       +        switch(m->type){
       +        case Tinit:
       +                memimageinit();
       +                i = attachscreen(m->label, m->winsize);
       +                _initdisplaymemimage(i);
       +                replymsg(m);
       +                break;
       +
       +        case Trdmouse:
       +                zlock();
       +                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");
       +                mouse.stall = 0;
       +                matchmouse();
       +                zunlock();
       +                break;
       +
       +        case Trdkbd:
       +                zlock();
       +                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();
       +                zunlock();
       +                break;
       +
       +        case Tmoveto:
       +                setmouse(m->mouse.xy);
       +                replymsg(m);
       +                break;
       +
       +        case Tcursor:
       +                if(m->arrowcursor)
       +                        setcursor(nil, nil);
       +                else
       +                        setcursor(&m->cursor, nil);
       +                replymsg(m);
       +                break;
       +
       +        case Tcursor2:
       +                if(m->arrowcursor)
       +                        setcursor(nil, nil);
       +                else
       +                        setcursor(&m->cursor, &m->cursor2);
       +                replymsg(m);
       +                break;
       +
       +        case Tbouncemouse:
       +        //        _xbouncemouse(&m->mouse);
       +                replymsg(m);
       +                break;
       +
       +        case Tlabel:
       +                kicklabel(m->label);
       +                replymsg(m);
       +                break;
       +
       +        case Trdsnarf:
       +                m->snarf = getsnarf();
       +                replymsg(m);
       +                free(m->snarf);
       +                break;
       +
       +        case Twrsnarf:
       +                putsnarf(m->snarf);
       +                replymsg(m);
       +                break;
       +
       +        case Trddraw:
       +                zlock();
       +                n = m->count;
       +                if(n > sizeof buf)
       +                        n = sizeof buf;
       +                n = _drawmsgread(buf, n);
       +                if(n < 0)
       +                        replyerror(m);
       +                else{
       +                        m->count = n;
       +                        m->data = buf;
       +                        replymsg(m);
       +                }
       +                zunlock();
       +                break;
       +
       +        case Twrdraw:
       +                zlock();
       +                if(_drawmsgwrite(m->data, m->count) < 0)
       +                        replyerror(m);
       +                else
       +                        replymsg(m);
       +                zunlock();
       +                break;
       +
       +        case Ttop:
       +                topwin();
       +                replymsg(m);
       +                break;
       +
       +        case Tresize:
       +                resizewindow(m->rect);
       +                replymsg(m);
       +                break;
       +        }
       +}
       +
       +/*
       + * Reply to m.
       + */
       +QLock replylock;
       +void
       +replymsg(Wsysmsg *m)
       +{
       +        int n;
       +        static uchar *mbuf;
       +        static int nmbuf;
       +
       +        /* T -> R msg */
       +        if(m->type%2 == 0)
       +                m->type++;
       +
       +        if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
       +        /* copy to output buffer */
       +        n = sizeW2M(m);
       +
       +        qlock(&replylock);
       +        if(n > nmbuf){
       +                free(mbuf);
       +                mbuf = malloc(n);
       +                if(mbuf == nil)
       +                        sysfatal("out of memory");
       +                nmbuf = n;
       +        }
       +        convW2M(m, mbuf, n);
       +        if(write(4, mbuf, n) != n)
       +                sysfatal("write: %r");
       +        qunlock(&replylock);
       +}
       +
       +/*
       + * 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 = mouseresized;
       +                mouseresized = 0;
       +                /*
       +                if(m.resized)
       +                        fprint(2, "sending resize\n");
       +                */
       +                mouse.ri++;
       +                if(mouse.ri == nelem(mouse.m))
       +                        mouse.ri = 0;
       +                replymsg(&m);
       +        }
       +}
       +
       +void
       +mousetrack(int x, int y, int b, uint ms)
       +{
       +        Mouse *m;
       +
       +        if(x < mouserect.min.x)
       +                x = mouserect.min.x;
       +        if(x > mouserect.max.x)
       +                x = mouserect.max.x;
       +        if(y < mouserect.min.y)
       +                y = mouserect.min.y;
       +        if(y > mouserect.max.y)
       +                y = mouserect.max.y;
       +
       +        zlock();
       +        // If reader has stopped reading, don't bother.
       +        // If reader is completely caught up, definitely queue.
       +        // Otherwise, queue only button change events.
       +        if(!mouse.stall)
       +        if(mouse.wi == mouse.ri || mouse.last.buttons != b){
       +                m = &mouse.last;
       +                m->xy.x = x;
       +                m->xy.y = y;
       +                m->buttons = b;
       +                m->msec = ms;
       +
       +                mouse.m[mouse.wi] = *m;
       +                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;
       +                }
       +                matchmouse();
       +        }
       +        zunlock();
       +}
       +
       +void
       +kputc(int c)
       +{
       +        zlock();
       +        kbd.r[kbd.wi++] = c;
       +        if(kbd.wi == nelem(kbd.r))
       +                kbd.wi = 0;
       +        if(kbd.ri == kbd.wi)
       +                kbd.stall = 1;
       +        matchkbd();
       +        zunlock();
       +}
       +
       +static int alting;
       +
       +void
       +abortcompose(void)
       +{
       +        if(alting)
       +                keystroke(Kalt);
       +}
       +
       +void
       +keystroke(int c)
       +{
       +        static Rune k[10];
       +        static int nk;
       +        int i;
       +
       +        if(c == Kalt){
       +                alting = !alting;
       +                nk = 0;
       +                return;
       +        }
       +        if(c == Kcmd+'r') {
       +                if(forcedpi)
       +                        forcedpi = 0;
       +                else if(displaydpi >= 200)
       +                        forcedpi = 100;
       +                else
       +                        forcedpi = 225;
       +                resizeimg();
       +                return;
       +        }
       +        if(!alting){
       +                kputc(c);
       +                return;
       +        }
       +        if(nk >= nelem(k))      // should not happen
       +                nk = 0;
       +        k[nk++] = c;
       +        c = _latin1(k, nk);
       +        if(c > 0){
       +                alting = 0;
       +                kputc(c);
       +                nk = 0;
       +                return;
       +        }
       +        if(c == -1){
       +                alting = 0;
       +                for(i=0; i<nk; i++)
       +                        kputc(k[i]);
       +                nk = 0;
       +                return;
       +        }
       +        // need more input
       +        return;
       +}
 (DIR) diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh
       t@@ -26,7 +26,7 @@ if [ "x$WSYSTYPE" = "x" ]; then
                                echo 1>&2 'OS X 10.12 and older are not supported'
                                exit 1
                        fi
       -                WSYSTYPE=osx-cocoa
       +                WSYSTYPE=mac
                elif [ -d "$X11" ]; then
                        WSYSTYPE=x11
                else
       t@@ -51,9 +51,9 @@ if [ $WSYSTYPE = x11 ]; then
                echo 'HFILES=$HFILES $XHFILES'
                XO=`ls x11-*.c 2>/dev/null | sed 's/\.c$/.o/'`
                echo 'WSYSOFILES=$WSYSOFILES '$XO
       -elif [ $WSYSTYPE = osx-cocoa ]; then
       +elif [ $WSYSTYPE = mac ]; then
                echo 'OBJCFLAGS=$OBJCFLAGS -fobjc-arc'
       -        echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen.o cocoa-srv.o'
       +        echo 'WSYSOFILES=$WSYSOFILES mac-draw.o mac-screen.o mac-srv.o'
                echo 'MACARGV=macargv.o'
        elif [ $WSYSTYPE = nowsys ]; then
                echo 'WSYSOFILES=nowsys.o'
 (DIR) diff --git a/src/cmd/devdraw/osx-keycodes.h b/src/cmd/devdraw/osx-keycodes.h
       t@@ -1,189 +0,0 @@
       -/* These are the Macintosh key scancode constants -- from Inside Macintosh */
       -#define QZ_ESCAPE                0x35
       -#define QZ_F1                        0x7A
       -#define QZ_F2                        0x78
       -#define QZ_F3                        0x63
       -#define QZ_F4                        0x76
       -#define QZ_F5                        0x60
       -#define QZ_F6                        0x61
       -#define QZ_F7                        0x62
       -#define QZ_F8                        0x64
       -#define QZ_F9                        0x65
       -#define QZ_F10                        0x6D
       -#define QZ_F11                        0x67
       -#define QZ_F12                        0x6F
       -#define QZ_PRINT                0x69
       -#define QZ_SCROLLOCK            0x6B
       -#define QZ_PAUSE                0x71
       -#define QZ_POWER                0x7F
       -#define QZ_BACKQUOTE                0x32
       -#define QZ_1                        0x12
       -#define QZ_2                        0x13
       -#define QZ_3                        0x14
       -#define QZ_4                        0x15
       -#define QZ_5                        0x17
       -#define QZ_6                        0x16
       -#define QZ_7                        0x1A
       -#define QZ_8                        0x1C
       -#define QZ_9                        0x19
       -#define QZ_0                        0x1D
       -#define QZ_MINUS                0x1B
       -#define QZ_EQUALS                0x18
       -#define QZ_BACKSPACE                0x33
       -#define QZ_INSERT                0x72
       -#define QZ_HOME                        0x73
       -#define QZ_PAGEUP                0x74
       -#define QZ_NUMLOCK                0x47
       -#define QZ_KP_EQUALS                0x51
       -#define QZ_KP_DIVIDE                0x4B
       -#define QZ_KP_MULTIPLY                0x43
       -#define QZ_TAB                        0x30
       -#define QZ_q                        0x0C
       -#define QZ_w                        0x0D
       -#define QZ_e                        0x0E
       -#define QZ_r                        0x0F
       -#define QZ_t                        0x11
       -#define QZ_y                        0x10
       -#define QZ_u                        0x20
       -#define QZ_i                        0x22
       -#define QZ_o                        0x1F
       -#define QZ_p                        0x23
       -#define QZ_LEFTBRACKET                0x21
       -#define QZ_RIGHTBRACKET                0x1E
       -#define QZ_BACKSLASH                0x2A
       -#define QZ_DELETE                0x75
       -#define QZ_END                        0x77
       -#define QZ_PAGEDOWN                0x79
       -#define QZ_KP7                        0x59
       -#define QZ_KP8                        0x5B
       -#define QZ_KP9                        0x5C
       -#define QZ_KP_MINUS                0x4E
       -#define QZ_CAPSLOCK                0x39
       -#define QZ_a                        0x00
       -#define QZ_s                        0x01
       -#define QZ_d                        0x02
       -#define QZ_f                        0x03
       -#define QZ_g                        0x05
       -#define QZ_h                        0x04
       -#define QZ_j                        0x26
       -#define QZ_k                        0x28
       -#define QZ_l                        0x25
       -#define QZ_SEMICOLON                0x29
       -#define QZ_QUOTE                0x27
       -#define QZ_RETURN                0x24
       -#define QZ_KP4                        0x56
       -#define QZ_KP5                        0x57
       -#define QZ_KP6                        0x58
       -#define QZ_KP_PLUS                0x45
       -#define QZ_LSHIFT                0x38
       -#define QZ_z                        0x06
       -#define QZ_x                        0x07
       -#define QZ_c                        0x08
       -#define QZ_v                        0x09
       -#define QZ_b                        0x0B
       -#define QZ_n                        0x2D
       -#define QZ_m                        0x2E
       -#define QZ_COMMA                0x2B
       -#define QZ_PERIOD                0x2F
       -#define QZ_SLASH                0x2C
       -/* These are the same as the left versions - use left by default */
       -#if 0
       -#define QZ_RSHIFT                0x38
       -#endif
       -#define QZ_UP                        0x7E
       -#define QZ_KP1                        0x53
       -#define QZ_KP2                        0x54
       -#define QZ_KP3                        0x55
       -#define QZ_KP_ENTER                0x4C
       -#define QZ_LCTRL                0x3B
       -#define QZ_LALT                        0x3A
       -#define QZ_LMETA                0x37
       -#define QZ_SPACE                0x31
       -/* These are the same as the left versions - use left by default */
       -#if 0
       -#define QZ_RMETA                0x37
       -#define QZ_RALT                        0x3A
       -#define QZ_RCTRL                0x3B
       -#endif
       -#define QZ_LEFT                        0x7B
       -#define QZ_DOWN                        0x7D
       -#define QZ_RIGHT                0x7C
       -#define QZ_KP0                        0x52
       -#define QZ_KP_PERIOD                0x41
       -
       -/* Wierd, these keys are on my iBook under MacOS X */
       -#define QZ_IBOOK_ENTER                0x34
       -#define QZ_IBOOK_LEFT                0x3B
       -#define QZ_IBOOK_RIGHT                0x3C
       -#define QZ_IBOOK_DOWN                0x3D
       -#define QZ_IBOOK_UP                0x3E
       -#define KEY_ENTER 13
       -#define KEY_TAB 9
       -
       -#define KEY_BASE 0x100
       -
       -/*  Function keys  */
       -#define KEY_F (KEY_BASE+64)
       -
       -/* Control keys */
       -#define KEY_CTRL (KEY_BASE)
       -#define KEY_BACKSPACE (KEY_CTRL+0)
       -#define KEY_DELETE (KEY_CTRL+1)
       -#define KEY_INSERT (KEY_CTRL+2)
       -#define KEY_HOME (KEY_CTRL+3)
       -#define KEY_END (KEY_CTRL+4)
       -#define KEY_PAGE_UP (KEY_CTRL+5)
       -#define KEY_PAGE_DOWN (KEY_CTRL+6)
       -#define KEY_ESC (KEY_CTRL+7)
       -
       -/* Control keys short name */
       -#define KEY_BS KEY_BACKSPACE
       -#define KEY_DEL KEY_DELETE
       -#define KEY_INS KEY_INSERT
       -#define KEY_PGUP KEY_PAGE_UP
       -#define KEY_PGDOWN KEY_PAGE_DOWN
       -#define KEY_PGDWN KEY_PAGE_DOWN
       -
       -/* Cursor movement */
       -#define KEY_CRSR (KEY_BASE+16)
       -#define KEY_RIGHT (KEY_CRSR+0)
       -#define KEY_LEFT (KEY_CRSR+1)
       -#define KEY_DOWN (KEY_CRSR+2)
       -#define KEY_UP (KEY_CRSR+3)
       -
       -/* Multimedia keyboard/remote keys */
       -#define KEY_MM_BASE (0x100+384)
       -#define KEY_POWER (KEY_MM_BASE+0)
       -#define KEY_MENU (KEY_MM_BASE+1)
       -#define KEY_PLAY (KEY_MM_BASE+2)
       -#define KEY_PAUSE (KEY_MM_BASE+3)
       -#define KEY_PLAYPAUSE (KEY_MM_BASE+4)
       -#define KEY_STOP (KEY_MM_BASE+5)
       -#define KEY_FORWARD (KEY_MM_BASE+6)
       -#define KEY_REWIND (KEY_MM_BASE+7)
       -#define KEY_NEXT (KEY_MM_BASE+8)
       -#define KEY_PREV (KEY_MM_BASE+9)
       -#define KEY_VOLUME_UP (KEY_MM_BASE+10)
       -#define KEY_VOLUME_DOWN (KEY_MM_BASE+11)
       -#define KEY_MUTE (KEY_MM_BASE+12)
       -
       -/* Keypad keys */
       -#define KEY_KEYPAD (KEY_BASE+32)
       -#define KEY_KP0 (KEY_KEYPAD+0)
       -#define KEY_KP1 (KEY_KEYPAD+1)
       -#define KEY_KP2 (KEY_KEYPAD+2)
       -#define KEY_KP3 (KEY_KEYPAD+3)
       -#define KEY_KP4 (KEY_KEYPAD+4)
       -#define KEY_KP5 (KEY_KEYPAD+5)
       -#define KEY_KP6 (KEY_KEYPAD+6)
       -#define KEY_KP7 (KEY_KEYPAD+7)
       -#define KEY_KP8 (KEY_KEYPAD+8)
       -#define KEY_KP9 (KEY_KEYPAD+9)
       -#define KEY_KPDEC (KEY_KEYPAD+10)
       -#define KEY_KPINS (KEY_KEYPAD+11)
       -#define KEY_KPDEL (KEY_KEYPAD+12)
       -#define KEY_KPENTER (KEY_KEYPAD+13)
       -
       -/* Special keys */
       -#define KEY_INTERN (0x1000)
       -#define KEY_CLOSE_WIN (KEY_INTERN+0)
 (DIR) diff --git a/src/cmd/fontsrv/osx.c b/src/cmd/fontsrv/mac.c
 (DIR) diff --git a/src/cmd/fontsrv/mkfile b/src/cmd/fontsrv/mkfile
       t@@ -14,8 +14,6 @@ OFILES=\
        
        <$PLAN9/src/mkone
        
       -osx-cocoa.$O: osx.c
       -
        showpjw: showpjw.c
                9c showpjw.c
                9l -o showpjw showpjw.o
 (DIR) diff --git a/src/cmd/fontsrv/osx-cocoa.c b/src/cmd/fontsrv/osx-cocoa.c
       t@@ -1 +0,0 @@
       -#include "osx.c"
 (DIR) diff --git a/src/cmd/snarfer/osx-cocoa-snarfer.c b/src/cmd/snarfer/mac-snarfer.c
 (DIR) diff --git a/src/cmd/snarfer/mkfile b/src/cmd/snarfer/mkfile
       t@@ -9,4 +9,4 @@ HFILES=
        <$PLAN9/src/mkone
        
        x11-snarfer.$O: snarfer.c
       -osx-snarfer.$O: snarfer.c
       +mac-snarfer.$O: snarfer.c
 (DIR) diff --git a/src/cmd/snarfer/osx-snarfer.c b/src/cmd/snarfer/osx-snarfer.c
       t@@ -1 +0,0 @@
       -#include "snarfer.c"