1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk1/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" 
  13 // ============================================================================ 
  15 // ============================================================================ 
  17 // ---------------------------------------------------------------------------- 
  19 // ---------------------------------------------------------------------------- 
  25     #include "wx/dcclient.h" 
  27     #include "wx/dialog.h" 
  28     #include "wx/control.h" 
  32     #include "wx/toolbar.h" 
  35     #include "wx/statusbr.h" 
  39 #include "wx/gtk1/private.h" 
  41 #include <gdk/gdkkeysyms.h> 
  44 #include "wx/gtk1/win_gtk.h" 
  46 // ---------------------------------------------------------------------------- 
  48 // ---------------------------------------------------------------------------- 
  50 const int wxSTATUS_HEIGHT  
= 25; 
  51 const int wxPLACE_HOLDER   
= 0; 
  53 // ---------------------------------------------------------------------------- 
  55 // ---------------------------------------------------------------------------- 
  57 extern void wxapp_install_idle_handler(); 
  60 // ---------------------------------------------------------------------------- 
  62 // ---------------------------------------------------------------------------- 
  64 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
) 
  66 // ============================================================================ 
  68 // ============================================================================ 
  70 // ---------------------------------------------------------------------------- 
  72 // ---------------------------------------------------------------------------- 
  74 #if wxUSE_MENUS_NATIVE 
  76 //----------------------------------------------------------------------------- 
  77 // "child_attached" of menu bar 
  78 //----------------------------------------------------------------------------- 
  81 static void gtk_menu_attached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrame 
*win 
) 
  83     if (!win
->m_hasVMT
) return; 
  85     win
->m_menuBarDetached 
= false; 
  90 //----------------------------------------------------------------------------- 
  91 // "child_detached" of menu bar 
  92 //----------------------------------------------------------------------------- 
  95 static void gtk_menu_detached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrame 
*win 
) 
  98         wxapp_install_idle_handler(); 
 100     if (!win
->m_hasVMT
) return; 
 102     // Raise the client area area 
 103     gdk_window_raise( win
->m_wxwindow
->window 
); 
 105     win
->m_menuBarDetached 
= true; 
 106     win
->GtkUpdateSize(); 
 110 #endif // wxUSE_MENUS_NATIVE 
 113 //----------------------------------------------------------------------------- 
 114 // "child_attached" of tool bar 
 115 //----------------------------------------------------------------------------- 
 118 static void gtk_toolbar_attached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrame 
*win 
) 
 120     if (!win
->m_hasVMT
) return; 
 122     win
->m_toolBarDetached 
= false; 
 123     win
->GtkUpdateSize(); 
 127 //----------------------------------------------------------------------------- 
 128 // "child_detached" of tool bar 
 129 //----------------------------------------------------------------------------- 
 132 static void gtk_toolbar_detached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrame 
*win 
) 
 135         wxapp_install_idle_handler(); 
 137     if (!win
->m_hasVMT
) return; 
 139     // Raise the client area area 
 140     gdk_window_raise( win
->m_wxwindow
->window 
); 
 142     win
->m_toolBarDetached 
= true; 
 143     win
->GtkUpdateSize(); 
 146 #endif // wxUSE_TOOLBAR 
 149 // ---------------------------------------------------------------------------- 
 151 // ---------------------------------------------------------------------------- 
 153 //----------------------------------------------------------------------------- 
 154 // InsertChild for wxFrame 
 155 //----------------------------------------------------------------------------- 
 157 /* Callback for wxFrame. This very strange beast has to be used because 
 158  * C++ has no virtual methods in a constructor. We have to emulate a 
 159  * virtual function here as wxWidgets requires different ways to insert 
 160  * a child in container classes. */ 
 162 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child 
) 
 164     wxASSERT( GTK_IS_WIDGET(child
->m_widget
) ); 
 166     if (!parent
->m_insertInClientArea
) 
 168         // These are outside the client area 
 169         wxFrame
* frame 
= (wxFrame
*) parent
; 
 170         gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
), 
 171                          GTK_WIDGET(child
->m_widget
), 
 177 #if wxUSE_TOOLBAR_NATIVE 
 178         // We connect to these events for recalculating the client area 
 179         // space when the toolbar is floating 
 180         if (wxIS_KIND_OF(child
,wxToolBar
)) 
 182             wxToolBar 
*toolBar 
= (wxToolBar
*) child
; 
 183             if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
) 
 185                 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached", 
 186                     GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent 
); 
 188                 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached", 
 189                     GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent 
); 
 192 #endif // wxUSE_TOOLBAR 
 196         // These are inside the client area 
 197         gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
 198                          GTK_WIDGET(child
->m_widget
), 
 205     // Resize on OnInternalIdle 
 206     parent
