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