1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <stdio.h> 32 33 #include "tools/fsys.hxx" 34 #include "tools/getprocessworkingdir.hxx" 35 #include <tools/solarmutex.hxx> 36 37 #include "osl/process.h" 38 39 #include "rtl/ustrbuf.hxx" 40 41 #include "vcl/svapp.hxx" 42 #include "vcl/window.hxx" 43 #include "vcl/timer.hxx" 44 45 #include "aqua/saldata.hxx" 46 #include "aqua/salinst.h" 47 #include "aqua/salframe.h" 48 #include "aqua/salobj.h" 49 #include "aqua/salsys.h" 50 #include "aqua/salvd.h" 51 #include "aqua/salbmp.h" 52 #include "aqua/salprn.h" 53 #include "aqua/saltimer.h" 54 #include "aqua/vclnsapp.h" 55 56 #include "print.h" 57 #include "impbmp.hxx" 58 #include "salimestatus.hxx" 59 60 #include <comphelper/processfactory.hxx> 61 62 #include <com/sun/star/beans/XPropertySet.hpp> 63 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 64 #include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp> 65 #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp> 66 #include <com/sun/star/uno/XComponentContext.hpp> 67 68 #include "premac.h" 69 #include <Foundation/Foundation.h> 70 #include <ApplicationServices/ApplicationServices.h> 71 #import "apple_remote/RemoteMainController.h" 72 #include "apple_remote/RemoteControl.h" 73 #include "postmac.h" 74 75 using namespace std; 76 using namespace ::com::sun::star; 77 78 extern sal_Bool ImplSVMain(); 79 80 static sal_Bool* gpbInit = 0; 81 static NSMenu* pDockMenu = nil; 82 static bool bNoSVMain = true; 83 static bool bLeftMain = false; 84 // ----------------------------------------------------------------------- 85 86 class AquaDelayedSettingsChanged : public Timer 87 { 88 bool mbInvalidate; 89 public: 90 AquaDelayedSettingsChanged( bool bInvalidate ) : 91 mbInvalidate( bInvalidate ) 92 { 93 } 94 95 virtual void Timeout() 96 { 97 SalData* pSalData = GetSalData(); 98 if( ! pSalData->maFrames.empty() ) 99 pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL ); 100 101 if( mbInvalidate ) 102 { 103 for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin(); 104 it != pSalData->maFrames.end(); ++it ) 105 { 106 if( (*it)->mbShown ) 107 (*it)->SendPaintEvent( NULL ); 108 } 109 } 110 Stop(); 111 delete this; 112 } 113 }; 114 115 void AquaSalInstance::delayedSettingsChanged( bool bInvalidate ) 116 { 117 vos::OGuard aGuard( *mpSalYieldMutex ); 118 AquaDelayedSettingsChanged* pTimer = new AquaDelayedSettingsChanged( bInvalidate ); 119 pTimer->SetTimeout( 50 ); 120 pTimer->Start(); 121 } 122 123 124 // the AppEventList must be available before any SalData/SalInst/etc. objects are ready 125 typedef std::list<const ApplicationEvent*> AppEventList; 126 AppEventList AquaSalInstance::aAppEventList; 127 128 NSMenu* AquaSalInstance::GetDynamicDockMenu() 129 { 130 if( ! pDockMenu && ! bLeftMain ) 131 pDockMenu = [[NSMenu alloc] initWithTitle: @""]; 132 return pDockMenu; 133 } 134 135 bool AquaSalInstance::isOnCommandLine( const rtl::OUString& rArg ) 136 { 137 sal_uInt32 nArgs = osl_getCommandArgCount(); 138 for( sal_uInt32 i = 0; i < nArgs; i++ ) 139 { 140 rtl::OUString aArg; 141 osl_getCommandArg( i, &aArg.pData ); 142 if( aArg.equals( rArg ) ) 143 return true; 144 } 145 return false; 146 } 147 148 149 // initialize the cocoa VCL_NSApplication object 150 // returns an NSAutoreleasePool that must be released when the event loop begins 151 static void initNSApp() 152 { 153 // create our cocoa NSApplication 154 [VCL_NSApplication sharedApplication]; 155 156 SalData::ensureThreadAutoreleasePool(); 157 158 // put cocoa into multithreaded mode 159 [NSThread detachNewThreadSelector:@selector(enableCocoaThreads:) toTarget:[[CocoaThreadEnabler alloc] init] withObject:nil]; 160 161 // activate our delegate methods 162 [NSApp setDelegate: NSApp]; 163 164 [[NSNotificationCenter defaultCenter] addObserver: NSApp 165 selector: @selector(systemColorsChanged:) 166 name: NSSystemColorsDidChangeNotification 167 object: nil ]; 168 [[NSNotificationCenter defaultCenter] addObserver: NSApp 169 selector: @selector(screenParametersChanged:) 170 name: NSApplicationDidChangeScreenParametersNotification 171 object: nil ]; 172 // add observers for some settings changes that affect vcl's settings 173 // scrollbar variant 174 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 175 selector: @selector(scrollbarVariantChanged:) 176 name: @"AppleAquaScrollBarVariantChanged" 177 object: nil ]; 178 // scrollbar page behavior ("jump to here" or not) 179 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 180 selector: @selector(scrollbarSettingsChanged:) 181 name: @"AppleNoRedisplayAppearancePreferenceChanged" 182 object: nil ]; 183 184 // get System Version and store the value in GetSalData()->mnSystemVersion 185 OSErr err = noErr; 186 SInt32 systemVersion = VER_TIGER; // Initialize with minimal requirement 187 if( (err = Gestalt(gestaltSystemVersion, &systemVersion)) == noErr ) 188 { 189 GetSalData()->mnSystemVersion = systemVersion; 190 #if OSL_DEBUG_LEVEL > 1 191 fprintf( stderr, "System Version %x\n", (unsigned int)systemVersion); 192 #endif 193 } 194 else 195 NSLog(@"Unable to obtain system version: %ld", (long)err); 196 197 // Initialize Apple Remote 198 GetSalData()->mpMainController = [[MainController alloc] init]; 199 200 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 201 selector: @selector(applicationWillBecomeActive:) 202 name: @"AppleRemoteWillBecomeActive" 203 object: nil ]; 204 205 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 206 selector: @selector(applicationWillResignActive:) 207 name: @"AppleRemoteWillResignActive" 208 object: nil ]; 209 210 if( ImplGetSVData()->mbIsTestTool ) 211 [NSApp activateIgnoringOtherApps: YES]; 212 } 213 214 sal_Bool ImplSVMainHook( sal_Bool * pbInit ) 215 { 216 gpbInit = pbInit; 217 218 bNoSVMain = false; 219 initNSApp(); 220 221 NSPoint aPt = { 0, 0 }; 222 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined 223 location: aPt 224 modifierFlags: 0 225 timestamp: 0 226 windowNumber: 0 227 context: nil 228 subtype: AquaSalInstance::AppExecuteSVMain 229 data1: 0 230 data2: 0 ]; 231 if( pEvent ) 232 { 233 [NSApp postEvent: pEvent atStart: NO]; 234 235 rtl::OUString aExeURL, aExe; 236 osl_getExecutableFile( &aExeURL.pData ); 237 osl_getSystemPathFromFileURL( aExeURL.pData, &aExe.pData ); 238 rtl::OString aByteExe( rtl::OUStringToOString( aExe, osl_getThreadTextEncoding() ) ); 239 240 #ifdef DEBUG 241 aByteExe += OString ( " NSAccessibilityDebugLogLevel 1" ); 242 const char* pArgv[] = { aByteExe.getStr(), NULL }; 243 NSApplicationMain( 3, pArgv ); 244 #else 245 const char* pArgv[] = { aByteExe.getStr(), NULL }; 246 NSApplicationMain( 1, pArgv ); 247 #endif 248 } 249 else 250 { 251 DBG_ERROR( "NSApplication initialization could not be done" ); 252 } 253 254 return TRUE; // indicate that ImplSVMainHook is implemented 255 } 256 257 // ======================================================================= 258 259 void SalAbort( const XubString& rErrorText ) 260 { 261 if( !rErrorText.Len() ) 262 fprintf( stderr, "Application Error " ); 263 else 264 fprintf( stderr, "%s ", 265 ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() ); 266 abort(); 267 } 268 269 // ----------------------------------------------------------------------- 270 271 void InitSalData() 272 { 273 SalData *pSalData = new SalData; 274 SetSalData( pSalData ); 275 } 276 277 // ----------------------------------------------------------------------- 278 279 const ::rtl::OUString& SalGetDesktopEnvironment() 280 { 281 static OUString aDesktopEnvironment(RTL_CONSTASCII_USTRINGPARAM( "MacOSX" )); 282 return aDesktopEnvironment; 283 } 284 285 // ----------------------------------------------------------------------- 286 287 void DeInitSalData() 288 { 289 SalData *pSalData = GetSalData(); 290 if( pSalData->mpStatusItem ) 291 { 292 [pSalData->mpStatusItem release]; 293 pSalData->mpStatusItem = nil; 294 } 295 delete pSalData; 296 SetSalData( NULL ); 297 } 298 299 // ----------------------------------------------------------------------- 300 301 extern "C" { 302 #include <crt_externs.h> 303 } 304 305 // ----------------------------------------------------------------------- 306 307 void InitSalMain() 308 { 309 rtl::OUString urlWorkDir; 310 rtl_uString *sysWorkDir = NULL; 311 if (tools::getProcessWorkingDir(&urlWorkDir)) 312 { 313 oslFileError err2 = osl_getSystemPathFromFileURL(urlWorkDir.pData, &sysWorkDir); 314 if (err2 == osl_File_E_None) 315 { 316 ByteString aPath( getenv( "PATH" ) ); 317 ByteString aResPath( getenv( "STAR_RESOURCEPATH" ) ); 318 ByteString aLibPath( getenv( "DYLD_LIBRARY_PATH" ) ); 319 ByteString aCmdPath( OUStringToOString(OUString(sysWorkDir), RTL_TEXTENCODING_UTF8).getStr() ); 320 ByteString aTmpPath; 321 // Get absolute path of command's directory 322 if ( aCmdPath.Len() ) { 323 DirEntry aCmdDirEntry( aCmdPath ); 324 aCmdDirEntry.ToAbs(); 325 aCmdPath = ByteString( aCmdDirEntry.GetPath().GetFull(), RTL_TEXTENCODING_ASCII_US ); 326 } 327 // Assign to PATH environment variable 328 if ( aCmdPath.Len() ) 329 { 330 aTmpPath = ByteString( "PATH=" ); 331 aTmpPath += aCmdPath; 332 if ( aPath.Len() ) 333 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US ); 334 aTmpPath += aPath; 335 putenv( (char*)aTmpPath.GetBuffer() ); 336 } 337 // Assign to STAR_RESOURCEPATH environment variable 338 if ( aCmdPath.Len() ) 339 { 340 aTmpPath = ByteString( "STAR_RESOURCEPATH=" ); 341 aTmpPath += aCmdPath; 342 if ( aResPath.Len() ) 343 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US ); 344 aTmpPath += aResPath; 345 putenv( (char*)aTmpPath.GetBuffer() ); 346 } 347 // Assign to DYLD_LIBRARY_PATH environment variable 348 if ( aCmdPath.Len() ) 349 { 350 aTmpPath = ByteString( "DYLD_LIBRARY_PATH=" ); 351 aTmpPath += aCmdPath; 352 if ( aLibPath.Len() ) 353 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US ); 354 aTmpPath += aLibPath; 355 putenv( (char*)aTmpPath.GetBuffer() ); 356 } 357 } 358 } 359 } 360 361 // ----------------------------------------------------------------------- 362 363 void DeInitSalMain() 364 { 365 } 366 367 // ======================================================================= 368 369 SalYieldMutex::SalYieldMutex() 370 { 371 mnCount = 0; 372 mnThreadId = 0; 373 } 374 375 void SalYieldMutex::acquire() 376 { 377 OMutex::acquire(); 378 mnThreadId = vos::OThread::getCurrentIdentifier(); 379 mnCount++; 380 } 381 382 void SalYieldMutex::release() 383 { 384 if ( mnThreadId == vos::OThread::getCurrentIdentifier() ) 385 { 386 if ( mnCount == 1 ) 387 mnThreadId = 0; 388 mnCount--; 389 } 390 OMutex::release(); 391 } 392 393 sal_Bool SalYieldMutex::tryToAcquire() 394 { 395 if ( OMutex::tryToAcquire() ) 396 { 397 mnThreadId = vos::OThread::getCurrentIdentifier(); 398 mnCount++; 399 return sal_True; 400 } 401 else 402 return sal_False; 403 } 404 405 // ----------------------------------------------------------------------- 406 407 // some convenience functions regarding the yield mutex, aka solar mutex 408 409 sal_Bool ImplSalYieldMutexTryToAcquire() 410 { 411 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance; 412 if ( pInst ) 413 return pInst->mpSalYieldMutex->tryToAcquire(); 414 else 415 return FALSE; 416 } 417 418 void ImplSalYieldMutexAcquire() 419 { 420 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance; 421 if ( pInst ) 422 pInst->mpSalYieldMutex->acquire(); 423 } 424 425 void ImplSalYieldMutexRelease() 426 { 427 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance; 428 if ( pInst ) 429 pInst->mpSalYieldMutex->release(); 430 } 431 432 // ======================================================================= 433 434 SalInstance* CreateSalInstance() 435 { 436 // this is the case for not using SVMain 437 // not so good 438 if( bNoSVMain ) 439 initNSApp(); 440 441 SalData* pSalData = GetSalData(); 442 DBG_ASSERT( pSalData->mpFirstInstance == NULL, "more than one instance created" ); 443 AquaSalInstance* pInst = new AquaSalInstance; 444 445 // init instance (only one instance in this version !!!) 446 pSalData->mpFirstInstance = pInst; 447 // this one is for outside AquaSalInstance::Yield 448 SalData::ensureThreadAutoreleasePool(); 449 // no focus rects on NWF aqua 450 ImplGetSVData()->maNWFData.mbNoFocusRects = true; 451 ImplGetSVData()->maNWFData.mbNoBoldTabFocus = true; 452 ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise = true; 453 ImplGetSVData()->maNWFData.mbCenteredTabs = true; 454 ImplGetSVData()->maNWFData.mbProgressNeedsErase = true; 455 ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase = true; 456 ImplGetSVData()->maNWFData.mnStatusBarLowerRightOffset = 10; 457 ImplGetSVData()->maGDIData.mbNoXORClipping = true; 458 ImplGetSVData()->maWinData.mbNoSaveBackground = true; 459 460 return pInst; 461 } 462 463 // ----------------------------------------------------------------------- 464 465 void DestroySalInstance( SalInstance* pInst ) 466 { 467 delete pInst; 468 } 469 470 // ----------------------------------------------------------------------- 471 472 AquaSalInstance::AquaSalInstance() 473 { 474 mpSalYieldMutex = new SalYieldMutex; 475 mpSalYieldMutex->acquire(); 476 ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex ); 477 maMainThread = vos::OThread::getCurrentIdentifier(); 478 mbWaitingYield = false; 479 maUserEventListMutex = osl_createMutex(); 480 mnActivePrintJobs = 0; 481 maWaitingYieldCond = osl_createCondition(); 482 } 483 484 // ----------------------------------------------------------------------- 485 486 AquaSalInstance::~AquaSalInstance() 487 { 488 ::tools::SolarMutex::SetSolarMutex( 0 ); 489 mpSalYieldMutex->release(); 490 delete mpSalYieldMutex; 491 osl_destroyMutex( maUserEventListMutex ); 492 osl_destroyCondition( maWaitingYieldCond ); 493 } 494 495 // ----------------------------------------------------------------------- 496 497 void AquaSalInstance::wakeupYield() 498 { 499 // wakeup :Yield 500 if( mbWaitingYield ) 501 { 502 SalData::ensureThreadAutoreleasePool(); 503 NSPoint aPt = { 0, 0 }; 504 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined 505 location: aPt 506 modifierFlags: 0 507 timestamp: 0 508 windowNumber: 0 509 context: nil 510 subtype: AquaSalInstance::YieldWakeupEvent 511 data1: 0 512 data2: 0 ]; 513 if( pEvent ) 514 [NSApp postEvent: pEvent atStart: NO]; 515 } 516 } 517 518 // ----------------------------------------------------------------------- 519 520 void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, sal_uInt16 nType, void* pData ) 521 { 522 osl_acquireMutex( maUserEventListMutex ); 523 maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) ); 524 osl_releaseMutex( maUserEventListMutex ); 525 526 // notify main loop that an event has arrived 527 wakeupYield(); 528 } 529 530 // ----------------------------------------------------------------------- 531 532 vos::IMutex* AquaSalInstance::GetYieldMutex() 533 { 534 return mpSalYieldMutex; 535 } 536 537 // ----------------------------------------------------------------------- 538 539 sal_uLong AquaSalInstance::ReleaseYieldMutex() 540 { 541 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 542 if ( pYieldMutex->GetThreadId() == 543 vos::OThread::getCurrentIdentifier() ) 544 { 545 sal_uLong nCount = pYieldMutex->GetAcquireCount(); 546 sal_uLong n = nCount; 547 while ( n ) 548 { 549 pYieldMutex->release(); 550 n--; 551 } 552 553 return nCount; 554 } 555 else 556 return 0; 557 } 558 559 // ----------------------------------------------------------------------- 560 561 void AquaSalInstance::AcquireYieldMutex( sal_uLong nCount ) 562 { 563 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 564 while ( nCount ) 565 { 566 pYieldMutex->acquire(); 567 nCount--; 568 } 569 } 570 571 // ----------------------------------------------------------------------- 572 573 bool AquaSalInstance::CheckYieldMutex() 574 { 575 bool bRet = true; 576 577 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 578 if ( pYieldMutex->GetThreadId() != 579 vos::OThread::getCurrentIdentifier() ) 580 { 581 bRet = false; 582 } 583 584 return bRet; 585 } 586 587 // ----------------------------------------------------------------------- 588 589 bool AquaSalInstance::isNSAppThread() const 590 { 591 return vos::OThread::getCurrentIdentifier() == maMainThread; 592 } 593 594 // ----------------------------------------------------------------------- 595 596 void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) 597 { 598 switch( [pEvent subtype] ) 599 { 600 case AppStartTimerEvent: 601 AquaSalTimer::handleStartTimerEvent( pEvent ); 602 break; 603 case AppEndLoopEvent: 604 [NSApp stop: NSApp]; 605 break; 606 case AppExecuteSVMain: 607 { 608 sal_Bool bResult = ImplSVMain(); 609 if( gpbInit ) 610 *gpbInit = bResult; 611 [NSApp stop: NSApp]; 612 bLeftMain = true; 613 if( pDockMenu ) 614 { 615 [pDockMenu release]; 616 pDockMenu = nil; 617 } 618 } 619 break; 620 case AppleRemoteEvent: 621 { 622 sal_Int16 nCommand = 0; 623 SalData* pSalData = GetSalData(); 624 bool bIsFullScreenMode = false; 625 626 std::list<AquaSalFrame*>::iterator it = pSalData->maFrames.begin(); 627 while( (*it) && ( (it != pSalData->maFrames.end() ) || ( (*it)->mbFullScreen == false ) ) ) 628 { 629 if ( ((*it)->mbFullScreen == true) ) 630 bIsFullScreenMode = true; 631 it++; 632 } 633 634 switch ([pEvent data1]) 635 { 636 case kRemoteButtonPlay: 637 nCommand = ( bIsFullScreenMode == true ) ? MEDIA_COMMAND_PLAY_PAUSE : MEDIA_COMMAND_PLAY; 638 break; 639 640 // kept for experimentation purpose (scheduled for future implementation) 641 // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break; 642 643 case kRemoteButtonPlus: nCommand = MEDIA_COMMAND_VOLUME_UP; break; 644 645 case kRemoteButtonMinus: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break; 646 647 case kRemoteButtonRight: nCommand = MEDIA_COMMAND_NEXTTRACK; break; 648 649 case kRemoteButtonRight_Hold: nCommand = MEDIA_COMMAND_NEXTTRACK_HOLD; break; 650 651 case kRemoteButtonLeft: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break; 652 653 case kRemoteButtonLeft_Hold: nCommand = MEDIA_COMMAND_REWIND; break; 654 655 case kRemoteButtonPlay_Hold: nCommand = MEDIA_COMMAND_PLAY_HOLD; break; 656 657 case kRemoteButtonMenu_Hold: nCommand = MEDIA_COMMAND_STOP; break; 658 659 // FIXME : not detected 660 case kRemoteButtonPlus_Hold: 661 case kRemoteButtonMinus_Hold: 662 break; 663 664 default: 665 break; 666 } 667 AquaSalFrame* pFrame = pSalData->maFrames.front(); 668 Window * pWindow = pFrame->GetWindow() ? pSalData->maFrames.front()->GetWindow() : NULL; 669 670 if( pWindow ) 671 { 672 const Point aPoint; 673 CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand ); 674 NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt ); 675 676 if ( !ImplCallPreNotify( aNCmdEvt ) ) 677 pWindow->Command( aCEvt ); 678 } 679 680 } 681 break; 682 683 case YieldWakeupEvent: 684 // do nothing, fall out of Yield 685 break; 686 687 default: 688 DBG_ERROR( "unhandled NSApplicationDefined event" ); 689 break; 690 }; 691 } 692 693 // ----------------------------------------------------------------------- 694 695 class ReleasePoolHolder 696 { 697 NSAutoreleasePool* mpPool; 698 public: 699 ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {} 700 ~ReleasePoolHolder() { [mpPool release]; } 701 }; 702 703 void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) 704 { 705 // ensure that the per thread autorelease pool is top level and 706 // will therefore not be destroyed by cocoa implicitly 707 SalData::ensureThreadAutoreleasePool(); 708 709 // NSAutoreleasePool documentation suggests we should have 710 // an own pool for each yield level 711 ReleasePoolHolder aReleasePool; 712 713 // Release all locks so that we don't deadlock when we pull pending 714 // events from the event queue 715 bool bDispatchUser = true; 716 while( bDispatchUser ) 717 { 718 sal_uLong nCount = ReleaseYieldMutex(); 719 720 // get one user event 721 osl_acquireMutex( maUserEventListMutex ); 722 SalUserEvent aEvent( NULL, NULL, 0 ); 723 if( ! maUserEvents.empty() ) 724 { 725 aEvent = maUserEvents.front(); 726 maUserEvents.pop_front(); 727 } 728 else 729 bDispatchUser = false; 730 osl_releaseMutex( maUserEventListMutex ); 731 732 AcquireYieldMutex( nCount ); 733 734 // dispatch it 735 if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) ) 736 { 737 aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); 738 osl_setCondition( maWaitingYieldCond ); 739 // return if only one event is asked for 740 if( ! bHandleAllCurrentEvents ) 741 return; 742 } 743 } 744 745 // handle cocoa event queue 746 // cocoa events mye be only handled in the thread the NSApp was created 747 if( isNSAppThread() && mnActivePrintJobs == 0 ) 748 { 749 // we need to be woken up by a cocoa-event 750 // if a user event should be posted by the event handling below 751 bool bOldWaitingYield = mbWaitingYield; 752 mbWaitingYield = bWait; 753 754 // handle available events 755 NSEvent* pEvent = nil; 756 bool bHadEvent = false; 757 do 758 { 759 sal_uLong nCount = ReleaseYieldMutex(); 760 761 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil 762 inMode: NSDefaultRunLoopMode dequeue: YES]; 763 if( pEvent ) 764 { 765 [NSApp sendEvent: pEvent]; 766 bHadEvent = true; 767 } 768 [NSApp updateWindows]; 769 770 AcquireYieldMutex( nCount ); 771 } while( bHandleAllCurrentEvents && pEvent ); 772 773 // if we had no event yet, wait for one if requested 774 if( bWait && ! bHadEvent ) 775 { 776 sal_uLong nCount = ReleaseYieldMutex(); 777 778 NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture]; 779 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt 780 inMode: NSDefaultRunLoopMode dequeue: YES]; 781 if( pEvent ) 782 [NSApp sendEvent: pEvent]; 783 [NSApp updateWindows]; 784 785 AcquireYieldMutex( nCount ); 786 787 // #i86581# 788 // FIXME: sometimes the NSTimer will never fire. Firing it by hand then 789 // fixes the problem even seems to set the correct next firing date 790 // Why oh why ? 791 if( ! pEvent && AquaSalTimer::pRunningTimer ) 792 { 793 // this cause crashes on MacOSX 10.4 794 // [AquaSalTimer::pRunningTimer fire]; 795 ImplGetSVData()->mpSalTimer->CallCallback(); 796 } 797 } 798 799 mbWaitingYield = bOldWaitingYield; 800 801 // collect update rectangles 802 const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames ); 803 for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) 804 { 805 if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() ) 806 { 807 (*it)->Flush( (*it)->maInvalidRect ); 808 (*it)->maInvalidRect.SetEmpty(); 809 } 810 } 811 osl_setCondition( maWaitingYieldCond ); 812 } 813 else if( bWait ) 814 { 815 // #i103162# 816 // wait until any thread (most likely the main thread) 817 // has dispatched an event, cop out at 200 ms 818 osl_resetCondition( maWaitingYieldCond ); 819 TimeValue aVal = { 0, 200000000 }; 820 sal_uLong nCount = ReleaseYieldMutex(); 821 osl_waitCondition( maWaitingYieldCond, &aVal ); 822 AcquireYieldMutex( nCount ); 823 } 824 825 // we get some apple events way too early 826 // before the application is ready to handle them, 827 // so their corresponding application events need to be delayed 828 // now is a good time to handle at least one of them 829 if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute ) 830 { 831 // make sure that only one application event is active at a time 832 static bool bInAppEvent = false; 833 if( !bInAppEvent ) 834 { 835 bInAppEvent = true; 836 // get the next delayed application event 837 const ApplicationEvent* pAppEvent = aAppEventList.front(); 838 aAppEventList.pop_front(); 839 // handle one application event (no recursion) 840 const ImplSVData* pSVData = ImplGetSVData(); 841 pSVData->mpApp->AppEvent( *pAppEvent ); 842 delete pAppEvent; 843 // allow the next delayed application event 844 bInAppEvent = false; 845 } 846 } 847 } 848 849 // ----------------------------------------------------------------------- 850 851 bool AquaSalInstance::AnyInput( sal_uInt16 nType ) 852 { 853 if( nType & INPUT_APPEVENT ) 854 { 855 if( ! aAppEventList.empty() ) 856 return true; 857 if( nType == INPUT_APPEVENT ) 858 return false; 859 } 860 861 if( nType & INPUT_TIMER ) 862 { 863 if( AquaSalTimer::pRunningTimer ) 864 { 865 NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate]; 866 if( pDt && [pDt timeIntervalSinceNow] < 0 ) 867 { 868 return true; 869 } 870 } 871 } 872 873 unsigned/*NSUInteger*/ nEventMask = 0; 874 if( nType & INPUT_MOUSE) 875 nEventMask |= 876 NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | 877 NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask | 878 NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask | 879 NSScrollWheelMask | 880 // NSMouseMovedMask | 881 NSMouseEnteredMask | NSMouseExitedMask; 882 if( nType & INPUT_KEYBOARD) 883 nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask; 884 if( nType & INPUT_OTHER) 885 nEventMask |= NSTabletPoint; 886 // TODO: INPUT_PAINT / more INPUT_OTHER 887 if( !nType) 888 return false; 889 890 NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil 891 inMode: NSDefaultRunLoopMode dequeue: NO]; 892 return (pEvent != NULL); 893 } 894 895 // ----------------------------------------------------------------------- 896 897 SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, sal_uLong /*nSalFrameStyle*/ ) 898 { 899 return NULL; 900 } 901 902 // ----------------------------------------------------------------------- 903 904 SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle ) 905 { 906 SalData::ensureThreadAutoreleasePool(); 907 908 SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle ); 909 return pFrame; 910 } 911 912 // ----------------------------------------------------------------------- 913 914 void AquaSalInstance::DestroyFrame( SalFrame* pFrame ) 915 { 916 delete pFrame; 917 } 918 919 // ----------------------------------------------------------------------- 920 921 SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, sal_Bool /* bShow */ ) 922 { 923 // SystemWindowData is meaningless on Mac OS X 924 AquaSalObject *pObject = NULL; 925 926 if ( pParent ) 927 pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) ); 928 929 return pObject; 930 } 931 932 // ----------------------------------------------------------------------- 933 934 void AquaSalInstance::DestroyObject( SalObject* pObject ) 935 { 936 delete ( pObject ); 937 } 938 939 // ----------------------------------------------------------------------- 940 941 SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) 942 { 943 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) ); 944 } 945 946 // ----------------------------------------------------------------------- 947 948 void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter ) 949 { 950 delete pPrinter; 951 } 952 953 // ----------------------------------------------------------------------- 954 955 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) 956 { 957 NSArray* pNames = [NSPrinter printerNames]; 958 NSArray* pTypes = [NSPrinter printerTypes]; 959 unsigned int nNameCount = pNames ? [pNames count] : 0; 960 unsigned int nTypeCount = pTypes ? [pTypes count] : 0; 961 DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" ); 962 for( unsigned int i = 0; i < nNameCount; i++ ) 963 { 964 NSString* pName = [pNames objectAtIndex: i]; 965 NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil; 966 if( pName ) 967 { 968 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; 969 pInfo->maPrinterName = GetOUString( pName ); 970 if( pType ) 971 pInfo->maDriver = GetOUString( pType ); 972 pInfo->mnStatus = 0; 973 pInfo->mnJobs = 0; 974 pInfo->mpSysData = NULL; 975 976 pList->Add( pInfo ); 977 } 978 } 979 } 980 981 // ----------------------------------------------------------------------- 982 983 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) 984 { 985 } 986 987 // ----------------------------------------------------------------------- 988 989 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) 990 { 991 delete pInfo; 992 } 993 994 // ----------------------------------------------------------------------- 995 996 XubString AquaSalInstance::GetDefaultPrinter() 997 { 998 // #i113170# may not be the main thread if called from UNO API 999 SalData::ensureThreadAutoreleasePool(); 1000 1001 if( ! maDefaultPrinter.getLength() ) 1002 { 1003 NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo]; 1004 DBG_ASSERT( pPI, "no print info" ); 1005 if( pPI ) 1006 { 1007 NSPrinter* pPr = [pPI printer]; 1008 DBG_ASSERT( pPr, "no printer in default info" ); 1009 if( pPr ) 1010 { 1011 NSString* pDefName = [pPr name]; 1012 DBG_ASSERT( pDefName, "printer has no name" ); 1013 maDefaultPrinter = GetOUString( pDefName ); 1014 } 1015 } 1016 } 1017 return maDefaultPrinter; 1018 } 1019 1020 // ----------------------------------------------------------------------- 1021 1022 SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, 1023 ImplJobSetup* pSetupData ) 1024 { 1025 // #i113170# may not be the main thread if called from UNO API 1026 SalData::ensureThreadAutoreleasePool(); 1027 1028 SalInfoPrinter* pNewInfoPrinter = NULL; 1029 if( pQueueInfo ) 1030 { 1031 pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo ); 1032 if( pSetupData ) 1033 pNewInfoPrinter->SetPrinterData( pSetupData ); 1034 } 1035 1036 return pNewInfoPrinter; 1037 } 1038 1039 // ----------------------------------------------------------------------- 1040 1041 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) 1042 { 1043 // #i113170# may not be the main thread if called from UNO API 1044 SalData::ensureThreadAutoreleasePool(); 1045 1046 delete pPrinter; 1047 } 1048 1049 // ----------------------------------------------------------------------- 1050 1051 SalSystem* AquaSalInstance::CreateSystem() 1052 { 1053 return new AquaSalSystem(); 1054 } 1055 1056 // ----------------------------------------------------------------------- 1057 1058 void AquaSalInstance::DestroySystem( SalSystem* pSystem ) 1059 { 1060 delete pSystem; 1061 } 1062 1063 // ----------------------------------------------------------------------- 1064 1065 void AquaSalInstance::SetEventCallback( void*, bool(*)(void*,void*,int) ) 1066 { 1067 } 1068 1069 // ----------------------------------------------------------------------- 1070 1071 void AquaSalInstance::SetErrorEventCallback( void*, bool(*)(void*,void*,int) ) 1072 { 1073 } 1074 1075 // ----------------------------------------------------------------------- 1076 1077 void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) 1078 { 1079 rReturnedBytes = 1; 1080 rReturnedType = AsciiCString; 1081 return (void*)""; 1082 } 1083 1084 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts 1085 // to UTF-8 before encoding non ascii characters, which is not what other apps expect. 1086 static rtl::OUString translateToExternalUrl(const rtl::OUString& internalUrl) 1087 { 1088 rtl::OUString extUrl; 1089 1090 uno::Reference< lang::XMultiServiceFactory > sm = comphelper::getProcessServiceFactory(); 1091 if (sm.is()) 1092 { 1093 uno::Reference< beans::XPropertySet > pset; 1094 sm->queryInterface( getCppuType( &pset )) >>= pset; 1095 if (pset.is()) 1096 { 1097 uno::Reference< uno::XComponentContext > context; 1098 static const rtl::OUString DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ); 1099 pset->getPropertyValue(DEFAULT_CONTEXT) >>= context; 1100 if (context.is()) 1101 extUrl = uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl); 1102 } 1103 } 1104 return extUrl; 1105 } 1106 1107 // #i104525# many versions of OSX have problems with some URLs: 1108 // when an app requests OSX to add one of these URLs to the "Recent Items" list 1109 // then this app gets killed (TextEdit, Preview, etc. and also OOo) 1110 static bool isDangerousUrl( const rtl::OUString& rUrl ) 1111 { 1112 // use a heuristic that detects all known cases since there is no official comment 1113 // on the exact impact and root cause of the OSX bug 1114 const int nLen = rUrl.getLength(); 1115 const sal_Unicode* p = rUrl.getStr(); 1116 for( int i = 0; i < nLen-3; ++i, ++p ) { 1117 if( p[0] != '%' ) 1118 continue; 1119 // escaped percent? 1120 if( (p[1] == '2') && (p[2] == '5') ) 1121 return true; 1122 // escapes are considered to be UTF-8 encoded 1123 // => check for invalid UTF-8 leading byte 1124 if( (p[1] != 'f') && (p[1] != 'F') ) 1125 continue; 1126 int cLowNibble = p[2]; 1127 if( (cLowNibble >= '0' ) && (cLowNibble <= '9')) 1128 return false; 1129 if( cLowNibble >= 'a' ) 1130 cLowNibble -= 'a' - 'A'; 1131 if( (cLowNibble < 'A') || (cLowNibble >= 'C')) 1132 return true; 1133 } 1134 1135 return false; 1136 } 1137 1138 void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/) 1139 { 1140 // Convert file URL for external use (see above) 1141 rtl::OUString externalUrl = translateToExternalUrl(rFileUrl); 1142 if( 0 == externalUrl.getLength() ) 1143 externalUrl = rFileUrl; 1144 1145 if( externalUrl.getLength() && !isDangerousUrl( externalUrl ) ) 1146 { 1147 NSString* pString = CreateNSString( externalUrl ); 1148 NSURL* pURL = [NSURL URLWithString: pString]; 1149 1150 if( pURL ) 1151 { 1152 NSDocumentController* pCtrl = [NSDocumentController sharedDocumentController]; 1153 [pCtrl noteNewRecentDocumentURL: pURL]; 1154 } 1155 if( pString ) 1156 [pString release]; 1157 } 1158 } 1159 1160 1161 // ----------------------------------------------------------------------- 1162 1163 SalTimer* AquaSalInstance::CreateSalTimer() 1164 { 1165 return new AquaSalTimer(); 1166 } 1167 1168 // ----------------------------------------------------------------------- 1169 1170 SalSystem* AquaSalInstance::CreateSalSystem() 1171 { 1172 return new AquaSalSystem(); 1173 } 1174 1175 // ----------------------------------------------------------------------- 1176 1177 SalBitmap* AquaSalInstance::CreateSalBitmap() 1178 { 1179 return new AquaSalBitmap(); 1180 } 1181 1182 // ----------------------------------------------------------------------- 1183 1184 SalSession* AquaSalInstance::CreateSalSession() 1185 { 1186 return NULL; 1187 } 1188 1189 // ----------------------------------------------------------------------- 1190 1191 class MacImeStatus : public SalI18NImeStatus 1192 { 1193 public: 1194 MacImeStatus() {} 1195 virtual ~MacImeStatus() {} 1196 1197 // asks whether there is a status window available 1198 // to toggle into menubar 1199 virtual bool canToggle() { return false; } 1200 virtual void toggle() {} 1201 }; 1202 1203 // ----------------------------------------------------------------------- 1204 1205 SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus() 1206 { 1207 return new MacImeStatus(); 1208 } 1209 1210 // YieldMutexReleaser 1211 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 ) 1212 { 1213 SalData* pSalData = GetSalData(); 1214 if( ! pSalData->mpFirstInstance->isNSAppThread() ) 1215 { 1216 SalData::ensureThreadAutoreleasePool(); 1217 mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex(); 1218 } 1219 } 1220 1221 YieldMutexReleaser::~YieldMutexReleaser() 1222 { 1223 if( mnCount != 0 ) 1224 GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount ); 1225 } 1226 1227 ////////////////////////////////////////////////////////////// 1228 rtl::OUString GetOUString( CFStringRef rStr ) 1229 { 1230 if( rStr == 0 ) 1231 return rtl::OUString(); 1232 CFIndex nLength = CFStringGetLength( rStr ); 1233 if( nLength == 0 ) 1234 return rtl::OUString(); 1235 const UniChar* pConstStr = CFStringGetCharactersPtr( rStr ); 1236 if( pConstStr ) 1237 return rtl::OUString( pConstStr, nLength ); 1238 UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) ); 1239 CFRange aRange = { 0, nLength }; 1240 CFStringGetCharacters( rStr, aRange, pStr ); 1241 rtl::OUString aRet( pStr, nLength ); 1242 rtl_freeMemory( pStr ); 1243 return aRet; 1244 } 1245 1246 rtl::OUString GetOUString( NSString* pStr ) 1247 { 1248 if( ! pStr ) 1249 return rtl::OUString(); 1250 int nLen = [pStr length]; 1251 if( nLen == 0 ) 1252 return rtl::OUString(); 1253 1254 rtl::OUStringBuffer aBuf( nLen+1 ); 1255 aBuf.setLength( nLen ); 1256 [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())]; 1257 return aBuf.makeStringAndClear(); 1258 } 1259 1260 CFStringRef CreateCFString( const rtl::OUString& rStr ) 1261 { 1262 return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() ); 1263 } 1264 1265 NSString* CreateNSString( const rtl::OUString& rStr ) 1266 { 1267 return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()]; 1268 } 1269 1270 CGImageRef CreateCGImage( const Image& rImage ) 1271 { 1272 BitmapEx aBmpEx( rImage.GetBitmapEx() ); 1273 Bitmap aBmp( aBmpEx.GetBitmap() ); 1274 1275 if( ! aBmp || ! aBmp.ImplGetImpBitmap() ) 1276 return NULL; 1277 1278 // simple case, no transparency 1279 AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap()); 1280 1281 if( ! pSalBmp ) 1282 return NULL; 1283 1284 CGImageRef xImage = NULL; 1285 if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) ) 1286 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1287 else if( aBmpEx.IsAlpha() ) 1288 { 1289 AlphaMask aAlphaMask( aBmpEx.GetAlpha() ); 1290 Bitmap aMask( aAlphaMask.GetBitmap() ); 1291 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap()); 1292 if( pMaskBmp ) 1293 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1294 else 1295 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1296 } 1297 else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP ) 1298 { 1299 Bitmap aMask( aBmpEx.GetMask() ); 1300 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap()); 1301 if( pMaskBmp ) 1302 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1303 else 1304 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1305 } 1306 else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR ) 1307 { 1308 Color aTransColor( aBmpEx.GetTransparentColor() ); 1309 SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() ); 1310 xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor ); 1311 } 1312 1313 return xImage; 1314 } 1315 1316 NSImage* CreateNSImage( const Image& rImage ) 1317 { 1318 CGImageRef xImage = CreateCGImage( rImage ); 1319 1320 if( ! xImage ) 1321 return nil; 1322 1323 Size aSize( rImage.GetSizePixel() ); 1324 NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )]; 1325 if( pImage ) 1326 { 1327 [pImage setFlipped: YES]; 1328 [pImage lockFocus]; 1329 1330 NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; 1331 CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]); 1332 1333 const CGRect aDstRect = { {0, 0}, { aSize.Width(), aSize.Height() } }; 1334 CGContextDrawImage( rCGContext, aDstRect, xImage ); 1335 1336 [pImage unlockFocus]; 1337 } 1338 1339 CGImageRelease( xImage ); 1340 1341 return pImage; 1342 } 1343