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 while( (*it) && ( (it != pSalData->maFrames.end() ) || ( (*it)->mbFullScreen == false ) ) ) 626 { 627 if( (*it)->mbFullScreen ) 628 bIsFullScreenMode = true; 629 it++; 630 } 631 632 switch ([pEvent data1]) 633 { 634 case kRemoteButtonPlay: 635 nCommand = ( bIsFullScreenMode == true ) ? MEDIA_COMMAND_PLAY_PAUSE : MEDIA_COMMAND_PLAY; 636 break; 637 638 // kept for experimentation purpose (scheduled for future implementation) 639 // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break; 640 641 case kRemoteButtonPlus: nCommand = MEDIA_COMMAND_VOLUME_UP; break; 642 643 case kRemoteButtonMinus: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break; 644 645 case kRemoteButtonRight: nCommand = MEDIA_COMMAND_NEXTTRACK; break; 646 647 case kRemoteButtonRight_Hold: nCommand = MEDIA_COMMAND_NEXTTRACK_HOLD; break; 648 649 case kRemoteButtonLeft: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break; 650 651 case kRemoteButtonLeft_Hold: nCommand = MEDIA_COMMAND_REWIND; break; 652 653 case kRemoteButtonPlay_Hold: nCommand = MEDIA_COMMAND_PLAY_HOLD; break; 654 655 case kRemoteButtonMenu_Hold: nCommand = MEDIA_COMMAND_STOP; break; 656 657 // FIXME : not detected 658 case kRemoteButtonPlus_Hold: 659 case kRemoteButtonMinus_Hold: 660 break; 661 662 default: 663 break; 664 } 665 AquaSalFrame* pFrame = pSalData->maFrames.front(); 666 Window * pWindow = pFrame->GetWindow() ? pSalData->maFrames.front()->GetWindow() : NULL; 667 668 if( pWindow ) 669 { 670 const Point aPoint; 671 CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand ); 672 NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt ); 673 674 if ( !ImplCallPreNotify( aNCmdEvt ) ) 675 pWindow->Command( aCEvt ); 676 } 677 678 } 679 break; 680 681 case YieldWakeupEvent: 682 // do nothing, fall out of Yield 683 break; 684 685 default: 686 DBG_ERROR( "unhandled NSApplicationDefined event" ); 687 break; 688 }; 689 } 690 691 // ----------------------------------------------------------------------- 692 693 class ReleasePoolHolder 694 { 695 NSAutoreleasePool* mpPool; 696 public: 697 ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {} 698 ~ReleasePoolHolder() { [mpPool release]; } 699 }; 700 701 void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) 702 { 703 // ensure that the per thread autorelease pool is top level and 704 // will therefore not be destroyed by cocoa implicitly 705 SalData::ensureThreadAutoreleasePool(); 706 707 // NSAutoreleasePool documentation suggests we should have 708 // an own pool for each yield level 709 ReleasePoolHolder aReleasePool; 710 711 // Release all locks so that we don't deadlock when we pull pending 712 // events from the event queue 713 bool bDispatchUser = true; 714 while( bDispatchUser ) 715 { 716 sal_uLong nCount = ReleaseYieldMutex(); 717 718 // get one user event 719 osl_acquireMutex( maUserEventListMutex ); 720 SalUserEvent aEvent( NULL, NULL, 0 ); 721 if( ! maUserEvents.empty() ) 722 { 723 aEvent = maUserEvents.front(); 724 maUserEvents.pop_front(); 725 } 726 else 727 bDispatchUser = false; 728 osl_releaseMutex( maUserEventListMutex ); 729 730 AcquireYieldMutex( nCount ); 731 732 // dispatch it 733 if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) ) 734 { 735 aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); 736 osl_setCondition( maWaitingYieldCond ); 737 // return if only one event is asked for 738 if( ! bHandleAllCurrentEvents ) 739 return; 740 } 741 } 742 743 // handle cocoa event queue 744 // cocoa events mye be only handled in the thread the NSApp was created 745 if( isNSAppThread() && mnActivePrintJobs == 0 ) 746 { 747 // we need to be woken up by a cocoa-event 748 // if a user event should be posted by the event handling below 749 bool bOldWaitingYield = mbWaitingYield; 750 mbWaitingYield = bWait; 751 752 // handle available events 753 NSEvent* pEvent = nil; 754 bool bHadEvent = false; 755 do 756 { 757 sal_uLong nCount = ReleaseYieldMutex(); 758 759 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil 760 inMode: NSDefaultRunLoopMode dequeue: YES]; 761 if( pEvent ) 762 { 763 [NSApp sendEvent: pEvent]; 764 bHadEvent = true; 765 } 766 [NSApp updateWindows]; 767 768 AcquireYieldMutex( nCount ); 769 } while( bHandleAllCurrentEvents && pEvent ); 770 771 // if we had no event yet, wait for one if requested 772 if( bWait && ! bHadEvent ) 773 { 774 sal_uLong nCount = ReleaseYieldMutex(); 775 776 NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture]; 777 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt 778 inMode: NSDefaultRunLoopMode dequeue: YES]; 779 if( pEvent ) 780 [NSApp sendEvent: pEvent]; 781 [NSApp updateWindows]; 782 783 AcquireYieldMutex( nCount ); 784 785 // #i86581# 786 // FIXME: sometimes the NSTimer will never fire. Firing it by hand then 787 // fixes the problem even seems to set the correct next firing date 788 // Why oh why ? 789 if( ! pEvent && AquaSalTimer::pRunningTimer ) 790 { 791 // this cause crashes on MacOSX 10.4 792 // [AquaSalTimer::pRunningTimer fire]; 793 ImplGetSVData()->mpSalTimer->CallCallback(); 794 } 795 } 796 797 mbWaitingYield = bOldWaitingYield; 798 799 // collect update rectangles 800 const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames ); 801 for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) 802 { 803 if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() ) 804 { 805 (*it)->Flush( (*it)->maInvalidRect ); 806 (*it)->maInvalidRect.SetEmpty(); 807 } 808 } 809 osl_setCondition( maWaitingYieldCond ); 810 } 811 else if( bWait ) 812 { 813 // #i103162# 814 // wait until any thread (most likely the main thread) 815 // has dispatched an event, cop out at 200 ms 816 osl_resetCondition( maWaitingYieldCond ); 817 TimeValue aVal = { 0, 200000000 }; 818 sal_uLong nCount = ReleaseYieldMutex(); 819 osl_waitCondition( maWaitingYieldCond, &aVal ); 820 AcquireYieldMutex( nCount ); 821 } 822 823 // we get some apple events way too early 824 // before the application is ready to handle them, 825 // so their corresponding application events need to be delayed 826 // now is a good time to handle at least one of them 827 if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute ) 828 { 829 // make sure that only one application event is active at a time 830 static bool bInAppEvent = false; 831 if( !bInAppEvent ) 832 { 833 bInAppEvent = true; 834 // get the next delayed application event 835 const ApplicationEvent* pAppEvent = aAppEventList.front(); 836 aAppEventList.pop_front(); 837 // handle one application event (no recursion) 838 const ImplSVData* pSVData = ImplGetSVData(); 839 pSVData->mpApp->AppEvent( *pAppEvent ); 840 delete pAppEvent; 841 // allow the next delayed application event 842 bInAppEvent = false; 843 } 844 } 845 } 846 847 // ----------------------------------------------------------------------- 848 849 bool AquaSalInstance::AnyInput( sal_uInt16 nType ) 850 { 851 if( nType & INPUT_APPEVENT ) 852 { 853 if( ! aAppEventList.empty() ) 854 return true; 855 if( nType == INPUT_APPEVENT ) 856 return false; 857 } 858 859 if( nType & INPUT_TIMER ) 860 { 861 if( AquaSalTimer::pRunningTimer ) 862 { 863 NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate]; 864 if( pDt && [pDt timeIntervalSinceNow] < 0 ) 865 { 866 return true; 867 } 868 } 869 } 870 871 unsigned/*NSUInteger*/ nEventMask = 0; 872 if( nType & INPUT_MOUSE) 873 nEventMask |= 874 NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | 875 NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask | 876 NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask | 877 NSScrollWheelMask | 878 // NSMouseMovedMask | 879 NSMouseEnteredMask | NSMouseExitedMask; 880 if( nType & INPUT_KEYBOARD) 881 nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask; 882 if( nType & INPUT_OTHER) 883 nEventMask |= NSTabletPoint; 884 // TODO: INPUT_PAINT / more INPUT_OTHER 885 if( !nType) 886 return false; 887 888 NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil 889 inMode: NSDefaultRunLoopMode dequeue: NO]; 890 return (pEvent != NULL); 891 } 892 893 // ----------------------------------------------------------------------- 894 895 SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, sal_uLong /*nSalFrameStyle*/ ) 896 { 897 return NULL; 898 } 899 900 // ----------------------------------------------------------------------- 901 902 SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle ) 903 { 904 SalData::ensureThreadAutoreleasePool(); 905 906 SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle ); 907 return pFrame; 908 } 909 910 // ----------------------------------------------------------------------- 911 912 void AquaSalInstance::DestroyFrame( SalFrame* pFrame ) 913 { 914 delete pFrame; 915 } 916 917 // ----------------------------------------------------------------------- 918 919 SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, sal_Bool /* bShow */ ) 920 { 921 // SystemWindowData is meaningless on Mac OS X 922 AquaSalObject *pObject = NULL; 923 924 if ( pParent ) 925 pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) ); 926 927 return pObject; 928 } 929 930 // ----------------------------------------------------------------------- 931 932 void AquaSalInstance::DestroyObject( SalObject* pObject ) 933 { 934 delete ( pObject ); 935 } 936 937 // ----------------------------------------------------------------------- 938 939 SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) 940 { 941 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) ); 942 } 943 944 // ----------------------------------------------------------------------- 945 946 void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter ) 947 { 948 delete pPrinter; 949 } 950 951 // ----------------------------------------------------------------------- 952 953 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) 954 { 955 NSArray* pNames = [NSPrinter printerNames]; 956 NSArray* pTypes = [NSPrinter printerTypes]; 957 unsigned int nNameCount = pNames ? [pNames count] : 0; 958 unsigned int nTypeCount = pTypes ? [pTypes count] : 0; 959 DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" ); 960 for( unsigned int i = 0; i < nNameCount; i++ ) 961 { 962 NSString* pName = [pNames objectAtIndex: i]; 963 NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil; 964 if( pName ) 965 { 966 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; 967 pInfo->maPrinterName = GetOUString( pName ); 968 if( pType ) 969 pInfo->maDriver = GetOUString( pType ); 970 pInfo->mnStatus = 0; 971 pInfo->mnJobs = 0; 972 pInfo->mpSysData = NULL; 973 974 pList->Add( pInfo ); 975 } 976 } 977 } 978 979 // ----------------------------------------------------------------------- 980 981 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) 982 { 983 } 984 985 // ----------------------------------------------------------------------- 986 987 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) 988 { 989 delete pInfo; 990 } 991 992 // ----------------------------------------------------------------------- 993 994 XubString AquaSalInstance::GetDefaultPrinter() 995 { 996 // #i113170# may not be the main thread if called from UNO API 997 SalData::ensureThreadAutoreleasePool(); 998 999 if( ! maDefaultPrinter.getLength() ) 1000 { 1001 NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo]; 1002 DBG_ASSERT( pPI, "no print info" ); 1003 if( pPI ) 1004 { 1005 NSPrinter* pPr = [pPI printer]; 1006 DBG_ASSERT( pPr, "no printer in default info" ); 1007 if( pPr ) 1008 { 1009 NSString* pDefName = [pPr name]; 1010 DBG_ASSERT( pDefName, "printer has no name" ); 1011 maDefaultPrinter = GetOUString( pDefName ); 1012 } 1013 } 1014 } 1015 return maDefaultPrinter; 1016 } 1017 1018 // ----------------------------------------------------------------------- 1019 1020 SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, 1021 ImplJobSetup* pSetupData ) 1022 { 1023 // #i113170# may not be the main thread if called from UNO API 1024 SalData::ensureThreadAutoreleasePool(); 1025 1026 SalInfoPrinter* pNewInfoPrinter = NULL; 1027 if( pQueueInfo ) 1028 { 1029 pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo ); 1030 if( pSetupData ) 1031 pNewInfoPrinter->SetPrinterData( pSetupData ); 1032 } 1033 1034 return pNewInfoPrinter; 1035 } 1036 1037 // ----------------------------------------------------------------------- 1038 1039 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) 1040 { 1041 // #i113170# may not be the main thread if called from UNO API 1042 SalData::ensureThreadAutoreleasePool(); 1043 1044 delete pPrinter; 1045 } 1046 1047 // ----------------------------------------------------------------------- 1048 1049 SalSystem* AquaSalInstance::CreateSystem() 1050 { 1051 return new AquaSalSystem(); 1052 } 1053 1054 // ----------------------------------------------------------------------- 1055 1056 void AquaSalInstance::DestroySystem( SalSystem* pSystem ) 1057 { 1058 delete pSystem; 1059 } 1060 1061 // ----------------------------------------------------------------------- 1062 1063 void AquaSalInstance::SetEventCallback( void*, bool(*)(void*,void*,int) ) 1064 { 1065 } 1066 1067 // ----------------------------------------------------------------------- 1068 1069 void AquaSalInstance::SetErrorEventCallback( void*, bool(*)(void*,void*,int) ) 1070 { 1071 } 1072 1073 // ----------------------------------------------------------------------- 1074 1075 void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) 1076 { 1077 rReturnedBytes = 1; 1078 rReturnedType = AsciiCString; 1079 return (void*)""; 1080 } 1081 1082 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts 1083 // to UTF-8 before encoding non ascii characters, which is not what other apps expect. 1084 static rtl::OUString translateToExternalUrl(const rtl::OUString& internalUrl) 1085 { 1086 rtl::OUString extUrl; 1087 1088 uno::Reference< lang::XMultiServiceFactory > sm = comphelper::getProcessServiceFactory(); 1089 if (sm.is()) 1090 { 1091 uno::Reference< beans::XPropertySet > pset; 1092 sm->queryInterface( getCppuType( &pset )) >>= pset; 1093 if (pset.is()) 1094 { 1095 uno::Reference< uno::XComponentContext > context; 1096 static const rtl::OUString DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ); 1097 pset->getPropertyValue(DEFAULT_CONTEXT) >>= context; 1098 if (context.is()) 1099 extUrl = uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl); 1100 } 1101 } 1102 return extUrl; 1103 } 1104 1105 // #i104525# many versions of OSX have problems with some URLs: 1106 // when an app requests OSX to add one of these URLs to the "Recent Items" list 1107 // then this app gets killed (TextEdit, Preview, etc. and also OOo) 1108 static bool isDangerousUrl( const rtl::OUString& rUrl ) 1109 { 1110 // use a heuristic that detects all known cases since there is no official comment 1111 // on the exact impact and root cause of the OSX bug 1112 const int nLen = rUrl.getLength(); 1113 const sal_Unicode* p = rUrl.getStr(); 1114 for( int i = 0; i < nLen-3; ++i, ++p ) { 1115 if( p[0] != '%' ) 1116 continue; 1117 // escaped percent? 1118 if( (p[1] == '2') && (p[2] == '5') ) 1119 return true; 1120 // escapes are considered to be UTF-8 encoded 1121 // => check for invalid UTF-8 leading byte 1122 if( (p[1] != 'f') && (p[1] != 'F') ) 1123 continue; 1124 int cLowNibble = p[2]; 1125 if( (cLowNibble >= '0' ) && (cLowNibble <= '9')) 1126 return false; 1127 if( cLowNibble >= 'a' ) 1128 cLowNibble -= 'a' - 'A'; 1129 if( (cLowNibble < 'A') || (cLowNibble >= 'C')) 1130 return true; 1131 } 1132 1133 return false; 1134 } 1135 1136 void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/) 1137 { 1138 // Convert file URL for external use (see above) 1139 rtl::OUString externalUrl = translateToExternalUrl(rFileUrl); 1140 if( 0 == externalUrl.getLength() ) 1141 externalUrl = rFileUrl; 1142 1143 if( externalUrl.getLength() && !isDangerousUrl( externalUrl ) ) 1144 { 1145 NSString* pString = CreateNSString( externalUrl ); 1146 NSURL* pURL = [NSURL URLWithString: pString]; 1147 1148 if( pURL ) 1149 { 1150 NSDocumentController* pCtrl = [NSDocumentController sharedDocumentController]; 1151 [pCtrl noteNewRecentDocumentURL: pURL]; 1152 } 1153 if( pString ) 1154 [pString release]; 1155 } 1156 } 1157 1158 1159 // ----------------------------------------------------------------------- 1160 1161 SalTimer* AquaSalInstance::CreateSalTimer() 1162 { 1163 return new AquaSalTimer(); 1164 } 1165 1166 // ----------------------------------------------------------------------- 1167 1168 SalSystem* AquaSalInstance::CreateSalSystem() 1169 { 1170 return new AquaSalSystem(); 1171 } 1172 1173 // ----------------------------------------------------------------------- 1174 1175 SalBitmap* AquaSalInstance::CreateSalBitmap() 1176 { 1177 return new AquaSalBitmap(); 1178 } 1179 1180 // ----------------------------------------------------------------------- 1181 1182 SalSession* AquaSalInstance::CreateSalSession() 1183 { 1184 return NULL; 1185 } 1186 1187 // ----------------------------------------------------------------------- 1188 1189 class MacImeStatus : public SalI18NImeStatus 1190 { 1191 public: 1192 MacImeStatus() {} 1193 virtual ~MacImeStatus() {} 1194 1195 // asks whether there is a status window available 1196 // to toggle into menubar 1197 virtual bool canToggle() { return false; } 1198 virtual void toggle() {} 1199 }; 1200 1201 // ----------------------------------------------------------------------- 1202 1203 SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus() 1204 { 1205 return new MacImeStatus(); 1206 } 1207 1208 // YieldMutexReleaser 1209 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 ) 1210 { 1211 SalData* pSalData = GetSalData(); 1212 if( ! pSalData->mpFirstInstance->isNSAppThread() ) 1213 { 1214 SalData::ensureThreadAutoreleasePool(); 1215 mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex(); 1216 } 1217 } 1218 1219 YieldMutexReleaser::~YieldMutexReleaser() 1220 { 1221 if( mnCount != 0 ) 1222 GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount ); 1223 } 1224 1225 ////////////////////////////////////////////////////////////// 1226 rtl::OUString GetOUString( CFStringRef rStr ) 1227 { 1228 if( rStr == 0 ) 1229 return rtl::OUString(); 1230 CFIndex nLength = CFStringGetLength( rStr ); 1231 if( nLength == 0 ) 1232 return rtl::OUString(); 1233 const UniChar* pConstStr = CFStringGetCharactersPtr( rStr ); 1234 if( pConstStr ) 1235 return rtl::OUString( pConstStr, nLength ); 1236 UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) ); 1237 CFRange aRange = { 0, nLength }; 1238 CFStringGetCharacters( rStr, aRange, pStr ); 1239 rtl::OUString aRet( pStr, nLength ); 1240 rtl_freeMemory( pStr ); 1241 return aRet; 1242 } 1243 1244 rtl::OUString GetOUString( NSString* pStr ) 1245 { 1246 if( ! pStr ) 1247 return rtl::OUString(); 1248 int nLen = [pStr length]; 1249 if( nLen == 0 ) 1250 return rtl::OUString(); 1251 1252 rtl::OUStringBuffer aBuf( nLen+1 ); 1253 aBuf.setLength( nLen ); 1254 [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())]; 1255 return aBuf.makeStringAndClear(); 1256 } 1257 1258 CFStringRef CreateCFString( const rtl::OUString& rStr ) 1259 { 1260 return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() ); 1261 } 1262 1263 NSString* CreateNSString( const rtl::OUString& rStr ) 1264 { 1265 return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()]; 1266 } 1267 1268 CGImageRef CreateCGImage( const Image& rImage ) 1269 { 1270 BitmapEx aBmpEx( rImage.GetBitmapEx() ); 1271 Bitmap aBmp( aBmpEx.GetBitmap() ); 1272 1273 if( ! aBmp || ! aBmp.ImplGetImpBitmap() ) 1274 return NULL; 1275 1276 // simple case, no transparency 1277 AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap()); 1278 1279 if( ! pSalBmp ) 1280 return NULL; 1281 1282 CGImageRef xImage = NULL; 1283 if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) ) 1284 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1285 else if( aBmpEx.IsAlpha() ) 1286 { 1287 AlphaMask aAlphaMask( aBmpEx.GetAlpha() ); 1288 Bitmap aMask( aAlphaMask.GetBitmap() ); 1289 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap()); 1290 if( pMaskBmp ) 1291 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1292 else 1293 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1294 } 1295 else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP ) 1296 { 1297 Bitmap aMask( aBmpEx.GetMask() ); 1298 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap()); 1299 if( pMaskBmp ) 1300 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1301 else 1302 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1303 } 1304 else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR ) 1305 { 1306 Color aTransColor( aBmpEx.GetTransparentColor() ); 1307 SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() ); 1308 xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor ); 1309 } 1310 1311 return xImage; 1312 } 1313 1314 NSImage* CreateNSImage( const Image& rImage ) 1315 { 1316 CGImageRef xImage = CreateCGImage( rImage ); 1317 1318 if( ! xImage ) 1319 return nil; 1320 1321 Size aSize( rImage.GetSizePixel() ); 1322 NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )]; 1323 if( pImage ) 1324 { 1325 [pImage setFlipped: YES]; 1326 [pImage lockFocus]; 1327 1328 NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; 1329 CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]); 1330 1331 const CGRect aDstRect = CGRectMake( 0, 0, aSize.Width(), aSize.Height()); 1332 CGContextDrawImage( rCGContext, aDstRect, xImage ); 1333 1334 [pImage unlockFocus]; 1335 } 1336 1337 CGImageRelease( xImage ); 1338 1339 return pImage; 1340 } 1341