Remove unneeded wxTLW child inserter function.
[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/win_gtk.h"
23
24 // ----------------------------------------------------------------------------
25 // constants
26 // ----------------------------------------------------------------------------
27
28 static const int wxSTATUS_HEIGHT = 25;
29 static const int wxPLACE_HOLDER = 0;
30
31 // ----------------------------------------------------------------------------
32 // event tables
33 // ----------------------------------------------------------------------------
34
35 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxTopLevelWindow)
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // ----------------------------------------------------------------------------
42 // GTK callbacks
43 // ----------------------------------------------------------------------------
44
45 #if wxUSE_MENUS_NATIVE
46
47 //-----------------------------------------------------------------------------
48 // "child_attached" of menu bar
49 //-----------------------------------------------------------------------------
50
51 extern "C" {
52 static void gtk_menu_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
53 {
54 if (!win->m_hasVMT) return;
55
56 win->m_menuBarDetached = false;
57 win->GtkUpdateSize();
58 }
59 }
60
61 //-----------------------------------------------------------------------------
62 // "child_detached" of menu bar
63 //-----------------------------------------------------------------------------
64
65 extern "C" {
66 static void gtk_menu_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
67 {
68 if (!win->m_hasVMT) return;
69
70 // Raise the client area area
71 gdk_window_raise( win->m_wxwindow->window );
72
73 win->m_menuBarDetached = true;
74 win->GtkUpdateSize();
75 }
76 }
77
78 #endif // wxUSE_MENUS_NATIVE
79
80 #if wxUSE_TOOLBAR
81 //-----------------------------------------------------------------------------
82 // "child_attached" of tool bar
83 //-----------------------------------------------------------------------------
84
85 extern "C" {
86 static void gtk_toolbar_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
87 {
88 if (!win->m_hasVMT) return;
89
90 win->m_toolBarDetached = false;
91 win->GtkUpdateSize();
92 }
93 }
94
95 //-----------------------------------------------------------------------------
96 // "child_detached" of tool bar
97 //-----------------------------------------------------------------------------
98
99 extern "C" {
100 static void gtk_toolbar_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
101 {
102 if (!win->m_hasVMT) return;
103
104 // Raise the client area area
105 gdk_window_raise( win->m_wxwindow->window );
106
107 win->m_toolBarDetached = true;
108 win->GtkUpdateSize();
109 }
110 }
111 #endif // wxUSE_TOOLBAR
112
113
114 // ----------------------------------------------------------------------------
115 // wxFrame itself
116 // ----------------------------------------------------------------------------
117
118 //-----------------------------------------------------------------------------
119 // InsertChild for wxFrame
120 //-----------------------------------------------------------------------------
121
122 /* Callback for wxFrame. This very strange beast has to be used because
123 * C++ has no virtual methods in a constructor. We have to emulate a
124 * virtual function here as wxWidgets requires different ways to insert
125 * a child in container classes. */
126
127 static void wxInsertChildInFrame(wxWindow* parent, wxWindow* child)
128 {
129 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
130
131 // These are outside the client area
132 wxFrame* frame = wx_static_cast(wxFrame*, parent);
133 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
134 child->m_widget,
135 child->m_x,
136 child->m_y,
137 child->m_width,
138 child->m_height );
139
140 #if wxUSE_TOOLBAR_NATIVE
141 // We connect to these events for recalculating the client area
142 // space when the toolbar is floating
143 if (wxIS_KIND_OF(child,wxToolBar))
144 {
145 if (child->HasFlag(wxTB_DOCKABLE))
146 {
147 g_signal_connect (child->m_widget, "child_attached",
148 G_CALLBACK (gtk_toolbar_attached_callback),
149 parent);
150 g_signal_connect (child->m_widget, "child_detached",
151 G_CALLBACK (gtk_toolbar_detached_callback),
152 parent);
153 }
154 }
155 #endif // wxUSE_TOOLBAR
156 }
157
158 // ----------------------------------------------------------------------------
159 // wxFrame creation
160 // ----------------------------------------------------------------------------
161
162 void wxFrame::Init()
163 {
164 m_menuBarDetached = false;
165 m_toolBarDetached = false;
166 m_menuBarHeight = 2;
167 }
168
169 bool wxFrame::Create( wxWindow *parent,
170 wxWindowID id,
171 const wxString& title,
172 const wxPoint& pos,
173 const wxSize& sizeOrig,
174 long style,
175 const wxString &name )
176 {
177 return wxFrameBase::Create(parent, id, title, pos, sizeOrig, style, name);
178 }
179
180 wxFrame::~wxFrame()
181 {
182 m_isBeingDeleted = true;
183 DeleteAllBars();
184 }
185
186 // ----------------------------------------------------------------------------
187 // overridden wxWindow methods
188 // ----------------------------------------------------------------------------
189
190 void wxFrame::DoGetClientSize( int *width, int *height ) const
191 {
192 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
193
194 wxFrameBase::DoGetClientSize(width, height);
195
196 if (height)
197 {
198 #if wxUSE_MENUS_NATIVE
199 // menu bar
200 if (m_frameMenuBar &&
201 GTK_WIDGET_VISIBLE(m_frameMenuBar->m_widget) && !m_menuBarDetached)
202 {
203 *height -= m_menuBarHeight;
204 }
205 #endif // wxUSE_MENUS_NATIVE
206
207 #if wxUSE_STATUSBAR
208 // status bar
209 if (m_frameStatusBar && GTK_WIDGET_VISIBLE(m_frameStatusBar->m_widget))
210 *height -= wxSTATUS_HEIGHT;
211 #endif // wxUSE_STATUSBAR
212 }
213
214 #if wxUSE_TOOLBAR
215 // tool bar
216 if (m_frameToolBar &&
217 GTK_WIDGET_VISIBLE(m_frameToolBar->m_widget) && !m_toolBarDetached)
218 {
219 if (m_frameToolBar->IsVertical())
220 {
221 if (width)
222 *width -= m_frameToolBar->GetSize().x;
223 }
224 else
225 {
226 if (height)
227 *height -= m_frameToolBar->GetSize().y;
228 }
229 }
230 #endif // wxUSE_TOOLBAR
231
232 if (width != NULL && *width < 0)
233 *width = 0;
234 if (height != NULL && *height < 0)
235 *height = 0;
236 }
237
238 void wxFrame::GtkOnSize()
239 {
240 // avoid recursions
241 if (m_resizing) return;
242 m_resizing = true;
243
244 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
245 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
246
247 // space occupied by m_frameToolBar and m_frameMenuBar
248 int client_area_x_offset = 0,
249 client_area_y_offset = 0;
250
251 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
252 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
253 set in wxFrame::Create so it is used to check what kind of frame we
254 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
255 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
256 importantly) m_mainWidget */
257
258 ConstrainSize();
259
260 if (m_mainWidget)
261 {
262 // TODO
263 // Rewrite this terrible code to using GtkVBox
264
265 // m_mainWidget holds the menubar, the toolbar and the client
266 // area, which is represented by m_wxwindow.
267
268 #if wxUSE_MENUS_NATIVE
269 if (m_frameMenuBar && !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOMENUBAR) != 0))
270 {
271 if (!GTK_WIDGET_VISIBLE(m_frameMenuBar->m_widget))
272 gtk_widget_show( m_frameMenuBar->m_widget );
273 int xx = m_miniEdge;
274 int yy = m_miniEdge + m_miniTitle;
275 int ww = m_width - 2*m_miniEdge;
276 if (ww < 0)
277 ww = 0;
278 int hh = m_menuBarHeight;
279 if (m_menuBarDetached) hh = wxPLACE_HOLDER;
280 m_frameMenuBar->m_x = xx;
281 m_frameMenuBar->m_y = yy;
282 m_frameMenuBar->m_width = ww;
283 m_frameMenuBar->m_height = hh;
284 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
285 m_frameMenuBar->m_widget,
286 xx, yy, ww, hh );
287 client_area_y_offset += hh;
288 }
289 else
290 {
291 if (m_frameMenuBar)
292 {
293 if (GTK_WIDGET_VISIBLE(m_frameMenuBar->m_widget))
294 gtk_widget_hide( m_frameMenuBar->m_widget );
295 }
296 }
297 #endif // wxUSE_MENUS_NATIVE
298
299 #if wxUSE_TOOLBAR
300 if ((m_frameToolBar) && m_frameToolBar->IsShown() &&
301 (m_frameToolBar->m_widget->parent == m_mainWidget))
302 {
303 int xx = m_miniEdge;
304 int yy = m_miniEdge + m_miniTitle;
305 #if wxUSE_MENUS_NATIVE
306 if (m_frameMenuBar)
307 {
308 if (!m_menuBarDetached)
309 yy += m_menuBarHeight;
310 else
311 yy += wxPLACE_HOLDER;
312 }
313 #endif // wxUSE_MENUS_NATIVE
314
315 m_frameToolBar->m_x = xx;
316 m_frameToolBar->m_y = yy;
317
318 // don't change the toolbar's reported height/width
319 int ww, hh;
320 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
321 {
322 ww = m_toolBarDetached ? wxPLACE_HOLDER
323 : m_frameToolBar->m_width;
324 hh = m_height - 2*m_miniEdge;
325
326 client_area_x_offset += ww;
327 }
328 else if( m_frameToolBar->HasFlag(wxTB_RIGHT) )
329 {
330 yy += 2;
331 ww = m_toolBarDetached ? wxPLACE_HOLDER
332 : m_frameToolBar->m_width;
333 xx = GetClientSize().x - 1;
334 hh = m_height - 2*m_miniEdge;
335 if( hh < 0 )
336 hh = 0;
337
338 }
339 else if( m_frameToolBar->GetWindowStyle() & wxTB_BOTTOM )
340 {
341 xx = m_miniEdge;
342 yy = GetClientSize().y;
343 #if wxUSE_MENUS_NATIVE
344 yy += m_menuBarHeight;
345 #endif // wxUSE_MENU_NATIVE
346 m_frameToolBar->m_x = xx;
347 m_frameToolBar->m_y = yy;
348 ww = m_width - 2*m_miniEdge;
349 hh = m_toolBarDetached ? wxPLACE_HOLDER
350 : m_frameToolBar->m_height;
351 }
352 else
353 {
354 ww = m_width - 2*m_miniEdge;
355 hh = m_toolBarDetached ? wxPLACE_HOLDER
356 : m_frameToolBar->m_height;
357
358 client_area_y_offset += hh;
359 }
360
361 if (ww < 0)
362 ww = 0;
363 if (hh < 0)
364 hh = 0;
365 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
366 m_frameToolBar->m_widget,
367 xx, yy, ww, hh );
368 }
369 #endif // wxUSE_TOOLBAR
370
371 int client_x = client_area_x_offset + m_miniEdge;
372 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
373 int client_w = m_width - client_area_x_offset - 2*m_miniEdge;
374 int client_h = m_height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
375 if (client_w < 0)
376 client_w = 0;
377 if (client_h < 0)
378 client_h = 0;
379 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
380 m_wxwindow,
381 client_x, client_y, client_w, client_h );
382 }
383 else
384 {
385 // If there is no m_mainWidget between m_widget and m_wxwindow there
386 // is no need to set the size or position of m_wxwindow.
387 }
388
389 #if wxUSE_STATUSBAR
390 if (m_frameStatusBar && m_frameStatusBar->IsShown() &&
391 !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOSTATUSBAR) != 0))
392 {
393 if (!GTK_WIDGET_VISIBLE(m_frameStatusBar->m_widget))
394 gtk_widget_show( m_frameStatusBar->m_widget );
395
396 int xx = 0 + m_miniEdge;
397 int yy = m_height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
398 int ww = m_width - 2*m_miniEdge;
399 if (ww < 0)
400 ww = 0;
401 int hh = wxSTATUS_HEIGHT;
402 m_frameStatusBar->m_x = xx;
403 m_frameStatusBar->m_y = yy;
404 m_frameStatusBar->m_width = ww;
405 m_frameStatusBar->m_height = hh;
406 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow),
407 m_frameStatusBar->m_widget,
408 xx, yy, ww, hh );
409 }
410 else
411 {
412 if (m_frameStatusBar)
413 {
414 if (GTK_WIDGET_VISIBLE(m_frameStatusBar->m_widget))
415 gtk_widget_hide( m_frameStatusBar->m_widget );
416 }
417 }
418 #endif // wxUSE_STATUSBAR
419
420 m_sizeSet = true;
421
422 // send size event to frame
423 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
424 event.SetEventObject( this );
425 GetEventHandler()->ProcessEvent( event );
426
427 #if wxUSE_STATUSBAR
428 // send size event to status bar
429 if (m_frameStatusBar)
430 {
431 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
432 event2.SetEventObject( m_frameStatusBar );
433 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
434 }
435 #endif // wxUSE_STATUSBAR
436
437 m_resizing = false;
438 }
439
440 void wxFrame::OnInternalIdle()
441 {
442 wxFrameBase::OnInternalIdle();
443
444 #if wxUSE_MENUS_NATIVE
445 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
446 #endif // wxUSE_MENUS_NATIVE
447 #if wxUSE_TOOLBAR
448 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
449 #endif
450 #if wxUSE_STATUSBAR
451 if (m_frameStatusBar)
452 {
453 m_frameStatusBar->OnInternalIdle();
454
455 // There may be controls in the status bar that
456 // need to be updated
457 for ( wxWindowList::compatibility_iterator node = m_frameStatusBar->GetChildren().GetFirst();
458 node;
459 node = node->GetNext() )
460 {
461 wxWindow *child = node->GetData();
462 child->OnInternalIdle();
463 }
464 }
465 #endif
466 }
467
468 // ----------------------------------------------------------------------------
469 // menu/tool/status bar stuff
470 // ----------------------------------------------------------------------------
471
472 #if wxUSE_MENUS_NATIVE
473
474 void wxFrame::DetachMenuBar()
475 {
476 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
477 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
478
479 if ( m_frameMenuBar )
480 {
481 m_frameMenuBar->UnsetInvokingWindow( this );
482
483 if (m_frameMenuBar->GetWindowStyle() & wxMB_DOCKABLE)
484 {
485 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
486 (gpointer) gtk_menu_attached_callback,
487 this);
488
489 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
490 (gpointer) gtk_menu_detached_callback,
491 this);
492 }
493
494 gtk_widget_ref( m_frameMenuBar->m_widget );
495
496 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
497 }
498
499 wxFrameBase::DetachMenuBar();
500 }
501
502 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
503 {
504 wxFrameBase::AttachMenuBar(menuBar);
505
506 if (m_frameMenuBar)
507 {
508 m_frameMenuBar->SetInvokingWindow( this );
509
510 m_frameMenuBar->SetParent(this);
511 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
512 m_frameMenuBar->m_widget,
513 m_frameMenuBar->m_x,
514 m_frameMenuBar->m_y,
515 m_frameMenuBar->m_width,
516 m_frameMenuBar->m_height );
517
518 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
519 {
520 g_signal_connect (menuBar->m_widget, "child_attached",
521 G_CALLBACK (gtk_menu_attached_callback),
522 this);
523 g_signal_connect (menuBar->m_widget, "child_detached",
524 G_CALLBACK (gtk_menu_detached_callback),
525 this);
526 }
527
528 gtk_widget_show( m_frameMenuBar->m_widget );
529
530 UpdateMenuBarSize();
531 }
532 else
533 {
534 m_menuBarHeight = 2;
535 GtkUpdateSize(); // resize window in OnInternalIdle
536 }
537 }
538
539 void wxFrame::UpdateMenuBarSize()
540 {
541 m_menuBarHeight = 2;
542
543 // this is called after Remove with a NULL m_frameMenuBar
544 if ( m_frameMenuBar )
545 {
546 GtkRequisition req;
547 gtk_widget_ensure_style(m_frameMenuBar->m_widget);
548 // have to call class method directly because
549 // "size_request" signal is overridden by wx
550 GTK_WIDGET_GET_CLASS(m_frameMenuBar->m_widget)->size_request(
551 m_frameMenuBar->m_widget, &req);
552
553 m_menuBarHeight = req.height;
554 }
555
556 // resize window in OnInternalIdle
557 GtkUpdateSize();
558 }
559
560 #endif // wxUSE_MENUS_NATIVE
561
562 #if wxUSE_TOOLBAR
563
564 wxToolBar* wxFrame::CreateToolBar( long style, wxWindowID id, const wxString& name )
565 {
566 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
567
568 InsertChildFunction save = m_insertCallback;
569 m_insertCallback = wxInsertChildInFrame;
570 m_frameToolBar = wxFrameBase::CreateToolBar( style, id, name );
571 m_insertCallback = save;
572
573 GtkUpdateSize();
574
575 return m_frameToolBar;
576 }
577
578 void wxFrame::SetToolBar(wxToolBar *toolbar)
579 {
580 bool hadTbar = m_frameToolBar != NULL;
581
582 wxFrameBase::SetToolBar(toolbar);
583
584 if ( m_frameToolBar )
585 {
586 // insert into toolbar area if not already there
587 if ((m_frameToolBar->m_widget->parent) &&
588 (m_frameToolBar->m_widget->parent != m_mainWidget))
589 {
590 GetChildren().DeleteObject( m_frameToolBar );
591
592 gtk_widget_reparent( m_frameToolBar->m_widget, m_mainWidget );
593 GtkUpdateSize();
594 }
595 }
596 else // toolbar unset
597 {
598 // still need to update size if it had been there before
599 if ( hadTbar )
600 {
601 GtkUpdateSize();
602 }
603 }
604 }
605
606 #endif // wxUSE_TOOLBAR
607
608 #if wxUSE_STATUSBAR
609
610 wxStatusBar* wxFrame::CreateStatusBar(int number,
611 long style,
612 wxWindowID id,
613 const wxString& name)
614 {
615 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
616
617 // because it will change when toolbar is added
618 GtkUpdateSize();
619
620 return wxFrameBase::CreateStatusBar( number, style, id, name );
621 }
622
623 void wxFrame::SetStatusBar(wxStatusBar *statbar)
624 {
625 bool hadStatBar = m_frameStatusBar != NULL;
626
627 wxFrameBase::SetStatusBar(statbar);
628
629 if (hadStatBar && !m_frameStatusBar)
630 GtkUpdateSize();
631 }
632
633 void wxFrame::PositionStatusBar()
634 {
635 if ( !m_frameStatusBar )
636 return;
637
638 GtkUpdateSize();
639 }
640 #endif // wxUSE_STATUSBAR