aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/devdraw
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2020-01-09 21:47:14 -0500
committerRuss Cox <rsc@swtch.com>2020-01-13 16:46:14 -0500
commitb1a086dee9bf5846b31323ba2c438f8853a9c87f (patch)
tree4f937160d21a46e73cddaf53ab8356b3aa56ae09 /src/cmd/devdraw
parent843e5af1986a2e8f1c4f6177dc4509501711a22c (diff)
downloadplan9port-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/cmd/devdraw')
-rw-r--r--src/cmd/devdraw/devdraw.c8
-rw-r--r--src/cmd/devdraw/devdraw.h22
-rw-r--r--src/cmd/devdraw/mac-screen.h19
-rw-r--r--src/cmd/devdraw/mac-screen.m827
-rw-r--r--src/cmd/devdraw/mkfile3
-rw-r--r--src/cmd/devdraw/mkwsysrules.sh4
-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;
}