--- /dev/null
+
+#include <AppKit/AppKit.h>
+#include <Carbon/Carbon.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/OpenGL.h>
+
+#include <brl.mod/system.mod/system.h>
+
+enum{
+ FLAGS_BACKBUFFER= 0x2,
+ FLAGS_ALPHABUFFER= 0x4,
+ FLAGS_DEPTHBUFFER= 0x8,
+ FLAGS_STENCILBUFFER=0x10,
+ FLAGS_ACCUMBUFFER= 0x20
+};
+
+enum{
+ MODE_WIDGET= 1,
+ MODE_WINDOW= 2,
+ MODE_DISPLAY= 3
+};
+
+@interface BBGLWindow : NSWindow{
+}
+@end
+@implementation BBGLWindow
+-(void)sendEvent:(NSEvent*)event{
+ bbSystemEmitOSEvent( event,[self contentView],&bbNullObject );
+ switch( [event type] ){
+ case NSKeyDown:case NSKeyUp:
+ //prevent 'beeps'!
+ return;
+ }
+ [super sendEvent:event];
+}
+-(BOOL)windowShouldClose:(id)sender{
+ bbSystemEmitEvent( BBEVENT_APPTERMINATE,&bbNullObject,0,0,0,0,&bbNullObject );
+ return NO;
+}
+- (BOOL)canBecomeKeyWindow{
+ return YES;
+}
+@end
+
+typedef struct BBGLContext BBGLContext;
+
+struct BBGLContext{
+ int mode,width,height,depth,hertz,flags,sync;
+
+ BBGLWindow *window;
+ NSView *view;
+
+ NSOpenGLContext *glContext;
+};
+
+static BBGLContext *_currentContext;
+
+static CFDictionaryRef oldDisplayMode;
+
+extern void bbFlushAutoreleasePool();
+
+void bbGLGraphicsClose( BBGLContext *context );
+void bbGLGraphicsGetSettings( BBGLContext *context,int *width,int *height,int *depth,int *hertz,int *flags );
+void bbGLGraphicsSetGraphics( BBGLContext *context );
+
+static int _initAttrs( CGLPixelFormatAttribute attrs[16],int flags ){
+ int n=0;
+ if( flags & FLAGS_BACKBUFFER ) attrs[n++]=kCGLPFADoubleBuffer;
+ if( flags & FLAGS_ALPHABUFFER ){ attrs[n++]=kCGLPFAAlphaSize;attrs[n++]=1; }
+ if( flags & FLAGS_DEPTHBUFFER ){ attrs[n++]=kCGLPFADepthSize;attrs[n++]=1; }
+ if( flags & FLAGS_STENCILBUFFER ){ attrs[n++]=kCGLPFAStencilSize;attrs[n++]=1; }
+ if( flags & FLAGS_ACCUMBUFFER ){ attrs[n++]=kCGLPFAAccumSize;attrs[n++]=1; }
+ attrs[n++]=kCGLPFANoRecovery;
+ attrs[n]=0;
+ return n;
+}
+
+static NSOpenGLContext *_sharedContext;
+
+static void _validateSize( BBGLContext *context ){
+ NSRect rect;
+
+ if( !context || context->mode!=MODE_WIDGET ) return;
+
+ rect=[context->view bounds];
+ if( rect.size.width==context->width && rect.size.height==context->height ) return;
+
+ context->width=rect.size.width;
+ context->height=rect.size.height;
+
+ if( context->glContext ) [context->glContext update];
+}
+
+static void _validateContext( BBGLContext *context ){
+ int flags;
+ NSOpenGLContext *shared;
+ NSOpenGLContext *glContext;
+ NSOpenGLPixelFormat *glFormat;
+ CGLPixelFormatAttribute attrs[16];
+
+ if( !context || context->glContext ) return;
+
+ flags=context->flags;
+
+ _initAttrs( attrs,flags );
+
+ glFormat=[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+ glContext=[[NSOpenGLContext alloc] initWithFormat:glFormat shareContext:_sharedContext];
+ [glFormat release];
+
+ if( !glContext ) bbExThrowCString( "Unable to create GL Context" );
+
+ context->glContext=glContext;
+
+ [glContext setView:context->view];
+
+ switch( context->mode ){
+ case MODE_DISPLAY:
+ CGLSetParameter( [glContext CGLContextObj],kCGLCPSurfaceBackingSize,&context->width );
+ CGLEnable( [glContext CGLContextObj],kCGLCESurfaceBackingSize );
+ break;
+ }
+}
+
+void bbGLGraphicsShareContexts(){
+ NSOpenGLPixelFormat *glFormat;
+ CGLPixelFormatAttribute attrs[16];
+
+ if( _sharedContext ) return;
+
+ _initAttrs( attrs,0 );
+ glFormat=[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+ _sharedContext=[[NSOpenGLContext alloc] initWithFormat:glFormat shareContext:0];
+ [glFormat release];
+}
+
+int bbGLGraphicsGraphicsModes( int *modes,int count ){
+ int i=0,n=0,sz;
+ CFArrayRef displayModeArray;
+
+ displayModeArray=CGDisplayAvailableModes( kCGDirectMainDisplay );
+ sz=CFArrayGetCount( displayModeArray );
+
+ while( i<sz && n<count ){
+
+ CFNumberRef number;
+ CFDictionaryRef displayMode;
+ int width,height,depth,hertz;
+
+ displayMode=(CFDictionaryRef)CFArrayGetValueAtIndex( displayModeArray,i++ );
+
+ number=CFDictionaryGetValue( displayMode,kCGDisplayBitsPerPixel );
+ CFNumberGetValue( number,kCFNumberLongType,&depth );
+
+ if( depth<16 ) continue;
+
+ number=CFDictionaryGetValue( displayMode,kCGDisplayWidth );
+ CFNumberGetValue( number,kCFNumberLongType,&width );
+
+ number=CFDictionaryGetValue( displayMode,kCGDisplayHeight );
+ CFNumberGetValue( number,kCFNumberLongType,&height );
+
+ number=CFDictionaryGetValue( displayMode,kCGDisplayRefreshRate );
+ CFNumberGetValue( number,kCFNumberLongType,&hertz );
+
+ *modes++=width;
+ *modes++=height;
+ *modes++=depth;
+ *modes++=hertz;
+ ++n;
+ }
+
+ return n;
+}
+
+BBGLContext *bbGLGraphicsAttachGraphics( NSView *view,int flags ){
+ NSRect rect;
+ BBGLContext *context;
+
+ rect=[view bounds];
+
+ context=(BBGLContext*)malloc( sizeof(BBGLContext) );
+ memset( context,0,sizeof(BBGLContext) );
+
+ context->mode=MODE_WIDGET;
+ context->width=rect.size.width;
+ context->height=rect.size.height;
+ context->flags=flags;
+ context->sync=-1;
+
+ context->view=view;
+
+ return context;
+}
+
+BBGLContext *bbGLGraphicsCreateGraphics( int width,int height,int depth,int hertz,int flags ){
+ int mode;
+ BBGLWindow *window=0;
+ NSView *view=0;
+ BBGLContext *context;
+ int sysv=0;
+
+ Gestalt( 'sysv',&sysv );
+
+ //fullscreen mode only available in Tiger++
+ //
+ if( depth && sysv>=0x1070 ){
+
+ view=[[NSView alloc] initWithFrame:[[NSScreen mainScreen] frame]];
+ [view enterFullScreenMode:[NSScreen mainScreen] withOptions:nil];
+ mode=MODE_DISPLAY;
+
+ }else{
+
+ window=[[BBGLWindow alloc]
+ initWithContentRect:NSMakeRect( 0,0,width,height )
+ styleMask:NSTitledWindowMask|NSClosableWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES];
+
+ if( !window ) return 0;
+
+ view=[window contentView];
+
+ [window setDelegate:window];
+ [window setAcceptsMouseMovedEvents:YES];
+
+ [window setTitle:[NSString stringWithUTF8String:bbTmpUTF8String(bbAppTitle)]];
+ [window center];
+
+ [window makeKeyAndOrderFront:NSApp];
+
+ mode=MODE_WINDOW;
+ }
+
+ context=(BBGLContext*)malloc( sizeof(BBGLContext) );
+ memset( context,0,sizeof(BBGLContext) );
+
+ context->mode=mode;
+ context->width=width;
+ context->height=height;
+ context->depth=depth;
+ context->hertz=hertz;
+ context->flags=flags;
+ context->sync=-1;
+ context->window=window;
+ context->view=view;
+
+ return context;
+}
+
+void bbGLGraphicsGetSettings( BBGLContext *context,int *width,int *height,int *depth,int *hertz, int *flags ){
+ _validateSize( context );
+ *width=context->width;
+ *height=context->height;
+ *depth=context->depth;
+ *hertz=context->hertz;
+ *flags=context->flags;
+}
+
+void bbGLGraphicsClose( BBGLContext *context ){
+ if( context==_currentContext ) bbGLGraphicsSetGraphics( 0 );
+
+ [context->glContext clearDrawable];
+ [context->glContext release];
+
+ switch( context->mode ){
+ case MODE_WINDOW:
+ bbSystemViewClosed( [context->window contentView] );
+ [context->window close];
+ break;
+ case MODE_DISPLAY:
+ bbSystemViewClosed( context->view );
+ [context->view exitFullScreenModeWithOptions:nil];
+ [context->view release];
+ break;
+ }
+ free( context );
+}
+
+void bbGLGraphicsSetGraphics( BBGLContext *context ){
+ if( context ){
+ _validateSize( context );
+ _validateContext( context );
+ [context->glContext makeCurrentContext];
+ }else{
+ [NSOpenGLContext clearCurrentContext];
+ }
+ _currentContext=context;
+}
+
+void bbGLGraphicsFlip( int sync ){
+ if( !_currentContext ) return;
+
+ sync=sync ? 1 : 0;
+
+ static int _sync=-1;
+
+ if( sync!=_currentContext->sync ){
+ _currentContext->sync=sync;
+ [_currentContext->glContext setValues:(long*)&sync forParameter:kCGLCPSwapInterval];
+ }
+
+ [_currentContext->glContext flushBuffer];
+}
--- /dev/null
+
+#import <brl.mod/system.mod/system.h>
+
+#include <AppKit/AppKit.h>
+
+#include <Carbon/Carbon.h>
+
+static unsigned char key_table[]={
+ //0...
+ KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
+ KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
+ KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
+ KEY_EQUALS, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_CLOSEBRACKET,KEY_O,
+ //32...
+ KEY_U, KEY_OPENBRACKET,KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_QUOTES,
+ KEY_K, KEY_SEMICOLON,KEY_BACKSLASH,KEY_COMMA,KEY_SLASH,KEY_N, KEY_M, KEY_PERIOD,
+ KEY_TAB, KEY_SPACE, KEY_TILDE, KEY_BACKSPACE,0, KEY_ESC, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ //64...
+ 0, KEY_NUMDECIMAL,0, KEY_NUMMULTIPLY,0, KEY_NUMADD, 0, 0,
+ 0, 0, 0, KEY_NUMDIVIDE,KEY_ENTER,0, KEY_NUMSUBTRACT,0,
+ //80...
+ 0, 0, KEY_NUM0, KEY_NUM1, KEY_NUM2, KEY_NUM3, KEY_NUM4, KEY_NUM5,
+ KEY_NUM6, KEY_NUM7, 0, KEY_NUM8, KEY_NUM9, 0, 0, 0,
+ //96...
+ KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11,
+ 0, 0, 0, 0, 0, KEY_F10, 0, KEY_F12,
+ 0, 0, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END,
+ KEY_F2, KEY_PAGEDOWN,KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0,
+ //128...
+};
+
+void bbSystemPoll();
+void bbFlushAutoreleasePool();
+
+static int mods,deltaMods;
+static NSDate *distantPast,*distantFuture;
+
+static int mouseVisible=1;
+static int displayCaptured=0;
+
+static NSView *mouseView;
+static BBObject *mouseSource;
+static NSTrackingRectTag mouseTrackTag;
+
+static NSEvent *anullEvent;
+static NSView *capturedView;
+
+static int appWaiting;
+static NSWindow *keyWin;
+
+#define LSHIFTMASK 0x2
+#define RSHIFTMASK 0x4
+#define LCTRLMASK 0x1
+#define RCTRLMASK 0x2000
+#define LSYSMASK 0x8
+#define RSYSMASK 0x10
+#define LALTMASK 0x20
+#define RALTMASK 0x40
+
+typedef struct AsyncOp{
+ BBAsyncOp asyncOp;
+ int asyncInfo;
+ int asyncRet;
+ BBSyncOp syncOp;
+ BBObject *syncInfo;
+}AsyncOp;
+
+@interface BBSystemAppDelegate : NSObject{
+}
+@end
+
+static BBSystemAppDelegate *appDelegate;
+
+static NSString *tmpNSString( BBString *str ){
+ return [NSString stringWithCharacters:str->buf length:str->length];
+}
+
+static BBString *stringFromNSString( NSString *nsstr ){
+ return bbStringFromUTF8String( [nsstr UTF8String] );
+}
+
+static NSString *appTitle(){
+ return tmpNSString( bbAppTitle );
+}
+
+int bbSystemTranslateKey( key ){
+ return (key>=0 && key<128) ? key_table[key] : 0;
+}
+
+int bbSystemTranslateChar( chr ){
+ switch(chr){
+ case 127:return 8;
+ case 63272:return 127;
+ }
+ return chr;
+}
+
+int bbSystemTranslateMods( mods ){
+ int n=0;
+ if( mods & NSShiftKeyMask ) n|=MODIFIER_SHIFT;
+ if( mods & NSControlKeyMask ) n|=MODIFIER_CONTROL;
+ if( mods & NSAlternateKeyMask ) n|=MODIFIER_OPTION;
+ if( mods & NSCommandKeyMask ) n|=MODIFIER_SYSTEM;
+ return n;
+}
+
+static void updateMouseVisibility(){
+ static int cursorVisible=1;
+
+ int visible=mouseVisible;
+
+ if( !visible && !displayCaptured ){
+
+ NSArray *windows=(NSArray*)[NSApp windows];
+ int count=[windows count],i;
+
+ visible=1;
+
+ for( i=0;i<count;++i ){
+ NSRect rect;
+ NSPoint point;
+ NSView *view;
+ NSWindow *window;
+
+ window=[windows objectAtIndex:i];
+ view=[window contentView];
+ if( !view ) continue;
+
+ rect=[view bounds];
+ point=[window mouseLocationOutsideOfEventStream];
+ point=[view convertPoint:point fromView:nil];
+
+ if( ![view isFlipped] ) point.y=rect.size.height-point.y;
+
+ if( point.x<0 || point.y<0 || point.x>=rect.size.width || point.y>=rect.size.height ) continue;
+
+ visible=0;
+ break;
+ }
+ }
+ if( visible ){
+ if( !CGCursorIsVisible() ){
+ CGDisplayShowCursor( kCGDirectMainDisplay );
+ }
+ }else{
+ if( CGCursorIsVisible() ){
+ CGDisplayHideCursor( kCGDirectMainDisplay );
+ }
+ }
+}
+
+static int mouseViewPos( NSView *view,int *x,int *y ){
+ NSRect rect;
+ NSPoint point;
+ NSWindow *window;
+
+ if( displayCaptured ){
+
+ Point point;
+ CGLContextObj gl;
+
+ GetMouse( &point );
+
+ if( gl=CGLGetCurrentContext() ){
+
+ GLint enabled=0;
+ CGLIsEnabled( gl,kCGLCESurfaceBackingSize,&enabled );
+
+ if( enabled ){
+
+ NSRect frame;
+ GLint size[2];
+
+ frame=[[NSScreen mainScreen] frame];
+ CGLGetParameter( gl,kCGLCPSurfaceBackingSize,size );
+
+ *x=point.h * size[0] / frame.size.width;
+ *y=point.v * size[1] / frame.size.height;
+ return 1;
+ }
+ }
+
+ *x=point.h;
+ *y=point.v;
+ return 1;
+ }
+
+ if( !view ) return *x=*y=0;
+
+ window=[view window];
+ point=[window mouseLocationOutsideOfEventStream];
+ rect=[view bounds];
+ point=[view convertPoint:point fromView:nil];
+ if( ![view isFlipped] ) point.y=rect.size.height-point.y;
+ *x=point.x;
+ *y=point.y;
+ return point.x>=0 && point.y>=0 && point.x<rect.size.width && point.y<rect.size.height;
+}
+
+static void setMouseView( NSView *view,int x,int y,BBObject *source ){
+ if( view==mouseView ) return;
+
+ if( mouseView ){
+ int x,y;
+ mouseViewPos( mouseView,&x,&y );
+ bbSystemEmitEvent( BBEVENT_MOUSELEAVE,mouseSource,0,0,x,y,&bbNullObject );
+ if( mouseSource ){
+ BBRELEASE( mouseSource );
+ }
+ [mouseView removeTrackingRect:mouseTrackTag];
+ [mouseView release];
+ }
+
+ mouseView=[view retain];
+
+ if( mouseView ){
+ mouseSource=source;
+ if( mouseSource ){
+ BBRETAIN( mouseSource );
+ }
+ bbSystemEmitEvent( BBEVENT_MOUSEENTER,mouseSource,0,0,x,y,&bbNullObject );
+ mouseTrackTag=[mouseView addTrackingRect:[mouseView bounds] owner:appDelegate userData:0 assumeInside:YES];
+ }
+}
+
+static NSEvent *appDefEvent( int subtype,int data1,int data2 ){
+ return [NSEvent
+ otherEventWithType:NSApplicationDefined
+ location:NSMakePoint(0,0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:0
+ subtype:subtype
+ data1:data1
+ data2:data2];
+}
+
+@implementation BBSystemAppDelegate
+-(void)applicationWillTerminate:(NSNotification*)notification{
+ exit(0);
+}
+-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender{
+ bbSystemEmitEvent( BBEVENT_APPTERMINATE,&bbNullObject,0,0,0,0,&bbNullObject );
+ return NSTerminateCancel;
+}
+-(void)applicationDidBecomeActive:(NSNotification *)aNotification{
+ bbSystemEmitEvent( BBEVENT_APPRESUME,&bbNullObject,0,0,0,0,&bbNullObject );
+}
+-(void)applicationDidResignActive:(NSNotification *)aNotification{
+ bbSystemEmitEvent( BBEVENT_APPSUSPEND,&bbNullObject,0,0,0,0,&bbNullObject );
+}
+-(BOOL)application:(NSApplication*)app openFile:(NSString*)path{
+ BBString *t=bbStringFromCString( [path cString] );
+ bbSystemEmitEvent( BBEVENT_APPOPENFILE,&bbNullObject,0,0,0,0,(BBObject*)t );
+ return YES;
+}
+-(void)mouseEntered:(NSEvent*)event{
+ //Never gets here hopefully!
+}
+-(void)mouseExited:(NSEvent*)event{
+ setMouseView( 0,0,0,0 );
+}
+-(void)asyncOpThread:(NSEvent*)event{
+ AsyncOp *p=(AsyncOp*)[event data1];
+ p->asyncRet=p->asyncOp( p->asyncInfo );
+ [NSApp postEvent:event atStart:NO];
+}
+@end
+
+static void updateDisplayCaptured(){
+ displayCaptured=CGDisplayIsCaptured( kCGDirectMainDisplay );
+}
+
+static void updateEvents( NSDate *until ){
+ NSEvent *event;
+
+ updateDisplayCaptured();
+ updateMouseVisibility();
+
+ while( event=[NSApp nextEventMatchingMask:NSAnyEventMask untilDate:until inMode:NSDefaultRunLoopMode dequeue:YES] ){
+ if( [event type]==NSApplicationDefined ){
+ if( [event subtype]==BB_RESERVEDEVENTSUBTYPE1 ){
+ AsyncOp *p=(AsyncOp*)[event data1];
+ p->syncOp( p->syncInfo,p->asyncRet );
+ if( p->asyncOp ){
+ BBRELEASE( p->syncInfo );
+ }
+ free( p );
+ continue;
+ }
+ }
+ if( displayCaptured ){
+ bbSystemEmitOSEvent( event,0,&bbNullObject );
+ }else{
+ [NSApp sendEvent:event];
+ }
+ until=distantPast;
+ }
+
+ bbFlushAutoreleasePool();
+}
+
+static void checkDisplay(){
+ updateDisplayCaptured();
+ if( displayCaptured ) bbExThrowCString( "GUI unavailable in fullscreen mode" );
+}
+
+static void beginPanel(){
+ checkDisplay();
+ keyWin=[NSApp keyWindow];
+ if( !keyWin ) [NSApp activateIgnoringOtherApps:YES];
+}
+
+static void endPanel(){
+ if( keyWin ) [keyWin makeKeyWindow];
+}
+
+static NSWindow *appMainWindow(){
+ int i;
+ if( ![[NSApp windows] count] ) return 0;
+ for( i=0;i<10;++i ){
+ NSWindow *window=[NSApp mainWindow];
+ if( window ) return window;
+ bbSystemPoll();
+ }
+ return 0;
+}
+
+void bbSystemPoll(){
+ updateEvents( distantPast );
+}
+
+void bbSystemWait(){
+ appWaiting=1;
+ updateEvents( distantFuture );
+ appWaiting=0;
+}
+
+void bbSystemIntr(){
+ if( !appWaiting ) return;
+ appWaiting=0;
+ [NSApp postEvent:anullEvent atStart:NO];
+}
+
+void bbSystemViewClosed( NSView *view ){
+ if( view!=mouseView ) return;
+ [mouseView removeTrackingRect:mouseTrackTag];
+ mouseView=0;
+}
+
+void bbSystemEmitOSEvent( NSEvent *event,NSView *view,BBObject *source ){
+ int inView;
+ NSEventType type;
+ NSString *characters;
+ int ev=0,data=0,x=0,y=0,oldMods=mods,mask;
+ float f;
+
+ mods=[event modifierFlags];
+
+ type=[event type];
+
+ switch( type ){
+ case NSKeyDown:
+ if( data=bbSystemTranslateKey( [event keyCode] ) ){
+ ev=[event isARepeat] ? BBEVENT_KEYREPEAT : BBEVENT_KEYDOWN;
+ bbSystemEmitEvent( ev,source,data,bbSystemTranslateMods(mods),0,0,&bbNullObject );
+ }
+ characters=[event characters];
+ if( [characters length]!=1 ) return;
+ data=[characters characterAtIndex:0];
+ if( data>=0xf700 && data<=0xf8ff ) return;
+ ev=BBEVENT_KEYCHAR;
+ data=bbSystemTranslateChar( data );
+ break;
+ case NSKeyUp:
+ data=bbSystemTranslateKey( [event keyCode] );
+ if( !data ) return;
+ ev=BBEVENT_KEYUP;
+ break;
+ case NSFlagsChanged:
+ deltaMods=mods^oldMods;
+ if( deltaMods & (mask=LSHIFTMASK) ) data=KEY_LSHIFT;
+ else if( deltaMods & (mask=RSHIFTMASK) ) data=KEY_RSHIFT;
+ else if( deltaMods & (mask=LCTRLMASK) ) data=KEY_LCONTROL;
+ else if( deltaMods & (mask=RCTRLMASK) ) data=KEY_RCONTROL;
+ else if( deltaMods & (mask=LALTMASK) ) data=KEY_LALT;
+ else if( deltaMods & (mask=RALTMASK) ) data=KEY_RALT;
+ else if( deltaMods & (mask=LSYSMASK) ) data=KEY_LSYS;
+ else if( deltaMods & (mask=RSYSMASK) ) data=KEY_RSYS;
+ if( !data ) return;
+ ev=(mods & mask) ? BBEVENT_KEYDOWN : BBEVENT_KEYUP;
+ break;
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
+ inView=mouseViewPos( view,&x,&y );
+ if( !inView ) return;
+ setMouseView( view,x,y,source );
+ capturedView=mouseView;
+ ev=BBEVENT_MOUSEDOWN;
+ data=(type==NSLeftMouseDown) ? 1 : (type==NSRightMouseDown ? 2 : 3);
+ break;
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ inView=mouseViewPos( view,&x,&y );
+ if( !inView && !capturedView ) return;
+ capturedView=0;
+ ev=BBEVENT_MOUSEUP;
+ data=(type==NSLeftMouseUp) ? 1 : (type==NSRightMouseUp ? 2 : 3);
+ break;
+ case NSMouseMoved:
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged:
+ inView=mouseViewPos( view,&x,&y );
+ setMouseView( inView ? view : 0,x,y,source );
+ if( !inView && !capturedView ) return;
+ ev=BBEVENT_MOUSEMOVE;
+ data=(type==NSLeftMouseDragged) ? 1 : (type==NSRightMouseDragged ? 2 : (type==NSOtherMouseDragged ? 3 : 0));
+ break;
+ case NSScrollWheel:
+ inView=mouseViewPos( view,&x,&y );
+ if( !inView && view!=capturedView ) return;
+ ev=BBEVENT_MOUSEWHEEL;
+ f=[event deltaY];
+ data=f>0 ? ceil(f) : floor(f);
+ break;
+ default:
+ return;
+ }
+ bbSystemEmitEvent( ev,source,data,bbSystemTranslateMods(mods),x,y,&bbNullObject );
+}
+
+void bbSystemMoveMouse( int x,int y ){
+ NSEvent *event;
+ CGPoint cgPoint={x,y};
+
+ CGSetLocalEventsSuppressionInterval(0.0);
+
+ if( !CGDisplayIsCaptured(kCGDirectMainDisplay) ){
+ NSPoint nsPoint={x,y};
+
+ NSWindow *window=appMainWindow();
+
+ if( !window ) return;
+
+ nsPoint.y=[[window contentView] bounds].size.height-1-nsPoint.y;
+ nsPoint=[window convertBaseToScreen:nsPoint];
+
+ cgPoint.x=nsPoint.x;
+ cgPoint.y=CGDisplayPixelsHigh(kCGDirectMainDisplay)-nsPoint.y;
+ }
+
+ CGDisplayMoveCursorToPoint( kCGDirectMainDisplay,cgPoint );
+
+ bbSystemEmitEvent( BBEVENT_MOUSEMOVE,&bbNullObject,0,bbSystemTranslateMods(mods),x,y,&bbNullObject );
+}
+
+void bbSystemSetMouseVisible( int visible ){
+ mouseVisible=visible;
+ updateDisplayCaptured();
+ updateMouseVisibility();
+}
+
+void bbSystemStartup(){
+ anullEvent=[appDefEvent( -1,0,0 ) retain];
+ distantPast=[[NSDate distantPast] retain];
+ distantFuture=[[NSDate distantFuture] retain];
+ appDelegate=[[BBSystemAppDelegate alloc] init];
+ [NSApp setDelegate:appDelegate];
+}
+
+typedef int (*AlertPanel)(
+ NSString *title,
+ NSString *msg,
+ NSString *defaultButton,
+ NSString *alternateButton,
+ NSString *otherButton );
+
+void bbSystemNotify( BBString *text,int serious ){
+ AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
+
+ beginPanel();
+ panel(
+ appTitle(),
+ tmpNSString(text),
+ @"OK",0,0 );
+
+ endPanel();
+}
+
+int bbSystemConfirm( BBString *text,int serious ){
+ int n;
+ AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
+
+ beginPanel();
+ n=panel(
+ appTitle(),
+ tmpNSString(text),
+ @"OK",@"Cancel",0 );
+
+ endPanel();
+
+ switch( n ){
+ case NSAlertDefaultReturn:return 1;
+ }
+ return 0;
+}
+
+int bbSystemProceed( BBString *text,int serious ){
+ int n;
+ AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
+
+ beginPanel();
+ n=panel(
+ appTitle(),
+ tmpNSString(text),
+ @"Yes",@"No",@"Cancel" );
+ endPanel();
+
+ switch( n ){
+ case NSAlertDefaultReturn:return 1;
+ case NSAlertAlternateReturn:return 0;
+ }
+ return -1;
+}
+
+BBString *bbSystemRequestFile( BBString *title,BBString *exts,int save,BBString *file,BBString *dir ){
+
+ NSString *nsdir=0;
+ NSString *nsfile=0;
+ NSString *nstitle=0;
+ NSMutableArray *nsexts=0;
+
+ BBString *str=&bbEmptyString;
+
+ if( dir->length ){
+ char tmp[PATH_MAX];
+ realpath( bbTmpUTF8String(dir),tmp );
+ nsdir=[NSString stringWithUTF8String:tmp];
+ }
+
+ if( file->length ){
+ nsfile=tmpNSString(file);
+ }
+
+ if( title->length ){
+ nstitle=tmpNSString(title);
+ }
+
+ if( exts->length ){
+ char *p=bbTmpUTF8String(exts),*t;
+ nsexts=[NSMutableArray arrayWithCapacity:10];
+ while( t=strchr(p,',') ){
+ *t=0;
+ [nsexts addObject:[NSString stringWithUTF8String:p]];
+ p=t+1;
+ }
+ if( *p ) [nsexts addObject:[NSString stringWithUTF8String:p]];
+ }
+
+ beginPanel();
+
+ if( save ){
+ NSSavePanel *panel=[NSSavePanel savePanel];
+
+ if( nstitle ) [panel setTitle:nstitle];
+
+ if( nsexts ){
+ [panel setAllowedFileTypes:nsexts];
+ [panel setAllowsOtherFileTypes:YES];
+ }
+
+ if( [panel runModalForDirectory:nsdir file:nsfile]==NSFileHandlingPanelOKButton ){
+ str=stringFromNSString([panel filename]);
+ }
+
+ }else{
+ NSOpenPanel *panel=[NSOpenPanel openPanel];
+
+ if( nstitle ) [panel setTitle:nstitle];
+
+ if( [panel runModalForDirectory:nsdir file:nsfile types:nsexts]==NSFileHandlingPanelOKButton ){
+ str=stringFromNSString([panel filename]);
+ }
+ }
+ endPanel();
+
+ return str;
+}
+
+BBString *bbSystemRequestDir( BBString *title,BBString *dir ){
+
+ NSString *nsdir=0;
+ NSString *nstitle=0;
+ NSOpenPanel *panel;
+
+ BBString *str=&bbEmptyString;
+
+ if( dir->length ){
+ char tmp[PATH_MAX];
+ realpath( bbTmpUTF8String(dir),tmp );
+ nsdir=[NSString stringWithUTF8String:tmp];
+ }
+
+ if( title->length ){
+ nstitle=tmpNSString(title);
+ }
+
+ panel=[NSOpenPanel openPanel];
+
+ [panel setCanChooseFiles:NO];
+ [panel setCanChooseDirectories:YES];
+ [panel setCanCreateDirectories:YES];
+
+ if( title ) [panel setTitle:nstitle];
+
+ beginPanel();
+ if( [panel runModalForDirectory:nsdir file:0 types:0]==NSFileHandlingPanelOKButton ){
+ str=stringFromNSString([panel filename]);
+ }
+ endPanel();
+
+ return str;
+}
+
+int bbOpenURL( BBString *bburl ){
+ NSURL *url;
+ NSString *loc;
+ int res=0;
+
+ checkDisplay();
+ loc=tmpNSString(bburl);
+ url=[NSURL URLWithString:[loc stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ if( url ) res=[[NSWorkspace sharedWorkspace] openURL:url];
+ return res;
+}
+
+void bbSystemPostSyncOp( BBSyncOp syncOp,BBObject *syncInfo,int asyncRet ){
+ AsyncOp *p=(AsyncOp*)malloc( sizeof(AsyncOp) );
+ NSEvent *event=appDefEvent( BB_RESERVEDEVENTSUBTYPE1,(int)p,0 );
+ p->asyncOp=0;
+ p->asyncRet=asyncRet;
+ p->syncOp=syncOp;
+ p->syncInfo=syncInfo;
+ [NSApp postEvent:event atStart:NO];
+}
+
+void bbSystemStartAsyncOp( BBAsyncOp asyncOp,int asyncInfo,BBSyncOp syncOp,BBObject *syncInfo ){
+ AsyncOp *p=(AsyncOp*)malloc( sizeof( AsyncOp ) );
+ NSEvent *event=appDefEvent( BB_RESERVEDEVENTSUBTYPE1,(int)p,0 );
+ BBRETAIN( syncInfo );
+ p->asyncOp=asyncOp;
+ p->asyncInfo=asyncInfo;
+ p->syncOp=syncOp;
+ p->syncInfo=syncInfo;
+ [NSThread detachNewThreadSelector:@selector(asyncOpThread:) toTarget:appDelegate withObject:event];
+}
+
+static NSScreen *DesktopScreen(){
+ NSArray *screens;
+ if( screens=[NSScreen screens] ){
+ if( [screens count] ) return [screens objectAtIndex:0];
+ }
+ return 0;
+}
+
+int bbSystemDesktopWidth(){
+ NSScreen *screen=DesktopScreen();
+ if( screen ) return [screen frame].size.width;
+ return 640;
+}
+
+int bbSystemDesktopHeight(){
+ NSScreen *screen=DesktopScreen();
+ if( screen ) return [screen frame].size.height;
+ return 480;
+}
+
+int bbSystemDesktopDepth(){
+ NSScreen *screen=DesktopScreen();
+ if( screen ) return NSBitsPerPixelFromDepth( [screen depth] );
+ return 32;
+}
+
+int bbSystemDesktopHertz(){
+ return 60;
+}