1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
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"
58 #include <comphelper/processfactory.hxx>
60 #include <com/sun/star/beans/XPropertySet.hpp>
61 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
62 #include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
63 #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
64 #include <com/sun/star/uno/XComponentContext.hpp>
67 #include <Foundation/Foundation.h>
68 #include <ApplicationServices/ApplicationServices.h>
69 #import "apple_remote/RemoteMainController.h"
70 #include "apple_remote/RemoteControl.h"
75 using namespace ::com::sun::star
;
77 extern BOOL
ImplSVMain();
79 static BOOL
* gpbInit
= 0;
80 static NSMenu
* pDockMenu
= nil
;
81 static bool bNoSVMain
= true;
82 static bool bLeftMain
= false;
83 // -----------------------------------------------------------------------
85 class AquaDelayedSettingsChanged
: public Timer
89 AquaDelayedSettingsChanged( bool bInvalidate
) :
90 mbInvalidate( bInvalidate
)
94 virtual void Timeout()
96 SalData
* pSalData
= GetSalData();
97 if( ! pSalData
->maFrames
.empty() )
98 pSalData
->maFrames
.front()->CallCallback( SALEVENT_SETTINGSCHANGED
, NULL
);
102 for( std::list
< AquaSalFrame
* >::iterator it
= pSalData
->maFrames
.begin();
103 it
!= pSalData
->maFrames
.end(); ++it
)
106 (*it
)->SendPaintEvent( NULL
);
114 void AquaSalInstance::delayedSettingsChanged( bool bInvalidate
)
116 vos::OGuard
aGuard( *mpSalYieldMutex
);
117 AquaDelayedSettingsChanged
* pTimer
= new AquaDelayedSettingsChanged( bInvalidate
);
118 pTimer
->SetTimeout( 50 );
123 // the AppEventList must be available before any SalData/SalInst/etc. objects are ready
124 typedef std::list
<const ApplicationEvent
*> AppEventList
;
125 AppEventList
AquaSalInstance::aAppEventList
;
127 NSMenu
* AquaSalInstance::GetDynamicDockMenu()
129 if( ! pDockMenu
&& ! bLeftMain
)
130 pDockMenu
= [[NSMenu alloc
] initWithTitle
: @
""];
134 bool AquaSalInstance::isOnCommandLine( const rtl::OUString
& rArg
)
136 sal_uInt32 nArgs
= osl_getCommandArgCount();
137 for( sal_uInt32 i
= 0; i
< nArgs
; i
++ )
140 osl_getCommandArg( i
, &aArg
.pData
);
141 if( aArg
.equals( rArg
) )
148 // initialize the cocoa VCL_NSApplication object
149 // returns an NSAutoreleasePool that must be released when the event loop begins
150 static void initNSApp()
152 // create our cocoa NSApplication
153 [VCL_NSApplication sharedApplication
];
155 SalData::ensureThreadAutoreleasePool();
157 // put cocoa into multithreaded mode
158 [NSThread detachNewThreadSelector
:@
selector(enableCocoaThreads
:) toTarget
:[[CocoaThreadEnabler alloc
] init
] withObject
:nil
];
160 // activate our delegate methods
161 [NSApp setDelegate
: NSApp
];
163 [[NSNotificationCenter defaultCenter
] addObserver
: NSApp
164 selector
: @
selector(systemColorsChanged
:)
165 name
: NSSystemColorsDidChangeNotification
167 [[NSNotificationCenter defaultCenter
] addObserver
: NSApp
168 selector
: @
selector(screenParametersChanged
:)
169 name
: NSApplicationDidChangeScreenParametersNotification
171 // add observers for some settings changes that affect vcl's settings
173 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
174 selector
: @
selector(scrollbarVariantChanged
:)
175 name
: @
"AppleAquaScrollBarVariantChanged"
177 // scrollbar page behavior ("jump to here" or not)
178 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
179 selector
: @
selector(scrollbarSettingsChanged
:)
180 name
: @
"AppleNoRedisplayAppearancePreferenceChanged"
183 // get System Version and store the value in GetSalData()->mnSystemVersion
185 SInt32 systemVersion
= VER_TIGER
; // Initialize with minimal requirement
186 if( (err
= Gestalt(gestaltSystemVersion
, &systemVersion
)) == noErr
)
188 GetSalData()->mnSystemVersion
= systemVersion
;
189 #if OSL_DEBUG_LEVEL > 1
190 fprintf( stderr
, "System Version %x\n", (unsigned int)systemVersion
);
194 NSLog(@
"Unable to obtain system version: %ld", (long)err
);
196 // Initialize Apple Remote
197 GetSalData()->mpMainController
= [[MainController alloc
] init
];
199 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
200 selector
: @
selector(applicationWillBecomeActive
:)
201 name
: @
"AppleRemoteWillBecomeActive"
204 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
205 selector
: @
selector(applicationWillResignActive
:)
206 name
: @
"AppleRemoteWillResignActive"
209 if( ImplGetSVData()->mbIsTestTool
)
210 [NSApp activateIgnoringOtherApps
: YES
];
213 BOOL
ImplSVMainHook( BOOL
* pbInit
)
220 NSPoint aPt
= { 0, 0 };
221 NSEvent
* pEvent
= [NSEvent otherEventWithType
: NSApplicationDefined
227 subtype
: AquaSalInstance::AppExecuteSVMain
232 [NSApp postEvent
: pEvent atStart
: NO
];
234 rtl::OUString aExeURL
, aExe
;
235 osl_getExecutableFile( &aExeURL
.pData
);
236 osl_getSystemPathFromFileURL( aExeURL
.pData
, &aExe
.pData
);
237 rtl::OString
aByteExe( rtl::OUStringToOString( aExe
, osl_getThreadTextEncoding() ) );
240 aByteExe
+= OString ( " NSAccessibilityDebugLogLevel 1" );
241 const char* pArgv
[] = { aByteExe
.getStr(), NULL
};
242 NSApplicationMain( 3, pArgv
);
244 const char* pArgv
[] = { aByteExe
.getStr(), NULL
};
245 NSApplicationMain( 1, pArgv
);
250 DBG_ERROR( "NSApplication initialization could not be done" );
253 return TRUE
; // indicate that ImplSVMainHook is implemented
256 // =======================================================================
258 void SalAbort( const XubString
& rErrorText
)
260 if( !rErrorText
.Len() )
261 fprintf( stderr
, "Application Error " );
263 fprintf( stderr
, "%s ",
264 ByteString( rErrorText
, gsl_getSystemTextEncoding() ).GetBuffer() );
268 // -----------------------------------------------------------------------
272 SalData
*pSalData
= new SalData
;
273 SetSalData( pSalData
);
276 // -----------------------------------------------------------------------
278 const ::rtl::OUString
& SalGetDesktopEnvironment()
280 static OUString
aDesktopEnvironment(RTL_CONSTASCII_USTRINGPARAM( "MacOSX" ));
281 return aDesktopEnvironment
;
284 // -----------------------------------------------------------------------
288 SalData
*pSalData
= GetSalData();
289 if( pSalData
->mpStatusItem
)
291 [pSalData
->mpStatusItem release
];
292 pSalData
->mpStatusItem
= nil
;
298 // -----------------------------------------------------------------------
301 #include <crt_externs.h>
304 // -----------------------------------------------------------------------
308 rtl::OUString urlWorkDir
;
309 rtl_uString
*sysWorkDir
= NULL
;
310 if (tools::getProcessWorkingDir(&urlWorkDir
))
312 oslFileError err2
= osl_getSystemPathFromFileURL(urlWorkDir
.pData
, &sysWorkDir
);
313 if (err2
== osl_File_E_None
)
315 ByteString
aPath( getenv( "PATH" ) );
316 ByteString
aResPath( getenv( "STAR_RESOURCEPATH" ) );
317 ByteString
aLibPath( getenv( "DYLD_LIBRARY_PATH" ) );
318 ByteString
aCmdPath( OUStringToOString(OUString(sysWorkDir
), RTL_TEXTENCODING_UTF8
).getStr() );
320 // Get absolute path of command's directory
321 if ( aCmdPath
.Len() ) {
322 DirEntry
aCmdDirEntry( aCmdPath
);
323 aCmdDirEntry
.ToAbs();
324 aCmdPath
= ByteString( aCmdDirEntry
.GetPath().GetFull(), RTL_TEXTENCODING_ASCII_US
);
326 // Assign to PATH environment variable
327 if ( aCmdPath
.Len() )
329 aTmpPath
= ByteString( "PATH=" );
330 aTmpPath
+= aCmdPath
;
332 aTmpPath
+= ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US
);
334 putenv( (char*)aTmpPath
.GetBuffer() );
336 // Assign to STAR_RESOURCEPATH environment variable
337 if ( aCmdPath
.Len() )
339 aTmpPath
= ByteString( "STAR_RESOURCEPATH=" );
340 aTmpPath
+= aCmdPath
;
341 if ( aResPath
.Len() )
342 aTmpPath
+= ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US
);
343 aTmpPath
+= aResPath
;
344 putenv( (char*)aTmpPath
.GetBuffer() );
346 // Assign to DYLD_LIBRARY_PATH environment variable
347 if ( aCmdPath
.Len() )
349 aTmpPath
= ByteString( "DYLD_LIBRARY_PATH=" );
350 aTmpPath
+= aCmdPath
;
351 if ( aLibPath
.Len() )
352 aTmpPath
+= ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US
);
353 aTmpPath
+= aLibPath
;
354 putenv( (char*)aTmpPath
.GetBuffer() );
360 // -----------------------------------------------------------------------
366 // =======================================================================
368 SalYieldMutex::SalYieldMutex()
374 void SalYieldMutex::acquire()
377 mnThreadId
= NAMESPACE_VOS(OThread
)::getCurrentIdentifier();
381 void SalYieldMutex::release()
383 if ( mnThreadId
== NAMESPACE_VOS(OThread
)::getCurrentIdentifier() )
392 sal_Bool
SalYieldMutex::tryToAcquire()
394 if ( OMutex::tryToAcquire() )
396 mnThreadId
= NAMESPACE_VOS(OThread
)::getCurrentIdentifier();
404 // -----------------------------------------------------------------------
406 // some convenience functions regarding the yield mutex, aka solar mutex
408 BOOL
ImplSalYieldMutexTryToAcquire()
410 AquaSalInstance
* pInst
= (AquaSalInstance
*) GetSalData()->mpFirstInstance
;
412 return pInst
->mpSalYieldMutex
->tryToAcquire();
417 void ImplSalYieldMutexAcquire()
419 AquaSalInstance
* pInst
= (AquaSalInstance
*) GetSalData()->mpFirstInstance
;
421 pInst
->mpSalYieldMutex
->acquire();
424 void ImplSalYieldMutexRelease()
426 AquaSalInstance
* pInst
= (AquaSalInstance
*) GetSalData()->mpFirstInstance
;
428 pInst
->mpSalYieldMutex
->release();
431 // =======================================================================
433 SalInstance
* CreateSalInstance()
435 // this is the case for not using SVMain
440 SalData
* pSalData
= GetSalData();
441 DBG_ASSERT( pSalData
->mpFirstInstance
== NULL
, "more than one instance created" );
442 AquaSalInstance
* pInst
= new AquaSalInstance
;
444 // init instance (only one instance in this version !!!)
445 pSalData
->mpFirstInstance
= pInst
;
446 // this one is for outside AquaSalInstance::Yield
447 SalData::ensureThreadAutoreleasePool();
448 // no focus rects on NWF aqua
449 ImplGetSVData()->maNWFData
.mbNoFocusRects
= true;
450 ImplGetSVData()->maNWFData
.mbNoBoldTabFocus
= true;
451 ImplGetSVData()->maNWFData
.mbNoActiveTabTextRaise
= true;
452 ImplGetSVData()->maNWFData
.mbCenteredTabs
= true;
453 ImplGetSVData()->maNWFData
.mbProgressNeedsErase
= true;
454 ImplGetSVData()->maNWFData
.mbCheckBoxNeedsErase
= true;
455 ImplGetSVData()->maGDIData
.mbPrinterPullModel
= true;
456 ImplGetSVData()->maGDIData
.mbNoXORClipping
= true;
457 ImplGetSVData()->maWinData
.mbNoSaveBackground
= true;
462 // -----------------------------------------------------------------------
464 void DestroySalInstance( SalInstance
* pInst
)
469 // -----------------------------------------------------------------------
471 AquaSalInstance::AquaSalInstance()
473 mpSalYieldMutex
= new SalYieldMutex
;
474 mpSalYieldMutex
->acquire();
475 maMainThread
= vos::OThread::getCurrentIdentifier();
476 mbWaitingYield
= false;
477 maUserEventListMutex
= osl_createMutex();
478 mnActivePrintJobs
= 0;
481 // -----------------------------------------------------------------------
483 AquaSalInstance::~AquaSalInstance()
485 mpSalYieldMutex
->release();
486 delete mpSalYieldMutex
;
487 osl_destroyMutex( maUserEventListMutex
);
490 // -----------------------------------------------------------------------
492 void AquaSalInstance::wakeupYield()
497 SalData::ensureThreadAutoreleasePool();
498 NSPoint aPt
= { 0, 0 };
499 NSEvent
* pEvent
= [NSEvent otherEventWithType
: NSApplicationDefined
505 subtype
: AquaSalInstance::YieldWakeupEvent
509 [NSApp postEvent
: pEvent atStart
: NO
];
513 // -----------------------------------------------------------------------
515 void AquaSalInstance::PostUserEvent( AquaSalFrame
* pFrame
, USHORT nType
, void* pData
)
517 osl_acquireMutex( maUserEventListMutex
);
518 maUserEvents
.push_back( SalUserEvent( pFrame
, pData
, nType
) );
519 osl_releaseMutex( maUserEventListMutex
);
521 // notify main loop that an event has arrived
525 // -----------------------------------------------------------------------
527 vos::IMutex
* AquaSalInstance::GetYieldMutex()
529 return mpSalYieldMutex
;
532 // -----------------------------------------------------------------------
534 ULONG
AquaSalInstance::ReleaseYieldMutex()
536 SalYieldMutex
* pYieldMutex
= mpSalYieldMutex
;
537 if ( pYieldMutex
->GetThreadId() ==
538 NAMESPACE_VOS(OThread
)::getCurrentIdentifier() )
540 ULONG nCount
= pYieldMutex
->GetAcquireCount();
544 pYieldMutex
->release();
554 // -----------------------------------------------------------------------
556 void AquaSalInstance::AcquireYieldMutex( ULONG nCount
)
558 SalYieldMutex
* pYieldMutex
= mpSalYieldMutex
;
561 pYieldMutex
->acquire();
566 // -----------------------------------------------------------------------
568 bool AquaSalInstance::isNSAppThread() const
570 return vos::OThread::getCurrentIdentifier() == maMainThread
;
573 // -----------------------------------------------------------------------
575 void AquaSalInstance::handleAppDefinedEvent( NSEvent
* pEvent
)
577 switch( [pEvent subtype
] )
579 case AppStartTimerEvent
:
580 AquaSalTimer::handleStartTimerEvent( pEvent
);
582 case AppEndLoopEvent
:
585 case AppExecuteSVMain
:
587 BOOL bResult
= ImplSVMain();
599 case AppleRemoteEvent
:
601 sal_Int16 nCommand
= 0;
602 SalData
* pSalData
= GetSalData();
603 bool bIsFullScreenMode
= false;
605 std::list
<AquaSalFrame
*>::iterator it
= pSalData
->maFrames
.begin();
606 while( (*it
) && ( (it
!= pSalData
->maFrames
.end() ) || ( (*it
)->mbFullScreen
== false ) ) )
608 if ( ((*it
)->mbFullScreen
== true) )
609 bIsFullScreenMode
= true;
613 switch ([pEvent data1
])
615 case kRemoteButtonPlay
:
616 nCommand
= ( bIsFullScreenMode
== true ) ? MEDIA_COMMAND_PLAY_PAUSE
: MEDIA_COMMAND_PLAY
;
619 // kept for experimentation purpose (scheduled for future implementation)
620 // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break;
622 case kRemoteButtonPlus
: nCommand
= MEDIA_COMMAND_VOLUME_UP
; break;
624 case kRemoteButtonMinus
: nCommand
= MEDIA_COMMAND_VOLUME_DOWN
; break;
626 case kRemoteButtonRight
: nCommand
= MEDIA_COMMAND_NEXTTRACK
; break;
628 case kRemoteButtonRight_Hold
: nCommand
= MEDIA_COMMAND_NEXTTRACK_HOLD
; break;
630 case kRemoteButtonLeft
: nCommand
= MEDIA_COMMAND_PREVIOUSTRACK
; break;
632 case kRemoteButtonLeft_Hold
: nCommand
= MEDIA_COMMAND_REWIND
; break;
634 case kRemoteButtonPlay_Hold
: nCommand
= MEDIA_COMMAND_PLAY_HOLD
; break;
636 case kRemoteButtonMenu_Hold
: nCommand
= MEDIA_COMMAND_STOP
; break;
638 // FIXME : not detected
639 case kRemoteButtonPlus_Hold
:
640 case kRemoteButtonMinus_Hold
:
646 AquaSalFrame
* pFrame
= pSalData
->maFrames
.front();
647 Window
* pWindow
= pFrame
->GetWindow() ? pSalData
->maFrames
.front()->GetWindow() : NULL
;
652 CommandEvent
aCEvt( aPoint
, COMMAND_MEDIA
, FALSE
, &nCommand
);
653 NotifyEvent
aNCmdEvt( EVENT_COMMAND
, pWindow
, &aCEvt
);
655 if ( !ImplCallPreNotify( aNCmdEvt
) )
656 pWindow
->Command( aCEvt
);
662 case YieldWakeupEvent
:
663 // do nothing, fall out of Yield
667 DBG_ERROR( "unhandled NSApplicationDefined event" );
672 // -----------------------------------------------------------------------
674 class ReleasePoolHolder
676 NSAutoreleasePool
* mpPool
;
678 ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc
] init
] ) {}
679 ~ReleasePoolHolder() { [mpPool release
]; }
682 void AquaSalInstance::Yield( bool bWait
, bool bHandleAllCurrentEvents
)
684 // ensure that the per thread autorelease pool is top level and
685 // will therefore not be destroyed by cocoa implicitly
686 SalData::ensureThreadAutoreleasePool();
688 // NSAutoreleasePool documentation suggests we should have
689 // an own pool for each yield level
690 ReleasePoolHolder aReleasePool
;
692 // Release all locks so that we don't deadlock when we pull pending
693 // events from the event queue
694 bool bDispatchUser
= true;
695 while( bDispatchUser
)
697 ULONG nCount
= ReleaseYieldMutex();
699 // get one user event
700 osl_acquireMutex( maUserEventListMutex
);
701 SalUserEvent
aEvent( NULL
, NULL
, 0 );
702 if( ! maUserEvents
.empty() )
704 aEvent
= maUserEvents
.front();
705 maUserEvents
.pop_front();
708 bDispatchUser
= false;
709 osl_releaseMutex( maUserEventListMutex
);
711 AcquireYieldMutex( nCount
);
714 if( aEvent
.mpFrame
&& AquaSalFrame::isAlive( aEvent
.mpFrame
) )
716 aEvent
.mpFrame
->CallCallback( aEvent
.mnType
, aEvent
.mpData
);
717 // return if only one event is asked for
718 if( ! bHandleAllCurrentEvents
)
723 // handle cocoa event queue
724 // cocoa events mye be only handled in the thread the NSApp was created
725 if( isNSAppThread() && mnActivePrintJobs
== 0 )
727 // we need to be woken up by a cocoa-event
728 // if a user event should be posted by the event handling below
729 bool bOldWaitingYield
= mbWaitingYield
;
730 mbWaitingYield
= bWait
;
732 // handle available events
733 NSEvent
* pEvent
= nil
;
734 bool bHadEvent
= false;
737 ULONG nCount
= ReleaseYieldMutex();
739 pEvent
= [NSApp nextEventMatchingMask
: NSAnyEventMask untilDate
: nil
740 inMode
: NSDefaultRunLoopMode dequeue
: YES
];
743 [NSApp sendEvent
: pEvent
];
746 [NSApp updateWindows
];
748 AcquireYieldMutex( nCount
);
749 } while( bHandleAllCurrentEvents
&& pEvent
);
751 // if we had no event yet, wait for one if requested
752 if( bWait
&& ! bHadEvent
)
754 ULONG nCount
= ReleaseYieldMutex();
756 NSDate
* pDt
= AquaSalTimer::pRunningTimer
? [AquaSalTimer::pRunningTimer fireDate
] : [NSDate distantFuture
];
757 pEvent
= [NSApp nextEventMatchingMask
: NSAnyEventMask untilDate
: pDt
758 inMode
: NSDefaultRunLoopMode dequeue
: YES
];
760 [NSApp sendEvent
: pEvent
];
761 [NSApp updateWindows
];
763 AcquireYieldMutex( nCount
);
766 // FIXME: sometimes the NSTimer will never fire. Firing it by hand then
767 // fixes the problem even seems to set the correct next firing date
769 if( ! pEvent
&& AquaSalTimer::pRunningTimer
)
771 // this cause crashes on MacOSX 10.4
772 // [AquaSalTimer::pRunningTimer fire];
773 ImplGetSVData()->mpSalTimer
->CallCallback();
777 mbWaitingYield
= bOldWaitingYield
;
779 // collect update rectangles
780 const std::list
< AquaSalFrame
* > rFrames( GetSalData()->maFrames
);
781 for( std::list
< AquaSalFrame
* >::const_iterator it
= rFrames
.begin(); it
!= rFrames
.end(); ++it
)
783 if( (*it
)->mbShown
&& ! (*it
)->maInvalidRect
.IsEmpty() )
785 (*it
)->Flush( (*it
)->maInvalidRect
);
786 (*it
)->maInvalidRect
.SetEmpty();
791 // we get some apple events way too early
792 // before the application is ready to handle them,
793 // so their corresponding application events need to be delayed
794 // now is a good time to handle at least one of them
795 if( bWait
&& !aAppEventList
.empty() && ImplGetSVData()->maAppData
.mbInAppExecute
)
797 // make sure that only one application event is active at a time
798 static bool bInAppEvent
= false;
802 // get the next delayed application event
803 const ApplicationEvent
* pAppEvent
= aAppEventList
.front();
804 aAppEventList
.pop_front();
805 // handle one application event (no recursion)
806 const ImplSVData
* pSVData
= ImplGetSVData();
807 pSVData
->mpApp
->AppEvent( *pAppEvent
);
809 // allow the next delayed application event
815 // -----------------------------------------------------------------------
817 bool AquaSalInstance::AnyInput( USHORT nType
)
819 if( nType
& INPUT_APPEVENT
)
821 if( ! aAppEventList
.empty() )
823 if( nType
== INPUT_APPEVENT
)
827 if( nType
& INPUT_TIMER
)
829 if( AquaSalTimer::pRunningTimer
)
831 NSDate
* pDt
= [AquaSalTimer::pRunningTimer fireDate
];
832 if( pDt
&& [pDt timeIntervalSinceNow
] < 0 )
839 unsigned/*NSUInteger*/ nEventMask
= 0;
840 if( nType
& INPUT_MOUSE
)
842 NSLeftMouseDownMask
| NSRightMouseDownMask
| NSOtherMouseDownMask
|
843 NSLeftMouseUpMask
| NSRightMouseUpMask
| NSOtherMouseUpMask
|
844 NSLeftMouseDraggedMask
| NSRightMouseDraggedMask
| NSOtherMouseDraggedMask
|
846 // NSMouseMovedMask |
847 NSMouseEnteredMask
| NSMouseExitedMask
;
848 if( nType
& INPUT_KEYBOARD
)
849 nEventMask
|= NSKeyDownMask
| NSKeyUpMask
| NSFlagsChangedMask
;
850 if( nType
& INPUT_OTHER
)
851 nEventMask
|= NSTabletPoint
;
852 // TODO: INPUT_PAINT / more INPUT_OTHER
856 NSEvent
* pEvent
= [NSApp nextEventMatchingMask
: nEventMask untilDate
: nil
857 inMode
: NSDefaultRunLoopMode dequeue
: NO
];
858 return (pEvent
!= NULL
);
861 // -----------------------------------------------------------------------
863 SalFrame
* AquaSalInstance::CreateChildFrame( SystemParentData
* pSystemParentData
, ULONG nSalFrameStyle
)
868 // -----------------------------------------------------------------------
870 SalFrame
* AquaSalInstance::CreateFrame( SalFrame
* pParent
, ULONG nSalFrameStyle
)
872 SalData::ensureThreadAutoreleasePool();
874 SalFrame
* pFrame
= new AquaSalFrame( pParent
, nSalFrameStyle
);
878 // -----------------------------------------------------------------------
880 void AquaSalInstance::DestroyFrame( SalFrame
* pFrame
)
885 // -----------------------------------------------------------------------
887 SalObject
* AquaSalInstance::CreateObject( SalFrame
* pParent
, SystemWindowData
* /* pWindowData */, BOOL
/* bShow */ )
889 // SystemWindowData is meaningless on Mac OS X
890 AquaSalObject
*pObject
= NULL
;
893 pObject
= new AquaSalObject( static_cast<AquaSalFrame
*>(pParent
) );
898 // -----------------------------------------------------------------------
900 void AquaSalInstance::DestroyObject( SalObject
* pObject
)
905 // -----------------------------------------------------------------------
907 SalPrinter
* AquaSalInstance::CreatePrinter( SalInfoPrinter
* pInfoPrinter
)
909 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter
*>(pInfoPrinter
) );
912 // -----------------------------------------------------------------------
914 void AquaSalInstance::DestroyPrinter( SalPrinter
* pPrinter
)
919 // -----------------------------------------------------------------------
921 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList
* pList
)
923 NSArray
* pNames
= [NSPrinter printerNames
];
924 NSArray
* pTypes
= [NSPrinter printerTypes
];
925 unsigned int nNameCount
= pNames
? [pNames count
] : 0;
926 unsigned int nTypeCount
= pTypes
? [pTypes count
] : 0;
927 DBG_ASSERT( nTypeCount
== nNameCount
, "type count not equal to printer count" );
928 for( unsigned int i
= 0; i
< nNameCount
; i
++ )
930 NSString
* pName
= [pNames objectAtIndex
: i
];
931 NSString
* pType
= i
< nTypeCount
? [pTypes objectAtIndex
: i
] : nil
;
934 SalPrinterQueueInfo
* pInfo
= new SalPrinterQueueInfo
;
935 pInfo
->maPrinterName
= GetOUString( pName
);
937 pInfo
->maDriver
= GetOUString( pType
);
940 pInfo
->mpSysData
= NULL
;
947 // -----------------------------------------------------------------------
949 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo
* pInfo
)
953 // -----------------------------------------------------------------------
955 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo
* pInfo
)
960 // -----------------------------------------------------------------------
962 XubString
AquaSalInstance::GetDefaultPrinter()
964 if( ! maDefaultPrinter
.getLength() )
966 NSPrintInfo
* pPI
= [NSPrintInfo sharedPrintInfo
];
967 DBG_ASSERT( pPI
, "no print info" );
970 NSPrinter
* pPr
= [pPI printer
];
971 DBG_ASSERT( pPr
, "no printer in default info" );
974 NSString
* pDefName
= [pPr name
];
975 DBG_ASSERT( pDefName
, "printer has no name" );
976 maDefaultPrinter
= GetOUString( pDefName
);
980 return maDefaultPrinter
;
983 // -----------------------------------------------------------------------
985 SalInfoPrinter
* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo
* pQueueInfo
,
986 ImplJobSetup
* pSetupData
)
988 SalInfoPrinter
* pNewInfoPrinter
= NULL
;
991 pNewInfoPrinter
= new AquaSalInfoPrinter( *pQueueInfo
);
993 pNewInfoPrinter
->SetPrinterData( pSetupData
);
996 return pNewInfoPrinter
;
999 // -----------------------------------------------------------------------
1001 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter
* pPrinter
)
1006 // -----------------------------------------------------------------------
1008 SalSystem
* AquaSalInstance::CreateSystem()
1010 return new AquaSalSystem();
1013 // -----------------------------------------------------------------------
1015 void AquaSalInstance::DestroySystem( SalSystem
* pSystem
)
1020 // -----------------------------------------------------------------------
1022 void AquaSalInstance::SetEventCallback( void* pInstance
, bool(*pCallback
)(void*,void*,int) )
1026 // -----------------------------------------------------------------------
1028 void AquaSalInstance::SetErrorEventCallback( void* pInstance
, bool(*pCallback
)(void*,void*,int) )
1032 // -----------------------------------------------------------------------
1034 void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType
& rReturnedType
, int& rReturnedBytes
)
1037 rReturnedType
= AsciiCString
;
1041 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts
1042 // to UTF-8 before encoding non ascii characters, which is not what other apps expect.
1043 static rtl::OUString
translateToExternalUrl(const rtl::OUString
& internalUrl
)
1045 rtl::OUString extUrl
;
1047 uno::Reference
< lang::XMultiServiceFactory
> sm
= comphelper::getProcessServiceFactory();
1050 uno::Reference
< beans::XPropertySet
> pset
;
1051 sm
->queryInterface( getCppuType( &pset
)) >>= pset
;
1054 uno::Reference
< uno::XComponentContext
> context
;
1055 static const rtl::OUString
DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) );
1056 pset
->getPropertyValue(DEFAULT_CONTEXT
) >>= context
;
1058 extUrl
= uri::ExternalUriReferenceTranslator::create(context
)->translateToExternal(internalUrl
);
1064 // #i104525# many versions of OSX have problems with some URLs:
1065 // when an app requests OSX to add one of these URLs to the "Recent Items" list
1066 // then this app gets killed (TextEdit, Preview, etc. and also OOo)
1067 static bool isDangerousUrl( const rtl::OUString
& rUrl
)
1069 // use a heuristic that detects all known cases since there is no official comment
1070 // on the exact impact and root cause of the OSX bug
1071 const int nLen
= rUrl
.getLength();
1072 const sal_Unicode
* p
= rUrl
.getStr();
1073 for( int i
= 0; i
< nLen
-3; ++i
, ++p
) {
1077 if( (p
[1] == '2') && (p
[2] == '5') )
1079 // escapes are considered to be UTF-8 encoded
1080 // => check for invalid UTF-8 leading byte
1081 if( (p
[1] != 'f') && (p
[1] != 'F') )
1083 int cLowNibble
= p
[2];
1084 if( (cLowNibble
>= '0' ) && (cLowNibble
<= '9'))
1086 if( cLowNibble
>= 'a' )
1087 cLowNibble
-= 'a' - 'A';
1088 if( (cLowNibble
< 'A') || (cLowNibble
>= 'C'))
1095 void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString
& rFileUrl
, const rtl::OUString
& /*rMimeType*/)
1097 // Convert file URL for external use (see above)
1098 rtl::OUString externalUrl
= translateToExternalUrl(rFileUrl
);
1099 if( 0 == externalUrl
.getLength() )
1100 externalUrl
= rFileUrl
;
1102 if( externalUrl
.getLength() && !isDangerousUrl( externalUrl
) )
1104 NSString
* pString
= CreateNSString( externalUrl
);
1105 NSURL
* pURL
= [NSURL URLWithString
: pString
];
1109 NSDocumentController
* pCtrl
= [NSDocumentController sharedDocumentController
];
1110 [pCtrl noteNewRecentDocumentURL
: pURL
];
1118 // -----------------------------------------------------------------------
1120 SalTimer
* AquaSalInstance::CreateSalTimer()
1122 return new AquaSalTimer();
1125 // -----------------------------------------------------------------------
1127 SalSystem
* AquaSalInstance::CreateSalSystem()
1129 return new AquaSalSystem();
1132 // -----------------------------------------------------------------------
1134 SalBitmap
* AquaSalInstance::CreateSalBitmap()
1136 return new AquaSalBitmap();
1139 // -----------------------------------------------------------------------
1141 SalSession
* AquaSalInstance::CreateSalSession()
1146 // -----------------------------------------------------------------------
1148 class MacImeStatus
: public SalI18NImeStatus
1152 virtual ~MacImeStatus() {}
1154 // asks whether there is a status window available
1155 // to toggle into menubar
1156 virtual bool canToggle() { return false; }
1157 virtual void toggle() {}
1160 // -----------------------------------------------------------------------
1162 SalI18NImeStatus
* AquaSalInstance::CreateI18NImeStatus()
1164 return new MacImeStatus();
1167 // YieldMutexReleaser
1168 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
1170 SalData
* pSalData
= GetSalData();
1171 if( ! pSalData
->mpFirstInstance
->isNSAppThread() )
1173 SalData::ensureThreadAutoreleasePool();
1174 mnCount
= pSalData
->mpFirstInstance
->ReleaseYieldMutex();
1178 YieldMutexReleaser::~YieldMutexReleaser()
1181 GetSalData()->mpFirstInstance
->AcquireYieldMutex( mnCount
);
1184 //////////////////////////////////////////////////////////////
1185 rtl::OUString
GetOUString( CFStringRef rStr
)
1188 return rtl::OUString();
1189 CFIndex nLength
= CFStringGetLength( rStr
);
1191 return rtl::OUString();
1192 const UniChar
* pConstStr
= CFStringGetCharactersPtr( rStr
);
1194 return rtl::OUString( pConstStr
, nLength
);
1195 UniChar
* pStr
= reinterpret_cast<UniChar
*>( rtl_allocateMemory( sizeof(UniChar
)*nLength
) );
1196 CFRange aRange
= { 0, nLength
};
1197 CFStringGetCharacters( rStr
, aRange
, pStr
);
1198 rtl::OUString
aRet( pStr
, nLength
);
1199 rtl_freeMemory( pStr
);
1203 rtl::OUString
GetOUString( NSString
* pStr
)
1206 return rtl::OUString();
1207 int nLen
= [pStr length
];
1209 return rtl::OUString();
1211 rtl::OUStringBuffer
aBuf( nLen
+1 );
1212 aBuf
.setLength( nLen
);
1213 [pStr getCharacters
: const_cast<sal_Unicode
*>(aBuf
.getStr())];
1214 return aBuf
.makeStringAndClear();
1217 CFStringRef
CreateCFString( const rtl::OUString
& rStr
)
1219 return CFStringCreateWithCharacters(kCFAllocatorDefault
, rStr
.getStr(), rStr
.getLength() );
1222 NSString
* CreateNSString( const rtl::OUString
& rStr
)
1224 return [[NSString alloc
] initWithCharacters
: rStr
.getStr() length
: rStr
.getLength()];
1227 CGImageRef
CreateCGImage( const Image
& rImage
)
1229 BitmapEx
aBmpEx( rImage
.GetBitmapEx() );
1230 Bitmap
aBmp( aBmpEx
.GetBitmap() );
1232 if( ! aBmp
|| ! aBmp
.ImplGetImpBitmap() )
1235 // simple case, no transparency
1236 AquaSalBitmap
* pSalBmp
= static_cast<AquaSalBitmap
*>(aBmp
.ImplGetImpBitmap()->ImplGetSalBitmap());
1241 CGImageRef xImage
= NULL
;
1242 if( ! (aBmpEx
.IsAlpha() || aBmpEx
.IsTransparent() ) )
1243 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1244 else if( aBmpEx
.IsAlpha() )
1246 AlphaMask
aAlphaMask( aBmpEx
.GetAlpha() );
1247 Bitmap
aMask( aAlphaMask
.GetBitmap() );
1248 AquaSalBitmap
* pMaskBmp
= static_cast<AquaSalBitmap
*>(aMask
.ImplGetImpBitmap()->ImplGetSalBitmap());
1250 xImage
= pSalBmp
->CreateWithMask( *pMaskBmp
, 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1252 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1254 else if( aBmpEx
.GetTransparentType() == TRANSPARENT_BITMAP
)
1256 Bitmap
aMask( aBmpEx
.GetMask() );
1257 AquaSalBitmap
* pMaskBmp
= static_cast<AquaSalBitmap
*>(aMask
.ImplGetImpBitmap()->ImplGetSalBitmap());
1259 xImage
= pSalBmp
->CreateWithMask( *pMaskBmp
, 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1261 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1263 else if( aBmpEx
.GetTransparentType() == TRANSPARENT_COLOR
)
1265 Color
aTransColor( aBmpEx
.GetTransparentColor() );
1266 SalColor nTransColor
= MAKE_SALCOLOR( aTransColor
.GetRed(), aTransColor
.GetGreen(), aTransColor
.GetBlue() );
1267 xImage
= pSalBmp
->CreateColorMask( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
, nTransColor
);
1273 NSImage
* CreateNSImage( const Image
& rImage
)
1275 CGImageRef xImage
= CreateCGImage( rImage
);
1280 Size
aSize( rImage
.GetSizePixel() );
1281 NSImage
* pImage
= [[NSImage alloc
] initWithSize
: NSMakeSize( aSize
.Width(), aSize
.Height() )];
1284 [pImage setFlipped
: YES
];
1287 NSGraphicsContext
* pContext
= [NSGraphicsContext currentContext
];
1288 CGContextRef rCGContext
= reinterpret_cast<CGContextRef
>([pContext graphicsPort
]);
1290 const CGRect aDstRect
= { {0, 0}, { aSize
.Width(), aSize
.Height() } };
1291 CGContextDrawImage( rCGContext
, aDstRect
, xImage
);
1293 [pImage unlockFocus
];
1296 CGImageRelease( xImage
);