1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/mdi.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" 
  14 #include "wx/notebook.h" 
  18 #include "wx/dialog.h" 
  21 #include "wx/gtk/private.h" 
  26 #include "wx/gtk/win_gtk.h" 
  28 //----------------------------------------------------------------------------- 
  30 //----------------------------------------------------------------------------- 
  32 const int wxMENU_HEIGHT 
= 27; 
  34 //----------------------------------------------------------------------------- 
  36 //----------------------------------------------------------------------------- 
  38 extern void wxapp_install_idle_handler(); 
  41 //----------------------------------------------------------------------------- 
  43 //----------------------------------------------------------------------------- 
  45 extern wxList wxPendingDelete
; 
  47 //----------------------------------------------------------------------------- 
  49 //----------------------------------------------------------------------------- 
  53 gtk_mdi_page_change_callback( GtkNotebook 
*WXUNUSED(widget
), 
  54                               GtkNotebookPage 
*page
, 
  55                               gint 
WXUNUSED(page_num
), 
  56                               wxMDIParentFrame 
*parent 
) 
  59         wxapp_install_idle_handler(); 
  61     // send deactivate event to old child 
  63     wxMDIChildFrame 
*child 
= parent
->GetActiveChild(); 
  66         wxActivateEvent 
event1( wxEVT_ACTIVATE
, false, child
->GetId() ); 
  67         event1
.SetEventObject( child
); 
  68         child
->GetEventHandler()->ProcessEvent( event1 
); 
  71     // send activate event to new child 
  73     wxMDIClientWindow 
*client_window 
= parent
->GetClientWindow(); 
  77     child 
= (wxMDIChildFrame
*) NULL
; 
  79     wxWindowList::compatibility_iterator node 
= client_window
->GetChildren().GetFirst(); 
  82         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
  83         // CE: we come here in the destructor with a null child_frame - I think because 
  84         // g_signal_connect (m_widget, "switch_page", (see below) 
  85         // isn't deleted early enough 
  89         if (child_frame
->m_page 
== page
) 
  94         node 
= node
->GetNext(); 
 100     wxActivateEvent 
event2( wxEVT_ACTIVATE
, true, child
->GetId() ); 
 101     event2
.SetEventObject( child
); 
 102     child
->GetEventHandler()->ProcessEvent( event2 
); 
 106 //----------------------------------------------------------------------------- 
 108 //----------------------------------------------------------------------------- 
 110 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
) 
 112 void wxMDIParentFrame::Init() 
 114     m_justInserted 
= false; 
 115     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 118 wxMDIParentFrame::~wxMDIParentFrame() 
 122 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 124                               const wxString
& title
, 
 128                               const wxString
& name 
) 
 130     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 137 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height 
) 
 139     wxFrame::GtkOnSize( x
, y
, width
, height 
); 
 141     wxMDIChildFrame 
*child_frame 
= GetActiveChild(); 
 142     if (!child_frame
) return; 
 144     wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 145     if (!menu_bar
) return; 
 146     if (!menu_bar
->m_widget
) return; 
 150     menu_bar
->m_width 
= m_width
; 
 151     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 152     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 154                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 157 void wxMDIParentFrame::OnInternalIdle() 
 159     /* if a an MDI child window has just been inserted 
 160        it has to be brought to the top in idle time. we 
 161        simply set the last notebook page active as new 
 162        pages can only be appended at the end */ 
 166         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 167         gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 169         /* need to set the menubar of the child */ 
 170         wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 171         if (active_child_frame 
!= NULL
) 
 173             wxMenuBar 
*menu_bar 
= active_child_frame
->m_menuBar
; 
 176                 menu_bar
->m_width 
= m_width
; 
 177                 menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 178                 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 180                                     0, 0, m_width
, wxMENU_HEIGHT 
); 
 181                 menu_bar
->SetInvokingWindow(active_child_frame
); 
 184         m_justInserted 
= false; 
 188     wxFrame::OnInternalIdle(); 
 190     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 191     bool visible_child_menu 
= false; 
 193     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 196         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 200             wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 203                 if (child_frame 
== active_child_frame
) 
 205                     if (menu_bar
->Show(true)) 
 207                         menu_bar
->m_width 
= m_width
; 
 208                         menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 209                         gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 211                                             0, 0, m_width
, wxMENU_HEIGHT 
); 
 212                         menu_bar
->SetInvokingWindow( child_frame 
); 
 214                     visible_child_menu 
= true; 
 218                     if (menu_bar
->Show(false)) 
 220                         menu_bar
->UnsetInvokingWindow( child_frame 
); 
 226         node 
= node
->GetNext(); 
 229     /* show/hide parent menu bar as required */ 
 230     if ((m_frameMenuBar
) && 
 231         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 233         if (visible_child_menu
) 
 235             m_frameMenuBar
->Show( false ); 
 236             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 240             m_frameMenuBar
->Show( true ); 
 241             m_frameMenuBar
->SetInvokingWindow( this ); 
 243             m_frameMenuBar
->m_width 
= m_width
; 
 244             m_frameMenuBar
->m_height 
= wxMENU_HEIGHT
; 
 245             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 246                                 m_frameMenuBar
->m_widget
, 
 247                                 0, 0, m_width
, wxMENU_HEIGHT 
); 
 252 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height 
) const 
 254     wxFrame::DoGetClientSize( width
, height 
); 
 257 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 259     if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
