vcl: double dispose protection & unit test.

Widgets must be able to tolerate multiple 'dispose' calls.

Change-Id: I76069a10b83b8384ad84dd146766054cab5bd222
diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index 189f15b..90c5d85 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -363,6 +363,8 @@ class VclBuilder;
class ImplDockingWindowWrapper;
class ImplPopupFloatWin;
class MenuFloatingWindow;
class LifecycleTest;

namespace svt { class PopupWindowControllerImpl; }

struct WindowResHeader
@@ -392,6 +394,7 @@ class VCL_DLLPUBLIC Window : public ::OutputDevice, public Resource
    friend class ::ImplBorderWindow;
    friend class ::VclBuilder;
    friend class ::PaintHelper;
    friend class ::LifecycleTest;

    // TODO: improve missing functionality
    // only required because of SetFloatingMode()
diff --git a/vcl/qa/cppunit/lifecycle.cxx b/vcl/qa/cppunit/lifecycle.cxx
index d635dd6..1c887b9 100644
--- a/vcl/qa/cppunit/lifecycle.cxx
+++ b/vcl/qa/cppunit/lifecycle.cxx
@@ -20,15 +20,30 @@ class LifecycleTest : public test::BootstrapFixture
public:
    LifecycleTest() : BootstrapFixture(true, false) {}

    void testMultiDispose();
    void testIsolatedWidgets();
    void testParentedWidgets();

    CPPUNIT_TEST_SUITE(LifecycleTest);
    CPPUNIT_TEST(testMultiDispose);
    CPPUNIT_TEST(testIsolatedWidgets);
    CPPUNIT_TEST(testParentedWidgets);
    CPPUNIT_TEST_SUITE_END();
};

void LifecycleTest::testMultiDispose()
{
    VclReference<WorkWindow> xWin(new WorkWindow((vcl::Window *)NULL,
                                                 WB_APP|WB_STDWORK));
    CPPUNIT_ASSERT(xWin.get() != NULL);
    xWin->dispose();
    xWin->dispose();
    xWin->dispose();
    CPPUNIT_ASSERT(xWin->GetWindow(0) == NULL);
    CPPUNIT_ASSERT(xWin->GetChild(0) == NULL);
    CPPUNIT_ASSERT(xWin->GetChildCount() == 0);
}

void LifecycleTest::testWidgets(vcl::Window *pParent)
{
    { PushButtonPtr   aPtr(new PushButton(pParent));   }
diff --git a/vcl/source/window/stacking.cxx b/vcl/source/window/stacking.cxx
index ee29a8d..9d81501 100644
--- a/vcl/source/window/stacking.cxx
+++ b/vcl/source/window/stacking.cxx
@@ -1023,6 +1023,8 @@ void Window::SetParent( vcl::Window* pNewParent )

sal_uInt16 Window::GetChildCount() const
{
    if (!mpWindowImpl)
        return 0;

    sal_uInt16  nChildCount = 0;
    vcl::Window* pChild = mpWindowImpl->mpFirstChild;
@@ -1037,6 +1039,8 @@ sal_uInt16 Window::GetChildCount() const

vcl::Window* Window::GetChild( sal_uInt16 nChild ) const
{
    if (!mpWindowImpl)
        return NULL;

    sal_uInt16  nChildCount = 0;
    vcl::Window* pChild = mpWindowImpl->mpFirstChild;
@@ -1053,6 +1057,8 @@ vcl::Window* Window::GetChild( sal_uInt16 nChild ) const

vcl::Window* Window::GetWindow( sal_uInt16 nType ) const
{
    if (!mpWindowImpl)
        return 0;

    switch ( nType )
    {
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
index 122181d..17b3cea 100644
--- a/vcl/source/window/window.cxx
+++ b/vcl/source/window/window.cxx
@@ -133,6 +133,9 @@ namespace

void Window::dispose()
{
    if (!mpWindowImpl)
        return;

    // remove Key and Mouse events issued by Application::PostKey/MouseEvent
    Application::RemoveMouseAndKeyEvents( this );