diff options
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/devdraw/bigarrow.h | 22 | ||||
-rw-r--r-- | src/cmd/devdraw/cocoa-screen-metal.m | 1260 | ||||
-rw-r--r-- | src/cmd/devdraw/cocoa-screen.h | 6 | ||||
-rw-r--r-- | src/cmd/devdraw/cocoa-srv.c | 22 | ||||
-rw-r--r-- | src/cmd/devdraw/cocoa-thread.c | 7 | ||||
-rw-r--r-- | src/cmd/devdraw/cocoa-thread.h | 1 | ||||
-rw-r--r-- | src/cmd/devdraw/mkfile | 3 | ||||
-rw-r--r-- | src/cmd/devdraw/mkwsysrules.sh | 7 |
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' |