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 = {
{0, 0},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,

View file

@ -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)
{
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;
NSCursor *d;
NSImage *i;
NSPoint p;
int b;
uchar *plane[5];
qlock(&win.cursorl);
r = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nil
pixelsWide:16
pixelsHigh:16
bitsPerSample:1
samplesPerPixel:2
hasAlpha:YES
isPlanar:YES
colorSpaceName:NSDeviceBlackColorSpace
bytesPerRow:2
bitsPerPixel:1];
if(win.cursor){
[win.cursor release];
win.cursor = nil;
[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];
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];
win.cursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
[win.cursor set];
[i release];
[r release];
}
qunlock(&win.cursorl);
[WIN invalidateCursorRectsForView:win.content];
d = [[NSCursor alloc] initWithImage:i hotSpot:p];
[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 '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'