2
0

_system.macos.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. #import <brl.mod/system.mod/system.h>
  2. #include <AppKit/AppKit.h>
  3. #include <Carbon/Carbon.h>
  4. static unsigned char key_table[]={
  5. //0...
  6. KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
  7. KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
  8. KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
  9. KEY_EQUALS, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_CLOSEBRACKET,KEY_O,
  10. //32...
  11. KEY_U, KEY_OPENBRACKET,KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_QUOTES,
  12. KEY_K, KEY_SEMICOLON,KEY_BACKSLASH,KEY_COMMA,KEY_SLASH,KEY_N, KEY_M, KEY_PERIOD,
  13. KEY_TAB, KEY_SPACE, KEY_TILDE, KEY_BACKSPACE,0, KEY_ESC, 0, 0,
  14. 0, 0, 0, 0, 0, 0, 0, 0,
  15. //64...
  16. 0, KEY_NUMDECIMAL,0, KEY_NUMMULTIPLY,0, KEY_NUMADD, 0, 0,
  17. 0, 0, 0, KEY_NUMDIVIDE,KEY_ENTER,0, KEY_NUMSUBTRACT,0,
  18. //80...
  19. 0, 0, KEY_NUM0, KEY_NUM1, KEY_NUM2, KEY_NUM3, KEY_NUM4, KEY_NUM5,
  20. KEY_NUM6, KEY_NUM7, 0, KEY_NUM8, KEY_NUM9, 0, 0, 0,
  21. //96...
  22. KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11,
  23. 0, 0, 0, 0, 0, KEY_F10, 0, KEY_F12,
  24. 0, 0, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END,
  25. KEY_F2, KEY_PAGEDOWN,KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0,
  26. //128...
  27. };
  28. void bbSystemPoll();
  29. void bbFlushAutoreleasePool();
  30. static int mods,deltaMods;
  31. static NSDate *distantPast,*distantFuture;
  32. static int mouseVisible=1;
  33. static int displayCaptured=0;
  34. static NSView *mouseView;
  35. static BBObject *mouseSource;
  36. static NSTrackingRectTag mouseTrackTag;
  37. static NSEvent *anullEvent;
  38. static NSView *capturedView;
  39. static int appWaiting;
  40. static NSWindow *keyWin;
  41. #define LSHIFTMASK 0x2
  42. #define RSHIFTMASK 0x4
  43. #define LCTRLMASK 0x1
  44. #define RCTRLMASK 0x2000
  45. #define LSYSMASK 0x8
  46. #define RSYSMASK 0x10
  47. #define LALTMASK 0x20
  48. #define RALTMASK 0x40
  49. typedef struct AsyncOp{
  50. BBAsyncOp asyncOp;
  51. int asyncInfo;
  52. int asyncRet;
  53. BBSyncOp syncOp;
  54. BBObject *syncInfo;
  55. }AsyncOp;
  56. @interface BBSystemAppDelegate : NSObject{
  57. }
  58. @end
  59. static BBSystemAppDelegate *appDelegate;
  60. static NSString *tmpNSString( BBString *str ){
  61. return [NSString stringWithCharacters:str->buf length:str->length];
  62. }
  63. static BBString *stringFromNSString( NSString *nsstr ){
  64. return bbStringFromUTF8String( [nsstr UTF8String] );
  65. }
  66. static NSString *appTitle(){
  67. return tmpNSString( bbAppTitle );
  68. }
  69. int bbSystemTranslateKey( key ){
  70. return (key>=0 && key<128) ? key_table[key] : 0;
  71. }
  72. int bbSystemTranslateChar( chr ){
  73. switch(chr){
  74. case 127:return 8;
  75. case 63272:return 127;
  76. }
  77. return chr;
  78. }
  79. int bbSystemTranslateMods( mods ){
  80. int n=0;
  81. if( mods & NSShiftKeyMask ) n|=MODIFIER_SHIFT;
  82. if( mods & NSControlKeyMask ) n|=MODIFIER_CONTROL;
  83. if( mods & NSAlternateKeyMask ) n|=MODIFIER_OPTION;
  84. if( mods & NSCommandKeyMask ) n|=MODIFIER_SYSTEM;
  85. return n;
  86. }
  87. static void updateMouseVisibility(){
  88. static int cursorVisible=1;
  89. int visible=mouseVisible;
  90. if( !visible && !displayCaptured ){
  91. NSArray *windows=(NSArray*)[NSApp windows];
  92. int count=[windows count],i;
  93. visible=1;
  94. for( i=0;i<count;++i ){
  95. NSRect rect;
  96. NSPoint point;
  97. NSView *view;
  98. NSWindow *window;
  99. window=[windows objectAtIndex:i];
  100. view=[window contentView];
  101. if( !view ) continue;
  102. rect=[view bounds];
  103. point=[window mouseLocationOutsideOfEventStream];
  104. point=[view convertPoint:point fromView:nil];
  105. if( ![view isFlipped] ) point.y=rect.size.height-point.y;
  106. if( point.x<0 || point.y<0 || point.x>=rect.size.width || point.y>=rect.size.height ) continue;
  107. visible=0;
  108. break;
  109. }
  110. }
  111. if( visible ){
  112. if( !CGCursorIsVisible() ){
  113. CGDisplayShowCursor( kCGDirectMainDisplay );
  114. }
  115. }else{
  116. if( CGCursorIsVisible() ){
  117. CGDisplayHideCursor( kCGDirectMainDisplay );
  118. }
  119. }
  120. }
  121. static int mouseViewPos( NSView *view,int *x,int *y ){
  122. NSRect rect;
  123. NSPoint point;
  124. NSWindow *window;
  125. if( !view ){
  126. NSPoint point;
  127. NSRect frame;
  128. CGLContextObj gl;
  129. point=[NSEvent mouseLocation];
  130. frame=[[NSScreen mainScreen] frame];
  131. point.y=frame.size.height-point.y-1;
  132. //yurk...
  133. if( gl=CGLGetCurrentContext() ){
  134. GLint enabled=0;
  135. if( !CGLIsEnabled( gl,kCGLCESurfaceBackingSize,&enabled ) && enabled ){
  136. GLint size[2]={0,0};
  137. if( !CGLGetParameter( gl,kCGLCPSurfaceBackingSize,size ) ){
  138. point.x=point.x*size[0]/frame.size.width;
  139. point.y=point.y*size[1]/frame.size.height;
  140. }
  141. }
  142. }
  143. *x=point.x;
  144. *y=point.y;
  145. return 1;
  146. }
  147. window=[view window];
  148. point=[window mouseLocationOutsideOfEventStream];
  149. rect=[view bounds];
  150. point=[view convertPoint:point fromView:nil];
  151. if( ![view isFlipped] ) point.y=rect.size.height-point.y;
  152. *x=point.x;
  153. *y=point.y;
  154. return point.x>=0 && point.y>=0 && point.x<rect.size.width && point.y<rect.size.height;
  155. }
  156. static void setMouseView( NSView *view,int x,int y,BBObject *source ){
  157. if( view==mouseView ) return;
  158. if( mouseView ){
  159. int x,y;
  160. mouseViewPos( mouseView,&x,&y );
  161. bbSystemEmitEvent( BBEVENT_MOUSELEAVE,mouseSource,0,0,x,y,&bbNullObject );
  162. if( mouseSource ){
  163. BBRELEASE( mouseSource );
  164. }
  165. [mouseView removeTrackingRect:mouseTrackTag];
  166. [mouseView release];
  167. }
  168. mouseView=[view retain];
  169. if( mouseView ){
  170. mouseSource=source;
  171. if( mouseSource ){
  172. BBRETAIN( mouseSource );
  173. }
  174. bbSystemEmitEvent( BBEVENT_MOUSEENTER,mouseSource,0,0,x,y,&bbNullObject );
  175. mouseTrackTag=[mouseView addTrackingRect:[mouseView bounds] owner:appDelegate userData:0 assumeInside:YES];
  176. }
  177. }
  178. static NSEvent *appDefEvent( int subtype,int data1,int data2 ){
  179. return [NSEvent
  180. otherEventWithType:NSApplicationDefined
  181. location:NSMakePoint(0,0)
  182. modifierFlags:0
  183. timestamp:0
  184. windowNumber:0
  185. context:0
  186. subtype:subtype
  187. data1:data1
  188. data2:data2];
  189. }
  190. @implementation BBSystemAppDelegate
  191. -(void)applicationWillTerminate:(NSNotification*)notification{
  192. exit(0);
  193. }
  194. -(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender{
  195. bbSystemEmitEvent( BBEVENT_APPTERMINATE,&bbNullObject,0,0,0,0,&bbNullObject );
  196. return NSTerminateCancel;
  197. }
  198. -(void)applicationDidBecomeActive:(NSNotification *)aNotification{
  199. bbSystemEmitEvent( BBEVENT_APPRESUME,&bbNullObject,0,0,0,0,&bbNullObject );
  200. }
  201. -(void)applicationDidResignActive:(NSNotification *)aNotification{
  202. bbSystemEmitEvent( BBEVENT_APPSUSPEND,&bbNullObject,0,0,0,0,&bbNullObject );
  203. }
  204. -(BOOL)application:(NSApplication*)app openFile:(NSString*)path{
  205. BBString *t=bbStringFromCString( [path cString] );
  206. bbSystemEmitEvent( BBEVENT_APPOPENFILE,&bbNullObject,0,0,0,0,(BBObject*)t );
  207. return YES;
  208. }
  209. -(void)mouseEntered:(NSEvent*)event{
  210. //Never gets here hopefully!
  211. }
  212. -(void)mouseExited:(NSEvent*)event{
  213. setMouseView( 0,0,0,0 );
  214. }
  215. -(void)asyncOpThread:(NSEvent*)event{
  216. AsyncOp *p=(AsyncOp*)[event data1];
  217. p->asyncRet=p->asyncOp( p->asyncInfo );
  218. [NSApp postEvent:event atStart:NO];
  219. }
  220. @end
  221. static void updateDisplayCaptured(){
  222. displayCaptured=CGDisplayIsCaptured( kCGDirectMainDisplay );
  223. }
  224. static void updateEvents( NSDate *until ){
  225. NSEvent *event;
  226. updateDisplayCaptured();
  227. updateMouseVisibility();
  228. while( event=[NSApp nextEventMatchingMask:NSAnyEventMask untilDate:until inMode:NSDefaultRunLoopMode dequeue:YES] ){
  229. if( [event type]==NSApplicationDefined ){
  230. if( [event subtype]==BB_RESERVEDEVENTSUBTYPE1 ){
  231. AsyncOp *p=(AsyncOp*)[event data1];
  232. p->syncOp( p->syncInfo,p->asyncRet );
  233. if( p->asyncOp ){
  234. BBRELEASE( p->syncInfo );
  235. }
  236. free( p );
  237. continue;
  238. }
  239. }
  240. if( displayCaptured ){
  241. bbSystemEmitOSEvent( event,0,&bbNullObject );
  242. }else{
  243. [NSApp sendEvent:event];
  244. }
  245. until=distantPast;
  246. }
  247. bbFlushAutoreleasePool();
  248. }
  249. static void checkDisplay(){
  250. updateDisplayCaptured();
  251. if( displayCaptured ) bbExThrowCString( "GUI unavailable in fullscreen mode" );
  252. }
  253. static void beginPanel(){
  254. checkDisplay();
  255. keyWin=[NSApp keyWindow];
  256. if( !keyWin ) [NSApp activateIgnoringOtherApps:YES];
  257. }
  258. static void endPanel(){
  259. if( keyWin ) [keyWin makeKeyWindow];
  260. }
  261. static NSWindow *appMainWindow(){
  262. int i;
  263. if( ![[NSApp windows] count] ) return 0;
  264. for( i=0;i<10;++i ){
  265. NSWindow *window=[NSApp mainWindow];
  266. if( window ) return window;
  267. bbSystemPoll();
  268. }
  269. return 0;
  270. }
  271. void bbSystemPoll(){
  272. updateEvents( distantPast );
  273. }
  274. void bbSystemWait(){
  275. appWaiting=1;
  276. updateEvents( distantFuture );
  277. appWaiting=0;
  278. }
  279. void bbSystemIntr(){
  280. if( !appWaiting ) return;
  281. appWaiting=0;
  282. [NSApp postEvent:anullEvent atStart:NO];
  283. }
  284. void bbSystemViewClosed( NSView *view ){
  285. if( view!=mouseView ) return;
  286. [mouseView removeTrackingRect:mouseTrackTag];
  287. mouseView=0;
  288. }
  289. void bbSystemEmitOSEvent( NSEvent *event,NSView *view,BBObject *source ){
  290. int inView;
  291. NSEventType type;
  292. NSString *characters;
  293. int ev=0,data=0,x=0,y=0,oldMods=mods,mask;
  294. float f;
  295. mods=[event modifierFlags];
  296. type=[event type];
  297. switch( type ){
  298. case NSKeyDown:
  299. if( data=bbSystemTranslateKey( [event keyCode] ) ){
  300. ev=[event isARepeat] ? BBEVENT_KEYREPEAT : BBEVENT_KEYDOWN;
  301. bbSystemEmitEvent( ev,source,data,bbSystemTranslateMods(mods),0,0,&bbNullObject );
  302. }
  303. characters=[event characters];
  304. if( [characters length]!=1 ) return;
  305. data=[characters characterAtIndex:0];
  306. if( data>=0xf700 && data<=0xf8ff ) return;
  307. ev=BBEVENT_KEYCHAR;
  308. data=bbSystemTranslateChar( data );
  309. break;
  310. case NSKeyUp:
  311. data=bbSystemTranslateKey( [event keyCode] );
  312. if( !data ) return;
  313. ev=BBEVENT_KEYUP;
  314. break;
  315. case NSFlagsChanged:
  316. deltaMods=mods^oldMods;
  317. if( deltaMods & (mask=LSHIFTMASK) ) data=KEY_LSHIFT;
  318. else if( deltaMods & (mask=RSHIFTMASK) ) data=KEY_RSHIFT;
  319. else if( deltaMods & (mask=LCTRLMASK) ) data=KEY_LCONTROL;
  320. else if( deltaMods & (mask=RCTRLMASK) ) data=KEY_RCONTROL;
  321. else if( deltaMods & (mask=LALTMASK) ) data=KEY_LALT;
  322. else if( deltaMods & (mask=RALTMASK) ) data=KEY_RALT;
  323. else if( deltaMods & (mask=LSYSMASK) ) data=KEY_LSYS;
  324. else if( deltaMods & (mask=RSYSMASK) ) data=KEY_RSYS;
  325. if( !data ) return;
  326. ev=(mods & mask) ? BBEVENT_KEYDOWN : BBEVENT_KEYUP;
  327. break;
  328. case NSLeftMouseDown:
  329. case NSRightMouseDown:
  330. case NSOtherMouseDown:
  331. inView=mouseViewPos( view,&x,&y );
  332. if( !inView ) return;
  333. setMouseView( view,x,y,source );
  334. capturedView=mouseView;
  335. ev=BBEVENT_MOUSEDOWN;
  336. data=(type==NSLeftMouseDown) ? 1 : (type==NSRightMouseDown ? 2 : 3);
  337. break;
  338. case NSLeftMouseUp:
  339. case NSRightMouseUp:
  340. case NSOtherMouseUp:
  341. inView=mouseViewPos( view,&x,&y );
  342. if( !inView && !capturedView ) return;
  343. capturedView=0;
  344. ev=BBEVENT_MOUSEUP;
  345. data=(type==NSLeftMouseUp) ? 1 : (type==NSRightMouseUp ? 2 : 3);
  346. break;
  347. case NSMouseMoved:
  348. case NSLeftMouseDragged:
  349. case NSRightMouseDragged:
  350. case NSOtherMouseDragged:
  351. inView=mouseViewPos( view,&x,&y );
  352. setMouseView( inView ? view : 0,x,y,source );
  353. if( !inView && !capturedView ) return;
  354. ev=BBEVENT_MOUSEMOVE;
  355. data=(type==NSLeftMouseDragged) ? 1 : (type==NSRightMouseDragged ? 2 : (type==NSOtherMouseDragged ? 3 : 0));
  356. break;
  357. case NSScrollWheel:
  358. inView=mouseViewPos( view,&x,&y );
  359. if( !inView && view!=capturedView ) return;
  360. ev=BBEVENT_MOUSEWHEEL;
  361. f=[event deltaY];
  362. data=f>0 ? ceil(f) : floor(f);
  363. break;
  364. default:
  365. return;
  366. }
  367. bbSystemEmitEvent( ev,source,data,bbSystemTranslateMods(mods),x,y,&bbNullObject );
  368. }
  369. void bbSystemMoveMouse( int x,int y ){
  370. NSEvent *event;
  371. CGPoint cgPoint={x,y};
  372. CGSetLocalEventsSuppressionInterval(0.0);
  373. if( !CGDisplayIsCaptured(kCGDirectMainDisplay) ){
  374. NSPoint nsPoint={x,y};
  375. NSWindow *window=appMainWindow();
  376. if( !window ) return;
  377. nsPoint.y=[[window contentView] bounds].size.height-1-nsPoint.y;
  378. nsPoint=[window convertBaseToScreen:nsPoint];
  379. cgPoint.x=nsPoint.x;
  380. cgPoint.y=CGDisplayPixelsHigh(kCGDirectMainDisplay)-nsPoint.y;
  381. }
  382. CGDisplayMoveCursorToPoint( kCGDirectMainDisplay,cgPoint );
  383. bbSystemEmitEvent( BBEVENT_MOUSEMOVE,&bbNullObject,0,bbSystemTranslateMods(mods),x,y,&bbNullObject );
  384. }
  385. void bbSystemSetMouseVisible( int visible ){
  386. mouseVisible=visible;
  387. updateDisplayCaptured();
  388. updateMouseVisibility();
  389. }
  390. void bbSystemStartup(){
  391. anullEvent=[appDefEvent( -1,0,0 ) retain];
  392. distantPast=[[NSDate distantPast] retain];
  393. distantFuture=[[NSDate distantFuture] retain];
  394. appDelegate=[[BBSystemAppDelegate alloc] init];
  395. [NSApp setDelegate:appDelegate];
  396. }
  397. typedef int (*AlertPanel)(
  398. NSString *title,
  399. NSString *msg,
  400. NSString *defaultButton,
  401. NSString *alternateButton,
  402. NSString *otherButton );
  403. void bbSystemNotify( BBString *text,int serious ){
  404. AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
  405. beginPanel();
  406. panel(
  407. appTitle(),
  408. tmpNSString(text),
  409. @"OK",0,0 );
  410. endPanel();
  411. }
  412. int bbSystemConfirm( BBString *text,int serious ){
  413. int n;
  414. AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
  415. beginPanel();
  416. n=panel(
  417. appTitle(),
  418. tmpNSString(text),
  419. @"OK",@"Cancel",0 );
  420. endPanel();
  421. switch( n ){
  422. case NSAlertDefaultReturn:return 1;
  423. }
  424. return 0;
  425. }
  426. int bbSystemProceed( BBString *text,int serious ){
  427. int n;
  428. AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
  429. beginPanel();
  430. n=panel(
  431. appTitle(),
  432. tmpNSString(text),
  433. @"Yes",@"No",@"Cancel" );
  434. endPanel();
  435. switch( n ){
  436. case NSAlertDefaultReturn:return 1;
  437. case NSAlertAlternateReturn:return 0;
  438. }
  439. return -1;
  440. }
  441. BBString *bbSystemRequestFile( BBString *title,BBString *exts,int save,BBString *file,BBString *dir ){
  442. NSString *nsdir=0;
  443. NSString *nsfile=0;
  444. NSString *nstitle=0;
  445. NSMutableArray *nsexts=0;
  446. BBString *str=&bbEmptyString;
  447. if( dir->length ){
  448. char tmp[PATH_MAX];
  449. realpath( bbTmpUTF8String(dir),tmp );
  450. nsdir=[NSString stringWithUTF8String:tmp];
  451. }
  452. if( file->length ){
  453. nsfile=tmpNSString(file);
  454. }
  455. if( title->length ){
  456. nstitle=tmpNSString(title);
  457. }
  458. if( exts->length ){
  459. char *p=bbTmpUTF8String(exts),*t;
  460. nsexts=[NSMutableArray arrayWithCapacity:10];
  461. while( t=strchr(p,',') ){
  462. *t=0;
  463. [nsexts addObject:[NSString stringWithUTF8String:p]];
  464. p=t+1;
  465. }
  466. if( *p ) [nsexts addObject:[NSString stringWithUTF8String:p]];
  467. }
  468. beginPanel();
  469. if( save ){
  470. NSSavePanel *panel=[NSSavePanel savePanel];
  471. if( nstitle ) [panel setTitle:nstitle];
  472. if( nsexts ){
  473. [panel setAllowedFileTypes:nsexts];
  474. [panel setAllowsOtherFileTypes:YES];
  475. }
  476. if( [panel runModalForDirectory:nsdir file:nsfile]==NSFileHandlingPanelOKButton ){
  477. str=stringFromNSString([panel filename]);
  478. }
  479. }else{
  480. NSOpenPanel *panel=[NSOpenPanel openPanel];
  481. if( nstitle ) [panel setTitle:nstitle];
  482. if( [panel runModalForDirectory:nsdir file:nsfile types:nsexts]==NSFileHandlingPanelOKButton ){
  483. str=stringFromNSString([panel filename]);
  484. }
  485. }
  486. endPanel();
  487. return str;
  488. }
  489. BBString *bbSystemRequestDir( BBString *title,BBString *dir ){
  490. NSString *nsdir=0;
  491. NSString *nstitle=0;
  492. NSOpenPanel *panel;
  493. BBString *str=&bbEmptyString;
  494. if( dir->length ){
  495. char tmp[PATH_MAX];
  496. realpath( bbTmpUTF8String(dir),tmp );
  497. nsdir=[NSString stringWithUTF8String:tmp];
  498. }
  499. if( title->length ){
  500. nstitle=tmpNSString(title);
  501. }
  502. panel=[NSOpenPanel openPanel];
  503. [panel setCanChooseFiles:NO];
  504. [panel setCanChooseDirectories:YES];
  505. [panel setCanCreateDirectories:YES];
  506. if( title ) [panel setTitle:nstitle];
  507. beginPanel();
  508. if( [panel runModalForDirectory:nsdir file:0 types:0]==NSFileHandlingPanelOKButton ){
  509. str=stringFromNSString([panel filename]);
  510. }
  511. endPanel();
  512. return str;
  513. }
  514. int bbOpenURL( BBString *bburl ){
  515. NSURL *url;
  516. NSString *loc;
  517. int res=0;
  518. checkDisplay();
  519. loc=tmpNSString(bburl);
  520. url=[NSURL URLWithString:[loc stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
  521. if( url ) res=[[NSWorkspace sharedWorkspace] openURL:url];
  522. return res;
  523. }
  524. void bbSystemPostSyncOp( BBSyncOp syncOp,BBObject *syncInfo,int asyncRet ){
  525. AsyncOp *p=(AsyncOp*)malloc( sizeof(AsyncOp) );
  526. NSEvent *event=appDefEvent( BB_RESERVEDEVENTSUBTYPE1,(int)p,0 );
  527. p->asyncOp=0;
  528. p->asyncRet=asyncRet;
  529. p->syncOp=syncOp;
  530. p->syncInfo=syncInfo;
  531. [NSApp postEvent:event atStart:NO];
  532. }
  533. void bbSystemStartAsyncOp( BBAsyncOp asyncOp,int asyncInfo,BBSyncOp syncOp,BBObject *syncInfo ){
  534. AsyncOp *p=(AsyncOp*)malloc( sizeof( AsyncOp ) );
  535. NSEvent *event=appDefEvent( BB_RESERVEDEVENTSUBTYPE1,(int)p,0 );
  536. BBRETAIN( syncInfo );
  537. p->asyncOp=asyncOp;
  538. p->asyncInfo=asyncInfo;
  539. p->syncOp=syncOp;
  540. p->syncInfo=syncInfo;
  541. [NSThread detachNewThreadSelector:@selector(asyncOpThread:) toTarget:appDelegate withObject:event];
  542. }
  543. static NSScreen *DesktopScreen(){
  544. NSArray *screens;
  545. if( screens=[NSScreen screens] ){
  546. if( [screens count] ) return [screens objectAtIndex:0];
  547. }
  548. return 0;
  549. }
  550. int bbSystemDesktopWidth(){
  551. NSScreen *screen=DesktopScreen();
  552. if( screen ) return [screen frame].size.width;
  553. return 640;
  554. }
  555. int bbSystemDesktopHeight(){
  556. NSScreen *screen=DesktopScreen();
  557. if( screen ) return [screen frame].size.height;
  558. return 480;
  559. }
  560. int bbSystemDesktopDepth(){
  561. NSScreen *screen=DesktopScreen();
  562. if( screen ) return NSBitsPerPixelFromDepth( [screen depth] );
  563. return 32;
  564. }
  565. int bbSystemDesktopHertz(){
  566. return 60;
  567. }