]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/frame.cpp
Ensure that validators work even in presence of pushed event handlers.
[wxWidgets.git] / src / gtk / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/frame.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #include "wx/frame.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/menu.h"
17 #include "wx/toolbar.h"
18 #include "wx/statusbr.h"
19 #endif // WX_PRECOMP
20
21 #include <gtk/gtk.h>
22
23 #if wxUSE_LIBHILDON
24 #include <hildon-widgets/hildon-window.h>
25 #endif // wxUSE_LIBHILDON
26
27 #if wxUSE_LIBHILDON2
28 #include <hildon/hildon.h>
29 #endif // wxUSE_LIBHILDON2
30
31 // ----------------------------------------------------------------------------
32 // event tables
33 // ----------------------------------------------------------------------------
34
35 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxTopLevelWindow)
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // ----------------------------------------------------------------------------
42 // wxFrame creation
43 // ----------------------------------------------------------------------------
44
45 void wxFrame::Init()
46 {
47 m_fsSaveFlag = 0;
48 }
49
50 bool wxFrame::Create( wxWindow *parent,
51 wxWindowID id,
52 const wxString& title,
53 const wxPoint& pos,
54 const wxSize& sizeOrig,
55 long style,
56 const wxString &name )
57 {
58 return wxFrameBase::Create(parent, id, title, pos, sizeOrig, style, name);
59 }
60
61 wxFrame::~wxFrame()
62 {
63 SendDestroyEvent();
64
65 DeleteAllBars();
66 }
67
68 // ----------------------------------------------------------------------------
69 // overridden wxWindow methods
70 // ----------------------------------------------------------------------------
71
72 void wxFrame::DoGetClientSize( int *width, int *height ) const
73 {
74 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
75
76 wxFrameBase::DoGetClientSize(width, height);
77
78 if (height)
79 {
80 #if wxUSE_MENUS_NATIVE
81 // menu bar
82 if (m_frameMenuBar && m_frameMenuBar->IsShown())
83 {
84 GtkRequisition req;
85 gtk_widget_size_request(m_frameMenuBar->m_widget, &req);
86 #if !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
87 *height -= req.height;
88 #endif
89 }
90 #endif // wxUSE_MENUS_NATIVE
91
92 #if wxUSE_STATUSBAR
93 // status bar
94 if (m_frameStatusBar && m_frameStatusBar->IsShown())
95 *height -= m_frameStatusBar->m_height;
96 #endif // wxUSE_STATUSBAR
97 }
98
99 #if wxUSE_TOOLBAR
100 // tool bar
101 if (m_frameToolBar && m_frameToolBar->IsShown())
102 {
103 GtkRequisition req;
104 gtk_widget_size_request(m_frameToolBar->m_widget, &req);
105 if (m_frameToolBar->IsVertical())
106 {
107 if (width)
108 *width -= req.width;
109 }
110 else
111 {
112 if (height)
113 *height -= req.height;
114 }
115 }
116 #endif // wxUSE_TOOLBAR
117
118 if (width != NULL && *width < 0)
119 *width = 0;
120 if (height != NULL && *height < 0)
121 *height = 0;
122 }
123
124 #if wxUSE_MENUS && wxUSE_ACCEL
125 // Helper for wxCreateAcceleratorTableForMenuBar
126 static void wxAddAccelerators(wxList& accelEntries, wxMenu* menu)
127 {
128 size_t i;
129 for (i = 0; i < menu->GetMenuItems().GetCount(); i++)
130 {
131 wxMenuItem* item = (wxMenuItem*) menu->GetMenuItems().Item(i)->GetData();
132 if (item->GetSubMenu())
133 {
134 wxAddAccelerators(accelEntries, item->GetSubMenu());
135 }
136 else if (!item->GetItemLabel().IsEmpty())
137 {
138 wxAcceleratorEntry* entry = wxAcceleratorEntry::Create(item->GetItemLabel());
139 if (entry)
140 {
141 entry->Set(entry->GetFlags(), entry->GetKeyCode(), item->GetId());
142 accelEntries.Append((wxObject*) entry);
143 }
144 }
145 }
146 }
147
148 // Create an accelerator table consisting of all the accelerators
149 // from the menubar in the given menus
150 static wxAcceleratorTable wxCreateAcceleratorTableForMenuBar(wxMenuBar* menuBar)
151 {
152 wxList accelEntries;
153
154 size_t i;
155 for (i = 0; i < menuBar->GetMenuCount(); i++)
156 {
157 wxAddAccelerators(accelEntries, menuBar->GetMenu(i));
158 }
159
160 size_t n = accelEntries.GetCount();
161
162 if (n == 0)
163 return wxAcceleratorTable();
164
165 wxAcceleratorEntry* entries = new wxAcceleratorEntry[n];
166
167 for (i = 0; i < accelEntries.GetCount(); i++)
168 {
169 wxAcceleratorEntry* entry = (wxAcceleratorEntry*) accelEntries.Item(i)->GetData();
170 entries[i] = (*entry);
171 delete entry;
172
173 }
174
175 wxAcceleratorTable table(n, entries);
176 delete[] entries;
177
178 return table;
179 }
180 #endif // wxUSE_MENUS && wxUSE_ACCEL
181
182 bool wxFrame::ShowFullScreen(bool show, long style)
183 {
184 if (!wxFrameBase::ShowFullScreen(show, style))
185 return false;
186
187 #if wxUSE_MENUS && wxUSE_ACCEL
188 if (show && GetMenuBar())
189 {
190 wxAcceleratorTable table(wxCreateAcceleratorTableForMenuBar(GetMenuBar()));
191 if (table.IsOk())
192 SetAcceleratorTable(table);
193 }
194 #endif // wxUSE_MENUS && wxUSE_ACCEL
195
196 wxWindow* const bar[] = {
197 #if wxUSE_MENUS
198 m_frameMenuBar,
199 #else
200 NULL,
201 #endif
202 #if wxUSE_TOOLBAR
203 m_frameToolBar,
204 #else
205 NULL,
206 #endif
207 #if wxUSE_STATUSBAR
208 m_frameStatusBar,
209 #else
210 NULL,
211 #endif
212 };
213 const long fsNoBar[] = {
214 wxFULLSCREEN_NOMENUBAR, wxFULLSCREEN_NOTOOLBAR, wxFULLSCREEN_NOSTATUSBAR
215 };
216 for (int i = 0; i < 3; i++)
217 {
218 if (show)
219 {
220 if (bar[i] && (style & fsNoBar[i]))
221 {
222 if (bar[i]->IsShown())
223 bar[i]->Show(false);
224 else
225 style &= ~fsNoBar[i];
226 }
227 }
228 else
229 {
230 if (bar[i] && (m_fsSaveFlag & fsNoBar[i]))
231 bar[i]->Show(true);
232 }
233 }
234 if (show)
235 m_fsSaveFlag = style;
236
237 return true;
238 }
239
240 void wxFrame::OnInternalIdle()
241 {
242 wxFrameBase::OnInternalIdle();
243
244 #if wxUSE_MENUS_NATIVE
245 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
246 #endif // wxUSE_MENUS_NATIVE
247 #if wxUSE_TOOLBAR
248 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
249 #endif
250 #if wxUSE_STATUSBAR
251 if (m_frameStatusBar)
252 {
253 m_frameStatusBar->OnInternalIdle();
254
255 // There may be controls in the status bar that
256 // need to be updated
257 for ( wxWindowList::compatibility_iterator node = m_frameStatusBar->GetChildren().GetFirst();
258 node;
259 node = node->GetNext() )
260 {
261 wxWindow *child = node->GetData();
262 child->OnInternalIdle();
263 }
264 }
265 #endif
266 }
267
268 // ----------------------------------------------------------------------------
269 // menu/tool/status bar stuff
270 // ----------------------------------------------------------------------------
271
272 #if wxUSE_MENUS_NATIVE
273
274 void wxFrame::DetachMenuBar()
275 {
276 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
277 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
278
279 if ( m_frameMenuBar )
280 {
281 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
282 hildon_window_set_menu(HILDON_WINDOW(m_widget), NULL);
283 #else // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
284 gtk_widget_ref( m_frameMenuBar->m_widget );
285
286 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
287 #endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2 /!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
288 }
289
290 wxFrameBase::DetachMenuBar();
291
292 // make sure next size_allocate causes a wxSizeEvent
293 m_oldClientWidth = 0;
294 }
295
296 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
297 {
298 wxFrameBase::AttachMenuBar(menuBar);
299
300 if (m_frameMenuBar)
301 {
302 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
303 hildon_window_set_menu(HILDON_WINDOW(m_widget),
304 GTK_MENU(m_frameMenuBar->m_menubar));
305 #else // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
306 m_frameMenuBar->SetParent(this);
307
308 // menubar goes into top of vbox (m_mainWidget)
309 gtk_box_pack_start(
310 GTK_BOX(m_mainWidget), menuBar->m_widget, false, false, 0);
311 gtk_box_reorder_child(GTK_BOX(m_mainWidget), menuBar->m_widget, 0);
312
313 // disconnect wxWindowGTK "size_request" handler,
314 // it interferes with sizing of detached GtkHandleBox
315 gulong handler_id = g_signal_handler_find(
316 menuBar->m_widget,
317 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
318 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
319 0, NULL, NULL, menuBar);
320 if (handler_id != 0)
321 g_signal_handler_disconnect(menuBar->m_widget, handler_id);
322
323 // reset size request to allow native sizing to work
324 gtk_widget_set_size_request(menuBar->m_widget, -1, -1);
325
326 gtk_widget_show( m_frameMenuBar->m_widget );
327 #endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2/!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
328 }
329 // make sure next size_allocate causes a wxSizeEvent
330 m_oldClientWidth = 0;
331 }
332 #endif // wxUSE_MENUS_NATIVE
333
334 #if wxUSE_TOOLBAR
335
336 void wxFrame::SetToolBar(wxToolBar *toolbar)
337 {
338 m_frameToolBar = toolbar;
339 if (toolbar)
340 {
341 if (toolbar->IsVertical())
342 {
343 // Vertical toolbar and m_wxwindow go into an hbox, inside the
344 // vbox (m_mainWidget). hbox is created on demand.
345 GtkWidget* hbox = m_wxwindow->parent;
346 if (!GTK_IS_HBOX(hbox))
347 {
348 hbox = gtk_hbox_new(false, 0);
349 gtk_widget_show(hbox);
350 gtk_container_add(GTK_CONTAINER(m_mainWidget), hbox);
351 gtk_widget_reparent(m_wxwindow, hbox);
352 }
353 gtk_widget_reparent(toolbar->m_widget, hbox);
354 gtk_box_set_child_packing(GTK_BOX(hbox),
355 toolbar->m_widget, false, false, 0, GTK_PACK_START);
356
357 int pos = 0; // left
358 if (toolbar->HasFlag(wxTB_RIGHT))
359 pos = 1; // right
360 gtk_box_reorder_child(GTK_BOX(hbox), toolbar->m_widget, pos);
361 }
362 else
363 {
364 // Horizontal toolbar goes into vbox (m_mainWidget)
365 gtk_widget_reparent(toolbar->m_widget, m_mainWidget);
366 gtk_box_set_child_packing(GTK_BOX(m_mainWidget),
367 toolbar->m_widget, false, false, 0, GTK_PACK_START);
368
369 int pos = 0; // top
370 if (m_frameMenuBar)
371 pos = 1; // below menubar
372 if (toolbar->HasFlag(wxTB_BOTTOM))
373 pos += 2; // below client area (m_wxwindow)
374 gtk_box_reorder_child(
375 GTK_BOX(m_mainWidget), toolbar->m_widget, pos);
376 }
377
378 // disconnect wxWindowGTK "size_request" handler,
379 // it interferes with sizing of detached GtkHandleBox
380 gulong handler_id = g_signal_handler_find(
381 toolbar->m_widget,
382 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
383 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
384 0, NULL, NULL, toolbar);
385 if (handler_id != 0)
386 g_signal_handler_disconnect(toolbar->m_widget, handler_id);
387
388 // reset size request to allow native sizing to work
389 gtk_widget_set_size_request(toolbar->m_widget, -1, -1);
390 }
391 // make sure next size_allocate causes a wxSizeEvent
392 m_oldClientWidth = 0;
393 }
394
395 #endif // wxUSE_TOOLBAR
396
397 #if wxUSE_STATUSBAR
398
399 void wxFrame::SetStatusBar(wxStatusBar *statbar)
400 {
401 m_frameStatusBar = statbar;
402 if (statbar)
403 {
404 // statusbar goes into bottom of vbox (m_mainWidget)
405 gtk_widget_reparent(statbar->m_widget, m_mainWidget);
406 gtk_box_set_child_packing(GTK_BOX(m_mainWidget),
407 statbar->m_widget, false, false, 0, GTK_PACK_END);
408 // make sure next size_allocate on statusbar causes a size event
409 statbar->m_oldClientWidth = 0;
410 }
411 // make sure next size_allocate causes a wxSizeEvent
412 m_oldClientWidth = 0;
413 }
414 #endif // wxUSE_STATUSBAR