Use client size determined by size-allocate when possible
[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 #include "wx/gtk/private/gtk2-compat.h"
23
24 #if wxUSE_LIBHILDON
25 #include <hildon-widgets/hildon-window.h>
26 #endif // wxUSE_LIBHILDON
27
28 #if wxUSE_LIBHILDON2
29 #include <hildon/hildon.h>
30 #endif // wxUSE_LIBHILDON2
31
32 // ----------------------------------------------------------------------------
33 // event tables
34 // ----------------------------------------------------------------------------
35
36 // ============================================================================
37 // implementation
38 // ============================================================================
39
40 // ----------------------------------------------------------------------------
41 // wxFrame creation
42 // ----------------------------------------------------------------------------
43
44 void wxFrame::Init()
45 {
46 m_fsSaveFlag = 0;
47 }
48
49 bool wxFrame::Create( wxWindow *parent,
50 wxWindowID id,
51 const wxString& title,
52 const wxPoint& pos,
53 const wxSize& sizeOrig,
54 long style,
55 const wxString &name )
56 {
57 return wxFrameBase::Create(parent, id, title, pos, sizeOrig, style, name);
58 }
59
60 wxFrame::~wxFrame()
61 {
62 SendDestroyEvent();
63
64 DeleteAllBars();
65 }
66
67 // ----------------------------------------------------------------------------
68 // overridden wxWindow methods
69 // ----------------------------------------------------------------------------
70
71 void wxFrame::DoGetClientSize( int *width, int *height ) const
72 {
73 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
74
75 wxFrameBase::DoGetClientSize(width, height);
76
77 if (m_useCachedClientSize)
78 return;
79
80 if (height)
81 {
82 #if wxUSE_MENUS_NATIVE
83 // menu bar
84 if (m_frameMenuBar && m_frameMenuBar->IsShown())
85 {
86 int h;
87 gtk_widget_get_preferred_height(m_frameMenuBar->m_widget, NULL, &h);
88 #if !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
89 *height -= h;
90 #endif
91 }
92 #endif // wxUSE_MENUS_NATIVE
93
94 #if wxUSE_STATUSBAR
95 // status bar
96 if (m_frameStatusBar && m_frameStatusBar->IsShown())
97 *height -= m_frameStatusBar->m_height;
98 #endif // wxUSE_STATUSBAR
99 }
100
101 #if wxUSE_TOOLBAR
102 // tool bar
103 if (m_frameToolBar && m_frameToolBar->IsShown())
104 {
105 if (m_frameToolBar->IsVertical())
106 {
107 if (width)
108 {
109 int w;
110 gtk_widget_get_preferred_width(m_frameToolBar->m_widget, NULL, &w);
111 *width -= w;
112 }
113 }
114 else
115 {
116 if (height)
117 {
118 int h;
119 gtk_widget_get_preferred_height(m_frameToolBar->m_widget, NULL, &h);
120 *height -= h;
121 }
122 }
123 }
124 #endif // wxUSE_TOOLBAR
125
126 if (width != NULL && *width < 0)
127 *width = 0;
128 if (height != NULL && *height < 0)
129 *height = 0;
130 }
131
132 #if wxUSE_MENUS && wxUSE_ACCEL
133 // Helper for wxCreateAcceleratorTableForMenuBar
134 static void wxAddAccelerators(wxList& accelEntries, wxMenu* menu)
135 {
136 size_t i;
137 for (i = 0; i < menu->GetMenuItems().GetCount(); i++)
138 {
139 wxMenuItem* item = (wxMenuItem*) menu->GetMenuItems().Item(i)->GetData();
140 if (item->GetSubMenu())
141 {
142 wxAddAccelerators(accelEntries, item->GetSubMenu());
143 }
144 else if (!item->GetItemLabel().IsEmpty())
145 {
146 wxAcceleratorEntry* entry = wxAcceleratorEntry::Create(item->GetItemLabel());
147 if (entry)
148 {
149 entry->Set(entry->GetFlags(), entry->GetKeyCode(), item->GetId());
150 accelEntries.Append((wxObject*) entry);
151 }
152 }
153 }
154 }
155
156 // Create an accelerator table consisting of all the accelerators
157 // from the menubar in the given menus
158 static wxAcceleratorTable wxCreateAcceleratorTableForMenuBar(wxMenuBar* menuBar)
159 {
160 wxList accelEntries;
161
162 size_t i;
163 for (i = 0; i < menuBar->GetMenuCount(); i++)
164 {
165 wxAddAccelerators(accelEntries, menuBar->GetMenu(i));
166 }
167
168 size_t n = accelEntries.GetCount();
169
170 if (n == 0)
171 return wxAcceleratorTable();
172
173 wxAcceleratorEntry* entries = new wxAcceleratorEntry[n];
174
175 for (i = 0; i < accelEntries.GetCount(); i++)
176 {
177 wxAcceleratorEntry* entry = (wxAcceleratorEntry*) accelEntries.Item(i)->GetData();
178 entries[i] = (*entry);
179 delete entry;
180
181 }
182
183 wxAcceleratorTable table(n, entries);
184 delete[] entries;
185
186 return table;
187 }
188 #endif // wxUSE_MENUS && wxUSE_ACCEL
189
190 bool wxFrame::ShowFullScreen(bool show, long style)
191 {
192 if (!wxFrameBase::ShowFullScreen(show, style))
193 return false;
194
195 #if wxUSE_MENUS && wxUSE_ACCEL
196 if (show && GetMenuBar())
197 {
198 wxAcceleratorTable table(wxCreateAcceleratorTableForMenuBar(GetMenuBar()));
199 if (table.IsOk())
200 SetAcceleratorTable(table);
201 }
202 #endif // wxUSE_MENUS && wxUSE_ACCEL
203
204 wxWindow* const bar[] = {
205 #if wxUSE_MENUS
206 m_frameMenuBar,
207 #else
208 NULL,
209 #endif
210 #if wxUSE_TOOLBAR
211 m_frameToolBar,
212 #else
213 NULL,
214 #endif
215 #if wxUSE_STATUSBAR
216 m_frameStatusBar,
217 #else
218 NULL,
219 #endif
220 };
221 const long fsNoBar[] = {
222 wxFULLSCREEN_NOMENUBAR, wxFULLSCREEN_NOTOOLBAR, wxFULLSCREEN_NOSTATUSBAR
223 };
224 for (int i = 0; i < 3; i++)
225 {
226 if (show)
227 {
228 if (bar[i] && (style & fsNoBar[i]))
229 {
230 if (bar[i]->IsShown())
231 bar[i]->Show(false);
232 else
233 style &= ~fsNoBar[i];
234 }
235 }
236 else
237 {
238 if (bar[i] && (m_fsSaveFlag & fsNoBar[i]))
239 bar[i]->Show(true);
240 }
241 }
242 if (show)
243 m_fsSaveFlag = style;
244
245 return true;
246 }
247
248 bool wxFrame::SendIdleEvents(wxIdleEvent& event)
249 {
250 bool needMore = wxFrameBase::SendIdleEvents(event);
251
252 #if wxUSE_MENUS
253 if (m_frameMenuBar && m_frameMenuBar->SendIdleEvents(event))
254 needMore = true;
255 #endif
256 #if wxUSE_TOOLBAR
257 if (m_frameToolBar && m_frameToolBar->SendIdleEvents(event))
258 needMore = true;
259 #endif
260 #if wxUSE_STATUSBAR
261 if (m_frameStatusBar && m_frameStatusBar->SendIdleEvents(event))
262 needMore = true;
263 #endif
264
265 return needMore;
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 g_object_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_useCachedClientSize = false;
294 m_clientWidth = 0;
295 }
296
297 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
298 {
299 wxFrameBase::AttachMenuBar(menuBar);
300
301 if (m_frameMenuBar)
302 {
303 #if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
304 hildon_window_set_menu(HILDON_WINDOW(m_widget),
305 GTK_MENU(m_frameMenuBar->m_menubar));
306 #else // !wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
307 m_frameMenuBar->SetParent(this);
308
309 // menubar goes into top of vbox (m_mainWidget)
310 gtk_box_pack_start(
311 GTK_BOX(m_mainWidget), menuBar->m_widget, false, false, 0);
312 gtk_box_reorder_child(GTK_BOX(m_mainWidget), menuBar->m_widget, 0);
313
314 // reset size request to allow native sizing to work
315 gtk_widget_set_size_request(menuBar->m_widget, -1, -1);
316
317 gtk_widget_show( m_frameMenuBar->m_widget );
318 #endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2/!wxUSE_LIBHILDON && !wxUSE_LIBHILDON2
319 }
320 // make sure next size_allocate causes a wxSizeEvent
321 m_useCachedClientSize = false;
322 m_clientWidth = 0;
323 }
324 #endif // wxUSE_MENUS_NATIVE
325
326 #if wxUSE_TOOLBAR
327
328 void wxFrame::SetToolBar(wxToolBar *toolbar)
329 {
330 m_frameToolBar = toolbar;
331 if (toolbar)
332 {
333 if (toolbar->IsVertical())
334 {
335 // Vertical toolbar and m_wxwindow go into an hbox, inside the
336 // vbox (m_mainWidget). hbox is created on demand.
337 GtkWidget* hbox = gtk_widget_get_parent(m_wxwindow);
338 if (hbox == m_mainWidget)
339 {
340 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
341 gtk_widget_show(hbox);
342 gtk_box_pack_start(GTK_BOX(m_mainWidget), hbox, true, true, 0);
343 gtk_widget_reparent(m_wxwindow, hbox);
344 }
345 gtk_widget_reparent(toolbar->m_widget, hbox);
346 gtk_box_set_child_packing(GTK_BOX(hbox),
347 toolbar->m_widget, false, false, 0, GTK_PACK_START);
348
349 int pos = 0; // left
350 if (toolbar->HasFlag(wxTB_RIGHT))
351 pos = 1; // right
352 gtk_box_reorder_child(GTK_BOX(hbox), toolbar->m_widget, pos);
353 }
354 else
355 {
356 // Horizontal toolbar goes into vbox (m_mainWidget)
357 gtk_widget_reparent(toolbar->m_widget, m_mainWidget);
358 gtk_box_set_child_packing(GTK_BOX(m_mainWidget),
359 toolbar->m_widget, false, false, 0, GTK_PACK_START);
360
361 int pos = 0; // top
362 if (m_frameMenuBar)
363 pos = 1; // below menubar
364 if (toolbar->HasFlag(wxTB_BOTTOM))
365 pos += 2; // below client area (m_wxwindow)
366 gtk_box_reorder_child(
367 GTK_BOX(m_mainWidget), toolbar->m_widget, pos);
368 }
369 // reset size request to allow native sizing to work
370 gtk_widget_set_size_request(toolbar->m_widget, -1, -1);
371 }
372 // make sure next size_allocate causes a wxSizeEvent
373 m_useCachedClientSize = false;
374 m_clientWidth = 0;
375 }
376
377 #endif // wxUSE_TOOLBAR
378
379 #if wxUSE_STATUSBAR
380
381 void wxFrame::SetStatusBar(wxStatusBar *statbar)
382 {
383 m_frameStatusBar = statbar;
384 if (statbar)
385 {
386 // statusbar goes into bottom of vbox (m_mainWidget)
387 gtk_widget_reparent(statbar->m_widget, m_mainWidget);
388 gtk_box_set_child_packing(GTK_BOX(m_mainWidget),
389 statbar->m_widget, false, false, 0, GTK_PACK_END);
390 // make sure next size_allocate on statusbar causes a size event
391 statbar->m_useCachedClientSize = false;
392 statbar->m_clientWidth = 0;
393 int h = -1;
394 if (statbar->m_wxwindow)
395 {
396 // statusbar is not a native widget, need to set height request
397 h = statbar->m_height;
398 }
399 gtk_widget_set_size_request(statbar->m_widget, -1, h);
400 }
401 // make sure next size_allocate causes a wxSizeEvent
402 m_useCachedClientSize = false;
403 m_clientWidth = 0;
404 }
405 #endif // wxUSE_STATUSBAR