| # Based on http://cocoawithlove.com/2010/09/minimalist-cocoa-programming.html |
| # by Juraj Sukop. This demo was eventually expanded into a more complete |
| # Cocoa library available at https://bitbucket.org/sukop/nspython . |
| |
| from cffi import FFI |
| |
| ffi = FFI() |
| ffi.cdef(''' |
| |
| typedef signed char BOOL; |
| |
| typedef long NSInteger; |
| typedef unsigned long NSUInteger; |
| typedef NSInteger NSApplicationActivationPolicy; |
| typedef NSUInteger NSBackingStoreType; |
| typedef NSUInteger NSStringEncoding; |
| |
| typedef double CGFloat; |
| struct CGPoint { |
| CGFloat x; |
| CGFloat y; |
| }; |
| typedef struct CGPoint CGPoint; |
| struct CGSize { |
| CGFloat width; |
| CGFloat height; |
| }; |
| typedef struct CGSize CGSize; |
| struct CGRect { |
| CGPoint origin; |
| CGSize size; |
| }; |
| typedef struct CGRect CGRect; |
| |
| typedef CGPoint NSPoint; |
| typedef CGSize NSSize; |
| typedef CGRect NSRect; |
| |
| typedef struct objc_class *Class; |
| typedef struct objc_object { |
| Class isa; |
| } *id; |
| typedef struct objc_selector *SEL; |
| |
| SEL sel_registerName(const char *str); |
| id objc_getClass(const char *name); |
| id objc_msgSend(id theReceiver, SEL theSelector, ...); |
| |
| ''') |
| |
| objc = ffi.dlopen('objc') |
| appkit = ffi.dlopen('AppKit') |
| |
| nil = ffi.NULL |
| YES = ffi.cast('BOOL', 1) |
| NO = ffi.cast('BOOL', 0) |
| |
| NSASCIIStringEncoding = ffi.cast('NSStringEncoding', 1) |
| NSApplicationActivationPolicyRegular = ffi.cast('NSApplicationActivationPolicy', 0) |
| NSTitledWindowMask = ffi.cast('NSUInteger', 1) |
| NSBackingStoreBuffered = ffi.cast('NSBackingStoreType', 2) |
| |
| NSMakePoint = lambda x, y: ffi.new('NSPoint *', (x, y))[0] |
| NSMakeRect = lambda x, y, w, h: ffi.new('NSRect *', ((x, y), (w, h)))[0] |
| |
| get, send, sel = objc.objc_getClass, objc.objc_msgSend, objc.sel_registerName |
| at = lambda s: send( |
| get('NSString'), |
| sel('stringWithCString:encoding:'), |
| ffi.new('char[]', s), NSASCIIStringEncoding) |
| |
| send(get('NSAutoreleasePool'), sel('new')) |
| app = send(get('NSApplication'), sel('sharedApplication')) |
| send(app, sel('setActivationPolicy:'), NSApplicationActivationPolicyRegular) |
| |
| menubar = send(send(get('NSMenu'), sel('new')), sel('autorelease')) |
| appMenuItem = send(send(get('NSMenuItem'), sel('new')), sel('autorelease')) |
| send(menubar, sel('addItem:'), appMenuItem) |
| send(app, sel('setMainMenu:'), menubar) |
| |
| appMenu = send(send(get('NSMenu'), sel('new')), sel('autorelease')) |
| appName = send(send(get('NSProcessInfo'), sel('processInfo')), sel('processName')) |
| quitTitle = send(at('Quit '), sel('stringByAppendingString:'), appName) |
| quitMenuItem = send(send(send( |
| get('NSMenuItem'), sel('alloc')), |
| sel('initWithTitle:action:keyEquivalent:'), |
| quitTitle, sel('terminate:'), at('q')), |
| sel('autorelease')) |
| send(appMenu, sel('addItem:'), quitMenuItem) |
| send(appMenuItem, sel('setSubmenu:'), appMenu) |
| |
| window = send(send(send( |
| get('NSWindow'), sel('alloc')), |
| sel('initWithContentRect:styleMask:backing:defer:'), |
| NSMakeRect(0, 0, 200, 200), NSTitledWindowMask, NSBackingStoreBuffered, NO), |
| sel('autorelease')) |
| send(window, sel('cascadeTopLeftFromPoint:'), NSMakePoint(20, 20)) |
| send(window, sel('setTitle:'), appName) |
| send(window, sel('makeKeyAndOrderFront:'), nil) |
| |
| send(app, sel('activateIgnoringOtherApps:'), YES) |
| send(app, sel('run')) |