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/inc | |
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/inc')
-rw-r--r-- | vcl/inc/osx/runinmain.hxx | 150 | ||||
-rw-r--r-- | vcl/inc/osx/salframe.h | 8 | ||||
-rw-r--r-- | vcl/inc/osx/salinst.h | 21 |
3 files changed, 171 insertions, 8 deletions
diff --git a/vcl/inc/osx/runinmain.hxx b/vcl/inc/osx/runinmain.hxx new file mode 100644 index 000000000000..e9ef9113d041 --- /dev/null +++ b/vcl/inc/osx/runinmain.hxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX +#define INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX + +/** + * Runs a command in the main thread. + * + * These macros are always used like a recursive calls, so they work like + * a closure. + * + * Uses two conditionals for a two way communication. + * The data (code block + result) is protected by the SolarMutex. + * + * There are three main macros, which act as function initializers: + * - OSX_RUNINMAIN - for all functions without return values + * - OSX_RUNINMAIN_POINTER - for all functions returning a pointer + * - OSX_RUNINMAIN_UNION - for all other return types + * + * All types used via OSX_RUNINMAIN_UNION must implement a move constructor, + * so there is no memory leak! + */ + +#include <unordered_map> + +#include <Block.h> + +#include <osl/thread.h> + +#include "saltimer.h" +#include "salframe.hxx" + +union RuninmainResult +{ + void* pointer; + bool boolean; + struct SalFrame::SalPointerState state; + + RuninmainResult() {} +}; + +#define OSX_RUNINMAIN_MEMBERS \ + osl::Condition m_aInMainCondition; \ + osl::Condition m_aResultCondition; \ + RuninmainBlock m_aCodeBlock; \ + RuninmainResult m_aResult; + +#define OSX_RUNINMAIN( instance, command ) \ + if ( !instance->IsMainThread() ) \ + { \ + DBG_TESTSOLARMUTEX(); \ + SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \ + assert( !aMutex->m_aCodeBlock ); \ + aMutex->m_aCodeBlock = Block_copy(^{ \ + command; \ + }); \ + aMutex->m_aResultCondition.reset(); \ + dispatch_async(dispatch_get_main_queue(),^{ \ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \ + }); \ + aMutex->m_aInMainCondition.set(); \ + osl::Condition::Result res = aMutex->m_aResultCondition.wait(); \ + assert(osl::Condition::Result::result_ok == res); \ + return; \ + } + +#define OSX_RUNINMAIN_POINTER( instance, command, type ) \ + if ( !instance->IsMainThread() ) \ + { \ + DBG_TESTSOLARMUTEX(); \ + SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \ + assert( !aMutex->m_aCodeBlock ); \ + aMutex->m_aCodeBlock = Block_copy(^{ \ + aMutex->m_aResult.pointer = static_cast<void*>( command ); \ + }); \ + aMutex->m_aResultCondition.reset(); \ + dispatch_async(dispatch_get_main_queue(),^{ \ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \ + }); \ + aMutex->m_aInMainCondition.set(); \ + osl::Condition::Result res = aMutex->m_aResultCondition.wait(); \ + assert(osl::Condition::Result::result_ok == res); \ + return static_cast<type>( aMutex->m_aResult.pointer ); \ + } + +#define OSX_RUNINMAIN_UNION( instance, command, member ) \ + if ( !instance->IsMainThread() ) \ + { \ + DBG_TESTSOLARMUTEX(); \ + SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \ + assert( !aMutex->m_aCodeBlock ); \ + aMutex->m_aCodeBlock = Block_copy(^{ \ + aMutex->m_aResult.member = command; \ + }); \ + aMutex->m_aResultCondition.reset(); \ + dispatch_async(dispatch_get_main_queue(),^{ \ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \ + }); \ + aMutex->m_aInMainCondition.set(); \ + osl::Condition::Result res = aMutex->m_aResultCondition.wait(); \ + assert(osl::Condition::Result::result_ok == res); \ + return std::move( aMutex->m_aResult.member ); \ + } + +/** + * convenience macros used from SalInstance + */ + +#define OSX_INST_RUNINMAIN( command ) \ + OSX_RUNINMAIN( this, command ) + +#define OSX_INST_RUNINMAIN_POINTER( command, type ) \ + OSX_RUNINMAIN_POINTER( this, command, type ) + +#define OSX_INST_RUNINMAIN_UNION( command, member ) \ + OSX_RUNINMAIN_UNION( this, command, member ) + +/** + * convenience macros using global SalData + */ + +#define OSX_SALDATA_RUNINMAIN( command ) \ + OSX_RUNINMAIN( GetSalData()->mpFirstInstance, command ) + +#define OSX_SALDATA_RUNINMAIN_POINTER( command, type ) \ + OSX_RUNINMAIN_POINTER( GetSalData()->mpFirstInstance, command, type ) + +#define OSX_SALDATA_RUNINMAIN_UNION( command, member ) \ + OSX_RUNINMAIN_UNION( GetSalData()->mpFirstInstance, command, member ) + +#endif // INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salframe.h b/vcl/inc/osx/salframe.h index 4b6d486f6be6..e99a3175876d 100644 --- a/vcl/inc/osx/salframe.h +++ b/vcl/inc/osx/salframe.h @@ -183,22 +183,22 @@ public: void VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen = true ); void CocoaToVCL( NSPoint& io_Point, bool bRelativeToScreen = true ); - NSCursor* getCurrentCursor() const; + NSCursor* getCurrentCursor(); CGMutablePathRef getClipPath() const { return mrClippingPath; } // called by VCL_NSApplication to indicate screen settings have changed void screenParametersChanged(); - private: // methods +private: // methods /** do things on initial show (like centering on parent or on screen) */ void initShow(); void initWindowAndView(); - private: // data - static AquaSalFrame* s_pCaptureFrame; +private: // data + static AquaSalFrame* s_pCaptureFrame; AquaSalFrame( const AquaSalFrame& ) = delete; AquaSalFrame& operator=(const AquaSalFrame&) = delete; diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index f1598a4f1040..1f456f737901 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -32,16 +32,31 @@ #endif #include "salinst.hxx" +#include "osx/runinmain.hxx" + class AquaSalFrame; +class SalFrame; +class SalObject; class ApplicationEvent; class Image; enum class SalEvent; +typedef void(^RuninmainBlock)(void); + class SalYieldMutex : public comphelper::GenericSolarMutex { public: + OSX_RUNINMAIN_MEMBERS + +protected: + virtual void doAcquire( sal_uInt32 nLockCount ) override; + virtual sal_uInt32 doRelease( bool bUnlockAll ) override; + +public: SalYieldMutex(); virtual ~SalYieldMutex() override; + + virtual bool IsCurrentThread() const override; }; class AquaSalInstance : public SalInstance @@ -61,12 +76,12 @@ public: SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex OUString maDefaultPrinter; oslThreadIdentifier maMainThread; - bool mbWaitingYield; int mnActivePrintJobs; std::list< SalUserEvent > maUserEvents; osl::Mutex maUserEventListMutex; osl::Condition maWaitingYieldCond; bool mbIsLiveResize; + bool mbNoYieldLock; static std::list<const ApplicationEvent*> aAppEventList; @@ -126,9 +141,7 @@ public: // this is needed to avoid duplicate open events through a) command line and b) NSApp's openFile static bool isOnCommandLine( const OUString& ); - void wakeupYield(); - - public: +public: friend class AquaSalFrame; void PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData ); |