From 2aee749cb188d42282f54043a9723778f1cf1a05 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 11 Mar 2008 00:03:46 +0000 Subject: [PATCH] delete wxNativeContainerWindow when the native window is destroyed, even if this means leaking memory in GTK case -- still better than getting X errors and crashing git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52437 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/nativewin.h | 7 +++++ src/gtk/nativewin.cpp | 62 ++++++++++++++++++++++++++++++++++++++++-- src/msw/nativewin.cpp | 5 ++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/include/wx/nativewin.h b/include/wx/nativewin.h index ca663ba4d7..3aa6ffc790 100644 --- a/include/wx/nativewin.h +++ b/include/wx/nativewin.h @@ -145,6 +145,13 @@ public: return false; } + + // this is an implementation detail: called when the native window is + // destroyed by an outside agency; deletes the C++ object too but can in + // principle be overridden to something else (knowing that the window + // handle of this object and all of its children is invalid any more) + virtual void OnNativeDestroyed(); + private: DECLARE_NO_COPY_CLASS(wxNativeContainerWindow) }; diff --git a/src/gtk/nativewin.cpp b/src/gtk/nativewin.cpp index 0ccb183ff1..8647cc0aca 100644 --- a/src/gtk/nativewin.cpp +++ b/src/gtk/nativewin.cpp @@ -30,12 +30,42 @@ #include +#ifdef GDK_WINDOWING_X11 + #include +#endif + // ============================================================================ // implementation // ============================================================================ +// TODO: we probably need equivalent code for other GDK platforms +#ifdef GDK_WINDOWING_X11 + +extern "C" GdkFilterReturn +wxNativeContainerWindowFilter(GdkXEvent *gdkxevent, + GdkEvent *event, + gpointer data) +{ + XEvent * const xevent = static_cast(gdkxevent); + if ( xevent->type == DestroyNotify ) + { + // we won't need it any more + gdk_window_remove_filter(event->any.window, + wxNativeContainerWindowFilter, data); + + // the underlying window got destroyed, notify the C++ object + static_cast(data)->OnNativeDestroyed(); + } + + return GDK_FILTER_CONTINUE; +} + +#endif // GDK_WINDOWING_X11 + bool wxNativeContainerWindow::Create(wxNativeContainerWindowHandle win) { + wxCHECK( win, false ); + if ( !wxTopLevelWindow::Create(NULL, wxID_ANY, "") ) return false; @@ -43,6 +73,15 @@ bool wxNativeContainerWindow::Create(wxNativeContainerWindowHandle win) gtk_widget_realize(m_widget); gdk_window_reparent(m_widget->window, win, 0, 0); +#ifdef GDK_WINDOWING_X11 + // if the native window is destroyed, our own window will be destroyed too + // but GTK doesn't expect it and will complain about "unexpectedly + // destroyed" GdkWindow, so intercept to DestroyNotify ourselves to fix + // this and also destroy the associated C++ object when its window is + // destroyed + gdk_window_add_filter(m_widget->window, wxNativeContainerWindowFilter, this); +#endif // GDK_WINDOWING_X11 + // we should be initially visible as we suppose that the native window we // wrap is (we could use gdk_window_is_visible() to test for this but this // doesn't make much sense unless we also react to visibility changes, so @@ -69,8 +108,27 @@ bool wxNativeContainerWindow::Create(wxNativeContainerWindowId anid) return rc; } +void wxNativeContainerWindow::OnNativeDestroyed() +{ + // unfortunately we simply can't do anything else than leak memory here: + // we really need to call _gdk_window_destroy(m_widget->win, TRUE) to + // indicate that the native window was deleted, but we can't do this + // because it's a private GDK function and calling normal + // gdk_window_destroy() results in X errors while nulling just the window + // pointer and destroying m_widget results in many GTK errors + m_widget = NULL; + + // notice that we intentionally don't use Close() nor Delete() here as our + // window (and the windows of all of our children) is invalid any more and + // any attempts to use it, as may happen with the delayed destruction, will + // result in GDK warnings at best and crashes or X errors at worst + delete this; +} + wxNativeContainerWindow::~wxNativeContainerWindow() { - // there doesn't seem to be anything to do here, GTK+ seems to handle - // everything correctly due to its use of reference counting + // nothing to do here, either we have a valid m_widget and it will be + // destroyed as usual (this corresponds to manual destruction of this C++ + // object) or we are being deleted because the native window was destroyed + // and in this case our m_widget was set to NULL by OnNativeDestroyed() } diff --git a/src/msw/nativewin.cpp b/src/msw/nativewin.cpp index 1f0ddeca87..3ac00548a7 100644 --- a/src/msw/nativewin.cpp +++ b/src/msw/nativewin.cpp @@ -54,6 +54,11 @@ bool wxNativeContainerWindow::Create(wxNativeContainerWindowHandle hwnd) return true; } +void wxNativeContainerWindow::OnNativeDestroyed() +{ + // currently this is not called so nothing to do here +} + wxNativeContainerWindow::~wxNativeContainerWindow() { // prevent the base class dtor from destroying the window, it doesn't -- 2.45.2