diff options
Diffstat (limited to 'src/cmd/devdraw/mac-screen.m')
-rw-r--r-- | src/cmd/devdraw/mac-screen.m | 271 |
1 files changed, 105 insertions, 166 deletions
diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m index d756d3d7..2ce6bb34 100644 --- a/src/cmd/devdraw/mac-screen.m +++ b/src/cmd/devdraw/mac-screen.m @@ -34,13 +34,6 @@ static void setprocname(const char*); static uint keycvt(uint); static uint msec(void); -void -usage(void) -{ - fprint(2, "usage: devdraw (don't run directly)\n"); - threadexitsall("usage"); -} - @class DrawView; @class DrawLayer; @@ -49,43 +42,9 @@ usage(void) static AppDelegate *myApp = NULL; - -static QLock snarfl; - void -threadmain(int argc, char **argv) +gfx_main(void) { - /* - * 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 - - client0 = mallocz(sizeof(Client), 1); - if(client0 == nil){ - fprint(2, "initdraw: allocating client0: out of memory"); - abort(); - } - client0->displaydpi = 100; - client0->rfd = 3; - client0->wfd = 4; - setprocname(argv0); @autoreleasepool{ @@ -97,12 +56,10 @@ threadmain(int argc, char **argv) } } + void -callservep9p(void *v) +rpc_shutdown(void) { - USED(v); - - servep9p(client0); [NSApp terminate:myApp]; } @@ -128,8 +85,8 @@ callservep9p(void *v) i = [[NSImage alloc] initWithData:d]; [NSApp setApplicationIconImage:i]; [[NSApp dockTile] display]; - - proccreate(callservep9p, nil, 0); + + gfx_started(); } - (NSApplicationPresentationOptions)window:(id)arg @@ -242,10 +199,10 @@ callservep9p(void *v) - (BOOL)isFlipped { return YES; } - (BOOL)acceptsFirstResponder { return YES; } -// rpc_attachscreen allocates a new screen window with the given label and size +// rpc_attach allocates a new screen window with the given label and size // and attaches it to client c (by setting c->view). Memimage* -rpc_attachscreen(Client *c, char *label, char *winsize) +rpc_attach(Client *c, char *label, char *winsize) { LOG(@"attachscreen(%s, %s)", label, winsize); @@ -468,71 +425,73 @@ rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2) } - (void)initimg { -@autoreleasepool{ - CGFloat scale; - NSSize size; - MTLTextureDescriptor *textureDesc; - - size = [self convertSizeToBacking:[self bounds].size]; - self.client->mouserect = Rect(0, 0, size.width, size.height); - - LOG(@"initimg %.0f %.0f", size.width, size.height); - - self.img = allocmemimage(self.client->mouserect, XRGB32); - if(self.img == nil) - panic("allocmemimage: %r"); - if(self.img->data == nil) - panic("img->data == nil"); - - textureDesc = [MTLTextureDescriptor - texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm - width:size.width - height:size.height - mipmapped:NO]; - textureDesc.allowGPUOptimizedContents = YES; - textureDesc.usage = MTLTextureUsageShaderRead; - textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined; - self.dlayer.texture = [self.dlayer.device newTextureWithDescriptor:textureDesc]; - - scale = [self.win backingScaleFactor]; - [self.dlayer setDrawableSize:size]; - [self.dlayer setContentsScale:scale]; - - // NOTE: This is not really the display DPI. - // On retina, scale is 2; otherwise it is 1. - // This formula gives us 220 for retina, 110 otherwise. - // That's not quite right but it's close to correct. - // https://en.wikipedia.org/wiki/Retina_display#Models - self.client->displaydpi = scale * 110; -} - LOG(@"initimg return"); + @autoreleasepool { + CGFloat scale; + NSSize size; + MTLTextureDescriptor *textureDesc; + + size = [self convertSizeToBacking:[self bounds].size]; + self.client->mouserect = Rect(0, 0, size.width, size.height); + + LOG(@"initimg %.0f %.0f", size.width, size.height); + + self.img = allocmemimage(self.client->mouserect, XRGB32); + if(self.img == nil) + panic("allocmemimage: %r"); + if(self.img->data == nil) + panic("img->data == nil"); + + textureDesc = [MTLTextureDescriptor + texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm + width:size.width + height:size.height + mipmapped:NO]; + textureDesc.allowGPUOptimizedContents = YES; + textureDesc.usage = MTLTextureUsageShaderRead; + textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined; + self.dlayer.texture = [self.dlayer.device newTextureWithDescriptor:textureDesc]; + + scale = [self.win backingScaleFactor]; + [self.dlayer setDrawableSize:size]; + [self.dlayer setContentsScale:scale]; + + // NOTE: This is not really the display DPI. + // On retina, scale is 2; otherwise it is 1. + // This formula gives us 220 for retina, 110 otherwise. + // That's not quite right but it's close to correct. + // https://en.wikipedia.org/wiki/Retina_display#Models + self.client->displaydpi = scale * 110; + } } -// rpc_flushmemscreen flushes changes to view.img's rectangle r +// rpc_flush flushes changes to view.img's rectangle r // to the on-screen window, making them visible. // Called from an RPC thread with no client lock held. void -rpc_flushmemscreen(Client *client, Rectangle r) +rpc_flush(Client *client, Rectangle r) { DrawView *view = (__bridge DrawView*)client->view; dispatch_async(dispatch_get_main_queue(), ^(void){ - [view flushmemscreen:r]; + [view flush:r]; }); } -- (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, self.dlayer.texture.width, self.dlayer.texture.height))){ - LOG(@"Rectangle is out of bounds, return."); - return; - } - +- (void)flush:(Rectangle)r { @autoreleasepool{ + if(!rectclip(&r, Rect(0, 0, self.dlayer.texture.width, self.dlayer.texture.height)) || !rectclip(&r, self.img->r)) + return; + + // self.client->drawlk protects the pixel data in self.img. + // In addition to avoiding a technical data race, + // the lock avoids drawing partial updates, which makes + // animations like sweeping windows much less flickery. + qlock(&self.client->drawlk); [self.dlayer.texture replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r)) mipmapLevel:0 withBytes:byteaddr(self.img, Pt(r.min.x, r.min.y)) bytesPerRow:self.img->width*sizeof(u32int)]; + qunlock(&self.client->drawlk); NSRect nr = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r)); dispatch_time_t time; @@ -565,7 +524,7 @@ rpc_resizeimg(Client *c) - (void)resizeimg { [self initimg]; - _drawreplacescreenimage(self.client, self.img); + gfx_replacescreenimage(self.client, self.img); [self sendmouse:0]; } @@ -750,7 +709,7 @@ rpc_setmouse(Client *c, Point p) }); } --(void)setmouse:(Point)p { +- (void)setmouse:(Point)p { @autoreleasepool{ NSPoint q; @@ -782,21 +741,10 @@ rpc_setmouse(Client *c, Point p) } // conforms to protocol NSTextInputClient -- (BOOL)hasMarkedText -{ - LOG(@"hasMarkedText"); - return _markedRange.location != NSNotFound; -} -- (NSRange)markedRange -{ - LOG(@"markedRange"); - return _markedRange; -} -- (NSRange)selectedRange -{ - LOG(@"selectedRange"); - return _selectedRange; -} +- (BOOL)hasMarkedText { return _markedRange.location != NSNotFound; } +- (NSRange)markedRange { return _markedRange; } +- (NSRange)selectedRange { return _selectedRange; } + - (void)setMarkedText:(id)string selectedRange:(NSRange)sRange replacementRange:(NSRange)rRange @@ -861,8 +809,8 @@ rpc_setmouse(Client *c, Point p) _markedRange.location, _markedRange.length, _selectedRange.location, _selectedRange.length); } -- (void)unmarkText -{ + +- (void)unmarkText { //NSUInteger i; NSUInteger len; @@ -874,12 +822,13 @@ rpc_setmouse(Client *c, Point p) _markedRange = NSMakeRange(NSNotFound, 0); _selectedRange = NSMakeRange(0, 0); } -- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText -{ + +- (NSArray<NSAttributedStringKey>*)validAttributesForMarkedText { LOG(@"validAttributesForMarkedText"); return @[]; } -- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r + +- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)r actualRange:(NSRangePointer)actualRange { NSRange sr; @@ -899,9 +848,8 @@ rpc_setmouse(Client *c, Point p) LOG(@" return %@", s); return s; } -- (void)insertText:(id)s - replacementRange:(NSRange)r -{ + +- (void)insertText:(id)s replacementRange:(NSRange)r { NSUInteger i; NSUInteger len; @@ -916,22 +864,22 @@ rpc_setmouse(Client *c, Point p) _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 -{ + +- (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 -{ + +- (void)doCommandBySelector:(SEL)s { NSEvent *e; NSEventModifierFlags m; uint c, k; @@ -955,8 +903,7 @@ rpc_setmouse(Client *c, Point p) } // Helper for managing input rect approximately -- (void)resetLastInputRect -{ +- (void)resetLastInputRect { LOG(@"resetLastInputRect"); _lastInputRect.origin.x = 0.0; _lastInputRect.origin.y = 0.0; @@ -964,8 +911,7 @@ rpc_setmouse(Client *c, Point p) _lastInputRect.size.height = 0.0; } -- (void)enlargeLastInputRect:(NSRect)r -{ +- (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)", @@ -973,8 +919,7 @@ rpc_setmouse(Client *c, Point p) _lastInputRect.size.width, _lastInputRect.size.height); } -- (void)clearInput -{ +- (void)clearInput { if(_tmpText.length){ uint i; int l; @@ -1079,48 +1024,42 @@ keycvt(uint code) } } -// TODO +// rpc_getsnarf reads the current pasteboard as a plain text string. +// Called from an RPC thread with no client lock held. char* rpc_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; - } + char __block *ret; + + ret = nil; + dispatch_sync(dispatch_get_main_queue(), ^(void) { + @autoreleasepool { + NSPasteboard *pb = [NSPasteboard generalPasteboard]; + NSString *s = [pb stringForType:NSPasteboardTypeString]; + if(s) + ret = strdup((char*)[s UTF8String]); + } + }); + return ret; } -// TODO +// rpc_putsnarf writes the given text to the pasteboard. +// Called from an RPC thread with no client lock held. void rpc_putsnarf(char *s) { - NSArray *t; - NSPasteboard *pb; - NSString *str; - - if(strlen(s) >= SnarfSize) + if(s == nil || 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); - } + dispatch_sync(dispatch_get_main_queue(), ^(void) { + @autoreleasepool{ + NSArray *t = [NSArray arrayWithObject:NSPasteboardTypeString]; + NSPasteboard *pb = [NSPasteboard generalPasteboard]; + NSString *str = [[NSString alloc] initWithUTF8String:s]; + [pb declareTypes:t owner:nil]; + [pb setString:str forType:NSPasteboardTypeString]; + } + }); } static void |