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 wxList wxPendingDelete
; 
  40 //----------------------------------------------------------------------------- 
  42 //----------------------------------------------------------------------------- 
  46 gtk_mdi_page_change_callback( GtkNotebook 
*WXUNUSED(widget
), 
  47                               GtkNotebookPage 
*page
, 
  48                               gint 
WXUNUSED(page_num
), 
  49                               wxMDIParentFrame 
*parent 
) 
  52         wxapp_install_idle_handler(); 
  54     // send deactivate event to old child 
  56     wxMDIChildFrame 
*child 
= parent
->GetActiveChild(); 
  59         wxActivateEvent 
event1( wxEVT_ACTIVATE
, false, child
->GetId() ); 
  60         event1
.SetEventObject( child
); 
  61         child
->GetEventHandler()->ProcessEvent( event1 
); 
  64     // send activate event to new child 
  66     wxMDIClientWindow 
*client_window 
= parent
->GetClientWindow(); 
  70     child 
= (wxMDIChildFrame
*) NULL
; 
  72     wxWindowList::compatibility_iterator node 
= client_window
->GetChildren().GetFirst(); 
  75         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
  76         // CE: we come here in the destructor with a null child_frame - I think because 
  77         // g_signal_connect (m_widget, "switch_page", (see below) 
  78         // isn't deleted early enough 
  82         if (child_frame
->m_page 
== page
) 
  87         node 
= node
->GetNext(); 
  93     wxActivateEvent 
event2( wxEVT_ACTIVATE
, true, child
->GetId() ); 
  94     event2
.SetEventObject( child
); 
  95     child
->GetEventHandler()->ProcessEvent( event2 
); 
  99 //----------------------------------------------------------------------------- 
 101 //----------------------------------------------------------------------------- 
 103 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
) 
 105 void wxMDIParentFrame::Init() 
 107     m_justInserted 
= false; 
 108     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 111 wxMDIParentFrame::~wxMDIParentFrame() 
 115 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 117                               const wxString
& title
, 
 121                               const wxString
& name 
) 
 123     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 130 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height 
) 
 132     wxFrame::GtkOnSize( x
, y
, width
, height 
); 
 134     wxMDIChildFrame 
*child_frame 
= GetActiveChild(); 
 135     if (!child_frame
) return; 
 137     wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 138     if (!menu_bar
) return; 
 139     if (!menu_bar
->m_widget
) return; 
 143     menu_bar
->m_width 
= m_width
; 
 144     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 145     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 147                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 150 void wxMDIParentFrame::OnInternalIdle() 
 152     /* if a an MDI child window has just been inserted 
 153        it has to be brought to the top in idle time. we 
 154        simply set the last notebook page active as new 
 155        pages can only be appended at the end */ 
 159         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 160         gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 162         /* need to set the menubar of the child */ 
 163         wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 164         if (active_child_frame 
!= NULL
) 
 166             wxMenuBar 
*menu_bar 
= active_child_frame
->m_menuBar
; 
 169                 menu_bar
->m_width 
= m_width
; 
 170                 menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 171                 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 173                                     0, 0, m_width
, wxMENU_HEIGHT 
); 
 174                 menu_bar
->SetInvokingWindow(active_child_frame
); 
 177         m_justInserted 
= false; 
 181     wxFrame::OnInternalIdle(); 
 183     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 184     bool visible_child_menu 
= false; 
 186     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 189         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 193             wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 196                 if (child_frame 
== active_child_frame
) 
 198                     if (menu_bar
->Show(true)) 
 200                         menu_bar
->m_width 
= m_width
; 
 201                         menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 202                         gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 204                                             0, 0, m_width
, wxMENU_HEIGHT 
); 
 205                         menu_bar
->SetInvokingWindow( child_frame 
); 
 207                     visible_child_menu 
= true; 
 211                     if (menu_bar
->Show(false)) 
 213                         menu_bar
->UnsetInvokingWindow( child_frame 
); 
 219         node 
= node
->GetNext(); 
 222     /* show/hide parent menu bar as required */ 
 223     if ((m_frameMenuBar
) && 
 224         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 226         if (visible_child_menu
) 
 228             m_frameMenuBar
->Show( false ); 
 229             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 233             m_frameMenuBar
->Show( true ); 
 234             m_frameMenuBar
->SetInvokingWindow( this ); 
 236             m_frameMenuBar
->m_width 
= m_width
; 
 237             m_frameMenuBar
->m_height 
= wxMENU_HEIGHT
; 
 238             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 239                                 m_frameMenuBar
->m_widget
, 
 240                                 0, 0, m_width
, wxMENU_HEIGHT 
); 
 245 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height 
) const 
 247     wxFrame::DoGetClientSize( width
, height 
); 
 250 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 252     if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
