commit 48107872baacadfc18527fda65e096c95424b13f from: David Jeannot via: Russ Cox date: Mon Sep 19 12:58:59 2011 UTC devdraw: update Lion cocoa R=rsc CC=plan9port.codebot http://codereview.appspot.com/5015042 commit - 53000799bec3a182fe5cc64424bc6302d1e6ba55 commit + 48107872baacadfc18527fda65e096c95424b13f blob - /dev/null blob + 4af44da24a4421a9db221ed83eec5a41b46e36eb (mode 755) --- /dev/null +++ bin/osxvers @@ -0,0 +1,7 @@ +#!/bin/sh + +u=`uname` +case "$u" in +Darwin) + sw_vers | awk '$1 == "ProductVersion:" {print $2}' | awk -F. '{printf("CFLAGS=$CFLAGS -DOSX_VERSION=%d%02d%02d\n", $1, $2, $3)}' +esac blob - 2f6961a2cfef2e98a01bec3cb6094fb4d1f5eb52 blob + d8d63b413709316e2c6dfe6259ed404c43a4bdf5 --- src/cmd/9pfuse/mkfile +++ src/cmd/9pfuse/mkfile @@ -1,5 +1,5 @@ <$PLAN9/src/mkhdr -<|./osxvers +<|osxvers TARG=9pfuse blob - 4af44da24a4421a9db221ed83eec5a41b46e36eb (mode 755) blob + /dev/null --- src/cmd/9pfuse/osxvers +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -u=`uname` -case "$u" in -Darwin) - sw_vers | awk '$1 == "ProductVersion:" {print $2}' | awk -F. '{printf("CFLAGS=$CFLAGS -DOSX_VERSION=%d%02d%02d\n", $1, $2, $3)}' -esac blob - 3a53efb4daf4df47170107b536cb3dbbb5edfe8f blob + 797b9a58dc57c1da7ee14bd739bfa84f89956c00 --- src/cmd/devdraw/cocoa-screen.h +++ src/cmd/devdraw/cocoa-screen.h @@ -7,7 +7,7 @@ void setlabel(char*); char* getsnarf(void); void putsnarf(char*); -void mousetrack(int, int, int, int); +void mousetrack(int, int, int, uint); void keystroke(int); void kicklabel(char*); blob - 03f681712db9ef2e4da2f217dbf3e2da30a10f7f blob + f10614efb747e97eba46ad66963640927558caea --- src/cmd/devdraw/cocoa-screen.m +++ src/cmd/devdraw/cocoa-screen.m @@ -14,7 +14,7 @@ #include #include -#include "cocoa-thread.h" +#include "cocoa-thread.h" // try libthread when possible #include #include #include @@ -24,39 +24,18 @@ #include "devdraw.h" #include "glendapng.h" -#define DEBUG if(0)NSLog - AUTOFRAMEWORK(Cocoa) #define panic sysfatal -struct { - NSWindow *obj; - NSString *label; - char *winsize; - int ispositioned; +/* + * Incompatible with Magic Mouse? + */ +int reimplementswipe = 0; + int usecopygesture = 0; - NSImage *img; - Memimage *imgbuf; - NSSize imgsize; +int useoldfullscreen = 0; - QLock lock; - Rendez meeting; - NSRect flushr; - int osxdrawing; - int p9pflushing; - int isresizing; -} win; - -@interface appdelegate : NSObject - +(void)callmakewin:(id)arg; @end -@interface appthreads : NSObject - +(void)callservep9p:(id)arg; @end -@interface appview : NSView @end - -int chatty; -int multitouch = 1; - void usage(void) { @@ -64,6 +43,9 @@ usage(void) exits("usage"); } +@interface appdelegate : NSObject +@end + void main(int argc, char **argv) { @@ -78,22 +60,18 @@ main(int argc, char **argv) open("/dev/null", OREAD); open("/dev/null", OWRITE); + // Libdraw don't permit arguments currently. + ARGBEGIN{ - case 'D': - chatty++; + case 'D': // only for good ps -a listings break; - case 'M': - multitouch = 0; - break; default: usage(); }ARGEND - /* - * Ignore arguments. They're only for good ps -a listings. - */ + if(usecopygesture) + reimplementswipe = 1; - [NSApplication sharedApplication]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; [NSApp setDelegate:[appdelegate new]]; @@ -101,146 +79,193 @@ main(int argc, char **argv) [NSApp run]; } -static void eresized(int); +struct { + NSWindow *p; + NSView *content; + Cursor *cursor; + NSString *title; + QLock titlel; + char *rectstr; + NSRect lastrect; + NSBitmapImageRep *img; + NSRect flushrect; + int needflush; +} win; + +static void drawimg(void); +static void flushwin(void); +static void fullscreen(void); static void getmousepos(void); -static void makemenu(NSString*); -static void makewin(); -static void seticon(NSString*); +static void makeicon(void); +static void makemenu(void); +static void makewin(void); +static void resize(void); +static void sendmouse(int); +static void setcursor0(void); @implementation appdelegate - (void)applicationDidFinishLaunching:(id)arg { - [NSApplication detachDrawingThread:@selector(callservep9p:) - toTarget:[appthreads class] withObject:nil]; + makeicon(); + makemenu(); + [NSApplication + detachDrawingThread:@selector(callservep9p:) + toTarget:[self class] withObject:nil]; } -+ (void)callmakewin:(id)arg +- (void)windowDidBecomeKey:(id)arg { - makewin(); + getmousepos(); + sendmouse(0); } - (void)windowDidResize:(id)arg { - eresized(1); + getmousepos(); + sendmouse(0); + + if([win.p inLiveResize]) + return; + + resize(); } -- (void)windowDidBecomeKey:(id)arg +- (void)windowDidEndLiveResize:(id)arg { - getmousepos(); + resize(); } +- (void)windowDidDeminiaturize:(id)arg +{ + resize(); +} - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(id)arg { return YES; } -@end - -@implementation appthreads -+(void)callservep9p:(id)arg ++ (void)callservep9p:(id)arg { servep9p(); [NSApp terminate:self]; } ++ (void)calldrawimg:(id)arg{ drawimg();} ++ (void)callflushwin:(id)arg{ flushwin();} +- (void)callfullscreen:(id)arg{ fullscreen();} ++ (void)callmakewin:(id)arg{ makewin();} ++ (void)callsetcursor0:(id)arg{ setcursor0();} @end +static Memimage* makeimg(void); + Memimage* attachscreen(char *label, char *winsize) { static int first = 1; - if(! first--) + if(first) + first = 0; + else panic("attachscreen called twice"); if(label == nil) label = "gnot a label"; - win.label = [[NSString alloc] initWithUTF8String:label]; - win.meeting.l = &win.lock; - win.winsize = strdup(winsize); + win.rectstr = strdup(winsize); - makemenu(win.label); - -// make NSWindow in the main thread, -// else no resize cursor when resizing. +// Create window in main thread, +// else no cursor change when resizing. [appdelegate performSelectorOnMainThread:@selector(callmakewin:) withObject:nil waitUntilDone:YES]; // makewin(); - seticon(win.label); + kicklabel(label); + return makeimg(); +} - eresized(0); +@interface appview : NSView +@end - return win.imgbuf; +@interface appwin : NSWindow +@end + +@implementation appwin +- (NSTimeInterval)animationResizeTime:(NSRect)r +{ + return 0; } +@end -void -makewin(id winsize) +enum { - char *s; - int style; - NSWindow *w; + Winstyle = NSTitledWindowMask + | NSClosableWindowMask + | NSMiniaturizableWindowMask + | NSResizableWindowMask +}; + +static void +makewin(void) +{ NSRect r, sr; + NSView *v; + NSWindow *w; Rectangle wr; + char *s; + int set; - s = win.winsize; + s = win.rectstr; if(s && *s){ - if(parsewinsize(s, &wr, &win.ispositioned) < 0) + if(parsewinsize(s, &wr, &set) < 0) sysfatal("%r"); }else{ sr = [[NSScreen mainScreen] frame]; wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3); + set = 0; } // The origin is the left-bottom corner with Cocoa. -// Does the following work with any rectangles? r = NSMakeRect(wr.min.x, r.size.height-wr.min.y, Dx(wr), Dy(wr)); - style = NSTitledWindowMask - | NSClosableWindowMask - | NSResizableWindowMask - | NSMiniaturizableWindowMask; + v = [appview new]; + [v setAcceptsTouchEvents:YES]; - w = [[NSWindow alloc] + w = [[appwin alloc] initWithContentRect:r - styleMask:style + styleMask:Winstyle backing:NSBackingStoreBuffered defer:NO]; - - [w setAcceptsMouseMovedEvents:YES]; + if(!set) + [w center]; #if OSX_VERSION >= 100700 [w setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; #endif - [w setContentView:[appview new]]; + [w setAcceptsMouseMovedEvents:YES]; + [w setContentView:v]; [w setDelegate:[NSApp delegate]]; [w setMinSize:NSMakeSize(128,128)]; - [[w contentView] setAcceptsTouchEvents:YES]; - - if(win.ispositioned == 0) - [w center]; - - [w setTitle:win.label]; [w makeKeyAndOrderFront:nil]; - win.obj = w; + win.content = v; + win.p = w; } -static void sendmouse(int); - -static void -eresized(int new) +static Memimage* +makeimg(void) { static int first = 1; - uint ch; + Memimage *m; NSSize size; Rectangle r; - Memimage *m; - int bpl; + uint ch; - if(first--) + if(first){ memimageinit(); + first = 0; + } + size = [win.content bounds].size; - size = [[win.obj contentView] bounds].size; -DEBUG(@"eresized called new=%d, [%.0f %.0f] -> [%.0f %.0f]", new, -win.imgsize.width, win.imgsize.height, size.width, size.height); - + if(size.width<=0 || size.height<=0){ + NSLog(@"bad content size: %.0f %.0f", size.width, size.height); + return nil; + } r = Rect(0, 0, size.width, size.height); ch = XBGR32; m = allocmemimage(r, ch); @@ -249,42 +274,98 @@ win.imgsize.width, win.imgsize.height, size.width, siz if(m->data == nil) panic("m->data == nil"); - bpl = bytesperline(r, 32); - - CGDataProviderRef dp; - CGImageRef i; - CGColorSpaceRef cs; - - dp = CGDataProviderCreateWithData(0, m->data->bdata, Dy(r)*bpl, 0); - cs = CGColorSpaceCreateDeviceRGB(); - i = CGImageCreate(Dx(r), Dy(r), 8, 32, bpl, - cs, kCGImageAlphaNone, dp, 0, 0, kCGRenderingIntentDefault); - - _drawreplacescreenimage(m); if(win.img) [win.img release]; + win.img = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:&m->data->bdata + pixelsWide:Dx(r) + pixelsHigh:Dy(r) + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:bytesperline(r, 32) + bitsPerPixel:32]; - win.img = [[NSImage alloc] initWithCGImage:i size:size]; - win.imgbuf = m; - win.imgsize = size; + _drawreplacescreenimage(m); + return m; +} - CGColorSpaceRelease(cs); - CGDataProviderRelease(dp); - CGImageRelease(i); +static void +resize(void) +{ + makeimg(); + sendmouse(1); +} - if(new){ - win.isresizing = 1; // to call before mousetrack - sendmouse(1); +void +_flushmemscreen(Rectangle r) +{ + win.flushrect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r)); + +// Call "lockFocusIfCanDraw" from main thread, else +// we deadlock while synchronizing both threads with +// qlock(): main thread must apparently be idle while we call it. + [appdelegate + performSelectorOnMainThread:@selector(calldrawimg:) + withObject:nil + waitUntilDone:YES]; +} + +static void +drawimg(void) +{ + static int first = 1; + NSRect dr, sr; + + if(first){ + [NSTimer scheduledTimerWithTimeInterval:0.033 + target:[appdelegate class] + selector:@selector(callflushwin:) userInfo:nil + repeats:YES]; + first = 0; } -DEBUG(@"eresized exit"); + dr = win.flushrect; + sr = [win.content convertRect:dr fromView:nil]; + + if([win.content lockFocusIfCanDraw]){ + [win.img drawInRect:dr fromRect:sr + operation:NSCompositeCopy fraction:1 + respectFlipped:YES hints:nil]; + [win.content unlockFocus]; + win.needflush = 1; + } } +static void +flushwin(void) +{ + if(win.needflush){ + [win.p flushWindow]; + win.needflush = 0; + } +} + static void getgesture(NSEvent*); static void getkeyboard(NSEvent*); static void getmouse(NSEvent*); +static void gettouch(NSEvent*, int); @implementation appview +- (void)drawRect:(NSRect)r +{ + // else no window background +} +- (BOOL)isFlipped +{ + return YES; // to have the origin at top left +} +- (BOOL)acceptsFirstResponder +{ + return YES; // to receive mouseMoved events +} - (void)mouseMoved:(NSEvent*)e{ getmouse(e);} - (void)mouseDown:(NSEvent*)e{ getmouse(e);} - (void)mouseDragged:(NSEvent*)e{ getmouse(e);} @@ -300,108 +381,36 @@ static void getmouse(NSEvent*); - (void)keyDown:(NSEvent*)e{ getkeyboard(e);} - (void)flagsChanged:(NSEvent*)e{ getkeyboard(e);} -- (void)magnifyWithEvent:(NSEvent*)e{ DEBUG(@"magnifyWithEvent"); getgesture(e);} -- (void)swipeWithEvent:(NSEvent*)e{ DEBUG(@"swipeWithEvent"); getgesture(e);} -- (void)touchesEndedWithEvent:(NSEvent*)e{ DEBUG(@"touchesEndedWithEvent"); getgesture(e);} +- (void)swipeWithEvent:(NSEvent*)e{ getgesture(e);} +- (void)magnifyWithEvent:(NSEvent*)e{ getgesture(e);} -- (BOOL)acceptsFirstResponder{ return YES; } // to receive mouseMoved events -- (BOOL)isFlipped{ return YES; } -- (BOOL)isOpaque{ return YES; } // to disable background painting before drawRect calls - -- (void)drawRect:(NSRect)r +- (void)touchesBeganWithEvent:(NSEvent*)e { - NSRect sr; - NSView *v; - - v = [win.obj contentView]; - - DEBUG(@"drawRect called [%.0f %.0f] [%.0f %.0f]", - r.origin.x, r.origin.y, r.size.width, r.size.height); - - if(! NSEqualSizes([v bounds].size, win.imgsize)){ - DEBUG(@"drawRect: contentview & img don't correspond: [%.0f %.0f] [%.0f %.0f]", - [v bounds].size.width, [v bounds].size.height, - win.imgsize.width, win.imgsize.height); - return; - } - - qlock(win.meeting.l); - if(win.isresizing){ - if(! NSEqualRects(r, [v bounds])){ - DEBUG(@"drawRect reject osx"); - goto Return; - } - win.isresizing = 0; - DEBUG(@"drawRect serve osx"); - }else{ - if(! NSEqualRects(r, win.flushr)){ - DEBUG(@"drawRect reject p9p"); - goto Return; - } - DEBUG(@"drawRect serve p9p"); - } - win.flushr = r; - win.osxdrawing = 1; - rwakeup(&win.meeting); - DEBUG(@"drawRect rsleep for p9pflushing=1"); - while(win.p9pflushing == 0) - rsleep(&win.meeting); - - DEBUG(@"drawRect drawInRect [%.0f %.0f] [%.0f %.0f]", - r.origin.x, r.origin.y, r.size.width, r.size.height); - - sr = [v convertRect:r fromView:nil]; - [win.img drawInRect:r fromRect:sr - operation:NSCompositeCopy fraction:1 - respectFlipped:YES hints:nil]; - - [win.obj flushWindow]; - - win.osxdrawing = 0; - rwakeup(&win.meeting); -Return: - DEBUG(@"drawRect exit"); - qunlock(win.meeting.l); + gettouch(e, NSTouchPhaseBegan); } -@end - -void -_flushmemscreen(Rectangle r) +- (void)touchesMovedWithEvent:(NSEvent*)e +{ + gettouch(e, NSTouchPhaseMoved); +} +- (void)touchesEndedWithEvent:(NSEvent*)e { - NSRect rect; - NSView *v; - - v = [win.obj contentView]; - rect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r)); - - DEBUG(@"_flushmemscreen called [%.0f %.0f] [%.0f %.0f]", - rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); - qlock(win.meeting.l); - if(win.osxdrawing == 0){ - DEBUG(@"_flushmemscreen setNeedsDisplayInRect"); - [v setNeedsDisplayInRect:rect]; - win.flushr = rect; - DEBUG(@"_flushmemscreen rsleep for osxdrawing=1"); - while(win.osxdrawing == 0) - rsleep(&win.meeting); - } - if(! NSEqualRects(rect, win.flushr)){ - qunlock(win.meeting.l); - DEBUG(@"_flushmemscreen bad rectangle"); - return; - } - win.flushr = NSMakeRect(0,0,0,0); - win.p9pflushing = 1; - rwakeup(&win.meeting); - DEBUG(@"_flushmemscreen rsleep for osxdrawing=0"); - while(win.osxdrawing) - rsleep(&win.meeting); - - win.p9pflushing = 0; - DEBUG(@"_flushmemscreen exit"); - qunlock(win.meeting.l); + gettouch(e, NSTouchPhaseEnded); } +- (void)touchesCancelledWithEvent:(NSEvent*)e +{ + gettouch(e, NSTouchPhaseCancelled); +} +@end +struct { + int kalting; + int kbuttons; + int mbuttons; + Point mpos; + int mscroll; + int undo; +} in; + static int keycvt[] = { [QZ_IBOOK_ENTER] '\n', @@ -452,45 +461,26 @@ static int keycvt[] = [QZ_KP9] '9', }; -int kalting; -int kbuttons; -int mbuttons; -Point mpos; -int scroll; - static void getkeyboard(NSEvent *e) { - uint code; - int k, m; char c; + int k, m; + uint code; m = [e modifierFlags]; switch([e type]){ case NSKeyDown: - kalting = 0; + in.kalting = 0; c = [[e characters] characterAtIndex:0]; if(m & NSCommandKeyMask){ - -// If I add cmd+h in the menu, does the combination -// appear here? If it doesn't, remove the following -// -// // OS X interprets a few no matter what we do, -// switch(c) { -// case 'm': // minimize window -// case 'h': // hide window -// case 'H': // hide others -// case 'q': // quit -// return; -// } - if(' '<=c && c<='~') { + if(' '<=c && c<='~'){ keystroke(Kcmd+c); - return; } return; } -// to undersand +// to understand k = c; code = [e keyCode]; if(code < nelem(keycvt) && keycvt[code]) @@ -504,16 +494,16 @@ getkeyboard(NSEvent *e) break; case NSFlagsChanged: - if(mbuttons || kbuttons){ - kbuttons = 0; + if(in.mbuttons || in.kbuttons){ + in.kbuttons = 0; if(m & NSAlternateKeyMask) - kbuttons |= 2; + in.kbuttons |= 2; if(m & NSCommandKeyMask) - kbuttons |= 4; + in.kbuttons |= 4; sendmouse(0); }else - if(m & NSAlternateKeyMask) { - kalting = 1; + if(m & NSAlternateKeyMask){ + in.kalting = 1; keystroke(Kalt); } break; @@ -528,17 +518,16 @@ getmousepos(void) { NSPoint p; - p = [win.obj mouseLocationOutsideOfEventStream]; - p = [[win.obj contentView] convertPoint:p fromView:nil]; -// DEBUG(@"getmousepos: %0.f %0.f", p.x, p.y); - mpos = Pt(p.x, p.y); + p = [win.p mouseLocationOutsideOfEventStream]; + p = [win.content convertPoint:p fromView:nil]; + in.mpos = Pt(p.x, p.y); } static void getmouse(NSEvent *e) { - int b, m; float d; + int b, m; getmousepos(); @@ -549,25 +538,24 @@ getmouse(NSEvent *e) case NSOtherMouseUp: case NSRightMouseDown: case NSRightMouseUp: - b = [NSEvent pressedMouseButtons]; b = b&~6 | (b&4)>>1 | (b&2)<<1; b = mouseswap(b); if(b == 1){ m = [e modifierFlags]; - if(m & NSAlternateKeyMask) { + if(m & NSAlternateKeyMask){ b = 2; // Take the ALT away from the keyboard handler. - if(kalting) { - kalting = 0; + if(in.kalting){ + in.kalting = 0; keystroke(Kalt); } }else if(m & NSCommandKeyMask) b = 4; } - mbuttons = b; + in.mbuttons = b; break; case NSScrollWheel: @@ -577,9 +565,10 @@ getmouse(NSEvent *e) d = [e deltaY]; #endif if(d>0) - scroll = 8; - else if(d<0) - scroll = 16; + in.mscroll = 8; + else + if(d<0) + in.mscroll = 16; break; case NSMouseMoved: @@ -594,163 +583,314 @@ getmouse(NSEvent *e) sendmouse(0); } -static void sendexec(int); -static void sendcmd(int, int*); +static void sendswipe(int, int); static void getgesture(NSEvent *e) { - static int undo; - int dx, dy; - switch([e type]){ case NSEventTypeMagnify: -#if OSX_VERSION >= 100700 - [win.obj toggleFullScreen:nil]; -#endif +// if(fabs([e magnification]) > 0.025) + fullscreen(); break; case NSEventTypeSwipe: - - dx = - [e deltaX]; - dy = - [e deltaY]; + if(reimplementswipe) + break; - if(dx == -1) - sendcmd('x', &undo); - else - if(dx == +1) - sendcmd('v', &undo); - else - if(dy == -1) - sendexec(0); - else - if(dy == +1) - sendexec(1); - else // fingers lifted - undo = 0; + sendswipe(-[e deltaX], -[e deltaY]); break; + } +} -// When I lift the fingers from the trackpad, I -// receive 1, 2, or 3 events "touchesEndedWithEvent". -// Their type is either generic (NSEventTypeGesture) -// or specific (NSEventTypeSwipe for example). I -// always receive at least 1 event of specific type. +static void sendclick(int); +static void sendchord(int, int); +static void sendcmd(int); -// I sometimes receive NSEventTypeEndGesture -// apparently, even without implementing -// "endGestureWithEvent" -// I even received a NSEventTypeBeginGesture once. +static uint +msec(void) +{ + return nsec()/1000000; +} - case NSEventTypeBeginGesture: +enum +{ + Msec = 1, + Maxtap = 400*Msec, + Maxtouch = 3, + Mindelta = 0, + Minswipe = 15, +}; + +static void +gettouch(NSEvent *e, int type) +{ + static NSPoint delta, odelta; + static NSTouch *toucha[Maxtouch]; + static NSTouch *touchb[Maxtouch]; + static int done, ntouch, tapping; + static uint taptime; + NSArray *a; + NSPoint d; + NSSet *set; + NSSize s; + int i, p; + + if(reimplementswipe==0 && type!=NSTouchPhaseEnded) + return; + + switch(type){ + + case NSTouchPhaseBegan: + p = NSTouchPhaseTouching; + set = [e touchesMatchingPhase:p inView:nil]; + if(set.count == 3){ + tapping = 1; + taptime = msec(); + }else + if(set.count > 3) + tapping = 0; + return; + + case NSTouchPhaseMoved: + p = NSTouchPhaseMoved; + set = [e touchesMatchingPhase:p inView:nil]; + a = [set allObjects]; + if(set.count > Maxtouch) + return; + if(ntouch==0){ + ntouch = set.count; + for(i=0; iMindelta || fabs(d.y)>Mindelta){ + tapping = 0; + if(ntouch != 3){ + done = 1; + goto Return; + } + delta = NSMakePoint(delta.x+d.x, delta.y+d.y); + d = NSMakePoint(fabs(delta.x), fabs(delta.y)); + if(d.x>Minswipe || d.y>Minswipe){ + if(d.x > d.y) + delta = NSMakePoint(-copysign(1,delta.x), 0); + else + delta = NSMakePoint(0, copysign(1,delta.y)); + + if(! NSEqualPoints(delta, odelta)){ +// if(ntouch == 3) + sendswipe(-delta.x, -delta.y); + odelta = delta; + } + done = 1; + goto Return; + } + for(i=0; ir; - mousetrack(mpos.x, mpos.y, kbuttons|mbuttons|scroll, msec()); - scroll = 0; + mouserect = Rect(0, 0, size.width, size.height); + + b = in.kbuttons | in.mbuttons | in.mscroll; + mousetrack(in.mpos.x, in.mpos.y, b, msec()); + in.mscroll = 0; } void setmouse(Point p) { + static int first = 1; NSPoint q; NSRect r; - r = [[NSScreen mainScreen] frame]; + if(first){ +// try to move Acme's scrollbars without that! + CGSetLocalEventsSuppressionInterval(0); + first = 0; + } + r = [[win.p screen] frame]; q = NSMakePoint(p.x,p.y); - q = [[win.obj contentView] convertPoint:q toView:nil]; - q = [win.obj convertBaseToScreen:q]; + q = [win.content convertPoint:q toView:nil]; + q = [win.p convertBaseToScreen:q]; q.y = r.size.height - q.y; - CGWarpMouseCursorPosition(q); + CGWarpMouseCursorPosition(NSPointToCGPoint(q)); // race condition - mpos = p; + in.mpos = p; + +//NSLog(@"setmouse %d %d", p.x, p.y); } -// setBadgeLabel don't have to be in this function. -// Remove seticon's argument too. static void -seticon(NSString *s) +fullscreen(void) { - NSData *d; - NSImage *i; +#if OSX_VERSION >= 100700 + if(useoldfullscreen == 0){ + [win.p toggleFullScreen:nil]; + return; + } +#endif + NSScreen *screen; + int opt; - d = [[NSData alloc] - initWithBytes:glenda_png - length:(sizeof glenda_png)]; + screen = [win.p screen]; - i = [[NSImage alloc] initWithData:d]; - if(i){ - [NSApp setApplicationIconImage:i]; - [[NSApp dockTile] display]; - [[NSApp dockTile] setBadgeLabel:s]; + if(NSEqualRects([win.p frame], [screen frame])){ + opt = NSApplicationPresentationDefault; + [NSApp setPresentationOptions:opt]; + [win.p setStyleMask:Winstyle]; + [win.p setFrame:win.lastrect display:YES]; + }else{ + win.lastrect = [win.p frame]; + opt = NSApplicationPresentationAutoHideDock + | NSApplicationPresentationAutoHideMenuBar; + [NSApp setPresentationOptions:opt]; + [win.p setStyleMask:NSBorderlessWindowMask]; + [win.p setFrame:[screen frame] display:YES]; } - [d release]; - [i release]; -} +// On OS X Lion, after "setStyleMask", window is activated (the gesture work for example), but no keyboard input until mouse or trackpad pressed +// What I tried without success on OS X Lion: +// [NSApp activateIgnoringOtherApps:YES]; +// [win.p makeKeyAndOrderFront:nil]; +// implementing canBecomeKeyWindow +// implementing canBecomeMainWindow +// saving/restoring [win.content nextResponder] +// using enterFullScreenMode instead +// What I didn't try: +// using 2 windows instead: one for each mode -// Menu should be called during app creation, not window creation. -// See ./osx-delegate.m implementation. + qlock(&win.titlel); + [win.p setTitle:win.title]; + qunlock(&win.titlel); +} -// If an application supports fullscreen, it should -// add an "Enter Full Screen" menu item to the View -// menu. The menu item is now available through -// Xcode 4. You can also add the item -// programmatically, with toggleFullScreen: as the -// action, nil as the target, and cmd-ctrl-f as the -// key equivalent. AppKit will automatically update -// the menu item title as part of its menu item -// validation. +// Rewrite this function +// See ./osx-delegate.m implementation (NSLocalizedString) static void -makemenu(NSString *s) +makemenu(void) { NSString *title; NSMenu *menu; @@ -762,26 +902,51 @@ makemenu(NSString *s) [NSApp setMenu:menu]; [menu release]; - title = [@"Quit " stringByAppendingString:win.label]; + menu = [NSMenu new]; + + title = @"Full Screen"; item = [[NSMenuItem alloc] initWithTitle:title - action:@selector(terminate:) keyEquivalent:@"q"]; + action:@selector(callfullscreen:) keyEquivalent:@"f"]; + [menu addItem:item]; + [item release]; - menu = [NSMenu new]; + title = @"Quit"; + item = [[NSMenuItem alloc] + initWithTitle:title + action:@selector(terminate:) keyEquivalent:@"q"]; [menu addItem:item]; [item release]; + [appmenu setSubmenu:menu]; [appmenu release]; [menu release]; } +static void +makeicon(void) +{ + NSData *d; + NSImage *i; + + d = [[NSData alloc] + initWithBytes:glenda_png + length:(sizeof glenda_png)]; + + i = [[NSImage alloc] initWithData:d]; + [NSApp setApplicationIconImage:i]; + [[NSApp dockTile] display]; + [i release]; + [d release]; +} + QLock snarfl; char* getsnarf(void) { - NSString *s; NSPasteboard *pb; + NSString *s; pb = [NSPasteboard generalPasteboard]; @@ -797,15 +962,22 @@ getsnarf(void) return strdup((char*)[s UTF8String]); else return nil; -// should I call autorelease here for example? + +// "you should periodically drain and create +// autorelease pools (like the Application Kit does +// on the main thread); otherwise, autoreleased +// objects accumulate and your memory footprint +// grows." +// Should we do it here? +// Verify that we need it before. } void putsnarf(char *s) { NSArray *t; - NSString *str; NSPasteboard *pb; + NSString *str; int r; if(strlen(s) >= SnarfSize) @@ -821,15 +993,81 @@ putsnarf(char *s) qunlock(&snarfl); if(!r) - DEBUG(@"putsnarf: setString failed"); + NSLog(@"putsnarf: setString failed"); } void -kicklabel(char *c) +kicklabel(char *label) { + if(label == nil) + return; + + qlock(&win.titlel); + if(win.title) + [win.title release]; + win.title = [[NSString alloc] initWithUTF8String:label]; + [win.p setTitle:win.title]; + [[NSApp dockTile] setBadgeLabel:win.title]; + qunlock(&win.titlel); } void -setcursor(Cursor *c) +setcursor(Cursor *cursor) { + win.cursor = cursor; + +// cursor change only if main thread + [appdelegate + performSelectorOnMainThread:@selector(callsetcursor0:) + withObject:nil + waitUntilDone:YES]; +// setcursor0(); + + win.cursor = nil; } + +static void +setcursor0(void) +{ + Cursor *c; + NSBitmapImageRep *r; + NSCursor *d; + NSImage *i; + NSPoint p; + int b; + uchar *plane[5]; + + c = win.cursor; + + if(c == nil){ + [[NSCursor arrowCursor] set]; + return; + } + 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]; + d = [[NSCursor alloc] initWithImage:i hotSpot:p]; + [d set]; + + [d release]; + [r release]; + [i release]; +} blob - 507138f8e4e19b1d9cd06b61d10a3690ad24e563 blob + 191a66893f78ddd3911306fa679a35bec2b30577 --- src/cmd/devdraw/cocoa-srv.c +++ src/cmd/devdraw/cocoa-srv.c @@ -308,7 +308,7 @@ matchmouse(void) } void -mousetrack(int x, int y, int b, int ms) +mousetrack(int x, int y, int b, uint ms) { Mouse *m; blob - 4b2443cebee3a3a214ba3a99ca3935817bfcb11f blob + a69d082831a2cb7530637f9bf7ca3f9d30302ba7 --- src/cmd/devdraw/cocoa-thread.c +++ src/cmd/devdraw/cocoa-thread.c @@ -23,32 +23,3 @@ qunlock(QLock *q) { pthread_mutex_unlock(&q->m); } - -static void -rinit(Rendez *r) -{ - pthread_mutex_lock(&initlock); - if(r->init == 0){ - pthread_cond_init(&r->c, nil); - r->init = 1; - } - pthread_mutex_unlock(&initlock); -} - -void -rsleep(Rendez *r) -{ - if(r->init == 0) - rinit(r); - pthread_cond_wait(&r->c, &r->l->m); -} - -int -rwakeup(Rendez *r) -{ - if(r->init == 0) - rinit(r); - pthread_cond_signal(&r->c); - - return 0; -} blob - 17a12eb78b1970540f72a2d13f633bc013c5f438 blob + 925c4e0e9b8f92c771ad2485b4c5d12d753d618b --- src/cmd/devdraw/cocoa-thread.h +++ src/cmd/devdraw/cocoa-thread.h @@ -1,12 +1,8 @@ #define QLock DQLock #define qlock dqlock #define qunlock dqunlock -#define Rendez DRendez -#define rsleep drsleep -#define rwakeup drwakeup typedef struct QLock QLock; -typedef struct Rendez Rendez; struct QLock { @@ -14,14 +10,5 @@ struct QLock int init; }; -struct Rendez -{ - QLock *l; - pthread_cond_t c; - int init; -}; - void qlock(QLock*); void qunlock(QLock*); -void rsleep(Rendez*); -int rwakeup(Rendez*); /* BUG: always returns 0 */ blob - 61d59839ab1343010c33b15e2d35ae716efef996 blob + 1e7ac0bfa0e128caba507b397056f360b810fbee --- src/cmd/devdraw/mkfile +++ src/cmd/devdraw/mkfile @@ -1,4 +1,5 @@ <$PLAN9/src/mkhdr +<|osxvers TARG=devdraw