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