xref: /aoo41x/main/vcl/aqua/source/app/salinst.cxx (revision 2dae3561)
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     OSErr err = noErr;
182     SInt32 systemVersion = VER_TIGER; // Initialize with minimal requirement
183     if( (err = Gestalt(gestaltSystemVersion, &systemVersion)) == noErr )
184     {
185         GetSalData()->mnSystemVersion = systemVersion;
186 #if OSL_DEBUG_LEVEL > 1
187         fprintf( stderr, "System Version %x\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