1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // ============================================================================ 
  12 // ============================================================================ 
  14 // ---------------------------------------------------------------------------- 
  16 // ---------------------------------------------------------------------------- 
  19     #pragma implementation "frame.h" 
  24 #include "wx/dialog.h" 
  25 #include "wx/control.h" 
  29     #include "wx/toolbar.h" 
  32     #include "wx/statusbr.h" 
  34 #include "wx/dcclient.h" 
  39 #include <gdk/gdkkeysyms.h> 
  42 #include "wx/gtk/win_gtk.h" 
  44 // ---------------------------------------------------------------------------- 
  46 // ---------------------------------------------------------------------------- 
  48 const int wxMENU_HEIGHT    
= 27; 
  49 const int wxSTATUS_HEIGHT  
= 25; 
  50 const int wxPLACE_HOLDER   
= 0; 
  52 // ---------------------------------------------------------------------------- 
  54 // ---------------------------------------------------------------------------- 
  56 extern void wxapp_install_idle_handler(); 
  58 extern int g_openDialogs
; 
  60 // ---------------------------------------------------------------------------- 
  62 // ---------------------------------------------------------------------------- 
  64 #ifndef __WXUNIVERSAL__ 
  65     IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
) 
  68 // ============================================================================ 
  70 // ============================================================================ 
  72 // ---------------------------------------------------------------------------- 
  74 // ---------------------------------------------------------------------------- 
  76 #if wxUSE_MENUS_NATIVE 
  78 //----------------------------------------------------------------------------- 
  79 // "child_attached" of menu bar 
  80 //----------------------------------------------------------------------------- 
  82 static void gtk_menu_attached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrameGTK 
*win 
) 
  84     if (!win
->m_hasVMT
) return; 
  86     win
->m_menuBarDetached 
= FALSE
; 
  90 //----------------------------------------------------------------------------- 
  91 // "child_detached" of menu bar 
  92 //----------------------------------------------------------------------------- 
  94 static void gtk_menu_detached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrameGTK 
*win 
) 
  96     if (!win
->m_hasVMT
) return; 
  98     win
->m_menuBarDetached 
= TRUE
; 
 102 #endif // wxUSE_MENUS_NATIVE 
 105 //----------------------------------------------------------------------------- 
 106 // "child_attached" of tool bar 
 107 //----------------------------------------------------------------------------- 
 109 static void gtk_toolbar_attached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrameGTK 
*win 
) 
 111     if (!win
->m_hasVMT
) return; 
 113     win
->m_toolBarDetached 
= FALSE
; 
 115     win
->GtkUpdateSize(); 
 118 //----------------------------------------------------------------------------- 
 119 // "child_detached" of tool bar 
 120 //----------------------------------------------------------------------------- 
 122 static void gtk_toolbar_detached_callback( GtkWidget 
*WXUNUSED(widget
), GtkWidget 
*WXUNUSED(child
), wxFrameGTK 
*win 
) 
 125         wxapp_install_idle_handler(); 
 127     if (!win
->m_hasVMT
) return; 
 129     win
->m_toolBarDetached 
= TRUE
; 
 130     win
->GtkUpdateSize(); 
 132 #endif // wxUSE_TOOLBAR 
 135 // ---------------------------------------------------------------------------- 
 137 // ---------------------------------------------------------------------------- 
 139 //----------------------------------------------------------------------------- 
 140 // InsertChild for wxFrameGTK 
 141 //----------------------------------------------------------------------------- 
 143 /* Callback for wxFrameGTK. This very strange beast has to be used because 
 144  * C++ has no virtual methods in a constructor. We have to emulate a 
 145  * virtual function here as wxWindows requires different ways to insert 
 146  * a child in container classes. */ 
 148 static void wxInsertChildInFrame( wxFrameGTK
* parent
, wxWindow
* child 
) 
 150     wxASSERT( GTK_IS_WIDGET(child
->m_widget
) ); 
 152     if (!parent
->m_insertInClientArea
) 
 154         /* these are outside the client area */ 
 155         wxFrameGTK
* frame 
= (wxFrameGTK
*) parent
; 
 156         gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
), 
 157                          GTK_WIDGET(child
->m_widget
), 
 163 #if wxUSE_TOOLBAR_NATIVE 
 164         /* we connect to these events for recalculating the client area 
 165            space when the toolbar is floating */ 
 166         if (wxIS_KIND_OF(child
,wxToolBar
)) 
 168             wxToolBar 
