| /* |
| * Cocoa's event loop must be in the main thread. |
| */ |
| |
| #define Point OSXPoint |
| #define Rect OSXRect |
| #define Cursor OSXCursor |
| |
| #import <Cocoa/Cocoa.h> |
| |
| #undef Rect |
| #undef Point |
| #undef Cursor |
| |
| #include <u.h> |
| #include <libc.h> |
| #include "cocoa-thread.h" // try libthread when possible |
| #include <draw.h> |
| #include <memdraw.h> |
| #include <keyboard.h> |
| #include <cursor.h> |
| #include "cocoa-screen.h" |
| #include "osx-keycodes.h" |
| #include "devdraw.h" |
| #include "glendapng.h" |
| |
| AUTOFRAMEWORK(Cocoa) |
| |
| #define panic sysfatal |
| |
| /* |
| * Incompatible with Magic Mouse? |
| */ |
| int reimplementswipe = 0; |
| int usecopygesture = 0; |
| |
| int useoldfullscreen = 0; |
| |
| void |
| usage(void) |
| { |
| fprint(2, "usage: devdraw (don't run directly)\n"); |
| exits("usage"); |
| } |
| |
| @interface appdelegate : NSObject |
| @end |
| |
| void |
| main(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); |
| |
| // Libdraw don't permit arguments currently. |
| |
| ARGBEGIN{ |
| case 'D': // only for good ps -a listings |
| break; |
| default: |
| usage(); |
| }ARGEND |
| |
| if(usecopygesture) |
| reimplementswipe = 1; |
| |
| [NSApplication sharedApplication]; |
| [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; |
| [NSApp setDelegate:[appdelegate new]]; |
| [NSApp activateIgnoringOtherApps:YES]; |
| [NSApp run]; |
| } |
| |
| 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 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 |
| { |
| makeicon(); |
| makemenu(); |
| [NSApplication |
| detachDrawingThread:@selector(callservep9p:) |
| toTarget:[self class] withObject:nil]; |
| } |
| - (void)windowDidBecomeKey:(id)arg |
| { |
| getmousepos(); |
| sendmouse(0); |
| } |
| - (void)windowDidResize:(id)arg |
| { |
| getmousepos(); |
| sendmouse(0); |
| |
| if([win.p inLiveResize]) |
| return; |
| |
| resize(); |
| } |
| - (void)windowDidEndLiveResize:(id)arg |
| { |
| resize(); |
| } |
| - (void)windowDidDeminiaturize:(id)arg |
| { |
| resize(); |
| } |
| - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(id)arg |
| { |
| return YES; |
| } |
| + (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) |
| first = 0; |
| else |
| panic("attachscreen called twice"); |
| |
| if(label == nil) |
| label = "gnot a label"; |
| |
| win.rectstr = strdup(winsize); |
| |
| // Create window in main thread, |
| // else no cursor change when resizing. |
| [appdelegate |
| performSelectorOnMainThread:@selector(callmakewin:) |
| withObject:nil |
| waitUntilDone:YES]; |
| // makewin(); |
| |
| kicklabel(label); |
| return makeimg(); |
| } |
| |
| @interface appview : NSView |
| @end |
| |
| @interface appwin : NSWindow |
| @end |
| |
| @implementation appwin |
| - (NSTimeInterval)animationResizeTime:(NSRect)r |
| { |
| return 0; |
| } |
| @end |
| |
| enum |
| { |
| Winstyle = NSTitledWindowMask |
| | NSClosableWindowMask |
| | NSMiniaturizableWindowMask |
| | NSResizableWindowMask |
| }; |
| |
| static void |
| makewin(void) |
| { |
| NSRect r, sr; |
| NSView *v; |
| NSWindow *w; |
| Rectangle wr; |
| char *s; |
| int set; |
| |
| s = win.rectstr; |
| |
| if(s && *s){ |
| 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. |
| r = NSMakeRect(wr.min.x, r.size.height-wr.min.y, Dx(wr), Dy(wr)); |
| |
| v = [appview new]; |
| [v setAcceptsTouchEvents:YES]; |
| |
| w = [[appwin alloc] |
| initWithContentRect:r |
| styleMask:Winstyle |
| backing:NSBackingStoreBuffered |
| defer:NO]; |
| if(!set) |
| [w center]; |
| #if OSX_VERSION >= 100700 |
| [w setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; |
| #endif |
| [w setAcceptsMouseMovedEvents:YES]; |
| [w setContentView:v]; |
| [w setDelegate:[NSApp delegate]]; |
| [w setMinSize:NSMakeSize(128,128)]; |
| [w makeKeyAndOrderFront:nil]; |
| |
| win.content = v; |
| win.p = w; |
| } |
| |
| static Memimage* |
| makeimg(void) |
| { |
| static int first = 1; |
| Memimage *m; |
| NSSize size; |
| Rectangle r; |
| uint ch; |
| |
| if(first){ |
| memimageinit(); |
| first = 0; |
| } |
| size = [win.content bounds].size; |
| |
| 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); |
| if(m == nil) |
| panic("allocmemimage: %r"); |
| if(m->data == nil) |
| panic("m->data == nil"); |
| |
| 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]; |
| |
| _drawreplacescreenimage(m); |
| return m; |
| } |
| |
| static void |
| resize(void) |
| { |
| makeimg(); |
| 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; |
| } |
| 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);} |
| - (void)mouseUp:(NSEvent*)e{ getmouse(e);} |
| - (void)otherMouseDown:(NSEvent*)e{ getmouse(e);} |
| - (void)otherMouseDragged:(NSEvent*)e{ getmouse(e);} |
| - (void)otherMouseUp:(NSEvent*)e{ getmouse(e);} |
| - (void)rightMouseDown:(NSEvent*)e{ getmouse(e);} |
| - (void)rightMouseDragged:(NSEvent*)e{ getmouse(e);} |
| - (void)rightMouseUp:(NSEvent*)e{ getmouse(e);} |
| - (void)scrollWheel:(NSEvent*)e{ getmouse(e);} |
| |
| - (void)keyDown:(NSEvent*)e{ getkeyboard(e);} |
| - (void)flagsChanged:(NSEvent*)e{ getkeyboard(e);} |
| |
| - (void)swipeWithEvent:(NSEvent*)e{ getgesture(e);} |
| - (void)magnifyWithEvent:(NSEvent*)e{ getgesture(e);} |
| |
| - (void)touchesBeganWithEvent:(NSEvent*)e |
| { |
| gettouch(e, NSTouchPhaseBegan); |
| } |
| - (void)touchesMovedWithEvent:(NSEvent*)e |
| { |
| gettouch(e, NSTouchPhaseMoved); |
| } |
| - (void)touchesEndedWithEvent:(NSEvent*)e |
| { |
| 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', |
| [QZ_RETURN] '\n', |
| [QZ_ESCAPE] 27, |
| [QZ_BACKSPACE] '\b', |
| [QZ_LALT] Kalt, |
| [QZ_LCTRL] Kctl, |
| [QZ_LSHIFT] Kshift, |
| [QZ_F1] KF+1, |
| [QZ_F2] KF+2, |
| [QZ_F3] KF+3, |
| [QZ_F4] KF+4, |
| [QZ_F5] KF+5, |
| [QZ_F6] KF+6, |
| [QZ_F7] KF+7, |
| [QZ_F8] KF+8, |
| [QZ_F9] KF+9, |
| [QZ_F10] KF+10, |
| [QZ_F11] KF+11, |
| [QZ_F12] KF+12, |
| [QZ_INSERT] Kins, |
| [QZ_DELETE] 0x7F, |
| [QZ_HOME] Khome, |
| [QZ_END] Kend, |
| [QZ_KP_PLUS] '+', |
| [QZ_KP_MINUS] '-', |
| [QZ_TAB] '\t', |
| [QZ_PAGEUP] Kpgup, |
| [QZ_PAGEDOWN] Kpgdown, |
| [QZ_UP] Kup, |
| [QZ_DOWN] Kdown, |
| [QZ_LEFT] Kleft, |
| [QZ_RIGHT] Kright, |
| [QZ_KP_MULTIPLY] '*', |
| [QZ_KP_DIVIDE] '/', |
| [QZ_KP_ENTER] '\n', |
| [QZ_KP_PERIOD] '.', |
| [QZ_KP0] '0', |
| [QZ_KP1] '1', |
| [QZ_KP2] '2', |
| [QZ_KP3] '3', |
| [QZ_KP4] '4', |
| [QZ_KP5] '5', |
| [QZ_KP6] '6', |
| [QZ_KP7] '7', |
| [QZ_KP8] '8', |
| [QZ_KP9] '9', |
| }; |
| |
| static void |
| getkeyboard(NSEvent *e) |
| { |
| char c; |
| int k, m; |
| uint code; |
| |
| m = [e modifierFlags]; |
| |
| switch([e type]){ |
| case NSKeyDown: |
| in.kalting = 0; |
| c = [[e characters] characterAtIndex:0]; |
| if(m & NSCommandKeyMask){ |
| if(' '<=c && c<='~'){ |
| keystroke(Kcmd+c); |
| } |
| return; |
| } |
| // to understand |
| k = c; |
| code = [e keyCode]; |
| if(code < nelem(keycvt) && keycvt[code]) |
| k = keycvt[code]; |
| if(k == 0) |
| return; |
| if(k > 0) |
| keystroke(k); |
| else |
| keystroke(c); |
| break; |
| |
| case NSFlagsChanged: |
| if(in.mbuttons || in.kbuttons){ |
| in.kbuttons = 0; |
| if(m & NSAlternateKeyMask) |
| in.kbuttons |= 2; |
| if(m & NSCommandKeyMask) |
| in.kbuttons |= 4; |
| sendmouse(0); |
| }else |
| if(m & NSAlternateKeyMask){ |
| in.kalting = 1; |
| keystroke(Kalt); |
| } |
| break; |
| |
| default: |
| panic("getkey: unexpected event type"); |
| } |
| } |
| |
| static void |
| getmousepos(void) |
| { |
| NSPoint p; |
| |
| p = [win.p mouseLocationOutsideOfEventStream]; |
| p = [win.content convertPoint:p fromView:nil]; |
| in.mpos = Pt(p.x, p.y); |
| } |
| |
| static void |
| getmouse(NSEvent *e) |
| { |
| float d; |
| int b, m; |
| |
| getmousepos(); |
| |
| switch([e type]){ |
| case NSLeftMouseDown: |
| case NSLeftMouseUp: |
| case NSOtherMouseDown: |
| 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){ |
| b = 2; |
| // Take the ALT away from the keyboard handler. |
| if(in.kalting){ |
| in.kalting = 0; |
| keystroke(Kalt); |
| } |
| }else |
| if(m & NSCommandKeyMask) |
| b = 4; |
| } |
| in.mbuttons = b; |
| break; |
| |
| case NSScrollWheel: |
| #if OSX_VERSION >= 100700 |
| d = [e scrollingDeltaY]; |
| #else |
| d = [e deltaY]; |
| #endif |
| if(d>0) |
| in.mscroll = 8; |
| else |
| if(d<0) |
| in.mscroll = 16; |
| break; |
| |
| case NSMouseMoved: |
| case NSLeftMouseDragged: |
| case NSRightMouseDragged: |
| case NSOtherMouseDragged: |
| break; |
| |
| default: |
| panic("getmouse: unexpected event type"); |
| } |
| sendmouse(0); |
| } |
| |
| static void sendswipe(int, int); |
| |
| static void |
| getgesture(NSEvent *e) |
| { |
| switch([e type]){ |
| |
| case NSEventTypeMagnify: |
| // if(fabs([e magnification]) > 0.025) |
| fullscreen(); |
| break; |
| |
| case NSEventTypeSwipe: |
| if(reimplementswipe) |
| break; |
| |
| sendswipe(-[e deltaX], -[e deltaY]); |
| break; |
| } |
| } |
| |
| static void sendclick(int); |
| static void sendchord(int, int); |
| static void sendcmd(int); |
| |
| static uint |
| msec(void) |
| { |
| return nsec()/1000000; |
| } |
| |
| 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; i<ntouch; i++){ |
| assert(toucha[i] == nil); |
| toucha[i] = [[a objectAtIndex:i] retain]; |
| } |
| return; |
| } |
| if(ntouch != set.count) |
| break; |
| if(done) |
| return; |
| |
| d = NSMakePoint(0,0); |
| for(i=0; i<ntouch; i++){ |
| assert(touchb[i] == nil); |
| touchb[i] = [a objectAtIndex:i]; |
| d.x += touchb[i].normalizedPosition.x; |
| d.y += touchb[i].normalizedPosition.y; |
| d.x -= toucha[i].normalizedPosition.x; |
| d.y -= toucha[i].normalizedPosition.y; |
| } |
| s = toucha[0].deviceSize; |
| d.x = d.x/ntouch * s.width; |
| d.y = d.y/ntouch * s.height; |
| if(fabs(d.x)>Mindelta || 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; i<ntouch; i++){ |
| [toucha[i] release]; |
| toucha[i] = [touchb[i] retain]; |
| } |
| } |
| Return: |
| for(i=0; i<ntouch; i++) |
| touchb[i] = nil; |
| return; |
| |
| case NSTouchPhaseEnded: |
| p = NSTouchPhaseTouching; |
| set = [e touchesMatchingPhase:p inView:nil]; |
| if(set.count == 0){ |
| in.undo = 0; |
| |
| if(usecopygesture) |
| if(tapping && msec()-taptime<Maxtap) |
| sendclick(2); |
| tapping = 0; |
| odelta = NSMakePoint(0,0); |
| } |
| break; |
| |
| case NSTouchPhaseCancelled: |
| break; |
| |
| default: |
| panic("gettouch: unexpected event type: %d", type); |
| } |
| for(i=0; i<ntouch; i++){ |
| [toucha[i] release]; |
| toucha[i] = nil; |
| } |
| for(i=0; i<3; i++){ |
| assert(toucha[i] == nil); |
| assert(touchb[i] == nil); |
| } |
| ntouch = 0; |
| delta = NSMakePoint(0,0); |
| done = 0; |
| } |
| |
| static void |
| sendswipe(int dx, int dy) |
| { |
| if(dx == -1){ |
| sendcmd('x'); |
| }else |
| if(dx == +1){ |
| sendcmd('v'); |
| }else |
| if(dy == -1){ |
| if(usecopygesture) |
| sendcmd('c'); |
| else |
| sendclick(2); |
| }else |
| if(dy == +1){ |
| sendchord(2,1); |
| } |
| } |
| |
| static void |
| sendcmd(int c) |
| { |
| if(c=='x' || c=='v'){ |
| if(in.undo) |
| c = 'z'; |
| in.undo = ! in.undo; |
| } |
| keystroke(Kcmd+c); |
| } |
| |
| static void |
| sendclick(int b) |
| { |
| in.mbuttons = b; |
| sendmouse(0); |
| in.mbuttons = 0; |
| sendmouse(0); |
| } |
| |
| static void |
| sendchord(int b1, int b2) |
| { |
| in.mbuttons = b1; |
| sendmouse(0); |
| in.mbuttons |= b2; |
| sendmouse(0); |
| in.mbuttons = 0; |
| sendmouse(0); |
| } |
| |
| static void |
| sendmouse(int resized) |
| { |
| NSSize size; |
| int b; |
| |
| size = [win.img size]; |
| |
| if(resized) |
| mouseresized = 1; |
| 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; |
| |
| 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.content convertPoint:q toView:nil]; |
| q = [win.p convertBaseToScreen:q]; |
| q.y = r.size.height - q.y; |
| |
| CGWarpMouseCursorPosition(NSPointToCGPoint(q)); |
| |
| // race condition |
| in.mpos = p; |
| |
| //NSLog(@"setmouse %d %d", p.x, p.y); |
| } |
| |
| static void |
| fullscreen(void) |
| { |
| #if OSX_VERSION >= 100700 |
| if(useoldfullscreen == 0){ |
| [win.p toggleFullScreen:nil]; |
| return; |
| } |
| #endif |
| NSScreen *screen; |
| int opt; |
| |
| screen = [win.p screen]; |
| |
| 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]; |
| } |
| // 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 |
| |
| qlock(&win.titlel); |
| [win.p setTitle:win.title]; |
| qunlock(&win.titlel); |
| } |
| |
| // Rewrite this function |
| // See ./osx-delegate.m implementation (NSLocalizedString) |
| static void |
| makemenu(void) |
| { |
| NSString *title; |
| NSMenu *menu; |
| NSMenuItem *appmenu, *item; |
| |
| menu = [NSMenu new]; |
| appmenu = [NSMenuItem new]; |
| [menu addItem:appmenu]; |
| [NSApp setMenu:menu]; |
| [menu release]; |
| |
| menu = [NSMenu new]; |
| |
| title = @"Full Screen"; |
| item = [[NSMenuItem alloc] |
| initWithTitle:title |
| action:@selector(callfullscreen:) keyEquivalent:@"f"]; |
| [menu addItem:item]; |
| [item release]; |
| |
| 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) |
| { |
| NSPasteboard *pb; |
| NSString *s; |
| |
| pb = [NSPasteboard generalPasteboard]; |
| |
| // use NSPasteboardTypeString instead of NSStringPboardType |
| qlock(&snarfl); |
| s = [pb stringForType:NSStringPboardType]; |
| qunlock(&snarfl); |
| |
| // change the pastebuffer here to see if s is |
| // altered. Move the lock accordingly. |
| |
| if(s) |
| return strdup((char*)[s UTF8String]); |
| else |
| return nil; |
| |
| // "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; |
| NSPasteboard *pb; |
| NSString *str; |
| int r; |
| |
| if(strlen(s) >= SnarfSize) |
| return; |
| |
| t = [NSArray arrayWithObject:NSPasteboardTypeString]; |
| pb = [NSPasteboard generalPasteboard]; |
| str = [[NSString alloc] initWithUTF8String:s]; |
| |
| qlock(&snarfl); |
| [pb declareTypes:t owner:nil]; |
| r = [pb setString:str forType:NSPasteboardTypeString]; |
| qunlock(&snarfl); |
| |
| if(!r) |
| NSLog(@"putsnarf: setString failed"); |
| } |
| |
| void |
| 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 *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]; |
| } |