svx/source/svdraw/sdrpaintwindow.cxx | 96 ---
vcl/source/window/window.cxx |5 +
2 files changed, 83 insertions(+), 18 deletions(-)
New commits:
commit fa3c550a8eeb4a7be3ec4afe0540c1320d321110
Author: Caolán McNamara caol...@redhat.com
Date: Fri Feb 28 16:55:03 2014 +
Resolves: rhbz#1007697 Update on a Window triggering delete on window
Reviewed-on: https://gerrit.libreoffice.org/8396
Reviewed-by: Caolán McNamara caol...@redhat.com
Tested-by: Caolán McNamara caol...@redhat.com
(cherry picked from commit 1ec2880679d88c89901ce00fe30dd78e584f6960)
Conflicts:
svx/source/svdraw/sdrpaintwindow.cxx
vcl/source/window/window.cxx
Change-Id: Ic6374ce45e3a3ba97217ae77e91f9143f46e277b
diff --git a/svx/source/svdraw/sdrpaintwindow.cxx
b/svx/source/svdraw/sdrpaintwindow.cxx
index 6ab2b40..da94126 100644
--- a/svx/source/svdraw/sdrpaintwindow.cxx
+++ b/svx/source/svdraw/sdrpaintwindow.cxx
@@ -22,35 +22,95 @@
#include svx/svdpntv.hxx
#include vcl/gdimtf.hxx
#include vcl/svapp.hxx
+#include set
+#include vector
+
+//rhbz#1007697 do this in two loops, one to collect the candidates
+//and another to update them because updating a candidate can
+//trigger the candidate to be deleted, so asking for its
+//sibling after that is going to fail hard
+class CandidateMgr
+{
+std::vectorWindow* m_aCandidates;
+std::setWindow* m_aDeletedCandidates;
+DECL_LINK(WindowEventListener, VclSimpleEvent*);
+public:
+void PaintTransparentChildren(Window rWindow, Rectangle const
rPixelRect);
+~CandidateMgr();
+};
+
+IMPL_LINK(CandidateMgr, WindowEventListener, VclSimpleEvent*, pEvent)
+{
+VclWindowEvent* pWinEvent = dynamic_cast VclWindowEvent* ( pEvent );
+if (pWinEvent)
+{
+Window* pWindow = pWinEvent-GetWindow();
+if (pWinEvent-GetId() == VCLEVENT_OBJECT_DYING)
+{
+m_aDeletedCandidates.insert(pWindow);
+}
+}
+return 0;
+}
+
+CandidateMgr::~CandidateMgr()
+{
+for (std::vectorWindow*::iterator aI = m_aCandidates.begin();
+ aI != m_aCandidates.end(); ++aI)
+{
+Window* pCandidate = *aI;
+if (m_aDeletedCandidates.find(pCandidate) !=
m_aDeletedCandidates.end())
+continue;
+pCandidate-RemoveEventListener(LINK(this, CandidateMgr,
WindowEventListener));
+}
+}
void PaintTransparentChildren(Window rWindow, Rectangle const rPixelRect)
{
-if (rWindow.IsChildTransparentModeEnabled())
+if (!rWindow.IsChildTransparentModeEnabled())
+return;
+
+CandidateMgr aManager;
+aManager.PaintTransparentChildren(rWindow, rPixelRect);
+}
+
+void CandidateMgr::PaintTransparentChildren(Window rWindow, Rectangle const
rPixelRect)
+{
+Window * pCandidate = rWindow.GetWindow( WINDOW_FIRSTCHILD );
+while (pCandidate)
{
-Window * pCandidate = rWindow.GetWindow( WINDOW_FIRSTCHILD );
-while (pCandidate)
+if (pCandidate-IsPaintTransparent())
{
-if (pCandidate-IsPaintTransparent())
+const Rectangle aCandidatePosSizePixel(
+pCandidate-GetPosPixel(),
+pCandidate-GetSizePixel());
+
+if (aCandidatePosSizePixel.IsOver(rPixelRect))
{
-const Rectangle aCandidatePosSizePixel(
-pCandidate-GetPosPixel(),
-pCandidate-GetSizePixel());
-
-if (aCandidatePosSizePixel.IsOver(rPixelRect))
-{
-pCandidate-Invalidate(
-INVALIDATE_NOTRANSPARENT|INVALIDATE_CHILDREN );
-// important: actually paint the child here!
-pCandidate-Update();
-}
+m_aCandidates.push_back(pCandidate);
+pCandidate-AddEventListener(LINK(this, CandidateMgr,
WindowEventListener));
}
-pCandidate = pCandidate-GetWindow( WINDOW_NEXT );
}
+pCandidate = pCandidate-GetWindow( WINDOW_NEXT );
}
-}
-
+for (std::vectorWindow*::iterator aI = m_aCandidates.begin();
+ aI != m_aCandidates.end(); ++aI)
+{
+pCandidate = *aI;
+if (m_aDeletedCandidates.find(pCandidate) !=
m_aDeletedCandidates.end())
+continue;
+//rhbz#1007697 this can cause the window itself to be
+//deleted. So we are listening to see if that happens
+//and if so, then skip the update
+pCandidate-Invalidate(INVALIDATE_NOTRANSPARENT|INVALIDATE_CHILDREN);
+// important: actually paint the child here!
+if (m_aDeletedCandidates.find(pCandidate) !=
m_aDeletedCandidates.end())
+continue;
+pCandidate-Update();
+}
+}