update dev300-m58
[ooovba.git] / vcl / aqua / source / app / salinst.cxx
blob82fb005085dbfc9b689631ed28919e4afb4115b8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salinst.cxx,v $
10 * $Revision: 1.53.22.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include <stdio.h>
36 #include "tools/fsys.hxx"
37 #include "tools/getprocessworkingdir.hxx"
38 #include "osl/process.h"
39 #include "rtl/ustrbuf.hxx"
40 #include "vcl/svapp.hxx"
41 #include "vcl/print.h"
42 #include "vcl/salimestatus.hxx"
43 #include "vcl/window.hxx"
44 #include "vcl/timer.hxx"
45 #include "vcl/impbmp.hxx"
47 #include "saldata.hxx"
48 #include "salinst.h"
49 #include "salframe.h"
50 #include "salobj.h"
51 #include "salsys.h"
52 #include "salvd.h"
53 #include "salbmp.h"
54 #include "salprn.h"
55 #include "saltimer.h"
56 #include "vclnsapp.h"
58 #include "premac.h"
59 #include <Foundation/Foundation.h>
60 #include <ApplicationServices/ApplicationServices.h>
61 #import "apple_remote/RemoteMainController.h"
62 #include "apple_remote/RemoteControl.h"
63 #include "postmac.h"
66 using namespace std;
68 extern BOOL ImplSVMain();
70 static BOOL* gpbInit = 0;
71 static NSMenu* pDockMenu = nil;
72 static bool bNoSVMain = true;
73 static bool bLeftMain = false;
74 // -----------------------------------------------------------------------
76 class AquaDelayedSettingsChanged : public Timer
78 bool mbInvalidate;
79 public:
80 AquaDelayedSettingsChanged( bool bInvalidate ) :
81 mbInvalidate( bInvalidate )
85 virtual void Timeout()
87 SalData* pSalData = GetSalData();
88 if( ! pSalData->maFrames.empty() )
89 pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
91 if( mbInvalidate )
93 for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
94 it != pSalData->maFrames.end(); ++it )
96 if( (*it)->mbShown )
97 (*it)->SendPaintEvent( NULL );
100 Stop();
101 delete this;
105 void AquaSalInstance::delayedSettingsChanged( bool bInvalidate )
107 vos::OGuard aGuard( *mpSalYieldMutex );
108 AquaDelayedSettingsChanged* pTimer = new AquaDelayedSettingsChanged( bInvalidate );
109 pTimer->SetTimeout( 50 );
110 pTimer->Start();
114 // the AppEventList must be available before any SalData/SalInst/etc. objects are ready
115 typedef std::list<const ApplicationEvent*> AppEventList;
116 AppEventList AquaSalInstance::aAppEventList;
118 NSMenu* AquaSalInstance::GetDynamicDockMenu()
120 if( ! pDockMenu && ! bLeftMain )
121 pDockMenu = [[NSMenu alloc] initWithTitle: @""];
122 return pDockMenu;
125 bool AquaSalInstance::isOnCommandLine( const rtl::OUString& rArg )
127 sal_uInt32 nArgs = osl_getCommandArgCount();
128 for( sal_uInt32 i = 0; i < nArgs; i++ )
130 rtl::OUString aArg;
131 osl_getCommandArg( i, &aArg.pData );
132 if( aArg.equals( rArg ) )
133 return true;
135 return false;
139 // initialize the cocoa VCL_NSApplication object
140 // returns an NSAutoreleasePool that must be released when the event loop begins
141 static void initNSApp()
143 // create our cocoa NSApplication
144 [VCL_NSApplication sharedApplication];
146 SalData::ensureThreadAutoreleasePool();
148 // put cocoa into multithreaded mode
149 [NSThread detachNewThreadSelector:@selector(enableCocoaThreads:) toTarget:[[CocoaThreadEnabler alloc] init] withObject:nil];
151 // activate our delegate methods
152 [NSApp setDelegate: NSApp];
154 [[NSNotificationCenter defaultCenter] addObserver: NSApp
155 selector: @selector(systemColorsChanged:)
156 name: NSSystemColorsDidChangeNotification
157 object: nil ];
158 [[NSNotificationCenter defaultCenter] addObserver: NSApp
159 selector: @selector(screenParametersChanged:)
160 name: NSApplicationDidChangeScreenParametersNotification
161 object: nil ];
162 // add observers for some settings changes that affect vcl's settings
163 // scrollbar variant
164 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
165 selector: @selector(scrollbarVariantChanged:)
166 name: @"AppleAquaScrollBarVariantChanged"
167 object: nil ];
168 // scrollbar page behavior ("jump to here" or not)
169 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
170 selector: @selector(scrollbarSettingsChanged:)
171 name: @"AppleNoRedisplayAppearancePreferenceChanged"
172 object: nil ];
174 // get System Version and store the value in GetSalData()->mnSystemVersion
175 OSErr err = noErr;
176 SInt32 systemVersion = VER_TIGER; // Initialize with minimal requirement
177 if( (err = Gestalt(gestaltSystemVersion, &systemVersion)) == noErr )
179 GetSalData()->mnSystemVersion = systemVersion;
180 #if OSL_DEBUG_LEVEL > 1
181 fprintf( stderr, "System Version %x\n", (unsigned int)systemVersion);
182 #endif
184 else
185 NSLog(@"Unable to obtain system version: %ld", (long)err);
187 // Initialize Apple Remote
188 GetSalData()->mpMainController = [[MainController alloc] init];
190 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
191 selector: @selector(applicationWillBecomeActive:)
192 name: @"AppleRemoteWillBecomeActive"
193 object: nil ];
195 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
196 selector: @selector(applicationWillResignActive:)
197 name: @"AppleRemoteWillResignActive"
198 object: nil ];
200 if( ImplGetSVData()->mbIsTestTool )
201 [NSApp activateIgnoringOtherApps: YES];
204 BOOL ImplSVMainHook( BOOL * pbInit )
206 gpbInit = pbInit;
208 bNoSVMain = false;
209 initNSApp();
211 NSPoint aPt = { 0, 0 };
212 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
213 location: aPt
214 modifierFlags: 0
215 timestamp: 0
216 windowNumber: 0
217 context: nil
218 subtype: AquaSalInstance::AppExecuteSVMain
219 data1: 0
220 data2: 0 ];
221 if( pEvent )
223 [NSApp postEvent: pEvent atStart: NO];
225 rtl::OUString aExeURL, aExe;
226 osl_getExecutableFile( &aExeURL.pData );
227 osl_getSystemPathFromFileURL( aExeURL.pData, &aExe.pData );
228 rtl::OString aByteExe( rtl::OUStringToOString( aExe, osl_getThreadTextEncoding() ) );
230 #ifdef DEBUG
231 aByteExe += OString ( " NSAccessibilityDebugLogLevel 1" );
232 const char* pArgv[] = { aByteExe.getStr(), NULL };
233 NSApplicationMain( 3, pArgv );
234 #else
235 const char* pArgv[] = { aByteExe.getStr(), NULL };
236 NSApplicationMain( 1, pArgv );
237 #endif
239 else
241 DBG_ERROR( "NSApplication initialization could not be done" );
244 return TRUE; // indicate that ImplSVMainHook is implemented
247 // =======================================================================
249 void SalAbort( const XubString& rErrorText )
251 if( !rErrorText.Len() )
252 fprintf( stderr, "Application Error " );
253 else
254 fprintf( stderr, "%s ",
255 ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
256 abort();
259 // -----------------------------------------------------------------------
261 void InitSalData()
263 SalData *pSalData = new SalData;
264 SetSalData( pSalData );
267 // -----------------------------------------------------------------------
269 const ::rtl::OUString& SalGetDesktopEnvironment()
271 static OUString aDesktopEnvironment(RTL_CONSTASCII_USTRINGPARAM( "MacOSX" ));
272 return aDesktopEnvironment;
275 // -----------------------------------------------------------------------
277 void DeInitSalData()
279 SalData *pSalData = GetSalData();
280 if( pSalData->mpStatusItem )
282 [pSalData->mpStatusItem release];
283 pSalData->mpStatusItem = nil;
285 delete pSalData;
286 SetSalData( NULL );
289 // -----------------------------------------------------------------------
291 extern "C" {
292 #include <crt_externs.h>
295 // -----------------------------------------------------------------------
297 void InitSalMain()
299 rtl::OUString urlWorkDir;
300 rtl_uString *sysWorkDir = NULL;
301 if (tools::getProcessWorkingDir(&urlWorkDir))
303 oslFileError err2 = osl_getSystemPathFromFileURL(urlWorkDir.pData, &sysWorkDir);
304 if (err2 == osl_File_E_None)
306 ByteString aPath( getenv( "PATH" ) );
307 ByteString aResPath( getenv( "STAR_RESOURCEPATH" ) );
308 ByteString aLibPath( getenv( "DYLD_LIBRARY_PATH" ) );
309 ByteString aCmdPath( OUStringToOString(OUString(sysWorkDir), RTL_TEXTENCODING_UTF8).getStr() );
310 ByteString aTmpPath;
311 // Get absolute path of command's directory
312 if ( aCmdPath.Len() ) {
313 DirEntry aCmdDirEntry( aCmdPath );
314 aCmdDirEntry.ToAbs();
315 aCmdPath = ByteString( aCmdDirEntry.GetPath().GetFull(), RTL_TEXTENCODING_ASCII_US );
317 // Assign to PATH environment variable
318 if ( aCmdPath.Len() )
320 aTmpPath = ByteString( "PATH=" );
321 aTmpPath += aCmdPath;
322 if ( aPath.Len() )
323 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
324 aTmpPath += aPath;
325 putenv( (char*)aTmpPath.GetBuffer() );
327 // Assign to STAR_RESOURCEPATH environment variable
328 if ( aCmdPath.Len() )
330 aTmpPath = ByteString( "STAR_RESOURCEPATH=" );
331 aTmpPath += aCmdPath;
332 if ( aResPath.Len() )
333 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
334 aTmpPath += aResPath;
335 putenv( (char*)aTmpPath.GetBuffer() );
337 // Assign to DYLD_LIBRARY_PATH environment variable
338 if ( aCmdPath.Len() )
340 aTmpPath = ByteString( "DYLD_LIBRARY_PATH=" );
341 aTmpPath += aCmdPath;
342 if ( aLibPath.Len() )
343 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
344 aTmpPath += aLibPath;
345 putenv( (char*)aTmpPath.GetBuffer() );
351 // -----------------------------------------------------------------------
353 void DeInitSalMain()
357 // =======================================================================
359 SalYieldMutex::SalYieldMutex()
361 mnCount = 0;
362 mnThreadId = 0;
365 void SalYieldMutex::acquire()
367 OMutex::acquire();
368 mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
369 mnCount++;
372 void SalYieldMutex::release()
374 if ( mnThreadId == NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
376 if ( mnCount == 1 )
377 mnThreadId = 0;
378 mnCount--;
380 OMutex::release();
383 sal_Bool SalYieldMutex::tryToAcquire()
385 if ( OMutex::tryToAcquire() )
387 mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
388 mnCount++;
389 return sal_True;
391 else
392 return sal_False;
395 // -----------------------------------------------------------------------
397 // some convenience functions regarding the yield mutex, aka solar mutex
399 BOOL ImplSalYieldMutexTryToAcquire()
401 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
402 if ( pInst )
403 return pInst->mpSalYieldMutex->tryToAcquire();
404 else
405 return FALSE;
408 void ImplSalYieldMutexAcquire()
410 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
411 if ( pInst )
412 pInst->mpSalYieldMutex->acquire();
415 void ImplSalYieldMutexRelease()
417 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
418 if ( pInst )
419 pInst->mpSalYieldMutex->release();
422 // =======================================================================
424 SalInstance* CreateSalInstance()
426 // this is the case for not using SVMain
427 // not so good
428 if( bNoSVMain )
429 initNSApp();
431 SalData* pSalData = GetSalData();
432 DBG_ASSERT( pSalData->mpFirstInstance == NULL, "more than one instance created" );
433 AquaSalInstance* pInst = new AquaSalInstance;
435 // init instance (only one instance in this version !!!)
436 pSalData->mpFirstInstance = pInst;
437 // this one is for outside AquaSalInstance::Yield
438 SalData::ensureThreadAutoreleasePool();
439 // no focus rects on NWF aqua
440 ImplGetSVData()->maNWFData.mbNoFocusRects = true;
441 ImplGetSVData()->maNWFData.mbNoBoldTabFocus = true;
442 ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise = true;
443 ImplGetSVData()->maNWFData.mbCenteredTabs = true;
444 ImplGetSVData()->maNWFData.mbProgressNeedsErase = true;
445 ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase = true;
446 ImplGetSVData()->maGDIData.mbPrinterPullModel = true;
447 ImplGetSVData()->maGDIData.mbNoXORClipping = true;
448 ImplGetSVData()->maWinData.mbNoSaveBackground = true;
450 return pInst;
453 // -----------------------------------------------------------------------
455 void DestroySalInstance( SalInstance* pInst )
457 delete pInst;
460 // -----------------------------------------------------------------------
462 AquaSalInstance::AquaSalInstance()
464 mpSalYieldMutex = new SalYieldMutex;
465 mpSalYieldMutex->acquire();
466 maMainThread = vos::OThread::getCurrentIdentifier();
467 mbWaitingYield = false;
468 maUserEventListMutex = osl_createMutex();
469 mnActivePrintJobs = 0;
472 // -----------------------------------------------------------------------
474 AquaSalInstance::~AquaSalInstance()
476 mpSalYieldMutex->release();
477 delete mpSalYieldMutex;
478 osl_destroyMutex( maUserEventListMutex );
481 // -----------------------------------------------------------------------
483 void AquaSalInstance::wakeupYield()
485 // wakeup :Yield
486 if( mbWaitingYield )
488 SalData::ensureThreadAutoreleasePool();
489 NSPoint aPt = { 0, 0 };
490 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
491 location: aPt
492 modifierFlags: 0
493 timestamp: 0
494 windowNumber: 0
495 context: nil
496 subtype: AquaSalInstance::YieldWakeupEvent
497 data1: 0
498 data2: 0 ];
499 if( pEvent )
500 [NSApp postEvent: pEvent atStart: NO];
504 // -----------------------------------------------------------------------
506 void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, USHORT nType, void* pData )
508 osl_acquireMutex( maUserEventListMutex );
509 maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) );
510 osl_releaseMutex( maUserEventListMutex );
512 // notify main loop that an event has arrived
513 wakeupYield();
516 // -----------------------------------------------------------------------
518 vos::IMutex* AquaSalInstance::GetYieldMutex()
520 return mpSalYieldMutex;
523 // -----------------------------------------------------------------------
525 ULONG AquaSalInstance::ReleaseYieldMutex()
527 SalYieldMutex* pYieldMutex = mpSalYieldMutex;
528 if ( pYieldMutex->GetThreadId() ==
529 NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
531 ULONG nCount = pYieldMutex->GetAcquireCount();
532 ULONG n = nCount;
533 while ( n )
535 pYieldMutex->release();
536 n--;
539 return nCount;
541 else
542 return 0;
545 // -----------------------------------------------------------------------
547 void AquaSalInstance::AcquireYieldMutex( ULONG nCount )
549 SalYieldMutex* pYieldMutex = mpSalYieldMutex;
550 while ( nCount )
552 pYieldMutex->acquire();
553 nCount--;
557 // -----------------------------------------------------------------------
559 bool AquaSalInstance::isNSAppThread() const
561 return vos::OThread::getCurrentIdentifier() == maMainThread;
564 // -----------------------------------------------------------------------
566 void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent )
568 switch( [pEvent subtype] )
570 case AppStartTimerEvent:
571 AquaSalTimer::handleStartTimerEvent( pEvent );
572 break;
573 case AppEndLoopEvent:
574 [NSApp stop: NSApp];
575 break;
576 case AppExecuteSVMain:
578 BOOL bResult = ImplSVMain();
579 if( gpbInit )
580 *gpbInit = bResult;
581 [NSApp stop: NSApp];
582 bLeftMain = true;
583 if( pDockMenu )
585 [pDockMenu release];
586 pDockMenu = nil;
589 break;
590 case AppleRemoteEvent:
592 sal_Int16 nCommand = 0;
593 SalData* pSalData = GetSalData();
594 bool bIsFullScreenMode = false;
596 std::list<AquaSalFrame*>::iterator it = pSalData->maFrames.begin();
597 while( (*it) && ( (it != pSalData->maFrames.end() ) || ( (*it)->mbFullScreen == false ) ) )
599 if ( ((*it)->mbFullScreen == true) )
600 bIsFullScreenMode = true;
601 it++;
604 switch ([pEvent data1])
606 case kRemoteButtonPlay:
607 nCommand = ( bIsFullScreenMode == true ) ? MEDIA_COMMAND_PLAY_PAUSE : MEDIA_COMMAND_PLAY;
608 break;
610 // kept for experimentation purpose (scheduled for future implementation)
611 // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break;
613 case kRemoteButtonPlus: nCommand = MEDIA_COMMAND_VOLUME_UP; break;
615 case kRemoteButtonMinus: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break;
617 case kRemoteButtonRight: nCommand = MEDIA_COMMAND_NEXTTRACK; break;
619 case kRemoteButtonRight_Hold: nCommand = MEDIA_COMMAND_NEXTTRACK_HOLD; break;
621 case kRemoteButtonLeft: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break;
623 case kRemoteButtonLeft_Hold: nCommand = MEDIA_COMMAND_REWIND; break;
625 case kRemoteButtonPlay_Hold: nCommand = MEDIA_COMMAND_PLAY_HOLD; break;
627 case kRemoteButtonMenu_Hold: nCommand = MEDIA_COMMAND_STOP; break;
629 // FIXME : not detected
630 case kRemoteButtonPlus_Hold:
631 case kRemoteButtonMinus_Hold:
632 break;
634 default:
635 break;
637 AquaSalFrame* pFrame = pSalData->maFrames.front();
638 Window * pWindow = pFrame->GetWindow() ? pSalData->maFrames.front()->GetWindow() : NULL;
640 if( pWindow )
642 const Point aPoint;
643 CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand );
644 NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
646 if ( !ImplCallPreNotify( aNCmdEvt ) )
647 pWindow->Command( aCEvt );
651 break;
653 case YieldWakeupEvent:
654 // do nothing, fall out of Yield
655 break;
657 default:
658 DBG_ERROR( "unhandled NSApplicationDefined event" );
659 break;
663 // -----------------------------------------------------------------------
665 class ReleasePoolHolder
667 NSAutoreleasePool* mpPool;
668 public:
669 ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {}
670 ~ReleasePoolHolder() { [mpPool release]; }
673 void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
675 // ensure that the per thread autorelease pool is top level and
676 // will therefore not be destroyed by cocoa implicitly
677 SalData::ensureThreadAutoreleasePool();
679 // NSAutoreleasePool documentation suggests we should have
680 // an own pool for each yield level
681 ReleasePoolHolder aReleasePool;
683 // Release all locks so that we don't deadlock when we pull pending
684 // events from the event queue
685 bool bDispatchUser = true;
686 while( bDispatchUser )
688 ULONG nCount = ReleaseYieldMutex();
690 // get one user event
691 osl_acquireMutex( maUserEventListMutex );
692 SalUserEvent aEvent( NULL, NULL, 0 );
693 if( ! maUserEvents.empty() )
695 aEvent = maUserEvents.front();
696 maUserEvents.pop_front();
698 else
699 bDispatchUser = false;
700 osl_releaseMutex( maUserEventListMutex );
702 AcquireYieldMutex( nCount );
704 // dispatch it
705 if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) )
707 aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData );
708 // return if only one event is asked for
709 if( ! bHandleAllCurrentEvents )
710 return;
714 // handle cocoa event queue
715 // cocoa events mye be only handled in the thread the NSApp was created
716 if( isNSAppThread() && mnActivePrintJobs == 0 )
718 // we need to be woken up by a cocoa-event
719 // if a user event should be posted by the event handling below
720 bool bOldWaitingYield = mbWaitingYield;
721 mbWaitingYield = bWait;
723 // handle available events
724 NSEvent* pEvent = nil;
725 bool bHadEvent = false;
728 ULONG nCount = ReleaseYieldMutex();
730 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil
731 inMode: NSDefaultRunLoopMode dequeue: YES];
732 if( pEvent )
734 [NSApp sendEvent: pEvent];
735 bHadEvent = true;
737 [NSApp updateWindows];
739 AcquireYieldMutex( nCount );
740 } while( bHandleAllCurrentEvents && pEvent );
742 // if we had no event yet, wait for one if requested
743 if( bWait && ! bHadEvent )
745 ULONG nCount = ReleaseYieldMutex();
747 NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture];
748 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt
749 inMode: NSDefaultRunLoopMode dequeue: YES];
750 if( pEvent )
751 [NSApp sendEvent: pEvent];
752 [NSApp updateWindows];
754 AcquireYieldMutex( nCount );
756 // #i86581#
757 // FIXME: sometimes the NSTimer will never fire. Firing it by hand then
758 // fixes the problem even seems to set the correct next firing date
759 // Why oh why ?
760 if( ! pEvent && AquaSalTimer::pRunningTimer )
762 // this cause crashes on MacOSX 10.4
763 // [AquaSalTimer::pRunningTimer fire];
764 ImplGetSVData()->mpSalTimer->CallCallback();
768 mbWaitingYield = bOldWaitingYield;
770 // collect update rectangles
771 const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames );
772 for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
774 if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() )
776 (*it)->Flush( (*it)->maInvalidRect );
777 (*it)->maInvalidRect.SetEmpty();
782 // we get some apple events way too early
783 // before the application is ready to handle them,
784 // so their corresponding application events need to be delayed
785 // now is a good time to handle at least one of them
786 if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute )
788 // make sure that only one application event is active at a time
789 static bool bInAppEvent = false;
790 if( !bInAppEvent )
792 bInAppEvent = true;
793 // get the next delayed application event
794 const ApplicationEvent* pAppEvent = aAppEventList.front();
795 aAppEventList.pop_front();
796 // handle one application event (no recursion)
797 const ImplSVData* pSVData = ImplGetSVData();
798 pSVData->mpApp->AppEvent( *pAppEvent );
799 delete pAppEvent;
800 // allow the next delayed application event
801 bInAppEvent = false;
806 // -----------------------------------------------------------------------
808 bool AquaSalInstance::AnyInput( USHORT nType )
810 if( nType & INPUT_APPEVENT )
812 if( ! aAppEventList.empty() )
813 return true;
814 if( nType == INPUT_APPEVENT )
815 return false;
818 if( nType & INPUT_TIMER )
820 if( AquaSalTimer::pRunningTimer )
822 NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate];
823 if( pDt && [pDt timeIntervalSinceNow] < 0 )
825 return true;
830 unsigned/*NSUInteger*/ nEventMask = 0;
831 if( nType & INPUT_MOUSE)
832 nEventMask |=
833 NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask |
834 NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask |
835 NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask |
836 NSScrollWheelMask |
837 // NSMouseMovedMask |
838 NSMouseEnteredMask | NSMouseExitedMask;
839 if( nType & INPUT_KEYBOARD)
840 nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask;
841 if( nType & INPUT_OTHER)
842 nEventMask |= NSTabletPoint;
843 // TODO: INPUT_PAINT / more INPUT_OTHER
844 if( !nType)
845 return false;
847 NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil
848 inMode: NSDefaultRunLoopMode dequeue: NO];
849 return (pEvent != NULL);
852 // -----------------------------------------------------------------------
854 SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, ULONG nSalFrameStyle )
856 return NULL;
859 // -----------------------------------------------------------------------
861 SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, ULONG nSalFrameStyle )
863 SalData::ensureThreadAutoreleasePool();
865 SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle );
866 return pFrame;
869 // -----------------------------------------------------------------------
871 void AquaSalInstance::DestroyFrame( SalFrame* pFrame )
873 delete pFrame;
876 // -----------------------------------------------------------------------
878 SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, BOOL /* bShow */ )
880 // SystemWindowData is meaningless on Mac OS X
881 AquaSalObject *pObject = NULL;
883 if ( pParent )
884 pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) );
886 return pObject;
889 // -----------------------------------------------------------------------
891 void AquaSalInstance::DestroyObject( SalObject* pObject )
893 delete ( pObject );
896 // -----------------------------------------------------------------------
898 SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
900 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) );
903 // -----------------------------------------------------------------------
905 void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter )
907 delete pPrinter;
910 // -----------------------------------------------------------------------
912 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
914 NSArray* pNames = [NSPrinter printerNames];
915 NSArray* pTypes = [NSPrinter printerTypes];
916 unsigned int nNameCount = pNames ? [pNames count] : 0;
917 unsigned int nTypeCount = pTypes ? [pTypes count] : 0;
918 DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" );
919 for( unsigned int i = 0; i < nNameCount; i++ )
921 NSString* pName = [pNames objectAtIndex: i];
922 NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil;
923 if( pName )
925 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
926 pInfo->maPrinterName = GetOUString( pName );
927 if( pType )
928 pInfo->maDriver = GetOUString( pType );
929 pInfo->mnStatus = 0;
930 pInfo->mnJobs = 0;
931 pInfo->mpSysData = NULL;
933 pList->Add( pInfo );
938 // -----------------------------------------------------------------------
940 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
944 // -----------------------------------------------------------------------
946 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
948 delete pInfo;
951 // -----------------------------------------------------------------------
953 XubString AquaSalInstance::GetDefaultPrinter()
955 if( ! maDefaultPrinter.getLength() )
957 NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo];
958 DBG_ASSERT( pPI, "no print info" );
959 if( pPI )
961 NSPrinter* pPr = [pPI printer];
962 DBG_ASSERT( pPr, "no printer in default info" );
963 if( pPr )
965 NSString* pDefName = [pPr name];
966 DBG_ASSERT( pDefName, "printer has no name" );
967 maDefaultPrinter = GetOUString( pDefName );
971 return maDefaultPrinter;
974 // -----------------------------------------------------------------------
976 SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
977 ImplJobSetup* pSetupData )
979 SalInfoPrinter* pNewInfoPrinter = NULL;
980 if( pQueueInfo )
982 pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo );
983 if( pSetupData )
984 pNewInfoPrinter->SetPrinterData( pSetupData );
987 return pNewInfoPrinter;
990 // -----------------------------------------------------------------------
992 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
994 delete pPrinter;
997 // -----------------------------------------------------------------------
999 SalSystem* AquaSalInstance::CreateSystem()
1001 return new AquaSalSystem();
1004 // -----------------------------------------------------------------------
1006 void AquaSalInstance::DestroySystem( SalSystem* pSystem )
1008 delete pSystem;
1011 // -----------------------------------------------------------------------
1013 void AquaSalInstance::SetEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
1017 // -----------------------------------------------------------------------
1019 void AquaSalInstance::SetErrorEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
1023 // -----------------------------------------------------------------------
1025 void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
1027 rReturnedBytes = 1;
1028 rReturnedType = AsciiCString;
1029 return (void*)"";
1032 // -----------------------------------------------------------------------
1034 SalTimer* AquaSalInstance::CreateSalTimer()
1036 return new AquaSalTimer();
1039 // -----------------------------------------------------------------------
1041 SalSystem* AquaSalInstance::CreateSalSystem()
1043 return new AquaSalSystem();
1046 // -----------------------------------------------------------------------
1048 SalBitmap* AquaSalInstance::CreateSalBitmap()
1050 return new AquaSalBitmap();
1053 // -----------------------------------------------------------------------
1055 SalSession* AquaSalInstance::CreateSalSession()
1057 return NULL;
1060 // -----------------------------------------------------------------------
1062 class MacImeStatus : public SalI18NImeStatus
1064 public:
1065 MacImeStatus() {}
1066 virtual ~MacImeStatus() {}
1068 // asks whether there is a status window available
1069 // to toggle into menubar
1070 virtual bool canToggle() { return false; }
1071 virtual void toggle() {}
1074 // -----------------------------------------------------------------------
1076 SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus()
1078 return new MacImeStatus();
1081 // YieldMutexReleaser
1082 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
1084 SalData* pSalData = GetSalData();
1085 if( ! pSalData->mpFirstInstance->isNSAppThread() )
1087 SalData::ensureThreadAutoreleasePool();
1088 mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex();
1092 YieldMutexReleaser::~YieldMutexReleaser()
1094 if( mnCount != 0 )
1095 GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount );
1098 //////////////////////////////////////////////////////////////
1099 rtl::OUString GetOUString( CFStringRef rStr )
1101 if( rStr == 0 )
1102 return rtl::OUString();
1103 CFIndex nLength = CFStringGetLength( rStr );
1104 if( nLength == 0 )
1105 return rtl::OUString();
1106 const UniChar* pConstStr = CFStringGetCharactersPtr( rStr );
1107 if( pConstStr )
1108 return rtl::OUString( pConstStr, nLength );
1109 UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) );
1110 CFRange aRange = { 0, nLength };
1111 CFStringGetCharacters( rStr, aRange, pStr );
1112 rtl::OUString aRet( pStr, nLength );
1113 rtl_freeMemory( pStr );
1114 return aRet;
1117 rtl::OUString GetOUString( NSString* pStr )
1119 if( ! pStr )
1120 return rtl::OUString();
1121 int nLen = [pStr length];
1122 if( nLen == 0 )
1123 return rtl::OUString();
1125 rtl::OUStringBuffer aBuf( nLen+1 );
1126 aBuf.setLength( nLen );
1127 [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())];
1128 return aBuf.makeStringAndClear();
1131 CFStringRef CreateCFString( const rtl::OUString& rStr )
1133 return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() );
1136 NSString* CreateNSString( const rtl::OUString& rStr )
1138 return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()];
1141 CGImageRef CreateCGImage( const Image& rImage )
1143 BitmapEx aBmpEx( rImage.GetBitmapEx() );
1144 Bitmap aBmp( aBmpEx.GetBitmap() );
1146 if( ! aBmp || ! aBmp.ImplGetImpBitmap() )
1147 return NULL;
1149 // simple case, no transparency
1150 AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap());
1152 if( ! pSalBmp )
1153 return NULL;
1155 CGImageRef xImage = NULL;
1156 if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) )
1157 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1158 else if( aBmpEx.IsAlpha() )
1160 AlphaMask aAlphaMask( aBmpEx.GetAlpha() );
1161 Bitmap aMask( aAlphaMask.GetBitmap() );
1162 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
1163 if( pMaskBmp )
1164 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1165 else
1166 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1168 else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP )
1170 Bitmap aMask( aBmpEx.GetMask() );
1171 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
1172 if( pMaskBmp )
1173 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1174 else
1175 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1177 else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR )
1179 Color aTransColor( aBmpEx.GetTransparentColor() );
1180 SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() );
1181 xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor );
1184 return xImage;
1187 NSImage* CreateNSImage( const Image& rImage )
1189 CGImageRef xImage = CreateCGImage( rImage );
1191 if( ! xImage )
1192 return nil;
1194 Size aSize( rImage.GetSizePixel() );
1195 NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )];
1196 if( pImage )
1198 [pImage setFlipped: YES];
1199 [pImage lockFocus];
1201 NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
1202 CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
1204 const CGRect aDstRect = { {0, 0}, { aSize.Width(), aSize.Height() } };
1205 CGContextDrawImage( rCGContext, aDstRect, xImage );
1207 [pImage unlockFocus];
1210 CGImageRelease( xImage );
1212 return pImage;