*toolBar 
= (wxToolBar
*) child
; 
 169             if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
) 
 171                 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached", 
 172                     GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent 
); 
 174                 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached", 
 175                     GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent 
); 
 178 #endif // wxUSE_TOOLBAR 
 182         /* these are inside the client area */ 
 183         gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
 184                          GTK_WIDGET(child
->m_widget
), 
 191     /* resize on OnInternalIdle */ 
 192     parent
->GtkUpdateSize(); 
 195 // ---------------------------------------------------------------------------- 
 196 // wxFrameGTK creation 
 197 // ---------------------------------------------------------------------------- 
 199 void wxFrameGTK::Init() 
 201     m_menuBarDetached 
= FALSE
; 
 202     m_toolBarDetached 
= FALSE
; 
 205 bool wxFrameGTK::Create( wxWindow 
*parent
, 
 207                       const wxString
& title
, 
 209                       const wxSize
& sizeOrig
, 
 211                       const wxString 
&name 
) 
 213     bool rt 
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,  
 215     m_insertCallback 
= (wxInsertChildFunction
) wxInsertChildInFrame
; 
 219 wxFrameGTK::~wxFrameGTK() 
 221     m_isBeingDeleted 
= TRUE
; 
 225 // ---------------------------------------------------------------------------- 
 226 // overridden wxWindow methods 
 227 // ---------------------------------------------------------------------------- 
 229 void wxFrameGTK::DoGetClientSize( int *width
, int *height 
) const 
 231     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 233     wxTopLevelWindow::DoGetClientSize( width
, height 
); 
 237 #if wxUSE_MENUS_NATIVE 
 241             if (!m_menuBarDetached
) 
 242                 (*height
) -= wxMENU_HEIGHT
; 
 244                 (*height
) -= wxPLACE_HOLDER
; 
 246 #endif // wxUSE_MENUS_NATIVE 
 250         if (m_frameStatusBar 
&& m_frameStatusBar
->IsShown())  
 251             (*height
) -= wxSTATUS_HEIGHT
; 
 252 #endif // wxUSE_STATUSBAR 
 256         if (m_frameToolBar 
&& m_frameToolBar
->IsShown()) 
 258             if (m_toolBarDetached
) 
 260                 *height 
-= wxPLACE_HOLDER
; 
 265                 m_frameToolBar
->GetSize( &x
, &y 
); 
 266                 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL 
) 
 276 #endif // wxUSE_TOOLBAR 
 280 void wxFrameGTK::DoSetClientSize( int width
, int height 
) 
 282     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 284 #if wxUSE_MENUS_NATIVE 
 288             if (!m_menuBarDetached
) 
 289                 height 
+= wxMENU_HEIGHT
; 
 291                 height 
+= wxPLACE_HOLDER
; 
 293 #endif // wxUSE_MENUS_NATIVE 
 297         if (m_frameStatusBar 
&& m_frameStatusBar
->IsShown()) height 
+= wxSTATUS_HEIGHT
; 
 302         if (m_frameToolBar 
&& m_frameToolBar
->IsShown()) 
 304             if (m_toolBarDetached
) 
 306                 height 
+= wxPLACE_HOLDER
; 
 311                 m_frameToolBar
->GetSize( &x
, &y 
); 
 312                 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL 
) 
 324     wxTopLevelWindow::DoSetClientSize( width
, height 
); 
 327 void wxFrameGTK::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), 
 328                          int width
, int height 
) 
 330     // due to a bug in gtk, x,y are always 0 
 334     /* avoid recursions */ 
 335     if (m_resizing
) return; 
 338     /* this shouldn't happen: wxFrameGTK, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */ 
 339     wxASSERT_MSG( (m_wxwindow 
!= NULL
), wxT("invalid frame") ); 
 344     /* space occupied by m_frameToolBar and m_frameMenuBar */ 
 345     int client_area_x_offset 
= 0, 
 346         client_area_y_offset 
= 0; 
 348     /* wxMDIChildFrame derives from wxFrameGTK but it _is_ a wxWindow as it uses 
 349        wxWindow::Create to create it's GTK equivalent. m_mainWidget is only 
 350        set in wxFrameGTK::Create so it is used to check what kind of frame we 
 351        have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we 
 352        skip the part which handles m_frameMenuBar, m_frameToolBar and (most 
 353        importantly) m_mainWidget */ 
 355     if ((m_minWidth 
!= -1) && (m_width 
< m_minWidth
)) m_width 
= m_minWidth
; 
 356     if ((m_minHeight 
!= -1) && (m_height 
< m_minHeight
)) m_height 
= m_minHeight
; 
 357     if ((m_maxWidth 
!= -1) && (m_width 
> m_maxWidth
)) m_width 
= m_maxWidth
; 
 358     if ((m_maxHeight 
!= -1) && (m_height 
> m_maxHeight
)) m_height 
= m_maxHeight
; 
 363         gint flag 