->GtkUpdateSize(); 
 209 // ---------------------------------------------------------------------------- 
 211 // ---------------------------------------------------------------------------- 
 215     m_menuBarDetached 
= false; 
 216     m_toolBarDetached 
= false; 
 220 bool wxFrame::Create( wxWindow 
*parent
, 
 222                       const wxString
& title
, 
 224                       const wxSize
& sizeOrig
, 
 226                       const wxString 
&name 
) 
 228     bool rt 
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
, 
 230     m_insertCallback 
= (wxInsertChildFunction
) wxInsertChildInFrame
; 
 237     m_isBeingDeleted 
= true; 
 241 // ---------------------------------------------------------------------------- 
 242 // overridden wxWindow methods 
 243 // ---------------------------------------------------------------------------- 
 245 void wxFrame::DoGetClientSize( int *width
, int *height 
) const 
 247     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 249     wxTopLevelWindow::DoGetClientSize( width
, height 
); 
 253 #if wxUSE_MENUS_NATIVE 
 257             if (!m_menuBarDetached
) 
 258                 (*height
) -= m_menuBarHeight
; 
 260                 (*height
) -= wxPLACE_HOLDER
; 
 262 #endif // wxUSE_MENUS_NATIVE 
 266         if (m_frameStatusBar 
&& m_frameStatusBar
->IsShown()) 
 267             (*height
) -= wxSTATUS_HEIGHT
; 
 268 #endif // wxUSE_STATUSBAR 
 272         if (m_frameToolBar 
&& m_frameToolBar
->IsShown()) 
 274             if (m_toolBarDetached
) 
 276                 *height 
-= wxPLACE_HOLDER
; 
 281                 m_frameToolBar
->GetSize( &x
, &y 
); 
 282                 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL 
) 
 292 #endif // wxUSE_TOOLBAR 
 296 void wxFrame::DoSetClientSize( int width
, int height 
) 
 298     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 300 #if wxUSE_MENUS_NATIVE 
 304             if (!m_menuBarDetached
) 
 305                 height 
+= m_menuBarHeight
; 
 307                 height 
+= wxPLACE_HOLDER
; 
 309 #endif // wxUSE_MENUS_NATIVE 
 313         if (m_frameStatusBar 
&& m_frameStatusBar
->IsShown()) height 
+= wxSTATUS_HEIGHT
; 
 318         if (m_frameToolBar 
&& m_frameToolBar
->IsShown()) 
 320             if (m_toolBarDetached
) 
 322                 height 
+= wxPLACE_HOLDER
; 
 327                 m_frameToolBar
->GetSize( &x
, &y 
); 
 328                 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL 
) 
 340     wxTopLevelWindow::DoSetClientSize( width
, height 
); 
 343 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), 
 344                          int width
, int height 
) 
 346     // due to a bug in gtk, x,y are always 0 
 351     if (m_resizing
) return; 
 354     // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow 
 355     wxASSERT_MSG( (m_wxwindow 
!= NULL
), wxT("invalid frame") ); 
 360     // space occupied by m_frameToolBar and m_frameMenuBar 
 361     int client_area_x_offset 
= 0, 
 362         client_area_y_offset 
= 0; 
 364     /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses 
 365        wxWindow::Create to create it's GTK equivalent. m_mainWidget is only 
 366        set in wxFrame::Create so it is used to check what kind of frame we 
 367        have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we 
 368        skip the part which handles m_frameMenuBar, m_frameToolBar and (most 
 369        importantly) m_mainWidget */ 
 371     int minWidth 
= GetMinWidth(), 
 372         minHeight 
= GetMinHeight(), 
 373         maxWidth 
= GetMaxWidth(), 
 374         maxHeight 
= GetMaxHeight(); 
 376     if ((minWidth 
!= -1) && (m_width 
< minWidth
)) m_width 
= minWidth
; 
 377     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
 378     if ((maxWidth 
!= -1) && (m_width 
> maxWidth
)) m_width 
= maxWidth
; 
 379     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
 384         gint flag 
= 0; // GDK_HINT_POS; 
 385         if ((minWidth 
!= -1) || (minHeight 
!= -1)) flag 
|= GDK_HINT_MIN_SIZE
; 
 386         if ((maxWidth 
!= -1) || (maxHeight 
!= -1)) flag 
|= GDK_HINT_MAX_SIZE
; 
 388         geom
.min_width 
= minWidth
; 
 389         geom
.min_height 
= minHeight
; 
 390         geom
