commit 933b98054f40bb224acda134d7bb77a023bcc57f
parent ce27d7babdf2ee09ff6d1f8d4a166c2208995774
Author: Russ Cox <rsc@swtch.com>
Date: Wed, 8 Jan 2020 20:07:15 -0500
devdraw: use consistent mac-* prefix on macOS files
We were using osx- and cocoa- but it's not even OS X anymore.
Diffstat:
14 files changed, 1679 insertions(+), 1873 deletions(-)
diff --git a/src/cmd/devdraw/cocoa-screen.m b/src/cmd/devdraw/cocoa-screen.m
@@ -1,1249 +0,0 @@
-#define Cursor OSXCursor
-#define Point OSXPoint
-#define Rect OSXRect
-
-#import <Cocoa/Cocoa.h>
-#import <Metal/Metal.h>
-#import <QuartzCore/CAMetalLayer.h>
-
-#undef Cursor
-#undef Point
-#undef Rect
-
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include <draw.h>
-#include <memdraw.h>
-#include <keyboard.h>
-#include <cursor.h>
-#include "cocoa-screen.h"
-#include "osx-keycodes.h"
-#include "devdraw.h"
-#include "bigarrow.h"
-#include "glendapng.h"
-
-AUTOFRAMEWORK(Cocoa)
-AUTOFRAMEWORK(Metal)
-AUTOFRAMEWORK(QuartzCore)
-
-#define LOG if(0)NSLog
-
-static void setprocname(const char*);
-static uint keycvt(uint);
-static uint msec(void);
-static Memimage* initimg(void);
-
-void
-usage(void)
-{
- fprint(2, "usage: devdraw (don't run directly)\n");
- threadexitsall("usage");
-}
-
-
-@interface AppDelegate : NSObject<NSApplicationDelegate,NSWindowDelegate>
-+ (void)makewin:(NSValue *)v;
-+ (void)callkicklabel:(NSString *)v;
-+ (void)callsetNeedsDisplayInRect:(NSValue *)v;
-+ (void)callsetcursor:(NSValue *)v;
-@end
-@interface DevDrawView : NSView<NSTextInputClient>
-- (void)clearInput;
-- (void)getmouse:(NSEvent *)e;
-- (void)sendmouse:(NSUInteger)b;
-- (void)resetLastInputRect;
-- (void)enlargeLastInputRect:(NSRect)r;
-@end
-@interface DrawLayer : CAMetalLayer
-@end
-
-static AppDelegate *myApp = NULL;
-static DevDrawView *myContent = NULL;
-static NSWindow *win = NULL;
-static NSCursor *currentCursor = NULL;
-
-static DrawLayer *layer;
-static id<MTLDevice> device;
-static id<MTLCommandQueue> commandQueue;
-static id<MTLTexture> texture;
-
-static Memimage *img = NULL;
-
-static QLock snarfl;
-
-void
-threadmain(int argc, char **argv)
-{
- /*
- * Move the protocol off stdin/stdout so that
- * any inadvertent prints don't screw things up.
- */
- dup(0,3);
- dup(1,4);
- close(0);
- close(1);
- open("/dev/null", OREAD);
- open("/dev/null", OWRITE);
-
- ARGBEGIN{
- case 'D': /* for good ps -a listings */
- break;
- case 'f': /* fall through for backward compatibility */
- case 'g':
- case 'b':
- break;
- default:
- usage();
- }ARGEND
-
- setprocname(argv0);
-
- @autoreleasepool{
- [NSApplication sharedApplication];
- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
- myApp = [AppDelegate new];
- [NSApp setDelegate:myApp];
- [NSApp run];
- }
-}
-
-
-void
-callservep9p(void *v)
-{
- USED(v);
-
- servep9p();
- [NSApp terminate:myApp];
-}
-
-@implementation AppDelegate
-
-+ (void)makewin:(NSValue *)v
-{
- NSRect r, sr;
- Rectangle wr;
- int set;
- char *s;
- NSArray *allDevices;
-
- const NSWindowStyleMask Winstyle = NSWindowStyleMaskTitled
- | NSWindowStyleMaskClosable
- | NSWindowStyleMaskMiniaturizable
- | NSWindowStyleMaskResizable;
-
- sr = [[NSScreen mainScreen] frame];
- r = [[NSScreen mainScreen] visibleFrame];
-
- s = [v pointerValue];
- LOG(@"makewin(%s)", s);
- if(s && *s){
- if(parsewinsize(s, &wr, &set) < 0)
- sysfatal("%r");
- }else{
- wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
- set = 0;
- }
-
- r.origin.x = wr.min.x;
- r.origin.y = sr.size.height-wr.max.y; /* winsize is top-left-based */
- r.size.width = fmin(Dx(wr), r.size.width);
- r.size.height = fmin(Dy(wr), r.size.height);
- r = [NSWindow contentRectForFrameRect:r styleMask:Winstyle];
-
- win = [[NSWindow alloc]
- initWithContentRect:r
- styleMask:Winstyle
- backing:NSBackingStoreBuffered defer:NO];
- [win setTitle:@"devdraw"];
-
- if(!set)
- [win center];
- [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
- [win setContentMinSize:NSMakeSize(64,64)];
- [win setOpaque:YES];
- [win setRestorable:NO];
- [win setAcceptsMouseMovedEvents:YES];
- [win setDelegate:myApp];
-
- myContent = [DevDrawView new];
- [win setContentView:myContent];
- [myContent setWantsLayer:YES];
- [myContent setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
-
- device = nil;
- allDevices = MTLCopyAllDevices();
- for(id mtlDevice in allDevices) {
- if ([mtlDevice isLowPower] && ![mtlDevice isRemovable]) {
- device = mtlDevice;
- break;
- }
- }
- if(!device)
- device = MTLCreateSystemDefaultDevice();
-
- commandQueue = [device newCommandQueue];
-
- layer = (DrawLayer *)[myContent layer];
- layer.device = device;
- 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.
- {
- CALayer *stub = [CALayer layer];
- stub.frame = CGRectMake(0, 0, 1, 1);
- [stub setNeedsDisplay];
- [layer addSublayer:stub];
- }
-
- [NSEvent setMouseCoalescingEnabled:NO];
-
- topwin();
-}
-
-+ (void)callkicklabel:(NSString *)s
-{
- LOG(@"callkicklabel(%@)", s);
- [win setTitle:s];
- [[NSApp dockTile] setBadgeLabel:s];
-}
-
-
-+ (void)callsetNeedsDisplayInRect:(NSValue *)v
-{
- NSRect r;
- dispatch_time_t time;
-
- r = [v rectValue];
- LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
- r = [win convertRectFromBacking:r];
- LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
- [layer setNeedsDisplayInRect:r];
-
- time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC);
- dispatch_after(time, dispatch_get_main_queue(), ^(void){
- [layer setNeedsDisplayInRect:r];
- });
-
- [myContent enlargeLastInputRect:r];
-}
-
-typedef struct Cursors Cursors;
-struct Cursors {
- Cursor *c;
- Cursor2 *c2;
-};
-
-+ (void)callsetcursor:(NSValue *)v
-{
- Cursors *cs;
- Cursor *c;
- Cursor2 *c2;
- NSBitmapImageRep *r, *r2;
- NSImage *i;
- NSPoint p;
- uchar *plane[5], *plane2[5];
- uint b;
-
- cs = [v pointerValue];
- c = cs->c;
- if(!c)
- c = &bigarrow;
- c2 = cs->c2;
- if(!c2)
- c2 = &bigarrow2;
-
- r = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:nil
- pixelsWide:16
- pixelsHigh:16
- bitsPerSample:1
- samplesPerPixel:2
- hasAlpha:YES
- isPlanar:YES
- colorSpaceName:NSDeviceWhiteColorSpace
- bytesPerRow:2
- bitsPerPixel:0];
- [r getBitmapDataPlanes:plane];
- for(b=0; b<nelem(c->set); b++){
- plane[0][b] = ~c->set[b] & c->clr[b];
- plane[1][b] = c->set[b] | c->clr[b];
- }
-
- r2 = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:nil
- pixelsWide:32
- pixelsHigh:32
- bitsPerSample:1
- samplesPerPixel:2
- hasAlpha:YES
- isPlanar:YES
- colorSpaceName:NSDeviceWhiteColorSpace
- bytesPerRow:4
- bitsPerPixel:0];
- [r2 getBitmapDataPlanes:plane2];
- for(b=0; b<nelem(c2->set); b++){
- plane2[0][b] = ~c2->set[b] & c2->clr[b];
- plane2[1][b] = c2->set[b] | c2->clr[b];
- }
-
- // For checking out the cursor bitmap image
-/*
- static BOOL saveimg = YES;
- if(saveimg){
- NSData *data = [r representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
- [data writeToFile: @"/tmp/r.bmp" atomically: NO];
- data = [r2 representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
- [data writeToFile: @"/tmp/r2.bmp" atomically: NO];
- saveimg = NO;
- }
-*/
-
- i = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)];
- [i addRepresentation:r2];
- [i addRepresentation:r];
-
- p = NSMakePoint(-c->offset.x, -c->offset.y);
- currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
-
- [win invalidateCursorRectsForView:myContent];
-}
-
-- (void)applicationDidFinishLaunching:(id)arg
-{
- NSMenu *m, *sm;
- NSData *d;
- NSImage *i;
-
- LOG(@"applicationDidFinishLaunching");
-
- sm = [NSMenu new];
- [sm addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
- [sm addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"];
- [sm addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
- m = [NSMenu new];
- [m addItemWithTitle:@"DEVDRAW" action:NULL keyEquivalent:@""];
- [m setSubmenu:sm forItem:[m itemWithTitle:@"DEVDRAW"]];
- [NSApp setMainMenu:m];
-
- d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
- i = [[NSImage alloc] initWithData:d];
- [NSApp setApplicationIconImage:i];
- [[NSApp dockTile] display];
-
- 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;
-}
-
-- (void)windowDidResize:(NSNotification *)notification
-{
- if(![myContent inLiveResize] && img) {
- resizeimg();
- }
-}
-
-- (void)windowDidBecomeKey:(id)arg
-{
- [myContent sendmouse:0];
-}
-
-@end
-
-@implementation DevDrawView
-{
- NSMutableString *_tmpText;
- NSRange _markedRange;
- NSRange _selectedRange;
- NSRect _lastInputRect; // The view is flipped, this is not.
- BOOL _tapping;
- NSUInteger _tapFingers;
- NSUInteger _tapTime;
-}
-
-- (id)init
-{
- LOG(@"View init");
- self = [super init];
- [self setAllowedTouchTypes:NSTouchTypeMaskDirect|NSTouchTypeMaskIndirect];
- _tmpText = [[NSMutableString alloc] initWithCapacity:2];
- _markedRange = NSMakeRange(NSNotFound, 0);
- _selectedRange = NSMakeRange(0, 0);
- return self;
-}
-
-- (CALayer *)makeBackingLayer
-{
- LOG(@"makeBackingLayer");
- return [DrawLayer layer];
-}
-
-- (BOOL)wantsUpdateLayer
-{
- return YES;
-}
-
-- (BOOL)isOpaque
-{
- return YES;
-}
-
-- (BOOL)isFlipped
-{
- return YES;
-}
-
-- (BOOL)acceptsFirstResponder
-{
- return YES;
-}
-
-- (void)mouseMoved:(NSEvent*)e{ [self getmouse:e];}
-- (void)mouseDown:(NSEvent*)e{ [self getmouse:e];}
-- (void)mouseDragged:(NSEvent*)e{ [self getmouse:e];}
-- (void)mouseUp:(NSEvent*)e{ [self getmouse:e];}
-- (void)otherMouseDown:(NSEvent*)e{ [self getmouse:e];}
-- (void)otherMouseDragged:(NSEvent*)e{ [self getmouse:e];}
-- (void)otherMouseUp:(NSEvent*)e{ [self getmouse:e];}
-- (void)rightMouseDown:(NSEvent*)e{ [self getmouse:e];}
-- (void)rightMouseDragged:(NSEvent*)e{ [self getmouse:e];}
-- (void)rightMouseUp:(NSEvent*)e{ [self getmouse:e];}
-
-- (void)scrollWheel:(NSEvent*)e
-{
- NSInteger s;
-
- s = [e scrollingDeltaY];
- if(s > 0)
- [self sendmouse:8];
- else if (s < 0)
- [self sendmouse:16];
-}
-
-- (void)keyDown:(NSEvent*)e
-{
- LOG(@"keyDown to interpret");
-
- [self interpretKeyEvents:[NSArray arrayWithObject:e]];
-
- [self resetLastInputRect];
-}
-
-- (void)flagsChanged:(NSEvent*)e
-{
- static NSEventModifierFlags omod;
- NSEventModifierFlags m;
- uint b;
-
- LOG(@"flagsChanged");
- m = [e modifierFlags];
-
- b = [NSEvent pressedMouseButtons];
- b = (b&~6) | (b&4)>>1 | (b&2)<<1;
- if(b){
- if(m & ~omod & NSEventModifierFlagControl)
- b |= 1;
- if(m & ~omod & NSEventModifierFlagOption)
- b |= 2;
- if(m & ~omod & NSEventModifierFlagCommand)
- b |= 4;
- [self sendmouse:b];
- }else if(m & ~omod & NSEventModifierFlagOption)
- keystroke(Kalt);
-
- omod = m;
-}
-
-- (void)magnifyWithEvent:(NSEvent*)e
-{
- if(fabs([e magnification]) > 0.02)
- [[self window] toggleFullScreen:nil];
-}
-
-- (void)touchesBeganWithEvent:(NSEvent*)e
-{
- _tapping = YES;
- _tapFingers = [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count;
- _tapTime = msec();
-}
-- (void)touchesMovedWithEvent:(NSEvent*)e
-{
- _tapping = NO;
-}
-- (void)touchesEndedWithEvent:(NSEvent*)e
-{
- if(_tapping
- && [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count == 0
- && msec() - _tapTime < 250){
- switch(_tapFingers){
- case 3:
- [self sendmouse:2];
- [self sendmouse:0];
- break;
- case 4:
- [self sendmouse:2];
- [self sendmouse:1];
- [self sendmouse:0];
- break;
- }
- _tapping = NO;
- }
-}
-- (void)touchesCancelledWithEvent:(NSEvent*)e
-{
- _tapping = NO;
-}
-
-- (void)getmouse:(NSEvent *)e
-{
- NSUInteger b;
- NSEventModifierFlags m;
-
- b = [NSEvent pressedMouseButtons];
- b = b&~6 | (b&4)>>1 | (b&2)<<1;
- b = mouseswap(b);
-
- if(b == 1){
- m = [e modifierFlags];
- if(m & NSEventModifierFlagOption){
- abortcompose();
- b = 2;
- }else
- if(m & NSEventModifierFlagCommand)
- b = 4;
- }
- [self sendmouse:b];
-}
-
-- (void)sendmouse:(NSUInteger)b
-{
- NSPoint p;
-
- p = [self.window convertPointToBacking:
- [self.window mouseLocationOutsideOfEventStream]];
- p.y = Dy(mouserect) - p.y;
- // LOG(@"(%g, %g) <- sendmouse(%d)", p.x, p.y, (uint)b);
- mousetrack(p.x, p.y, b, msec());
- if(b && _lastInputRect.size.width && _lastInputRect.size.height)
- [self resetLastInputRect];
-}
-
-- (void)resetCursorRects {
- [super resetCursorRects];
- [self addCursorRect:self.bounds cursor:currentCursor];
-}
-
-- (void)viewDidEndLiveResize
-{
- [super viewDidEndLiveResize];
- if(img)
- resizeimg();
-}
-
-- (void)viewDidChangeBackingProperties
-{
- [super viewDidChangeBackingProperties];
- if(img)
- resizeimg();
-}
-
-// conforms to protocol NSTextInputClient
-- (BOOL)hasMarkedText
-{
- LOG(@"hasMarkedText");
- return _markedRange.location != NSNotFound;
-}
-- (NSRange)markedRange
-{
- LOG(@"markedRange");
- return _markedRange;
-}
-- (NSRange)selectedRange
-{
- LOG(@"selectedRange");
- return _selectedRange;
-}
-- (void)setMarkedText:(id)string
- selectedRange:(NSRange)sRange
- replacementRange:(NSRange)rRange
-{
- NSString *str;
-
- LOG(@"setMarkedText: %@ (%ld, %ld) (%ld, %ld)", string,
- sRange.location, sRange.length,
- rRange.location, rRange.length);
-
- [self clearInput];
-
- if([string isKindOfClass:[NSAttributedString class]])
- str = [string string];
- else
- str = string;
-
- if(rRange.location == NSNotFound){
- if(_markedRange.location != NSNotFound){
- rRange = _markedRange;
- }else{
- rRange = _selectedRange;
- }
- }
-
- if(str.length == 0){
- [_tmpText deleteCharactersInRange:rRange];
- [self unmarkText];
- }else{
- _markedRange = NSMakeRange(rRange.location, str.length);
- [_tmpText replaceCharactersInRange:rRange withString:str];
- }
- _selectedRange.location = rRange.location + sRange.location;
- _selectedRange.length = sRange.length;
-
- if(_tmpText.length){
- uint i;
- LOG(@"text length %ld", _tmpText.length);
- for(i = 0; i <= _tmpText.length; ++i){
- if(i == _markedRange.location)
- keystroke('[');
- if(_selectedRange.length){
- if(i == _selectedRange.location)
- keystroke('{');
- if(i == NSMaxRange(_selectedRange))
- keystroke('}');
- }
- if(i == NSMaxRange(_markedRange))
- keystroke(']');
- if(i < _tmpText.length)
- keystroke([_tmpText characterAtIndex:i]);
- }
- int l;
- l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
- + (_selectedRange.length > 0);
- LOG(@"move left %d", l);
- for(i = 0; i < l; ++i)
- keystroke(Kleft);
- }
-
- LOG(@"text: \"%@\" (%ld,%ld) (%ld,%ld)", _tmpText,
- _markedRange.location, _markedRange.length,
- _selectedRange.location, _selectedRange.length);
-}
-- (void)unmarkText
-{
- //NSUInteger i;
- NSUInteger len;
-
- LOG(@"unmarkText");
- len = [_tmpText length];
- //for(i = 0; i < len; ++i)
- // keystroke([_tmpText characterAtIndex:i]);
- [_tmpText deleteCharactersInRange:NSMakeRange(0, len)];
- _markedRange = NSMakeRange(NSNotFound, 0);
- _selectedRange = NSMakeRange(0, 0);
-}
-- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText
-{
- LOG(@"validAttributesForMarkedText");
- return @[];
-}
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r
- actualRange:(NSRangePointer)actualRange
-{
- NSRange sr;
- NSAttributedString *s;
-
- LOG(@"attributedSubstringForProposedRange: (%ld, %ld) (%ld, %ld)",
- r.location, r.length, actualRange->location, actualRange->length);
- sr = NSMakeRange(0, [_tmpText length]);
- sr = NSIntersectionRange(sr, r);
- if(actualRange)
- *actualRange = sr;
- LOG(@"use range: %ld, %ld", sr.location, sr.length);
- s = nil;
- if(sr.length)
- s = [[NSAttributedString alloc]
- initWithString:[_tmpText substringWithRange:sr]];
- LOG(@" return %@", s);
- return s;
-}
-- (void)insertText:(id)s
- replacementRange:(NSRange)r
-{
- NSUInteger i;
- NSUInteger len;
-
- LOG(@"insertText: %@ replacementRange: %ld, %ld", s, r.location, r.length);
-
- [self clearInput];
-
- len = [s length];
- for(i = 0; i < len; ++i)
- keystroke([s characterAtIndex:i]);
- [_tmpText deleteCharactersInRange:NSMakeRange(0, _tmpText.length)];
- _markedRange = NSMakeRange(NSNotFound, 0);
- _selectedRange = NSMakeRange(0, 0);
-}
-- (NSUInteger)characterIndexForPoint:(NSPoint)point
-{
- LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
- return 0;
-}
-- (NSRect)firstRectForCharacterRange:(NSRange)r
- actualRange:(NSRangePointer)actualRange
-{
- LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
- r.location, r.length, actualRange->location, actualRange->length);
- if(actualRange)
- *actualRange = r;
- return [[self window] convertRectToScreen:_lastInputRect];
-}
-- (void)doCommandBySelector:(SEL)s
-{
- NSEvent *e;
- NSEventModifierFlags m;
- uint c, k;
-
- LOG(@"doCommandBySelector (%@)", NSStringFromSelector(s));
-
- e = [NSApp currentEvent];
- c = [[e characters] characterAtIndex:0];
- k = keycvt(c);
- LOG(@"keyDown: character0: 0x%x -> 0x%x", c, k);
- m = [e modifierFlags];
-
- if(m & NSEventModifierFlagCommand){
- if((m & NSEventModifierFlagShift) && 'a' <= k && k <= 'z')
- k += 'A' - 'a';
- if(' '<=k && k<='~')
- k += Kcmd;
- }
- if(k>0)
- keystroke(k);
-}
-
-// Helper for managing input rect approximately
-- (void)resetLastInputRect
-{
- LOG(@"resetLastInputRect");
- _lastInputRect.origin.x = 0.0;
- _lastInputRect.origin.y = 0.0;
- _lastInputRect.size.width = 0.0;
- _lastInputRect.size.height = 0.0;
-}
-
-- (void)enlargeLastInputRect:(NSRect)r
-{
- r.origin.y = [self bounds].size.height - r.origin.y - r.size.height;
- _lastInputRect = NSUnionRect(_lastInputRect, r);
- LOG(@"update last input rect (%g, %g, %g, %g)",
- _lastInputRect.origin.x, _lastInputRect.origin.y,
- _lastInputRect.size.width, _lastInputRect.size.height);
-}
-
-- (void)clearInput
-{
- if(_tmpText.length){
- uint i;
- int l;
- l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
- + (_selectedRange.length > 0);
- LOG(@"move right %d", l);
- for(i = 0; i < l; ++i)
- keystroke(Kright);
- l = _tmpText.length+2+2*(_selectedRange.length > 0);
- LOG(@"backspace %d", l);
- for(uint i = 0; i < l; ++i)
- keystroke(Kbs);
- }
-}
-
-@end
-
-@implementation DrawLayer
-
-- (void)display
-{
- id<MTLCommandBuffer> cbuf;
- id<MTLBlitCommandEncoder> blit;
-
- LOG(@"display");
-
- cbuf = [commandQueue commandBuffer];
-
- LOG(@"display query drawable");
-
-@autoreleasepool{
- id<CAMetalDrawable> drawable;
-
- drawable = [layer nextDrawable];
- if(!drawable){
- LOG(@"display couldn't get drawable");
- [self setNeedsDisplay];
- return;
- }
-
- LOG(@"display got drawable");
-
- 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
-msec(void)
-{
- return nsec()/1000000;
-}
-
-static uint
-keycvt(uint code)
-{
- switch(code){
- case '\r': return '\n';
- case 127: return '\b';
- case NSUpArrowFunctionKey: return Kup;
- case NSDownArrowFunctionKey: return Kdown;
- case NSLeftArrowFunctionKey: return Kleft;
- case NSRightArrowFunctionKey: return Kright;
- case NSInsertFunctionKey: return Kins;
- case NSDeleteFunctionKey: return Kdel;
- case NSHomeFunctionKey: return Khome;
- case NSEndFunctionKey: return Kend;
- case NSPageUpFunctionKey: return Kpgup;
- case NSPageDownFunctionKey: return Kpgdown;
- case NSF1FunctionKey: return KF|1;
- case NSF2FunctionKey: return KF|2;
- case NSF3FunctionKey: return KF|3;
- case NSF4FunctionKey: return KF|4;
- case NSF5FunctionKey: return KF|5;
- case NSF6FunctionKey: return KF|6;
- case NSF7FunctionKey: return KF|7;
- case NSF8FunctionKey: return KF|8;
- case NSF9FunctionKey: return KF|9;
- case NSF10FunctionKey: return KF|10;
- case NSF11FunctionKey: return KF|11;
- case NSF12FunctionKey: return KF|12;
- case NSBeginFunctionKey:
- case NSPrintScreenFunctionKey:
- case NSScrollLockFunctionKey:
- case NSF13FunctionKey:
- case NSF14FunctionKey:
- case NSF15FunctionKey:
- case NSF16FunctionKey:
- case NSF17FunctionKey:
- case NSF18FunctionKey:
- case NSF19FunctionKey:
- case NSF20FunctionKey:
- case NSF21FunctionKey:
- case NSF22FunctionKey:
- case NSF23FunctionKey:
- case NSF24FunctionKey:
- case NSF25FunctionKey:
- case NSF26FunctionKey:
- case NSF27FunctionKey:
- case NSF28FunctionKey:
- case NSF29FunctionKey:
- case NSF30FunctionKey:
- case NSF31FunctionKey:
- case NSF32FunctionKey:
- case NSF33FunctionKey:
- case NSF34FunctionKey:
- case NSF35FunctionKey:
- case NSPauseFunctionKey:
- case NSSysReqFunctionKey:
- case NSBreakFunctionKey:
- case NSResetFunctionKey:
- case NSStopFunctionKey:
- case NSMenuFunctionKey:
- case NSUserFunctionKey:
- case NSSystemFunctionKey:
- case NSPrintFunctionKey:
- case NSClearLineFunctionKey:
- case NSClearDisplayFunctionKey:
- case NSInsertLineFunctionKey:
- case NSDeleteLineFunctionKey:
- case NSInsertCharFunctionKey:
- case NSDeleteCharFunctionKey:
- case NSPrevFunctionKey:
- case NSNextFunctionKey:
- case NSSelectFunctionKey:
- case NSExecuteFunctionKey:
- case NSUndoFunctionKey:
- case NSRedoFunctionKey:
- case NSFindFunctionKey:
- case NSHelpFunctionKey:
- case NSModeSwitchFunctionKey: return 0;
- default: return code;
- }
-}
-
-Memimage*
-attachscreen(char *label, char *winsize)
-{
- LOG(@"attachscreen(%s, %s)", label, winsize);
- [AppDelegate
- performSelectorOnMainThread:@selector(makewin:)
- withObject:[NSValue valueWithPointer:winsize]
- waitUntilDone:YES];
- kicklabel(label);
- setcursor(nil, nil);
- mouseresized = 0;
- return initimg();
-}
-
-static Memimage*
-initimg(void)
-{
-@autoreleasepool{
- CGFloat scale;
- NSSize size;
- MTLTextureDescriptor *textureDesc;
-
- size = [myContent convertSizeToBacking:[myContent bounds].size];
- mouserect = Rect(0, 0, size.width, size.height);
-
- LOG(@"initimg %.0f %.0f", size.width, size.height);
-
- img = allocmemimage(mouserect, XRGB32);
- if(img == nil)
- panic("allocmemimage: %r");
- if(img->data == nil)
- panic("img->data == nil");
-
- textureDesc = [MTLTextureDescriptor
- texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
- width:size.width
- height:size.height
- mipmapped:NO];
- textureDesc.allowGPUOptimizedContents = YES;
- textureDesc.usage = MTLTextureUsageShaderRead;
- textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
- texture = [device newTextureWithDescriptor:textureDesc];
-
- scale = [win backingScaleFactor];
- [layer setDrawableSize:size];
- [layer setContentsScale:scale];
-
- // NOTE: This is not really the display DPI.
- // On retina, scale is 2; otherwise it is 1.
- // This formula gives us 220 for retina, 110 otherwise.
- // That's not quite right but it's close to correct.
- // https://en.wikipedia.org/wiki/Retina_display#Models
- displaydpi = scale * 110;
-}
- LOG(@"initimg return");
-
- return img;
-}
-
-void
-_flushmemscreen(Rectangle r)
-{
- LOG(@"_flushmemscreen(%d,%d,%d,%d)", r.min.x, r.min.y, Dx(r), Dy(r));
- 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(img, Pt(r.min.x, r.min.y))
- bytesPerRow:img->width*sizeof(u32int)];
- [AppDelegate
- performSelectorOnMainThread:@selector(callsetNeedsDisplayInRect:)
- withObject:[NSValue valueWithRect:NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r))]
- waitUntilDone:NO];
- }
-}
-
-void
-setmouse(Point p)
-{
- @autoreleasepool{
- NSPoint q;
-
- LOG(@"setmouse(%d,%d)", p.x, p.y);
- q = [win convertPointFromBacking:NSMakePoint(p.x, p.y)];
- LOG(@"(%g, %g) <- fromBacking", q.x, q.y);
- q = [myContent convertPoint:q toView:nil];
- LOG(@"(%g, %g) <- toWindow", q.x, q.y);
- q = [win convertPointToScreen:q];
- LOG(@"(%g, %g) <- toScreen", q.x, q.y);
- // Quartz has the origin of the "global display
- // coordinate space" at the top left of the primary
- // screen with y increasing downward, while Cocoa has
- // the origin at the bottom left of the primary screen
- // with y increasing upward. We flip the coordinate
- // with a negative sign and shift upward by the height
- // of the primary screen.
- q.y = NSScreen.screens[0].frame.size.height - q.y;
- LOG(@"(%g, %g) <- setmouse", q.x, q.y);
- CGWarpMouseCursorPosition(NSPointToCGPoint(q));
- CGAssociateMouseAndMouseCursorPosition(true);
- }
-}
-
-char*
-getsnarf(void)
-{
- NSPasteboard *pb;
- NSString *s;
-
- @autoreleasepool{
- pb = [NSPasteboard generalPasteboard];
-
- qlock(&snarfl);
- s = [pb stringForType:NSPasteboardTypeString];
- qunlock(&snarfl);
-
- if(s)
- return strdup((char *)[s UTF8String]);
- else
- return nil;
- }
-}
-
-void
-putsnarf(char *s)
-{
- NSArray *t;
- NSPasteboard *pb;
- NSString *str;
-
- if(strlen(s) >= SnarfSize)
- return;
-
- @autoreleasepool{
- t = [NSArray arrayWithObject:NSPasteboardTypeString];
- pb = [NSPasteboard generalPasteboard];
- str = [[NSString alloc] initWithUTF8String:s];
-
- qlock(&snarfl);
- [pb declareTypes:t owner:nil];
- [pb setString:str forType:NSPasteboardTypeString];
- qunlock(&snarfl);
- }
-}
-
-void
-kicklabel(char *label)
-{
- NSString *s;
-
- LOG(@"kicklabel(%s)", label);
- if(label == nil)
- return;
-
- @autoreleasepool{
- s = [[NSString alloc] initWithUTF8String:label];
- [AppDelegate
- performSelectorOnMainThread:@selector(callkicklabel:)
- withObject:s
- waitUntilDone:NO];
- }
-}
-
-void
-setcursor(Cursor *c, Cursor2 *c2)
-{
- Cursors cs;
-
- cs.c = c;
- cs.c2 = c2;
-
- [AppDelegate
- performSelectorOnMainThread:@selector(callsetcursor:)
- withObject:[NSValue valueWithPointer:&cs]
- waitUntilDone:YES];
-}
-
-void
-topwin(void)
-{
- [win
- performSelectorOnMainThread:
- @selector(makeKeyAndOrderFront:)
- withObject:nil
- waitUntilDone:YES];
-
- [NSApp activateIgnoringOtherApps:YES];
-}
-
-void
-resizeimg(void)
-{
- zlock();
- _drawreplacescreenimage(initimg());
-
- mouseresized = 1;
- zunlock();
- [myContent sendmouse:0];
-}
-
-void
-resizewindow(Rectangle r)
-{
- LOG(@"resizewindow %d %d %d %d", r.min.x, r.min.y, Dx(r), Dy(r));
- dispatch_async(dispatch_get_main_queue(), ^(void){
- NSSize s;
-
- s = [myContent convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))];
- [win setContentSize:s];
- });
-}
-
-static void
-setprocname(const char *s)
-{
- CFStringRef process_name;
-
- process_name = CFStringCreateWithBytes(nil, (uchar*)s, strlen(s), kCFStringEncodingUTF8, false);
-
- // Adapted from Chrome's mac_util.mm.
- // http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm
- //
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
- // plugin host, and could break at any time (although realistically it's only
- // likely to break in a new major release).
- // When 10.7 is available, check that this still works, and update this
- // comment for 10.8.
-
- // Private CFType used in these LaunchServices calls.
- typedef CFTypeRef PrivateLSASN;
- typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
- typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
- CFStringRef,
- CFStringRef,
- CFDictionaryRef*);
-
- static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
- NULL;
- static LSSetApplicationInformationItemType
- ls_set_application_information_item_func = NULL;
- static CFStringRef ls_display_name_key = NULL;
-
- static bool did_symbol_lookup = false;
- if (!did_symbol_lookup) {
- did_symbol_lookup = true;
- CFBundleRef launch_services_bundle =
- CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
- if (!launch_services_bundle) {
- fprint(2, "Failed to look up LaunchServices bundle\n");
- return;
- }
-
- ls_get_current_application_asn_func =
- (LSGetCurrentApplicationASNType)(
- CFBundleGetFunctionPointerForName(
- launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
- if (!ls_get_current_application_asn_func)
- fprint(2, "Could not find _LSGetCurrentApplicationASN\n");
-
- ls_set_application_information_item_func =
- (LSSetApplicationInformationItemType)(
- CFBundleGetFunctionPointerForName(
- launch_services_bundle,
- CFSTR("_LSSetApplicationInformationItem")));
- if (!ls_set_application_information_item_func)
- fprint(2, "Could not find _LSSetApplicationInformationItem\n");
-
- CFStringRef* key_pointer = (CFStringRef*)(
- CFBundleGetDataPointerForName(launch_services_bundle,
- CFSTR("_kLSDisplayNameKey")));
- ls_display_name_key = key_pointer ? *key_pointer : NULL;
- if (!ls_display_name_key)
- fprint(2, "Could not find _kLSDisplayNameKey\n");
-
- // Internally, this call relies on the Mach ports that are started up by the
- // Carbon Process Manager. In debug builds this usually happens due to how
- // the logging layers are started up; but in release, it isn't started in as
- // much of a defined order. So if the symbols had to be loaded, go ahead
- // and force a call to make sure the manager has been initialized and hence
- // the ports are opened.
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- }
- if (!ls_get_current_application_asn_func ||
- !ls_set_application_information_item_func ||
- !ls_display_name_key) {
- return;
- }
-
- PrivateLSASN asn = ls_get_current_application_asn_func();
- // Constant used by WebKit; what exactly it means is unknown.
- const int magic_session_constant = -2;
- OSErr err =
- ls_set_application_information_item_func(magic_session_constant, asn,
- ls_display_name_key,
- process_name,
- NULL /* optional out param */);
- if(err != noErr)
- fprint(2, "Call to set process name failed\n");
-}
diff --git a/src/cmd/devdraw/cocoa-srv.c b/src/cmd/devdraw/cocoa-srv.c
@@ -1,427 +0,0 @@
-/*
- * Window system protocol server.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include <draw.h>
-#include <memdraw.h>
-#include <keyboard.h>
-#include <mouse.h>
-#include <cursor.h>
-#include <drawfcall.h>
-#include "cocoa-screen.h"
-#include "devdraw.h"
-
-typedef struct Kbdbuf Kbdbuf;
-typedef struct Mousebuf Mousebuf;
-typedef struct Fdbuf Fdbuf;
-typedef struct Tagbuf Tagbuf;
-
-struct Kbdbuf
-{
- Rune r[256];
- int ri;
- int wi;
- int stall;
-};
-
-struct Mousebuf
-{
- Mouse m[256];
- Mouse last;
- int ri;
- int wi;
- int stall;
-};
-
-struct Tagbuf
-{
- int t[256];
- int ri;
- int wi;
-};
-
-Kbdbuf kbd;
-Mousebuf mouse;
-Tagbuf kbdtags;
-Tagbuf mousetags;
-
-void runmsg(Wsysmsg*);
-void replymsg(Wsysmsg*);
-void matchkbd(void);
-void matchmouse(void);
-
-
-QLock lk;
-void
-zlock(void)
-{
- qlock(&lk);
-}
-
-void
-zunlock(void)
-{
- qunlock(&lk);
-}
-
-int trace = 0;
-
-void
-servep9p(void)
-{
- uchar buf[4], *mbuf;
- int nmbuf, n, nn;
- Wsysmsg m;
-
- fmtinstall('W', drawfcallfmt);
-
- mbuf = nil;
- nmbuf = 0;
- while((n = read(3, buf, 4)) == 4){
- GET(buf, n);
- if(n > nmbuf){
- free(mbuf);
- mbuf = malloc(4+n);
- if(mbuf == nil)
- sysfatal("malloc: %r");
- nmbuf = n;
- }
- memmove(mbuf, buf, 4);
- nn = readn(3, mbuf+4, n-4);
- if(nn != n-4)
- sysfatal("eof during message");
-
- /* pick off messages one by one */
- if(convM2W(mbuf, nn+4, &m) <= 0)
- sysfatal("cannot convert message");
- if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
- runmsg(&m);
- }
-}
-
-void
-replyerror(Wsysmsg *m)
-{
- char err[256];
-
- rerrstr(err, sizeof err);
- m->type = Rerror;
- m->error = err;
- replymsg(m);
-}
-
-/*
- * Handle a single wsysmsg.
- * Might queue for later (kbd, mouse read)
- */
-void
-runmsg(Wsysmsg *m)
-{
- static uchar buf[65536];
- int n;
- Memimage *i;
-
- switch(m->type){
- case Tinit:
- memimageinit();
- i = attachscreen(m->label, m->winsize);
- _initdisplaymemimage(i);
- replymsg(m);
- break;
-
- case Trdmouse:
- zlock();
- mousetags.t[mousetags.wi++] = m->tag;
- if(mousetags.wi == nelem(mousetags.t))
- mousetags.wi = 0;
- if(mousetags.wi == mousetags.ri)
- sysfatal("too many queued mouse reads");
- mouse.stall = 0;
- matchmouse();
- zunlock();
- break;
-
- case Trdkbd:
- zlock();
- kbdtags.t[kbdtags.wi++] = m->tag;
- if(kbdtags.wi == nelem(kbdtags.t))
- kbdtags.wi = 0;
- if(kbdtags.wi == kbdtags.ri)
- sysfatal("too many queued keyboard reads");
- kbd.stall = 0;
- matchkbd();
- zunlock();
- break;
-
- case Tmoveto:
- setmouse(m->mouse.xy);
- replymsg(m);
- break;
-
- case Tcursor:
- if(m->arrowcursor)
- setcursor(nil, nil);
- else
- setcursor(&m->cursor, nil);
- replymsg(m);
- break;
-
- case Tcursor2:
- if(m->arrowcursor)
- setcursor(nil, nil);
- else
- setcursor(&m->cursor, &m->cursor2);
- replymsg(m);
- break;
-
- case Tbouncemouse:
- // _xbouncemouse(&m->mouse);
- replymsg(m);
- break;
-
- case Tlabel:
- kicklabel(m->label);
- replymsg(m);
- break;
-
- case Trdsnarf:
- m->snarf = getsnarf();
- replymsg(m);
- free(m->snarf);
- break;
-
- case Twrsnarf:
- putsnarf(m->snarf);
- replymsg(m);
- break;
-
- case Trddraw:
- zlock();
- n = m->count;
- if(n > sizeof buf)
- n = sizeof buf;
- n = _drawmsgread(buf, n);
- if(n < 0)
- replyerror(m);
- else{
- m->count = n;
- m->data = buf;
- replymsg(m);
- }
- zunlock();
- break;
-
- case Twrdraw:
- zlock();
- if(_drawmsgwrite(m->data, m->count) < 0)
- replyerror(m);
- else
- replymsg(m);
- zunlock();
- break;
-
- case Ttop:
- topwin();
- replymsg(m);
- break;
-
- case Tresize:
- resizewindow(m->rect);
- replymsg(m);
- break;
- }
-}
-
-/*
- * Reply to m.
- */
-QLock replylock;
-void
-replymsg(Wsysmsg *m)
-{
- int n;
- static uchar *mbuf;
- static int nmbuf;
-
- /* T -> R msg */
- if(m->type%2 == 0)
- m->type++;
-
- if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
- /* copy to output buffer */
- n = sizeW2M(m);
-
- qlock(&replylock);
- if(n > nmbuf){
- free(mbuf);
- mbuf = malloc(n);
- if(mbuf == nil)
- sysfatal("out of memory");
- nmbuf = n;
- }
- convW2M(m, mbuf, n);
- if(write(4, mbuf, n) != n)
- sysfatal("write: %r");
- qunlock(&replylock);
-}
-
-/*
- * Match queued kbd reads with queued kbd characters.
- */
-void
-matchkbd(void)
-{
- Wsysmsg m;
-
- if(kbd.stall)
- return;
- while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){
- m.type = Rrdkbd;
- m.tag = kbdtags.t[kbdtags.ri++];
- if(kbdtags.ri == nelem(kbdtags.t))
- kbdtags.ri = 0;
- m.rune = kbd.r[kbd.ri++];
- if(kbd.ri == nelem(kbd.r))
- kbd.ri = 0;
- replymsg(&m);
- }
-}
-
-/*
- * Match queued mouse reads with queued mouse events.
- */
-void
-matchmouse(void)
-{
- Wsysmsg m;
-
- while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){
- m.type = Rrdmouse;
- m.tag = mousetags.t[mousetags.ri++];
- if(mousetags.ri == nelem(mousetags.t))
- mousetags.ri = 0;
- m.mouse = mouse.m[mouse.ri];
- m.resized = mouseresized;
- mouseresized = 0;
- /*
- if(m.resized)
- fprint(2, "sending resize\n");
- */
- mouse.ri++;
- if(mouse.ri == nelem(mouse.m))
- mouse.ri = 0;
- replymsg(&m);
- }
-}
-
-void
-mousetrack(int x, int y, int b, uint ms)
-{
- Mouse *m;
-
- if(x < mouserect.min.x)
- x = mouserect.min.x;
- if(x > mouserect.max.x)
- x = mouserect.max.x;
- if(y < mouserect.min.y)
- y = mouserect.min.y;
- if(y > mouserect.max.y)
- y = mouserect.max.y;
-
- zlock();
- // If reader has stopped reading, don't bother.
- // If reader is completely caught up, definitely queue.
- // Otherwise, queue only button change events.
- if(!mouse.stall)
- if(mouse.wi == mouse.ri || mouse.last.buttons != b){
- m = &mouse.last;
- m->xy.x = x;
- m->xy.y = y;
- m->buttons = b;
- m->msec = ms;
-
- mouse.m[mouse.wi] = *m;
- if(++mouse.wi == nelem(mouse.m))
- mouse.wi = 0;
- if(mouse.wi == mouse.ri){
- mouse.stall = 1;
- mouse.ri = 0;
- mouse.wi = 1;
- mouse.m[0] = *m;
- }
- matchmouse();
- }
- zunlock();
-}
-
-void
-kputc(int c)
-{
- zlock();
- kbd.r[kbd.wi++] = c;
- if(kbd.wi == nelem(kbd.r))
- kbd.wi = 0;
- if(kbd.ri == kbd.wi)
- kbd.stall = 1;
- matchkbd();
- zunlock();
-}
-
-static int alting;
-
-void
-abortcompose(void)
-{
- if(alting)
- keystroke(Kalt);
-}
-
-void
-keystroke(int c)
-{
- static Rune k[10];
- static int nk;
- int i;
-
- if(c == Kalt){
- alting = !alting;
- nk = 0;
- return;
- }
- if(c == Kcmd+'r') {
- if(forcedpi)
- forcedpi = 0;
- else if(displaydpi >= 200)
- forcedpi = 100;
- else
- forcedpi = 225;
- resizeimg();
- return;
- }
- if(!alting){
- kputc(c);
- return;
- }
- if(nk >= nelem(k)) // should not happen
- nk = 0;
- k[nk++] = c;
- c = _latin1(k, nk);
- if(c > 0){
- alting = 0;
- kputc(c);
- nk = 0;
- return;
- }
- if(c == -1){
- alting = 0;
- for(i=0; i<nk; i++)
- kputc(k[i]);
- nk = 0;
- return;
- }
- // need more input
- return;
-}
diff --git a/src/cmd/devdraw/osx-draw.c b/src/cmd/devdraw/mac-draw.c
diff --git a/src/cmd/devdraw/cocoa-screen.h b/src/cmd/devdraw/mac-screen.h
diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m
@@ -0,0 +1,1248 @@
+#define Cursor OSXCursor
+#define Point OSXPoint
+#define Rect OSXRect
+
+#import <Cocoa/Cocoa.h>
+#import <Metal/Metal.h>
+#import <QuartzCore/CAMetalLayer.h>
+
+#undef Cursor
+#undef Point
+#undef Rect
+
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <keyboard.h>
+#include <cursor.h>
+#include "mac-screen.h"
+#include "devdraw.h"
+#include "bigarrow.h"
+#include "glendapng.h"
+
+AUTOFRAMEWORK(Cocoa)
+AUTOFRAMEWORK(Metal)
+AUTOFRAMEWORK(QuartzCore)
+
+#define LOG if(0)NSLog
+
+static void setprocname(const char*);
+static uint keycvt(uint);
+static uint msec(void);
+static Memimage* initimg(void);
+
+void
+usage(void)
+{
+ fprint(2, "usage: devdraw (don't run directly)\n");
+ threadexitsall("usage");
+}
+
+
+@interface AppDelegate : NSObject<NSApplicationDelegate,NSWindowDelegate>
++ (void)makewin:(NSValue *)v;
++ (void)callkicklabel:(NSString *)v;
++ (void)callsetNeedsDisplayInRect:(NSValue *)v;
++ (void)callsetcursor:(NSValue *)v;
+@end
+@interface DevDrawView : NSView<NSTextInputClient>
+- (void)clearInput;
+- (void)getmouse:(NSEvent *)e;
+- (void)sendmouse:(NSUInteger)b;
+- (void)resetLastInputRect;
+- (void)enlargeLastInputRect:(NSRect)r;
+@end
+@interface DrawLayer : CAMetalLayer
+@end
+
+static AppDelegate *myApp = NULL;
+static DevDrawView *myContent = NULL;
+static NSWindow *win = NULL;
+static NSCursor *currentCursor = NULL;
+
+static DrawLayer *layer;
+static id<MTLDevice> device;
+static id<MTLCommandQueue> commandQueue;
+static id<MTLTexture> texture;
+
+static Memimage *img = NULL;
+
+static QLock snarfl;
+
+void
+threadmain(int argc, char **argv)
+{
+ /*
+ * Move the protocol off stdin/stdout so that
+ * any inadvertent prints don't screw things up.
+ */
+ dup(0,3);
+ dup(1,4);
+ close(0);
+ close(1);
+ open("/dev/null", OREAD);
+ open("/dev/null", OWRITE);
+
+ ARGBEGIN{
+ case 'D': /* for good ps -a listings */
+ break;
+ case 'f': /* fall through for backward compatibility */
+ case 'g':
+ case 'b':
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ setprocname(argv0);
+
+ @autoreleasepool{
+ [NSApplication sharedApplication];
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+ myApp = [AppDelegate new];
+ [NSApp setDelegate:myApp];
+ [NSApp run];
+ }
+}
+
+
+void
+callservep9p(void *v)
+{
+ USED(v);
+
+ servep9p();
+ [NSApp terminate:myApp];
+}
+
+@implementation AppDelegate
+
++ (void)makewin:(NSValue *)v
+{
+ NSRect r, sr;
+ Rectangle wr;
+ int set;
+ char *s;
+ NSArray *allDevices;
+
+ const NSWindowStyleMask Winstyle = NSWindowStyleMaskTitled
+ | NSWindowStyleMaskClosable
+ | NSWindowStyleMaskMiniaturizable
+ | NSWindowStyleMaskResizable;
+
+ sr = [[NSScreen mainScreen] frame];
+ r = [[NSScreen mainScreen] visibleFrame];
+
+ s = [v pointerValue];
+ LOG(@"makewin(%s)", s);
+ if(s && *s){
+ if(parsewinsize(s, &wr, &set) < 0)
+ sysfatal("%r");
+ }else{
+ wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
+ set = 0;
+ }
+
+ r.origin.x = wr.min.x;
+ r.origin.y = sr.size.height-wr.max.y; /* winsize is top-left-based */
+ r.size.width = fmin(Dx(wr), r.size.width);
+ r.size.height = fmin(Dy(wr), r.size.height);
+ r = [NSWindow contentRectForFrameRect:r styleMask:Winstyle];
+
+ win = [[NSWindow alloc]
+ initWithContentRect:r
+ styleMask:Winstyle
+ backing:NSBackingStoreBuffered defer:NO];
+ [win setTitle:@"devdraw"];
+
+ if(!set)
+ [win center];
+ [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ [win setContentMinSize:NSMakeSize(64,64)];
+ [win setOpaque:YES];
+ [win setRestorable:NO];
+ [win setAcceptsMouseMovedEvents:YES];
+ [win setDelegate:myApp];
+
+ myContent = [DevDrawView new];
+ [win setContentView:myContent];
+ [myContent setWantsLayer:YES];
+ [myContent setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
+
+ device = nil;
+ allDevices = MTLCopyAllDevices();
+ for(id mtlDevice in allDevices) {
+ if ([mtlDevice isLowPower] && ![mtlDevice isRemovable]) {
+ device = mtlDevice;
+ break;
+ }
+ }
+ if(!device)
+ device = MTLCreateSystemDefaultDevice();
+
+ commandQueue = [device newCommandQueue];
+
+ layer = (DrawLayer *)[myContent layer];
+ layer.device = device;
+ 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.
+ {
+ CALayer *stub = [CALayer layer];
+ stub.frame = CGRectMake(0, 0, 1, 1);
+ [stub setNeedsDisplay];
+ [layer addSublayer:stub];
+ }
+
+ [NSEvent setMouseCoalescingEnabled:NO];
+
+ topwin();
+}
+
++ (void)callkicklabel:(NSString *)s
+{
+ LOG(@"callkicklabel(%@)", s);
+ [win setTitle:s];
+ [[NSApp dockTile] setBadgeLabel:s];
+}
+
+
++ (void)callsetNeedsDisplayInRect:(NSValue *)v
+{
+ NSRect r;
+ dispatch_time_t time;
+
+ r = [v rectValue];
+ LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
+ r = [win convertRectFromBacking:r];
+ LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
+ [layer setNeedsDisplayInRect:r];
+
+ time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC);
+ dispatch_after(time, dispatch_get_main_queue(), ^(void){
+ [layer setNeedsDisplayInRect:r];
+ });
+
+ [myContent enlargeLastInputRect:r];
+}
+
+typedef struct Cursors Cursors;
+struct Cursors {
+ Cursor *c;
+ Cursor2 *c2;
+};
+
++ (void)callsetcursor:(NSValue *)v
+{
+ Cursors *cs;
+ Cursor *c;
+ Cursor2 *c2;
+ NSBitmapImageRep *r, *r2;
+ NSImage *i;
+ NSPoint p;
+ uchar *plane[5], *plane2[5];
+ uint b;
+
+ cs = [v pointerValue];
+ c = cs->c;
+ if(!c)
+ c = &bigarrow;
+ c2 = cs->c2;
+ if(!c2)
+ c2 = &bigarrow2;
+
+ r = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:nil
+ pixelsWide:16
+ pixelsHigh:16
+ bitsPerSample:1
+ samplesPerPixel:2
+ hasAlpha:YES
+ isPlanar:YES
+ colorSpaceName:NSDeviceWhiteColorSpace
+ bytesPerRow:2
+ bitsPerPixel:0];
+ [r getBitmapDataPlanes:plane];
+ for(b=0; b<nelem(c->set); b++){
+ plane[0][b] = ~c->set[b] & c->clr[b];
+ plane[1][b] = c->set[b] | c->clr[b];
+ }
+
+ r2 = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:nil
+ pixelsWide:32
+ pixelsHigh:32
+ bitsPerSample:1
+ samplesPerPixel:2
+ hasAlpha:YES
+ isPlanar:YES
+ colorSpaceName:NSDeviceWhiteColorSpace
+ bytesPerRow:4
+ bitsPerPixel:0];
+ [r2 getBitmapDataPlanes:plane2];
+ for(b=0; b<nelem(c2->set); b++){
+ plane2[0][b] = ~c2->set[b] & c2->clr[b];
+ plane2[1][b] = c2->set[b] | c2->clr[b];
+ }
+
+ // For checking out the cursor bitmap image
+/*
+ static BOOL saveimg = YES;
+ if(saveimg){
+ NSData *data = [r representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
+ [data writeToFile: @"/tmp/r.bmp" atomically: NO];
+ data = [r2 representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
+ [data writeToFile: @"/tmp/r2.bmp" atomically: NO];
+ saveimg = NO;
+ }
+*/
+
+ i = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)];
+ [i addRepresentation:r2];
+ [i addRepresentation:r];
+
+ p = NSMakePoint(-c->offset.x, -c->offset.y);
+ currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
+
+ [win invalidateCursorRectsForView:myContent];
+}
+
+- (void)applicationDidFinishLaunching:(id)arg
+{
+ NSMenu *m, *sm;
+ NSData *d;
+ NSImage *i;
+
+ LOG(@"applicationDidFinishLaunching");
+
+ sm = [NSMenu new];
+ [sm addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
+ [sm addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"];
+ [sm addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
+ m = [NSMenu new];
+ [m addItemWithTitle:@"DEVDRAW" action:NULL keyEquivalent:@""];
+ [m setSubmenu:sm forItem:[m itemWithTitle:@"DEVDRAW"]];
+ [NSApp setMainMenu:m];
+
+ d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
+ i = [[NSImage alloc] initWithData:d];
+ [NSApp setApplicationIconImage:i];
+ [[NSApp dockTile] display];
+
+ 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;
+}
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+ if(![myContent inLiveResize] && img) {
+ resizeimg();
+ }
+}
+
+- (void)windowDidBecomeKey:(id)arg
+{
+ [myContent sendmouse:0];
+}
+
+@end
+
+@implementation DevDrawView
+{
+ NSMutableString *_tmpText;
+ NSRange _markedRange;
+ NSRange _selectedRange;
+ NSRect _lastInputRect; // The view is flipped, this is not.
+ BOOL _tapping;
+ NSUInteger _tapFingers;
+ NSUInteger _tapTime;
+}
+
+- (id)init
+{
+ LOG(@"View init");
+ self = [super init];
+ [self setAllowedTouchTypes:NSTouchTypeMaskDirect|NSTouchTypeMaskIndirect];
+ _tmpText = [[NSMutableString alloc] initWithCapacity:2];
+ _markedRange = NSMakeRange(NSNotFound, 0);
+ _selectedRange = NSMakeRange(0, 0);
+ return self;
+}
+
+- (CALayer *)makeBackingLayer
+{
+ LOG(@"makeBackingLayer");
+ return [DrawLayer layer];
+}
+
+- (BOOL)wantsUpdateLayer
+{
+ return YES;
+}
+
+- (BOOL)isOpaque
+{
+ return YES;
+}
+
+- (BOOL)isFlipped
+{
+ return YES;
+}
+
+- (BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+- (void)mouseMoved:(NSEvent*)e{ [self getmouse:e];}
+- (void)mouseDown:(NSEvent*)e{ [self getmouse:e];}
+- (void)mouseDragged:(NSEvent*)e{ [self getmouse:e];}
+- (void)mouseUp:(NSEvent*)e{ [self getmouse:e];}
+- (void)otherMouseDown:(NSEvent*)e{ [self getmouse:e];}
+- (void)otherMouseDragged:(NSEvent*)e{ [self getmouse:e];}
+- (void)otherMouseUp:(NSEvent*)e{ [self getmouse:e];}
+- (void)rightMouseDown:(NSEvent*)e{ [self getmouse:e];}
+- (void)rightMouseDragged:(NSEvent*)e{ [self getmouse:e];}
+- (void)rightMouseUp:(NSEvent*)e{ [self getmouse:e];}
+
+- (void)scrollWheel:(NSEvent*)e
+{
+ NSInteger s;
+
+ s = [e scrollingDeltaY];
+ if(s > 0)
+ [self sendmouse:8];
+ else if (s < 0)
+ [self sendmouse:16];
+}
+
+- (void)keyDown:(NSEvent*)e
+{
+ LOG(@"keyDown to interpret");
+
+ [self interpretKeyEvents:[NSArray arrayWithObject:e]];
+
+ [self resetLastInputRect];
+}
+
+- (void)flagsChanged:(NSEvent*)e
+{
+ static NSEventModifierFlags omod;
+ NSEventModifierFlags m;
+ uint b;
+
+ LOG(@"flagsChanged");
+ m = [e modifierFlags];
+
+ b = [NSEvent pressedMouseButtons];
+ b = (b&~6) | (b&4)>>1 | (b&2)<<1;
+ if(b){
+ if(m & ~omod & NSEventModifierFlagControl)
+ b |= 1;
+ if(m & ~omod & NSEventModifierFlagOption)
+ b |= 2;
+ if(m & ~omod & NSEventModifierFlagCommand)
+ b |= 4;
+ [self sendmouse:b];
+ }else if(m & ~omod & NSEventModifierFlagOption)
+ keystroke(Kalt);
+
+ omod = m;
+}
+
+- (void)magnifyWithEvent:(NSEvent*)e
+{
+ if(fabs([e magnification]) > 0.02)
+ [[self window] toggleFullScreen:nil];
+}
+
+- (void)touchesBeganWithEvent:(NSEvent*)e
+{
+ _tapping = YES;
+ _tapFingers = [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count;
+ _tapTime = msec();
+}
+- (void)touchesMovedWithEvent:(NSEvent*)e
+{
+ _tapping = NO;
+}
+- (void)touchesEndedWithEvent:(NSEvent*)e
+{
+ if(_tapping
+ && [e touchesMatchingPhase:NSTouchPhaseTouching inView:nil].count == 0
+ && msec() - _tapTime < 250){
+ switch(_tapFingers){
+ case 3:
+ [self sendmouse:2];
+ [self sendmouse:0];
+ break;
+ case 4:
+ [self sendmouse:2];
+ [self sendmouse:1];
+ [self sendmouse:0];
+ break;
+ }
+ _tapping = NO;
+ }
+}
+- (void)touchesCancelledWithEvent:(NSEvent*)e
+{
+ _tapping = NO;
+}
+
+- (void)getmouse:(NSEvent *)e
+{
+ NSUInteger b;
+ NSEventModifierFlags m;
+
+ b = [NSEvent pressedMouseButtons];
+ b = b&~6 | (b&4)>>1 | (b&2)<<1;
+ b = mouseswap(b);
+
+ if(b == 1){
+ m = [e modifierFlags];
+ if(m & NSEventModifierFlagOption){
+ abortcompose();
+ b = 2;
+ }else
+ if(m & NSEventModifierFlagCommand)
+ b = 4;
+ }
+ [self sendmouse:b];
+}
+
+- (void)sendmouse:(NSUInteger)b
+{
+ NSPoint p;
+
+ p = [self.window convertPointToBacking:
+ [self.window mouseLocationOutsideOfEventStream]];
+ p.y = Dy(mouserect) - p.y;
+ // LOG(@"(%g, %g) <- sendmouse(%d)", p.x, p.y, (uint)b);
+ mousetrack(p.x, p.y, b, msec());
+ if(b && _lastInputRect.size.width && _lastInputRect.size.height)
+ [self resetLastInputRect];
+}
+
+- (void)resetCursorRects {
+ [super resetCursorRects];
+ [self addCursorRect:self.bounds cursor:currentCursor];
+}
+
+- (void)viewDidEndLiveResize
+{
+ [super viewDidEndLiveResize];
+ if(img)
+ resizeimg();
+}
+
+- (void)viewDidChangeBackingProperties
+{
+ [super viewDidChangeBackingProperties];
+ if(img)
+ resizeimg();
+}
+
+// conforms to protocol NSTextInputClient
+- (BOOL)hasMarkedText
+{
+ LOG(@"hasMarkedText");
+ return _markedRange.location != NSNotFound;
+}
+- (NSRange)markedRange
+{
+ LOG(@"markedRange");
+ return _markedRange;
+}
+- (NSRange)selectedRange
+{
+ LOG(@"selectedRange");
+ return _selectedRange;
+}
+- (void)setMarkedText:(id)string
+ selectedRange:(NSRange)sRange
+ replacementRange:(NSRange)rRange
+{
+ NSString *str;
+
+ LOG(@"setMarkedText: %@ (%ld, %ld) (%ld, %ld)", string,
+ sRange.location, sRange.length,
+ rRange.location, rRange.length);
+
+ [self clearInput];
+
+ if([string isKindOfClass:[NSAttributedString class]])
+ str = [string string];
+ else
+ str = string;
+
+ if(rRange.location == NSNotFound){
+ if(_markedRange.location != NSNotFound){
+ rRange = _markedRange;
+ }else{
+ rRange = _selectedRange;
+ }
+ }
+
+ if(str.length == 0){
+ [_tmpText deleteCharactersInRange:rRange];
+ [self unmarkText];
+ }else{
+ _markedRange = NSMakeRange(rRange.location, str.length);
+ [_tmpText replaceCharactersInRange:rRange withString:str];
+ }
+ _selectedRange.location = rRange.location + sRange.location;
+ _selectedRange.length = sRange.length;
+
+ if(_tmpText.length){
+ uint i;
+ LOG(@"text length %ld", _tmpText.length);
+ for(i = 0; i <= _tmpText.length; ++i){
+ if(i == _markedRange.location)
+ keystroke('[');
+ if(_selectedRange.length){
+ if(i == _selectedRange.location)
+ keystroke('{');
+ if(i == NSMaxRange(_selectedRange))
+ keystroke('}');
+ }
+ if(i == NSMaxRange(_markedRange))
+ keystroke(']');
+ if(i < _tmpText.length)
+ keystroke([_tmpText characterAtIndex:i]);
+ }
+ int l;
+ l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
+ + (_selectedRange.length > 0);
+ LOG(@"move left %d", l);
+ for(i = 0; i < l; ++i)
+ keystroke(Kleft);
+ }
+
+ LOG(@"text: \"%@\" (%ld,%ld) (%ld,%ld)", _tmpText,
+ _markedRange.location, _markedRange.length,
+ _selectedRange.location, _selectedRange.length);
+}
+- (void)unmarkText
+{
+ //NSUInteger i;
+ NSUInteger len;
+
+ LOG(@"unmarkText");
+ len = [_tmpText length];
+ //for(i = 0; i < len; ++i)
+ // keystroke([_tmpText characterAtIndex:i]);
+ [_tmpText deleteCharactersInRange:NSMakeRange(0, len)];
+ _markedRange = NSMakeRange(NSNotFound, 0);
+ _selectedRange = NSMakeRange(0, 0);
+}
+- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText
+{
+ LOG(@"validAttributesForMarkedText");
+ return @[];
+}
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r
+ actualRange:(NSRangePointer)actualRange
+{
+ NSRange sr;
+ NSAttributedString *s;
+
+ LOG(@"attributedSubstringForProposedRange: (%ld, %ld) (%ld, %ld)",
+ r.location, r.length, actualRange->location, actualRange->length);
+ sr = NSMakeRange(0, [_tmpText length]);
+ sr = NSIntersectionRange(sr, r);
+ if(actualRange)
+ *actualRange = sr;
+ LOG(@"use range: %ld, %ld", sr.location, sr.length);
+ s = nil;
+ if(sr.length)
+ s = [[NSAttributedString alloc]
+ initWithString:[_tmpText substringWithRange:sr]];
+ LOG(@" return %@", s);
+ return s;
+}
+- (void)insertText:(id)s
+ replacementRange:(NSRange)r
+{
+ NSUInteger i;
+ NSUInteger len;
+
+ LOG(@"insertText: %@ replacementRange: %ld, %ld", s, r.location, r.length);
+
+ [self clearInput];
+
+ len = [s length];
+ for(i = 0; i < len; ++i)
+ keystroke([s characterAtIndex:i]);
+ [_tmpText deleteCharactersInRange:NSMakeRange(0, _tmpText.length)];
+ _markedRange = NSMakeRange(NSNotFound, 0);
+ _selectedRange = NSMakeRange(0, 0);
+}
+- (NSUInteger)characterIndexForPoint:(NSPoint)point
+{
+ LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
+ return 0;
+}
+- (NSRect)firstRectForCharacterRange:(NSRange)r
+ actualRange:(NSRangePointer)actualRange
+{
+ LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
+ r.location, r.length, actualRange->location, actualRange->length);
+ if(actualRange)
+ *actualRange = r;
+ return [[self window] convertRectToScreen:_lastInputRect];
+}
+- (void)doCommandBySelector:(SEL)s
+{
+ NSEvent *e;
+ NSEventModifierFlags m;
+ uint c, k;
+
+ LOG(@"doCommandBySelector (%@)", NSStringFromSelector(s));
+
+ e = [NSApp currentEvent];
+ c = [[e characters] characterAtIndex:0];
+ k = keycvt(c);
+ LOG(@"keyDown: character0: 0x%x -> 0x%x", c, k);
+ m = [e modifierFlags];
+
+ if(m & NSEventModifierFlagCommand){
+ if((m & NSEventModifierFlagShift) && 'a' <= k && k <= 'z')
+ k += 'A' - 'a';
+ if(' '<=k && k<='~')
+ k += Kcmd;
+ }
+ if(k>0)
+ keystroke(k);
+}
+
+// Helper for managing input rect approximately
+- (void)resetLastInputRect
+{
+ LOG(@"resetLastInputRect");
+ _lastInputRect.origin.x = 0.0;
+ _lastInputRect.origin.y = 0.0;
+ _lastInputRect.size.width = 0.0;
+ _lastInputRect.size.height = 0.0;
+}
+
+- (void)enlargeLastInputRect:(NSRect)r
+{
+ r.origin.y = [self bounds].size.height - r.origin.y - r.size.height;
+ _lastInputRect = NSUnionRect(_lastInputRect, r);
+ LOG(@"update last input rect (%g, %g, %g, %g)",
+ _lastInputRect.origin.x, _lastInputRect.origin.y,
+ _lastInputRect.size.width, _lastInputRect.size.height);
+}
+
+- (void)clearInput
+{
+ if(_tmpText.length){
+ uint i;
+ int l;
+ l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
+ + (_selectedRange.length > 0);
+ LOG(@"move right %d", l);
+ for(i = 0; i < l; ++i)
+ keystroke(Kright);
+ l = _tmpText.length+2+2*(_selectedRange.length > 0);
+ LOG(@"backspace %d", l);
+ for(uint i = 0; i < l; ++i)
+ keystroke(Kbs);
+ }
+}
+
+@end
+
+@implementation DrawLayer
+
+- (void)display
+{
+ id<MTLCommandBuffer> cbuf;
+ id<MTLBlitCommandEncoder> blit;
+
+ LOG(@"display");
+
+ cbuf = [commandQueue commandBuffer];
+
+ LOG(@"display query drawable");
+
+@autoreleasepool{
+ id<CAMetalDrawable> drawable;
+
+ drawable = [layer nextDrawable];
+ if(!drawable){
+ LOG(@"display couldn't get drawable");
+ [self setNeedsDisplay];
+ return;
+ }
+
+ LOG(@"display got drawable");
+
+ 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
+msec(void)
+{
+ return nsec()/1000000;
+}
+
+static uint
+keycvt(uint code)
+{
+ switch(code){
+ case '\r': return '\n';
+ case 127: return '\b';
+ case NSUpArrowFunctionKey: return Kup;
+ case NSDownArrowFunctionKey: return Kdown;
+ case NSLeftArrowFunctionKey: return Kleft;
+ case NSRightArrowFunctionKey: return Kright;
+ case NSInsertFunctionKey: return Kins;
+ case NSDeleteFunctionKey: return Kdel;
+ case NSHomeFunctionKey: return Khome;
+ case NSEndFunctionKey: return Kend;
+ case NSPageUpFunctionKey: return Kpgup;
+ case NSPageDownFunctionKey: return Kpgdown;
+ case NSF1FunctionKey: return KF|1;
+ case NSF2FunctionKey: return KF|2;
+ case NSF3FunctionKey: return KF|3;
+ case NSF4FunctionKey: return KF|4;
+ case NSF5FunctionKey: return KF|5;
+ case NSF6FunctionKey: return KF|6;
+ case NSF7FunctionKey: return KF|7;
+ case NSF8FunctionKey: return KF|8;
+ case NSF9FunctionKey: return KF|9;
+ case NSF10FunctionKey: return KF|10;
+ case NSF11FunctionKey: return KF|11;
+ case NSF12FunctionKey: return KF|12;
+ case NSBeginFunctionKey:
+ case NSPrintScreenFunctionKey:
+ case NSScrollLockFunctionKey:
+ case NSF13FunctionKey:
+ case NSF14FunctionKey:
+ case NSF15FunctionKey:
+ case NSF16FunctionKey:
+ case NSF17FunctionKey:
+ case NSF18FunctionKey:
+ case NSF19FunctionKey:
+ case NSF20FunctionKey:
+ case NSF21FunctionKey:
+ case NSF22FunctionKey:
+ case NSF23FunctionKey:
+ case NSF24FunctionKey:
+ case NSF25FunctionKey:
+ case NSF26FunctionKey:
+ case NSF27FunctionKey:
+ case NSF28FunctionKey:
+ case NSF29FunctionKey:
+ case NSF30FunctionKey:
+ case NSF31FunctionKey:
+ case NSF32FunctionKey:
+ case NSF33FunctionKey:
+ case NSF34FunctionKey:
+ case NSF35FunctionKey:
+ case NSPauseFunctionKey:
+ case NSSysReqFunctionKey:
+ case NSBreakFunctionKey:
+ case NSResetFunctionKey:
+ case NSStopFunctionKey:
+ case NSMenuFunctionKey:
+ case NSUserFunctionKey:
+ case NSSystemFunctionKey:
+ case NSPrintFunctionKey:
+ case NSClearLineFunctionKey:
+ case NSClearDisplayFunctionKey:
+ case NSInsertLineFunctionKey:
+ case NSDeleteLineFunctionKey:
+ case NSInsertCharFunctionKey:
+ case NSDeleteCharFunctionKey:
+ case NSPrevFunctionKey:
+ case NSNextFunctionKey:
+ case NSSelectFunctionKey:
+ case NSExecuteFunctionKey:
+ case NSUndoFunctionKey:
+ case NSRedoFunctionKey:
+ case NSFindFunctionKey:
+ case NSHelpFunctionKey:
+ case NSModeSwitchFunctionKey: return 0;
+ default: return code;
+ }
+}
+
+Memimage*
+attachscreen(char *label, char *winsize)
+{
+ LOG(@"attachscreen(%s, %s)", label, winsize);
+ [AppDelegate
+ performSelectorOnMainThread:@selector(makewin:)
+ withObject:[NSValue valueWithPointer:winsize]
+ waitUntilDone:YES];
+ kicklabel(label);
+ setcursor(nil, nil);
+ mouseresized = 0;
+ return initimg();
+}
+
+static Memimage*
+initimg(void)
+{
+@autoreleasepool{
+ CGFloat scale;
+ NSSize size;
+ MTLTextureDescriptor *textureDesc;
+
+ size = [myContent convertSizeToBacking:[myContent bounds].size];
+ mouserect = Rect(0, 0, size.width, size.height);
+
+ LOG(@"initimg %.0f %.0f", size.width, size.height);
+
+ img = allocmemimage(mouserect, XRGB32);
+ if(img == nil)
+ panic("allocmemimage: %r");
+ if(img->data == nil)
+ panic("img->data == nil");
+
+ textureDesc = [MTLTextureDescriptor
+ texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+ width:size.width
+ height:size.height
+ mipmapped:NO];
+ textureDesc.allowGPUOptimizedContents = YES;
+ textureDesc.usage = MTLTextureUsageShaderRead;
+ textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
+ texture = [device newTextureWithDescriptor:textureDesc];
+
+ scale = [win backingScaleFactor];
+ [layer setDrawableSize:size];
+ [layer setContentsScale:scale];
+
+ // NOTE: This is not really the display DPI.
+ // On retina, scale is 2; otherwise it is 1.
+ // This formula gives us 220 for retina, 110 otherwise.
+ // That's not quite right but it's close to correct.
+ // https://en.wikipedia.org/wiki/Retina_display#Models
+ displaydpi = scale * 110;
+}
+ LOG(@"initimg return");
+
+ return img;
+}
+
+void
+_flushmemscreen(Rectangle r)
+{
+ LOG(@"_flushmemscreen(%d,%d,%d,%d)", r.min.x, r.min.y, Dx(r), Dy(r));
+ 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(img, Pt(r.min.x, r.min.y))
+ bytesPerRow:img->width*sizeof(u32int)];
+ [AppDelegate
+ performSelectorOnMainThread:@selector(callsetNeedsDisplayInRect:)
+ withObject:[NSValue valueWithRect:NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r))]
+ waitUntilDone:NO];
+ }
+}
+
+void
+setmouse(Point p)
+{
+ @autoreleasepool{
+ NSPoint q;
+
+ LOG(@"setmouse(%d,%d)", p.x, p.y);
+ q = [win convertPointFromBacking:NSMakePoint(p.x, p.y)];
+ LOG(@"(%g, %g) <- fromBacking", q.x, q.y);
+ q = [myContent convertPoint:q toView:nil];
+ LOG(@"(%g, %g) <- toWindow", q.x, q.y);
+ q = [win convertPointToScreen:q];
+ LOG(@"(%g, %g) <- toScreen", q.x, q.y);
+ // Quartz has the origin of the "global display
+ // coordinate space" at the top left of the primary
+ // screen with y increasing downward, while Cocoa has
+ // the origin at the bottom left of the primary screen
+ // with y increasing upward. We flip the coordinate
+ // with a negative sign and shift upward by the height
+ // of the primary screen.
+ q.y = NSScreen.screens[0].frame.size.height - q.y;
+ LOG(@"(%g, %g) <- setmouse", q.x, q.y);
+ CGWarpMouseCursorPosition(NSPointToCGPoint(q));
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
+}
+
+char*
+getsnarf(void)
+{
+ NSPasteboard *pb;
+ NSString *s;
+
+ @autoreleasepool{
+ pb = [NSPasteboard generalPasteboard];
+
+ qlock(&snarfl);
+ s = [pb stringForType:NSPasteboardTypeString];
+ qunlock(&snarfl);
+
+ if(s)
+ return strdup((char *)[s UTF8String]);
+ else
+ return nil;
+ }
+}
+
+void
+putsnarf(char *s)
+{
+ NSArray *t;
+ NSPasteboard *pb;
+ NSString *str;
+
+ if(strlen(s) >= SnarfSize)
+ return;
+
+ @autoreleasepool{
+ t = [NSArray arrayWithObject:NSPasteboardTypeString];
+ pb = [NSPasteboard generalPasteboard];
+ str = [[NSString alloc] initWithUTF8String:s];
+
+ qlock(&snarfl);
+ [pb declareTypes:t owner:nil];
+ [pb setString:str forType:NSPasteboardTypeString];
+ qunlock(&snarfl);
+ }
+}
+
+void
+kicklabel(char *label)
+{
+ NSString *s;
+
+ LOG(@"kicklabel(%s)", label);
+ if(label == nil)
+ return;
+
+ @autoreleasepool{
+ s = [[NSString alloc] initWithUTF8String:label];
+ [AppDelegate
+ performSelectorOnMainThread:@selector(callkicklabel:)
+ withObject:s
+ waitUntilDone:NO];
+ }
+}
+
+void
+setcursor(Cursor *c, Cursor2 *c2)
+{
+ Cursors cs;
+
+ cs.c = c;
+ cs.c2 = c2;
+
+ [AppDelegate
+ performSelectorOnMainThread:@selector(callsetcursor:)
+ withObject:[NSValue valueWithPointer:&cs]
+ waitUntilDone:YES];
+}
+
+void
+topwin(void)
+{
+ [win
+ performSelectorOnMainThread:
+ @selector(makeKeyAndOrderFront:)
+ withObject:nil
+ waitUntilDone:YES];
+
+ [NSApp activateIgnoringOtherApps:YES];
+}
+
+void
+resizeimg(void)
+{
+ zlock();
+ _drawreplacescreenimage(initimg());
+
+ mouseresized = 1;
+ zunlock();
+ [myContent sendmouse:0];
+}
+
+void
+resizewindow(Rectangle r)
+{
+ LOG(@"resizewindow %d %d %d %d", r.min.x, r.min.y, Dx(r), Dy(r));
+ dispatch_async(dispatch_get_main_queue(), ^(void){
+ NSSize s;
+
+ s = [myContent convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))];
+ [win setContentSize:s];
+ });
+}
+
+static void
+setprocname(const char *s)
+{
+ CFStringRef process_name;
+
+ process_name = CFStringCreateWithBytes(nil, (uchar*)s, strlen(s), kCFStringEncodingUTF8, false);
+
+ // Adapted from Chrome's mac_util.mm.
+ // http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm
+ //
+ // Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ //
+ // Redistribution and use in source and binary forms, with or without
+ // modification, are permitted provided that the following conditions are
+ // met:
+ //
+ // * Redistributions of source code must retain the above copyright
+ // notice, this list of conditions and the following disclaimer.
+ // * Redistributions in binary form must reproduce the above
+ // copyright notice, this list of conditions and the following disclaimer
+ // in the documentation and/or other materials provided with the
+ // distribution.
+ // * Neither the name of Google Inc. nor the names of its
+ // contributors may be used to endorse or promote products derived from
+ // this software without specific prior written permission.
+ //
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
+ // plugin host, and could break at any time (although realistically it's only
+ // likely to break in a new major release).
+ // When 10.7 is available, check that this still works, and update this
+ // comment for 10.8.
+
+ // Private CFType used in these LaunchServices calls.
+ typedef CFTypeRef PrivateLSASN;
+ typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
+ typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
+ CFStringRef,
+ CFStringRef,
+ CFDictionaryRef*);
+
+ static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
+ NULL;
+ static LSSetApplicationInformationItemType
+ ls_set_application_information_item_func = NULL;
+ static CFStringRef ls_display_name_key = NULL;
+
+ static bool did_symbol_lookup = false;
+ if (!did_symbol_lookup) {
+ did_symbol_lookup = true;
+ CFBundleRef launch_services_bundle =
+ CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
+ if (!launch_services_bundle) {
+ fprint(2, "Failed to look up LaunchServices bundle\n");
+ return;
+ }
+
+ ls_get_current_application_asn_func =
+ (LSGetCurrentApplicationASNType)(
+ CFBundleGetFunctionPointerForName(
+ launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
+ if (!ls_get_current_application_asn_func)
+ fprint(2, "Could not find _LSGetCurrentApplicationASN\n");
+
+ ls_set_application_information_item_func =
+ (LSSetApplicationInformationItemType)(
+ CFBundleGetFunctionPointerForName(
+ launch_services_bundle,
+ CFSTR("_LSSetApplicationInformationItem")));
+ if (!ls_set_application_information_item_func)
+ fprint(2, "Could not find _LSSetApplicationInformationItem\n");
+
+ CFStringRef* key_pointer = (CFStringRef*)(
+ CFBundleGetDataPointerForName(launch_services_bundle,
+ CFSTR("_kLSDisplayNameKey")));
+ ls_display_name_key = key_pointer ? *key_pointer : NULL;
+ if (!ls_display_name_key)
+ fprint(2, "Could not find _kLSDisplayNameKey\n");
+
+ // Internally, this call relies on the Mach ports that are started up by the
+ // Carbon Process Manager. In debug builds this usually happens due to how
+ // the logging layers are started up; but in release, it isn't started in as
+ // much of a defined order. So if the symbols had to be loaded, go ahead
+ // and force a call to make sure the manager has been initialized and hence
+ // the ports are opened.
+ ProcessSerialNumber psn;
+ GetCurrentProcess(&psn);
+ }
+ if (!ls_get_current_application_asn_func ||
+ !ls_set_application_information_item_func ||
+ !ls_display_name_key) {
+ return;
+ }
+
+ PrivateLSASN asn = ls_get_current_application_asn_func();
+ // Constant used by WebKit; what exactly it means is unknown.
+ const int magic_session_constant = -2;
+ OSErr err =
+ ls_set_application_information_item_func(magic_session_constant, asn,
+ ls_display_name_key,
+ process_name,
+ NULL /* optional out param */);
+ if(err != noErr)
+ fprint(2, "Call to set process name failed\n");
+}
diff --git a/src/cmd/devdraw/mac-srv.c b/src/cmd/devdraw/mac-srv.c
@@ -0,0 +1,427 @@
+/*
+ * Window system protocol server.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <drawfcall.h>
+#include "mac-screen.h"
+#include "devdraw.h"
+
+typedef struct Kbdbuf Kbdbuf;
+typedef struct Mousebuf Mousebuf;
+typedef struct Fdbuf Fdbuf;
+typedef struct Tagbuf Tagbuf;
+
+struct Kbdbuf
+{
+ Rune r[256];
+ int ri;
+ int wi;
+ int stall;
+};
+
+struct Mousebuf
+{
+ Mouse m[256];
+ Mouse last;
+ int ri;
+ int wi;
+ int stall;
+};
+
+struct Tagbuf
+{
+ int t[256];
+ int ri;
+ int wi;
+};
+
+Kbdbuf kbd;
+Mousebuf mouse;
+Tagbuf kbdtags;
+Tagbuf mousetags;
+
+void runmsg(Wsysmsg*);
+void replymsg(Wsysmsg*);
+void matchkbd(void);
+void matchmouse(void);
+
+
+QLock lk;
+void
+zlock(void)
+{
+ qlock(&lk);
+}
+
+void
+zunlock(void)
+{
+ qunlock(&lk);
+}
+
+int trace = 0;
+
+void
+servep9p(void)
+{
+ uchar buf[4], *mbuf;
+ int nmbuf, n, nn;
+ Wsysmsg m;
+
+ fmtinstall('W', drawfcallfmt);
+
+ mbuf = nil;
+ nmbuf = 0;
+ while((n = read(3, buf, 4)) == 4){
+ GET(buf, n);
+ if(n > nmbuf){
+ free(mbuf);
+ mbuf = malloc(4+n);
+ if(mbuf == nil)
+ sysfatal("malloc: %r");
+ nmbuf = n;
+ }
+ memmove(mbuf, buf, 4);
+ nn = readn(3, mbuf+4, n-4);
+ if(nn != n-4)
+ sysfatal("eof during message");
+
+ /* pick off messages one by one */
+ if(convM2W(mbuf, nn+4, &m) <= 0)
+ sysfatal("cannot convert message");
+ if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
+ runmsg(&m);
+ }
+}
+
+void
+replyerror(Wsysmsg *m)
+{
+ char err[256];
+
+ rerrstr(err, sizeof err);
+ m->type = Rerror;
+ m->error = err;
+ replymsg(m);
+}
+
+/*
+ * Handle a single wsysmsg.
+ * Might queue for later (kbd, mouse read)
+ */
+void
+runmsg(Wsysmsg *m)
+{
+ static uchar buf[65536];
+ int n;
+ Memimage *i;
+
+ switch(m->type){
+ case Tinit:
+ memimageinit();
+ i = attachscreen(m->label, m->winsize);
+ _initdisplaymemimage(i);
+ replymsg(m);
+ break;
+
+ case Trdmouse:
+ zlock();
+ mousetags.t[mousetags.wi++] = m->tag;
+ if(mousetags.wi == nelem(mousetags.t))
+ mousetags.wi = 0;
+ if(mousetags.wi == mousetags.ri)
+ sysfatal("too many queued mouse reads");
+ mouse.stall = 0;
+ matchmouse();
+ zunlock();
+ break;
+
+ case Trdkbd:
+ zlock();
+ kbdtags.t[kbdtags.wi++] = m->tag;
+ if(kbdtags.wi == nelem(kbdtags.t))
+ kbdtags.wi = 0;
+ if(kbdtags.wi == kbdtags.ri)
+ sysfatal("too many queued keyboard reads");
+ kbd.stall = 0;
+ matchkbd();
+ zunlock();
+ break;
+
+ case Tmoveto:
+ setmouse(m->mouse.xy);
+ replymsg(m);
+ break;
+
+ case Tcursor:
+ if(m->arrowcursor)
+ setcursor(nil, nil);
+ else
+ setcursor(&m->cursor, nil);
+ replymsg(m);
+ break;
+
+ case Tcursor2:
+ if(m->arrowcursor)
+ setcursor(nil, nil);
+ else
+ setcursor(&m->cursor, &m->cursor2);
+ replymsg(m);
+ break;
+
+ case Tbouncemouse:
+ // _xbouncemouse(&m->mouse);
+ replymsg(m);
+ break;
+
+ case Tlabel:
+ kicklabel(m->label);
+ replymsg(m);
+ break;
+
+ case Trdsnarf:
+ m->snarf = getsnarf();
+ replymsg(m);
+ free(m->snarf);
+ break;
+
+ case Twrsnarf:
+ putsnarf(m->snarf);
+ replymsg(m);
+ break;
+
+ case Trddraw:
+ zlock();
+ n = m->count;
+ if(n > sizeof buf)
+ n = sizeof buf;
+ n = _drawmsgread(buf, n);
+ if(n < 0)
+ replyerror(m);
+ else{
+ m->count = n;
+ m->data = buf;
+ replymsg(m);
+ }
+ zunlock();
+ break;
+
+ case Twrdraw:
+ zlock();
+ if(_drawmsgwrite(m->data, m->count) < 0)
+ replyerror(m);
+ else
+ replymsg(m);
+ zunlock();
+ break;
+
+ case Ttop:
+ topwin();
+ replymsg(m);
+ break;
+
+ case Tresize:
+ resizewindow(m->rect);
+ replymsg(m);
+ break;
+ }
+}
+
+/*
+ * Reply to m.
+ */
+QLock replylock;
+void
+replymsg(Wsysmsg *m)
+{
+ int n;
+ static uchar *mbuf;
+ static int nmbuf;
+
+ /* T -> R msg */
+ if(m->type%2 == 0)
+ m->type++;
+
+ if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
+ /* copy to output buffer */
+ n = sizeW2M(m);
+
+ qlock(&replylock);
+ if(n > nmbuf){
+ free(mbuf);
+ mbuf = malloc(n);
+ if(mbuf == nil)
+ sysfatal("out of memory");
+ nmbuf = n;
+ }
+ convW2M(m, mbuf, n);
+ if(write(4, mbuf, n) != n)
+ sysfatal("write: %r");
+ qunlock(&replylock);
+}
+
+/*
+ * Match queued kbd reads with queued kbd characters.
+ */
+void
+matchkbd(void)
+{
+ Wsysmsg m;
+
+ if(kbd.stall)
+ return;
+ while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){
+ m.type = Rrdkbd;
+ m.tag = kbdtags.t[kbdtags.ri++];
+ if(kbdtags.ri == nelem(kbdtags.t))
+ kbdtags.ri = 0;
+ m.rune = kbd.r[kbd.ri++];
+ if(kbd.ri == nelem(kbd.r))
+ kbd.ri = 0;
+ replymsg(&m);
+ }
+}
+
+/*
+ * Match queued mouse reads with queued mouse events.
+ */
+void
+matchmouse(void)
+{
+ Wsysmsg m;
+
+ while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){
+ m.type = Rrdmouse;
+ m.tag = mousetags.t[mousetags.ri++];
+ if(mousetags.ri == nelem(mousetags.t))
+ mousetags.ri = 0;
+ m.mouse = mouse.m[mouse.ri];
+ m.resized = mouseresized;
+ mouseresized = 0;
+ /*
+ if(m.resized)
+ fprint(2, "sending resize\n");
+ */
+ mouse.ri++;
+ if(mouse.ri == nelem(mouse.m))
+ mouse.ri = 0;
+ replymsg(&m);
+ }
+}
+
+void
+mousetrack(int x, int y, int b, uint ms)
+{
+ Mouse *m;
+
+ if(x < mouserect.min.x)
+ x = mouserect.min.x;
+ if(x > mouserect.max.x)
+ x = mouserect.max.x;
+ if(y < mouserect.min.y)
+ y = mouserect.min.y;
+ if(y > mouserect.max.y)
+ y = mouserect.max.y;
+
+ zlock();
+ // If reader has stopped reading, don't bother.
+ // If reader is completely caught up, definitely queue.
+ // Otherwise, queue only button change events.
+ if(!mouse.stall)
+ if(mouse.wi == mouse.ri || mouse.last.buttons != b){
+ m = &mouse.last;
+ m->xy.x = x;
+ m->xy.y = y;
+ m->buttons = b;
+ m->msec = ms;
+
+ mouse.m[mouse.wi] = *m;
+ if(++mouse.wi == nelem(mouse.m))
+ mouse.wi = 0;
+ if(mouse.wi == mouse.ri){
+ mouse.stall = 1;
+ mouse.ri = 0;
+ mouse.wi = 1;
+ mouse.m[0] = *m;
+ }
+ matchmouse();
+ }
+ zunlock();
+}
+
+void
+kputc(int c)
+{
+ zlock();
+ kbd.r[kbd.wi++] = c;
+ if(kbd.wi == nelem(kbd.r))
+ kbd.wi = 0;
+ if(kbd.ri == kbd.wi)
+ kbd.stall = 1;
+ matchkbd();
+ zunlock();
+}
+
+static int alting;
+
+void
+abortcompose(void)
+{
+ if(alting)
+ keystroke(Kalt);
+}
+
+void
+keystroke(int c)
+{
+ static Rune k[10];
+ static int nk;
+ int i;
+
+ if(c == Kalt){
+ alting = !alting;
+ nk = 0;
+ return;
+ }
+ if(c == Kcmd+'r') {
+ if(forcedpi)
+ forcedpi = 0;
+ else if(displaydpi >= 200)
+ forcedpi = 100;
+ else
+ forcedpi = 225;
+ resizeimg();
+ return;
+ }
+ if(!alting){
+ kputc(c);
+ return;
+ }
+ if(nk >= nelem(k)) // should not happen
+ nk = 0;
+ k[nk++] = c;
+ c = _latin1(k, nk);
+ if(c > 0){
+ alting = 0;
+ kputc(c);
+ nk = 0;
+ return;
+ }
+ if(c == -1){
+ alting = 0;
+ for(i=0; i<nk; i++)
+ kputc(k[i]);
+ nk = 0;
+ return;
+ }
+ // need more input
+ return;
+}
diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh
@@ -26,7 +26,7 @@ if [ "x$WSYSTYPE" = "x" ]; then
echo 1>&2 'OS X 10.12 and older are not supported'
exit 1
fi
- WSYSTYPE=osx-cocoa
+ WSYSTYPE=mac
elif [ -d "$X11" ]; then
WSYSTYPE=x11
else
@@ -51,9 +51,9 @@ if [ $WSYSTYPE = x11 ]; then
echo 'HFILES=$HFILES $XHFILES'
XO=`ls x11-*.c 2>/dev/null | sed 's/\.c$/.o/'`
echo 'WSYSOFILES=$WSYSOFILES '$XO
-elif [ $WSYSTYPE = osx-cocoa ]; then
+elif [ $WSYSTYPE = mac ]; then
echo 'OBJCFLAGS=$OBJCFLAGS -fobjc-arc'
- echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen.o cocoa-srv.o'
+ echo 'WSYSOFILES=$WSYSOFILES mac-draw.o mac-screen.o mac-srv.o'
echo 'MACARGV=macargv.o'
elif [ $WSYSTYPE = nowsys ]; then
echo 'WSYSOFILES=nowsys.o'
diff --git a/src/cmd/devdraw/osx-keycodes.h b/src/cmd/devdraw/osx-keycodes.h
@@ -1,189 +0,0 @@
-/* These are the Macintosh key scancode constants -- from Inside Macintosh */
-#define QZ_ESCAPE 0x35
-#define QZ_F1 0x7A
-#define QZ_F2 0x78
-#define QZ_F3 0x63
-#define QZ_F4 0x76
-#define QZ_F5 0x60
-#define QZ_F6 0x61
-#define QZ_F7 0x62
-#define QZ_F8 0x64
-#define QZ_F9 0x65
-#define QZ_F10 0x6D
-#define QZ_F11 0x67
-#define QZ_F12 0x6F
-#define QZ_PRINT 0x69
-#define QZ_SCROLLOCK 0x6B
-#define QZ_PAUSE 0x71
-#define QZ_POWER 0x7F
-#define QZ_BACKQUOTE 0x32
-#define QZ_1 0x12
-#define QZ_2 0x13
-#define QZ_3 0x14
-#define QZ_4 0x15
-#define QZ_5 0x17
-#define QZ_6 0x16
-#define QZ_7 0x1A
-#define QZ_8 0x1C
-#define QZ_9 0x19
-#define QZ_0 0x1D
-#define QZ_MINUS 0x1B
-#define QZ_EQUALS 0x18
-#define QZ_BACKSPACE 0x33
-#define QZ_INSERT 0x72
-#define QZ_HOME 0x73
-#define QZ_PAGEUP 0x74
-#define QZ_NUMLOCK 0x47
-#define QZ_KP_EQUALS 0x51
-#define QZ_KP_DIVIDE 0x4B
-#define QZ_KP_MULTIPLY 0x43
-#define QZ_TAB 0x30
-#define QZ_q 0x0C
-#define QZ_w 0x0D
-#define QZ_e 0x0E
-#define QZ_r 0x0F
-#define QZ_t 0x11
-#define QZ_y 0x10
-#define QZ_u 0x20
-#define QZ_i 0x22
-#define QZ_o 0x1F
-#define QZ_p 0x23
-#define QZ_LEFTBRACKET 0x21
-#define QZ_RIGHTBRACKET 0x1E
-#define QZ_BACKSLASH 0x2A
-#define QZ_DELETE 0x75
-#define QZ_END 0x77
-#define QZ_PAGEDOWN 0x79
-#define QZ_KP7 0x59
-#define QZ_KP8 0x5B
-#define QZ_KP9 0x5C
-#define QZ_KP_MINUS 0x4E
-#define QZ_CAPSLOCK 0x39
-#define QZ_a 0x00
-#define QZ_s 0x01
-#define QZ_d 0x02
-#define QZ_f 0x03
-#define QZ_g 0x05
-#define QZ_h 0x04
-#define QZ_j 0x26
-#define QZ_k 0x28
-#define QZ_l 0x25
-#define QZ_SEMICOLON 0x29
-#define QZ_QUOTE 0x27
-#define QZ_RETURN 0x24
-#define QZ_KP4 0x56
-#define QZ_KP5 0x57
-#define QZ_KP6 0x58
-#define QZ_KP_PLUS 0x45
-#define QZ_LSHIFT 0x38
-#define QZ_z 0x06
-#define QZ_x 0x07
-#define QZ_c 0x08
-#define QZ_v 0x09
-#define QZ_b 0x0B
-#define QZ_n 0x2D
-#define QZ_m 0x2E
-#define QZ_COMMA 0x2B
-#define QZ_PERIOD 0x2F
-#define QZ_SLASH 0x2C
-/* These are the same as the left versions - use left by default */
-#if 0
-#define QZ_RSHIFT 0x38
-#endif
-#define QZ_UP 0x7E
-#define QZ_KP1 0x53
-#define QZ_KP2 0x54
-#define QZ_KP3 0x55
-#define QZ_KP_ENTER 0x4C
-#define QZ_LCTRL 0x3B
-#define QZ_LALT 0x3A
-#define QZ_LMETA 0x37
-#define QZ_SPACE 0x31
-/* These are the same as the left versions - use left by default */
-#if 0
-#define QZ_RMETA 0x37
-#define QZ_RALT 0x3A
-#define QZ_RCTRL 0x3B
-#endif
-#define QZ_LEFT 0x7B
-#define QZ_DOWN 0x7D
-#define QZ_RIGHT 0x7C
-#define QZ_KP0 0x52
-#define QZ_KP_PERIOD 0x41
-
-/* Wierd, these keys are on my iBook under MacOS X */
-#define QZ_IBOOK_ENTER 0x34
-#define QZ_IBOOK_LEFT 0x3B
-#define QZ_IBOOK_RIGHT 0x3C
-#define QZ_IBOOK_DOWN 0x3D
-#define QZ_IBOOK_UP 0x3E
-#define KEY_ENTER 13
-#define KEY_TAB 9
-
-#define KEY_BASE 0x100
-
-/* Function keys */
-#define KEY_F (KEY_BASE+64)
-
-/* Control keys */
-#define KEY_CTRL (KEY_BASE)
-#define KEY_BACKSPACE (KEY_CTRL+0)
-#define KEY_DELETE (KEY_CTRL+1)
-#define KEY_INSERT (KEY_CTRL+2)
-#define KEY_HOME (KEY_CTRL+3)
-#define KEY_END (KEY_CTRL+4)
-#define KEY_PAGE_UP (KEY_CTRL+5)
-#define KEY_PAGE_DOWN (KEY_CTRL+6)
-#define KEY_ESC (KEY_CTRL+7)
-
-/* Control keys short name */
-#define KEY_BS KEY_BACKSPACE
-#define KEY_DEL KEY_DELETE
-#define KEY_INS KEY_INSERT
-#define KEY_PGUP KEY_PAGE_UP
-#define KEY_PGDOWN KEY_PAGE_DOWN
-#define KEY_PGDWN KEY_PAGE_DOWN
-
-/* Cursor movement */
-#define KEY_CRSR (KEY_BASE+16)
-#define KEY_RIGHT (KEY_CRSR+0)
-#define KEY_LEFT (KEY_CRSR+1)
-#define KEY_DOWN (KEY_CRSR+2)
-#define KEY_UP (KEY_CRSR+3)
-
-/* Multimedia keyboard/remote keys */
-#define KEY_MM_BASE (0x100+384)
-#define KEY_POWER (KEY_MM_BASE+0)
-#define KEY_MENU (KEY_MM_BASE+1)
-#define KEY_PLAY (KEY_MM_BASE+2)
-#define KEY_PAUSE (KEY_MM_BASE+3)
-#define KEY_PLAYPAUSE (KEY_MM_BASE+4)
-#define KEY_STOP (KEY_MM_BASE+5)
-#define KEY_FORWARD (KEY_MM_BASE+6)
-#define KEY_REWIND (KEY_MM_BASE+7)
-#define KEY_NEXT (KEY_MM_BASE+8)
-#define KEY_PREV (KEY_MM_BASE+9)
-#define KEY_VOLUME_UP (KEY_MM_BASE+10)
-#define KEY_VOLUME_DOWN (KEY_MM_BASE+11)
-#define KEY_MUTE (KEY_MM_BASE+12)
-
-/* Keypad keys */
-#define KEY_KEYPAD (KEY_BASE+32)
-#define KEY_KP0 (KEY_KEYPAD+0)
-#define KEY_KP1 (KEY_KEYPAD+1)
-#define KEY_KP2 (KEY_KEYPAD+2)
-#define KEY_KP3 (KEY_KEYPAD+3)
-#define KEY_KP4 (KEY_KEYPAD+4)
-#define KEY_KP5 (KEY_KEYPAD+5)
-#define KEY_KP6 (KEY_KEYPAD+6)
-#define KEY_KP7 (KEY_KEYPAD+7)
-#define KEY_KP8 (KEY_KEYPAD+8)
-#define KEY_KP9 (KEY_KEYPAD+9)
-#define KEY_KPDEC (KEY_KEYPAD+10)
-#define KEY_KPINS (KEY_KEYPAD+11)
-#define KEY_KPDEL (KEY_KEYPAD+12)
-#define KEY_KPENTER (KEY_KEYPAD+13)
-
-/* Special keys */
-#define KEY_INTERN (0x1000)
-#define KEY_CLOSE_WIN (KEY_INTERN+0)
diff --git a/src/cmd/fontsrv/osx.c b/src/cmd/fontsrv/mac.c
diff --git a/src/cmd/fontsrv/mkfile b/src/cmd/fontsrv/mkfile
@@ -14,8 +14,6 @@ OFILES=\
<$PLAN9/src/mkone
-osx-cocoa.$O: osx.c
-
showpjw: showpjw.c
9c showpjw.c
9l -o showpjw showpjw.o
diff --git a/src/cmd/fontsrv/osx-cocoa.c b/src/cmd/fontsrv/osx-cocoa.c
@@ -1 +0,0 @@
-#include "osx.c"
diff --git a/src/cmd/snarfer/osx-cocoa-snarfer.c b/src/cmd/snarfer/mac-snarfer.c
diff --git a/src/cmd/snarfer/mkfile b/src/cmd/snarfer/mkfile
@@ -9,4 +9,4 @@ HFILES=
<$PLAN9/src/mkone
x11-snarfer.$O: snarfer.c
-osx-snarfer.$O: snarfer.c
+mac-snarfer.$O: snarfer.c
diff --git a/src/cmd/snarfer/osx-snarfer.c b/src/cmd/snarfer/osx-snarfer.c
@@ -1 +0,0 @@
-#include "snarfer.c"