= 0; // GDK_HINT_POS; 
 364         if ((m_minWidth 
!= -1) || (m_minHeight 
!= -1)) flag 
|= GDK_HINT_MIN_SIZE
; 
 365         if ((m_maxWidth 
!= -1) || (m_maxHeight 
!= -1)) flag 
|= GDK_HINT_MAX_SIZE
; 
 367         geom
.min_width 
= m_minWidth
; 
 368         geom
.min_height 
= m_minHeight
; 
 369         geom
.max_width 
= m_maxWidth
; 
 370         geom
.max_height 
= m_maxHeight
; 
 371         gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
), 
 374                                        (GdkWindowHints
) flag 
); 
 376         /* I revert back to wxGTK's original behaviour. m_mainWidget holds the 
 377          * menubar, the toolbar and the client area, which is represented by 
 379          * this hurts in the eye, but I don't want to call SetSize() 
 380          * because I don't want to call any non-native functions here. */ 
 382 #if wxUSE_MENUS_NATIVE 
 386             int yy 
= m_miniEdge 
+ m_miniTitle
; 
 387             int ww 
= m_width  
- 2*m_miniEdge
; 
 388             int hh 
= wxMENU_HEIGHT
; 
 389             if (m_menuBarDetached
) hh 
= wxPLACE_HOLDER
; 
 390             m_frameMenuBar
->m_x 
= xx
; 
 391             m_frameMenuBar
->m_y 
= yy
; 
 392             m_frameMenuBar
->m_width 
= ww
; 
 393             m_frameMenuBar
->m_height 
= hh
; 
 394             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 395                                   m_frameMenuBar
->m_widget
, 
 397             client_area_y_offset 
+= hh
; 
 399 #endif // wxUSE_MENUS_NATIVE 
 402         if ((m_frameToolBar
) && m_frameToolBar
->IsShown() && 
 403             (m_frameToolBar
->m_widget
->parent 
== m_mainWidget
)) 
 406             int yy 
= m_miniEdge 
+ m_miniTitle
; 
 407 #if wxUSE_MENUS_NATIVE 
 410                 if (!m_menuBarDetached
) 
 413                     yy 
+= wxPLACE_HOLDER
; 
 415 #endif // wxUSE_MENUS_NATIVE 
 417             m_frameToolBar
->m_x 
= xx
; 
 418             m_frameToolBar
->m_y 
= yy
; 
 420             /* don't change the toolbar's reported height/width */ 
 422             if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL 
) 
 424                 ww 
= m_toolBarDetached 
? wxPLACE_HOLDER
 
 425                                        : m_frameToolBar
->m_width
; 
 426                 hh 
= m_height 
- 2*m_miniEdge
; 
 428                 client_area_x_offset 
+= ww
; 
 432                 ww 
= m_width 
- 2*m_miniEdge
; 
 433                 hh 
= m_toolBarDetached 
? wxPLACE_HOLDER
 
 434                                        : m_frameToolBar
->m_height
; 
 436                 client_area_y_offset 
+= hh
; 
 439             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 440                                   m_frameToolBar
->m_widget
, 
 443 #endif // wxUSE_TOOLBAR 
 445         int client_x 
= client_area_x_offset 
+ m_miniEdge
; 
 446         int client_y 
= client_area_y_offset 
+ m_miniEdge 
+ m_miniTitle
; 
 447         int client_w 
= m_width 
- client_area_x_offset 
- 2*m_miniEdge
; 
 448         int client_h 
= m_height 
- client_area_y_offset
- 2*m_miniEdge 
- m_miniTitle
; 
 449         gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 451                               client_x
, client_y
, client_w
, client_h 
); 
 455         /* if there is no m_mainWidget between m_widget and m_wxwindow there 
 456            is no need to set the size or position of m_wxwindow. */ 
 460     if (m_frameStatusBar 
&& m_frameStatusBar
->IsShown()) 
 462         int xx 
= 0 + m_miniEdge
; 
 463         int yy 
= m_height 
- wxSTATUS_HEIGHT 
- m_miniEdge 
- client_area_y_offset
; 
 464         int ww 
