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:
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user