; 
 254     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 255     if (!notebook
) return (wxMDIChildFrame
*) NULL
; 
 257     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 258     if (i 
< 0) return (wxMDIChildFrame
*) NULL
; 
 260     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 261     if (!page
) return (wxMDIChildFrame
*) NULL
; 
 263     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 266         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 268         wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") ); 
 270         if (child_frame
->m_page 
== page
) 
 272         node 
= node
->GetNext(); 
 275     return (wxMDIChildFrame
*) NULL
; 
 278 wxMDIClientWindow 
*wxMDIParentFrame::GetClientWindow() const 
 280     return m_clientWindow
; 
 283 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 285     m_clientWindow 
= new wxMDIClientWindow( this ); 
 286     return m_clientWindow
; 
 289 void wxMDIParentFrame::ActivateNext() 
 292       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 295 void wxMDIParentFrame::ActivatePrevious() 
 298       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 301 //----------------------------------------------------------------------------- 
 303 //----------------------------------------------------------------------------- 
 305 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 307 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 308     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 309     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 312 wxMDIChildFrame::wxMDIChildFrame() 
 314     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 315     m_page 
= (GtkNotebookPage 
*) NULL
; 
 318 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame 
*parent
, 
 319       wxWindowID id
, const wxString
& title
, 
 320       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 321       long style
, const wxString
& name 
) 
 323     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 324     m_page 
= (GtkNotebookPage 
*) NULL
; 
 325     Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name 
); 
 328 wxMDIChildFrame::~wxMDIChildFrame() 
 334 bool wxMDIChildFrame::Create( wxMDIParentFrame 
*parent
, 
 335       wxWindowID id
, const wxString
& title
, 
 336       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 337       long style
, const wxString
& name 
) 
 341     return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name 
); 
 344 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 346     wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags 
); 
 349 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 351     wxWindow::DoSetClientSize( width
, height 
); 
 354 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height 
) const 
 356     wxWindow::DoGetClientSize( width
, height 
); 
 359 void wxMDIChildFrame::AddChild( wxWindowBase 
*child 
) 
 361     wxWindow::AddChild(child
); 
 364 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 366     wxASSERT_MSG( m_menuBar 
== NULL
, wxT("Only one menubar allowed") ); 
 368     m_menuBar 
= menu_bar
; 
 372         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 374         m_menuBar
->SetParent( mdi_frame 
); 
 376         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 377         gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
), 
 379                          0, 0,  mdi_frame
->m_width
, wxMENU_HEIGHT 
); 
 383 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 388 void wxMDIChildFrame::Activate() 
 390     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 391     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 392     gint pageno 
= gtk_notebook_page_num( notebook
, m_widget 
); 
 393     gtk_notebook_set_current_page( notebook
, pageno 
); 
 396 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 400 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 403     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 404     if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) ) 
 406         // we don't have any help text for this item, but may be the MDI frame 
 408         mdi_frame
->OnMenuHighlight(event
); 
 410 #endif // wxUSE_STATUSBAR 
 413 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 415     if ( title 
== m_title 
) 
 420     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 421     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 422     gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title 
) ); 
 425 //----------------------------------------------------------------------------- 
 427 //----------------------------------------------------------------------------- 
 430 static void gtk_page_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow 
*win 
) 
 432     if (g_isIdle
) wxapp_install_idle_handler(); 
 434     if ((win
->m_x 
== alloc
->x
) && 
 435         (win
->m_y 
== alloc
->y
) && 
 436         (win
->m_width 
== alloc
->width
) && 
 437         (win
->m_height 
== alloc
->height
) && 
 443     win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height 
); 
 447 //----------------------------------------------------------------------------- 
 448 // InsertChild callback for wxMDIClientWindow 
 449 //----------------------------------------------------------------------------- 
 451 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child 
) 
 453     wxString s 
= child
->GetTitle(); 
 454     if (s
.IsNull()) s 
= _("MDI child"); 
 456     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 457     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 459     g_signal_connect (child
->m_widget
, "size_allocate", 
 460                       G_CALLBACK (gtk_page_size_callback
), child
); 
 462     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 464     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 466     child
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 468     wxMDIParentFrame 
*parent_frame 
= (wxMDIParentFrame
*) parent
->GetParent(); 
 469     parent_frame
->m_justInserted 
= true; 
 472 //----------------------------------------------------------------------------- 
 474 //----------------------------------------------------------------------------- 
 476 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
) 
 478 wxMDIClientWindow::wxMDIClientWindow() 
 482 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame 
*parent
, long style 
) 
 484     CreateClient( parent
, style 
); 
 487 wxMDIClientWindow::~wxMDIClientWindow() 
 492 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame 
*parent
, long style 
) 
 496     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInMDI
; 
 498     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 499         !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") )) 
 501         wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") ); 
 505     m_widget 
= gtk_notebook_new(); 
 507     g_signal_connect (m_widget
, "switch_page", 
 508                       G_CALLBACK (gtk_mdi_page_change_callback
), parent
); 
 510     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 512     m_parent
->DoAddChild( this );