aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/devdraw/bigarrow.h22
-rw-r--r--src/cmd/devdraw/cocoa-screen-metal.m1260
-rw-r--r--src/cmd/devdraw/cocoa-screen.h6
-rw-r--r--src/cmd/devdraw/cocoa-srv.c22
-rw-r--r--src/cmd/devdraw/cocoa-thread.c7
-rw-r--r--src/cmd/devdraw/cocoa-thread.h1
-rw-r--r--src/cmd/devdraw/mkfile3
-rw-r--r--src/cmd/devdraw/mkwsysrules.sh7
8 files changed, 1307 insertions, 21 deletions
diff --git a/src/cmd/devdraw/bigarrow.h b/src/cmd/devdraw/bigarrow.h
index a46f19a0..3b66c954 100644
--- a/src/cmd/devdraw/bigarrow.h
+++ b/src/cmd/devdraw/bigarrow.h
@@ -1,11 +1,13 @@
-Cursor bigarrow = {
- {0, 0},
- {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
- 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC,
- 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
- 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40},
- {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
- 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
- 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
- 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00},
+Cursor bigarrow = {
+ { -1, -1 },
+ { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
+ 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
+ 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
+ 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
+ },
+ { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
+ 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
+ 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
+ 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
+ },
};
diff --git a/src/cmd/devdraw/cocoa-screen-metal.m b/src/cmd/devdraw/cocoa-screen-metal.m
new file mode 100644
index 00000000..c82ce0bc
--- /dev/null
+++ b/src/cmd/devdraw/cocoa-screen-metal.m
@@ -0,0 +1,1260 @@
+#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 "cocoa-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)callservep9p:(id)arg;
++ (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 MTLRenderPassDescriptor *renderPass;
+static id<MTLDevice> device;
+static id<MTLRenderPipelineState> pipelineState;
+static id<MTLCommandQueue> commandQueue;
+static id<MTLTexture> texture;
+
+static Memimage *img = NULL;
+
+static QLock snarfl;
+
+static NSString *const metal =
+@"#include<metal_stdlib>\n"
+"using namespace metal;\n"
+"typedef struct {\n"
+" float4 rCoord [[position]];\n"
+" float2 tCoord;\n"
+"} VertexOut;\n"
+"vertex VertexOut\n"
+"renderVertex(unsigned int vid [[ vertex_id ]])\n"
+"{\n"
+" const VertexOut fixedV[] = {\n"
+" {{ -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f }},\n"
+" {{ 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f }},\n"
+" {{ -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f }},\n"
+" {{ 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f }},\n"
+" };\n"
+" return fixedV[vid];\n"
+"}\n"
+"fragment half4\n"
+"renderFragment(VertexOut in [[ stage_in ]],\n"
+" texture2d<half> texture [[ texture(0) ]]) {\n"
+" constexpr sampler s;\n"
+" return texture.sample(s, in.tCoord);\n"
+"}";
+
+
+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];
+ }
+}
+
+@implementation AppDelegate
+
++ (void)callservep9p:(id)arg
+{
+ servep9p();
+ [NSApp terminate:self];
+}
+
++ (void)makewin:(NSValue *)v
+{
+ NSRect r, sr;
+ Rectangle wr;
+ int set;
+ char *s;
+ id<MTLLibrary> library;
+ MTLRenderPipelineDescriptor *pipelineDesc;
+ NSError *error;
+
+ 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 setRestorable:NO];
+ [win setAcceptsMouseMovedEvents:YES];
+ [win setDelegate:myApp];
+
+ myContent = [DevDrawView new];
+ [win setContentView:myContent];
+ [myContent setWantsLayer:YES];
+ [myContent setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
+
+ device = MTLCreateSystemDefaultDevice();
+ commandQueue = [device newCommandQueue];
+
+ layer = (DrawLayer *)[myContent layer];
+ layer.device = device;
+ layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
+ layer.framebufferOnly = YES;
+ layer.opaque = YES;
+
+ renderPass = [MTLRenderPassDescriptor renderPassDescriptor];
+ renderPass.colorAttachments[0].loadAction = MTLLoadActionDontCare;
+ renderPass.colorAttachments[0].storeAction = MTLStoreActionDontCare;
+
+ library = [device newLibraryWithSource:metal options:nil error:&error];
+ if(!library)
+ sysfatal((char *)[[error localizedDescription] UTF8String]);
+
+ pipelineDesc = [MTLRenderPipelineDescriptor new];
+ pipelineDesc.alphaToOneEnabled = YES;
+ pipelineDesc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle;
+ pipelineDesc.rasterSampleCount = 1;
+ pipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
+ [pipelineDesc setVertexFunction: [library newFunctionWithName: @"renderVertex"]];
+ [pipelineDesc setFragmentFunction: [library newFunctionWithName: @"renderFragment"]];
+
+ pipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
+ if(!pipelineState)
+ sysfatal((char *)[[error localizedDescription] UTF8String]);
+
+ [NSEvent setMouseCoalescingEnabled:NO];
+
+ topwin();
+}
+
++ (void)callkicklabel:(NSString *)s
+{
+ LOG(@"callkicklabel(%@)", s);
+ [win setTitle:s];
+ [[NSApp dockTile] setBadgeLabel:s];
+}
+
+
++ (void)callsetNeedsDisplayInRect:(NSValue *)v
+{
+ NSRect r;
+
+ 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];
+ [myContent enlargeLastInputRect:r];
+}
+
++ (void)callsetcursor:(NSValue *)v
+{
+ Cursor *c;
+ NSBitmapImageRep *r, *r2;
+ NSImage *i;
+ NSPoint p;
+ uint b, x, y, a;
+ uchar *plane[5], *plane2[5];
+ uchar pu, pb, pl, pr, pc; // upper, bottom, left, right, center
+ uchar pul, pur, pbl, pbr;
+ uchar ful, fur, fbl, fbr;
+
+ c = [v pointerValue];
+ if(!c)
+ c = &bigarrow;
+
+ 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<2*16; 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];
+ // https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms#EPX/Scale2×/AdvMAME2×
+ for(a=0; a<2; a++){
+ for(y=0; y<16; y++){
+ for(x=0; x<2; x++){
+ pc = plane[a][x+2*y];
+ pu = y==0 ? pc : plane[a][x+2*(y-1)];
+ pb = y==15 ? pc : plane[a][x+2*(y+1)];
+ pl = (pc>>1) | (x==0 ? pc&0x80 : (plane[a][x-1+2*y]&1)<<7);
+ pr = (pc<<1) | (x==1 ? pc&1 : (plane[a][x+1+2*y]&0x80)>>7);
+ ful = ~(pl^pu) & (pl^pb) & (pu^pr);
+ pul = (ful & pu) | (~ful & pc);
+ fur = ~(pu^pr) & (pu^pl) & (pr^pb);
+ pur = (fur & pr) | (~fur & pc);
+ fbl = ~(pb^pl) & (pb^pr) & (pl^pu);
+ pbl = (fbl & pl) | (~fbl & pc);
+ fbr = ~(pr^pb) & (pr^pu) & (pb^pl);
+ pbr = (fbr & pb) | (~fbr & pc);
+ plane2[a][2*x+4*2*y] = (pul&0x80) | ((pul&0x40)>>1) | ((pul&0x20)>>2) | ((pul&0x10)>>3)
+ | ((pur&0x80)>>1) | ((pur&0x40)>>2) | ((pur&0x20)>>3) | ((pur&0x10)>>4);
+ plane2[a][2*x+1+4*2*y] = ((pul&0x8)<<4) | ((pul&0x4)<<3) | ((pul&0x2)<<2) | ((pul&0x1)<<1)
+ | ((pur&0x8)<<3) | ((pur&0x4)<<2) | ((pur&0x2)<<1) | (pur&0x1);
+ plane2[a][2*x+4*(2*y+1)] = (pbl&0x80) | ((pbl&0x40)>>1) | ((pbl&0x20)>>2) | ((pbl&0x10)>>3)
+ | ((pbr&0x80)>>1) | ((pbr&0x40)>>2) | ((pbr&0x20)>>3) | ((pbr&0x10)>>4);
+ plane2[a][2*x+1+4*(2*y+1)] = ((pbl&0x8)<<4) | ((pbl&0x4)<<3) | ((pbl&0x2)<<2) | ((pbl&0x1)<<1)
+ | ((pbr&0x8)<<3) | ((pbr&0x4)<<2) | ((pbr&0x2)<<1) | (pbr&0x1);
+ }
+ }
+ }
+
+ // 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];
+
+ [NSThread
+ detachNewThreadSelector:@selector(callservep9p:)
+ toTarget:[self class] withObject:nil];
+}
+
+- (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;
+}
+
+@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];
+ resizeimg();
+}
+
+- (void)viewDidChangeBackingProperties
+{
+ [super viewDidChangeBackingProperties];
+ 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);
+ 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<MTLRenderCommandEncoder> cmd;
+
+ 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");
+
+ renderPass.colorAttachments[0].texture = drawable.texture;
+
+ cmd = [cbuf renderCommandEncoderWithDescriptor:renderPass];
+ [cmd setRenderPipelineState:pipelineState];
+ [cmd setFragmentTexture:texture atIndex:0];
+ [cmd drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+ [cmd 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 '\b': return 127;
+ 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);
+ 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));
+
+ @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)
+{
+ [AppDelegate
+ performSelectorOnMainThread:@selector(callsetcursor:)
+ withObject:[NSValue valueWithPointer:c]
+ 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];
+ resizeimg();
+ });
+}
+
+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");
+}
diff --git a/src/cmd/devdraw/cocoa-screen.h b/src/cmd/devdraw/cocoa-screen.h
index 3c4c94c5..7b41c34b 100644
--- a/src/cmd/devdraw/cocoa-screen.h
+++ b/src/cmd/devdraw/cocoa-screen.h
@@ -16,5 +16,9 @@ void servep9p(void);
void zlock(void);
void zunlock(void);
+void resizeimg(void);
+
Rectangle mouserect;
-int mouseresized;
+
+int mouseresized;
+void resizewindow(Rectangle);
diff --git a/src/cmd/devdraw/cocoa-srv.c b/src/cmd/devdraw/cocoa-srv.c
index 197fd512..6f9449ad 100644
--- a/src/cmd/devdraw/cocoa-srv.c
+++ b/src/cmd/devdraw/cocoa-srv.c
@@ -21,7 +21,7 @@ typedef struct Tagbuf Tagbuf;
struct Kbdbuf
{
- Rune r[32];
+ Rune r[256];
int ri;
int wi;
int stall;
@@ -29,7 +29,7 @@ struct Kbdbuf
struct Mousebuf
{
- Mouse m[32];
+ Mouse m[256];
Mouse last;
int ri;
int wi;
@@ -38,7 +38,7 @@ struct Mousebuf
struct Tagbuf
{
- int t[32];
+ int t[256];
int ri;
int wi;
};
@@ -97,7 +97,7 @@ servep9p(void)
/* pick off messages one by one */
if(convM2W(mbuf, nn+4, &m) <= 0)
sysfatal("cannot convert message");
- if(trace) fprint(2, "<- %W\n", &m);
+ if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
runmsg(&m);
}
}
@@ -191,6 +191,7 @@ runmsg(Wsysmsg *m)
break;
case Trddraw:
+ zlock();
n = m->count;
if(n > sizeof buf)
n = sizeof buf;
@@ -202,13 +203,16 @@ runmsg(Wsysmsg *m)
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:
@@ -217,7 +221,9 @@ runmsg(Wsysmsg *m)
break;
case Tresize:
- // _xresizewindow(m->rect);
+#if OSX_VERSION >= 101400
+ resizewindow(m->rect);
+#endif
replymsg(m);
break;
}
@@ -238,7 +244,7 @@ replymsg(Wsysmsg *m)
if(m->type%2 == 0)
m->type++;
- if(trace) fprint(2, "-> %W\n", m);
+ if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
/* copy to output buffer */
n = sizeW2M(m);
@@ -293,11 +299,11 @@ matchmouse(void)
mousetags.ri = 0;
m.mouse = mouse.m[mouse.ri];
m.resized = mouseresized;
+ mouseresized = 0;
/*
if(m.resized)
fprint(2, "sending resize\n");
*/
- mouseresized = 0;
mouse.ri++;
if(mouse.ri == nelem(mouse.m))
mouse.ri = 0;
@@ -367,8 +373,6 @@ abortcompose(void)
keystroke(Kalt);
}
-void resizeimg(void);
-
void
keystroke(int c)
{
diff --git a/src/cmd/devdraw/cocoa-thread.c b/src/cmd/devdraw/cocoa-thread.c
index c9b280f7..92b92d2c 100644
--- a/src/cmd/devdraw/cocoa-thread.c
+++ b/src/cmd/devdraw/cocoa-thread.c
@@ -25,4 +25,11 @@ qunlock(QLock *q)
{
pthread_mutex_unlock(&q->m);
}
+
+int
+threadid(void)
+{
+ return pthread_mach_thread_np(pthread_self());
+}
+
#endif
diff --git a/src/cmd/devdraw/cocoa-thread.h b/src/cmd/devdraw/cocoa-thread.h
index c2f3e982..d5793f0a 100644
--- a/src/cmd/devdraw/cocoa-thread.h
+++ b/src/cmd/devdraw/cocoa-thread.h
@@ -30,4 +30,5 @@
void qlock(QLock*);
void qunlock(QLock*);
+ int threadid(void);
#endif
diff --git a/src/cmd/devdraw/mkfile b/src/cmd/devdraw/mkfile
index cad244ac..2e40087e 100644
--- a/src/cmd/devdraw/mkfile
+++ b/src/cmd/devdraw/mkfile
@@ -35,6 +35,9 @@ latin1.h: $PLAN9/lib/keyboard $O.mklatinkbd
$O.macargv: $MACARGV
$LD -o $target $prereq
+cocoa-screen-metal-objc.$O: cocoa-screen-metal.m
+ $CC $CFLAGS $OBJCFLAGS -o $target cocoa-screen-metal.m
+
%-objc.$O: %.m
$CC $CFLAGS -o $target $stem.m
diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh
index 9c422261..98d6799d 100644
--- a/src/cmd/devdraw/mkwsysrules.sh
+++ b/src/cmd/devdraw/mkwsysrules.sh
@@ -60,7 +60,12 @@ elif [ $WSYSTYPE = osx ]; then
echo 'WSYSOFILES=$WSYSOFILES osx-screen-carbon-objc.o osx-draw.o osx-srv.o'
echo 'MACARGV=macargv.o'
elif [ $WSYSTYPE = osx-cocoa ]; then
- echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen-objc.o cocoa-srv.o cocoa-thread.o'
+ if sw_vers|awk '/ProductVersion/{split($2,a,".");exit(a[2]<14)}' >/dev/null; then # 0 is true in sh.
+ echo 'OBJCFLAGS=$OBJCFLAGS -fobjc-arc'
+ echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen-metal-objc.o cocoa-srv.o cocoa-thread.o'
+ else
+ echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen-objc.o cocoa-srv.o cocoa-thread.o'
+ fi
echo 'MACARGV=macargv-objc.o'
elif [ $WSYSTYPE = nowsys ]; then
echo 'WSYSOFILES=nowsys.o'