1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/nativewin.cpp
3 // Purpose:     wxNativeWindow implementation
4 // Author:      Vadim Zeitlin
5 // Created:     2008-03-05
6 // Copyright:   (c) 2008 Vadim Zeitlin <vadim@wxwindows.org>
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 // ============================================================================
11 // declarations
12 // ============================================================================
13 
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17 
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20 
21 #ifdef __BORLANDC__
22     #pragma hdrstop
23 #endif
24 
25 #ifndef WX_PRECOMP
26 #endif // WX_PRECOMP
27 
28 #include "wx/nativewin.h"
29 
30 #include <gtk/gtk.h>
31 #include "wx/gtk/private/gtk2-compat.h"
32 
33 #ifdef GDK_WINDOWING_X11
34     #include <gdk/gdkx.h>
35 #endif
36 
37 // ============================================================================
38 // implementation
39 // ============================================================================
40 
41 // TODO: we probably need equivalent code for other GDK platforms
42 #ifdef GDK_WINDOWING_X11
43 
44 extern "C" GdkFilterReturn
wxNativeContainerWindowFilter(GdkXEvent * gdkxevent,GdkEvent * event,gpointer data)45 wxNativeContainerWindowFilter(GdkXEvent *gdkxevent,
46                               GdkEvent *event,
47                               gpointer data)
48 {
49     XEvent * const xevent = static_cast<XEvent *>(gdkxevent);
50     if ( xevent->type == DestroyNotify )
51     {
52         // we won't need it any more
53         gdk_window_remove_filter(event->any.window,
54                                  wxNativeContainerWindowFilter, data);
55 
56         // the underlying window got destroyed, notify the C++ object
57         static_cast<wxNativeContainerWindow *>(data)->OnNativeDestroyed();
58     }
59 
60     return GDK_FILTER_CONTINUE;
61 }
62 
63 #endif // GDK_WINDOWING_X11
64 
Create(wxNativeContainerWindowHandle win)65 bool wxNativeContainerWindow::Create(wxNativeContainerWindowHandle win)
66 {
67     wxCHECK( win, false );
68 
69     if ( !wxTopLevelWindow::Create(NULL, wxID_ANY, "") )
70         return false;
71 
72     // we need to realize the window first before reparenting it
73     gtk_widget_realize(m_widget);
74     gdk_window_reparent(gtk_widget_get_window(m_widget), win, 0, 0);
75 
76 #ifdef GDK_WINDOWING_X11
77     // if the native window is destroyed, our own window will be destroyed too
78     // but GTK doesn't expect it and will complain about "unexpectedly
79     // destroyed" GdkWindow, so intercept to DestroyNotify ourselves to fix
80     // this and also destroy the associated C++ object when its window is
81     // destroyed
82     gdk_window_add_filter(gtk_widget_get_window(m_widget), wxNativeContainerWindowFilter, this);
83 #endif // GDK_WINDOWING_X11
84 
85     // we should be initially visible as we suppose that the native window we
86     // wrap is (we could use gdk_window_is_visible() to test for this but this
87     // doesn't make much sense unless we also react to visibility changes, so
88     // just suppose it's always shown for now)
89     Show();
90 
91     return true;
92 }
93 
Create(wxNativeContainerWindowId anid)94 bool wxNativeContainerWindow::Create(wxNativeContainerWindowId anid)
95 {
96     bool rc;
97 #ifdef __WXGTK3__
98 #ifdef GDK_WINDOWING_X11
99     GdkWindow * const win = gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), anid);
100 #else
101     GdkWindow * const win = NULL;
102 #endif
103 #else
104     GdkWindow * const win = gdk_window_foreign_new(anid);
105 #endif
106     if ( win )
107     {
108         rc = Create(win);
109         g_object_unref(win);
110     }
111     else // invalid native window id
112     {
113         rc = false;
114     }
115 
116     return rc;
117 }
118 
OnNativeDestroyed()119 void wxNativeContainerWindow::OnNativeDestroyed()
120 {
121     // unfortunately we simply can't do anything else than leak memory here:
122     // we really need to call _gdk_window_destroy(m_widget->win, TRUE) to
123     // indicate that the native window was deleted, but we can't do this
124     // because it's a private GDK function and calling normal
125     // gdk_window_destroy() results in X errors while nulling just the window
126     // pointer and destroying m_widget results in many GTK errors
127     GTKDisconnect(m_widget);
128     m_widget = NULL;
129 
130     // notice that we intentionally don't use Close() nor Delete() here as our
131     // window (and the windows of all of our children) is invalid any more and
132     // any attempts to use it, as may happen with the delayed destruction, will
133     // result in GDK warnings at best and crashes or X errors at worst
134     delete this;
135 }
136 
~wxNativeContainerWindow()137 wxNativeContainerWindow::~wxNativeContainerWindow()
138 {
139     // nothing to do here, either we have a valid m_widget and it will be
140     // destroyed as usual (this corresponds to manual destruction of this C++
141     // object) or we are being deleted because the native window was destroyed
142     // and in this case our m_widget was set to NULL by OnNativeDestroyed()
143 }
144