]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/glcanvas.cpp
follow up parent chain to properly support modal dialog parents, see #15383
[wxWidgets.git] / src / gtk / glcanvas.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL/Mesa with wxWidgets and GTK
4 // Author: Robert Roebling
5 // Modified by:
6 // Created: 17/08/98
7 // Copyright: (c) Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #if wxUSE_GLCANVAS
15
16 #include "wx/glcanvas.h"
17
18 #include <gtk/gtk.h>
19 #include <gdk/gdkx.h>
20 #include "wx/gtk/private/gtk2-compat.h"
21
22 #if WXWIN_COMPATIBILITY_2_8
23
24 //-----------------------------------------------------------------------------
25 // "realize" from m_wxwindow: used to create m_glContext implicitly
26 //-----------------------------------------------------------------------------
27
28 extern "C" {
29 static void
30 gtk_glwindow_realized_callback( GtkWidget *WXUNUSED(widget), wxGLCanvas *win )
31 {
32 win->GTKInitImplicitContext();
33 }
34 }
35
36 #endif // WXWIN_COMPATIBILITY_2_8
37
38 //-----------------------------------------------------------------------------
39 // "map" from m_wxwindow
40 //-----------------------------------------------------------------------------
41
42 #ifndef __WXGTK3__
43 extern "C" {
44 static void
45 gtk_glwindow_map_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win )
46 {
47 wxPaintEvent event( win->GetId() );
48 event.SetEventObject( win );
49 win->HandleWindowEvent( event );
50
51 win->m_exposed = false;
52 win->GetUpdateRegion().Clear();
53 }
54 }
55 #endif
56
57 //-----------------------------------------------------------------------------
58 // "expose_event" of m_wxwindow
59 //-----------------------------------------------------------------------------
60
61 extern "C" {
62 #ifdef __WXGTK3__
63 static gboolean draw(GtkWidget*, cairo_t* cr, wxGLCanvas* win)
64 {
65 win->m_exposed = true;
66 if (win->m_cairoPaintContext == NULL)
67 {
68 win->m_cairoPaintContext = cr;
69 cairo_reference(cr);
70 }
71 double x1, y1, x2, y2;
72 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
73 win->GetUpdateRegion().Union(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
74 return false;
75 }
76 #else
77 static gboolean
78 gtk_glwindow_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxGLCanvas *win )
79 {
80 win->m_exposed = true;
81
82 win->GetUpdateRegion().Union( gdk_event->area.x,
83 gdk_event->area.y,
84 gdk_event->area.width,
85 gdk_event->area.height );
86 return false;
87 }
88 #endif
89 }
90
91 //-----------------------------------------------------------------------------
92 // "size_allocate" of m_wxwindow
93 //-----------------------------------------------------------------------------
94
95 extern "C" {
96 static void
97 gtk_glcanvas_size_callback(GtkWidget *WXUNUSED(widget),
98 GtkAllocation * WXUNUSED(alloc),
99 wxGLCanvas *win)
100 {
101 wxSizeEvent event( wxSize(win->m_width,win->m_height), win->GetId() );
102 event.SetEventObject( win );
103 win->HandleWindowEvent( event );
104 }
105 }
106
107 //-----------------------------------------------------------------------------
108 // emission hook for "parent-set"
109 //-----------------------------------------------------------------------------
110
111 extern "C" {
112 static gboolean
113 parent_set_hook(GSignalInvocationHint*, guint, const GValue* param_values, void* data)
114 {
115 wxGLCanvas* win = (wxGLCanvas*)data;
116 if (g_value_peek_pointer(&param_values[0]) == win->m_wxwindow)
117 {
118 const XVisualInfo* xvi = win->GetXVisualInfo();
119 GdkVisual* visual = gtk_widget_get_visual(win->m_wxwindow);
120 if (GDK_VISUAL_XVISUAL(visual)->visualid != xvi->visualid)
121 {
122 GdkScreen* screen = gtk_widget_get_screen(win->m_wxwindow);
123 visual = gdk_x11_screen_lookup_visual(screen, xvi->visualid);
124 #ifdef __WXGTK3__
125 gtk_widget_set_visual(win->m_wxwindow, visual);
126 #else
127 GdkColormap* colormap = gdk_colormap_new(visual, false);
128 gtk_widget_set_colormap(win->m_wxwindow, colormap);
129 g_object_unref(colormap);
130 #endif
131 }
132 // remove hook
133 return false;
134 }
135 return true;
136 }
137 }
138
139 //---------------------------------------------------------------------------
140 // wxGlCanvas
141 //---------------------------------------------------------------------------
142
143 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
144
145 wxGLCanvas::wxGLCanvas(wxWindow *parent,
146 wxWindowID id,
147 const int *attribList,
148 const wxPoint& pos,
149 const wxSize& size,
150 long style,
151 const wxString& name,
152 const wxPalette& palette)
153 #if WXWIN_COMPATIBILITY_2_8
154 : m_createImplicitContext(false)
155 #endif
156 {
157 Create(parent, id, pos, size, style, name, attribList, palette);
158 }
159
160 #if WXWIN_COMPATIBILITY_2_8
161
162 wxGLCanvas::wxGLCanvas(wxWindow *parent,
163 wxWindowID id,
164 const wxPoint& pos,
165 const wxSize& size,
166 long style,
167 const wxString& name,
168 const int *attribList,
169 const wxPalette& palette)
170 : m_createImplicitContext(true)
171 {
172 m_sharedContext = NULL;
173 m_sharedContextOf = NULL;
174
175 Create(parent, id, pos, size, style, name, attribList, palette);
176 }
177
178 wxGLCanvas::wxGLCanvas(wxWindow *parent,
179 const wxGLContext *shared,
180 wxWindowID id,
181 const wxPoint& pos,
182 const wxSize& size,
183 long style,
184 const wxString& name,
185 const int *attribList,
186 const wxPalette& palette)
187 : m_createImplicitContext(true)
188 {
189 m_sharedContext = const_cast<wxGLContext *>(shared);
190
191 Create(parent, id, pos, size, style, name, attribList, palette);
192 }
193
194 wxGLCanvas::wxGLCanvas(wxWindow *parent,
195 const wxGLCanvas *shared,
196 wxWindowID id,
197 const wxPoint& pos, const wxSize& size,
198 long style, const wxString& name,
199 const int *attribList,
200 const wxPalette& palette )
201 : m_createImplicitContext(true)
202 {
203 m_sharedContext = NULL;
204 m_sharedContextOf = const_cast<wxGLCanvas *>(shared);
205
206 Create(parent, id, pos, size, style, name, attribList, palette);
207 }
208
209 #endif // WXWIN_COMPATIBILITY_2_8
210
211 bool wxGLCanvas::Create(wxWindow *parent,
212 wxWindowID id,
213 const wxPoint& pos,
214 const wxSize& size,
215 long style,
216 const wxString& name,
217 const int *attribList,
218 const wxPalette& palette)
219 {
220 #if wxUSE_PALETTE
221 wxASSERT_MSG( !palette.IsOk(), wxT("palettes not supported") );
222 #endif // wxUSE_PALETTE
223 wxUnusedVar(palette); // Unused when wxDEBUG_LEVEL==0
224
225 m_exposed = false;
226 m_noExpose = true;
227 m_nativeSizeEvent = true;
228 #ifdef __WXGTK3__
229 m_cairoPaintContext = NULL;
230 m_backgroundStyle = wxBG_STYLE_PAINT;
231 #endif
232
233 if ( !InitVisual(attribList) )
234 return false;
235
236 // watch for the "parent-set" signal on m_wxwindow so we can set colormap
237 // before m_wxwindow is realized (which will occur before
238 // wxWindow::Create() returns if parent is already visible)
239 unsigned sig_id = g_signal_lookup("parent-set", GTK_TYPE_WIDGET);
240 g_signal_add_emission_hook(sig_id, 0, parent_set_hook, this, NULL);
241
242 wxWindow::Create( parent, id, pos, size, style, name );
243
244 gtk_widget_set_double_buffered(m_wxwindow, false);
245
246 #if WXWIN_COMPATIBILITY_2_8
247 g_signal_connect(m_wxwindow, "realize", G_CALLBACK(gtk_glwindow_realized_callback), this);
248 #endif // WXWIN_COMPATIBILITY_2_8
249 #ifdef __WXGTK3__
250 g_signal_connect(m_wxwindow, "draw", G_CALLBACK(draw), this);
251 #else
252 g_signal_connect(m_wxwindow, "map", G_CALLBACK(gtk_glwindow_map_callback), this);
253 g_signal_connect(m_wxwindow, "expose_event", G_CALLBACK(gtk_glwindow_expose_callback), this);
254 #endif
255 g_signal_connect(m_widget, "size_allocate", G_CALLBACK(gtk_glcanvas_size_callback), this);
256
257 #if WXWIN_COMPATIBILITY_2_8
258 // if our parent window is already visible, we had been realized before we
259 // connected to the "realize" signal and hence our m_glContext hasn't been
260 // initialized yet and we have to do it now
261 if (gtk_widget_get_realized(m_wxwindow))
262 gtk_glwindow_realized_callback( m_wxwindow, this );
263 #endif // WXWIN_COMPATIBILITY_2_8
264
265 #ifndef __WXGTK3__
266 if (gtk_widget_get_mapped(m_wxwindow))
267 gtk_glwindow_map_callback( m_wxwindow, this );
268 #endif
269
270 return true;
271 }
272
273 bool wxGLCanvas::SetBackgroundStyle(wxBackgroundStyle /* style */)
274 {
275 return false;
276 }
277
278 Window wxGLCanvas::GetXWindow() const
279 {
280 GdkWindow* window = GTKGetDrawingWindow();
281 return window ? GDK_WINDOW_XID(window) : 0;
282 }
283
284 void wxGLCanvas::OnInternalIdle()
285 {
286 if (m_exposed)
287 {
288 #ifdef __WXGTK3__
289 GTKSendPaintEvents(m_cairoPaintContext);
290 cairo_destroy(m_cairoPaintContext);
291 m_cairoPaintContext = NULL;
292 #else
293 wxPaintEvent event( GetId() );
294 event.SetEventObject( this );
295 HandleWindowEvent( event );
296 #endif
297
298 m_exposed = false;
299 GetUpdateRegion().Clear();
300 }
301
302 wxWindow::OnInternalIdle();
303 }
304
305 #if WXWIN_COMPATIBILITY_2_8
306
307 void wxGLCanvas::GTKInitImplicitContext()
308 {
309 if ( !m_glContext && m_createImplicitContext )
310 {
311 wxGLContext *share = m_sharedContext;
312 if ( !share && m_sharedContextOf )
313 share = m_sharedContextOf->m_glContext;
314
315 m_glContext = new wxGLContext(this, share);
316 }
317 }
318
319 #endif // WXWIN_COMPATIBILITY_2_8
320
321 #endif // wxUSE_GLCANVAS