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