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" 
  22 #include "wx/gtk/private.h" 
  24 //----------------------------------------------------------------------------- 
  26 //----------------------------------------------------------------------------- 
  30 gtk_mdi_page_change_callback( GtkNotebook 
*WXUNUSED(widget
), 
  31                               GtkNotebookPage 
*page
, 
  32                               gint 
WXUNUSED(page_num
), 
  33                               wxMDIParentFrame 
*parent 
) 
  35     // send deactivate event to old child 
  37     wxMDIChildFrame 
*child 
= parent
->GetActiveChild(); 
  40         wxActivateEvent 
event1( wxEVT_ACTIVATE
, false, child
->GetId() ); 
  41         event1
.SetEventObject( child
); 
  42         child
->HandleWindowEvent( event1 
); 
  45     // send activate event to new child 
  47     wxMDIClientWindowBase 
*client_window 
= parent
->GetClientWindow(); 
  53     wxWindowList::compatibility_iterator node 
= client_window
->GetChildren().GetFirst(); 
  56         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
  58         // child_frame can be NULL when this is called from dtor, probably 
  59         // because g_signal_connect (m_widget, "switch_page", (see below) 
  60         // isn't deleted early enough 
  61         if ( child_frame 
&& child_frame
->m_page 
== page 
) 
  66         node 
= node
->GetNext(); 
  72     wxActivateEvent 
event2( wxEVT_ACTIVATE
, true, child
->GetId() ); 
  73     event2
.SetEventObject( child
); 
  74     child
->HandleWindowEvent( event2 
); 
  78 //----------------------------------------------------------------------------- 
  80 //----------------------------------------------------------------------------- 
  82 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
) 
  84 void wxMDIParentFrame::Init() 
  86     m_justInserted 
= false; 
  89 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
  91                               const wxString
& title
, 
  95                               const wxString
& name 
) 
  97     if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
) ) 
 100     m_clientWindow 
= OnCreateClient(); 
 101     if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) ) 
 107 void wxMDIParentFrame::OnInternalIdle() 
 109     /* if a MDI child window has just been inserted 
 110        it has to be brought to the top in idle time. we 
 111        simply set the last notebook page active as new 
 112        pages can only be appended at the end */ 
 116         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 117         gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 119         /* need to set the menubar of the child */ 
 120         wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 121         if (active_child_frame 
!= NULL
) 
 123             wxMenuBar 
*menu_bar 
= active_child_frame
->m_menuBar
; 
 126                 menu_bar
->SetInvokingWindow(active_child_frame
); 
 129         m_justInserted 
= false; 
 133     wxFrame::OnInternalIdle(); 
 135     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 136     bool visible_child_menu 
= false; 
 138     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 141         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 145             wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 148                 if (child_frame 
== active_child_frame
) 
 150                     if (menu_bar
->Show(true)) 
 152                         menu_bar
->SetInvokingWindow( child_frame 
); 
 154                     visible_child_menu 
= true; 
 158                     if (menu_bar
->Show(false)) 
 160                         menu_bar
->UnsetInvokingWindow( child_frame 
); 
 166         node 
= node
->GetNext(); 
 169     /* show/hide parent menu bar as required */ 
 170     if ((m_frameMenuBar
) && 
 171         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 173         if (visible_child_menu
) 
 175             m_frameMenuBar
->Show( false ); 
 176             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 180             m_frameMenuBar
->Show( true ); 
 181             m_frameMenuBar
->SetInvokingWindow( this ); 
 186 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const 
 188     wxFrame::DoGetClientSize(width
, height
); 
 192         wxMDIChildFrame
* active_child_frame 
= GetActiveChild(); 
 193         if (active_child_frame
) 
 195             wxMenuBar
* menubar 
= active_child_frame
->m_menuBar
; 
 196             if (menubar 
&& menubar
->IsShown()) 
 199                 gtk_widget_size_request(menubar
->m_widget
, &req
); 
 200                 *height 
-= req
.height
; 
 201                 if (*height 
< 0) *height 
= 0; 
 207 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 209     if (!m_clientWindow
) return NULL
; 
 211     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 212     if (!notebook
) return NULL
; 
 214     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 215     if (i 
< 0) return NULL
; 
 217     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 218     if (!page
) return NULL
; 
 220     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 223         if ( wxPendingDelete
.Member(node
->GetData()) ) 
 226         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 231         if (child_frame
->m_page 
== page
) 
 234         node 
= node
->GetNext(); 
 240 void wxMDIParentFrame::ActivateNext() 
 243       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 246 void wxMDIParentFrame::ActivatePrevious() 
 249       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 252 //----------------------------------------------------------------------------- 
 254 //----------------------------------------------------------------------------- 
 256 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 258 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 259     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 260     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 263 void wxMDIChildFrame::Init() 
 269 bool wxMDIChildFrame::Create(wxMDIParentFrame 
*parent
, 
 271                              const wxString
& title
, 
 272                              const wxPoint
& WXUNUSED(pos
), 
 275                              const wxString
& name
) 
 277     m_mdiParent 
= parent
; 
 280     return wxWindow::Create(parent
->GetClientWindow(), id
, 
 281                             wxDefaultPosition
, size
, 
 285 wxMDIChildFrame::~wxMDIChildFrame() 
 289     // wxMDIClientWindow does not get redrawn properly after last child is removed 
 290     if (m_parent 
&& m_parent
->GetChildren().size() <= 1) 
 291         gtk_widget_queue_draw(m_parent
->m_widget
); 
 294 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 296     wxASSERT_MSG( m_menuBar 
== NULL
, "Only one menubar allowed" ); 
 298     m_menuBar 
= menu_bar
; 
 302         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 304         m_menuBar
->SetParent( mdi_frame 
); 
 306         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 307         m_menuBar
->Show(false); 
 308         gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0); 
 309         gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0); 
 311         gulong handler_id 
