1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <condition_variable>
26 #include <config_features.h>
30 #include <comphelper/solarmutex.hxx>
32 #include <comphelper/lok.hxx>
34 #include <osl/process.h>
36 #include <rtl/ustrbuf.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/window.hxx>
40 #include <vcl/idle.hxx>
41 #include <vcl/svmain.hxx>
42 #include <vcl/opengl/OpenGLContext.hxx>
44 #include <osx/saldata.hxx>
45 #include <osx/salinst.h>
46 #include <osx/salframe.h>
47 #include <osx/salobj.h>
48 #include <osx/salsys.h>
49 #include <quartz/salvd.h>
50 #include <quartz/salbmp.h>
51 #include <quartz/utils.h>
52 #include <osx/salprn.h>
53 #include <osx/saltimer.h>
54 #include <osx/vclnsapp.h>
55 #include <osx/runinmain.hxx>
58 #include <salimestatus.hxx>
60 #include <comphelper/processfactory.hxx>
62 #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
63 #include <com/sun/star/uno/XComponentContext.hpp>
66 #include <Foundation/Foundation.h>
67 #include <ApplicationServices/ApplicationServices.h>
68 #import "apple_remote/RemoteMainController.h"
69 #include <apple_remote/RemoteControl.h>
73 #include <crt_externs.h>
77 using namespace ::com::sun::star
;
79 static int* gpnInit
= nullptr;
80 static NSMenu
* pDockMenu
= nil
;
81 static bool bNoSVMain
= true;
82 static bool bLeftMain
= false;
84 class AquaDelayedSettingsChanged
: public Idle
89 AquaDelayedSettingsChanged( bool bInvalidate
) :
90 mbInvalidate( bInvalidate
)
94 virtual void Invoke() override
96 AquaSalInstance
*pInst
= GetSalData()->mpInstance
;
97 SalFrame
*pAnyFrame
= pInst
->anyFrame();
99 pAnyFrame
->CallCallback( SalEvent::SettingsChanged
, nullptr );
103 for( auto pSalFrame
: pInst
->getFrames() )
105 AquaSalFrame
* pFrame
= static_cast<AquaSalFrame
*>( pSalFrame
);
106 if( pFrame
->mbShown
)
107 pFrame
->SendPaintEvent();
114 void AquaSalInstance::delayedSettingsChanged( bool bInvalidate
)
116 osl::Guard
< comphelper::SolarMutex
> aGuard( *mpSalYieldMutex
);
117 AquaDelayedSettingsChanged
* pIdle
= new AquaDelayedSettingsChanged( bInvalidate
);
118 pIdle
->SetDebugName( "AquaSalInstance AquaDelayedSettingsChanged" );
122 // the std::list<const ApplicationEvent*> must be available before any SalData/SalInst/etc. objects are ready
123 std::list
<const ApplicationEvent
*> AquaSalInstance::aAppEventList
;
125 NSMenu
* AquaSalInstance::GetDynamicDockMenu()
127 if( ! pDockMenu
&& ! bLeftMain
)
128 pDockMenu
= [[NSMenu alloc
] initWithTitle
: @
""];
132 bool AquaSalInstance::isOnCommandLine( const OUString
& rArg
)
134 sal_uInt32 nArgs
= osl_getCommandArgCount();
135 for( sal_uInt32 i
= 0; i
< nArgs
; i
++ )
138 osl_getCommandArg( i
, &aArg
.pData
);
139 if( aArg
.equals( rArg
) )
145 // initialize the cocoa VCL_NSApplication object
146 // returns an NSAutoreleasePool that must be released when the event loop begins
147 static void initNSApp()
149 // create our cocoa NSApplication
150 [VCL_NSApplication sharedApplication
];
152 SalData::ensureThreadAutoreleasePool();
154 // put cocoa into multithreaded mode
155 [NSThread detachNewThreadSelector
:@
selector(enableCocoaThreads
:) toTarget
:[[CocoaThreadEnabler alloc
] init
] withObject
:nil
];
157 // activate our delegate methods
158 [NSApp setDelegate
: NSApp
];
161 void postInitVCLinitNSApp()
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"
182 #if !HAVE_FEATURE_MACOSX_SANDBOX
183 // Initialize Apple Remote
184 GetSalData()->mpAppleRemoteMainController
= [[AppleRemoteMainController alloc
] init
];
186 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
187 selector
: @
selector(applicationWillBecomeActive
:)
188 name
: @
"AppleRemoteWillBecomeActive"
191 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
192 selector
: @
selector(applicationWillResignActive
:)
193 name
: @
"AppleRemoteWillResignActive"
198 bool ImplSVMainHook( int * pnInit
)
200 if (comphelper::LibreOfficeKit::isActive())
203 NSAutoreleasePool
* pool
= [ [ NSAutoreleasePool alloc
] init
];
204 unlink([[NSString stringWithFormat
:@
"%@/Library/Saved Application State/%s.savedState/restorecount.plist", NSHomeDirectory(), MACOSX_BUNDLE_IDENTIFIER
] UTF8String
]);
205 unlink([[NSString stringWithFormat
:@
"%@/Library/Saved Application State/%s.savedState/restorecount.txt", NSHomeDirectory(), MACOSX_BUNDLE_IDENTIFIER
] UTF8String
]);
213 OUString aExeURL
, aExe
;
214 osl_getExecutableFile( &aExeURL
.pData
);
215 osl_getSystemPathFromFileURL( aExeURL
.pData
, &aExe
.pData
);
216 OString
aByteExe( OUStringToOString( aExe
, osl_getThreadTextEncoding() ) );
219 aByteExe
+= OString ( " NSAccessibilityDebugLogLevel 1" );
220 const char* pArgv
[] = { aByteExe
.getStr(), NULL
};
221 NSApplicationMain( 3, pArgv
);
223 const char* pArgv
[] = { aByteExe
.getStr(), nullptr };
224 NSApplicationMain( 1, pArgv
);
227 return TRUE
; // indicate that ImplSVMainHook is implemented
230 void SalAbort( const OUString
& rErrorText
, bool bDumpCore
)
232 if( rErrorText
.isEmpty() )
233 fprintf( stderr
, "Application Error " );
235 fprintf( stderr
, "%s ",
236 OUStringToOString( rErrorText
, osl_getThreadTextEncoding() ).getStr() );
245 SalData
*pSalData
= new SalData
;
246 SetSalData( pSalData
);
249 const OUString
& SalGetDesktopEnvironment()
251 static OUString
aDesktopEnvironment( "MacOSX" );
252 return aDesktopEnvironment
;
257 SalData
*pSalData
= GetSalData();
258 if( pSalData
->mpStatusItem
)
260 [pSalData
->mpStatusItem release
];
261 pSalData
->mpStatusItem
= nil
;
264 SetSalData( nullptr );
271 SalYieldMutex::SalYieldMutex()
272 : m_aCodeBlock( nullptr )
276 SalYieldMutex::~SalYieldMutex()
280 void SalYieldMutex::doAcquire( sal_uInt32 nLockCount
)
282 AquaSalInstance
*pInst
= GetSalData()->mpInstance
;
283 if ( pInst
&& pInst
->IsMainThread() )
285 if ( pInst
->mbNoYieldLock
)
288 RuninmainBlock block
= nullptr;
290 std::unique_lock
<std::mutex
> g(m_runInMainMutex
);
291 if (m_aMutex
.tryToAcquire()) {
292 assert(m_aCodeBlock
== nullptr);
293 m_wakeUpMain
= false;
296 // wait for doRelease() or RUNINMAIN_* to set the condition
297 m_aInMainCondition
.wait(g
, [this]() { return m_wakeUpMain
; });
298 m_wakeUpMain
= false;
299 std::swap(block
, m_aCodeBlock
);
303 assert( !pInst
->mbNoYieldLock
);
304 pInst
->mbNoYieldLock
= true;
306 pInst
->mbNoYieldLock
= false;
307 Block_release( block
);
308 std::unique_lock
<std::mutex
> g(m_runInMainMutex
);
309 assert(!m_resultReady
);
310 m_resultReady
= true;
311 m_aResultCondition
.notify_all();
321 comphelper::GenericSolarMutex::doAcquire( nLockCount
);
324 sal_uInt32
SalYieldMutex::doRelease( const bool bUnlockAll
)
326 AquaSalInstance
*pInst
= GetSalData()->mpInstance
;
327 if ( pInst
->mbNoYieldLock
&& pInst
->IsMainThread() )
331 std::unique_lock
<std::mutex
> g(m_runInMainMutex
);
332 // read m_nCount before doRelease
333 bool const isReleased(bUnlockAll
|| m_nCount
== 1);
334 nCount
= comphelper::GenericSolarMutex::doRelease( bUnlockAll
);
335 if (isReleased
&& !pInst
->IsMainThread()) {
337 m_aInMainCondition
.notify_all();
343 bool SalYieldMutex::IsCurrentThread() const
345 if ( !GetSalData()->mpInstance
->mbNoYieldLock
)
346 return comphelper::GenericSolarMutex::IsCurrentThread();
348 return GetSalData()->mpInstance
->IsMainThread();
351 // some convenience functions regarding the yield mutex, aka solar mutex
353 bool ImplSalYieldMutexTryToAcquire()
355 AquaSalInstance
* pInst
= GetSalData()->mpInstance
;
357 return pInst
->mpSalYieldMutex
->tryToAcquire();
362 void ImplSalYieldMutexRelease()
364 AquaSalInstance
* pInst
= GetSalData()->mpInstance
;
366 pInst
->mpSalYieldMutex
->release();
369 SalInstance
* CreateSalInstance()
371 // this is the case for not using SVMain
376 SalData
* pSalData
= GetSalData();
377 SAL_WARN_IF( pSalData
->mpInstance
!= nullptr, "vcl", "more than one instance created" );
378 AquaSalInstance
* pInst
= new AquaSalInstance
;
380 // init instance (only one instance in this version !!!)
381 pSalData
->mpInstance
= pInst
;
382 // this one is for outside AquaSalInstance::Yield
383 SalData::ensureThreadAutoreleasePool();
384 // no focus rects on NWF
385 ImplGetSVData()->maNWFData
.mbNoFocusRects
= true;
386 ImplGetSVData()->maNWFData
.mbNoActiveTabTextRaise
= true;
387 ImplGetSVData()->maNWFData
.mbCenteredTabs
= true;
388 ImplGetSVData()->maNWFData
.mbProgressNeedsErase
= true;
389 ImplGetSVData()->maNWFData
.mnStatusBarLowerRightOffset
= 10;
394 void DestroySalInstance( SalInstance
* pInst
)
399 AquaSalInstance::AquaSalInstance()
400 : mnActivePrintJobs( 0 )
401 , mbIsLiveResize( false )
402 , mbNoYieldLock( false )
403 , mbTimerProcessed( false )
405 mpSalYieldMutex
= new SalYieldMutex
;
406 mpSalYieldMutex
->acquire();
407 maMainThread
= osl::Thread::getCurrentIdentifier();
410 AquaSalInstance::~AquaSalInstance()
412 mpSalYieldMutex
->release();
413 delete mpSalYieldMutex
;
416 void AquaSalInstance::TriggerUserEventProcessing()
418 dispatch_async(dispatch_get_main_queue(),^{
419 ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent
, NO
);
423 void AquaSalInstance::ProcessEvent( SalUserEvent aEvent
)
425 aEvent
.m_pFrame
->CallCallback( aEvent
.m_nEvent
, aEvent
.m_pData
);
426 maWaitingYieldCond
.set();
429 comphelper::SolarMutex
* AquaSalInstance::GetYieldMutex()
431 return mpSalYieldMutex
;
434 sal_uInt32
AquaSalInstance::ReleaseYieldMutexAll()
436 return mpSalYieldMutex
->release( true/*bUnlockAll*/ );
439 void AquaSalInstance::AcquireYieldMutex( sal_uInt32 nCount
)
441 mpSalYieldMutex
->acquire( nCount
);
444 bool AquaSalInstance::IsMainThread() const
446 return osl::Thread::getCurrentIdentifier() == maMainThread
;
449 void AquaSalInstance::handleAppDefinedEvent( NSEvent
* pEvent
)
451 AquaSalTimer
*pTimer
= static_cast<AquaSalTimer
*>( ImplGetSVData()->maSchedCtx
.mpSalTimer
);
452 int nSubtype
= [pEvent subtype
];
455 case AppStartTimerEvent
:
457 pTimer
->handleStartTimerEvent( pEvent
);
459 case AppEndLoopEvent
:
462 case AppExecuteSVMain
:
464 int nResult
= ImplSVMain();
476 case DispatchTimerEvent
:
478 AquaSalInstance
*pInst
= GetSalData()->mpInstance
;
479 if ( pTimer
&& pInst
)
480 pInst
->mbTimerProcessed
= pTimer
->handleDispatchTimerEvent( pEvent
);
483 #if !HAVE_FEATURE_MACOSX_SANDBOX
484 case AppleRemoteControlEvent
: // Defined in <apple_remote/RemoteMainController.h>
486 MediaCommand nCommand
;
487 AquaSalInstance
*pInst
= GetSalData()->mpInstance
;
488 bool bIsFullScreenMode
= false;
490 for( auto pSalFrame
: pInst
->getFrames() )
492 const AquaSalFrame
* pFrame
= static_cast<const AquaSalFrame
*>( pSalFrame
);
493 if ( pFrame
->mbFullScreen
)
495 bIsFullScreenMode
= true;
500 switch ([pEvent data1
])
502 case kRemoteButtonPlay
:
503 nCommand
= bIsFullScreenMode
? MediaCommand::PlayPause
: MediaCommand::Play
;
506 // kept for experimentation purpose (scheduled for future implementation)
507 // case kRemoteButtonMenu: nCommand = MediaCommand::Menu; break;
509 case kRemoteButtonPlus
: nCommand
= MediaCommand::VolumeUp
; break;
511 case kRemoteButtonMinus
: nCommand
= MediaCommand::VolumeDown
; break;
513 case kRemoteButtonRight
: nCommand
= MediaCommand::NextTrack
; break;
515 case kRemoteButtonRight_Hold
: nCommand
= MediaCommand::NextTrackHold
; break;
517 case kRemoteButtonLeft
: nCommand
= MediaCommand::PreviousTrack
; break;
519 case kRemoteButtonLeft_Hold
: nCommand
= MediaCommand::Rewind
; break;
521 case kRemoteButtonPlay_Hold
: nCommand
= MediaCommand::PlayHold
; break;
523 case kRemoteButtonMenu_Hold
: nCommand
= MediaCommand::Stop
; break;
525 // FIXME : not detected
526 case kRemoteButtonPlus_Hold
:
527 case kRemoteButtonMinus_Hold
:
533 AquaSalFrame
* pFrame
= static_cast<AquaSalFrame
*>( pInst
->anyFrame() );
534 vcl::Window
* pWindow
= pFrame
? pFrame
->GetWindow() : nullptr;
538 CommandMediaData
aMediaData(nCommand
);
539 CommandEvent
aCEvt( aPoint
, CommandEventId::Media
, FALSE
, &aMediaData
);
540 NotifyEvent
aNCmdEvt( MouseNotifyEvent::COMMAND
, pWindow
, &aCEvt
);
542 if ( !ImplCallPreNotify( aNCmdEvt
) )
543 pWindow
->Command( aCEvt
);
550 case YieldWakeupEvent
:
551 // do nothing, fall out of Yield
555 OSL_FAIL( "unhandled NSApplicationDefined event" );
560 bool AquaSalInstance::RunInMainYield( bool bHandleAllCurrentEvents
)
562 OSX_SALDATA_RUNINMAIN_UNION( DoYield( false, bHandleAllCurrentEvents
), boolean
)
563 assert( false && "Don't call this from the main thread!" );
568 static bool isWakeupEvent( NSEvent
*pEvent
)
570 SAL_WNODEPRECATED_DECLARATIONS_PUSH
571 return NSApplicationDefined
== [pEvent type
]
572 && AquaSalInstance::YieldWakeupEvent
== static_cast<int>([pEvent subtype
]);
573 SAL_WNODEPRECATED_DECLARATIONS_POP
576 bool AquaSalInstance::DoYield(bool bWait
, bool bHandleAllCurrentEvents
)
578 // ensure that the per thread autorelease pool is top level and
579 // will therefore not be destroyed by cocoa implicitly
580 SalData::ensureThreadAutoreleasePool();
582 // NSAutoreleasePool documentation suggests we should have
583 // an own pool for each yield level
584 ReleasePoolHolder aReleasePool
;
586 // first, process current user events
587 bool bHadEvent
= DispatchUserEvents( bHandleAllCurrentEvents
);
588 if ( !bHandleAllCurrentEvents
&& bHadEvent
)
591 // handle cocoa event queue
592 // cocoa events may be only handled in the thread the NSApp was created
593 if( IsMainThread() && mnActivePrintJobs
== 0 )
595 // handle available events
596 NSEvent
* pEvent
= nil
;
597 NSTimeInterval now
= [[NSProcessInfo processInfo
] systemUptime
];
598 mbTimerProcessed
= false;
602 SolarMutexReleaser aReleaser
;
604 SAL_WNODEPRECATED_DECLARATIONS_PUSH
605 // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
606 pEvent
= [NSApp nextEventMatchingMask
: NSAnyEventMask
607 SAL_WNODEPRECATED_DECLARATIONS_POP
609 inMode
: NSDefaultRunLoopMode
613 [NSApp sendEvent
: pEvent
];
614 if ( isWakeupEvent( pEvent
) )
619 [NSApp updateWindows
];
621 if ( !bHandleAllCurrentEvents
|| !pEvent
|| now
< [pEvent timestamp
] )
626 AquaSalTimer
*pTimer
= static_cast<AquaSalTimer
*>( ImplGetSVData()->maSchedCtx
.mpSalTimer
);
627 if ( !mbTimerProcessed
&& pTimer
&& pTimer
->IsDirectTimeout() )
629 pTimer
->handleTimerElapsed();
633 // if we had no event yet, wait for one if requested
634 if( bWait
&& ! bHadEvent
)
636 SolarMutexReleaser aReleaser
;
638 SAL_WNODEPRECATED_DECLARATIONS_PUSH
639 // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
640 pEvent
= [NSApp nextEventMatchingMask
: NSAnyEventMask
641 SAL_WNODEPRECATED_DECLARATIONS_POP
642 untilDate
: [NSDate distantFuture
]
643 inMode
: NSDefaultRunLoopMode
647 [NSApp sendEvent
: pEvent
];
648 if ( !isWakeupEvent( pEvent
) )
651 [NSApp updateWindows
];
654 // collect update rectangles
655 for( auto pSalFrame
: GetSalData()->mpInstance
->getFrames() )
657 AquaSalFrame
* pFrame
= static_cast<AquaSalFrame
*>( pSalFrame
);
658 if( pFrame
->mbShown
&& ! pFrame
->maInvalidRect
.IsEmpty() )
660 pFrame
->Flush( pFrame
->maInvalidRect
);
661 pFrame
->maInvalidRect
.SetEmpty();
666 maWaitingYieldCond
.set();
670 bHadEvent
= RunInMainYield( bHandleAllCurrentEvents
);
671 if ( !bHadEvent
&& bWait
)
674 // wait until the main thread has dispatched an event
675 maWaitingYieldCond
.reset();
676 SolarMutexReleaser aReleaser
;
677 maWaitingYieldCond
.wait();
681 // we get some apple events way too early
682 // before the application is ready to handle them,
683 // so their corresponding application events need to be delayed
684 // now is a good time to handle at least one of them
685 if( bWait
&& !aAppEventList
.empty() && ImplGetSVData()->maAppData
.mbInAppExecute
)
687 // make sure that only one application event is active at a time
688 static bool bInAppEvent
= false;
692 // get the next delayed application event
693 const ApplicationEvent
* pAppEvent
= aAppEventList
.front();
694 aAppEventList
.pop_front();
695 // handle one application event (no recursion)
696 const ImplSVData
* pSVData
= ImplGetSVData();
697 pSVData
->mpApp
->AppEvent( *pAppEvent
);
699 // allow the next delayed application event
707 bool AquaSalInstance::AnyInput( VclInputFlags nType
)
709 if( nType
& VclInputFlags::APPEVENT
)
711 if( ! aAppEventList
.empty() )
713 if( nType
== VclInputFlags::APPEVENT
)
717 OSX_INST_RUNINMAIN_UNION( AnyInput( nType
), boolean
)
719 if( nType
& VclInputFlags::TIMER
)
721 AquaSalTimer
*pTimer
= static_cast<AquaSalTimer
*>( ImplGetSVData()->maSchedCtx
.mpSalTimer
);
722 if (pTimer
&& pTimer
->IsTimerElapsed())
726 unsigned/*NSUInteger*/ nEventMask
= 0;
727 SAL_WNODEPRECATED_DECLARATIONS_PUSH
728 // 'NSFlagsChangedMask' is deprecated: first deprecated in macOS 10.12
729 // 'NSKeyDownMask' is deprecated: first deprecated in macOS 10.12
730 // 'NSKeyUpMask' is deprecated: first deprecated in macOS 10.12
731 // 'NSLeftMouseDownMask' is deprecated: first deprecated in macOS 10.12
732 // 'NSLeftMouseDraggedMask' is deprecated: first deprecated in macOS 10.12
733 // 'NSLeftMouseUpMask' is deprecated: first deprecated in macOS 10.12
734 // 'NSMouseEnteredMask' is deprecated: first deprecated in macOS 10.12
735 // 'NSMouseExitedMask' is deprecated: first deprecated in macOS 10.12
736 // 'NSOtherMouseDownMask' is deprecated: first deprecated in macOS 10.12
737 // 'NSOtherMouseDraggedMask' is deprecated: first deprecated in macOS 10.12
738 // 'NSOtherMouseUpMask' is deprecated: first deprecated in macOS 10.12
739 // 'NSRightMouseDownMask' is deprecated: first deprecated in macOS 10.12
740 // 'NSRightMouseDraggedMask' is deprecated: first deprecated in macOS 10.12
741 // 'NSRightMouseUpMask' is deprecated: first deprecated in macOS 10.12
742 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
743 // 'NSTabletPoint' is deprecated: first deprecated in macOS 10.12
744 if( nType
& VclInputFlags::MOUSE
)
746 NSLeftMouseDownMask
| NSRightMouseDownMask
| NSOtherMouseDownMask
|
747 NSLeftMouseUpMask
| NSRightMouseUpMask
| NSOtherMouseUpMask
|
748 NSLeftMouseDraggedMask
| NSRightMouseDraggedMask
| NSOtherMouseDraggedMask
|
750 // NSMouseMovedMask |
751 NSMouseEnteredMask
| NSMouseExitedMask
;
752 if( nType
& VclInputFlags::KEYBOARD
)
753 nEventMask
|= NSKeyDownMask
| NSKeyUpMask
| NSFlagsChangedMask
;
754 if( nType
& VclInputFlags::OTHER
)
755 nEventMask
|= NSTabletPoint
| NSApplicationDefinedMask
;
756 SAL_WNODEPRECATED_DECLARATIONS_POP
757 // TODO: VclInputFlags::PAINT / more VclInputFlags::OTHER
761 NSEvent
* pEvent
= [NSApp nextEventMatchingMask
: nEventMask untilDate
: nil
762 inMode
: NSDefaultRunLoopMode dequeue
: NO
];
763 return (pEvent
!= nullptr);
766 SalFrame
* AquaSalInstance::CreateChildFrame( SystemParentData
*, SalFrameStyleFlags
/*nSalFrameStyle*/ )
771 SalFrame
* AquaSalInstance::CreateFrame( SalFrame
* pParent
, SalFrameStyleFlags nSalFrameStyle
)
773 OSX_INST_RUNINMAIN_POINTER( CreateFrame( pParent
, nSalFrameStyle
), SalFrame
* )
774 return new AquaSalFrame( pParent
, nSalFrameStyle
);
777 void AquaSalInstance::DestroyFrame( SalFrame
* pFrame
)
779 OSX_INST_RUNINMAIN( DestroyFrame( pFrame
) )
783 SalObject
* AquaSalInstance::CreateObject( SalFrame
* pParent
, SystemWindowData
* pWindowData
, bool /* bShow */ )
788 OSX_INST_RUNINMAIN_POINTER( CreateObject( pParent
, pWindowData
, false ), SalObject
* )
789 return new AquaSalObject( static_cast<AquaSalFrame
*>(pParent
), pWindowData
);
792 void AquaSalInstance::DestroyObject( SalObject
* pObject
)
794 OSX_INST_RUNINMAIN( DestroyObject( pObject
) )
798 SalPrinter
* AquaSalInstance::CreatePrinter( SalInfoPrinter
* pInfoPrinter
)
800 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter
*>(pInfoPrinter
) );
803 void AquaSalInstance::DestroyPrinter( SalPrinter
* pPrinter
)
808 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList
* pList
)
810 NSArray
* pNames
= [NSPrinter printerNames
];
811 NSArray
* pTypes
= [NSPrinter printerTypes
];
812 unsigned int nNameCount
= pNames
? [pNames count
] : 0;
813 unsigned int nTypeCount
= pTypes
? [pTypes count
] : 0;
814 SAL_WARN_IF( nTypeCount
!= nNameCount
, "vcl", "type count not equal to printer count" );
815 for( unsigned int i
= 0; i
< nNameCount
; i
++ )
817 NSString
* pName
= [pNames objectAtIndex
: i
];
818 NSString
* pType
= i
< nTypeCount
? [pTypes objectAtIndex
: i
] : nil
;
821 SalPrinterQueueInfo
* pInfo
= new SalPrinterQueueInfo
;
822 pInfo
->maPrinterName
= GetOUString( pName
);
824 pInfo
->maDriver
= GetOUString( pType
);
825 pInfo
->mnStatus
= PrintQueueFlags::NONE
;
827 pInfo
->mpSysData
= nullptr;
834 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo
* )
838 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo
* pInfo
)
843 OUString
AquaSalInstance::GetDefaultPrinter()
845 // #i113170# may not be the main thread if called from UNO API
846 SalData::ensureThreadAutoreleasePool();
848 if( maDefaultPrinter
.isEmpty() )
850 NSPrintInfo
* pPI
= [NSPrintInfo sharedPrintInfo
];
851 SAL_WARN_IF( !pPI
, "vcl", "no print info" );
854 NSPrinter
* pPr
= [pPI printer
];
855 SAL_WARN_IF( !pPr
, "vcl", "no printer in default info" );
858 NSString
* pDefName
= [pPr name
];
859 SAL_WARN_IF( !pDefName
, "vcl", "printer has no name" );
860 maDefaultPrinter
= GetOUString( pDefName
);
864 return maDefaultPrinter
;
867 SalInfoPrinter
* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo
* pQueueInfo
,
868 ImplJobSetup
* pSetupData
)
870 // #i113170# may not be the main thread if called from UNO API
871 SalData::ensureThreadAutoreleasePool();
873 SalInfoPrinter
* pNewInfoPrinter
= nullptr;
876 pNewInfoPrinter
= new AquaSalInfoPrinter( *pQueueInfo
);
878 pNewInfoPrinter
->SetPrinterData( pSetupData
);
881 return pNewInfoPrinter
;
884 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter
* pPrinter
)
886 // #i113170# may not be the main thread if called from UNO API
887 SalData::ensureThreadAutoreleasePool();
892 OUString
AquaSalInstance::GetConnectionIdentifier()
897 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts
898 // to UTF-8 before encoding non ascii characters, which is not what other apps expect.
899 static OUString
translateToExternalUrl(const OUString
& internalUrl
)
901 uno::Reference
< uno::XComponentContext
> context(
902 comphelper::getProcessComponentContext());
903 return uri::ExternalUriReferenceTranslator::create(context
)->translateToExternal(internalUrl
);
906 // #i104525# many versions of OSX have problems with some URLs:
907 // when an app requests OSX to add one of these URLs to the "Recent Items" list
908 // then this app gets killed (TextEdit, Preview, etc. and also OOo)
909 static bool isDangerousUrl( const OUString
& rUrl
)
911 // use a heuristic that detects all known cases since there is no official comment
912 // on the exact impact and root cause of the OSX bug
913 const int nLen
= rUrl
.getLength();
914 const sal_Unicode
* p
= rUrl
.getStr();
915 for( int i
= 0; i
< nLen
-3; ++i
, ++p
) {
919 if( (p
[1] == '2') && (p
[2] == '5') )
921 // escapes are considered to be UTF-8 encoded
922 // => check for invalid UTF-8 leading byte
923 if( (p
[1] != 'f') && (p
[1] != 'F') )
925 int cLowNibble
= p
[2];
926 if( (cLowNibble
>= '0' ) && (cLowNibble
<= '9'))
928 if( cLowNibble
>= 'a' )
929 cLowNibble
-= 'a' - 'A';
930 if( (cLowNibble
< 'A') || (cLowNibble
>= 'C'))
937 void AquaSalInstance::AddToRecentDocumentList(const OUString
& rFileUrl
, const OUString
& /*rMimeType*/, const OUString
& /*rDocumentService*/)
939 // Convert file URL for external use (see above)
940 OUString externalUrl
= translateToExternalUrl(rFileUrl
);
941 if( externalUrl
.isEmpty() )
942 externalUrl
= rFileUrl
;
944 if( !externalUrl
.isEmpty() && !isDangerousUrl( externalUrl
) )
946 NSString
* pString
= CreateNSString( externalUrl
);
947 NSURL
* pURL
= [NSURL URLWithString
: pString
];
951 NSDocumentController
* pCtrl
= [NSDocumentController sharedDocumentController
];
952 [pCtrl noteNewRecentDocumentURL
: pURL
];
959 SalTimer
* AquaSalInstance::CreateSalTimer()
961 return new AquaSalTimer();
964 SalSystem
* AquaSalInstance::CreateSalSystem()
966 return new AquaSalSystem();
969 SalBitmap
* AquaSalInstance::CreateSalBitmap()
971 return new QuartzSalBitmap();
974 SalSession
* AquaSalInstance::CreateSalSession()
979 OUString
AquaSalInstance::getOSVersion()
981 NSString
* versionString
= nullptr;
982 NSDictionary
* sysVersionDict
= [ NSDictionary dictionaryWithContentsOfFile
: @
"/System/Library/CoreServices/SystemVersion.plist" ];
983 if ( sysVersionDict
)
984 versionString
= [ sysVersionDict valueForKey
: @
"ProductVersion" ];
986 OUString aVersion
= "Mac OS X ";
988 aVersion
+= OUString::fromUtf8( [ versionString UTF8String
] );
990 aVersion
+= "(unknown)";
995 CGImageRef
CreateCGImage( const Image
& rImage
)
997 BitmapEx
aBmpEx( rImage
.GetBitmapEx() );
998 Bitmap
aBmp( aBmpEx
.GetBitmap() );
1000 if( ! aBmp
|| ! aBmp
.ImplGetSalBitmap() )
1003 // simple case, no transparency
1004 QuartzSalBitmap
* pSalBmp
= static_cast<QuartzSalBitmap
*>(aBmp
.ImplGetSalBitmap().get());
1009 CGImageRef xImage
= nullptr;
1010 if( ! (aBmpEx
.IsAlpha() || aBmpEx
.IsTransparent() ) )
1011 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1012 else if( aBmpEx
.IsAlpha() )
1014 AlphaMask
aAlphaMask( aBmpEx
.GetAlpha() );
1015 Bitmap
aMask( aAlphaMask
.GetBitmap() );
1016 QuartzSalBitmap
* pMaskBmp
= static_cast<QuartzSalBitmap
*>(aMask
.ImplGetSalBitmap().get());
1018 xImage
= pSalBmp
->CreateWithMask( *pMaskBmp
, 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1020 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1022 else if( aBmpEx
.GetTransparentType() == TransparentType::Bitmap
)
1024 Bitmap
aMask( aBmpEx
.GetMask() );
1025 QuartzSalBitmap
* pMaskBmp
= static_cast<QuartzSalBitmap
*>(aMask
.ImplGetSalBitmap().get());
1027 xImage
= pSalBmp
->CreateWithMask( *pMaskBmp
, 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1029 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1031 else if( aBmpEx
.GetTransparentType() == TransparentType::Color
)
1033 Color
aTransColor( aBmpEx
.GetTransparentColor() );
1034 Color
nTransColor( aTransColor
.GetRed(), aTransColor
.GetGreen(), aTransColor
.GetBlue() );
1035 xImage
= pSalBmp
->CreateColorMask( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
, nTransColor
);
1041 NSImage
* CreateNSImage( const Image
& rImage
)
1043 CGImageRef xImage
= CreateCGImage( rImage
);
1048 Size
aSize( rImage
.GetSizePixel() );
1049 NSImage
* pImage
= [[NSImage alloc
] initWithSize
: NSMakeSize( aSize
.Width(), aSize
.Height() )];
1052 [pImage lockFocusFlipped
:YES
];
1053 NSGraphicsContext
* pContext
= [NSGraphicsContext currentContext
];
1054 CGContextRef rCGContext
= static_cast<CGContextRef
>([pContext graphicsPort
]);
1056 const CGRect aDstRect
= { {0, 0}, { static_cast<CGFloat
>(aSize
.Width()), static_cast<CGFloat
>(aSize
.Height()) } };
1057 CGContextDrawImage( rCGContext
, aDstRect
, xImage
);
1059 [pImage unlockFocus
];
1062 CGImageRelease( xImage
);
1068 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */