drop LazyDeletor

Change-Id: I7d2e00466f321994a46b0529d645e342f229c929
Reviewed-on: https://gerrit.libreoffice.org/61718
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
This commit is contained in:
Caolán McNamara
2018-10-16 09:54:13 +02:00
parent 7dc9fb33db
commit 8a2f7704cd
12 changed files with 28 additions and 226 deletions
@@ -232,13 +232,10 @@ void ToolBarManager::Destroy()
delete static_cast< AddonsParams* >( m_pToolBar->GetItemData( nItemId ));
}
// Hide toolbar as lazy delete can destroy the toolbar much later.
m_pToolBar->Hide();
// #i93173# delete toolbar lazily as we can still be in one of its handlers
// tdf#119390 this will reparent the toolbar, so focus is restored from a
// floating toolbar to the last focused control of the application window.
m_pToolBar->doLazyDelete();
m_pToolBar->SetParentToDefaultWindow();
// #i93173# note we can still be in one of the toolbar's handlers
m_pToolBar->SetSelectHdl( Link<ToolBox *, void>() );
m_pToolBar->SetActivateHdl( Link<ToolBox *, void>() );
m_pToolBar->SetDeactivateHdl( Link<ToolBox *, void>() );
@@ -248,7 +245,7 @@ void ToolBarManager::Destroy()
m_pToolBar->SetStateChangedHdl( Link<StateChangedType const *, void>() );
m_pToolBar->SetDataChangedHdl( Link<DataChangedEvent const *, void>() );
m_pToolBar.clear();
m_pToolBar.disposeAndClear();
SvtMiscOptions().RemoveListenerLink( LINK( this, ToolBarManager, MiscOptionsChanged ) );
}
+1 -151
View File
@@ -35,158 +35,8 @@
namespace vcl
{
/* Helpers for lazy object deletion
With vcl it is often necessary to delete objects (especially Windows)
in the right order as well as in a way ensuring that the deleted objects
are not still on the stack (e.g. deleting a Window in its key handler). To
make this easier a helper class is given here which takes care of both
sorting as well as lazy deletion.
The grisly details:
LazyDelete is a class that LazyDeletor register to. When vcl's event
loop (that is Application::Yield or Application::Reschedule) comes out
of the last level, the LazyDelete::flush is called. This will cause
LazyDelete to delete all registered LazyDeletor objects.
LazyDeletor<T> is a one instance object that contains a list of
<T> objects to be deleted in sorted order. It is derived from
LazyDeletorBase as to be able to register itself in LazyDelete.
The user calls the static method LazyDeletor<T>::Delete( T* ) with the
object to be destroyed lazy. The static method creates the LazyDeletor<T>
(which in turn registers itself in LazyDelete) if this is the first time
a T* is to be destroyed lazy. It then inserts the object. When the LazyDeletor<T>
gets delete it will delete the stored objects in a fashion
that will ensure the correct order of deletion via the specialized is_less method
(e.g. if a Window is a child of another Window and therefore should be destroyed
first it is "less" in this sense)
LazyDelete::flush will be called when the top of the nested event loop is
reached again and will then destroy each registered LazyDeletor<T> which
in turn destroys the objects needed to be destroyed lazily. After this
the state is as before entering the event loop.
Preconditions:
- The class <T> of which objects are to be destroyed needs a virtual
destructor or must be final, else the wrong type will be destroyed.
- The destructor of <T> should call LazyDeletor<T>::Undelete( this ). This
prevents duplicate deletion in case someone destroys the object prematurely.
*/
class LazyDeletorBase;
class VCL_DLLPUBLIC LazyDelete
{
public:
/** flush all registered object lists
*/
static void flush();
/** register an object list to be destroyed
*/
static void addDeletor( LazyDeletorBase* pDeletor );
};
class VCL_DLLPUBLIC LazyDeletorBase
{
friend void LazyDelete::flush();
protected:
LazyDeletorBase();
virtual ~LazyDeletorBase();
};
class VCL_DLLPUBLIC LazyDeletor : public LazyDeletorBase
{
static LazyDeletor* s_pOneInstance;
struct DeleteObjectEntry
{
VclPtr<vcl::Window> m_pObject;
bool m_bDeleted;
DeleteObjectEntry( vcl::Window* i_pObject ) :
m_pObject( i_pObject ),
m_bDeleted( false )
{}
};
std::vector< DeleteObjectEntry > m_aObjects;
typedef std::unordered_map< sal_IntPtr, unsigned int > PtrToIndexMap;
PtrToIndexMap m_aPtrToIndex;
/** strict weak ordering function to bring objects to be destroyed lazily
in correct order, e.g. for Window objects children before parents
*/
static bool is_less( vcl::Window const * left, vcl::Window const * right );
LazyDeletor() { LazyDelete::addDeletor( this ); }
virtual ~LazyDeletor() override
{
SAL_INFO("vcl.lazydelete", typeid(*this).name() << std::hex << this << " deleted");
if( s_pOneInstance == this ) // sanity check
s_pOneInstance = nullptr;
// do the actual work
unsigned int nCount = m_aObjects.size();
std::vector< VclPtr < vcl::Window > > aRealDelete;
aRealDelete.reserve( nCount );
for( unsigned int i = 0; i < nCount; i++ )
{
if( ! m_aObjects[i].m_bDeleted )
{
aRealDelete.push_back( m_aObjects[i].m_pObject );
}
}
// sort the vector of objects to be destroyed
std::sort( aRealDelete.begin(), aRealDelete.end(), is_less );
nCount = aRealDelete.size();
for( unsigned int n = 0; n < nCount; n++ )
{
SAL_INFO("vcl.lazydelete", typeid(*this).name() << " deletes object " << aRealDelete[n] << " of type "
<< typeid(*aRealDelete[n]).name());
// check if the object to be deleted is not already destroyed
// as a side effect of a previous lazily destroyed object
if( ! m_aObjects[ m_aPtrToIndex[ reinterpret_cast<sal_IntPtr>(aRealDelete[n].get()) ] ].m_bDeleted )
aRealDelete[n].disposeAndClear();
}
}
public:
/** mark an object for lazy deletion
*/
static void Delete( vcl::Window* i_pObject )
{
if( s_pOneInstance == nullptr )
s_pOneInstance = new LazyDeletor();
// is this object already in the list ?
// if so mark it as not to be deleted; else insert it
PtrToIndexMap::const_iterator dup = s_pOneInstance->m_aPtrToIndex.find( reinterpret_cast<sal_IntPtr>(i_pObject) );
if( dup != s_pOneInstance->m_aPtrToIndex.end() )
{
s_pOneInstance->m_aObjects[ dup->second ].m_bDeleted = false;
}
else
{
s_pOneInstance->m_aPtrToIndex[ reinterpret_cast<sal_IntPtr>(i_pObject) ] = s_pOneInstance->m_aObjects.size();
s_pOneInstance->m_aObjects.push_back( DeleteObjectEntry( i_pObject ) );
}
}
/** unmark an object already marked for lazy deletion
*/
static void Undelete( vcl::Window* i_pObject )
{
if( s_pOneInstance )
{
PtrToIndexMap::const_iterator it = s_pOneInstance->m_aPtrToIndex.find( reinterpret_cast<sal_IntPtr>(i_pObject) );
if( it != s_pOneInstance->m_aPtrToIndex.end() )
s_pOneInstance->m_aObjects[ it->second ].m_bDeleted = true;
}
}
};
/*
class DeleteOnDeinit matches a similar need as LazyDelete for static objects:
you may not access vcl objects after DeInitVCL has been called this includes their destruction
You may not access vcl objects after DeInitVCL has been called this includes their destruction
therefore disallowing the existence of static vcl object like e.g. a static BitmapEx
To work around this use DeleteOnDeinit<BitmapEx> which will allow you to have a static object container,
that will have its contents destroyed on DeinitVCL. The single drawback is that you need to check on the
+5 -3
View File
@@ -1571,14 +1571,16 @@ public:
// a helper method for a Control's Draw method
void PaintToDevice( ::OutputDevice* pDevice, const Point& rPos, const Size& rSize );
/* mark Window for deletion in top of event queue
/* tdf#119390 set parent to default window. Typically for use in advance of destroying
* a floating windows which has the current focus so focus will revert to the main
* document window and not the first widget in the current parent of the floating
* window.
*/
void doLazyDelete();
void SetParentToDefaultWindow();
// Keyboard access functions
/** Query the states of keyboard indicators - Caps Lock, Num Lock and
Scroll Lock. Use the following mask to retrieve the state of each
indicator:
+2 -1
View File
@@ -81,7 +81,8 @@ void PopupWindowControllerImpl::SetFloatingWindow()
mpFloatingWindow->RemoveEventListener( LINK( this, PopupWindowControllerImpl, WindowEventListener ) );
// tdf#119390 reparent the window, so focus is restored
// to the last focused control of the application window.
mpFloatingWindow->doLazyDelete();
mpFloatingWindow->SetParentToDefaultWindow();
mpFloatingWindow.disposeAndClear();
}
mpFloatingWindow = mpPopupWindow;
mpPopupWindow.clear();
+1 -1
View File
@@ -189,7 +189,7 @@ ways and often both.
---------- What remains to be done ? ----------
* Cleanup DogTags and LazyDelete.
* Cleanup DogTags
* Expand the VclPtr pattern to many other less
than safe VCL types.
+3 -8
View File
@@ -458,10 +458,9 @@ static bool ImplYield(bool i_bWait, bool i_bAllEvents)
SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") <<
": " << (i_bAllEvents ? "all events" : "one event"));
// TODO: there's a data race here on WNT only because ImplYield may be
// called without SolarMutex; if we can get rid of LazyDelete (with VclPtr)
// then the only remaining use of mnDispatchLevel is in OSX specific code
// so that would effectively eliminate the race on WNT
// there's a data race here on WNT only because ImplYield may be
// called without SolarMutex; but the only remaining use of mnDispatchLevel
// is in OSX specific code
pSVData->maAppData.mnDispatchLevel++;
// do not wait for events if application was already quit; in that
@@ -473,10 +472,6 @@ static bool ImplYield(bool i_bWait, bool i_bAllEvents)
DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
// flush lazy deleted objects
if( pSVData->maAppData.mnDispatchLevel == 0 )
vcl::LazyDelete::flush();
SAL_INFO("vcl.schedule", "Leave ImplYield with return " << bProcessedEvent );
return bProcessedEvent;
}
-35
View File
@@ -25,41 +25,6 @@
namespace vcl {
LazyDeletorBase::LazyDeletorBase()
{
}
LazyDeletorBase::~LazyDeletorBase()
{
}
// instantiate instance pointer for LazyDeletor<Window>
LazyDeletor* LazyDeletor::s_pOneInstance = nullptr;
// a list for all LazyeDeletor<T> singletons
static std::vector< LazyDeletorBase* > lcl_aDeletors;
void LazyDelete::addDeletor( LazyDeletorBase* i_pDel )
{
lcl_aDeletors.push_back( i_pDel );
}
void LazyDelete::flush()
{
DBG_TESTSOLARMUTEX(); // must be locked
unsigned int nCount = lcl_aDeletors.size();
for( unsigned int i = 0; i < nCount; i++ )
delete lcl_aDeletors[i];
lcl_aDeletors.clear();
}
// specialized is_less function for Window
bool LazyDeletor::is_less( vcl::Window const * left, vcl::Window const * right )
{
return left != right && right->IsChild( left, true );
}
DeleteOnDeinitBase::~DeleteOnDeinitBase()
{
ImplSVData* pSVData = ImplGetSVData();
+4 -4
View File
@@ -2952,8 +2952,8 @@ sal_uInt16 PopupMenu::ImplExecute( const VclPtr<vcl::Window>& pW, const tools::R
{
pWin->StopExecute();
pWin->doShutdown();
pWindow->doLazyDelete();
pWindow = nullptr;
pWindow->SetParentToDefaultWindow();
pWindow.disposeAndClear();
ImplClosePopupToolBox(pW);
ImplFlushPendingSelect();
return nSelectedId;
@@ -3013,8 +3013,8 @@ sal_uInt16 PopupMenu::ImplExecute( const VclPtr<vcl::Window>& pW, const tools::R
}
}
pWin->doShutdown();
pWindow->doLazyDelete();
pWindow = nullptr;
pWindow->SetParentToDefaultWindow();
pWindow.disposeAndClear();
ImplClosePopupToolBox(pW);
ImplFlushPendingSelect();
}
+2 -2
View File
@@ -377,8 +377,8 @@ void MenuBarWindow::KillActivePopup()
}
pActivePopup->ImplGetFloatingWindow()->StopExecute();
pActivePopup->ImplGetFloatingWindow()->doShutdown();
pActivePopup->pWindow->doLazyDelete();
pActivePopup->pWindow = nullptr;
pActivePopup->pWindow->SetParentToDefaultWindow();
pActivePopup->pWindow.disposeAndClear();
}
pActivePopup = nullptr;
}
+2 -2
View File
@@ -473,8 +473,8 @@ void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly )
{
pPopup->ImplGetFloatingWindow()->StopExecute();
pPopup->ImplGetFloatingWindow()->doShutdown();
pPopup->pWindow->doLazyDelete();
pPopup->pWindow = nullptr;
pPopup->pWindow->SetParentToDefaultWindow();
pPopup->pWindow.disposeAndClear();
Update();
}
+3 -11
View File
@@ -571,8 +571,6 @@ void Window::dispose()
Window::~Window()
{
// FIXME: we should kill all LazyDeletor usage.
vcl::LazyDeletor::Undelete( this );
disposeOnce();
}
@@ -1758,16 +1756,10 @@ void Window::ImplNewInputContext()
pFocusWin->ImplGetFrame()->SetInputContext( &aNewContext );
}
void Window::doLazyDelete()
void Window::SetParentToDefaultWindow()
{
SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(this);
DockingWindow* pDockWin = dynamic_cast<DockingWindow*>(this);
if( pSysWin || ( pDockWin && pDockWin->IsFloatingMode() ) )
{
Show( false );
SetParent( ImplGetDefaultWindow() );
}
vcl::LazyDeletor::Delete( this );
Show(false);
SetParent(ImplGetDefaultWindow());
}
KeyIndicatorState Window::GetIndicatorState() const
+2 -2
View File
@@ -349,8 +349,8 @@ void Window::EndAutoScroll()
pSVData->maWinData.mpAutoScrollWin = nullptr;
pSVData->maWinData.mnAutoScrollFlags = StartAutoScrollFlags::NONE;
pSVData->maAppData.mpWheelWindow->ImplStop();
pSVData->maAppData.mpWheelWindow->doLazyDelete();
pSVData->maAppData.mpWheelWindow = nullptr;
pSVData->maAppData.mpWheelWindow->SetParentToDefaultWindow();
pSVData->maAppData.mpWheelWindow.disposeAndClear();
}
}