2
0

system.macos.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  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( displayCaptured || !view ){
  126. Point point;
  127. GetMouse( &point );
  128. *x=point.h;
  129. *y=point.v;
  130. return 1;
  131. }
  132. window=[view window];
  133. point=[window mouseLocationOutsideOfEventStream];
  134. rect=[view bounds];
  135. point=[view convertPoint:point fromView:nil];
  136. if( ![view isFlipped] ) point.y=rect.size.height-point.y;
  137. *x=point.x;
  138. *y=point.y;
  139. return point.x>=0 && point.y>=0 && point.x<rect.size.width && point.y<rect.size.height;
  140. }
  141. static void setMouseView( NSView *view,int x,int y,BBObject *source ){
  142. if( view==mouseView ) return;
  143. if( mouseView ){
  144. int x,y;
  145. mouseViewPos( mouseView,&x,&y );
  146. bbSystemEmitEvent( BBEVENT_MOUSELEAVE,mouseSource,0,0,x,y,&bbNullObject );
  147. if( mouseSource ){
  148. BBRELEASE( mouseSource );
  149. }
  150. [mouseView removeTrackingRect:mouseTrackTag];
  151. [mouseView release];
  152. }
  153. mouseView=[view retain];
  154. if( mouseView ){
  155. mouseSource=source;
  156. if( mouseSource ){
  157. BBRETAIN( mouseSource );
  158. }
  159. bbSystemEmitEvent( BBEVENT_MOUSEENTER,mouseSource,0,0,x,y,&bbNullObject );
  160. mouseTrackTag=[mouseView addTrackingRect:[mouseView bounds] owner:appDelegate userData:0 assumeInside:YES];
  161. }
  162. }
  163. static NSEvent *appDefEvent( int subtype,int data1,int data2 ){
  164. return [NSEvent
  165. otherEventWithType:NSApplicationDefined
  166. location:NSMakePoint(0,0)
  167. modifierFlags:0
  168. timestamp:0
  169. windowNumber:0
  170. context:0
  171. subtype:subtype
  172. data1:data1
  173. data2:data2];
  174. }
  175. @implementation BBSystemAppDelegate
  176. -(void)applicationWillTerminate:(NSNotification*)notification{
  177. exit(0);
  178. }
  179. -(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender{
  180. bbSystemEmitEvent( BBEVENT_APPTERMINATE,&bbNullObject,0,0,0,0,&bbNullObject );
  181. return NSTerminateCancel;
  182. }
  183. -(void)applicationDidBecomeActive:(NSNotification *)aNotification{
  184. bbSystemEmitEvent( BBEVENT_APPRESUME,&bbNullObject,0,0,0,0,&bbNullObject );
  185. }
  186. -(void)applicationDidResignActive:(NSNotification *)aNotification{
  187. bbSystemEmitEvent( BBEVENT_APPSUSPEND,&bbNullObject,0,0,0,0,&bbNullObject );
  188. }
  189. -(BOOL)application:(NSApplication*)app openFile:(NSString*)path{
  190. BBString *t=bbStringFromCString( [path cString] );
  191. bbSystemEmitEvent( BBEVENT_APPOPENFILE,&bbNullObject,0,0,0,0,(BBObject*)t );
  192. return YES;
  193. }
  194. -(void)mouseEntered:(NSEvent*)event{
  195. //Never gets here hopefully!
  196. }
  197. -(void)mouseExited:(NSEvent*)event{
  198. setMouseView( 0,0,0,0 );
  199. }
  200. -(void)asyncOpThread:(NSEvent*)event{
  201. AsyncOp *p=(AsyncOp*)[event data1];
  202. p->asyncRet=p->asyncOp( p->asyncInfo );
  203. [NSApp postEvent:event atStart:NO];
  204. }
  205. @end
  206. static void updateDisplayCaptured(){
  207. displayCaptured=CGDisplayIsCaptured( kCGDirectMainDisplay );
  208. }
  209. static void updateEvents( NSDate *until ){
  210. NSEvent *event;
  211. updateDisplayCaptured();
  212. updateMouseVisibility();
  213. while( event=[NSApp nextEventMatchingMask:NSAnyEventMask untilDate:until inMode:NSDefaultRunLoopMode dequeue:YES] ){
  214. if( [event type]==NSApplicationDefined ){
  215. if( [event subtype]==BB_RESERVEDEVENTSUBTYPE1 ){
  216. AsyncOp *p=(AsyncOp*)[event data1];
  217. p->syncOp( p->syncInfo,p->asyncRet );
  218. if( p->asyncOp ){
  219. BBRELEASE( p->syncInfo );
  220. }
  221. free( p );
  222. continue;
  223. }
  224. }
  225. if( displayCaptured ){
  226. bbSystemEmitOSEvent( event,0,&bbNullObject );
  227. }else{
  228. [NSApp sendEvent:event];
  229. }
  230. until=distantPast;
  231. }
  232. bbFlushAutoreleasePool();
  233. }
  234. static void checkDisplay(){
  235. updateDisplayCaptured();
  236. if( displayCaptured ) bbExThrowCString( "GUI unavailable in fullscreen mode" );
  237. }
  238. static void beginPanel(){
  239. checkDisplay();
  240. keyWin=[NSApp keyWindow];
  241. if( !keyWin ) [NSApp activateIgnoringOtherApps:YES];
  242. }
  243. static void endPanel(){
  244. if( keyWin ) [keyWin makeKeyWindow];
  245. }
  246. static NSWindow *appMainWindow(){
  247. int i;
  248. if( ![[NSApp windows] count] ) return 0;
  249. for( i=0;i<10;++i ){
  250. NSWindow *window=[NSApp mainWindow];
  251. if( window ) return window;
  252. bbSystemPoll();
  253. }
  254. return 0;
  255. }
  256. void bbSystemPoll(){
  257. updateEvents( distantPast );
  258. }
  259. void bbSystemWait(){
  260. appWaiting=1;
  261. updateEvents( distantFuture );
  262. appWaiting=0;
  263. }
  264. void bbSystemIntr(){
  265. if( !appWaiting ) return;
  266. appWaiting=0;
  267. [NSApp postEvent:anullEvent atStart:NO];
  268. }
  269. void bbSystemViewClosed( NSView *view ){
  270. if( view!=mouseView ) return;
  271. [mouseView removeTrackingRect:mouseTrackTag];
  272. mouseView=0;
  273. }
  274. void bbSystemEmitOSEvent( NSEvent *event,NSView *view,BBObject *source ){
  275. int inView;
  276. NSEventType type;
  277. NSString *characters;
  278. int ev=0,data=0,x=0,y=0,oldMods=mods,mask;
  279. float f;
  280. mods=[event modifierFlags];
  281. type=[event type];
  282. switch( type ){
  283. case NSKeyDown:
  284. if( data=bbSystemTranslateKey( [event keyCode] ) ){
  285. ev=[event isARepeat] ? BBEVENT_KEYREPEAT : BBEVENT_KEYDOWN;
  286. bbSystemEmitEvent( ev,source,data,bbSystemTranslateMods(mods),0,0,&bbNullObject );
  287. }
  288. characters=[event characters];
  289. if( [characters length]!=1 ) return;
  290. data=[characters characterAtIndex:0];
  291. if( data>=0xf700 && data<=0xf8ff ) return;
  292. ev=BBEVENT_KEYCHAR;
  293. data=bbSystemTranslateChar( data );
  294. break;
  295. case NSKeyUp:
  296. data=bbSystemTranslateKey( [event keyCode] );
  297. if( !data ) return;
  298. ev=BBEVENT_KEYUP;
  299. break;
  300. case NSFlagsChanged:
  301. deltaMods=mods^oldMods;
  302. if( deltaMods & (mask=LSHIFTMASK) ) data=KEY_LSHIFT;
  303. else if( deltaMods & (mask=RSHIFTMASK) ) data=KEY_RSHIFT;
  304. else if( deltaMods & (mask=LCTRLMASK) ) data=KEY_LCONTROL;
  305. else if( deltaMods & (mask=RCTRLMASK) ) data=KEY_RCONTROL;
  306. else if( deltaMods & (mask=LALTMASK) ) data=KEY_LALT;
  307. else if( deltaMods & (mask=RALTMASK) ) data=KEY_RALT;
  308. else if( deltaMods & (mask=LSYSMASK) ) data=KEY_LSYS;
  309. else if( deltaMods & (mask=RSYSMASK) ) data=KEY_RSYS;
  310. if( !data ) return;
  311. ev=(mods & mask) ? BBEVENT_KEYDOWN : BBEVENT_KEYUP;
  312. break;
  313. case NSLeftMouseDown:
  314. case NSRightMouseDown:
  315. case NSOtherMouseDown:
  316. inView=mouseViewPos( view,&x,&y );
  317. if( !inView ) return;
  318. setMouseView( view,x,y,source );
  319. capturedView=mouseView;
  320. ev=BBEVENT_MOUSEDOWN;
  321. data=(type==NSLeftMouseDown) ? 1 : (type==NSRightMouseDown ? 2 : 3);
  322. break;
  323. case NSLeftMouseUp:
  324. case NSRightMouseUp:
  325. case NSOtherMouseUp:
  326. inView=mouseViewPos( view,&x,&y );
  327. if( !inView && !capturedView ) return;
  328. capturedView=0;
  329. ev=BBEVENT_MOUSEUP;
  330. data=(type==NSLeftMouseUp) ? 1 : (type==NSRightMouseUp ? 2 : 3);
  331. break;
  332. case NSMouseMoved:
  333. case NSLeftMouseDragged:
  334. case NSRightMouseDragged:
  335. case NSOtherMouseDragged:
  336. inView=mouseViewPos( view,&x,&y );
  337. setMouseView( inView ? view : 0,x,y,source );
  338. if( !inView && !capturedView ) return;
  339. ev=BBEVENT_MOUSEMOVE;
  340. data=(type==NSLeftMouseDragged) ? 1 : (type==NSRightMouseDragged ? 2 : (type==NSOtherMouseDragged ? 3 : 0));
  341. break;
  342. case NSScrollWheel:
  343. inView=mouseViewPos( view,&x,&y );
  344. if( !inView && view!=capturedView ) return;
  345. ev=BBEVENT_MOUSEWHEEL;
  346. f=[event deltaY];
  347. data=f>0 ? ceil(f) : floor(f);
  348. break;
  349. default:
  350. return;
  351. }
  352. bbSystemEmitEvent( ev,source,data,bbSystemTranslateMods(mods),x,y,&bbNullObject );
  353. }
  354. void bbSystemMoveMouse( int x,int y ){
  355. NSEvent *event;
  356. CGPoint cgPoint={x,y};
  357. CGSetLocalEventsSuppressionInterval(0.0);
  358. if( !CGDisplayIsCaptured(kCGDirectMainDisplay) ){
  359. NSPoint nsPoint={x,y};
  360. NSWindow *window=appMainWindow();
  361. if( !window ) return;
  362. nsPoint.y=[[window contentView] bounds].size.height-1-nsPoint.y;
  363. nsPoint=[window convertBaseToScreen:nsPoint];
  364. cgPoint.x=nsPoint.x;
  365. cgPoint.y=CGDisplayPixelsHigh(kCGDirectMainDisplay)-nsPoint.y;
  366. }
  367. CGDisplayMoveCursorToPoint( kCGDirectMainDisplay,cgPoint );
  368. bbSystemEmitEvent( BBEVENT_MOUSEMOVE,&bbNullObject,0,bbSystemTranslateMods(mods),x,y,&bbNullObject );
  369. }
  370. void bbSystemSetMouseVisible( int visible ){
  371. mouseVisible=visible;
  372. updateDisplayCaptured();
  373. updateMouseVisibility();
  374. }
  375. void bbSystemStartup(){
  376. anullEvent=[appDefEvent( -1,0,0 ) retain];
  377. distantPast=[[NSDate distantPast] retain];
  378. distantFuture=[[NSDate distantFuture] retain];
  379. appDelegate=[[BBSystemAppDelegate alloc] init];
  380. [NSApp setDelegate:appDelegate];
  381. }
  382. typedef int (*AlertPanel)(
  383. NSString *title,
  384. NSString *msg,
  385. NSString *defaultButton,
  386. NSString *alternateButton,
  387. NSString *otherButton );
  388. void bbSystemNotify( BBString *text,int serious ){
  389. AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
  390. beginPanel();
  391. panel(
  392. appTitle(),
  393. tmpNSString(text),
  394. @"OK",0,0 );
  395. endPanel();
  396. }
  397. int bbSystemConfirm( BBString *text,int serious ){
  398. int n;
  399. AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
  400. beginPanel();
  401. n=panel(
  402. appTitle(),
  403. tmpNSString(text),
  404. @"OK",@"Cancel",0 );
  405. endPanel();
  406. switch( n ){
  407. case NSAlertDefaultReturn:return 1;
  408. }
  409. return 0;
  410. }
  411. int bbSystemProceed( BBString *text,int serious ){
  412. int n;
  413. AlertPanel panel=serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel;
  414. beginPanel();
  415. n=panel(
  416. appTitle(),
  417. tmpNSString(text),
  418. @"Yes",@"No",@"Cancel" );
  419. endPanel();
  420. switch( n ){
  421. case NSAlertDefaultReturn:return 1;
  422. case NSAlertAlternateReturn:return 0;
  423. }
  424. return -1;
  425. }
  426. BBString *bbSystemRequestFile( BBString *title,BBString *exts,int save,BBString *file,BBString *dir ){
  427. NSString *nsdir=0;
  428. NSString *nsfile=0;
  429. NSString *nstitle=0;
  430. NSMutableArray *nsexts=0;
  431. BBString *str=&bbEmptyString;
  432. if( dir->length ){
  433. char tmp[PATH_MAX];
  434. realpath( bbTmpUTF8String(dir),tmp );
  435. nsdir=[NSString stringWithUTF8String:tmp];
  436. }
  437. if( file->length ){
  438. nsfile=tmpNSString(file);
  439. }
  440. if( title->length ){
  441. nstitle=tmpNSString(title);
  442. }
  443. if( exts->length ){
  444. char *p=bbTmpUTF8String(exts),*t;
  445. nsexts=[NSMutableArray arrayWithCapacity:10];
  446. while( t=strchr(p,',') ){
  447. *t=0;
  448. [nsexts addObject:[NSString stringWithUTF8String:p]];
  449. p=t+1;
  450. }
  451. if( *p ) [nsexts addObject:[NSString stringWithUTF8String:p]];
  452. }
  453. beginPanel();
  454. if( save ){
  455. NSSavePanel *panel=[NSSavePanel savePanel];
  456. if( nstitle ) [panel setTitle:nstitle];
  457. if( nsexts ){
  458. [panel setAllowedFileTypes:nsexts];
  459. [panel setAllowsOtherFileTypes:YES];
  460. }
  461. if( [panel runModalForDirectory:nsdir file:nsfile]==NSFileHandlingPanelOKButton ){
  462. str=stringFromNSString([panel filename]);
  463. }
  464. }else{
  465. NSOpenPanel *panel=[NSOpenPanel openPanel];
  466. if( nstitle ) [panel setTitle:nstitle];
  467. if( [panel runModalForDirectory:nsdir file:nsfile types:nsexts]==NSFileHandlingPanelOKButton ){
  468. str=stringFromNSString([panel filename]);
  469. }
  470. }
  471. endPanel();
  472. return str;
  473. }
  474. BBString *bbSystemRequestDir( BBString *title,BBString *dir ){
  475. NSString *nsdir=0;
  476. NSString *nstitle=0;
  477. NSOpenPanel *panel;
  478. BBString *str=&bbEmptyString;
  479. if( dir->length ){
  480. char tmp[PATH_MAX];
  481. realpath( bbTmpUTF8String(dir),tmp );
  482. nsdir=[NSString stringWithUTF8String:tmp];
  483. }
  484. if( title->length ){
  485. nstitle=tmpNSString(title);
  486. }
  487. panel=[NSOpenPanel openPanel];
  488. [panel setCanChooseFiles:NO];
  489. [panel setCanChooseDirectories:YES];
  490. [panel setCanCreateDirectories:YES];
  491. if( title ) [panel setTitle:nstitle];
  492. beginPanel();
  493. if( [panel runModalForDirectory:nsdir file:0 types:0]==NSFileHandlingPanelOKButton ){
  494. str=stringFromNSString([panel filename]);
  495. }
  496. endPanel();
  497. return str;
  498. }
  499. int bbOpenURL( BBString *bburl ){
  500. NSURL *url;
  501. NSString *loc;
  502. int res=0;
  503. checkDisplay();
  504. loc=tmpNSString(bburl);
  505. url=[NSURL URLWithString:[loc stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
  506. if( url ) res=[[NSWorkspace sharedWorkspace] openURL:url];
  507. return res;
  508. }
  509. void bbSystemPostSyncOp( BBSyncOp syncOp,BBObject *syncInfo,int asyncRet ){
  510. AsyncOp *p=(AsyncOp*)malloc( sizeof(AsyncOp) );
  511. NSEvent *event=appDefEvent( BB_RESERVEDEVENTSUBTYPE1,(int)p,0 );
  512. p->asyncOp=0;
  513. p->asyncRet=asyncRet;
  514. p->syncOp=syncOp;
  515. p->syncInfo=syncInfo;
  516. [NSApp postEvent:event atStart:NO];
  517. }
  518. void bbSystemStartAsyncOp( BBAsyncOp asyncOp,int asyncInfo,BBSyncOp syncOp,BBObject *syncInfo ){
  519. AsyncOp *p=(AsyncOp*)malloc( sizeof( AsyncOp ) );
  520. NSEvent *event=appDefEvent( BB_RESERVEDEVENTSUBTYPE1,(int)p,0 );
  521. BBRETAIN( syncInfo );
  522. p->asyncOp=asyncOp;
  523. p->asyncInfo=asyncInfo;
  524. p->syncOp=syncOp;
  525. p->syncInfo=syncInfo;
  526. [NSThread detachNewThreadSelector:@selector(asyncOpThread:) toTarget:appDelegate withObject:event];
  527. }
  528. static NSScreen *DesktopScreen(){
  529. NSArray *screens;
  530. if( screens=[NSScreen screens] ){
  531. if( [screens count] ) return [screens objectAtIndex:0];
  532. }
  533. return 0;
  534. }
  535. int bbSystemDesktopWidth(){
  536. NSScreen *screen=DesktopScreen();
  537. if( screen ) return [screen frame].size.width;
  538. return 640;
  539. }
  540. int bbSystemDesktopHeight(){
  541. NSScreen *screen=DesktopScreen();
  542. if( screen ) return [screen frame].size.height;
  543. return 480;
  544. }
  545. int bbSystemDesktopDepth(){
  546. NSScreen *screen=DesktopScreen();
  547. if( screen ) return NSBitsPerPixelFromDepth( [screen depth] );
  548. return 32;
  549. }
  550. int bbSystemDesktopHertz(){
  551. return 60;
  552. }