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