]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/nativewin.cpp
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / gtk / nativewin.cpp
index 0ccb183ff17c528db31bc0949b9130d701e6558d..91cb1ce6139c3bfa77ee22754dadbb765aa6a08a 100644 (file)
 #include "wx/nativewin.h"
 
 #include <gtk/gtk.h>
+#include "wx/gtk/private/gtk2-compat.h"
+
+#ifdef GDK_WINDOWING_X11
+    #include <gdk/gdkx.h>
+#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<XEvent *>(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<wxNativeContainerWindow *>(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;
 
     // we need to realize the window first before reparenting it
     gtk_widget_realize(m_widget);
-    gdk_window_reparent(m_widget->window, win, 0, 0);
+    gdk_window_reparent(gtk_widget_get_window(m_widget), 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(gtk_widget_get_window(m_widget), 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
@@ -55,7 +95,15 @@ bool wxNativeContainerWindow::Create(wxNativeContainerWindowHandle win)
 bool wxNativeContainerWindow::Create(wxNativeContainerWindowId anid)
 {
     bool rc;
+#ifdef __WXGTK3__
+#ifdef GDK_WINDOWING_X11
+    GdkWindow * const win = gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), anid);
+#else
+    GdkWindow * const win = NULL;
+#endif
+#else
     GdkWindow * const win = gdk_window_foreign_new(anid);
+#endif
     if ( win )
     {
         rc = Create(win);
@@ -69,8 +117,28 @@ 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
+    GTKDisconnect(m_widget);
+    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()
 }