Source

cffi / demo / cffi-cocoa.py

# 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'))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.