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
->Attach(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                         // Attach() asserts if we call it for an already 
 153                         // attached menu bar so don't do it if we're already 
 154                         // associated with this frame (it would be nice to get 
 155                         // rid of this check and ensure that this doesn't 
 157                         if ( menu_bar
->GetFrame() != child_frame 
) 
 158                             menu_bar
->Attach( child_frame 
); 
 160                     visible_child_menu 
= true; 
 164                     if (menu_bar
->Show(false)) 
 172         node 
= node
->GetNext(); 
 175     /* show/hide parent menu bar as required */ 
 176     if ((m_frameMenuBar
) && 
 177         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 179         if (visible_child_menu
) 
 181             m_frameMenuBar
->Show( false ); 
 182             m_frameMenuBar
->Detach(); 
 186             m_frameMenuBar
->Show( true ); 
 187             m_frameMenuBar
->Attach( this ); 
 192 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const 
 194     wxFrame::DoGetClientSize(width
, height
); 
 198         wxMDIChildFrame
* active_child_frame 
= GetActiveChild(); 
 199         if (active_child_frame
) 
 201             wxMenuBar
* menubar 
= active_child_frame
->m_menuBar
; 
 202             if (menubar 
&& menubar
->IsShown()) 
 205                 gtk_widget_size_request(menubar
->m_widget
, &req
); 
 206                 *height 
-= req
.height
; 
 207                 if (*height 
< 0) *height 
= 0; 
 213 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 215     if (!m_clientWindow
) return NULL
; 
 217     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 218     if (!notebook
) return NULL
; 
 220     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 221     if (i 
< 0) return NULL
; 
 223     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 224     if (!page
) return NULL
; 
 226     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 229         if ( wxPendingDelete
.Member(node
->GetData()) ) 
 232         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 237         if (child_frame
->m_page 
== page
) 
 240         node 
= node
->GetNext(); 
 246 void wxMDIParentFrame::ActivateNext() 
 249       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 252 void wxMDIParentFrame::ActivatePrevious() 
 255       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 258 //----------------------------------------------------------------------------- 
 260 //----------------------------------------------------------------------------- 
 262 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 264 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 265     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 266     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 269 void wxMDIChildFrame::Init() 
 275 bool wxMDIChildFrame::Create(wxMDIParentFrame 
*parent
, 
 277                              const wxString
& title
, 
 278                              const wxPoint
& WXUNUSED(pos
), 
 281                              const wxString
& name
) 
 283     m_mdiParent 
= parent
; 
 286     return wxWindow::Create(parent
->GetClientWindow(), id
, 
 287                             wxDefaultPosition
, size
, 
 291 wxMDIChildFrame::~wxMDIChildFrame() 
 295     // wxMDIClientWindow does not get redrawn properly after last child is removed 
 296     if (m_parent 
&& m_parent
->GetChildren().size() <= 1) 
 297         gtk_widget_queue_draw(m_parent
->m_widget
); 
 300 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 302     wxASSERT_MSG( m_menuBar 
== NULL
, "Only one menubar allowed" ); 
 304     m_menuBar 
= menu_bar
; 
 308         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 310         m_menuBar
->SetParent( mdi_frame 
); 
 312         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 313         m_menuBar
->Show(false); 
 314         gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0); 
 315         gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0); 
 317         gulong handler_id 
= g_signal_handler_find( 
 319             GSignalMatchType(G_SIGNAL_MATCH_ID 
| G_SIGNAL_MATCH_DATA
), 
 320             g_signal_lookup("size_request", GTK_TYPE_WIDGET
), 
 321             0, NULL
, NULL
, m_menuBar
); 
 323             g_signal_handler_disconnect(m_menuBar
->m_widget
, handler_id
); 
 324         gtk_widget_set_size_request(m_menuBar
->m_widget
, -1, -1); 
 328 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 333 GtkNotebook 
*wxMDIChildFrame::GTKGetNotebook() const 
 335     wxMDIClientWindow 
* const 
 336         client 
= wxStaticCast(GetParent(), wxMDIClientWindow
); 
 337     wxCHECK( client
, NULL 
); 
 339     return GTK_NOTEBOOK(client
->m_widget
); 
 342 void wxMDIChildFrame::Activate() 
 344     GtkNotebook 
* const notebook 
= GTKGetNotebook(); 
 345     wxCHECK_RET( notebook
, "no parent notebook?" ); 
 347     gint pageno 
= gtk_notebook_page_num( notebook
, m_widget 
); 
 348     gtk_notebook_set_current_page( notebook
, pageno 
); 
 351 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 355 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 358     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 359     if ( !ShowMenuHelp(event
.GetMenuId()) ) 
 361         // we don't have any help text for this item, but may be the MDI frame 
 363         mdi_frame
->OnMenuHighlight(event
); 
 365 #endif // wxUSE_STATUSBAR 
 368 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 370     if ( title 
== m_title 
) 
 375     GtkNotebook 
* const notebook 
= GTKGetNotebook(); 
 376     wxCHECK_RET( notebook
, "no parent notebook?" ); 
 377     gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title 
) ); 
 380 //----------------------------------------------------------------------------- 
 382 //----------------------------------------------------------------------------- 
 384 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
) 
 386 wxMDIClientWindow::~wxMDIClientWindow() 
 388     // disconnect our handler because our ~wxWindow (which is going to be called 
 389     // after this dtor) will call DestroyChildren(); in turns our children 
 390     // ~wxWindow dtors will call wxWindow::Show(false) and this will generate 
 391     // a call to gtk_mdi_page_change_callback with an invalid parent 
 392     // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but 
 393     //  at that point of the dtor chain we are a simple wxWindow!) 
 394     g_signal_handlers_disconnect_by_func(m_widget
, 
 395                                          (gpointer
)gtk_mdi_page_change_callback
, 
 399 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame 
*parent
, long style
) 
 401     if ( !PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 402          !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, 
 403                        style
, wxDefaultValidator
, "wxMDIClientWindow" )) 
 405         wxFAIL_MSG( "wxMDIClientWindow creation failed" ); 
 409     m_widget 
= gtk_notebook_new(); 
 410     g_object_ref(m_widget
); 
 412     g_signal_connect (m_widget
, "switch_page", 
 413                       G_CALLBACK (gtk_mdi_page_change_callback
), parent
); 
 415     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 417     m_parent
->DoAddChild( this ); 
 426 void wxMDIClientWindow::AddChildGTK(wxWindowGTK
* child
) 
 428     wxMDIChildFrame
* child_frame 
= static_cast<wxMDIChildFrame
*>(child
); 
 429     wxString s 
= child_frame
->GetTitle(); 
 433     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 434     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 436     GtkNotebook
* notebook 
= GTK_NOTEBOOK(m_widget
); 
 438     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 440     child_frame
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 442     wxMDIParentFrame
* parent_frame 
= static_cast<wxMDIParentFrame
*>(GetParent()); 
 443     parent_frame
->m_justInserted 
= true;