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@wxwidgets.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 
22 #ifndef WX_PRECOMP
23 #endif // WX_PRECOMP
24 
25 #include "wx/nativewin.h"
26 
27 #include "wx/gtk/private/wrapgtk.h"
28 
29 #ifdef GDK_WINDOWING_X11
30     #include <gdk/gdkx.h>
31 #endif
32 
33 // ============================================================================
34 // implementation
35 // ============================================================================
36 
37 // ----------------------------------------------------------------------------
38 // wxNativeWindow
39 // ----------------------------------------------------------------------------
40 
41 bool
Create(wxWindow * parent,wxWindowID winid,wxNativeWindowHandle widget)42 wxNativeWindow::Create(wxWindow* parent,
43                        wxWindowID winid,
44                        wxNativeWindowHandle widget)
45 {
46     wxCHECK_MSG( widget, false, wxS("Invalid null GtkWidget") );
47 
48     // Standard wxGTK controls use PreCreation() but we never have any size
49     // specified at this stage, so don't bother with it.
50     if ( !CreateBase(parent, winid) )
51         return false;
52 
53     // Add a reference to the widget to match g_object_unref() in wxWindow dtor.
54     m_widget = widget;
55     g_object_ref(m_widget);
56 
57     parent->DoAddChild(this);
58 
59     PostCreation();
60 
61     // Ensure that the best (and minimal) size is set to fully display the
62     // widget.
63     GtkRequisition req;
64     gtk_widget_get_preferred_size(widget, NULL, &req);
65     SetInitialSize(wxSize(req.width, req.height));
66 
67     return true;
68 }
69 
DoDisown()70 void wxNativeWindow::DoDisown()
71 {
72     g_object_unref(m_widget);
73 }
74 
75 // ----------------------------------------------------------------------------
76 // wxNativeContainerWindow
77 // ----------------------------------------------------------------------------
78 
79 // TODO: we probably need equivalent code for other GDK platforms
80 #ifdef GDK_WINDOWING_X11
81 
82 extern "C" {
83 static GdkFilterReturn
wxNativeContainerWindowFilter(GdkXEvent * gdkxevent,GdkEvent * event,gpointer data)84 wxNativeContainerWindowFilter(GdkXEvent *gdkxevent,
85                               GdkEvent *event,
86                               gpointer data)
87 {
88     XEvent * const xevent = static_cast<XEvent *>(gdkxevent);
89     if ( xevent->type == DestroyNotify )
90     {
91         // we won't need it any more
92         gdk_window_remove_filter(event->any.window,
93                                  wxNativeContainerWindowFilter, data);
94 
95         // the underlying window got destroyed, notify the C++ object
96         static_cast<wxNativeContainerWindow *>(data)->OnNativeDestroyed();
97     }
98 
99     return GDK_FILTER_CONTINUE;
100 }
101 }
102 
103 #endif // GDK_WINDOWING_X11
104 
Create(wxNativeContainerWindowHandle win)105 bool wxNativeContainerWindow::Create(wxNativeContainerWindowHandle win)
106 {
107     wxCHECK( win, false );
108 
109     if ( !wxTopLevelWindow::Create(NULL, wxID_ANY, wxString()) )
110         return false;
111 
112     // we need to realize the window first before reparenting it
113     gtk_widget_realize(m_widget);
114     gdk_window_reparent(gtk_widget_get_window(m_widget), win, 0, 0);
115 
116 #ifdef GDK_WINDOWING_X11
117     // if the native window is destroyed, our own window will be destroyed too
118     // but GTK doesn't expect it and will complain about "unexpectedly
119     // destroyed" GdkWindow, so intercept to DestroyNotify ourselves to fix
120     // this and also destroy the associated C++ object when its window is
121     // destroyed
122     gdk_window_add_filter(gtk_widget_get_window(m_widget), wxNativeContainerWindowFilter, this);
123 #endif // GDK_WINDOWING_X11
124 
125     // we should be initially visible as we suppose that the native window we
126     // wrap is (we could use gdk_window_is_visible() to test for this but this
127     // doesn't make much sense unless we also react to visibility changes, so
128     // just suppose it's always shown for now)
129     Show();
130 
131     return true;
132 }
133 
Create(wxNativeContainerWindowId anid)134 bool wxNativeContainerWindow::Create(wxNativeContainerWindowId anid)
135 {
136     bool rc;
137 #ifdef __WXGTK3__
138 #ifdef GDK_WINDOWING_X11
139     GdkWindow * const win = gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), anid);
140 #else
141     GdkWindow * const win = NULL;
142 #endif
143 #else
144     GdkWindow * const win = gdk_window_foreign_new(anid);
145 #endif
146     if ( win )
147     {
148         rc = Create(win);
149         g_object_unref(win);
150     }
151     else // invalid native window id
152     {
153         rc = false;
154     }
155 
156     return rc;
157 }
158 
OnNativeDestroyed()159 void wxNativeContainerWindow::OnNativeDestroyed()
160 {
161     // unfortunately we simply can't do anything else than leak memory here:
162     // we really need to call _gdk_window_destroy(m_widget->win, TRUE) to
163     // indicate that the native window was deleted, but we can't do this
164     // because it's a private GDK function and calling normal
165     // gdk_window_destroy() results in X errors while nulling just the window
166     // pointer and destroying m_widget results in many GTK errors
167     GTKDisconnect(m_widget);
168     m_widget = NULL;
169 
170     // notice that we intentionally don't use Close() nor Delete() here as our
171     // window (and the windows of all of our children) is invalid any more and
172     // any attempts to use it, as may happen with the delayed destruction, will
173     // result in GDK warnings at best and crashes or X errors at worst
174     delete this;
175 }
176 
~wxNativeContainerWindow()177 wxNativeContainerWindow::~wxNativeContainerWindow()
178 {
179     // nothing to do here, either we have a valid m_widget and it will be
180     // destroyed as usual (this corresponds to manual destruction of this C++
181     // object) or we are being deleted because the native window was destroyed
182     // and in this case our m_widget was set to NULL by OnNativeDestroyed()
183 }
184