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