From ca81de0ae174e737cf3594787fa885e51d6e9d1d Mon Sep 17 00:00:00 2001 From: David Jeannot Date: Fri, 9 Dec 2011 22:21:09 -0500 Subject: Cocoa Devdraw: cursor fix R=rsc CC=plan9port.codebot http://codereview.appspot.com/5356050 --- src/cmd/devdraw/bigarrow.h | 11 ++ src/cmd/devdraw/cocoa-screen.m | 249 +++++++++++++++++++++++------------------ src/cmd/devdraw/cursor.c | 16 --- src/cmd/devdraw/mkwsysrules.sh | 2 +- 4 files changed, 150 insertions(+), 128 deletions(-) create mode 100644 src/cmd/devdraw/bigarrow.h delete mode 100644 src/cmd/devdraw/cursor.c diff --git a/src/cmd/devdraw/bigarrow.h b/src/cmd/devdraw/bigarrow.h new file mode 100644 index 00000000..a46f19a0 --- /dev/null +++ b/src/cmd/devdraw/bigarrow.h @@ -0,0 +1,11 @@ +Cursor bigarrow = { + {0, 0}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, + 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, + 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40}, + {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, + 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, + 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, + 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00}, +}; diff --git a/src/cmd/devdraw/cocoa-screen.m b/src/cmd/devdraw/cocoa-screen.m index 56124355..5ab6104e 100644 --- a/src/cmd/devdraw/cocoa-screen.m +++ b/src/cmd/devdraw/cocoa-screen.m @@ -22,6 +22,7 @@ #include "cocoa-screen.h" #include "osx-keycodes.h" #include "devdraw.h" +#include "bigarrow.h" #include "glendapng.h" AUTOFRAMEWORK(Cocoa) @@ -32,10 +33,6 @@ int usegestures = 0; int useoldfullscreen = 0; int usebigarrow = 0; -extern Cursor bigarrow; - -void setcursor0(Cursor *c); - void usage(void) { @@ -43,8 +40,7 @@ usage(void) threadexitsall("usage"); } -@interface appdelegate : NSObject -@end +@interface appdelegate : NSObject @end void threadmain(int argc, char **argv) @@ -79,11 +75,6 @@ threadmain(int argc, char **argv) if(OSX_VERSION < 100700) [NSAutoreleasePool new]; - // Reset cursor to ensure we start - // with bigarrow. - if(usebigarrow) - setcursor0(nil); - [NSApplication sharedApplication]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; [NSApp setDelegate:[appdelegate new]]; @@ -99,39 +90,41 @@ struct int isofs; int isnfs; NSView *content; - char *rectstr; NSBitmapImageRep *img; - NSRect flushrect; int needflush; NSCursor *cursor; - QLock cursorl; } win; struct { + NSCursor *bigarrow; int kalting; int kbuttons; int mbuttons; - Point mpos; + NSPoint mpos; int mscroll; int undo; int touchevent; } in; static void hidebars(int); -static void drawimg(void); +static void drawimg(NSRect); static void flushwin(void); static void followzoombutton(NSRect); static void getmousepos(void); static void makeicon(void); static void makemenu(void); -static void makewin(void); +static void makewin(char*); static void sendmouse(void); +static void setcursor0(Cursor*); static void togglefs(void); +static NSCursor* makecursor(Cursor*); + @implementation appdelegate - (void)applicationDidFinishLaunching:(id)arg { + in.bigarrow = makecursor(&bigarrow); makeicon(); makemenu(); [NSApplication @@ -191,11 +184,12 @@ static void togglefs(void); servep9p(); [NSApp terminate:self]; } -+ (void)calldrawimg:(id)arg{ drawimg();} + (void)callflushwin:(id)arg{ flushwin();} -+ (void)callmakewin:(id)arg{ makewin();} -+ (void)callsetcursor0:(id)arg{ setcursor0([[arg autorelease] pointerValue]);} - (void)calltogglefs:(id)arg{ togglefs();} + ++ (void)calldrawimg:(NSValue*)v{ drawimg([v rectValue]);} ++ (void)callmakewin:(NSValue*)v{ makewin([v pointerValue]);} ++ (void)callsetcursor0:(NSValue*)v{ setcursor0([v pointerValue]);} @end static Memimage* initimg(void); @@ -213,27 +207,22 @@ attachscreen(char *label, char *winsize) if(label == nil) label = "gnot a label"; - win.rectstr = strdup(winsize); - /* * Create window in main thread, else no cursor * change while resizing. */ [appdelegate performSelectorOnMainThread:@selector(callmakewin:) - withObject:nil + withObject:[NSValue valueWithPointer:winsize] waitUntilDone:YES]; -// makewin(); +// makewin(winsize); kicklabel(label); return initimg(); } -@interface appview : NSView -@end - -@interface appwin : NSWindow -@end +@interface appwin : NSWindow @end +@interface contentview : NSView @end @implementation appwin - (NSTimeInterval)animationResizeTime:(NSRect)r @@ -242,7 +231,7 @@ attachscreen(char *label, char *winsize) } - (BOOL)canBecomeKeyWindow { - return YES; /* else no keyboard with old fullscreen */ + return YES; /* else no keyboard for old fullscreen */ } @end @@ -255,15 +244,13 @@ enum }; static void -makewin(void) +makewin(char *s) { NSRect r, sr; NSWindow *w; Rectangle wr; - char *s; int i, set; - s = win.rectstr; sr = [[NSScreen mainScreen] frame]; if(s && *s){ @@ -305,8 +292,7 @@ makewin(void) [win.ofs[i] setDisplaysWhenScreenProfileChanges:NO]; } win.isofs = 0; - win.content = [appview new]; - [win.content setAcceptsTouchEvents:YES]; + win.content = [contentview new]; [WIN setContentView:win.content]; [WIN makeKeyAndOrderFront:nil]; } @@ -345,7 +331,9 @@ initimg(void) void _flushmemscreen(Rectangle r) { - win.flushrect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r)); + NSRect rect; + + rect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r)); /* * Call "lockFocusIfCanDraw" from main thread, else @@ -357,17 +345,17 @@ _flushmemscreen(Rectangle r) */ [appdelegate performSelectorOnMainThread:@selector(calldrawimg:) - withObject:nil + withObject:[NSValue valueWithRect:rect] waitUntilDone:YES]; } -static void drawresizehandle(void); +static void drawresizehandle(NSRect); static void -drawimg(void) +drawimg(NSRect dr) { static int first = 1; - NSRect dr, sr; + NSRect sr; if(first){ [NSTimer scheduledTimerWithTimeInterval:0.033 @@ -376,7 +364,6 @@ drawimg(void) repeats:YES]; first = 0; } - dr = win.flushrect; sr = [win.content convertRect:dr fromView:nil]; if([win.content lockFocusIfCanDraw]){ @@ -394,7 +381,7 @@ drawimg(void) respectFlipped:YES hints:nil]; if(OSX_VERSION<100700 && win.isofs==0) - drawresizehandle(); + drawresizehandle(dr); [win.content unlockFocus]; win.needflush = 1; @@ -418,7 +405,7 @@ enum }; static void -drawresizehandle(void) +drawresizehandle(NSRect dr) { NSColor *color[Barsize]; NSPoint a,b; @@ -431,7 +418,7 @@ drawresizehandle(void) c = Pt(size.width, size.height); r = NSMakeRect(0, 0, Handlesize, Handlesize); r.origin = NSMakePoint(c.x-Handlesize, c.y-Handlesize); - if(NSIntersectsRect(r, win.flushrect) == 0) + if(NSIntersectsRect(r,dr) == 0) return; [[WIN graphicsContext] setShouldAntialias:NO]; @@ -464,8 +451,9 @@ static void getgesture(NSEvent*); static void getkeyboard(NSEvent*); static void getmouse(NSEvent*); static void gettouch(NSEvent*, int); +static void updatecursor(void); -@implementation appview +@implementation contentview - (void)drawRect:(NSRect)r { @@ -481,29 +469,22 @@ static void gettouch(NSEvent*, int); /* We should wait for P9P's image here. */ } -- (void)resetCursorRects -{ - NSCursor *c; - - [super resetCursorRects]; - - qlock(&win.cursorl); - - c = win.cursor; - if(c == nil) - c = [NSCursor arrowCursor]; - - [self addCursorRect:[self bounds] cursor:c]; - qunlock(&win.cursorl); -} - (BOOL)isFlipped { - return YES; /* to have the origin at top left */ + return YES; /* to make the content's origin top left */ } - (BOOL)acceptsFirstResponder { - return YES; /* to receive mouseMoved events */ -} + return YES; /* else no keyboard */ +} +- (id)initWithFrame:(NSRect)r +{ + [super initWithFrame:r]; + [self setAcceptsTouchEvents:YES]; + return self; +} +- (void)cursorUpdate:(NSEvent*)e{ updatecursor();} + - (void)mouseMoved:(NSEvent*)e{ getmouse(e);} - (void)mouseDown:(NSEvent*)e{ getmouse(e);} - (void)mouseDragged:(NSEvent*)e{ getmouse(e);} @@ -644,6 +625,37 @@ getkeyboard(NSEvent *e) } } +/* + * Devdraw does not use NSTrackingArea, that often + * forgets to update the cursor on entering and on + * leaving the area, and that sometimes stops sending + * us MouseMove events, at least on OS X Lion. + */ +static void +updatecursor(void) +{ + NSCursor *c; + int isdown, isinside; + + isinside = NSPointInRect(in.mpos, [win.content bounds]); + isdown = (in.mbuttons || in.kbuttons); + + if(win.cursor && (isinside || isdown)) + c = win.cursor; + else if(isinside && usebigarrow) + c = in.bigarrow; + else + c = [NSCursor arrowCursor]; + [c set]; + + /* + * Without this trick, we can come back from the dock + * with a resize cursor. + */ + if(OSX_VERSION >= 100700) + [NSCursor unhide]; +} + static void getmousepos(void) { @@ -651,7 +663,10 @@ getmousepos(void) p = [WIN mouseLocationOutsideOfEventStream]; p = [win.content convertPoint:p fromView:nil]; - in.mpos = Pt(p.x, p.y); + in.mpos.x = round(p.x); + in.mpos.y = round(p.y); + + updatecursor(); } static void @@ -660,6 +675,9 @@ getmouse(NSEvent *e) float d; int b, m; + if([WIN isKeyWindow] == 0) + return; + getmousepos(); switch([e type]){ @@ -977,21 +995,23 @@ setmouse(Point p) NSPoint q; NSRect r; + if([NSApp isActive] == 0) + return; + if(first){ /* Try to move Acme's scrollbars without that! */ CGSetLocalEventsSuppressionInterval(0); first = 0; } + in.mpos = NSMakePoint(p.x, p.y); // race condition + r = [[WIN screen] frame]; - q = NSMakePoint(p.x, p.y); - q = [win.content convertPoint:q toView:nil]; + q = [win.content convertPoint:in.mpos toView:nil]; q = [WIN convertBaseToScreen:q]; q.y = r.size.height - q.y; CGWarpMouseCursorPosition(NSPointToCGPoint(q)); - - in.mpos = p; // race condition } static void @@ -1004,6 +1024,7 @@ followzoombutton(NSRect r) wr.origin.y += wr.size.height; r.origin.y += r.size.height; + getmousepos(); p.x = (r.origin.x - wr.origin.x) + in.mpos.x; p.y = -(r.origin.y - wr.origin.y) + in.mpos.y; setmouse(p); @@ -1176,63 +1197,69 @@ kicklabel(char *label) } void -setcursor(Cursor *cursor) +setcursor(Cursor *c) { + /* + * No cursor change unless in main thread. + */ [appdelegate performSelectorOnMainThread:@selector(callsetcursor0:) - withObject:[[NSValue valueWithPointer:cursor] retain] + withObject:[NSValue valueWithPointer:c] waitUntilDone:YES]; } -void +static void setcursor0(Cursor *c) { - NSBitmapImageRep *r; - NSImage *i; - NSPoint p; - int b; - uchar *plane[5]; + NSCursor *d; - qlock(&win.cursorl); + d = win.cursor; - if(win.cursor){ - [win.cursor release]; + if(c) + win.cursor = makecursor(c); + else win.cursor = nil; - } - if(c == nil && usebigarrow) - c = &bigarrow; - - if(c){ - r = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:nil - pixelsWide:16 - pixelsHigh:16 - bitsPerSample:1 - samplesPerPixel:2 - hasAlpha:YES - isPlanar:YES - colorSpaceName:NSDeviceBlackColorSpace - bytesPerRow:2 - bitsPerPixel:1]; - - [r getBitmapDataPlanes:plane]; - - for(b=0; b<2*16; b++){ - plane[0][b] = c->set[b]; - plane[1][b] = c->clr[b]; - } - p = NSMakePoint(-c->offset.x, -c->offset.y); - i = [NSImage new]; - [i addRepresentation:r]; + updatecursor(); + + if(d) + [d release]; +} - win.cursor = [[NSCursor alloc] initWithImage:i hotSpot:p]; +static NSCursor* +makecursor(Cursor *c) +{ + NSBitmapImageRep *r; + NSCursor *d; + NSImage *i; + NSPoint p; + int b; + uchar *plane[5]; - [win.cursor set]; - [i release]; - [r release]; + r = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:nil + pixelsWide:16 + pixelsHigh:16 + bitsPerSample:1 + samplesPerPixel:2 + hasAlpha:YES + isPlanar:YES + colorSpaceName:NSDeviceBlackColorSpace + bytesPerRow:2 + bitsPerPixel:1]; + + [r getBitmapDataPlanes:plane]; + + for(b=0; b<2*16; b++){ + plane[0][b] = c->set[b]; + plane[1][b] = c->clr[b]; } + p = NSMakePoint(-c->offset.x, -c->offset.y); + i = [NSImage new]; + [i addRepresentation:r]; + [r release]; - qunlock(&win.cursorl); - [WIN invalidateCursorRectsForView:win.content]; + d = [[NSCursor alloc] initWithImage:i hotSpot:p]; + [i release]; + return d; } diff --git a/src/cmd/devdraw/cursor.c b/src/cmd/devdraw/cursor.c deleted file mode 100644 index af7e65db..00000000 --- a/src/cmd/devdraw/cursor.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -#include -#include - -Cursor bigarrow = { - {0, 0}, - {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, - 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, - 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, - 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40}, - {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, - 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, - 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, - 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00}, -}; diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh index a9072adf..dde44c81 100644 --- a/src/cmd/devdraw/mkwsysrules.sh +++ b/src/cmd/devdraw/mkwsysrules.sh @@ -59,7 +59,7 @@ elif [ $WSYSTYPE = osx ]; then echo 'WSYSOFILES=$WSYSOFILES osx-screen-carbon-objc.o osx-draw.o osx-srv.o' echo 'MACARGV=macargv.o' elif [ $WSYSTYPE = osx-cocoa ]; then - echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen-objc.o cocoa-srv.o cocoa-thread.o cursor.o' + echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen-objc.o cocoa-srv.o cocoa-thread.o' echo 'MACARGV=macargv-objc.o' elif [ $WSYSTYPE = nowsys ]; then echo 'WSYSOFILES=nowsys.o' -- cgit v1.2.3