Cocoa Devdraw: cursor fix

R=rsc
CC=plan9port.codebot
http://codereview.appspot.com/5356050
This commit is contained in:
David Jeannot 2011-12-09 22:21:09 -05:00 committed by Russ Cox
parent 37234309e5
commit ca81de0ae1
3 changed files with 138 additions and 116 deletions

View file

@ -1,8 +1,3 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <cursor.h>
Cursor bigarrow = { Cursor bigarrow = {
{0, 0}, {0, 0},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,

View file

@ -22,6 +22,7 @@
#include "cocoa-screen.h" #include "cocoa-screen.h"
#include "osx-keycodes.h" #include "osx-keycodes.h"
#include "devdraw.h" #include "devdraw.h"
#include "bigarrow.h"
#include "glendapng.h" #include "glendapng.h"
AUTOFRAMEWORK(Cocoa) AUTOFRAMEWORK(Cocoa)
@ -32,10 +33,6 @@ int usegestures = 0;
int useoldfullscreen = 0; int useoldfullscreen = 0;
int usebigarrow = 0; int usebigarrow = 0;
extern Cursor bigarrow;
void setcursor0(Cursor *c);
void void
usage(void) usage(void)
{ {
@ -43,8 +40,7 @@ usage(void)
threadexitsall("usage"); threadexitsall("usage");
} }
@interface appdelegate : NSObject @interface appdelegate : NSObject @end
@end
void void
threadmain(int argc, char **argv) threadmain(int argc, char **argv)
@ -79,11 +75,6 @@ threadmain(int argc, char **argv)
if(OSX_VERSION < 100700) if(OSX_VERSION < 100700)
[NSAutoreleasePool new]; [NSAutoreleasePool new];
// Reset cursor to ensure we start
// with bigarrow.
if(usebigarrow)
setcursor0(nil);
[NSApplication sharedApplication]; [NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp setDelegate:[appdelegate new]]; [NSApp setDelegate:[appdelegate new]];
@ -99,39 +90,41 @@ struct
int isofs; int isofs;
int isnfs; int isnfs;
NSView *content; NSView *content;
char *rectstr;
NSBitmapImageRep *img; NSBitmapImageRep *img;
NSRect flushrect;
int needflush; int needflush;
NSCursor *cursor; NSCursor *cursor;
QLock cursorl;
} win; } win;
struct struct
{ {
NSCursor *bigarrow;
int kalting; int kalting;
int kbuttons; int kbuttons;
int mbuttons; int mbuttons;
Point mpos; NSPoint mpos;
int mscroll; int mscroll;
int undo; int undo;
int touchevent; int touchevent;
} in; } in;
static void hidebars(int); static void hidebars(int);
static void drawimg(void); static void drawimg(NSRect);
static void flushwin(void); static void flushwin(void);
static void followzoombutton(NSRect); static void followzoombutton(NSRect);
static void getmousepos(void); static void getmousepos(void);
static void makeicon(void); static void makeicon(void);
static void makemenu(void); static void makemenu(void);
static void makewin(void); static void makewin(char*);
static void sendmouse(void); static void sendmouse(void);
static void setcursor0(Cursor*);
static void togglefs(void); static void togglefs(void);
static NSCursor* makecursor(Cursor*);
@implementation appdelegate @implementation appdelegate
- (void)applicationDidFinishLaunching:(id)arg - (void)applicationDidFinishLaunching:(id)arg
{ {
in.bigarrow = makecursor(&bigarrow);
makeicon(); makeicon();
makemenu(); makemenu();
[NSApplication [NSApplication
@ -191,11 +184,12 @@ static void togglefs(void);
servep9p(); servep9p();
[NSApp terminate:self]; [NSApp terminate:self];
} }
+ (void)calldrawimg:(id)arg{ drawimg();}
+ (void)callflushwin:(id)arg{ flushwin();} + (void)callflushwin:(id)arg{ flushwin();}
+ (void)callmakewin:(id)arg{ makewin();}
+ (void)callsetcursor0:(id)arg{ setcursor0([[arg autorelease] pointerValue]);}
- (void)calltogglefs:(id)arg{ togglefs();} - (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 @end
static Memimage* initimg(void); static Memimage* initimg(void);
@ -213,27 +207,22 @@ attachscreen(char *label, char *winsize)
if(label == nil) if(label == nil)
label = "gnot a label"; label = "gnot a label";
win.rectstr = strdup(winsize);
/* /*
* Create window in main thread, else no cursor * Create window in main thread, else no cursor
* change while resizing. * change while resizing.
*/ */
[appdelegate [appdelegate
performSelectorOnMainThread:@selector(callmakewin:) performSelectorOnMainThread:@selector(callmakewin:)
withObject:nil withObject:[NSValue valueWithPointer:winsize]
waitUntilDone:YES]; waitUntilDone:YES];
// makewin(); // makewin(winsize);
kicklabel(label); kicklabel(label);
return initimg(); return initimg();
} }
@interface appview : NSView @interface appwin : NSWindow @end
@end @interface contentview : NSView @end
@interface appwin : NSWindow
@end
@implementation appwin @implementation appwin
- (NSTimeInterval)animationResizeTime:(NSRect)r - (NSTimeInterval)animationResizeTime:(NSRect)r
@ -242,7 +231,7 @@ attachscreen(char *label, char *winsize)
} }
- (BOOL)canBecomeKeyWindow - (BOOL)canBecomeKeyWindow
{ {
return YES; /* else no keyboard with old fullscreen */ return YES; /* else no keyboard for old fullscreen */
} }
@end @end
@ -255,15 +244,13 @@ enum
}; };
static void static void
makewin(void) makewin(char *s)
{ {
NSRect r, sr; NSRect r, sr;
NSWindow *w; NSWindow *w;
Rectangle wr; Rectangle wr;
char *s;
int i, set; int i, set;
s = win.rectstr;
sr = [[NSScreen mainScreen] frame]; sr = [[NSScreen mainScreen] frame];
if(s && *s){ if(s && *s){
@ -305,8 +292,7 @@ makewin(void)
[win.ofs[i] setDisplaysWhenScreenProfileChanges:NO]; [win.ofs[i] setDisplaysWhenScreenProfileChanges:NO];
} }
win.isofs = 0; win.isofs = 0;
win.content = [appview new]; win.content = [contentview new];
[win.content setAcceptsTouchEvents:YES];
[WIN setContentView:win.content]; [WIN setContentView:win.content];
[WIN makeKeyAndOrderFront:nil]; [WIN makeKeyAndOrderFront:nil];
} }
@ -345,7 +331,9 @@ initimg(void)
void void
_flushmemscreen(Rectangle r) _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 * Call "lockFocusIfCanDraw" from main thread, else
@ -357,17 +345,17 @@ _flushmemscreen(Rectangle r)
*/ */
[appdelegate [appdelegate
performSelectorOnMainThread:@selector(calldrawimg:) performSelectorOnMainThread:@selector(calldrawimg:)
withObject:nil withObject:[NSValue valueWithRect:rect]
waitUntilDone:YES]; waitUntilDone:YES];
} }
static void drawresizehandle(void); static void drawresizehandle(NSRect);
static void static void
drawimg(void) drawimg(NSRect dr)
{ {
static int first = 1; static int first = 1;
NSRect dr, sr; NSRect sr;
if(first){ if(first){
[NSTimer scheduledTimerWithTimeInterval:0.033 [NSTimer scheduledTimerWithTimeInterval:0.033
@ -376,7 +364,6 @@ drawimg(void)
repeats:YES]; repeats:YES];
first = 0; first = 0;
} }
dr = win.flushrect;
sr = [win.content convertRect:dr fromView:nil]; sr = [win.content convertRect:dr fromView:nil];
if([win.content lockFocusIfCanDraw]){ if([win.content lockFocusIfCanDraw]){
@ -394,7 +381,7 @@ drawimg(void)
respectFlipped:YES hints:nil]; respectFlipped:YES hints:nil];
if(OSX_VERSION<100700 && win.isofs==0) if(OSX_VERSION<100700 && win.isofs==0)
drawresizehandle(); drawresizehandle(dr);
[win.content unlockFocus]; [win.content unlockFocus];
win.needflush = 1; win.needflush = 1;
@ -418,7 +405,7 @@ enum
}; };
static void static void
drawresizehandle(void) drawresizehandle(NSRect dr)
{ {
NSColor *color[Barsize]; NSColor *color[Barsize];
NSPoint a,b; NSPoint a,b;
@ -431,7 +418,7 @@ drawresizehandle(void)
c = Pt(size.width, size.height); c = Pt(size.width, size.height);
r = NSMakeRect(0, 0, Handlesize, Handlesize); r = NSMakeRect(0, 0, Handlesize, Handlesize);
r.origin = NSMakePoint(c.x-Handlesize, c.y-Handlesize); r.origin = NSMakePoint(c.x-Handlesize, c.y-Handlesize);
if(NSIntersectsRect(r, win.flushrect) == 0) if(NSIntersectsRect(r,dr) == 0)
return; return;
[[WIN graphicsContext] setShouldAntialias:NO]; [[WIN graphicsContext] setShouldAntialias:NO];
@ -464,8 +451,9 @@ static void getgesture(NSEvent*);
static void getkeyboard(NSEvent*); static void getkeyboard(NSEvent*);
static void getmouse(NSEvent*); static void getmouse(NSEvent*);
static void gettouch(NSEvent*, int); static void gettouch(NSEvent*, int);
static void updatecursor(void);
@implementation appview @implementation contentview
- (void)drawRect:(NSRect)r - (void)drawRect:(NSRect)r
{ {
@ -481,29 +469,22 @@ static void gettouch(NSEvent*, int);
/* We should wait for P9P's image here. */ /* 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 - (BOOL)isFlipped
{ {
return YES; /* to have the origin at top left */ return YES; /* to make the content's origin top left */
} }
- (BOOL)acceptsFirstResponder - (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)mouseMoved:(NSEvent*)e{ getmouse(e);}
- (void)mouseDown:(NSEvent*)e{ getmouse(e);} - (void)mouseDown:(NSEvent*)e{ getmouse(e);}
- (void)mouseDragged:(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 static void
getmousepos(void) getmousepos(void)
{ {
@ -651,7 +663,10 @@ getmousepos(void)
p = [WIN mouseLocationOutsideOfEventStream]; p = [WIN mouseLocationOutsideOfEventStream];
p = [win.content convertPoint:p fromView:nil]; 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 static void
@ -660,6 +675,9 @@ getmouse(NSEvent *e)
float d; float d;
int b, m; int b, m;
if([WIN isKeyWindow] == 0)
return;
getmousepos(); getmousepos();
switch([e type]){ switch([e type]){
@ -977,21 +995,23 @@ setmouse(Point p)
NSPoint q; NSPoint q;
NSRect r; NSRect r;
if([NSApp isActive] == 0)
return;
if(first){ if(first){
/* Try to move Acme's scrollbars without that! */ /* Try to move Acme's scrollbars without that! */
CGSetLocalEventsSuppressionInterval(0); CGSetLocalEventsSuppressionInterval(0);
first = 0; first = 0;
} }
in.mpos = NSMakePoint(p.x, p.y); // race condition
r = [[WIN screen] frame]; r = [[WIN screen] frame];
q = NSMakePoint(p.x, p.y); q = [win.content convertPoint:in.mpos toView:nil];
q = [win.content convertPoint:q toView:nil];
q = [WIN convertBaseToScreen:q]; q = [WIN convertBaseToScreen:q];
q.y = r.size.height - q.y; q.y = r.size.height - q.y;
CGWarpMouseCursorPosition(NSPointToCGPoint(q)); CGWarpMouseCursorPosition(NSPointToCGPoint(q));
in.mpos = p; // race condition
} }
static void static void
@ -1004,6 +1024,7 @@ followzoombutton(NSRect r)
wr.origin.y += wr.size.height; wr.origin.y += wr.size.height;
r.origin.y += r.size.height; r.origin.y += r.size.height;
getmousepos();
p.x = (r.origin.x - wr.origin.x) + in.mpos.x; p.x = (r.origin.x - wr.origin.x) + in.mpos.x;
p.y = -(r.origin.y - wr.origin.y) + in.mpos.y; p.y = -(r.origin.y - wr.origin.y) + in.mpos.y;
setmouse(p); setmouse(p);
@ -1176,34 +1197,45 @@ kicklabel(char *label)
} }
void void
setcursor(Cursor *cursor) setcursor(Cursor *c)
{ {
/*
* No cursor change unless in main thread.
*/
[appdelegate [appdelegate
performSelectorOnMainThread:@selector(callsetcursor0:) performSelectorOnMainThread:@selector(callsetcursor0:)
withObject:[[NSValue valueWithPointer:cursor] retain] withObject:[NSValue valueWithPointer:c]
waitUntilDone:YES]; waitUntilDone:YES];
} }
void static void
setcursor0(Cursor *c) setcursor0(Cursor *c)
{
NSCursor *d;
d = win.cursor;
if(c)
win.cursor = makecursor(c);
else
win.cursor = nil;
updatecursor();
if(d)
[d release];
}
static NSCursor*
makecursor(Cursor *c)
{ {
NSBitmapImageRep *r; NSBitmapImageRep *r;
NSCursor *d;
NSImage *i; NSImage *i;
NSPoint p; NSPoint p;
int b; int b;
uchar *plane[5]; uchar *plane[5];
qlock(&win.cursorl);
if(win.cursor){
[win.cursor release];
win.cursor = nil;
}
if(c == nil && usebigarrow)
c = &bigarrow;
if(c){
r = [[NSBitmapImageRep alloc] r = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nil initWithBitmapDataPlanes:nil
pixelsWide:16 pixelsWide:16
@ -1225,14 +1257,9 @@ setcursor0(Cursor *c)
p = NSMakePoint(-c->offset.x, -c->offset.y); p = NSMakePoint(-c->offset.x, -c->offset.y);
i = [NSImage new]; i = [NSImage new];
[i addRepresentation:r]; [i addRepresentation:r];
win.cursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
[win.cursor set];
[i release];
[r release]; [r release];
}
qunlock(&win.cursorl); d = [[NSCursor alloc] initWithImage:i hotSpot:p];
[WIN invalidateCursorRectsForView:win.content]; [i release];
return d;
} }

View file

@ -59,7 +59,7 @@ elif [ $WSYSTYPE = osx ]; then
echo 'WSYSOFILES=$WSYSOFILES osx-screen-carbon-objc.o osx-draw.o osx-srv.o' echo 'WSYSOFILES=$WSYSOFILES osx-screen-carbon-objc.o osx-draw.o osx-srv.o'
echo 'MACARGV=macargv.o' echo 'MACARGV=macargv.o'
elif [ $WSYSTYPE = osx-cocoa ]; then 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' echo 'MACARGV=macargv-objc.o'
elif [ $WSYSTYPE = nowsys ]; then elif [ $WSYSTYPE = nowsys ]; then
echo 'WSYSOFILES=nowsys.o' echo 'WSYSOFILES=nowsys.o'