= g_signal_handler_find( 
 313             GSignalMatchType(G_SIGNAL_MATCH_ID 
| G_SIGNAL_MATCH_DATA
), 
 314             g_signal_lookup("size_request", GTK_TYPE_WIDGET
), 
 315             0, NULL
, NULL
, m_menuBar
); 
 317             g_signal_handler_disconnect(m_menuBar
->m_widget
, handler_id
); 
 318         gtk_widget_set_size_request(m_menuBar
->m_widget
, -1, -1); 
 322 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 327 GtkNotebook 
*wxMDIChildFrame::GTKGetNotebook() const 
 329     wxMDIClientWindow 
* const 
 330         client 
= wxStaticCast(GetParent(), wxMDIClientWindow
); 
 331     wxCHECK( client
, NULL 
); 
 333     return GTK_NOTEBOOK(client
->m_widget
); 
 336 void wxMDIChildFrame::Activate() 
 338     GtkNotebook 
* const notebook 
= GTKGetNotebook(); 
 339     wxCHECK_RET( notebook
, "no parent notebook?" ); 
 341     gint pageno 
= gtk_notebook_page_num( notebook
, m_widget 
); 
 342     gtk_notebook_set_current_page( notebook
, pageno 
); 
 345 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 349 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 352     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 353     if ( !ShowMenuHelp(event
.GetMenuId()) ) 
 355         // we don't have any help text for this item, but may be the MDI frame 
 357         mdi_frame
->OnMenuHighlight(event
); 
 359 #endif // wxUSE_STATUSBAR 
 362 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 364     if ( title 
== m_title 
) 
 369     GtkNotebook 
* const notebook 
= GTKGetNotebook(); 
 370     wxCHECK_RET( notebook
, "no parent notebook?" ); 
 371     gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title 
) ); 
 374 //----------------------------------------------------------------------------- 
 376 //----------------------------------------------------------------------------- 
 378 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
) 
 380 wxMDIClientWindow::~wxMDIClientWindow() 
 382     // disconnect our handler because our ~wxWindow (which is going to be called 
 383     // after this dtor) will call DestroyChildren(); in turns our children 
 384     // ~wxWindow dtors will call wxWindow::Show(false) and this will generate 
 385     // a call to gtk_mdi_page_change_callback with an invalid parent 
 386     // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but 
 387     //  at that point of the dtor chain we are a simple wxWindow!) 
 388     g_signal_handlers_disconnect_by_func(m_widget
, 
 389                                          (gpointer
)gtk_mdi_page_change_callback
, 
 393 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame 
*parent
, long style
) 
 395     if ( !PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 396          !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, 
 397                        style
, wxDefaultValidator
, "wxMDIClientWindow" )) 
 399         wxFAIL_MSG( "wxMDIClientWindow creation failed" ); 
 403     m_widget 
= gtk_notebook_new(); 
 404     g_object_ref(m_widget
); 
 406     g_signal_connect (m_widget
, "switch_page", 
 407                       G_CALLBACK (gtk_mdi_page_change_callback
), parent
); 
 409     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 411     m_parent
->DoAddChild( this ); 
 420 void wxMDIClientWindow::AddChildGTK(wxWindowGTK
* child
) 
 422     wxMDIChildFrame
* child_frame 
= static_cast<wxMDIChildFrame
*>(child
); 
 423     wxString s 
= child_frame
->GetTitle(); 
 427     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 428     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 430     GtkNotebook
* notebook 
= GTK_NOTEBOOK(m_widget
); 
 432     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 434     child_frame
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 436     wxMDIParentFrame
* parent_frame 
= static_cast<wxMDIParentFrame
*>(GetParent()); 
 437     parent_frame
->m_justInserted 
= true;