= m_width 
- 2*m_miniEdge
; 
 465         int hh 
= wxSTATUS_HEIGHT
; 
 466         m_frameStatusBar
->m_x 
= xx
; 
 467         m_frameStatusBar
->m_y 
= yy
; 
 468         m_frameStatusBar
->m_width 
= ww
; 
 469         m_frameStatusBar
->m_height 
= hh
; 
 470         gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
), 
 471                             m_frameStatusBar
->m_widget
, 
 473         gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL 
); 
 475 #endif // wxUSE_STATUSBAR 
 479     // send size event to frame 
 480     wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
 481     event
.SetEventObject( this ); 
 482     GetEventHandler()->ProcessEvent( event 
); 
 485     // send size event to status bar 
 486     if (m_frameStatusBar
) 
 488         wxSizeEvent 
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() ); 
 489         event2
.SetEventObject( m_frameStatusBar 
); 
 490         m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2 
); 
 492 #endif // wxUSE_STATUSBAR 
 497 void wxFrameGTK::OnInternalIdle() 
 499     wxTopLevelWindow::OnInternalIdle(); 
 501 #if wxUSE_MENUS_NATIVE 
 502     if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle(); 
 503 #endif // wxUSE_MENUS_NATIVE 
 505     if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle(); 
 508     if (m_frameStatusBar
) m_frameStatusBar
->OnInternalIdle(); 
 512 // ---------------------------------------------------------------------------- 
 513 // menu/tool/status bar stuff 
 514 // ---------------------------------------------------------------------------- 
 516 #if wxUSE_MENUS_NATIVE 
 518 void wxFrameGTK::DetachMenuBar() 
 520     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 521     wxASSERT_MSG( (m_wxwindow 
!= NULL
), wxT("invalid frame") ); 
 523     if ( m_frameMenuBar 
) 
 525         m_frameMenuBar
->UnsetInvokingWindow( this ); 
 527         if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
) 
 529             gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
), 
 530                 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this ); 
 532             gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
), 
 533                 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this ); 
 536         gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget 
); 
 537         gtk_widget_ref( m_frameMenuBar
->m_widget 
); 
 538         gtk_widget_unparent( m_frameMenuBar
->m_widget 
); 
 541     wxFrameBase::DetachMenuBar(); 
 544 void wxFrameGTK::AttachMenuBar( wxMenuBar 
*menuBar 
) 
 546     wxFrameBase::AttachMenuBar(menuBar
); 
 550         m_frameMenuBar
->SetInvokingWindow( this ); 
 552         m_frameMenuBar
->SetParent(this); 
 553         gtk_pizza_put( GTK_PIZZA(m_mainWidget
), 
 554                 m_frameMenuBar
->m_widget
, 
 557                 m_frameMenuBar
->m_width
, 
 558                 m_frameMenuBar
->m_height 
); 
 560         if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
) 
 562             gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached", 
 563                 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this ); 
 565             gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached", 
 566                 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this ); 
 569         m_frameMenuBar
->Show( TRUE 
); 
 572     /* resize window in OnInternalIdle */ 
 576 #endif // wxUSE_MENUS_NATIVE 
 580 wxToolBar
* wxFrameGTK::CreateToolBar( long style
, wxWindowID id
, const wxString
& name 
) 
 582     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 584     m_insertInClientArea 
= FALSE
; 
 586     m_frameToolBar 
= wxFrameBase::CreateToolBar( style
, id
, name 
); 
 588     m_insertInClientArea 
= TRUE
; 
 592     return m_frameToolBar
; 
 595 void wxFrameGTK::SetToolBar(wxToolBar 
*toolbar
) 
 597     wxFrameBase::SetToolBar(toolbar
); 
 601         /* insert into toolbar area if not already there */ 
 602         if ((m_frameToolBar
->m_widget
->parent
) && 
 603             (m_frameToolBar
->m_widget
->parent 
!= m_mainWidget
)) 
 605             GetChildren().DeleteObject( m_frameToolBar 
); 
 607             gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget 
); 
 613 #endif // wxUSE_TOOLBAR 
 617 wxStatusBar
* wxFrameGTK::CreateStatusBar(int number
, 
 620                                       const wxString
& name
) 
 622     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid frame") ); 
 624     // because it will change when toolbar is added 
 627     return wxFrameBase::CreateStatusBar( number
, style
, id
, name 
); 
 630 void wxFrameGTK::PositionStatusBar() 
 632     if ( !m_frameStatusBar 
) 
 637 #endif // wxUSE_STATUSBAR