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 200 ms
789 osl_resetCondition( maWaitingYieldCond );
790 TimeValue aVal = { 0, 200000000 };
791 sal_uLong nCount = ReleaseYieldMutex();
792 osl_waitCondition( maWaitingYieldCond, &aVal );
793 AcquireYieldMutex( nCount );
794 }
795
796 // we get some apple events way too early
797 // before the application is ready to handle them,
798 // so their corresponding application events need to be delayed
799 // now is a good time to handle at least one of them
800 if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute )
801 {
802 // make sure that only one application event is active at a time
803 static bool bInAppEvent = false;
804 if( !bInAppEvent )
805 {
806 bInAppEvent = true;
807 // get the next delayed application event
808 const ApplicationEvent* pAppEvent = aAppEventList.front();
809 aAppEventList.pop_front();
810 // handle one application event (no recursion)
811 const ImplSVData* pSVData = ImplGetSVData();
812 pSVData->mpApp->AppEvent( *pAppEvent );
813 delete pAppEvent;
814 // allow the next delayed application event
815 bInAppEvent = false;
816 }
817 }
818 }
819
820 // -----------------------------------------------------------------------
821
AnyInput(sal_uInt16 nType)822 bool AquaSalInstance::AnyInput( sal_uInt16 nType )
823 {
824 if( nType & INPUT_APPEVENT )
825 {
826 if( ! aAppEventList.empty() )
827 return true;
828 if( nType == INPUT_APPEVENT )
829 return false;
830 }
831
832 if( nType & INPUT_TIMER )
833 {
834 if( AquaSalTimer::pRunningTimer )
835 {
836 NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate];
837 if( pDt && [pDt timeIntervalSinceNow] < 0 )
838 {
839 return true;
840 }
841 }
842 }
843
844 unsigned/*NSUInteger*/ nEventMask = 0;
845 if( nType & INPUT_MOUSE)
846 nEventMask |=
847 NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask |
848 NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask |
849 NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask |
850 NSScrollWheelMask |
851 // NSMouseMovedMask |
852 NSMouseEnteredMask | NSMouseExitedMask;
853 if( nType & INPUT_KEYBOARD)
854 nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask;
855 if( nType & INPUT_OTHER)
856 nEventMask |= NSTabletPoint;
857 // TODO: INPUT_PAINT / more INPUT_OTHER
858 if( !nType)
859 return false;
860
861 NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil
862 inMode: NSDefaultRunLoopMode dequeue: NO];
863 return (pEvent != NULL);
864 }
865
866 // -----------------------------------------------------------------------
867
CreateChildFrame(SystemParentData *,sal_uLong)868 SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, sal_uLong /*nSalFrameStyle*/ )
869 {
870 return NULL;
871 }
872
873 // -----------------------------------------------------------------------
874
CreateFrame(SalFrame * pParent,sal_uLong nSalFrameStyle)875 SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle )
876 {
877 SalData::ensureThreadAutoreleasePool();
878
879 SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle );
880 return pFrame;
881 }
882
883 // -----------------------------------------------------------------------
884
DestroyFrame(SalFrame * pFrame)885 void AquaSalInstance::DestroyFrame( SalFrame* pFrame )
886 {
887 delete pFrame;
888 }
889
890 // -----------------------------------------------------------------------
891
CreateObject(SalFrame * pParent,SystemWindowData *,sal_Bool)892 SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, sal_Bool /* bShow */ )
893 {
894 // SystemWindowData is meaningless on Mac OS X
895 AquaSalObject *pObject = NULL;
896
897 if ( pParent )
898 pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) );
899
900 return pObject;
901 }
902
903 // -----------------------------------------------------------------------
904
DestroyObject(SalObject * pObject)905 void AquaSalInstance::DestroyObject( SalObject* pObject )
906 {
907 delete ( pObject );
908 }
909
910 // -----------------------------------------------------------------------
911
CreatePrinter(SalInfoPrinter * pInfoPrinter)912 SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
913 {
914 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) );
915 }
916
917 // -----------------------------------------------------------------------
918
DestroyPrinter(SalPrinter * pPrinter)919 void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter )
920 {
921 delete pPrinter;
922 }
923
924 // -----------------------------------------------------------------------
925
GetPrinterQueueInfo(ImplPrnQueueList * pList)926 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
927 {
928 NSArray* pNames = [NSPrinter printerNames];
929 NSArray* pTypes = [NSPrinter printerTypes];
930 unsigned int nNameCount = pNames ? [pNames count] : 0;
931 unsigned int nTypeCount = pTypes ? [pTypes count] : 0;
932 DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" );
933 for( unsigned int i = 0; i < nNameCount; i++ )
934 {
935 NSString* pName = [pNames objectAtIndex: i];
936 NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil;
937 if( pName )
938 {
939 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
940 pInfo->maPrinterName = GetOUString( pName );
941 if( pType )
942 pInfo->maDriver = GetOUString( pType );
943 pInfo->mnStatus = 0;
944 pInfo->mnJobs = 0;
945 pInfo->mpSysData = NULL;
946
947 pList->Add( pInfo );
948 }
949 }
950 }
951
952 // -----------------------------------------------------------------------
953
GetPrinterQueueState(SalPrinterQueueInfo *)954 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
955 {
956 }
957
958 // -----------------------------------------------------------------------
959
DeletePrinterQueueInfo(SalPrinterQueueInfo * pInfo)960 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
961 {
962 delete pInfo;
963 }
964
965 // -----------------------------------------------------------------------
966
GetDefaultPrinter()967 XubString AquaSalInstance::GetDefaultPrinter()
968 {
969 // #i113170# may not be the main thread if called from UNO API
970 SalData::ensureThreadAutoreleasePool();
971
972 if( ! maDefaultPrinter.getLength() )
973 {
974 NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo];
975 DBG_ASSERT( pPI, "no print info" );
976 if( pPI )
977 {
978 NSPrinter* pPr = [pPI printer];
979 DBG_ASSERT( pPr, "no printer in default info" );
980 if( pPr )
981 {
982 NSString* pDefName = [pPr name];
983 DBG_ASSERT( pDefName, "printer has no name" );
984 maDefaultPrinter = GetOUString( pDefName );
985 }
986 }
987 }
988 return maDefaultPrinter;
989 }
990
991 // -----------------------------------------------------------------------
992
CreateInfoPrinter(SalPrinterQueueInfo * pQueueInfo,ImplJobSetup * pSetupData)993 SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
994 ImplJobSetup* pSetupData )
995 {
996 // #i113170# may not be the main thread if called from UNO API
997 SalData::ensureThreadAutoreleasePool();
998
999 SalInfoPrinter* pNewInfoPrinter = NULL;
1000 if( pQueueInfo )
1001 {
1002 pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo );
1003 if( pSetupData )
1004 pNewInfoPrinter->SetPrinterData( pSetupData );
1005 }
1006
1007 return pNewInfoPrinter;
1008 }
1009
1010 // -----------------------------------------------------------------------
1011
DestroyInfoPrinter(SalInfoPrinter * pPrinter)1012 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
1013 {
1014 // #i113170# may not be the main thread if called from UNO API
1015 SalData::ensureThreadAutoreleasePool();
1016
1017 delete pPrinter;
1018 }
1019
1020 // -----------------------------------------------------------------------
1021
CreateSystem()1022 SalSystem* AquaSalInstance::CreateSystem()
1023 {
1024 return new AquaSalSystem();
1025 }
1026
1027 // -----------------------------------------------------------------------
1028
DestroySystem(SalSystem * pSystem)1029 void AquaSalInstance::DestroySystem( SalSystem* pSystem )
1030 {
1031 delete pSystem;
1032 }
1033
1034 // -----------------------------------------------------------------------
1035
SetEventCallback(void *,bool (*)(void *,void *,int))1036 void AquaSalInstance::SetEventCallback( void*, bool(*)(void*,void*,int) )
1037 {
1038 }
1039
1040 // -----------------------------------------------------------------------
1041
SetErrorEventCallback(void *,bool (*)(void *,void *,int))1042 void AquaSalInstance::SetErrorEventCallback( void*, bool(*)(void*,void*,int) )
1043 {
1044 }
1045
1046 // -----------------------------------------------------------------------
1047
GetConnectionIdentifier(ConnectionIdentifierType & rReturnedType,int & rReturnedBytes)1048 void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
1049 {
1050 rReturnedBytes = 1;
1051 rReturnedType = AsciiCString;
1052 return (void*)"";
1053 }
1054
1055 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts
1056 // to UTF-8 before encoding non ascii characters, which is not what other apps expect.
translateToExternalUrl(const rtl::OUString & internalUrl)1057 static rtl::OUString translateToExternalUrl(const rtl::OUString& internalUrl)
1058 {
1059 rtl::OUString extUrl;
1060
1061 uno::Reference< lang::XMultiServiceFactory > sm = comphelper::getProcessServiceFactory();
1062 if (sm.is())
1063 {
1064 uno::Reference< beans::XPropertySet > pset;
1065 sm->queryInterface( getCppuType( &pset )) >>= pset;
1066 if (pset.is())
1067 {
1068 uno::Reference< uno::XComponentContext > context;
1069 static const rtl::OUString DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) );
1070 pset->getPropertyValue(DEFAULT_CONTEXT) >>= context;
1071 if (context.is())
1072 extUrl = uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl);
1073 }
1074 }
1075 return extUrl;
1076 }
1077
1078 // #i104525# many versions of OSX have problems with some URLs:
1079 // when an app requests OSX to add one of these URLs to the "Recent Items" list
1080 // then this app gets killed (TextEdit, Preview, etc. and also OOo)
isDangerousUrl(const rtl::OUString & rUrl)1081 static bool isDangerousUrl( const rtl::OUString& rUrl )
1082 {
1083 // use a heuristic that detects all known cases since there is no official comment
1084 // on the exact impact and root cause of the OSX bug
1085 const int nLen = rUrl.getLength();
1086 const sal_Unicode* p = rUrl.getStr();
1087 for( int i = 0; i < nLen-3; ++i, ++p ) {
1088 if( p[0] != '%' )
1089 continue;
1090 // escaped percent?
1091 if( (p[1] == '2') && (p[2] == '5') )
1092 return true;
1093 // escapes are considered to be UTF-8 encoded
1094 // => check for invalid UTF-8 leading byte
1095 if( (p[1] != 'f') && (p[1] != 'F') )
1096 continue;
1097 int cLowNibble = p[2];
1098 if( (cLowNibble >= '0' ) && (cLowNibble <= '9'))
1099 return false;
1100 if( cLowNibble >= 'a' )
1101 cLowNibble -= 'a' - 'A';
1102 if( (cLowNibble < 'A') || (cLowNibble >= 'C'))
1103 return true;
1104 }
1105
1106 return false;
1107 }
1108
AddToRecentDocumentList(const rtl::OUString & rFileUrl,const rtl::OUString &)1109 void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/)
1110 {
1111 // Convert file URL for external use (see above)
1112 rtl::OUString externalUrl = translateToExternalUrl(rFileUrl);
1113 if( 0 == externalUrl.getLength() )
1114 externalUrl = rFileUrl;
1115
1116 if( externalUrl.getLength() && !isDangerousUrl( externalUrl ) )
1117 {
1118 NSString* pString = CreateNSString( externalUrl );
1119 NSURL* pURL = [NSURL URLWithString: pString];
1120
1121 if( pURL )
1122 {
1123 NSDocumentController* pCtrl = [NSDocumentController sharedDocumentController];
1124 [pCtrl noteNewRecentDocumentURL: pURL];
1125 }
1126 if( pString )
1127 [pString release];
1128 }
1129 }
1130
1131
1132 // -----------------------------------------------------------------------
1133
CreateSalTimer()1134 SalTimer* AquaSalInstance::CreateSalTimer()
1135 {
1136 return new AquaSalTimer();
1137 }
1138
1139 // -----------------------------------------------------------------------
1140
CreateSalSystem()1141 SalSystem* AquaSalInstance::CreateSalSystem()
1142 {
1143 return new AquaSalSystem();
1144 }
1145
1146 // -----------------------------------------------------------------------
1147
CreateSalBitmap()1148 SalBitmap* AquaSalInstance::CreateSalBitmap()
1149 {
1150 return new AquaSalBitmap();
1151 }
1152
1153 // -----------------------------------------------------------------------
1154
CreateSalSession()1155 SalSession* AquaSalInstance::CreateSalSession()
1156 {
1157 return NULL;
1158 }
1159
1160 // -----------------------------------------------------------------------
1161
1162 class MacImeStatus : public SalI18NImeStatus
1163 {
1164 public:
MacImeStatus()1165 MacImeStatus() {}
~MacImeStatus()1166 virtual ~MacImeStatus() {}
1167
1168 // asks whether there is a status window available
1169 // to toggle into menubar
canToggle()1170 virtual bool canToggle() { return false; }
toggle()1171 virtual void toggle() {}
1172 };
1173
1174 // -----------------------------------------------------------------------
1175
CreateI18NImeStatus()1176 SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus()
1177 {
1178 return new MacImeStatus();
1179 }
1180
1181 // YieldMutexReleaser
YieldMutexReleaser()1182 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
1183 {
1184 SalData* pSalData = GetSalData();
1185 if( ! pSalData->mpFirstInstance->isNSAppThread() )
1186 {
1187 SalData::ensureThreadAutoreleasePool();
1188 mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex();
1189 }
1190 }
1191
~YieldMutexReleaser()1192 YieldMutexReleaser::~YieldMutexReleaser()
1193 {
1194 if( mnCount != 0 )
1195 GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount );
1196 }
1197
1198 //////////////////////////////////////////////////////////////
GetOUString(CFStringRef rStr)1199 rtl::OUString GetOUString( CFStringRef rStr )
1200 {
1201 if( rStr == 0 )
1202 return rtl::OUString();
1203 CFIndex nLength = CFStringGetLength( rStr );
1204 if( nLength == 0 )
1205 return rtl::OUString();
1206 const UniChar* pConstStr = CFStringGetCharactersPtr( rStr );
1207 if( pConstStr )
1208 return rtl::OUString( pConstStr, nLength );
1209 UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) );
1210 CFRange aRange = { 0, nLength };
1211 CFStringGetCharacters( rStr, aRange, pStr );
1212 rtl::OUString aRet( pStr, nLength );
1213 rtl_freeMemory( pStr );
1214 return aRet;
1215 }
1216
GetOUString(NSString * pStr)1217 rtl::OUString GetOUString( NSString* pStr )
1218 {
1219 if( ! pStr )
1220 return rtl::OUString();
1221 int nLen = [pStr length];
1222 if( nLen == 0 )
1223 return rtl::OUString();
1224
1225 rtl::OUStringBuffer aBuf( nLen+1 );
1226 aBuf.setLength( nLen );
1227 [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())];
1228 return aBuf.makeStringAndClear();
1229 }
1230
CreateCFString(const rtl::OUString & rStr)1231 CFStringRef CreateCFString( const rtl::OUString& rStr )
1232 {
1233 return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() );
1234 }
1235
CreateNSString(const rtl::OUString & rStr)1236 NSString* CreateNSString( const rtl::OUString& rStr )
1237 {
1238 return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()];
1239 }
1240
CreateCGImage(const Image & rImage)1241 CGImageRef CreateCGImage( const Image& rImage )
1242 {
1243 BitmapEx aBmpEx( rImage.GetBitmapEx() );
1244 Bitmap aBmp( aBmpEx.GetBitmap() );
1245
1246 if( ! aBmp || ! aBmp.ImplGetImpBitmap() )
1247 return NULL;
1248
1249 // simple case, no transparency
1250 AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap());
1251
1252 if( ! pSalBmp )
1253 return NULL;
1254
1255 CGImageRef xImage = NULL;
1256 if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) )
1257 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1258 else if( aBmpEx.IsAlpha() )
1259 {
1260 AlphaMask aAlphaMask( aBmpEx.GetAlpha() );
1261 Bitmap aMask( aAlphaMask.GetBitmap() );
1262 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
1263 if( pMaskBmp )
1264 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1265 else
1266 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1267 }
1268 else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP )
1269 {
1270 Bitmap aMask( aBmpEx.GetMask() );
1271 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
1272 if( pMaskBmp )
1273 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1274 else
1275 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1276 }
1277 else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR )
1278 {
1279 Color aTransColor( aBmpEx.GetTransparentColor() );
1280 SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() );
1281 xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor );
1282 }
1283
1284 return xImage;
1285 }
1286
CreateNSImage(const Image & rImage)1287 NSImage* CreateNSImage( const Image& rImage )
1288 {
1289 CGImageRef xImage = CreateCGImage( rImage );
1290
1291 if( ! xImage )
1292 return nil;
1293
1294 Size aSize( rImage.GetSizePixel() );
1295 NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )];
1296 if( pImage )
1297 {
1298 [pImage setFlipped: YES];
1299 [pImage lockFocus];
1300
1301 NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
1302 CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
1303
1304 const CGRect aDstRect = CGRectMake( 0, 0, aSize.Width(), aSize.Height());
1305 CGContextDrawImage( rCGContext, aDstRect, xImage );
1306
1307 [pImage unlockFocus];
1308 }
1309
1310 CGImageRelease( xImage );
1311
1312 return pImage;
1313 }
1314