diff options
author | Russ Cox <rsc@swtch.com> | 2020-01-09 21:47:14 -0500 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2020-01-13 16:46:14 -0500 |
commit | b1a086dee9bf5846b31323ba2c438f8853a9c87f (patch) | |
tree | 4f937160d21a46e73cddaf53ab8356b3aa56ae09 /src | |
parent | 843e5af1986a2e8f1c4f6177dc4509501711a22c (diff) | |
download | plan9port-b1a086dee9bf5846b31323ba2c438f8853a9c87f.tar.gz plan9port-b1a086dee9bf5846b31323ba2c438f8853a9c87f.tar.bz2 plan9port-b1a086dee9bf5846b31323ba2c438f8853a9c87f.zip |
devdraw: refactor, clean up mac screen
Also turn mac-srv.c into a generic srv.c,
so we can remove the duplication with x11-srv.c.
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/devdraw/devdraw.c | 8 | ||||
-rw-r--r-- | src/cmd/devdraw/devdraw.h | 22 | ||||
-rw-r--r-- | src/cmd/devdraw/mac-screen.h | 19 | ||||
-rw-r--r-- | src/cmd/devdraw/mac-screen.m | 827 | ||||
-rw-r--r-- | src/cmd/devdraw/mkfile | 3 | ||||
-rw-r--r-- | src/cmd/devdraw/mkwsysrules.sh | 4 | ||||
-rw-r--r-- | src/cmd/devdraw/srv.c (renamed from src/cmd/devdraw/mac-srv.c) | 114 |
7 files changed, 492 insertions, 505 deletions
diff --git a/src/cmd/devdraw/devdraw.c b/src/cmd/devdraw/devdraw.c index e83f6f07..77a3f44a 100644 --- a/src/cmd/devdraw/devdraw.c +++ b/src/cmd/devdraw/devdraw.c @@ -14,8 +14,6 @@ #include <drawfcall.h> #include "devdraw.h" -extern void _flushmemscreen(Rectangle); - static Draw sdraw; Client *client0; static int drawuninstall(Client*, int); @@ -32,6 +30,8 @@ _initdisplaymemimage(Client *c, Memimage *m) c->op = SoverD; } +// _drawreplacescreen replaces c's screen image with m. +// It is called by the host driver on the main host thread. void _drawreplacescreenimage(Client *c, Memimage *m) { @@ -141,7 +141,7 @@ addflush(Client *c, Rectangle r) } /* emit current state */ if(c->flushrect.min.x < c->flushrect.max.x) - _flushmemscreen(c->flushrect); + rpc_flushmemscreen(c, c->flushrect); c->flushrect = r; c->waste = 0; } @@ -178,7 +178,7 @@ void drawflush(Client *c) { if(c->flushrect.min.x < c->flushrect.max.x) - _flushmemscreen(c->flushrect); + rpc_flushmemscreen(c, c->flushrect); c->flushrect = Rect(10000, 10000, -10000, -10000); } diff --git a/src/cmd/devdraw/devdraw.h b/src/cmd/devdraw/devdraw.h index fe9532b3..30586228 100644 --- a/src/cmd/devdraw/devdraw.h +++ b/src/cmd/devdraw/devdraw.h @@ -28,6 +28,8 @@ struct Kbdbuf int wi; int stall; int alting; + Rune k[10]; + int nk; }; struct Mousebuf @@ -75,7 +77,7 @@ struct Client int rfd; int wfd; - void* view; + const void* view; QLock inputlk; Kbdbuf kbd; @@ -163,6 +165,22 @@ void _drawreplacescreenimage(Client*, Memimage*); int _latin1(Rune*, int); int parsewinsize(char*, Rectangle*, int*); int mouseswap(int); -void abortcompose(Client*); + +void gfx_abortcompose(Client*); +void gfx_keystroke(Client*, int); +void gfx_mousetrack(Client*, int, int, int, uint); + +void rpc_setmouse(Client*, Point); +void rpc_setcursor(Client*, Cursor*, Cursor2*); +void rpc_setlabel(Client*, char*); +void rpc_resizeimg(Client*); +void rpc_resizewindow(Client*, Rectangle); +void rpc_topwin(Client*); +char* rpc_getsnarf(void); +void rpc_putsnarf(char*); +Memimage *rpc_attachscreen(Client*, char*, char*); +void rpc_flushmemscreen(Client*, Rectangle); extern Client *client0; + +void servep9p(Client*); diff --git a/src/cmd/devdraw/mac-screen.h b/src/cmd/devdraw/mac-screen.h deleted file mode 100644 index 7bc0920d..00000000 --- a/src/cmd/devdraw/mac-screen.h +++ /dev/null @@ -1,19 +0,0 @@ -#define setcursor dsetcursor - -Memimage *attachscreen(Client*, char*, char*); -void setmouse(Point); -void setcursor(Cursor*, Cursor2*); -void setlabel(char*); -char* getsnarf(void); -void putsnarf(char*); -void topwin(void); - -void mousetrack(Client*, int, int, int, uint); -void keystroke(Client*, int); -void kicklabel(char*); - -void servep9p(Client*); - -void resizeimg(Client*); - -void resizewindow(Rectangle); diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m index 8ce8a0cd..d756d3d7 100644 --- a/src/cmd/devdraw/mac-screen.m +++ b/src/cmd/devdraw/mac-screen.m @@ -21,7 +21,6 @@ #include <keyboard.h> #include <drawfcall.h> #include "devdraw.h" -#include "mac-screen.h" #include "bigarrow.h" #include "glendapng.h" @@ -34,7 +33,6 @@ AUTOFRAMEWORK(QuartzCore) static void setprocname(const char*); static uint keycvt(uint); static uint msec(void); -static Memimage* initimg(Client*); void usage(void) @@ -43,34 +41,14 @@ usage(void) threadexitsall("usage"); } -@interface DrawLayer : CAMetalLayer -@end -@interface AppDelegate : NSObject<NSApplicationDelegate> -+ (void)makewin:(NSValue *)v; -+ (void)callkicklabel:(NSString *)v; -+ (void)callsetNeedsDisplayInRect:(NSValue *)v; -+ (void)callsetcursor:(NSValue *)v; -@end - -@interface DevDrawView : NSView<NSTextInputClient,NSWindowDelegate> -@property (nonatomic, assign) Client *client; -@property (nonatomic, assign) DrawLayer *dlayer; -@property (nonatomic, assign) NSWindow *win; -@property (nonatomic, assign) NSCursor *currentCursor; -@property (nonatomic, assign) Memimage *img; +@class DrawView; +@class DrawLayer; -- (void)clearInput; -- (void)getmouse:(NSEvent *)e; -- (void)sendmouse:(NSUInteger)b; -- (void)resetLastInputRect; -- (void)enlargeLastInputRect:(NSRect)r; +@interface AppDelegate : NSObject<NSApplicationDelegate> @end static AppDelegate *myApp = NULL; -static id<MTLDevice> device; -static id<MTLCommandQueue> commandQueue; -static id<MTLTexture> texture; static QLock snarfl; @@ -100,11 +78,13 @@ threadmain(int argc, char **argv) }ARGEND client0 = mallocz(sizeof(Client), 1); - client0->displaydpi = 100; if(client0 == nil){ fprint(2, "initdraw: allocating client0: out of memory"); abort(); } + client0->displaydpi = 100; + client0->rfd = 3; + client0->wfd = 4; setprocname(argv0); @@ -117,22 +97,168 @@ threadmain(int argc, char **argv) } } - void callservep9p(void *v) { USED(v); - client0->rfd = 3; - client0->wfd = 4; servep9p(client0); [NSApp terminate:myApp]; } @implementation AppDelegate +- (void)applicationDidFinishLaunching:(id)arg +{ + NSMenu *m, *sm; + NSData *d; + NSImage *i; -+ (void)makewin:(NSValue *)v + LOG(@"applicationDidFinishLaunching"); + + sm = [NSMenu new]; + [sm addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"]; + [sm addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"]; + [sm addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"]; + m = [NSMenu new]; + [m addItemWithTitle:@"DEVDRAW" action:NULL keyEquivalent:@""]; + [m setSubmenu:sm forItem:[m itemWithTitle:@"DEVDRAW"]]; + [NSApp setMainMenu:m]; + + d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)]; + i = [[NSImage alloc] initWithData:d]; + [NSApp setApplicationIconImage:i]; + [[NSApp dockTile] display]; + + proccreate(callservep9p, nil, 0); +} + +- (NSApplicationPresentationOptions)window:(id)arg + willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions { + NSApplicationPresentationOptions o; + o = proposedOptions; + o &= ~(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar); + o |= NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar; + return o; +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication { + return YES; +} +@end + +@interface DrawLayer : CAMetalLayer +@property (nonatomic, retain) id<MTLCommandQueue> cmd; +@property (nonatomic, retain) id<MTLTexture> texture; +@end + +@implementation DrawLayer +- (void)display +{ + LOG(@"display"); + LOG(@"display query drawable"); + + @autoreleasepool{ + id<CAMetalDrawable> drawable = [self nextDrawable]; + if(!drawable){ + LOG(@"display couldn't get drawable"); + [self setNeedsDisplay]; + return; + } + + LOG(@"display got drawable"); + + id<MTLCommandBuffer> cbuf = [self.cmd commandBuffer]; + id<MTLBlitCommandEncoder> blit = [cbuf blitCommandEncoder]; + [blit copyFromTexture:self.texture + sourceSlice:0 + sourceLevel:0 + sourceOrigin:MTLOriginMake(0, 0, 0) + sourceSize:MTLSizeMake(self.texture.width, self.texture.height, self.texture.depth) + toTexture:drawable.texture + destinationSlice:0 + destinationLevel:0 + destinationOrigin:MTLOriginMake(0, 0, 0)]; + [blit endEncoding]; + + [cbuf presentDrawable:drawable]; + drawable = nil; + [cbuf addCompletedHandler:^(id<MTLCommandBuffer> cmdBuff){ + if(cmdBuff.error){ + NSLog(@"command buffer finished with error: %@", + cmdBuff.error.localizedDescription); + }else + LOG(@"command buffer finishes present drawable"); + }]; + [cbuf commit]; + } + LOG(@"display commit"); +} +@end + +@interface DrawView : NSView<NSTextInputClient,NSWindowDelegate> +@property (nonatomic, assign) Client *client; +@property (nonatomic, retain) DrawLayer *dlayer; +@property (nonatomic, retain) NSWindow *win; +@property (nonatomic, retain) NSCursor *currentCursor; +@property (nonatomic, assign) Memimage *img; + +- (id)attach:(Client*)client winsize:(char*)winsize label:(char*)label; +- (void)topwin; +- (void)setlabel:(char*)label; +- (void)setcursor:(Cursor*)c cursor2:(Cursor2*)c2; +- (void)setmouse:(Point)p; +- (void)clearInput; +- (void)getmouse:(NSEvent*)e; +- (void)sendmouse:(NSUInteger)b; +- (void)resetLastInputRect; +- (void)enlargeLastInputRect:(NSRect)r; +@end + +@implementation DrawView +{ + 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 { return [DrawLayer layer]; } +- (BOOL)wantsUpdateLayer { return YES; } +- (BOOL)isOpaque { return YES; } +- (BOOL)isFlipped { return YES; } +- (BOOL)acceptsFirstResponder { return YES; } + +// rpc_attachscreen 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) +{ + LOG(@"attachscreen(%s, %s)", label, winsize); + + dispatch_sync(dispatch_get_main_queue(), ^(void) { + @autoreleasepool { + DrawView *view = [[DrawView new] attach:c winsize:winsize label:label]; + [view initimg]; + } + }); + return ((__bridge DrawView*)c->view).img; +} + +- (id)attach:(Client*)client winsize:(char*)winsize label:(char*)label { NSRect r, sr; Rectangle wr; int set; @@ -144,10 +270,10 @@ callservep9p(void *v) | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; + s = winsize; sr = [[NSScreen mainScreen] frame]; r = [[NSScreen mainScreen] visibleFrame]; - s = [v pointerValue]; LOG(@"makewin(%s)", s); if(s && *s){ if(parsewinsize(s, &wr, &set) < 0) @@ -177,17 +303,16 @@ callservep9p(void *v) [win setRestorable:NO]; [win setAcceptsMouseMovedEvents:YES]; - DevDrawView *view = [DevDrawView new]; - client0->view = view; - view.client = client0; - view.win = win; - view.currentCursor = nil; - [win setContentView:view]; - [win setDelegate:view]; - [view setWantsLayer:YES]; - [view setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay]; + client->view = CFBridgingRetain(self); + self.client = client; + self.win = win; + self.currentCursor = nil; + [win setContentView:self]; + [win setDelegate:self]; + [self setWantsLayer:YES]; + [self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay]; - device = nil; + id<MTLDevice> device = nil; allDevices = MTLCopyAllDevices(); for(id mtlDevice in allDevices) { if ([mtlDevice isLowPower] && ![mtlDevice isRemovable]) { @@ -198,18 +323,19 @@ callservep9p(void *v) if(!device) device = MTLCreateSystemDefaultDevice(); - commandQueue = [device newCommandQueue]; - - DrawLayer *layer = (DrawLayer *)[view layer]; - view.dlayer = layer; + DrawLayer *layer = (DrawLayer*)[self layer]; + self.dlayer = layer; layer.device = device; + layer.cmd = [device newCommandQueue]; layer.pixelFormat = MTLPixelFormatBGRA8Unorm; layer.framebufferOnly = YES; layer.opaque = YES; // We use a default transparent layer on top of the CAMetalLayer. // This seems to make fullscreen applications behave. - { + // Specifically, without this code if you enter full screen with Cmd-F, + // the screen goes black until the first mouse click. + if(1) { CALayer *stub = [CALayer layer]; stub.frame = CGRectMake(0, 0, 1, 1); [stub setNeedsDisplay]; @@ -218,64 +344,76 @@ callservep9p(void *v) [NSEvent setMouseCoalescingEnabled:NO]; - topwin(); + [self topwin]; + [self setlabel:label]; + [self setcursor:nil cursor2:nil]; + + return self; } -+ (void)callkicklabel:(NSString *)s +// rpc_topwin moves the window to the top of the desktop. +// Called from an RPC thread with no client lock held. +void +rpc_topwin(Client *c) { - DevDrawView *view = client0->view; - - LOG(@"callkicklabel(%@)", s); - [view.win setTitle:s]; - [[NSApp dockTile] setBadgeLabel:s]; + DrawView *view = (__bridge DrawView*)c->view; + dispatch_sync(dispatch_get_main_queue(), ^(void) { + [view topwin]; + }); } +- (void)topwin { + [self.win makeKeyAndOrderFront:nil]; + [NSApp activateIgnoringOtherApps:YES]; +} -+ (void)callsetNeedsDisplayInRect:(NSValue *)v +// rpc_setlabel updates the client window's label. +// If label == nil, the call is a no-op. +// Called from an RPC thread with no client lock held. +void +rpc_setlabel(Client *client, char *label) { - NSRect r; - dispatch_time_t time; - DevDrawView *view = client0->view; - - r = [v rectValue]; - LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height); - r = [view.win convertRectFromBacking:r]; - LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height); - [view.dlayer setNeedsDisplayInRect:r]; - - time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC); - dispatch_after(time, dispatch_get_main_queue(), ^(void){ - [view.dlayer setNeedsDisplayInRect:r]; + DrawView *view = (__bridge DrawView*)client->view; + dispatch_sync(dispatch_get_main_queue(), ^(void){ + [view setlabel:label]; }); - - [view enlargeLastInputRect:r]; } -typedef struct Cursors Cursors; -struct Cursors { - Cursor *c; - Cursor2 *c2; -}; +- (void)setlabel:(char*)label { + LOG(@"setlabel(%s)", label); + if(label == nil) + return; + + @autoreleasepool{ + NSString *s = [[NSString alloc] initWithUTF8String:label]; + [self.win setTitle:s]; + [[NSApp dockTile] setBadgeLabel:s]; // TODO: Not with multiple windows + } +} -+ (void)callsetcursor:(NSValue *)v +// rpc_setcursor updates the client window's cursor image. +// Either c and c2 are both non-nil, or they are both nil to use the default arrow. +// Called from an RPC thread with no client lock held. +void +rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2) { - Cursors *cs; - Cursor *c; - Cursor2 *c2; + DrawView *view = (__bridge DrawView*)client->view; + dispatch_sync(dispatch_get_main_queue(), ^(void){ + [view setcursor:c cursor2:c2]; + }); +} + +- (void)setcursor:(Cursor*)c cursor2:(Cursor2*)c2 { + if(!c) { + c = &bigarrow; + c2 = &bigarrow2; + } + NSBitmapImageRep *r, *r2; NSImage *i; NSPoint p; uchar *plane[5], *plane2[5]; uint b; - DevDrawView *view = client0->view; - - cs = [v pointerValue]; - c = cs->c; - if(!c) - c = &bigarrow; - c2 = cs->c2; - if(!c2) - c2 = &bigarrow2; r = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil @@ -311,125 +449,164 @@ struct Cursors { plane2[1][b] = c2->set[b] | c2->clr[b]; } - // For checking out the cursor bitmap image -/* - static BOOL saveimg = YES; - if(saveimg){ + static BOOL debug = NO; + if(debug){ 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; + debug = NO; } -*/ i = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]; [i addRepresentation:r2]; [i addRepresentation:r]; p = NSMakePoint(-c->offset.x, -c->offset.y); - view.currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p]; - - [view.win invalidateCursorRectsForView:view]; + self.currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p]; + [self.win invalidateCursorRectsForView:self]; } -- (void)applicationDidFinishLaunching:(id)arg -{ - NSMenu *m, *sm; - NSData *d; - NSImage *i; +- (void)initimg { +@autoreleasepool{ + CGFloat scale; + NSSize size; + MTLTextureDescriptor *textureDesc; - LOG(@"applicationDidFinishLaunching"); + size = [self convertSizeToBacking:[self bounds].size]; + self.client->mouserect = Rect(0, 0, size.width, size.height); - 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]; + LOG(@"initimg %.0f %.0f", size.width, size.height); - d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)]; - i = [[NSImage alloc] initWithData:d]; - [NSApp setApplicationIconImage:i]; - [[NSApp dockTile] display]; + self.img = allocmemimage(self.client->mouserect, XRGB32); + if(self.img == nil) + panic("allocmemimage: %r"); + if(self.img->data == nil) + panic("img->data == nil"); - proccreate(callservep9p, nil, 0); -} + 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]; -- (NSApplicationPresentationOptions)window:(id)arg - willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions { - NSApplicationPresentationOptions o; - o = proposedOptions; - o &= ~(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar); - o |= NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar; - return o; -} + scale = [self.win backingScaleFactor]; + [self.dlayer setDrawableSize:size]; + [self.dlayer setContentsScale:scale]; -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication { - return YES; + // 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; } -@end - -@implementation DevDrawView -{ - NSMutableString *_tmpText; - NSRange _markedRange; - NSRange _selectedRange; - NSRect _lastInputRect; // The view is flipped, this is not. - BOOL _tapping; - NSUInteger _tapFingers; - NSUInteger _tapTime; + LOG(@"initimg return"); } -- (id)init +// rpc_flushmemscreen 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) { - 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; + DrawView *view = (__bridge DrawView*)client->view; + dispatch_async(dispatch_get_main_queue(), ^(void){ + [view flushmemscreen:r]; + }); } -- (void)windowDidResize:(NSNotification *)notification -{ - if(![self inLiveResize] && self.img) { - resizeimg(self.client); +- (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; + } + + @autoreleasepool{ + [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)]; + + NSRect nr = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r)); + dispatch_time_t time; + + LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", nr.origin.x, nr.origin.y, nr.size.width, nr.size.height); + nr = [self.win convertRectFromBacking:nr]; + LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", nr.origin.x, nr.origin.y, nr.size.width, nr.size.height); + [self.dlayer setNeedsDisplayInRect:nr]; + + time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC); + dispatch_after(time, dispatch_get_main_queue(), ^(void){ + [self.dlayer setNeedsDisplayInRect:nr]; + }); + + [self enlargeLastInputRect:nr]; } } -- (void)windowDidBecomeKey:(id)arg +// rpc_resizeimg forces the client window to discard its current window and make a new one. +// It is called when the user types Cmd-R to toggle whether retina mode is forced. +// Called from an RPC thread with no client lock held. +void +rpc_resizeimg(Client *c) { - [self sendmouse:0]; + DrawView *view = (__bridge DrawView*)c->view; + dispatch_sync(dispatch_get_main_queue(), ^(void){ + [view resizeimg]; + }); } -- (CALayer *)makeBackingLayer -{ - LOG(@"makeBackingLayer"); - return [DrawLayer layer]; +- (void)resizeimg { + [self initimg]; + _drawreplacescreenimage(self.client, self.img); + [self sendmouse:0]; } -- (BOOL)wantsUpdateLayer +- (void)windowDidResize:(NSNotification *)notification { + if(![self inLiveResize] && self.img) { + [self resizeimg]; + } +} +- (void)viewDidEndLiveResize { - return YES; + [super viewDidEndLiveResize]; + if(self.img) + [self resizeimg]; } -- (BOOL)isOpaque +- (void)viewDidChangeBackingProperties { - return YES; + [super viewDidChangeBackingProperties]; + if(self.img) + [self resizeimg]; } -- (BOOL)isFlipped +// rpc_resizewindow asks for the client window to be resized to size r. +// Called from an RPC thread with no client lock held. +void +rpc_resizewindow(Client *c, Rectangle r) { - return YES; + DrawView *view = (__bridge DrawView*)c->view; + + 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 = [view convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))]; + [view.win setContentSize:s]; + }); } -- (BOOL)acceptsFirstResponder -{ - return YES; + +- (void)windowDidBecomeKey:(id)arg { + [self sendmouse:0]; } - (void)mouseMoved:(NSEvent*)e{ [self getmouse:e];} @@ -483,7 +660,7 @@ struct Cursors { b |= 4; [self sendmouse:b]; }else if(m & ~omod & NSEventModifierFlagOption) - keystroke(self.client, Kalt); + gfx_keystroke(self.client, Kalt); omod = m; } @@ -540,7 +717,7 @@ struct Cursors { if(b == 1){ m = [e modifierFlags]; if(m & NSEventModifierFlagOption){ - abortcompose(self.client); + gfx_abortcompose(self.client); b = 2; }else if(m & NSEventModifierFlagCommand) @@ -557,28 +734,51 @@ struct Cursors { [self.window mouseLocationOutsideOfEventStream]]; p.y = Dy(self.client->mouserect) - p.y; // LOG(@"(%g, %g) <- sendmouse(%d)", p.x, p.y, (uint)b); - mousetrack(self.client, p.x, p.y, b, msec()); + gfx_mousetrack(self.client, 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:self.currentCursor]; +// rpc_setmouse moves the mouse cursor. +// Called from an RPC thread with no client lock held. +void +rpc_setmouse(Client *c, Point p) +{ + DrawView *view = (__bridge DrawView*)c->view; + dispatch_async(dispatch_get_main_queue(), ^(void){ + [view setmouse:p]; + }); } -- (void)viewDidEndLiveResize -{ - [super viewDidEndLiveResize]; - if(self.img) - resizeimg(self.client); +-(void)setmouse:(Point)p { + @autoreleasepool{ + NSPoint q; + + LOG(@"setmouse(%d,%d)", p.x, p.y); + q = [self.win convertPointFromBacking:NSMakePoint(p.x, p.y)]; + LOG(@"(%g, %g) <- fromBacking", q.x, q.y); + q = [self convertPoint:q toView:nil]; + LOG(@"(%g, %g) <- toWindow", q.x, q.y); + q = [self.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); + } } -- (void)viewDidChangeBackingProperties -{ - [super viewDidChangeBackingProperties]; - if(self.img) - resizeimg(self.client); + +- (void)resetCursorRects { + [super resetCursorRects]; + [self addCursorRect:self.bounds cursor:self.currentCursor]; } // conforms to protocol NSTextInputClient @@ -637,24 +837,24 @@ struct Cursors { LOG(@"text length %ld", _tmpText.length); for(i = 0; i <= _tmpText.length; ++i){ if(i == _markedRange.location) - keystroke(self.client, '['); + gfx_keystroke(self.client, '['); if(_selectedRange.length){ if(i == _selectedRange.location) - keystroke(self.client, '{'); + gfx_keystroke(self.client, '{'); if(i == NSMaxRange(_selectedRange)) - keystroke(self.client, '}'); + gfx_keystroke(self.client, '}'); } if(i == NSMaxRange(_markedRange)) - keystroke(self.client, ']'); + gfx_keystroke(self.client, ']'); if(i < _tmpText.length) - keystroke(self.client, [_tmpText characterAtIndex:i]); + gfx_keystroke(self.client, [_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(self.client, Kleft); + gfx_keystroke(self.client, Kleft); } LOG(@"text: \"%@\" (%ld,%ld) (%ld,%ld)", _tmpText, @@ -669,7 +869,7 @@ struct Cursors { LOG(@"unmarkText"); len = [_tmpText length]; //for(i = 0; i < len; ++i) - // keystroke(self.client, [_tmpText characterAtIndex:i]); + // gfx_keystroke(self.client, [_tmpText characterAtIndex:i]); [_tmpText deleteCharactersInRange:NSMakeRange(0, len)]; _markedRange = NSMakeRange(NSNotFound, 0); _selectedRange = NSMakeRange(0, 0); @@ -711,7 +911,7 @@ struct Cursors { len = [s length]; for(i = 0; i < len; ++i) - keystroke(self.client, [s characterAtIndex:i]); + gfx_keystroke(self.client, [s characterAtIndex:i]); [_tmpText deleteCharactersInRange:NSMakeRange(0, _tmpText.length)]; _markedRange = NSMakeRange(NSNotFound, 0); _selectedRange = NSMakeRange(0, 0); @@ -751,7 +951,7 @@ struct Cursors { k += Kcmd; } if(k>0) - keystroke(self.client, k); + gfx_keystroke(self.client, k); } // Helper for managing input rect approximately @@ -782,69 +982,13 @@ struct Cursors { + (_selectedRange.length > 0); LOG(@"move right %d", l); for(i = 0; i < l; ++i) - keystroke(self.client, Kright); + gfx_keystroke(self.client, Kright); l = _tmpText.length+2+2*(_selectedRange.length > 0); LOG(@"backspace %d", l); for(uint i = 0; i < l; ++i) - keystroke(self.client, Kbs); - } -} - -@end - -@implementation DrawLayer - -- (void)display -{ - id<MTLCommandBuffer> cbuf; - id<MTLBlitCommandEncoder> blit; - - LOG(@"display"); - - cbuf = [commandQueue commandBuffer]; - - LOG(@"display query drawable"); - -@autoreleasepool{ - id<CAMetalDrawable> drawable; - DevDrawView *view = client0->view; - - drawable = [view.dlayer nextDrawable]; - if(!drawable){ - LOG(@"display couldn't get drawable"); - [self setNeedsDisplay]; - return; + gfx_keystroke(self.client, Kbs); } - - LOG(@"display got drawable"); - - blit = [cbuf blitCommandEncoder]; - [blit copyFromTexture:texture - sourceSlice:0 - sourceLevel:0 - sourceOrigin:MTLOriginMake(0, 0, 0) - sourceSize:MTLSizeMake(texture.width, texture.height, texture.depth) - toTexture:drawable.texture - destinationSlice:0 - destinationLevel:0 - destinationOrigin:MTLOriginMake(0, 0, 0)]; - [blit endEncoding]; - - [cbuf presentDrawable:drawable]; - drawable = nil; } - [cbuf addCompletedHandler:^(id<MTLCommandBuffer> cmdBuff){ - if(cmdBuff.error){ - NSLog(@"command buffer finished with error: %@", - cmdBuff.error.localizedDescription); - }else - LOG(@"command buffer finishes present drawable"); - }]; - [cbuf commit]; - - LOG(@"display commit"); -} - @end static uint @@ -935,122 +1079,9 @@ keycvt(uint code) } } -Memimage* -attachscreen(Client *c, char *label, char *winsize) -{ - LOG(@"attachscreen(%s, %s)", label, winsize); - [AppDelegate - performSelectorOnMainThread:@selector(makewin:) - withObject:[NSValue valueWithPointer:winsize] - waitUntilDone:YES]; - kicklabel(label); - setcursor(nil, nil); - c->mouse.resized = 0; - return initimg(c); -} - -static Memimage* -initimg(Client *c) -{ - DevDrawView *view = c->view; - -@autoreleasepool{ - CGFloat scale; - NSSize size; - MTLTextureDescriptor *textureDesc; - - size = [view convertSizeToBacking:[view bounds].size]; - c->mouserect = Rect(0, 0, size.width, size.height); - - LOG(@"initimg %.0f %.0f", size.width, size.height); - - view.img = allocmemimage(c->mouserect, XRGB32); - if(view.img == nil) - panic("allocmemimage: %r"); - if(view.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 = [view.win backingScaleFactor]; - [view.dlayer setDrawableSize:size]; - [view.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 - c->displaydpi = scale * 110; -} - LOG(@"initimg return"); - - return view.img; -} - -void -_flushmemscreen(Rectangle r) -{ - DevDrawView *view = client0->view; - - LOG(@"_flushmemscreen(%d,%d,%d,%d)", r.min.x, r.min.y, Dx(r), Dy(r)); - if(!rectinrect(r, Rect(0, 0, texture.width, texture.height))){ - LOG(@"Rectangle is out of bounds, return."); - return; - } - - @autoreleasepool{ - [texture - replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r)) - mipmapLevel:0 - withBytes:byteaddr(view.img, Pt(r.min.x, r.min.y)) - bytesPerRow:view.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) -{ - DevDrawView *view = client0->view; - - @autoreleasepool{ - NSPoint q; - - LOG(@"setmouse(%d,%d)", p.x, p.y); - q = [view.win convertPointFromBacking:NSMakePoint(p.x, p.y)]; - LOG(@"(%g, %g) <- fromBacking", q.x, q.y); - q = [view convertPoint:q toView:nil]; - LOG(@"(%g, %g) <- toWindow", q.x, q.y); - q = [view.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); - } -} - +// TODO char* -getsnarf(void) +rpc_getsnarf(void) { NSPasteboard *pb; NSString *s; @@ -1069,8 +1100,9 @@ getsnarf(void) } } +// TODO void -putsnarf(char *s) +rpc_putsnarf(char *s) { NSArray *t; NSPasteboard *pb; @@ -1091,75 +1123,6 @@ putsnarf(char *s) } } -void -kicklabel(char *label) -{ - NSString *s; - - LOG(@"kicklabel(%s)", label); - if(label == nil) - return; - - @autoreleasepool{ - s = [[NSString alloc] initWithUTF8String:label]; - [AppDelegate - performSelectorOnMainThread:@selector(callkicklabel:) - withObject:s - waitUntilDone:NO]; - } -} - -void -setcursor(Cursor *c, Cursor2 *c2) -{ - Cursors cs; - - cs.c = c; - cs.c2 = c2; - - [AppDelegate - performSelectorOnMainThread:@selector(callsetcursor:) - withObject:[NSValue valueWithPointer:&cs] - waitUntilDone:YES]; -} - -void -topwin(void) -{ - DevDrawView *view = client0->view; - - [view.win - performSelectorOnMainThread: - @selector(makeKeyAndOrderFront:) - withObject:nil - waitUntilDone:YES]; - - [NSApp activateIgnoringOtherApps:YES]; -} - -void -resizeimg(Client *c) -{ - DevDrawView *view = c->view; - - _drawreplacescreenimage(c, initimg(c)); - [view sendmouse:0]; -} - -void -resizewindow(Rectangle r) -{ - DevDrawView *view = client0->view; - - 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 = [view convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))]; - [view.win setContentSize:s]; - }); -} - static void setprocname(const char *s) { diff --git a/src/cmd/devdraw/mkfile b/src/cmd/devdraw/mkfile index 6546b590..7ecf7dc1 100644 --- a/src/cmd/devdraw/mkfile +++ b/src/cmd/devdraw/mkfile @@ -9,6 +9,7 @@ WSYSOFILES=\ devdraw.$O\ latin1.$O\ mouseswap.$O\ + srv.$O\ winsize.$O\ <|sh ./mkwsysrules.sh @@ -42,7 +43,7 @@ $O.macargv: $MACARGV $LD -o $target $prereq %.$O: %.m - $CC $CFLAGS $OBJCFLAGS -o $target $stem.m + $CC $CFLAGS $OBJCFLAGS -fobjc-arc -o $target $stem.m CLEANFILES=$O.devdraw $O.macargv $O.drawclient $O.mklatinkbd latin1.h diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh index cd72120f..122e9123 100644 --- a/src/cmd/devdraw/mkwsysrules.sh +++ b/src/cmd/devdraw/mkwsysrules.sh @@ -53,8 +53,8 @@ if [ $WSYSTYPE = x11 ]; then echo 'WSYSOFILES=$WSYSOFILES '$XO echo 'WSYSHFILES=x11-inc.h x11-keysym2ucs.h x11-memdraw.h' elif [ $WSYSTYPE = mac ]; then - echo 'WSYSOFILES=$WSYSOFILES mac-draw.o mac-screen.o mac-srv.o' - echo 'WSYSHFILES=mac-screen.h' + echo 'WSYSOFILES=$WSYSOFILES mac-draw.o mac-screen.o' + echo 'WSYSHFILES=' echo 'MACARGV=macargv.o' elif [ $WSYSTYPE = nowsys ]; then echo 'WSYSOFILES=nowsys.o' diff --git a/src/cmd/devdraw/mac-srv.c b/src/cmd/devdraw/srv.c index 6727ef63..0e7540be 100644 --- a/src/cmd/devdraw/mac-srv.c +++ b/src/cmd/devdraw/srv.c @@ -13,12 +13,11 @@ #include <cursor.h> #include <drawfcall.h> #include "devdraw.h" -#include "mac-screen.h" -void runmsg(Client*, Wsysmsg*); -void replymsg(Client*, Wsysmsg*); -void matchkbd(Client*); -void matchmouse(Client*); +static void runmsg(Client*, Wsysmsg*); +static void replymsg(Client*, Wsysmsg*); +static void matchkbd(Client*); +static void matchmouse(Client*); int trace = 0; @@ -55,7 +54,7 @@ servep9p(Client *c) } } -void +static void replyerror(Client *c, Wsysmsg *m) { char err[256]; @@ -70,7 +69,7 @@ replyerror(Client *c, Wsysmsg *m) * Handle a single wsysmsg. * Might queue for later (kbd, mouse read) */ -void +static void runmsg(Client *c, Wsysmsg *m) { static uchar buf[65536]; @@ -80,7 +79,7 @@ runmsg(Client *c, Wsysmsg *m) switch(m->type){ case Tinit: memimageinit(); - i = attachscreen(c, m->label, m->winsize); + i = rpc_attachscreen(c, m->label, m->winsize); _initdisplaymemimage(c, i); replymsg(c, m); break; @@ -110,23 +109,25 @@ runmsg(Client *c, Wsysmsg *m) break; case Tmoveto: - setmouse(m->mouse.xy); + rpc_setmouse(c, m->mouse.xy); replymsg(c, m); break; case Tcursor: if(m->arrowcursor) - setcursor(nil, nil); - else - setcursor(&m->cursor, nil); + rpc_setcursor(c, nil, nil); + else { + scalecursor(&m->cursor2, &m->cursor); + rpc_setcursor(c, &m->cursor, &m->cursor2); + } replymsg(c, m); break; case Tcursor2: if(m->arrowcursor) - setcursor(nil, nil); + rpc_setcursor(c, nil, nil); else - setcursor(&m->cursor, &m->cursor2); + rpc_setcursor(c, &m->cursor, &m->cursor2); replymsg(c, m); break; @@ -136,12 +137,12 @@ runmsg(Client *c, Wsysmsg *m) break; case Tlabel: - kicklabel(m->label); + rpc_setlabel(c, m->label); replymsg(c, m); break; case Trdsnarf: - m->snarf = getsnarf(); + m->snarf = rpc_getsnarf(); replymsg(c, m); free(m->snarf); break; @@ -177,12 +178,12 @@ runmsg(Client *c, Wsysmsg *m) break; case Ttop: - topwin(); + rpc_topwin(c); replymsg(c, m); break; case Tresize: - resizewindow(m->rect); + rpc_resizewindow(c, m->rect); replymsg(c, m); break; } @@ -192,7 +193,7 @@ runmsg(Client *c, Wsysmsg *m) * Reply to m. */ QLock replylock; -void +static void replymsg(Client *c, Wsysmsg *m) { int n; @@ -224,7 +225,7 @@ replymsg(Client *c, Wsysmsg *m) /* * Match queued kbd reads with queued kbd characters. */ -void +static void matchkbd(Client *c) { Wsysmsg m; @@ -243,14 +244,18 @@ matchkbd(Client *c) } } -/* - * Match queued mouse reads with queued mouse events. - */ -void +// matchmouse matches queued mouse reads with queued mouse events. +// It must be called with c->inputlk held. +static void matchmouse(Client *c) { Wsysmsg m; + if(canqlock(&c->inputlk)) { + fprint(2, "misuse of matchmouse\n"); + abort(); + } + while(c->mouse.ri != c->mouse.wi && c->mousetags.ri != c->mousetags.wi){ m.type = Rrdmouse; m.tag = c->mousetags.t[c->mousetags.ri++]; @@ -271,10 +276,11 @@ matchmouse(Client *c) } void -mousetrack(Client *c, int x, int y, int b, uint ms) +gfx_mousetrack(Client *c, int x, int y, int b, uint ms) { Mouse *m; + qlock(&c->inputlk); if(x < c->mouserect.min.x) x = c->mouserect.min.x; if(x > c->mouserect.max.x) @@ -284,7 +290,6 @@ mousetrack(Client *c, int x, int y, int b, uint ms) if(y > c->mouserect.max.y) y = c->mouserect.max.y; - qlock(&c->inputlk); // If reader has stopped reading, don't bother. // If reader is completely caught up, definitely queue. // Otherwise, queue only button change events. @@ -310,36 +315,50 @@ mousetrack(Client *c, int x, int y, int b, uint ms) qunlock(&c->inputlk); } -void +// kputc adds ch to the keyboard buffer. +// It must be called with c->inputlk held. +static void kputc(Client *c, int ch) { - qlock(&c->inputlk); + if(canqlock(&c->inputlk)) { + fprint(2, "misuse of kputc\n"); + abort(); + } + c->kbd.r[c->kbd.wi++] = ch; if(c->kbd.wi == nelem(c->kbd.r)) c->kbd.wi = 0; if(c->kbd.ri == c->kbd.wi) c->kbd.stall = 1; matchkbd(c); - qunlock(&c->inputlk); } +// gfx_abortcompose stops any pending compose sequence, +// because a mouse button has been clicked. +// It is called from the graphics thread with no locks held. void -abortcompose(Client *c) +gfx_abortcompose(Client *c) { - if(c->kbd.alting) - keystroke(c, Kalt); + qlock(&c->inputlk); + if(c->kbd.alting) { + c->kbd.alting = 0; + c->kbd.nk = 0; + } + qunlock(&c->inputlk); } +// gfx_keystroke records a single-rune keystroke. +// It is called from the graphics thread with no locks held. void -keystroke(Client *c, int ch) +gfx_keystroke(Client *c, int ch) { - static Rune k[10]; - static int nk; int i; + qlock(&c->inputlk); if(ch == Kalt){ c->kbd.alting = !c->kbd.alting; - nk = 0; + c->kbd.nk = 0; + qunlock(&c->inputlk); return; } if(ch == Kcmd+'r') { @@ -349,30 +368,35 @@ keystroke(Client *c, int ch) c->forcedpi = 100; else c->forcedpi = 225; - resizeimg(c); + qunlock(&c->inputlk); + rpc_resizeimg(c); return; } if(!c->kbd.alting){ kputc(c, ch); + qunlock(&c->inputlk); return; } - if(nk >= nelem(k)) // should not happen - nk = 0; - k[nk++] = ch; - ch = _latin1(k, nk); + if(c->kbd.nk >= nelem(c->kbd.k)) // should not happen + c->kbd.nk = 0; + c->kbd.k[c->kbd.nk++] = ch; + ch = _latin1(c->kbd.k, c->kbd.nk); if(ch > 0){ c->kbd.alting = 0; kputc(c, ch); - nk = 0; + c->kbd.nk = 0; + qunlock(&c->inputlk); return; } if(ch == -1){ c->kbd.alting = 0; - for(i=0; i<nk; i++) - kputc(c, k[i]); - nk = 0; + for(i=0; i<c->kbd.nk; i++) + kputc(c, c->kbd.k[i]); + c->kbd.nk = 0; + qunlock(&c->inputlk); return; } // need more input + qunlock(&c->inputlk); return; } |