1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/frame.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
17 #include "wx/toolbar.h"
18 #include "wx/statusbr.h"
21 #include "wx/gtk/private.h"
22 #include "wx/gtk/win_gtk.h"
24 // ----------------------------------------------------------------------------
26 // ----------------------------------------------------------------------------
28 static const int wxSTATUS_HEIGHT
= 25;
29 static const int wxPLACE_HOLDER
= 0;
31 // ----------------------------------------------------------------------------
33 // ----------------------------------------------------------------------------
35 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
)
37 // ============================================================================
39 // ============================================================================
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 #if wxUSE_MENUS_NATIVE
47 //-----------------------------------------------------------------------------
48 // "child_attached" of menu bar
49 //-----------------------------------------------------------------------------
52 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
54 if (!win
->m_hasVMT
) return;
56 win
->m_menuBarDetached
= false;
61 //-----------------------------------------------------------------------------
62 // "child_detached" of menu bar
63 //-----------------------------------------------------------------------------
66 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
69 wxapp_install_idle_handler();
71 if (!win
->m_hasVMT
) return;
73 // Raise the client area area
74 gdk_window_raise( win
->m_wxwindow
->window
);
76 win
->m_menuBarDetached
= true;
81 #endif // wxUSE_MENUS_NATIVE
84 //-----------------------------------------------------------------------------
85 // "child_attached" of tool bar
86 //-----------------------------------------------------------------------------
89 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
91 if (!win
->m_hasVMT
) return;
93 win
->m_toolBarDetached
= false;
98 //-----------------------------------------------------------------------------
99 // "child_detached" of tool bar
100 //-----------------------------------------------------------------------------
103 static void gtk_toolbar_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
106 wxapp_install_idle_handler();
108 if (!win
->m_hasVMT
) return;
110 // Raise the client area area
111 gdk_window_raise( win
->m_wxwindow
->window
);
113 win
->m_toolBarDetached
= true;
114 win
->GtkUpdateSize();
117 #endif // wxUSE_TOOLBAR
120 // ----------------------------------------------------------------------------
122 // ----------------------------------------------------------------------------
124 //-----------------------------------------------------------------------------
125 // InsertChild for wxFrame
126 //-----------------------------------------------------------------------------
128 /* Callback for wxFrame. This very strange beast has to be used because
129 * C++ has no virtual methods in a constructor. We have to emulate a
130 * virtual function here as wxWidgets requires different ways to insert
131 * a child in container classes. */
133 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
135 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
137 if (!parent
->m_insertInClientArea
)
139 // These are outside the client area
140 wxFrame
* frame
= (wxFrame
*) parent
;
141 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
142 GTK_WIDGET(child
->m_widget
),
148 #if wxUSE_TOOLBAR_NATIVE
149 // We connect to these events for recalculating the client area
150 // space when the toolbar is floating
151 if (wxIS_KIND_OF(child
,wxToolBar
))
153 wxToolBar
*toolBar
= (wxToolBar
*) child
;
154 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
156 g_signal_connect (toolBar
->m_widget
, "child_attached",
157 G_CALLBACK (gtk_toolbar_attached_callback
),
159 g_signal_connect (toolBar
->m_widget
, "child_detached",
160 G_CALLBACK (gtk_toolbar_detached_callback
),
164 #endif // wxUSE_TOOLBAR
168 // These are inside the client area
169 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
170 GTK_WIDGET(child
->m_widget
),
178 // ----------------------------------------------------------------------------
180 // ----------------------------------------------------------------------------
184 m_menuBarDetached
= false;
185 m_toolBarDetached
= false;
189 bool wxFrame
::Create( wxWindow
*parent
,
191 const wxString
& title
,
193 const wxSize
& sizeOrig
,
195 const wxString
&name
)
197 bool rt
= wxTopLevelWindow
::Create(parent
, id
, title
, pos
, sizeOrig
,
199 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
206 m_isBeingDeleted
= true;
210 // ----------------------------------------------------------------------------
211 // overridden wxWindow methods
212 // ----------------------------------------------------------------------------
214 void wxFrame
::DoGetClientSize( int *width
, int *height
) const
216 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
218 wxTopLevelWindow
::DoGetClientSize( width
, height
);
222 #if wxUSE_MENUS_NATIVE
224 if (m_frameMenuBar
&& !(m_fsIsShowing
&& (m_fsSaveFlag
& wxFULLSCREEN_NOMENUBAR
!= 0)))
226 if (!m_menuBarDetached
)
227 (*height
) -= m_menuBarHeight
;
229 (*height
) -= wxPLACE_HOLDER
;
231 #endif // wxUSE_MENUS_NATIVE
235 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown() &&
236 !(m_fsIsShowing
&& (m_fsSaveFlag
& wxFULLSCREEN_NOSTATUSBAR
!= 0)))
237 (*height
) -= wxSTATUS_HEIGHT
;
238 #endif // wxUSE_STATUSBAR
243 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
245 if (m_toolBarDetached
)
248 *height
-= wxPLACE_HOLDER
;
253 m_frameToolBar
->GetSize( &x
, &y
);
254 if ( m_frameToolBar
->IsVertical() )
266 #endif // wxUSE_TOOLBAR
268 if (width
!= NULL
&& *width
< 0)
270 if (height
!= NULL
&& *height
< 0)
274 void wxFrame
::DoSetClientSize( int width
, int height
)
276 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
278 #if wxUSE_MENUS_NATIVE
280 if (m_frameMenuBar
&& !(m_fsIsShowing
&& (m_fsSaveFlag
& wxFULLSCREEN_NOMENUBAR
!= 0)))
282 if (!m_menuBarDetached
)
283 height
+= m_menuBarHeight
;
285 height
+= wxPLACE_HOLDER
;
287 #endif // wxUSE_MENUS_NATIVE
291 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown() &&
292 !(m_fsIsShowing
&& (m_fsSaveFlag
& wxFULLSCREEN_NOSTATUSBAR
!= 0)))
293 height
+= wxSTATUS_HEIGHT
;
298 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
300 if (m_toolBarDetached
)
302 height
+= wxPLACE_HOLDER
;
307 m_frameToolBar
->GetSize( &x
, &y
);
308 if ( m_frameToolBar
->IsVertical() )
320 wxTopLevelWindow
::DoSetClientSize( width
, height
);
323 void wxFrame
::GtkOnSize()
326 if (m_resizing
) return;
329 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
330 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
332 // space occupied by m_frameToolBar and m_frameMenuBar
333 int client_area_x_offset
= 0,
334 client_area_y_offset
= 0;
336 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
337 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
338 set in wxFrame::Create so it is used to check what kind of frame we
339 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
340 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
341 importantly) m_mainWidget */
343 int minWidth
= GetMinWidth(),
344 minHeight
= GetMinHeight(),
345 maxWidth
= GetMaxWidth(),
346 maxHeight
= GetMaxHeight();
348 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
349 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
350 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
351 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
356 gint flag
= 0; // GDK_HINT_POS;
357 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
358 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
360 geom
.min_width
= minWidth
;
361 geom
.min_height
= minHeight
;
362 geom
.max_width
= maxWidth
;
363 geom
.max_height
= maxHeight
;
364 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
367 (GdkWindowHints
) flag
);
369 // Rewrite this terrible code to using GtkVBox
371 // m_mainWidget holds the menubar, the toolbar and the client
372 // area, which is represented by m_wxwindow.
374 #if wxUSE_MENUS_NATIVE
375 if (m_frameMenuBar
&& !(m_fsIsShowing
&& (m_fsSaveFlag
& wxFULLSCREEN_NOMENUBAR
!= 0)))
377 if (!GTK_WIDGET_VISIBLE(m_frameMenuBar
->m_widget
))
378 gtk_widget_show( m_frameMenuBar
->m_widget
);
380 int yy
= m_miniEdge
+ m_miniTitle
;
381 int ww
= m_width
- 2*m_miniEdge
;
384 int hh
= m_menuBarHeight
;
385 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
386 m_frameMenuBar
->m_x
= xx
;
387 m_frameMenuBar
->m_y
= yy
;
388 m_frameMenuBar
->m_width
= ww
;
389 m_frameMenuBar
->m_height
= hh
;
390 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
391 m_frameMenuBar
->m_widget
,
393 client_area_y_offset
+= hh
;
399 if (GTK_WIDGET_VISIBLE(m_frameMenuBar
->m_widget
))
400 gtk_widget_hide( m_frameMenuBar
->m_widget
);
403 #endif // wxUSE_MENUS_NATIVE
406 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
407 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
410 int yy
= m_miniEdge
+ m_miniTitle
;
411 #if wxUSE_MENUS_NATIVE
414 if (!m_menuBarDetached
)
415 yy
+= m_menuBarHeight
;
417 yy
+= wxPLACE_HOLDER
;
419 #endif // wxUSE_MENUS_NATIVE
421 m_frameToolBar
->m_x
= xx
;
422 m_frameToolBar
->m_y
= yy
;
424 // don't change the toolbar's reported height/width
426 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
428 ww
= m_toolBarDetached ? wxPLACE_HOLDER
429 : m_frameToolBar
->m_width
;
430 hh
= m_height
- 2*m_miniEdge
;
432 client_area_x_offset
+= ww
;
434 else if( m_frameToolBar
->HasFlag(wxTB_RIGHT
) )
437 ww
= m_toolBarDetached ? wxPLACE_HOLDER
438 : m_frameToolBar
->m_width
;
439 xx
= GetClientSize().x
- 1;
440 hh
= m_height
- 2*m_miniEdge
;
445 else if( m_frameToolBar
->GetWindowStyle() & wxTB_BOTTOM
)
448 yy
= GetClientSize().y
;
449 #if wxUSE_MENUS_NATIVE
450 yy
+= m_menuBarHeight
;
451 #endif // wxUSE_MENU_NATIVE
452 m_frameToolBar
->m_x
= xx
;
453 m_frameToolBar
->m_y
= yy
;
454 ww
= m_width
- 2*m_miniEdge
;
455 hh
= m_toolBarDetached ? wxPLACE_HOLDER
456 : m_frameToolBar
->m_height
;
460 ww
= m_width
- 2*m_miniEdge
;
461 hh
= m_toolBarDetached ? wxPLACE_HOLDER
462 : m_frameToolBar
->m_height
;
464 client_area_y_offset
+= hh
;
471 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
472 m_frameToolBar
->m_widget
,
475 #endif // wxUSE_TOOLBAR
477 int client_x
= client_area_x_offset
+ m_miniEdge
;
478 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
479 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
480 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
485 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
487 client_x
, client_y
, client_w
, client_h
);
491 // If there is no m_mainWidget between m_widget and m_wxwindow there
492 // is no need to set the size or position of m_wxwindow.
496 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown() &&
497 !(m_fsIsShowing
&& (m_fsSaveFlag
& wxFULLSCREEN_NOSTATUSBAR
!= 0)))
499 if (!GTK_WIDGET_VISIBLE(m_frameStatusBar
->m_widget
))
500 gtk_widget_show( m_frameStatusBar
->m_widget
);
502 int xx
= 0 + m_miniEdge
;
503 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
504 int ww
= m_width
- 2*m_miniEdge
;
507 int hh
= wxSTATUS_HEIGHT
;
508 m_frameStatusBar
->m_x
= xx
;
509 m_frameStatusBar
->m_y
= yy
;
510 m_frameStatusBar
->m_width
= ww
;
511 m_frameStatusBar
->m_height
= hh
;
512 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
513 m_frameStatusBar
->m_widget
,
518 if (m_frameStatusBar
)
520 if (GTK_WIDGET_VISIBLE(m_frameStatusBar
->m_widget
))
521 gtk_widget_hide( m_frameStatusBar
->m_widget
);
524 #endif // wxUSE_STATUSBAR
528 // send size event to frame
529 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
530 event
.SetEventObject( this );
531 GetEventHandler()->ProcessEvent( event
);
534 // send size event to status bar
535 if (m_frameStatusBar
)
537 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
538 event2
.SetEventObject( m_frameStatusBar
);
539 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
541 #endif // wxUSE_STATUSBAR
546 void wxFrame
::OnInternalIdle()
548 wxFrameBase
::OnInternalIdle();
550 #if wxUSE_MENUS_NATIVE
551 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
552 #endif // wxUSE_MENUS_NATIVE
554 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
557 if (m_frameStatusBar
)
559 m_frameStatusBar
->OnInternalIdle();
561 // There may be controls in the status bar that
562 // need to be updated
563 for ( wxWindowList
::compatibility_iterator node
= m_frameStatusBar
->GetChildren().GetFirst();
565 node
= node
->GetNext() )
567 wxWindow
*child
= node
->GetData();
568 child
->OnInternalIdle();
574 // ----------------------------------------------------------------------------
575 // menu/tool/status bar stuff
576 // ----------------------------------------------------------------------------
578 #if wxUSE_MENUS_NATIVE
580 void wxFrame
::DetachMenuBar()
582 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
583 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
585 if ( m_frameMenuBar
)
587 m_frameMenuBar
->UnsetInvokingWindow( this );
589 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
591 g_signal_handlers_disconnect_by_func (m_frameMenuBar
->m_widget
,
592 (gpointer
) gtk_menu_attached_callback
,
595 g_signal_handlers_disconnect_by_func (m_frameMenuBar
->m_widget
,
596 (gpointer
) gtk_menu_detached_callback
,
600 gtk_widget_ref( m_frameMenuBar
->m_widget
);
602 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
605 wxFrameBase
::DetachMenuBar();
608 void wxFrame
::AttachMenuBar( wxMenuBar
*menuBar
)
610 wxFrameBase
::AttachMenuBar(menuBar
);
614 m_frameMenuBar
->SetInvokingWindow( this );
616 m_frameMenuBar
->SetParent(this);
617 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
618 m_frameMenuBar
->m_widget
,
621 m_frameMenuBar
->m_width
,
622 m_frameMenuBar
->m_height
);
624 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
626 g_signal_connect (menuBar
->m_widget
, "child_attached",
627 G_CALLBACK (gtk_menu_attached_callback
),
629 g_signal_connect (menuBar
->m_widget
, "child_detached",
630 G_CALLBACK (gtk_menu_detached_callback
),
634 gtk_widget_show( m_frameMenuBar
->m_widget
);
641 GtkUpdateSize(); // resize window in OnInternalIdle
645 void wxFrame
::UpdateMenuBarSize()
652 // this is called after Remove with a NULL m_frameMenuBar
653 if ( m_frameMenuBar
)
654 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request
)
655 (m_frameMenuBar
->m_widget
, &req
);
657 m_menuBarHeight
= req
.height
;
659 // resize window in OnInternalIdle
664 #endif // wxUSE_MENUS_NATIVE
668 wxToolBar
* wxFrame
::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
670 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
672 m_insertInClientArea
= false;
674 m_frameToolBar
= wxFrameBase
::CreateToolBar( style
, id
, name
);
676 m_insertInClientArea
= true;
680 return m_frameToolBar
;
683 void wxFrame
::SetToolBar(wxToolBar
*toolbar
)
685 bool hadTbar
= m_frameToolBar
!= NULL
;
687 wxFrameBase
::SetToolBar(toolbar
);
689 if ( m_frameToolBar
)
691 // insert into toolbar area if not already there
692 if ((m_frameToolBar
->m_widget
->parent
) &&
693 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
695 GetChildren().DeleteObject( m_frameToolBar
);
697 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
701 else // toolbar unset
703 // still need to update size if it had been there before
711 #endif // wxUSE_TOOLBAR
715 wxStatusBar
* wxFrame
::CreateStatusBar(int number
,
718 const wxString
& name
)
720 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
722 // because it will change when toolbar is added
725 return wxFrameBase
::CreateStatusBar( number
, style
, id
, name
);
728 void wxFrame
::SetStatusBar(wxStatusBar
*statbar
)
730 bool hadStatBar
= m_frameStatusBar
!= NULL
;
732 wxFrameBase
::SetStatusBar(statbar
);
734 if (hadStatBar
&& !m_frameStatusBar
)
738 void wxFrame
::PositionStatusBar()
740 if ( !m_frameStatusBar
)
745 #endif // wxUSE_STATUSBAR