.max_width 
= maxWidth
; 
 391         geom
.max_height 
= maxHeight
; 
 392         gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
), 
 395                                        (GdkWindowHints
) flag 
); 
 397         // I revert back to wxGTK's original behaviour. m_mainWidget holds 
 398         // the menubar, the toolbar and the client area, which is represented 
 400         // This hurts in the eye, but I don't want to call SetSize() 
 401         // because I don't want to call any non-native functions here. 
 403 #if wxUSE_MENUS_NATIVE 
 407             int yy 
= m_miniEdge 
+ m_miniTitle
; 
 408             int ww 
= m_width  
- 2*m_miniEdge
; 
 409             int hh 
= m_menuBarHeight
; 
 410             if (m_menuBarDetached
) hh 
= wxPLACE_HOLDER
; 
 411             m_frameMenuBar
->m_x 
= xx
; 
 412             m_frameMenuBar
->m_y 
= yy
; 
 413             m_frameMenuBar
->m_width 
= ww
; 
 414             m_frameMenuBar
->m_height 
= hh
; 
 415             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 416                                   m_frameMenuBar
->m_widget
, 
 418             client_area_y_offset 
+= hh
; 
 420 #endif // wxUSE_MENUS_NATIVE 
 423         if ((m_frameToolBar
) && m_frameToolBar
->IsShown() && 
 424             (m_frameToolBar
->m_widget
->parent 
== m_mainWidget
)) 
 427             int yy 
= m_miniEdge 
+ m_miniTitle
; 
 428 #if wxUSE_MENUS_NATIVE 
 431                 if (!m_menuBarDetached
) 
 432                     yy 
+= m_menuBarHeight
; 
 434                     yy 
+= wxPLACE_HOLDER
; 
 436 #endif // wxUSE_MENUS_NATIVE 
 438             m_frameToolBar
->m_x 
= xx
; 
 439             m_frameToolBar
->m_y 
= yy
; 
 441             // don't change the toolbar's reported height/width 
 443             if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL 
) 
 445                 ww 
= m_toolBarDetached 
? wxPLACE_HOLDER
 
 446                                        : m_frameToolBar
->m_width
; 
 447                 hh 
= m_height 
- 2*m_miniEdge
; 
 449                 client_area_x_offset 
+= ww
; 
 453                 ww 
= m_width 
- 2*m_miniEdge
; 
 454                 hh 
= m_toolBarDetached 
? wxPLACE_HOLDER
 
 455                                        : m_frameToolBar
->m_height
; 
 457                 client_area_y_offset 
+= hh
; 
 460             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 461                                   m_frameToolBar
->m_widget
, 
 464 #endif // wxUSE_TOOLBAR 
 466         int client_x 
= client_area_x_offset 
+ m_miniEdge
; 
 467         int client_y 
= client_area_y_offset 
+ m_miniEdge 
+ m_miniTitle
; 
 468         int client_w 
= m_width 
- client_area_x_offset 
- 2*m_miniEdge
; 
 469         int client_h 
= m_height 
- client_area_y_offset
- 2*m_miniEdge 
- m_miniTitle
; 
 470         gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 472                               client_x
, client_y
, client_w
, client_h 
); 
 476         // If there is no m_mainWidget between m_widget and m_wxwindow there 
 477         // is no need to set the size or position of m_wxwindow. 
 481     if (m_frameStatusBar 
&& m_frameStatusBar
->IsShown()) 
 483         int xx 
= 0 + m_miniEdge
; 
 484         int yy 
= m_height 
- wxSTATUS_HEIGHT 
- m_miniEdge 
- client_area_y_offset
; 
 485         int ww 
= m_width 
- 2*m_miniEdge
; 
 486         int hh 
= wxSTATUS_HEIGHT
; 
 487         m_frameStatusBar
->m_x 
= xx
; 
 488         m_frameStatusBar
->m_y 
= yy
; 
 489         m_frameStatusBar
->m_width 
= ww
; 
 490         m_frameStatusBar
->m_height 
= hh
; 
 491         gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
), 
 492                             m_frameStatusBar
->m_widget
, 
 494         gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL 
); 
 496 #endif // wxUSE_STATUSBAR 
 500     // send size event to frame 
 501     wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
 502     event
.SetEventObject( this ); 
 503     GetEventHandler()->ProcessEvent( event 
); 
 506     // send size event to status bar 
 507     if (m_frameStatusBar
) 
 509         wxSizeEvent 
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() ); 
 510         event2
