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