Rebased ref, commits from common ancestor: commit 699189c70f959006aa88db6576996e34b81a7034 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Sep 5 18:54:49 2017 +0200
OSX revert fix for i#90083 Part of commit d6f7c94e5c27ba02ff5c3229760c9808cc9b5bea At least on my current OSX box application based window switching "just works" "out of the box", even without the code. With the replacement of the list with a set, the result is probably also a bit unexpected. Change-Id: I456503a74d8cddbd1e81b4a826b94381b424c78c diff --git a/vcl/inc/osx/vclnsapp.h b/vcl/inc/osx/vclnsapp.h index c899ffce59d1..39bd3170abaf 100644 --- a/vcl/inc/osx/vclnsapp.h +++ b/vcl/inc/osx/vclnsapp.h @@ -61,8 +61,6 @@ class AquaSalFrame; #endif -(BOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (BOOL)bWinVisible; -(void)setDockIconClickHandler: (NSObject*)pHandler; --(void)cycleFrameForward: (AquaSalFrame*)pCurFrame; --(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame; @end #endif // INCLUDED_VCL_INC_OSX_VCLNSAPP_H diff --git a/vcl/osx/vclnsapp.mm b/vcl/osx/vclnsapp.mm index 535286e698a6..337e92d4f0fe 100644 --- a/vcl/osx/vclnsapp.mm +++ b/vcl/osx/vclnsapp.mm @@ -136,24 +136,6 @@ SAL_WNODEPRECATED_DECLARATIONS_PUSH } } - // #i90083# handle frame switching - // FIXME: lousy workaround - if( (nModMask & (NSControlKeyMask|NSAlternateKeyMask)) == 0 ) - { - if( [[pEvent characters] isEqualToString: @"<"] || - [[pEvent characters] isEqualToString: @"~"] ) - { - [self cycleFrameForward: pFrame]; - return; - } - else if( [[pEvent characters] isEqualToString: @">"] || - [[pEvent characters] isEqualToString: @"`"] ) - { - [self cycleFrameBackward: pFrame]; - return; - } - } - // get information whether the event was handled; keyDown returns nothing GetSalData()->maKeyEventAnswer[ pEvent ] = false; bool bHandled = false; @@ -245,77 +227,6 @@ SAL_WNODEPRECATED_DECLARATIONS_POP [super sendEvent: pEvent]; } --(void)cycleFrameForward: (AquaSalFrame*)pCurFrame -{ - // find current frame in list - auto &rFrames( GetSalData()->mpFirstInstance->getFrames() ); - auto it = rFrames.find( pCurFrame ); - if( it != rFrames.end() ) - { - ++it; - // now find the next frame (or end) - for( ; it != rFrames.end(); ++it ) - { - auto pFrame = static_cast<const AquaSalFrame*>( *it ); - if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) - { - [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; - return; - } - } - // cycle around, find the next up to pCurFrame - for( it = rFrames.begin(); *it != pCurFrame; ++it ) - { - auto pFrame = static_cast<const AquaSalFrame*>( *it ); - if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) - { - [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; - return; - } - } - } -} - -template< class Iterator > -std::reverse_iterator<Iterator> make_reverse_iterator( Iterator i ) -{ - return std::reverse_iterator<Iterator>(i); -} - --(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame -{ - // do the same as cycleFrameForward only with a reverse iterator - - // find current frame in list - auto &rFrames( GetSalData()->mpFirstInstance->getFrames() ); - auto search_it = rFrames.find( pCurFrame ); - if( search_it != rFrames.end() ) - { - auto it = ::make_reverse_iterator( search_it ); - ++it; - // now find the next frame (or end) - for( ; it != rFrames.rend(); ++it ) - { - auto pFrame = static_cast<const AquaSalFrame*>( *it ); - if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) - { - [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; - return; - } - } - // cycle around, find the next up to pCurFrame - for( it = rFrames.rbegin(); *it != pCurFrame; ++it ) - { - auto pFrame = static_cast<const AquaSalFrame*>( *it ); - if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) - { - [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; - return; - } - } - } -} - -(NSMenu*)applicationDockMenu:(NSApplication *)sender { (void)sender; commit f5a16666e9dfad228936fb5282b47b9ba29608d8 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Mon Sep 4 17:40:13 2017 +0200 Unify SalUserEvent handling Change-Id: I188b567e44fd79c162b2d9cabbd771d1f66c7dc4 diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 1a2105877de5..d76567776b42 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -321,6 +321,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/app/help \ vcl/source/app/i18nhelp \ vcl/source/app/idle \ + vcl/source/app/salusereventlist \ vcl/source/app/salvtables \ vcl/source/app/scheduler \ vcl/source/app/session \ diff --git a/vcl/headless/svpframe.cxx b/vcl/headless/svpframe.cxx index 9a086c0b3d6a..08c6a09ef834 100644 --- a/vcl/headless/svpframe.cxx +++ b/vcl/headless/svpframe.cxx @@ -94,10 +94,9 @@ SvpSalFrame::~SvpSalFrame() // pass focus to another frame, preferably a document style window if( s_pFocusFrame == nullptr ) { - const std::list< SalFrame* >& rFrames( m_pInstance->getFrames() ); - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + for (auto pSalFrame : m_pInstance->getFrames() ) { - SvpSalFrame* pFrame = static_cast<SvpSalFrame*>(*it); + SvpSalFrame* pFrame = static_cast<SvpSalFrame*>( const_cast<SalFrame*>( pSalFrame ) ); if( pFrame->m_bVisible && pFrame->m_pParent == nullptr && (pFrame->m_nStyle & (SalFrameStyleFlags::MOVEABLE | diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 8a805ea345b1..5153c8952f4a 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -47,19 +47,6 @@ // FIXME: remove when we re-work the svp mainloop #include "unx/salunxtime.h" -bool SvpSalInstance::isFrameAlive( const SalFrame* pFrame ) const -{ - for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin(); - it != m_aFrames.end(); ++it ) - { - if( *it == pFrame ) - { - return true; - } - } - return false; -} - SvpSalInstance* SvpSalInstance::s_pDefaultInstance = nullptr; #if !defined(ANDROID) && !defined(IOS) @@ -165,12 +152,8 @@ void SvpSalInstance::CreateWakeupPipe(bool log) #endif -void SvpSalInstance::PostEvent(const SalFrame* pFrame, ImplSVEvent* pData, SalEvent nEvent) +void SvpSalInstance::TriggerUserEventProcessing() { - { - osl::MutexGuard g(m_aEventGuard); - m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) ); - } Wakeup(); } @@ -186,31 +169,6 @@ bool SvpSalInstance::PostedEventsInQueue() } #endif -void SvpSalInstance::deregisterFrame( SalFrame* pFrame ) -{ - m_aFrames.remove( pFrame ); - - osl::MutexGuard g(m_aEventGuard); - // cancel outstanding events for this frame - if( ! m_aUserEvents.empty() ) - { - std::list< SalUserEvent >::iterator it = m_aUserEvents.begin(); - do - { - if( it->m_pFrame == pFrame ) - { - if (it->m_nEvent == SalEvent::UserEvent) - { - delete it->m_pData; - } - it = m_aUserEvents.erase( it ); - } - else - ++it; - } while( it != m_aUserEvents.end() ); - } -} - void SvpSalInstance::Wakeup() { #ifndef IOS @@ -304,44 +262,24 @@ SalBitmap* SvpSalInstance::CreateSalBitmap() #endif } -bool SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) +void SvpSalInstance::ProcessEvent( SalUserEvent aEvent ) { - // first, check for already queued events. - std::list< SalUserEvent > aEvents; + aEvent.m_pFrame->CallCallback( aEvent.m_nEvent, aEvent.m_pData ); + if( aEvent.m_nEvent == SalEvent::Resize ) { - osl::MutexGuard g(m_aEventGuard); - if( ! m_aUserEvents.empty() ) - { - if( bHandleAllCurrentEvents ) - { - aEvents = m_aUserEvents; - m_aUserEvents.clear(); - } - else - { - aEvents.push_back( m_aUserEvents.front() ); - m_aUserEvents.pop_front(); - } - } + // this would be a good time to post a paint + const SvpSalFrame* pSvpFrame = static_cast<const SvpSalFrame*>( aEvent.m_pFrame); + pSvpFrame->PostPaint(); } +} - bool bEvent = !aEvents.empty(); - if( bEvent ) - { - for( std::list<SalUserEvent>::const_iterator it = aEvents.begin(); it != aEvents.end(); ++it ) - { - if ( isFrameAlive( it->m_pFrame ) ) - { - it->m_pFrame->CallCallback( it->m_nEvent, it->m_pData ); - if( it->m_nEvent == SalEvent::Resize ) - { - // this would be a good time to post a paint - const SvpSalFrame* pSvpFrame = static_cast<const SvpSalFrame*>(it->m_pFrame); - pSvpFrame->PostPaint(); - } - } - } - } + +bool SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) +{ + // first, process current user events + bool bEvent = DispatchUserEvents( bHandleAllCurrentEvents ); + if ( !bHandleAllCurrentEvents &&bEvent ) + return true; bEvent = CheckTimeout() || bEvent; diff --git a/vcl/headless/svpprn.cxx b/vcl/headless/svpprn.cxx index 92a11e99d03a..eb9b322a9de5 100644 --- a/vcl/headless/svpprn.cxx +++ b/vcl/headless/svpprn.cxx @@ -257,10 +257,9 @@ OUString SvpSalInstance::GetDefaultPrinter() void SvpSalInstance::PostPrintersChanged() { - const std::list< SalFrame* >& rList = SvpSalInstance::s_pDefaultInstance->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rList.begin(); - it != rList.end(); ++it ) - SvpSalInstance::s_pDefaultInstance->PostEvent( *it, nullptr, SalEvent::PrinterChanged ); + SvpSalInstance *pInst = SvpSalInstance::s_pDefaultInstance; + for (auto pSalFrame : pInst->getFrames() ) + pInst->PostEvent( const_cast<SalFrame*>( pSalFrame ), nullptr, SalEvent::PrinterChanged ); } GenPspGraphics *SvpSalInstance::CreatePrintGraphics() diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx index 0883981c4406..a411315c761d 100644 --- a/vcl/inc/headless/svpinst.hxx +++ b/vcl/inc/headless/svpinst.hxx @@ -25,6 +25,7 @@ #include <salinst.hxx> #include <salwtype.hxx> #include <saltimer.hxx> +#include <salusereventlist.hxx> #include <unx/geninst.h> #include <unx/genprn.h> @@ -57,35 +58,18 @@ class GenPspGraphics; SalInstance* svp_create_SalInstance(); -class VCL_DLLPUBLIC SvpSalInstance : public SalGenericInstance +class VCL_DLLPUBLIC SvpSalInstance : public SalGenericInstance, public SalUserEventList { timeval m_aTimeout; sal_uLong m_nTimeoutMS; int m_pTimeoutFDS[2]; - // internal event queue - struct SalUserEvent - { - const SalFrame* m_pFrame; - ImplSVEvent* m_pData; - SalEvent m_nEvent; - - SalUserEvent( const SalFrame* pFrame, ImplSVEvent* pData, SalEvent nEvent ) - : m_pFrame( pFrame ), - m_pData( pData ), - m_nEvent( nEvent ) - {} - }; - - osl::Mutex m_aEventGuard; - std::list< SalUserEvent > m_aUserEvents; - - std::list< SalFrame* > m_aFrames; - - bool isFrameAlive( const SalFrame* pFrame ) const; - void DoReleaseYield( int nTimeoutMS ); + virtual void TriggerUserEventProcessing() override; + virtual void ProcessEvent( SalUserEvent aEvent ) override; + void Wakeup(); + public: static SvpSalInstance* s_pDefaultInstance; @@ -95,20 +79,15 @@ public: void CloseWakeupPipe(bool log); void CreateWakeupPipe(bool log); - void PostEvent(const SalFrame* pFrame, ImplSVEvent* pData, SalEvent nEvent); - #ifdef ANDROID bool PostedEventsInQueue(); #endif void StartTimer( sal_uLong nMS ); void StopTimer(); - void Wakeup(); - void registerFrame( SalFrame* pFrame ) { m_aFrames.push_back( pFrame ); } - void deregisterFrame( SalFrame* pFrame ); - const std::list< SalFrame* >& - getFrames() const { return m_aFrames; } + inline void registerFrame( const SalFrame* pFrame ); + inline void deregisterFrame( const SalFrame* pFrame ); bool CheckTimeout( bool bExecuteTimers = true ); @@ -171,6 +150,16 @@ public: virtual GenPspGraphics *CreatePrintGraphics() override; }; +inline void SvpSalInstance::registerFrame( const SalFrame* pFrame ) +{ + insertFrame( pFrame ); +} + +inline void SvpSalInstance::deregisterFrame( const SalFrame* pFrame ) +{ + eraseFrame( pFrame ); +} + #endif // INCLUDED_VCL_INC_HEADLESS_SVPINST_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/saldata.hxx b/vcl/inc/osx/saldata.hxx index 1cbdabb88563..6ca1adb235c5 100644 --- a/vcl/inc/osx/saldata.hxx +++ b/vcl/inc/osx/saldata.hxx @@ -47,6 +47,7 @@ #include "osx/runinmain.hxx" +class AquaSalFrame; class AquaSalInstance; class SalObject; class SalFrame; @@ -56,7 +57,6 @@ class SystemFontList; #define SAL_CLIPRECT_COUNT 16 -class AquaSalFrame; struct FrameHash : public std::hash<sal_IntPtr> { size_t operator()(const AquaSalFrame* frame) const @@ -73,8 +73,6 @@ class SalData public: SALTIMERPROC mpTimerProc; // timer callback proc AquaSalInstance *mpFirstInstance; // pointer of first instance - std::list<AquaSalFrame*> maFrames; // list of all frames - std::unordered_set<const AquaSalFrame*,FrameHash> maFrameCheck;// for fast check of frame existence std::list<AquaSalFrame*> maPresentationFrames; // list of frames in presentation mode SalObject *mpFirstObject; // pointer of first object window SalVirtualDevice *mpFirstVD; // first VirDev diff --git a/vcl/inc/osx/salframe.h b/vcl/inc/osx/salframe.h index 307356c76caa..5d46c136bcfe 100644 --- a/vcl/inc/osx/salframe.h +++ b/vcl/inc/osx/salframe.h @@ -26,6 +26,7 @@ #include <vcl/sysdata.hxx> +#include "osx/salinst.h" #include "osx/salmenu.h" #include "osx/saldata.hxx" #include "osx/osxvcltypes.h" @@ -164,8 +165,7 @@ public: // trigger painting of the window void SendPaintEvent( const tools::Rectangle* pRect = nullptr ); - static bool isAlive( const AquaSalFrame* pFrame ) - { return GetSalData()->maFrameCheck.find( pFrame ) != GetSalData()->maFrameCheck.end(); } + static inline bool isAlive( const AquaSalFrame* pFrame ); static AquaSalFrame* GetCaptureFrame() { return s_pCaptureFrame; } @@ -205,6 +205,12 @@ private: // data AquaSalFrame& operator=(const AquaSalFrame&) = delete; }; +inline bool AquaSalFrame::isAlive( const AquaSalFrame* pFrame ) +{ + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + return pInst && pInst->isFrameAlive( pFrame ); +} + #endif // INCLUDED_VCL_INC_OSX_SALFRAME_H /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index aa88ac02d5fd..5e8d08d228ba 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -34,6 +34,8 @@ #include "osx/runinmain.hxx" +#include "salusereventlist.hxx" + class AquaSalFrame; class SalFrame; class SalObject; @@ -59,27 +61,18 @@ public: virtual bool IsCurrentThread() const override; }; -class AquaSalInstance : public SalInstance +class AquaSalInstance : public SalInstance, public SalUserEventList { - struct SalUserEvent - { - AquaSalFrame* mpFrame; - void* mpData; - SalEvent mnType; - - SalUserEvent( AquaSalFrame* pFrame, void* pData, SalEvent nType ) : - mpFrame( pFrame ), mpData( pData ), mnType( nType ) - {} - }; - bool RunInMainYield( bool bHandleAllCurrentEvents ); + virtual void TriggerUserEventProcessing() override; + virtual void ProcessEvent( SalUserEvent aEvent ) override; + public: SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex OUString maDefaultPrinter; oslThreadIdentifier maMainThread; int mnActivePrintJobs; - std::list< SalUserEvent > maUserEvents; osl::Mutex maUserEventListMutex; osl::Condition maWaitingYieldCond; bool mbIsLiveResize; @@ -145,7 +138,6 @@ public: public: friend class AquaSalFrame; - void PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData ); void delayedSettingsChanged( bool bInvalidate ); // Is this the NSAppThread? diff --git a/vcl/inc/salusereventlist.hxx b/vcl/inc/salusereventlist.hxx new file mode 100644 index 000000000000..5165294fa387 --- /dev/null +++ b/vcl/inc/salusereventlist.hxx @@ -0,0 +1,118 @@ +/* -*- 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_SALUSEREVENTLIST_HXX +#define INCLUDED_VCL_INC_SALUSEREVENTLIST_HXX + +#include <sal/config.h> +#include <vcl/dllapi.h> +#include <osl/mutex.hxx> + +#include <assert.h> + +#include <list> +#include <set> + +class SalFrame; +enum class SalEvent; + +class VCL_PLUGIN_PUBLIC SalUserEventList +{ +public: + struct SalUserEvent + { + SalFrame* m_pFrame; + void* m_pData; + SalEvent m_nEvent; + + SalUserEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) + : m_pFrame( pFrame ), + m_pData( pData ), + m_nEvent( nEvent ) + {} + + bool operator==(const SalUserEvent &aEvent) const + { + return m_pFrame == aEvent.m_pFrame + && m_pData == aEvent.m_pData + && m_nEvent== aEvent.m_nEvent; + } + }; + +protected: + mutable osl::Mutex m_aUserEventsMutex; + std::list< SalUserEvent > m_aUserEvents; + std::list< SalUserEvent > m_aProcessingUserEvents; + std::set< const SalFrame* > m_aFrames; + const SalFrame * m_pFirstFrame; + + virtual void ProcessEvent( SalUserEvent aEvent ) = 0; + virtual void TriggerUserEventProcessing() = 0; + +public: + SalUserEventList(); + virtual ~SalUserEventList(); + + inline const std::set< const SalFrame* >& getFrames() const; + inline SalFrame* firstFrame() const; + void insertFrame( const SalFrame* pFrame ); + void eraseFrame( const SalFrame* pFrame ); + inline bool isFrameAlive( const SalFrame* pFrame ) const; + + void PostEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ); + bool RemoveEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ); + inline bool HasUserEvents() const; + + bool DispatchUserEvents( bool bHandleAllCurrentEvents ); +}; + +inline SalFrame* SalUserEventList::firstFrame() const +{ + return const_cast<SalFrame*>( m_pFirstFrame ); +} + +inline bool SalUserEventList::isFrameAlive( const SalFrame* pFrame ) const +{ + auto it = m_aFrames.find( pFrame ); + return it != m_aFrames.end(); +} + +inline bool SalUserEventList::HasUserEvents() const +{ + osl::MutexGuard aGuard( m_aUserEventsMutex ); + return !(m_aUserEvents.empty() && m_aProcessingUserEvents.empty()); +} + +inline void SalUserEventList::PostEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) +{ + { + osl::MutexGuard aGuard( m_aUserEventsMutex ); + m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) ); + } + TriggerUserEventProcessing(); +} + +inline const std::set< const SalFrame* >& SalUserEventList::getFrames() const +{ + return m_aFrames; +} + +#endif // INCLUDED_VCL_INC_SALUSEREVENTLIST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gendisp.hxx b/vcl/inc/unx/gendisp.hxx index 64564237a232..13f1247e20d3 100644 --- a/vcl/inc/unx/gendisp.hxx +++ b/vcl/inc/unx/gendisp.hxx @@ -27,45 +27,27 @@ #include <vcl/dllapi.h> #include <list> #include <vector> +#include <salusereventlist.hxx> class SalFrame; -class VCL_DLLPUBLIC SalGenericDisplay +class VCL_DLLPUBLIC SalGenericDisplay : public SalUserEventList { - mutable osl::Mutex m_aEventGuard; - struct SalUserEvent - { - SalFrame* m_pFrame; - void* m_pData; - SalEvent m_nEvent; - - SalUserEvent( SalFrame* pFrame, void* pData, - SalEvent nEvent ) - : m_pFrame( pFrame ), - m_pData( pData ), - m_nEvent( nEvent ) - {} - }; - std::list< SalUserEvent > m_aUserEvents; protected: SalFrame* m_pCapture; - std::list<SalFrame*> m_aFrames; + + virtual void ProcessEvent( SalUserEvent aEvent ) override; + public: SalGenericDisplay(); - virtual ~SalGenericDisplay(); + virtual ~SalGenericDisplay() override; - osl::Mutex& getEventGuardMutex() { return m_aEventGuard; } - - void registerFrame( SalFrame* pFrame ); - virtual void deregisterFrame( SalFrame* pFrame ); + void registerFrame( const SalFrame* pFrame ); + virtual void deregisterFrame( const SalFrame* pFrame ); void emitDisplayChanged(); - // Event handling - virtual void PostUserEvent() = 0; - void SendInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent = SalEvent::UserEvent ); - void CancelInternalEvent( SalFrame const * pFrame, void const * pData, SalEvent nEvent ); + void CancelInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ); bool DispatchInternalEvent(); - bool HasUserEvents() const; bool MouseCaptured( const SalFrame *pFrameData ) const { return m_pCapture == pFrameData; } diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx index 60a0940d9439..45d1564043da 100644 --- a/vcl/inc/unx/gtk/gtkdata.hxx +++ b/vcl/inc/unx/gtk/gtkdata.hxx @@ -111,7 +111,7 @@ public: static gboolean userEventFn( gpointer data ); - void PostUserEvent(); + void TriggerUserEventProcessing(); bool Yield( bool bWait, bool bHandleAllCurrentEvents ); inline GdkDisplay *GetGdkDisplay(); @@ -138,6 +138,9 @@ class GtkSalDisplay : public SalDisplay GdkCursor* getFromXBM( const unsigned char *pBitmap, const unsigned char *pMask, int nWidth, int nHeight, int nXHot, int nYHot ); + + void WakeupMainLoop(); + public: GtkSalDisplay( GdkDisplay* pDisplay ); virtual ~GtkSalDisplay() override; @@ -149,7 +152,7 @@ public: GtkWidget* findGtkWidgetForNativeHandle(sal_uIntPtr hWindow) const; - virtual void deregisterFrame( SalFrame* pFrame ) override; + virtual void deregisterFrame( const SalFrame* pFrame ) override; GdkCursor *getCursor( PointerStyle ePointerStyle ); #if GTK_CHECK_VERSION(3,0,0) virtual int CaptureMouse( SalFrame* pFrame ); @@ -172,7 +175,7 @@ public: void screenSizeChanged( GdkScreen const * ); void monitorsChanged( GdkScreen const * ); - virtual void PostUserEvent() override; + virtual void TriggerUserEventProcessing() override; #if !GTK_CHECK_VERSION(3,0,0) virtual bool Dispatch( XEvent *pEvent ) override; diff --git a/vcl/inc/unx/saldisp.hxx b/vcl/inc/unx/saldisp.hxx index 2c23d6010c35..72f3a43df371 100644 --- a/vcl/inc/unx/saldisp.hxx +++ b/vcl/inc/unx/saldisp.hxx @@ -168,7 +168,7 @@ public: virtual bool Yield( bool bWait, bool bHandleAllCurrentEvents ); virtual void Wakeup(); - virtual void PostUserEvent(); + void TriggerUserEventProcessing(); virtual void Insert( int fd, void* data, YieldFunc pending, @@ -371,12 +371,10 @@ public: { return getDataForScreen( nXScreen ).m_aRoot; } unsigned int GetXScreenCount() const { return m_aScreens.size(); } - const std::list< SalFrame* >& getFrames() const { return m_aFrames; } + const std::set< const SalFrame* >& getFrames() const { return m_aFrames; } bool IsNumLockFromXS() const { return bNumLockFromXS_; } std::list< SalObject* >& getSalObjects() { return m_aSalObjects; } - - virtual void PostUserEvent() override = 0; }; inline Display *SalColormap::GetXDisplay() const @@ -390,7 +388,7 @@ public: virtual bool Dispatch( XEvent *pEvent ) override; virtual void Yield(); - virtual void PostUserEvent() override; + virtual void TriggerUserEventProcessing() override; bool IsEvent(); void SetupInput(); diff --git a/vcl/osx/salframe.cxx b/vcl/osx/salframe.cxx index e54073cdf4f1..dcdfe6d9c936 100644 --- a/vcl/osx/salframe.cxx +++ b/vcl/osx/salframe.cxx @@ -87,8 +87,7 @@ AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle initWindowAndView(); SalData* pSalData = GetSalData(); - pSalData->maFrames.push_front( this ); - pSalData->maFrameCheck.insert( this ); + pSalData->mpFirstInstance->insertFrame( this ); } AquaSalFrame::~AquaSalFrame() @@ -106,8 +105,7 @@ AquaSalFrame::~AquaSalFrame() [SalFrameView unsetMouseFrame: this]; SalData* pSalData = GetSalData(); - pSalData->maFrames.remove( this ); - pSalData->maFrameCheck.erase( this ); + pSalData->mpFirstInstance->eraseFrame( this ); pSalData->maPresentationFrames.remove( this ); SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" ); @@ -296,7 +294,7 @@ void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics ) bool AquaSalFrame::PostEvent(ImplSVEvent* pData) { - GetSalData()->mpFirstInstance->PostUserEvent( this, SalEvent::UserEvent, pData ); + GetSalData()->mpFirstInstance->PostEvent( this, pData, SalEvent::UserEvent ); return TRUE; } diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 118400f7c45a..5c913e14ee25 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -79,7 +79,8 @@ static bool bLeftMain = false; class AquaDelayedSettingsChanged : public Idle { bool mbInvalidate; - public: + +public: AquaDelayedSettingsChanged( bool bInvalidate ) : mbInvalidate( bInvalidate ) { @@ -87,20 +88,19 @@ class AquaDelayedSettingsChanged : public Idle virtual void Invoke() override { - SalData* pSalData = GetSalData(); - if( ! pSalData->maFrames.empty() ) - pSalData->maFrames.front()->CallCallback( SalEvent::SettingsChanged, nullptr ); + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if( pInst->firstFrame() ) + pInst->firstFrame()->CallCallback( SalEvent::SettingsChanged, nullptr ); if( mbInvalidate ) { - for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin(); - it != pSalData->maFrames.end(); ++it ) + for( auto pSalFrame : pInst->getFrames() ) { - if( (*it)->mbShown ) - (*it)->SendPaintEvent(); + AquaSalFrame* pFrame = static_cast<AquaSalFrame*>( const_cast<SalFrame*>( pSalFrame ) ); + if( pFrame->mbShown ) + pFrame->SendPaintEvent(); } } - Stop(); delete this; } }; @@ -389,17 +389,19 @@ AquaSalInstance::~AquaSalInstance() delete mpSalYieldMutex; } -void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData ) +void AquaSalInstance::TriggerUserEventProcessing() { - { - osl::MutexGuard g( maUserEventListMutex ); - maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) ); - } dispatch_async(dispatch_get_main_queue(),^{ ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); }); } +void AquaSalInstance::ProcessEvent( SalUserEvent aEvent ) +{ + aEvent.m_pFrame->CallCallback( aEvent.m_nEvent, aEvent.m_pData ); + maWaitingYieldCond.set(); +} + comphelper::SolarMutex* AquaSalInstance::GetYieldMutex() { return mpSalYieldMutex; @@ -452,15 +454,17 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) case AppleRemoteControlEvent: // Defined in <apple_remote/RemoteMainController.h> { MediaCommand nCommand; - SalData* pSalData = GetSalData(); + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; bool bIsFullScreenMode = false; - std::list<AquaSalFrame*>::iterator it = pSalData->maFrames.begin(); - while( it != pSalData->maFrames.end() ) + for( auto pSalFrame : pInst->getFrames() ) { - if ( (*it) && (*it)->mbFullScreen ) + const AquaSalFrame* pFrame = static_cast<const AquaSalFrame*>( pSalFrame ); + if ( pFrame->mbFullScreen ) + { bIsFullScreenMode = true; - ++it; + break; + } } switch ([pEvent data1]) @@ -496,9 +500,8 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) default: break; } - AquaSalFrame* pFrame = pSalData->maFrames.front(); + AquaSalFrame* pFrame = static_cast<AquaSalFrame*>( pInst->firstFrame() ); vcl::Window* pWindow = pFrame ? pFrame->GetWindow() : nullptr; - if( pWindow ) { const Point aPoint; @@ -531,10 +534,16 @@ bool AquaSalInstance::RunInMainYield( bool bHandleAllCurrentEvents ) return false; } -bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) +static bool isWakeupEvent( NSEvent *pEvent ) { - bool bHadEvent = false; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + return NSApplicationDefined == [pEvent type] + && AquaSalInstance::YieldWakeupEvent == (int) [pEvent subtype]; +SAL_WNODEPRECATED_DECLARATIONS_POP +} +bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) +{ // ensure that the per thread autorelease pool is top level and // will therefore not be destroyed by cocoa implicitly SalData::ensureThreadAutoreleasePool(); @@ -543,36 +552,10 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) // an own pool for each yield level ReleasePoolHolder aReleasePool; - // Release all locks so that we don't deadlock when we pull pending - // events from the event queue - bool bDispatchUser = true; - while( bDispatchUser ) - { - // get one user event - SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE ); - { - osl::MutexGuard g( maUserEventListMutex ); - if( ! maUserEvents.empty() ) - { - aEvent = maUserEvents.front(); - maUserEvents.pop_front(); - bHadEvent = true; - } - else - bDispatchUser = false; - } - - // dispatch it - if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) ) - { - aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); - maWaitingYieldCond.set(); - } - - // return if only one event is asked for - if( !bHandleAllCurrentEvents && bDispatchUser ) - return true; - } + // first, process current user events + bool bHadEvent = DispatchUserEvents( bHandleAllCurrentEvents ); + if ( !bHandleAllCurrentEvents && bHadEvent ) + return true; // handle cocoa event queue // cocoa events may be only handled in the thread the NSApp was created @@ -632,13 +615,13 @@ SAL_WNODEPRECATED_DECLARATIONS_POP } // collect update rectangles - const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames ); - for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + for( auto pSalFrame : GetSalData()->mpFirstInstance->getFrames() ) { - if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() ) + AquaSalFrame* pFrame = static_cast<AquaSalFrame*>( const_cast<SalFrame*>( pSalFrame ) ); + if( pFrame->mbShown && ! pFrame->maInvalidRect.IsEmpty() ) { - (*it)->Flush( (*it)->maInvalidRect ); - (*it)->maInvalidRect.SetEmpty(); + pFrame->Flush( pFrame->maInvalidRect ); + pFrame->maInvalidRect.SetEmpty(); } } diff --git a/vcl/osx/vclnsapp.mm b/vcl/osx/vclnsapp.mm index 651fa2a014cc..535286e698a6 100644 --- a/vcl/osx/vclnsapp.mm +++ b/vcl/osx/vclnsapp.mm @@ -248,77 +248,70 @@ SAL_WNODEPRECATED_DECLARATIONS_POP -(void)cycleFrameForward: (AquaSalFrame*)pCurFrame { // find current frame in list - std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames ); - std::list< AquaSalFrame* >::iterator it = rFrames.begin(); - for( ; it != rFrames.end() && *it != pCurFrame; ++it ) - ; + auto &rFrames( GetSalData()->mpFirstInstance->getFrames() ); + auto it = rFrames.find( pCurFrame ); if( it != rFrames.end() ) { + ++it; // now find the next frame (or end) - do + for( ; it != rFrames.end(); ++it ) { - ++it; - if( it != rFrames.end() ) + auto pFrame = static_cast<const AquaSalFrame*>( *it ); + if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) { - if( (*it)->mpDockMenuEntry != nullptr && - (*it)->mbShown ) - { - [(*it)->getNSWindow() makeKeyAndOrderFront: NSApp]; - return; - } + [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; + return; } - } while( it != rFrames.end() ); + } // cycle around, find the next up to pCurFrame - it = rFrames.begin(); - while( *it != pCurFrame ) + for( it = rFrames.begin(); *it != pCurFrame; ++it ) { - if( (*it)->mpDockMenuEntry != nullptr && - (*it)->mbShown ) + auto pFrame = static_cast<const AquaSalFrame*>( *it ); + if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) { - [(*it)->getNSWindow() makeKeyAndOrderFront: NSApp]; + [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; return; } - ++it; } } } +template< class Iterator > +std::reverse_iterator<Iterator> make_reverse_iterator( Iterator i ) +{ + return std::reverse_iterator<Iterator>(i); +} + -(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame { // do the same as cycleFrameForward only with a reverse iterator // find current frame in list - std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames ); - std::list< AquaSalFrame* >::reverse_iterator it = rFrames.rbegin(); - for( ; it != rFrames.rend() && *it != pCurFrame; ++it ) - ; - if( it != rFrames.rend() ) + auto &rFrames( GetSalData()->mpFirstInstance->getFrames() ); + auto search_it = rFrames.find( pCurFrame ); + if( search_it != rFrames.end() ) { + auto it = ::make_reverse_iterator( search_it ); + ++it; // now find the next frame (or end) - do + for( ; it != rFrames.rend(); ++it ) { - ++it; - if( it != rFrames.rend() ) + auto pFrame = static_cast<const AquaSalFrame*>( *it ); + if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) { - if( (*it)->mpDockMenuEntry != nullptr && - (*it)->mbShown ) - { - [(*it)->getNSWindow() makeKeyAndOrderFront: NSApp]; - return; - } + [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; + return; } - } while( it != rFrames.rend() ); + } // cycle around, find the next up to pCurFrame - it = rFrames.rbegin(); - while( *it != pCurFrame ) + for( it = rFrames.rbegin(); *it != pCurFrame; ++it ) { - if( (*it)->mpDockMenuEntry != nullptr && - (*it)->mbShown ) + auto pFrame = static_cast<const AquaSalFrame*>( *it ); + if( pFrame->mpDockMenuEntry != nullptr && pFrame->mbShown ) { - [(*it)->getNSWindow() makeKeyAndOrderFront: NSApp]; + [pFrame->getNSWindow() makeKeyAndOrderFront: NSApp]; return; } - ++it; } } } @@ -413,12 +406,12 @@ SAL_WNODEPRECATED_DECLARATIONS_POP { SolarMutexGuard aGuard; - SalData* pSalData = GetSalData(); - if( ! pSalData->maFrames.empty() ) + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if( pInst->firstFrame() ) { // the following QueryExit will likely present a message box, activate application [NSApp activateIgnoringOtherApps: YES]; - aReply = pSalData->maFrames.front()->CallCallback( SalEvent::Shutdown, nullptr ) ? NSTerminateCancel : NSTerminateNow; + aReply = pInst->firstFrame()->CallCallback( SalEvent::Shutdown, nullptr ) ? NSTerminateCancel : NSTerminateNow; } if( aReply == NSTerminateNow ) @@ -439,9 +432,9 @@ SAL_WNODEPRECATED_DECLARATIONS_POP (void)pNotification; SolarMutexGuard aGuard; - const SalData* pSalData = GetSalData(); - if( !pSalData->maFrames.empty() ) - pSalData->maFrames.front()->CallCallback( SalEvent::SettingsChanged, nullptr ); + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if( pInst->firstFrame() ) + pInst->firstFrame()->CallCallback( SalEvent::SettingsChanged, nullptr ); } -(void)screenParametersChanged: (NSNotification*) pNotification @@ -449,11 +442,10 @@ SAL_WNODEPRECATED_DECLARATIONS_POP (void)pNotification; SolarMutexGuard aGuard; - SalData* pSalData = GetSalData(); - std::list< AquaSalFrame* >::iterator it; - for( it = pSalData->maFrames.begin(); it != pSalData->maFrames.end(); ++it ) + for( auto pSalFrame : GetSalData()->mpFirstInstance->getFrames() ) { - (*it)->screenParametersChanged(); + AquaSalFrame *pFrame = static_cast<AquaSalFrame*>( const_cast<SalFrame*>( pSalFrame ) ); + pFrame->screenParametersChanged(); } } diff --git a/vcl/quartz/salvd.cxx b/vcl/quartz/salvd.cxx index 3110398b8784..68d18870a44e 100644 --- a/vcl/quartz/salvd.cxx +++ b/vcl/quartz/salvd.cxx @@ -255,19 +255,10 @@ bool AquaSalVirtualDevice::SetSize( long nDX, long nDY ) AquaSalFrame* pSalFrame = mpGraphics->getGraphicsFrame(); if( !pSalFrame || !AquaSalFrame::isAlive( pSalFrame )) { - if( !GetSalData()->maFrames.empty() ) - { - // get the first matching frame - pSalFrame = *GetSalData()->maFrames.begin(); - } - else - { - // ensure we don't reuse a dead AquaSalFrame on the very - // unlikely case of no other frame to use - pSalFrame = nullptr; - } - // update the frame reference - mpGraphics->setGraphicsFrame( pSalFrame ); + pSalFrame = static_cast<AquaSalFrame*>( GetSalData()->mpFirstInstance->firstFrame() ); + if ( pSalFrame ) + // update the frame reference + mpGraphics->setGraphicsFrame( pSalFrame ); } if( pSalFrame ) { diff --git a/vcl/source/app/salusereventlist.cxx b/vcl/source/app/salusereventlist.cxx new file mode 100644 index 000000000000..1630b1e4d014 --- /dev/null +++ b/vcl/source/app/salusereventlist.cxx @@ -0,0 +1,121 @@ +/* -*- 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 . + */ + +#include <salusereventlist.hxx> +#include <salwtype.hxx> + +#include <algorithm> + +SalUserEventList::SalUserEventList() + : m_pFirstFrame( nullptr ) +{ +} + +SalUserEventList::~SalUserEventList() +{ +} + +void SalUserEventList::insertFrame( const SalFrame* pFrame ) +{ + auto aPair = m_aFrames.insert( pFrame ); + assert( aPair.second ); (void) aPair; + if ( nullptr == m_pFirstFrame ) + m_pFirstFrame = pFrame; +} + +void SalUserEventList::eraseFrame( const SalFrame* pFrame ) +{ + auto it = m_aFrames.find( pFrame ); + assert( it != m_aFrames.end() ); + if ( it != m_aFrames.end() ) + { + if ( it == m_aFrames.begin() ) + m_pFirstFrame = nullptr; + m_aFrames.erase( it ); + if ( !m_aFrames.empty() ) + m_pFirstFrame = *m_aFrames.begin(); + } +} + +bool SalUserEventList::DispatchUserEvents( bool bHandleAllCurrentEvents ) +{ + bool bWasEvent = false; + + { + osl::MutexGuard aGuard( m_aUserEventsMutex ); + if( ! m_aUserEvents.empty() ) + { + if( bHandleAllCurrentEvents ) + m_aProcessingUserEvents.swap( m_aUserEvents ); + else + { + m_aProcessingUserEvents.push_back( m_aUserEvents.front() ); + m_aUserEvents.pop_front(); + } + bWasEvent = true; + } + } + + if( bWasEvent ) + { + SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE ); + do { + { + osl::MutexGuard aGuard( m_aUserEventsMutex ); + if ( m_aProcessingUserEvents.empty() ) + break; + aEvent = m_aProcessingUserEvents.front(); + m_aProcessingUserEvents.pop_front(); + } + + if ( isFrameAlive( aEvent.m_pFrame ) ) + ProcessEvent( aEvent ); + } + while( true ); + } + + return bWasEvent; +} + +bool SalUserEventList::RemoveEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) +{ + SalUserEvent aEvent( pFrame, pData, nEvent ); + bool bResult = false; + + osl::MutexGuard aGuard( m_aUserEventsMutex ); + auto it = std::find( m_aUserEvents.begin(), m_aUserEvents.end(), aEvent ); + if ( it != m_aUserEvents.end() ) + { + m_aUserEvents.erase( it ); + bResult = true; + } + else + { + it = std::find( m_aProcessingUserEvents.begin(), m_aProcessingUserEvents.end(), aEvent ); + if ( it != m_aProcessingUserEvents.end() ) + { + m_aProcessingUserEvents.erase( it ); + bResult = true; + } + } + + return bResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/app/gendisp.cxx b/vcl/unx/generic/app/gendisp.cxx index c1cd5a23112e..87b9c14585b5 100644 --- a/vcl/unx/generic/app/gendisp.cxx +++ b/vcl/unx/generic/app/gendisp.cxx @@ -22,7 +22,6 @@ #include <unx/geninst.h> SalGenericDisplay::SalGenericDisplay() - : m_aEventGuard() { m_pCapture = nullptr; } @@ -31,96 +30,40 @@ SalGenericDisplay::~SalGenericDisplay() { } -void SalGenericDisplay::registerFrame( SalFrame* pFrame ) +void SalGenericDisplay::registerFrame( const SalFrame* pFrame ) { - m_aFrames.push_front( pFrame ); + insertFrame( pFrame ); } -void SalGenericDisplay::deregisterFrame( SalFrame* pFrame ) +void SalGenericDisplay::deregisterFrame( const SalFrame* pFrame ) { - { - osl::MutexGuard g( m_aEventGuard ); - std::list< SalUserEvent >::iterator it = m_aUserEvents.begin(); - while ( it != m_aUserEvents.end() ) - { - if( it->m_pFrame == pFrame ) - { - if (it->m_nEvent == SalEvent::UserEvent) { - delete static_cast<ImplSVEvent *>(it->m_pData); - } - it = m_aUserEvents.erase( it ); - } - else - ++it; - } - } - - m_aFrames.remove( pFrame ); + eraseFrame( pFrame ); } void SalGenericDisplay::emitDisplayChanged() { - if( !m_aFrames.empty() ) - m_aFrames.front()->CallCallback( SalEvent::DisplayChanged, nullptr ); + if( m_pFirstFrame ) + m_pFirstFrame->CallCallback( SalEvent::DisplayChanged, nullptr ); } bool SalGenericDisplay::DispatchInternalEvent() { - void* pData = nullptr; - SalFrame* pFrame = nullptr; - SalEvent nEvent = SalEvent::NONE; - - { - osl::MutexGuard g( m_aEventGuard ); - if( !m_aUserEvents.empty() ) - { - pFrame = m_aUserEvents.front().m_pFrame; - pData = m_aUserEvents.front().m_pData; - nEvent = m_aUserEvents.front().m_nEvent; - - m_aUserEvents.pop_front(); - } - } - - if( pFrame ) - pFrame->CallCallback( nEvent, pData ); - - return pFrame != nullptr; + return DispatchUserEvents( false ); } void SalGenericDisplay::SendInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) { - osl::MutexGuard g( m_aEventGuard ); - - m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) ); - - PostUserEvent(); // wakeup the concrete mainloop + PostEvent( pFrame, pData, nEvent ); } -void SalGenericDisplay::CancelInternalEvent( SalFrame const * pFrame, void const * pData, SalEvent nEvent ) +void SalGenericDisplay::CancelInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) { - osl::MutexGuard g( m_aEventGuard ); - if( ! m_aUserEvents.empty() ) - { - std::list< SalUserEvent >::iterator it = m_aUserEvents.begin(); - while (it != m_aUserEvents.end()) - { - if( it->m_pFrame == pFrame && - it->m_pData == pData && - it->m_nEvent == nEvent ) - { - it = m_aUserEvents.erase( it ); - } - else - ++it; - } - } + RemoveEvent( pFrame, pData, nEvent ); } -bool SalGenericDisplay::HasUserEvents() const +void SalGenericDisplay::ProcessEvent( SalUserEvent aEvent ) { - osl::MutexGuard g( m_aEventGuard ); - return !m_aUserEvents.empty(); + aEvent.m_pFrame->CallCallback( aEvent.m_nEvent, aEvent.m_pData ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/app/i18n_status.cxx b/vcl/unx/generic/app/i18n_status.cxx index cca11999e6b6..f6ea79399c9e 100644 --- a/vcl/unx/generic/app/i18n_status.cxx +++ b/vcl/unx/generic/app/i18n_status.cxx @@ -170,12 +170,9 @@ bool XIMStatusWindow::checkLastParent() const { if( m_pLastParent ) { - const std::list< SalFrame* >& rFrames = vcl_sal::getSalDisplay(GetGenericData())->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) - { - if( *it == m_pLastParent ) - return true; - } + auto rFrameList = vcl_sal::getSalDisplay(GetGenericData())->getFrames(); + auto it = rFrameList.find( m_pLastParent ); + return it != rFrameList.end(); } return false; } diff --git a/vcl/unx/generic/app/saldata.cxx b/vcl/unx/generic/app/saldata.cxx index fb5131473e5a..007162a17b36 100644 --- a/vcl/unx/generic/app/saldata.cxx +++ b/vcl/unx/generic/app/saldata.cxx @@ -786,7 +786,7 @@ void SalXLib::Wakeup() OSL_VERIFY(write (m_pTimeoutFDS[1], "", 1) == 1); } -void SalXLib::PostUserEvent() +void SalXLib::TriggerUserEventProcessing() { Wakeup(); } diff --git a/vcl/unx/generic/app/saldisp.cxx b/vcl/unx/generic/app/saldisp.cxx index 73d63086bec6..326d68f5adde 100644 --- a/vcl/unx/generic/app/saldisp.cxx +++ b/vcl/unx/generic/app/saldisp.cxx @@ -431,10 +431,10 @@ SalX11Display::~SalX11Display() } } -void SalX11Display::PostUserEvent() +void SalX11Display::TriggerUserEventProcessing() { if( pXLib_ ) - pXLib_->PostUserEvent(); + pXLib_->TriggerUserEventProcessing(); } SalDisplay::ScreenData * @@ -1935,17 +1935,16 @@ bool SalX11Display::Dispatch( XEvent *pEvent ) { ::Window aWindow = pEvent->xkey.window; - std::list< SalFrame* >::const_iterator it; - for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it ) + for (auto pSalFrame : m_aFrames ) { - const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it); + const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame ); if( pFrame->GetWindow() == aWindow || pFrame->GetShellWindow() == aWindow ) { aWindow = pFrame->GetWindow(); break; } } - if( it != m_aFrames.end() ) + if( aWindow != pEvent->xkey.window ) { if ( pInputMethod && pInputMethod->FilterEvent( pEvent , aWindow ) ) return false; @@ -1975,9 +1974,8 @@ bool SalX11Display::Dispatch( XEvent *pEvent ) { if( pEvent->xproperty.window == rScreen.m_aRefWindow ) { - std::list< SalFrame* >::const_iterator it; - for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it ) - (*it)->CallCallback( SalEvent::SettingsChanged, nullptr ); + for (auto pSalFrame : m_aFrames ) + pSalFrame->CallCallback( SalEvent::SettingsChanged, nullptr ); return false; } } @@ -2009,10 +2007,10 @@ bool SalX11Display::Dispatch( XEvent *pEvent ) break; } - std::list< SalFrame* >::iterator it; - for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it ) + for (auto pSalFrame : m_aFrames ) { - X11SalFrame* pFrame = static_cast< X11SalFrame* >(*it); + X11SalFrame* pFrame = static_cast<X11SalFrame*>( const_cast<SalFrame*>( pSalFrame ) ); + ::Window aDispatchWindow = pEvent->xany.window; if( pFrame->GetWindow() == aDispatchWindow || pFrame->GetShellWindow() == aDispatchWindow diff --git a/vcl/unx/generic/app/salinst.cxx b/vcl/unx/generic/app/salinst.cxx index 897d955ddccb..c306f6a78f70 100644 --- a/vcl/unx/generic/app/salinst.cxx +++ b/vcl/unx/generic/app/salinst.cxx @@ -225,10 +225,8 @@ void X11SalInstance::AddToRecentDocumentList(const OUString& rFileUrl, const OUS void X11SalInstance::PostPrintersChanged() { SalDisplay* pDisp = vcl_sal::getSalDisplay(GetGenericData()); - const std::list< SalFrame* >& rList = pDisp->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rList.begin(); - it != rList.end(); ++it ) - pDisp->SendInternalEvent( *it, nullptr, SalEvent::PrinterChanged ); + for (auto pSalFrame : pDisp->getFrames() ) + pDisp->PostEvent( const_cast<SalFrame*>( pSalFrame ), nullptr, SalEvent::PrinterChanged ); } GenPspGraphics *X11SalInstance::CreatePrintGraphics() diff --git a/vcl/unx/generic/app/sm.cxx b/vcl/unx/generic/app/sm.cxx index b86435fbaf73..5d6bf68edd7f 100644 --- a/vcl/unx/generic/app/sm.cxx +++ b/vcl/unx/generic/app/sm.cxx @@ -293,10 +293,9 @@ IMPL_STATIC_LINK( SessionManagerClient, SaveYourselfHdl, void*, pStateVal, void task of the quick-starter) */ *pSmRestartHint = SmRestartNever; - const std::list< SalFrame* >& rFrames = vcl_sal::getSalDisplay(GetGenericData())->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + for (auto pSalFrame : vcl_sal::getSalDisplay(GetGenericData())->getFrames() ) { - vcl::Window *pWindow = (*it)->GetWindow(); + vcl::Window *pWindow = pSalFrame->GetWindow(); if (pWindow && pWindow->IsVisible()) { *pSmRestartHint = SmRestartIfRunning; @@ -394,11 +393,10 @@ IMPL_STATIC_LINK_NOARG( SessionManagerClient, ShutDownHdl, void*, void ) m_pSession->CallCallback( &aEvent ); } - const std::list< SalFrame* >& rFrames = vcl_sal::getSalDisplay(GetGenericData())->getFrames(); - - SAL_INFO("vcl.sm.debug", " rFrames.empty() = " << (rFrames.empty() ? "true" : "false")); - if( !rFrames.empty() ) - rFrames.front()->CallCallback( SalEvent::Shutdown, nullptr ); + auto pFirstFrame = vcl_sal::getSalDisplay(GetGenericData())->firstFrame(); + SAL_INFO("vcl.sm.debug", " rFrames.empty() = " << (pFirstFrame ? "true" : "false")); + if( pFirstFrame ) + pFirstFrame->CallCallback( SalEvent::Shutdown, nullptr ); } void SessionManagerClient::DieProc( diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx index 4e9219505069..0d726f59466a 100644 --- a/vcl/unx/generic/gdi/salgdi2.cxx +++ b/vcl/unx/generic/gdi/salgdi2.cxx @@ -127,12 +127,11 @@ void X11SalGraphics::YieldGraphicsExpose() ::Window aWindow = GetDrawable(); if( ! pFrame ) { - const std::list< SalFrame* >& rFrames = vcl_sal::getSalDisplay(GetGenericData())->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end() && ! pFrame; ++it ) + for (auto pSalFrame : vcl_sal::getSalDisplay(GetGenericData())->getFrames() ) { - const SystemEnvData* pEnvData = (*it)->GetSystemData(); + const SystemEnvData* pEnvData = pSalFrame->GetSystemData(); if( Drawable(pEnvData->aWindow) == aWindow ) - pFrame = *it; + pFrame = const_cast<SalFrame*>( pSalFrame ); } if( ! pFrame ) return; diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx index f8baf9b0742e..2bc836d6afe5 100644 --- a/vcl/unx/generic/window/salframe.cxx +++ b/vcl/unx/generic/window/salframe.cxx @@ -492,15 +492,14 @@ void X11SalFrame::Init( SalFrameStyleFlags nSalFrameStyle, SalX11Screen nXScreen // check if this is really one of our own frames // do not change the input mask in that case - const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames(); - std::list< SalFrame* >::const_iterator it = rFrames.begin(); - while( it != rFrames.end() && mhForeignParent != static_cast<const X11SalFrame*>(*it)->GetWindow() ) - ++it; - - if( it == rFrames.end() ) + for (auto pSalFrame : GetDisplay()->getFrames() ) { - XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask ); - XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask ); + if ( static_cast<const X11SalFrame*>( pSalFrame )->GetWindow() == mhForeignParent ) + { + XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask ); + XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask ); + break; + } } } else @@ -521,11 +520,9 @@ void X11SalFrame::Init( SalFrameStyleFlags nSalFrameStyle, SalX11Screen nXScreen { // find the last document window (if any) const X11SalFrame* pFrame = nullptr; - const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames(); - std::list< SalFrame* >::const_iterator it = rFrames.begin(); - while( it != rFrames.end() ) + for (auto pSalFrame : GetDisplay()->getFrames() ) { - pFrame = static_cast< const X11SalFrame* >(*it); + pFrame = static_cast< const X11SalFrame* >( pSalFrame ); if( ! ( pFrame->mpParent || pFrame->mbFullScreen || ! ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE ) @@ -534,10 +531,9 @@ void X11SalFrame::Init( SalFrameStyleFlags nSalFrameStyle, SalX11Screen nXScreen ) ) break; - ++it; } - if( it != rFrames.end() ) + if( pFrame ) { // set a document position and size // the first frame gets positioned by the window manager @@ -954,13 +950,12 @@ X11SalFrame::~X11SalFrame() * check if there is only the status frame left * if so, free it */ - if( ! GetDisplay()->getFrames().empty() && vcl::I18NStatus::exists() ) + auto &rFrames = GetDisplay()->getFrames(); + if( ! rFrames.empty() && vcl::I18NStatus::exists() ) { SalFrame* pStatusFrame = vcl::I18NStatus::get().getStatusFrame(); - std::list< SalFrame* >::const_iterator sit = GetDisplay()->getFrames().begin(); - if( pStatusFrame - && *sit == pStatusFrame - && ++sit == GetDisplay()->getFrames().end() ) + auto sit = rFrames.begin(); + if( pStatusFrame && *sit == pStatusFrame && ++sit == rFrames.end() ) vcl::I18NStatus::free(); } } @@ -1204,10 +1199,9 @@ void X11SalFrame::Show( bool bVisible, bool bNoActivate ) if( ! (nStyle_ & SalFrameStyleFlags::INTRO) ) { // hide all INTRO frames - const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + for (auto pSalFrame : GetDisplay()->getFrames() ) { - const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it); + const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame ); // look for intro bit map; if present, hide it if( pFrame->nStyle_ & SalFrameStyleFlags::INTRO ) { @@ -2698,10 +2692,9 @@ bool X11SalFrame::HandleMouseEvent( XEvent *pEvent ) // see if the user clicks outside all of the floats // if yes release the grab bool bInside = false; - const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + for (auto pSalFrame : GetDisplay()->getFrames() ) { - const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it); + const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame ); if( pFrame->IsFloatGrabWindow() && pFrame->bMapped_ && pEvent->xbutton.x_root >= pFrame->maGeometry.nX && @@ -2738,9 +2731,9 @@ bool X11SalFrame::HandleMouseEvent( XEvent *pEvent ) && aChild // pointer may not be in any child ) { - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + for (auto pSalFrame : GetDisplay()->getFrames() ) { - const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it); + const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame ); if( ! pFrame->IsFloatGrabWindow() && ( pFrame->GetWindow() == aChild || pFrame->GetShellWindow() == aChild || diff --git a/vcl/unx/gtk/gtkdata.cxx b/vcl/unx/gtk/gtkdata.cxx index bcbce082ef29..5f6a30f35479 100644 --- a/vcl/unx/gtk/gtkdata.cxx +++ b/vcl/unx/gtk/gtkdata.cxx @@ -135,17 +135,16 @@ GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event ) // actually change when a corresponding PropertyNotify occurs if( pEvent->type == PropertyNotify && pEvent->xproperty.atom == getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) && - ! m_aFrames.empty() + m_pFirstFrame ) { - SendInternalEvent( m_aFrames.front(), nullptr, SalEvent::SettingsChanged ); + PostEvent( firstFrame(), nullptr, SalEvent::SettingsChanged ); } // let's see if one of our frames wants to swallow these events // get the frame - for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin(); - it != m_aFrames.end(); ++it ) + for (auto pSalFrame : m_aFrames ) { - GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(*it); + GtkSalFrame* pFrame = static_cast<GtkSalFrame*>( const_cast<SalFrame*>( pSalFrame ) ); if( pFrame->GetSystemData()->aWindow == pEvent->xany.window || ( pFrame->getForeignParent() && pFrame->getForeignParentWindow() == pEvent->xany.window ) || ( pFrame->getForeignTopLevel() && pFrame->getForeignTopLevelWindow() == pEvent->xany.window ) @@ -213,11 +212,10 @@ bool GtkSalDisplay::Dispatch( XEvent* pEvent ) { // let's see if one of our frames wants to swallow these events // get the child frame - for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin(); - it != m_aFrames.end(); ++it ) + for (auto pSalFrame : m_aFrames ) { - if ((*it)->GetSystemData()->aWindow == pEvent->xany.window) - return static_cast<GtkSalFrame*>(*it)->Dispatch( pEvent ); + if (pSalFrame->GetSystemData()->aWindow == pEvent->xany.window) + return static_cast<GtkSalFrame*>( const_cast<SalFrame*>( pSalFrame ) )->Dispatch( pEvent ); } } @@ -826,8 +824,7 @@ gboolean GtkData::userEventFn( gpointer data ) { OSL_ASSERT(static_cast<const SalGenericDisplay *>(pThis->GetGtkDisplay()) == pDisplay); { - osl::MutexGuard g (pThis->GetGtkDisplay()->getEventGuardMutex()); - + osl::MutexGuard g( pThis->m_aDispatchMutex ); if( !pThis->GetGtkDisplay()->HasUserEvents() ) { if( pThis->m_pUserEvent ) @@ -855,8 +852,9 @@ extern "C" { } // hEventGuard_ held during this invocation -void GtkData::PostUserEvent() +void GtkData::TriggerUserEventProcessing() { + osl::MutexGuard g( m_aDispatchMutex ); if (m_pUserEvent) g_main_context_wakeup (nullptr); // really needed ? else // nothing pending anyway @@ -870,16 +868,15 @@ void GtkData::PostUserEvent() } } -void GtkSalDisplay::PostUserEvent() +void GtkSalDisplay::TriggerUserEventProcessing() { - GetGtkSalData()->PostUserEvent(); + GetGtkSalData()->TriggerUserEventProcessing(); } GtkWidget* GtkSalDisplay::findGtkWidgetForNativeHandle(sal_uIntPtr hWindow) const { - for (auto it = m_aFrames.begin(); it != m_aFrames.end(); ++it) + for (auto pFrame : m_aFrames) { - SalFrame* pFrame = *it; const SystemEnvData* pEnvData = pFrame->GetSystemData(); if (pEnvData->aWindow == hWindow) return GTK_WIDGET(pEnvData->pWidget); @@ -887,7 +884,7 @@ GtkWidget* GtkSalDisplay::findGtkWidgetForNativeHandle(sal_uIntPtr hWindow) cons return nullptr; } -void GtkSalDisplay::deregisterFrame( SalFrame* pFrame ) +void GtkSalDisplay::deregisterFrame( const SalFrame* pFrame ) { if( m_pCapture == pFrame ) { diff --git a/vcl/unx/gtk/gtksalframe.cxx b/vcl/unx/gtk/gtksalframe.cxx index 8bd532eea78c..ab011854fdb9 100644 --- a/vcl/unx/gtk/gtksalframe.cxx +++ b/vcl/unx/gtk/gtksalframe.cxx @@ -2180,10 +2180,9 @@ void GtkSalFrame::grabPointer( bool bGrab, bool bOwnerEvents ) if( bGrab ) { bool bUseGdkGrab = true; - const std::list< SalFrame* >& rFrames = getDisplay()->getFrames(); - for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + for (auto pSalFrame : getDisplay()->getFrames() ) { - const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it); + const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >( pSalFrame ); if( pFrame->m_bWindowIsGtkPlug ) { bUseGdkGrab = false; diff --git a/vcl/unx/gtk3/gtk3gtkdata.cxx b/vcl/unx/gtk3/gtk3gtkdata.cxx index 77048114c2d0..2a6440b8ce61 100644 --- a/vcl/unx/gtk3/gtk3gtkdata.cxx +++ b/vcl/unx/gtk3/gtk3gtkdata.cxx @@ -788,8 +788,7 @@ gboolean GtkData::userEventFn( gpointer data ) { OSL_ASSERT(static_cast<const SalGenericDisplay *>(pThis->GetGtkDisplay()) == pDisplay); { - osl::MutexGuard g (pThis->GetGtkDisplay()->getEventGuardMutex()); - + osl::MutexGuard g( pThis->m_aDispatchMutex ); if( !pThis->GetGtkDisplay()->HasUserEvents() ) { if( pThis->m_pUserEvent ) @@ -817,8 +816,9 @@ extern "C" { } // hEventGuard_ held during this invocation -void GtkData::PostUserEvent() +void GtkData::TriggerUserEventProcessing() { + osl::MutexGuard g( m_aDispatchMutex ); if (m_pUserEvent) g_main_context_wakeup (nullptr); // really needed ? else // nothing pending anyway @@ -832,24 +832,23 @@ void GtkData::PostUserEvent() } } -void GtkSalDisplay::PostUserEvent() +void GtkSalDisplay::TriggerUserEventProcessing() { - GetGtkSalData()->PostUserEvent(); + GetGtkSalData()->TriggerUserEventProcessing(); } GtkWidget* GtkSalDisplay::findGtkWidgetForNativeHandle(sal_uIntPtr hWindow) const { - for (auto it = m_aFrames.begin(); it != m_aFrames.end(); ++it) + for (auto pSalFrame : m_aFrames ) { - SalFrame* pFrame = *it; - const SystemEnvData* pEnvData = pFrame->GetSystemData(); + const SystemEnvData* pEnvData = pSalFrame->GetSystemData(); if (pEnvData->aWindow == hWindow) return GTK_WIDGET(pEnvData->pWidget); } return nullptr; } -void GtkSalDisplay::deregisterFrame( SalFrame* pFrame ) +void GtkSalDisplay::deregisterFrame( const SalFrame* pFrame ) { if( m_pCapture == pFrame ) { diff --git a/vcl/unx/kde4/KDESalDisplay.cxx b/vcl/unx/kde4/KDESalDisplay.cxx index 4647b3d111c8..8a2422a3918d 100644 --- a/vcl/unx/kde4/KDESalDisplay.cxx +++ b/vcl/unx/kde4/KDESalDisplay.cxx @@ -86,4 +86,9 @@ bool SalKDEDisplay::checkDirectInputEvent( XEvent* ev ) return false; } +void SalKDEDisplay::TriggerUserEventProcessing() +{ + static_cast<KDEXLib*>(GetXLib())->TriggerUserEventProcessing(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalDisplay.hxx b/vcl/unx/kde4/KDESalDisplay.hxx index 4a0458dcc5c2..07b5ca3dadf5 100644 --- a/vcl/unx/kde4/KDESalDisplay.hxx +++ b/vcl/unx/kde4/KDESalDisplay.hxx @@ -23,15 +23,18 @@ class SalKDEDisplay : public SalX11Display { - public: - explicit SalKDEDisplay( Display* pDisp ); - virtual ~SalKDEDisplay() override; - static SalKDEDisplay* self(); - virtual void Yield() override; - bool checkDirectInputEvent( XEvent* ev ); - private: - Atom xim_protocol; - static SalKDEDisplay* selfptr; + Atom xim_protocol; + static SalKDEDisplay* selfptr; + +protected: + virtual void TriggerUserEventProcessing() override; + +public: + explicit SalKDEDisplay( Display* pDisp ); + virtual ~SalKDEDisplay() override; + static SalKDEDisplay* self(); + virtual void Yield() override; + bool checkDirectInputEvent( XEvent* ev ); }; inline SalKDEDisplay* SalKDEDisplay::self() diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx index d56c67e008cb..17920e276869 100644 --- a/vcl/unx/kde4/KDEXLib.cxx +++ b/vcl/unx/kde4/KDEXLib.cxx @@ -357,10 +357,10 @@ void KDEXLib::Wakeup() QAbstractEventDispatcher::instance( qApp->thread())->wakeUp(); // main thread event loop } -void KDEXLib::PostUserEvent() +void KDEXLib::TriggerUserEventProcessing() { if( !m_isGlibEventLoopType ) - return SalXLib::PostUserEvent(); + return SalXLib::TriggerUserEventProcessing(); QApplication::postEvent(this, new QEvent(QEvent::Type( m_postUserEventId ))); } diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx index 2fe497d019fa..4c06104b4c59 100644 --- a/vcl/unx/kde4/KDEXLib.hxx +++ b/vcl/unx/kde4/KDEXLib.hxx @@ -83,7 +83,7 @@ class KDEXLib : public QObject, public SalXLib virtual void StartTimer( sal_uLong nMS ) override; virtual void StopTimer() override; virtual void Wakeup() override; - virtual void PostUserEvent() override; + void TriggerUserEventProcessing(); void doStartup(); bool allowKdeDialogs() { return m_allowKdeDialogs; } commit 531d88b39dac4ac830ce5b8c0542ef0570a8c8f4 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 29 10:29:51 2017 +0200 Unify Reschedule implementation and usage Application::Reschedule(true) should process just all currently pending events and ignore all newly generated events when processing them. This way we also can drop nMaxEvents from the Windows backend. This limit was also never implemented on OSX and for the KDE4 backend it's actually impossible to handle single events. Also changes various call sites to just process all pending events instead of some made of number of times. Change-Id: I1ab95df89b079cc8c6319a808194fe3127144d1c diff --git a/cui/source/dialogs/cuigaldlg.cxx b/cui/source/dialogs/cuigaldlg.cxx index 599ec984b70f..598496f1d0e5 100644 --- a/cui/source/dialogs/cuigaldlg.cxx +++ b/cui/source/dialogs/cuigaldlg.cxx @@ -483,8 +483,7 @@ IMPL_LINK( ActualizeProgress, TimeoutHdl, Timer*, _pTimer, void) IMPL_LINK( ActualizeProgress, ActualizeHdl, const INetURLObject&, rURL, void ) { - for( long i = 0; i < 128; i++ ) - Application::Reschedule(); + Application::Reschedule( true ); Flush(); diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx index 5c9d8f0d0d6e..2d422c6e9678 100644 --- a/include/vcl/scheduler.hxx +++ b/include/vcl/scheduler.hxx @@ -53,7 +53,16 @@ public: static void CallbackTaskScheduling(); /// Process one pending task ahead of time with highest priority. static bool ProcessTaskScheduling(); - /// Process all events until we are idle + /** + * Process all events until none is pending + * + * This can busy-lock, if some task or system event always generates new + * events when being processed. Most time it's called in unit tests to + * process all pending events. Internally it just calls + * Application::Reschedule( true ) until it fails. + * + * @see Application::Reschedule + */ static void ProcessEventsToIdle(); /** * Process events until the parameter turns true, diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index d6e186350424..cdb3c2c150ac 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -466,17 +466,19 @@ public: /** Attempt to process current pending event(s) It doesn't sleep if no events are available for processing. + This doesn't processs any events generated after invoking the function. + So in contrast to Scheduler::ProcessEventsToIdle, this cannot be + dead-locked by event loops. - @param bAllEvents If set to true, then try to process all the - events. If set to false, then only process the current - event. Defaults to false. + @param bHandleAllCurrentEvents If set to true, then try to process all + the current events. If set to false, then only process one event. + Defaults to false. @returns true if any event was processed. - @see Execute, Quit, Yield, EndYield, GetSolarMutex, - GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex, + @see Yield, Scheduler::ProcessEventsToIdle */ - static bool Reschedule( bool bAllEvents = false ); + static bool Reschedule( bool bHandleAllCurrentEvents = false ); /** Process the next event. diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx index fd9c71197ded..1f56bba58179 100644 --- a/sc/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx @@ -1400,7 +1400,6 @@ void ScTiledRenderingTest::testDisableUndoRepair() pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::RETURN); pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::RETURN); Scheduler::ProcessEventsToIdle(); - Scheduler::ProcessEventsToIdle(); { SfxItemSet aSet1(pView1->GetPool(), svl::Items<SID_UNDO, SID_UNDO>{}); SfxItemSet aSet2(pView2->GetPool(), svl::Items<SID_UNDO, SID_UNDO>{}); diff --git a/svx/source/form/fmsrcimp.cxx b/svx/source/form/fmsrcimp.cxx index eb05a3676639..1cdc2df30255 100644 --- a/svx/source/form/fmsrcimp.cxx +++ b/svx/source/form/fmsrcimp.cxx @@ -311,13 +311,7 @@ FmSearchEngine::SearchResult FmSearchEngine::SearchSpecial(bool _bSearchForNull, bool bMovedAround(false); do { - Application::Reschedule(); - Application::Reschedule(); - // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event - // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings - // or anything like that. So within each loop we create one user event and handle one user event (and no - // paintings and these), so the office seems to be frozen while searching. - // FS - 70226 - 02.12.99 + Application::Reschedule( true ); // the content to be compared currently iterFieldLoop->xContents->getString(); // needed for wasNull @@ -376,13 +370,7 @@ FmSearchEngine::SearchResult FmSearchEngine::SearchWildcard(const OUString& strE bool bMovedAround(false); do { - Application::Reschedule(); - Application::Reschedule(); - // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event - // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings - // or anything like that. So within each loop we create one user event and handle one user event (and no - // paintings and these), so the office seems to be frozen while searching. - // FS - 70226 - 02.12.99 + Application::Reschedule( true ); // the content to be compared currently OUString sCurrentCheck; @@ -476,13 +464,7 @@ FmSearchEngine::SearchResult FmSearchEngine::SearchRegularApprox(const OUString& bool bMovedAround(false); do { - Application::Reschedule(); - Application::Reschedule(); - // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event - // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings - // or anything like that. So within each loop we create one user event and handle one user event (and no - // paintings and these), so the office seems to be frozen while searching. - // FS - 70226 - 02.12.99 + Application::Reschedule( true ); // the content to be compared currently OUString sCurrentCheck; diff --git a/sw/source/ui/dbui/addresslistdialog.cxx b/sw/source/ui/dbui/addresslistdialog.cxx index 96c77cd9edd7..3b88cac4dc0e 100644 --- a/sw/source/ui/dbui/addresslistdialog.cxx +++ b/sw/source/ui/dbui/addresslistdialog.cxx @@ -487,8 +487,7 @@ IMPL_LINK(SwAddressListDialog, StaticListBoxSelectHdl_Impl, void*, p, void) m_pListLB->SetEntryText(m_sConnecting, pSelect, ITEMID_TABLE - 1); // allow painting of the new entry m_pListLB->Window::Invalidate(InvalidateFlags::Update); - for (int i = 0; i < 10; ++i) - Application::Reschedule(); + Application::Reschedule( true ); } pUserData = static_cast<AddressUserData_Impl*>(pSelect->GetUserData()); diff --git a/sw/source/ui/dbui/mmresultdialogs.cxx b/sw/source/ui/dbui/mmresultdialogs.cxx index 1c3f17b4b52a..628c244b17d4 100644 --- a/sw/source/ui/dbui/mmresultdialogs.cxx +++ b/sw/source/ui/dbui/mmresultdialogs.cxx @@ -719,8 +719,7 @@ IMPL_LINK(SwMMResultSaveDialog, SaveOutputHdl_Impl, Button*, pButton, void) while(true) { //time for other slots is needed - for(sal_Int16 r = 0; r < 10; ++r) - Application::Reschedule(); + Application::Reschedule( true ); bool bFailed = false; try { @@ -1088,8 +1087,7 @@ IMPL_LINK(SwMMResultEmailDialog, SendDocumentsHdl_Impl, Button*, pButton, void) //help to force painting the dialog //TODO/CLEANUP //predetermined breaking point - for ( sal_Int16 i = 0; i < 25; i++) - Application::Reschedule(); + Application::Reschedule( true ); for(sal_uInt32 nDoc = nBegin; nDoc < nEnd; ++nDoc) { SwDocMergeInfo& rInfo = xConfigItem->GetDocumentMergeInfo(nDoc); @@ -1231,8 +1229,7 @@ IMPL_LINK(SwMMResultEmailDialog, SendDocumentsHdl_Impl, Button*, pButton, void) aDesc.sBCC = m_sBCC; pDlg->AddDocument( aDesc ); //help to force painting the dialog - for ( sal_Int16 i = 0; i < 25; i++) - Application::Reschedule(); + Application::Reschedule( true ); //stop creating of data when dialog has been closed if(!pDlg->IsVisible()) { diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx index a08a6a923cdc..a481985738ac 100644 --- a/sw/source/uibase/dbui/dbmgr.cxx +++ b/sw/source/uibase/dbui/dbmgr.cxx @@ -147,11 +147,6 @@ using namespace ::com::sun::star; namespace { -void rescheduleGui() { - for( sal_uInt16 i = 0; i < 25; i++) - Application::Reschedule(); -} - void lcl_emitEvent(SfxEventHintId nEventId, sal_Int32 nStrId, SfxObjectShell* pDocShell) { SfxGetpApp()->NotifyEvent(SfxEventHint(nEventId, @@ -1257,7 +1252,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) ); pProgressDlg->Show(); - rescheduleGui(); + Application::Reschedule( true ); } if( bCreateSingleFile && !pTargetView ) @@ -1400,7 +1395,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, pProgressDlg->Update(); } - rescheduleGui(); + Application::Reschedule( true ); // Create a copy of the source document and work with that one instead of the source. // If we're not in the single file mode (which requires modifying the document for the merging), @@ -1570,7 +1565,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, } else if( IsMergeOk() ) // && bCreateSingleFile { - rescheduleGui(); + Application::Reschedule( true ); // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate // unique fly names, do it here once. @@ -1589,7 +1584,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, aLayout->AllCheckPageDescs(); } - rescheduleGui(); + Application::Reschedule( true ); if( IsMergeOk() && bMT_FILE ) { @@ -1627,7 +1622,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, else if( xTargetDocShell.is() ) xTargetDocShell->DoClose(); - rescheduleGui(); + Application::Reschedule( true ); pProgressDlg.disposeAndClear(); diff --git a/vcl/README.scheduler b/vcl/README.scheduler index 68366a3a730f..a3410e1b0910 100644 --- a/vcl/README.scheduler +++ b/vcl/README.scheduler @@ -107,11 +107,29 @@ thread redirects using Qt::BlockingQueuedConnection. == General: non-main thread yield == Yielding from a non-main thread must not wait in the main thread, as this -may block the main thread until some events happen. +may block the main thread until some event happens. Currently we wait on an extra conditional, which is cleared by the main event loop. +== General: processing all current events for DoYield == + +This is easily implemented on all non-priority queue based implementations. +Windows and MacOS both have a timestamp attached to their events / messages, +so simply get the current time and just process anything < timestamp. +For the KDE backend this is already the default behaviour - single event +processing isn't even supported. The headless backend accomplishes this by +just processing the a copy of the list of current events. + +Problematic in this regard is the Gtk+ backend. g_main_context_iteration +dispatches "only those highest priority event sources". There is no real way +to tell, when these became ready. I've added a workaround idea to the TODO +list. FWIW: Qt runs just a single timer source in the glib mmain context, +basically the same we're doing with the LO scheduler as a system event. + +The gen X11 backend has some levels of redirection, but needs uite some work +to get this fixed. + == MacOS implementation details == Generally the Scheduler is handled as expected, except on resize, which is @@ -225,3 +243,39 @@ workaround using a validation timestamp is better then the current peek, remove, re-postEvent, which has to run in the main thread. Originally I didn't evaluate, if the event is actually lost or just delayed. + +== Drop nMaxEvents from Gtk+ based backends == + +gint last_priority = G_MAXINT; +bool bWasEvent = false; +do { + gint max_priority; + g_main_context_acquire( NULL ); + bool bHasPending = g_main_context_prepare( NULL, &max_priority ); + g_main_context_release( NULL ); + if ( bHasPending ) + { + if ( last_priority > max_priority ) + { + bHasPending = g_main_context_iteration( NULL, bWait ); + bWasEvent = bWasEvent || bHasPending; + } + else + bHasPending = false; + } +} +while ( bHasPending ) + +The idea is to use g_main_context_prepare and keep the max_priority as an +indicator. We cannot prevent running newer lower events, but we can prevent +running new higher events, which should be sufficient for most stuff. + +This also touches user event processing, which currently runs as a high +priority idle in the event loop. + +== Drop nMaxEvents from gen (X11) backend == + +A few layers of indirection make this code hard to follow. The SalXLib::Yield +and SalX11Display::Yield architecture makes it impossible to process just the +current events. This really needs a refactorung and rearchitecture step, which +will also affect the Gtk+ and KDE4 backend for the user event handling. diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 1966727ac936..8a805ea345b1 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -180,7 +180,7 @@ bool SvpSalInstance::PostedEventsInQueue() bool result = false; { osl::MutexGuard g(m_aEventGuard); - result = m_aUserEvents.size() > 0; + result = !m_aUserEvents.empty(); } return result; } diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 34ecae38bd5b..118400f7c45a 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -580,6 +580,7 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) { // handle available events NSEvent* pEvent = nil; + NSDate *now = [[NSDate alloc] init]; do { SolarMutexReleaser aReleaser; @@ -588,7 +589,7 @@ SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask SAL_WNODEPRECATED_DECLARATIONS_POP - untilDate: nil + untilDate: now inMode: NSDefaultRunLoopMode dequeue: YES]; if( pEvent ) diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index fdfc02a684d4..7f63ce0e4232 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -488,7 +488,7 @@ bool Application::Reschedule( bool i_bAllEvents ) void Scheduler::ProcessEventsToSignal(bool& bSignal) { - while (!bSignal && Application::Reschedule( false ) ); + while (!bSignal && Application::Reschedule() ); } void Scheduler::ProcessEventsToIdle() @@ -516,7 +516,8 @@ void Scheduler::ProcessEventsToIdle() Idle *pIdle = dynamic_cast<Idle*>( pSchedulerData->mpTask ); if ( pIdle && pIdle->IsActive() ) { - SAL_WARN( "vcl.schedule", "Unprocessed Idle: " << pIdle->GetDebugName() ); + SAL_WARN( "vcl.schedule", "Unprocessed Idle: " + << pIdle << " " << pIdle->GetDebugName() ); } } pSchedulerData = pSchedulerData->mpNext; diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx index 2ccb80ce2a36..155d359d30f0 100644 --- a/vcl/source/gdi/print2.cxx +++ b/vcl/source/gdi/print2.cxx @@ -1232,8 +1232,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, pCurrAct->Execute( aPaintVDev.get() ); } - if( !( nActionNum % 8 ) ) - Application::Reschedule(); + Application::Reschedule( true ); } const bool bOldMap = mbMap; diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx index a44b9f1a3233..d56c67e008cb 100644 --- a/vcl/unx/kde4/KDEXLib.cxx +++ b/vcl/unx/kde4/KDEXLib.cxx @@ -293,8 +293,7 @@ bool KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) // (it's ok to release it here, since even normal processYield() would // temporarily do it while checking for new events) SalYieldMutexReleaser aReleaser; - Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents ); - return false; + return Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents ); } } diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx index 01076286c429..2fe497d019fa 100644 --- a/vcl/unx/kde4/KDEXLib.hxx +++ b/vcl/unx/kde4/KDEXLib.hxx @@ -68,7 +68,7 @@ class KDEXLib : public QObject, public SalXLib Q_SIGNALS: void startTimeoutTimerSignal(); - void processYieldSignal( bool bWait, bool bHandleAllCurrentEvents ); + bool processYieldSignal( bool bWait, bool bHandleAllCurrentEvents ); css::uno::Reference< css::ui::dialogs::XFilePicker2 > createFilePickerSignal( const css::uno::Reference< css::uno::XComponentContext >& ); diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index 2da5e6bca80d..d7e519bbe527 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -503,14 +503,19 @@ static void ImplSalDispatchMessage( MSG* pMsg ) ImplSalPostDispatchMsg( pMsg, lResult ); } -static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents ) +static bool ImplSalYield( const bool bWait, const bool bHandleAllCurrentEvents ) { + static sal_uInt32 nLastTicks = 0; MSG aMsg; bool bWasMsg = false, bOneEvent = false; ImplSVData *const pSVData = ImplGetSVData(); WinSalTimer* pTimer = static_cast<WinSalTimer*>( pSVData->maSchedCtx.mpSalTimer ); - int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; + sal_uInt32 nCurTicks = 0; + if ( bHandleAllCurrentEvents ) + nCurTicks = GetTickCount(); + + bool bHadNewerEvent = false; do { bOneEvent = PeekMessageW( &aMsg, nullptr, 0, 0, PM_REMOVE ); @@ -519,30 +524,38 @@ static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents ) bWasMsg = true; TranslateMessage( &aMsg ); ImplSalDispatchMessage( &aMsg ); + if ( bHandleAllCurrentEvents + && !bHadNewerEvent && aMsg.time > nCurTicks + && (nLastTicks <= nCurTicks || aMsg.time < nLastTicks) ) + bHadNewerEvent = true; + bOneEvent = !bHadNewerEvent; } - else - // busy loop to catch the 0ms timeout - // We don't need to busy loop, if we wait anyway. - // Even if we didn't process the event directly, report it. - if ( pTimer && pTimer->WantBusyLoop() && !bWait ) - { - SwitchToThread(); - nMaxEvents++; - bOneEvent = true; - bWasMsg = true; - } - } while( --nMaxEvents && bOneEvent ); + // busy loop to catch a message, eventually the 0ms timer. + // we don't need to loop, if we wait anyway. + if ( !bWait && !bWasMsg && pTimer && pTimer->PollForMessage() ) + { + SwitchToThread(); + continue; + } + if ( !(bHandleAllCurrentEvents && bOneEvent) ) + break; + } + while( true ); + + if ( bHandleAllCurrentEvents ) + nLastTicks = nCurTicks; // Also check that we don't wait when application already has quit if ( bWait && !bWasMsg && !pSVData->maAppData.mbAppQuit ) { if ( GetMessageW( &aMsg, nullptr, 0, 0 ) ) { - // Ignore the scheduler wakeup message + bWasMsg = true; TranslateMessage( &aMsg ); ImplSalDispatchMessage( &aMsg ); } } + return bWasMsg; } commit 35baad769c7b1e04c6718eed490c59fd37059db5 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 29 09:40:01 2017 +0200 Don't wait-yield non-main threads in the main thread This prevents blocking the main thread by a yielding non-main thread. The current solution is to wait on a condition, which is set by the main thread on wakeup. Change-Id: I8d680bb51a36ce1e0d3d4713d47d8e2ef93d7297 diff --git a/vcl/README.scheduler b/vcl/README.scheduler index 5f6fbb624447..68366a3a730f 100644 --- a/vcl/README.scheduler +++ b/vcl/README.scheduler @@ -104,6 +104,14 @@ normally wait for the SolarMutex. Eventually this will move into the GenericSolarMutex. KDE / Qt also does main thread redirects using Qt::BlockingQueuedConnection. +== General: non-main thread yield == + +Yielding from a non-main thread must not wait in the main thread, as this +may block the main thread until some events happen. + +Currently we wait on an extra conditional, which is cleared by the main event +loop. + == MacOS implementation details == Generally the Scheduler is handled as expected, except on resize, which is diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 1d5c9ce41e3d..aa88ac02d5fd 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -72,6 +72,8 @@ class AquaSalInstance : public SalInstance {} }; + bool RunInMainYield( bool bHandleAllCurrentEvents ); + public: SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex OUString maDefaultPrinter; diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 9c7ddd734b0d..34ecae38bd5b 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -524,6 +524,13 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) }; } +bool AquaSalInstance::RunInMainYield( bool bHandleAllCurrentEvents ) +{ + OSX_SALDATA_RUNINMAIN_UNION( DoYield( false, bHandleAllCurrentEvents), boolean ) + assert( false && "Don't call this from the main thread!" ); + return false; +} + bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) { bool bHadEvent = false; @@ -637,13 +644,17 @@ SAL_WNODEPRECATED_DECLARATIONS_POP if ( bHadEvent ) maWaitingYieldCond.set(); } - else if( bWait ) + else { - // #i103162# - // wait until the main thread has dispatched an event - maWaitingYieldCond.reset(); - SolarMutexReleaser aReleaser; - maWaitingYieldCond.wait(); + bHadEvent = RunInMainYield( bHandleAllCurrentEvents ); + if ( !bHadEvent && bWait ) + { + // #i103162# + // wait until the main thread has dispatched an event + maWaitingYieldCond.reset(); + SolarMutexReleaser aReleaser; + maWaitingYieldCond.wait(); + } } // we get some apple events way too early diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index af2bc10e189a..2da5e6bca80d 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -558,31 +558,16 @@ bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) SolarMutexReleaser aReleaser; if ( !IsMainThread() ) { - if ( bWait ) + // If you change the SendMessageW function, you might need to update + // the PeekMessage( ... PM_QS_POSTMESSAGE) calls! + bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD, + (WPARAM) false, (LPARAM) bHandleAllCurrentEvents ); + if ( !bDidWork && bWait ) { maWaitingYieldCond.reset(); maWaitingYieldCond.wait(); bDidWork = true; } - else { - // #97739# A SendMessage call blocks until the called thread (here: the main thread) - // returns. During a yield however, messages are processed in the main thread that might - // result in a new message loop due to opening a dialog. Thus, SendMessage would not - // return which will block this thread! - // Solution: just give up the time slice and hope that messages are processed - // by the main thread anyway (where all windows are created) - // If the mainthread is not currently handling messages, then our SendMessage would - // also do nothing, so this seems to be reasonable. - - // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open - if( ImplGetSVData()->maAppData.mnModalMode ) - Sleep(1); - else - // If you change the SendMessageW function, you might need to update - // the PeekMessage( ... PM_QS_POSTMESSAGE) calls! - bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD, - (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents ); - } } else { @@ -602,7 +587,8 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i switch ( nMsg ) { case SAL_MSG_THREADYIELD: - nRet = static_cast<LRESULT>(ImplSalYield( (bool)wParam, (bool)lParam )); + assert( !(bool)wParam ); + nRet = static_cast<LRESULT>(ImplSalYield( false, (bool)lParam )); rDef = FALSE; break; case SAL_MSG_STARTTIMER: commit 9f22a239955e22cedf05c8daba8d28a49352380b Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Mon Aug 28 19:58:32 2017 +0200 WIN run main thread redirects ignoring SolarMutex This way we can drop all the special nReleased handling. Instead we use the same mechanism as on Mac, where we keep the lock, but disable it for the main thread. As a security measure we assert on duplicate redirects, which should not happen. As a result we can't use SendMessage on the main thread itself, which would normally just call the WinProc directly. This could be accomplished by converting the redirect bool into a counter, which should be safe, as no other thread could acquire the SolarMutex, as we don't release it. Change-Id: Icd87b3da37a2489f3cad2bc80215bf93fc41d388 diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index be6ea6f8a53c..d6e186350424 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -495,12 +495,6 @@ public: */ static void EndYield(); - /** Acquire SolarMutex after it has been temporarily dropped completely. - - This will Reschedule() on WNT and just acquire on other platforms. - */ ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits