devdraw: more cleanup, clearer locking

This commit is contained in:
Russ Cox 2020-01-10 00:11:55 -05:00
parent b1a086dee9
commit 41547af3f6
8 changed files with 331 additions and 315 deletions

View file

@ -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)
{
USED(v);
servep9p(client0);
void
rpc_shutdown(void)
{
[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