diff options
author | Jan-Marek Glogowski <glogow@fbihome.de> | 2017-08-08 15:03:37 +0200 |
---|---|---|
committer | Jan-Marek Glogowski <glogow@fbihome.de> | 2017-09-21 09:04:29 +0200 |
commit | 9796f792fef69bbe01b674365643d1fbb79918b4 (patch) | |
tree | bc684f43077f5b70ec5553d4f5253ca57f0b023b /vcl/osx/salinst.cxx | |
parent | 4067487eb304c6686a22319c51790e41e311de08 (diff) |
tdf#99784 OSX run GUI stuff in the main thread
The extension manager starts dialogs from its own thread. But the
OSX backend currently doesn't defer these calls to the main thread.
This implements the deference by running the called function
in the main thread, using a code ^Block, and returning the result
via a SalYieldMutex member.
Change-Id: Id8977991e3eda91da27c23d8021e028d4f4cefe5
Reviewed-on: https://gerrit.libreoffice.org/42448
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
Diffstat (limited to 'vcl/osx/salinst.cxx')
-rw-r--r-- | vcl/osx/salinst.cxx | 139 |
1 files changed, 99 insertions, 40 deletions
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 56dd7bef8feb..d33c0a33af25 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -46,6 +46,7 @@ #include "osx/salprn.h" #include "osx/saltimer.h" #include "osx/vclnsapp.h" +#include "osx/runinmain.hxx" #include "print.h" #include "impbmp.hxx" @@ -259,6 +260,7 @@ void InitSalMain() } SalYieldMutex::SalYieldMutex() + : m_aCodeBlock( nullptr ) { } @@ -266,6 +268,63 @@ SalYieldMutex::~SalYieldMutex() { } +void SalYieldMutex::doAcquire( sal_uInt32 nLockCount ) +{ + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if ( pInst && pInst->IsMainThread() ) + { + if ( pInst->mbNoYieldLock ) + return; + do { + m_aInMainCondition.reset(); + if ( m_aCodeBlock ) + { + assert( !pInst->mbNoYieldLock ); + pInst->mbNoYieldLock = true; + m_aCodeBlock(); + pInst->mbNoYieldLock = false; + Block_release( m_aCodeBlock ); + m_aCodeBlock = nullptr; + m_aResultCondition.set(); + } + // reset condition *before* acquiring! + if (m_aMutex.tryToAcquire()) + break; + // wait for doRelease() or RUNINMAIN_* to set the condition + osl::Condition::Result res = m_aInMainCondition.wait(); + assert(osl::Condition::Result::result_ok == res); + } + while ( true ); + } + else + m_aMutex.acquire(); + ++m_nCount; + --nLockCount; + + comphelper::GenericSolarMutex::doAcquire( nLockCount ); +} + +sal_uInt32 SalYieldMutex::doRelease( const bool bUnlockAll ) +{ + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if ( pInst->mbNoYieldLock && pInst->IsMainThread() ) + return 1; + sal_uInt32 nCount = comphelper::GenericSolarMutex::doRelease( bUnlockAll ); + + if ( 0 == m_nCount && !pInst->IsMainThread() ) + m_aInMainCondition.set(); + + return nCount; +} + +bool SalYieldMutex::IsCurrentThread() const +{ + if ( !GetSalData()->mpFirstInstance->mbNoYieldLock ) + return comphelper::GenericSolarMutex::IsCurrentThread(); + else + return GetSalData()->mpFirstInstance->IsMainThread(); +} + // some convenience functions regarding the yield mutex, aka solar mutex bool ImplSalYieldMutexTryToAcquire() @@ -315,15 +374,13 @@ void DestroySalInstance( SalInstance* pInst ) } AquaSalInstance::AquaSalInstance() - : maUserEventListMutex() - , maWaitingYieldCond() - , mbIsLiveResize( false ) + : mnActivePrintJobs( 0 ) + , mbIsLiveResize( false ) + , mbNoYieldLock( false ) { mpSalYieldMutex = new SalYieldMutex; mpSalYieldMutex->acquire(); maMainThread = osl::Thread::getCurrentIdentifier(); - mbWaitingYield = false; - mnActivePrintJobs = 0; } AquaSalInstance::~AquaSalInstance() @@ -332,21 +389,15 @@ AquaSalInstance::~AquaSalInstance() delete mpSalYieldMutex; } -void AquaSalInstance::wakeupYield() -{ - // wakeup :Yield - if( mbWaitingYield ) - ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, YES ); -} - void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData ) { { osl::MutexGuard g( maUserEventListMutex ); maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) ); } - // notify main loop that an event has arrived - wakeupYield(); + dispatch_async(dispatch_get_main_queue(),^{ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); + }); } comphelper::SolarMutex* AquaSalInstance::GetYieldMutex() @@ -465,7 +516,7 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) case YieldWakeupEvent: // do nothing, fall out of Yield - break; + break; default: OSL_FAIL( "unhandled NSApplicationDefined event" ); @@ -473,6 +524,14 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) }; } +static bool isWakeupEvent( NSEvent *pEvent ) +{ +SAL_WNODEPRECATED_DECLARATIONS_PUSH + return NSApplicationDefined == [pEvent type] + && AquaSalInstance::YieldWakeupEvent == (int) [pEvent subtype]; +SAL_WNODEPRECATED_DECLARATIONS_POP +} + bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased) { (void) nReleased; @@ -522,11 +581,6 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon // cocoa events may be only handled in the thread the NSApp was created if( IsMainThread() && mnActivePrintJobs == 0 ) { - // we need to be woken up by a cocoa-event - // if a user event should be posted by the event handling below - bool bOldWaitingYield = mbWaitingYield; - mbWaitingYield = bWait; - // handle available events NSEvent* pEvent = nil; do @@ -543,12 +597,17 @@ SAL_WNODEPRECATED_DECLARATIONS_POP if( pEvent ) { [NSApp sendEvent: pEvent]; + if ( isWakeupEvent( pEvent ) ) + continue; bHadEvent = true; } [NSApp updateWindows]; + + if ( !bHandleAllCurrentEvents || !pEvent ) + break; } - while( bHandleAllCurrentEvents && pEvent ); + while( true ); // if we had no event yet, wait for one if requested if( bWait && ! bHadEvent ) @@ -564,12 +623,14 @@ SAL_WNODEPRECATED_DECLARATIONS_POP inMode: NSDefaultRunLoopMode dequeue: YES]; if( pEvent ) + { [NSApp sendEvent: pEvent]; + if ( !isWakeupEvent( pEvent ) ) + bHadEvent = true; + } [NSApp updateWindows]; } - mbWaitingYield = bOldWaitingYield; - // collect update rectangles const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames ); for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) @@ -580,17 +641,17 @@ SAL_WNODEPRECATED_DECLARATIONS_POP (*it)->maInvalidRect.SetEmpty(); } } - maWaitingYieldCond.set(); + + if ( bHadEvent ) + maWaitingYieldCond.set(); } else if( bWait ) { // #i103162# - // wait until any thread (most likely the main thread) - // has dispatched an event, cop out at 200 ms + // wait until the main thread has dispatched an event maWaitingYieldCond.reset(); - TimeValue aVal = { 0, 200000000 }; SolarMutexReleaser aReleaser; - maWaitingYieldCond.wait( &aVal ); + maWaitingYieldCond.wait(); } // we get some apple events way too early @@ -629,6 +690,8 @@ bool AquaSalInstance::AnyInput( VclInputFlags nType ) return false; } + OSX_INST_RUNINMAIN_UNION( AnyInput( nType ), boolean ) + if( nType & VclInputFlags::TIMER ) { if( AquaSalTimer::pRunningTimer ) @@ -641,9 +704,6 @@ bool AquaSalInstance::AnyInput( VclInputFlags nType ) } } - if (!IsMainThread()) - return false; - unsigned/*NSUInteger*/ nEventMask = 0; SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSFlagsChangedMask' is deprecated: first deprecated in macOS 10.12 @@ -691,29 +751,28 @@ SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, SalFrameStyleFla SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nSalFrameStyle ) { - SalData::ensureThreadAutoreleasePool(); - - SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle ); - return pFrame; + OSX_INST_RUNINMAIN_POINTER( CreateFrame( pParent, nSalFrameStyle ), SalFrame* ) + return new AquaSalFrame( pParent, nSalFrameStyle ); } void AquaSalInstance::DestroyFrame( SalFrame* pFrame ) { + OSX_INST_RUNINMAIN( DestroyFrame( pFrame ) ) delete pFrame; } SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool /* bShow */ ) { - AquaSalObject *pObject = nullptr; - - if ( pParent ) - pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent), pWindowData ); + if ( !pParent ) + return nullptr; - return pObject; + OSX_INST_RUNINMAIN_POINTER( CreateObject( pParent, pWindowData, false ), SalObject* ) + return new AquaSalObject( static_cast<AquaSalFrame*>(pParent), pWindowData ); } void AquaSalInstance::DestroyObject( SalObject* pObject ) { + OSX_INST_RUNINMAIN( DestroyObject( pObject ) ) delete pObject; } |