; 
 261     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 262     if (!notebook
) return (wxMDIChildFrame
*) NULL
; 
 264     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 265     if (i 
< 0) return (wxMDIChildFrame
*) NULL
; 
 267     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 268     if (!page
) return (wxMDIChildFrame
*) NULL
; 
 270     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 273         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 275         wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") ); 
 277         if (child_frame
->m_page 
== page
) 
 279         node 
= node
->GetNext(); 
 282     return (wxMDIChildFrame
*) NULL
; 
 285 wxMDIClientWindow 
*wxMDIParentFrame::GetClientWindow() const 
 287     return m_clientWindow
; 
 290 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 292     m_clientWindow 
= new wxMDIClientWindow( this ); 
 293     return m_clientWindow
; 
 296 void wxMDIParentFrame::ActivateNext() 
 299       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 302 void wxMDIParentFrame::ActivatePrevious() 
 305       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 308 //----------------------------------------------------------------------------- 
 310 //----------------------------------------------------------------------------- 
 312 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 314 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 315     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 316     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 319 wxMDIChildFrame::wxMDIChildFrame() 
 321     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 322     m_page 
= (GtkNotebookPage 
*) NULL
; 
 325 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame 
*parent
, 
 326       wxWindowID id
, const wxString
& title
, 
 327       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 328       long style
, const wxString
& name 
) 
 330     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 331     m_page 
= (GtkNotebookPage 
*) NULL
; 
 332     Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name 
); 
 335 wxMDIChildFrame::~wxMDIChildFrame() 
 341 bool wxMDIChildFrame::Create( wxMDIParentFrame 
*parent
, 
 342       wxWindowID id
, const wxString
& title
, 
 343       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 344       long style
, const wxString
& name 
) 
 348     return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name 
); 
 351 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 353     wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags 
); 
 356 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 358     wxWindow::DoSetClientSize( width
, height 
); 
 361 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height 
) const 
 363     wxWindow::DoGetClientSize( width
, height 
); 
 366 void wxMDIChildFrame::AddChild( wxWindowBase 
*child 
) 
 368     wxWindow::AddChild(child
); 
 371 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 373     wxASSERT_MSG( m_menuBar 
== NULL
, wxT("Only one menubar allowed") ); 
 375     m_menuBar 
= menu_bar
; 
 379         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 381         m_menuBar
->SetParent( mdi_frame 
); 
 383         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 384         gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
), 
 386                          0, 0,  mdi_frame
->m_width
, wxMENU_HEIGHT 
); 
 390 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 395 void wxMDIChildFrame::Activate() 
 397     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 398     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 399     gint pageno 
= gtk_notebook_page_num( notebook
, m_widget 
); 
 400     gtk_notebook_set_current_page( notebook
, pageno 
); 
 403 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 407 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 410     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 411     if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) ) 
 413         // we don't have any help text for this item, but may be the MDI frame 
 415         mdi_frame
->OnMenuHighlight(event
); 
 417 #endif // wxUSE_STATUSBAR 
 420 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 422     if ( title 
== m_title 
) 
 427     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 428     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 429     gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title 
) ); 
 432 //----------------------------------------------------------------------------- 
 434 //----------------------------------------------------------------------------- 
 437 static void gtk_page_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow 
*win 
) 
 439     if (g_isIdle
) wxapp_install_idle_handler(); 
 441     if ((win
->m_x 
== alloc
->x
) && 
 442         (win
->m_y 
== alloc
->y
) && 
 443         (win
->m_width 
== alloc
->width
) && 
 444         (win
->m_height 
== alloc
->height
) && 
 450     win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height 
); 
 454 //----------------------------------------------------------------------------- 
 455 // InsertChild callback for wxMDIClientWindow 
 456 //----------------------------------------------------------------------------- 
 458 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child 
) 
 460     wxString s 
= child
->GetTitle(); 
 461     if (s
.IsNull()) s 
= _("MDI child"); 
 463     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 464     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 466     g_signal_connect (child
->m_widget
, "size_allocate", 
 467                       G_CALLBACK (gtk_page_size_callback
), child
); 
 469     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 471     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 473     child
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 475     wxMDIParentFrame 
*parent_frame 
= (wxMDIParentFrame
*) parent
->GetParent(); 
 476     parent_frame
->m_justInserted 
= true; 
 479 //----------------------------------------------------------------------------- 
 481 //----------------------------------------------------------------------------- 
 483 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
) 
 485 wxMDIClientWindow::wxMDIClientWindow() 
 489 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame 
*parent
, long style 
) 
 491     CreateClient( parent
, style 
); 
 494 wxMDIClientWindow::~wxMDIClientWindow() 
 499 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame 
*parent
, long style 
) 
 503     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInMDI
; 
 505     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 506         !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") )) 
 508         wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") ); 
 512     m_widget 
= gtk_notebook_new(); 
 514     g_signal_connect (m_widget
, "switch_page", 
 515                       G_CALLBACK (gtk_mdi_page_change_callback
), parent
); 
 517     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 519     m_parent
->DoAddChild( this );