.SetEventObject( m_frameStatusBar 
); 
 511         m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2 
); 
 513 #endif // wxUSE_STATUSBAR 
 518 void wxFrame::OnInternalIdle() 
 520     wxFrameBase::OnInternalIdle(); 
 522 #if wxUSE_MENUS_NATIVE 
 523     if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle(); 
 524 #endif // wxUSE_MENUS_NATIVE 
 526     if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle(); 
 529     if (m_frameStatusBar
) 
 531         m_frameStatusBar
->OnInternalIdle(); 
 533         // There may be controls in the status bar that 
 534         // need to be updated 
 535         for ( wxWindowList::compatibility_iterator node 
= m_frameStatusBar
->GetChildren().GetFirst(); 
 537           node 
= node
->GetNext() ) 
 539             wxWindow 
*child 
= node
->GetData(); 
 540             child
->OnInternalIdle(); 
 546 // ---------------------------------------------------------------------------- 
 547 // menu/tool/status bar stuff 
 548 // ---------------------------------------------------------------------------- 
 550 #if wxUSE_MENUS_NATIVE 
 552 void wxFrame::DetachMenuBar() 
 554     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 555     wxASSERT_MSG( (m_wxwindow 
!= NULL
), wxT("invalid frame") ); 
 557     if ( m_frameMenuBar 
) 
 559         m_frameMenuBar
->UnsetInvokingWindow( this ); 
 561         if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
) 
 563             gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
), 
 564                 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this ); 
 566             gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
), 
 567                 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this ); 
 570         gtk_widget_ref( m_frameMenuBar
->m_widget 
); 
 572         gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget 
); 
 575     wxFrameBase::DetachMenuBar(); 
 578 void wxFrame::AttachMenuBar( wxMenuBar 
*menuBar 
) 
 580     wxFrameBase::AttachMenuBar(menuBar
); 
 584         m_frameMenuBar
->SetInvokingWindow( this ); 
 586         m_frameMenuBar
->SetParent(this); 
 587         gtk_pizza_put( GTK_PIZZA(m_mainWidget
), 
 588                 m_frameMenuBar
->m_widget
, 
 591                 m_frameMenuBar
->m_width
, 
 592                 m_frameMenuBar
->m_height 
); 
 594         if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
) 
 596             gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached", 
 597                 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this ); 
 599             gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached", 
 600                 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this ); 
 603         gtk_widget_show( m_frameMenuBar
->m_widget 
); 
 610         GtkUpdateSize();        // resize window in OnInternalIdle 
 614 void wxFrame::UpdateMenuBarSize() 
 621     // this is called after Remove with a NULL m_frameMenuBar 
 622     if ( m_frameMenuBar 
) 
 623         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request 
) 
 624             (m_frameMenuBar
->m_widget
, &req 
); 
 626     m_menuBarHeight 
= req
.height
; 
 628     // resize window in OnInternalIdle 
 633 #endif // wxUSE_MENUS_NATIVE 
 637 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name 
) 
 639     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 641     m_insertInClientArea 
= false; 
 643     m_frameToolBar 
= wxFrameBase::CreateToolBar( style
, id
, name 
); 
 645     m_insertInClientArea 
= true; 
 649     return m_frameToolBar
; 
 652 void wxFrame::SetToolBar(wxToolBar 
*toolbar
) 
 654     bool hadTbar 
= m_frameToolBar 
!= NULL
; 
 656     wxFrameBase::SetToolBar(toolbar
); 
 658     if ( m_frameToolBar 
) 
 660         // insert into toolbar area if not already there 
 661         if ((m_frameToolBar
->m_widget
->parent
) && 
 662             (m_frameToolBar
->m_widget
->parent 
!= m_mainWidget
)) 
 664             GetChildren().DeleteObject( m_frameToolBar 
); 
 666             gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget 
); 
 670     else // toolbar unset 
 672         // still need to update size if it had been there before 
 680 #endif // wxUSE_TOOLBAR 
 684 wxStatusBar
* wxFrame::CreateStatusBar(int number
, 
 687                                       const wxString
& name
) 
 689     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 691     // because it will change when toolbar is added 
 694     return wxFrameBase::CreateStatusBar( number
, style
, id
, name 
); 
 697 void wxFrame::SetStatusBar(wxStatusBar 
*statbar
) 
 699     bool hadStatBar 
= m_frameStatusBar 
!= NULL
; 
 701     wxFrameBase::SetStatusBar(statbar
); 
 703     if (hadStatBar 
&& !m_frameStatusBar
) 
 707 void wxFrame::PositionStatusBar() 
 709     if ( !m_frameStatusBar 
) 
 714 #endif // wxUSE_STATUSBAR