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