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