1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "mdi.h" 
  16 #if wxUSE_MDI_ARCHITECTURE 
  18 #include "wx/dialog.h" 
  25 #include "wx/gtk/win_gtk.h" 
  27 //----------------------------------------------------------------------------- 
  29 //----------------------------------------------------------------------------- 
  31 const int wxMENU_HEIGHT 
= 27; 
  33 //----------------------------------------------------------------------------- 
  35 //----------------------------------------------------------------------------- 
  37 extern void wxapp_install_idle_handler(); 
  40 //----------------------------------------------------------------------------- 
  42 //----------------------------------------------------------------------------- 
  44 extern wxList wxPendingDelete
; 
  46 //----------------------------------------------------------------------------- 
  48 //----------------------------------------------------------------------------- 
  51 gtk_mdi_page_change_callback( GtkNotebook 
*WXUNUSED(widget
), 
  52                               GtkNotebookPage 
*page
, 
  53                               gint 
WXUNUSED(page_num
), 
  54                               wxMDIParentFrame 
*parent 
) 
  57         wxapp_install_idle_handler(); 
  59     // send deactivate event to old child 
  61     wxMDIChildFrame 
*child 
= parent
->GetActiveChild(); 
  64         wxActivateEvent 
event1( wxEVT_ACTIVATE
, FALSE
, child
->GetId() ); 
  65         event1
.SetEventObject( child
); 
  66         child
->GetEventHandler()->ProcessEvent( event1 
); 
  69     // send activate event to new child 
  71     wxMDIClientWindow 
*client_window 
= parent
->GetClientWindow(); 
  75     child 
= (wxMDIChildFrame
*) NULL
; 
  77     wxNode 
*node 
= client_window
->GetChildren().First(); 
  80         wxMDIChildFrame 
*child_frame 
= (wxMDIChildFrame 
*)node
->Data(); 
  81         if (child_frame
->m_page 
== page
) 
  92     wxActivateEvent 
event2( wxEVT_ACTIVATE
, TRUE
, child
->GetId() ); 
  93     event2
.SetEventObject( child
); 
  94     child
->GetEventHandler()->ProcessEvent( event2 
); 
  97 //----------------------------------------------------------------------------- 
  99 //----------------------------------------------------------------------------- 
 101 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
) 
 103 void wxMDIParentFrame::Init() 
 105     m_justInserted 
= FALSE
; 
 106     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 109 wxMDIParentFrame::~wxMDIParentFrame() 
 113 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 115                               const wxString
& title
, 
 119                               const wxString
& name 
) 
 121     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 128 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height 
) 
 130     wxFrame::GtkOnSize( x
, y
, width
, height 
); 
 132     wxMDIChildFrame 
*child_frame 
= GetActiveChild(); 
 133     if (!child_frame
) return; 
 135     wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 136     if (!menu_bar
) return; 
 137     if (!menu_bar
->m_widget
) return; 
 141     menu_bar
->m_width 
= m_width
; 
 142     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 143     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 145                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 148 void wxMDIParentFrame::OnInternalIdle() 
 150     /* if a an MDI child window has just been inserted 
 151        it has to be brought to the top in idle time. we 
 152        simply set the last notebook page active as new 
 153        pages can only be appended at the end */ 
 157         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 158         gtk_notebook_set_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 160         m_justInserted 
= FALSE
; 
 164     wxFrame::OnInternalIdle(); 
 166     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 167     bool visible_child_menu 
= FALSE
; 
 169     wxNode 
*node 
= m_clientWindow
->GetChildren().First(); 
 172         wxObject 
*child 
= node
->Data(); 
 173         wxMDIChildFrame 
*child_frame 
= wxDynamicCast(child
, wxMDIChildFrame
); 
 176             wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 179                 if (child_frame 
== active_child_frame
) 
 181                     if (menu_bar
->Show(TRUE
)) 
 183                         menu_bar
->m_width 
= m_width
; 
 184                         menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 185                         gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 187                                             0, 0, m_width
, wxMENU_HEIGHT 
); 
 188                         menu_bar
->SetInvokingWindow( child_frame 
); 
 190                     visible_child_menu 
= TRUE
; 
 194                     if (menu_bar
->Show(FALSE
)) 
 196                         menu_bar
->UnsetInvokingWindow( child_frame 
); 
 205     /* show/hide parent menu bar as required */ 
 206     if ((m_frameMenuBar
) && 
 207         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 209         if (visible_child_menu
) 
 211             m_frameMenuBar
->Show( FALSE 
); 
 212             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 216             m_frameMenuBar
->Show( TRUE 
); 
 217             m_frameMenuBar
->SetInvokingWindow( this ); 
 219             m_frameMenuBar
->m_width 
= m_width
; 
 220             m_frameMenuBar
->m_height 
= wxMENU_HEIGHT
; 
 221             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 222                                 m_frameMenuBar
->m_widget
, 
 223                                 0, 0, m_width
, wxMENU_HEIGHT 
); 
 228 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height 
) const 
 230     wxFrame::DoGetClientSize( width
, height 
); 
 233 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 235     if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
; 
 237     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 238     if (!notebook
) return (wxMDIChildFrame
*) NULL
; 
 240 #if (GTK_MINOR_VERSION > 0) 
 241     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 243     gint i 
= gtk_notebook_current_page( notebook 
); 
 245     if (i 
< 0) return (wxMDIChildFrame
*) NULL
; 
 247     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 248     if (!page
) return (wxMDIChildFrame
*) NULL
; 
 250     wxNode 
*node 
= m_clientWindow
->GetChildren().First(); 
 253         wxMDIChildFrame 
*child_frame 
= (wxMDIChildFrame 
*)node
->Data(); 
 254         if (child_frame
->m_page 
== page
) 
 259     return (wxMDIChildFrame
*) NULL
; 
 262 wxMDIClientWindow 
*wxMDIParentFrame::GetClientWindow() const 
 264     return m_clientWindow
; 
 267 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 269     m_clientWindow 
= new wxMDIClientWindow( this ); 
 270     return m_clientWindow
; 
 273 void wxMDIParentFrame::ActivateNext() 
 276       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 279 void wxMDIParentFrame::ActivatePrevious() 
 282       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 285 //----------------------------------------------------------------------------- 
 287 //----------------------------------------------------------------------------- 
 289 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 291 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 292     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 293     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 296 wxMDIChildFrame::wxMDIChildFrame() 
 298     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 299     m_page 
= (GtkNotebookPage 
*) NULL
; 
 303 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame 
*parent
, 
 304       wxWindowID id
, const wxString
& title
, 
 305       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 306       long style
, const wxString
& name 
) 
 308     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 309     m_page 
= (GtkNotebookPage 
*) NULL
; 
 311     Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name 
); 
 314 wxMDIChildFrame::~wxMDIChildFrame() 
 320 bool wxMDIChildFrame::Create( wxMDIParentFrame 
*parent
, 
 321       wxWindowID id
, const wxString
& title
, 
 322       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 323       long style
, const wxString
& name 
) 
 327     return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name 
); 
 330 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height 
) const 
 332     wxWindow::DoGetClientSize( width
, height 
); 
 335 void wxMDIChildFrame::AddChild( wxWindowBase 
*child 
) 
 337     wxWindow::AddChild(child
); 
 340 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 342     wxASSERT_MSG( m_menuBar 
== NULL
, wxT("Only one menubar allowed") ); 
 344     m_menuBar 
= menu_bar
; 
 348         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 350         m_menuBar
->SetParent( mdi_frame 
); 
 352         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 353         gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
), 
 355                          0, 0,  mdi_frame
->m_width
, wxMENU_HEIGHT 
); 
 359 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 364 void wxMDIChildFrame::Activate() 
 366 #if (GTK_MINOR_VERSION > 0) 
 367     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 368     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 369     gint pageno 
= gtk_notebook_page_num( notebook
, m_page
->child 
); 
 370     gtk_notebook_set_page( notebook
, pageno 
); 
 372     // the only way I can see to do this under gtk+ 1.0.X would 
 373     // be to keep track of page numbers, start at first and 
 374     // do "next" enough times to get to this page number - messy 
 375     // - J. Russell Smyth 
 379 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 383 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 386     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 387     if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) ) 
 389         // we don't have any help text for this item, but may be the MDI frame 
 391         mdi_frame
->OnMenuHighlight(event
); 
 393 #endif // wxUSE_STATUSBAR 
 396 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 398     if ( title 
== m_title 
) 
 403     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 404     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 405     gtk_notebook_set_tab_label_text(notebook
, m_page
->child
, title
.mbc_str()); 
 408 //----------------------------------------------------------------------------- 
 410 //----------------------------------------------------------------------------- 
 412 static void gtk_page_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow 
*win 
) 
 414     if (g_isIdle
) wxapp_install_idle_handler(); 
 416     if ((win
->m_x 
== alloc
->x
) && 
 417         (win
->m_y 
== alloc
->y
) && 
 418         (win
->m_width 
== alloc
->width
) && 
 419         (win
->m_height 
== alloc
->height
) && 
 425     win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height 
); 
 428 //----------------------------------------------------------------------------- 
 429 // InsertChild callback for wxMDIClientWindow 
 430 //----------------------------------------------------------------------------- 
 432 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child 
) 
 434     wxString s 
= child
->m_title
; 
 435     if (s
.IsNull()) s 
= _("MDI child"); 
 437     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 438     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 440     gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate", 
 441       GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child 
); 
 443     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 445     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 447     child
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 449     wxMDIParentFrame 
*parent_frame 
= (wxMDIParentFrame
*) parent
->GetParent(); 
 450     parent_frame
->m_justInserted 
= TRUE
; 
 453 //----------------------------------------------------------------------------- 
 455 //----------------------------------------------------------------------------- 
 457 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
) 
 459 wxMDIClientWindow::wxMDIClientWindow() 
 463 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame 
*parent
, long style 
) 
 465     CreateClient( parent
, style 
); 
 468 wxMDIClientWindow::~wxMDIClientWindow() 
 472 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame 
*parent
, long style 
) 
 476     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInMDI
; 
 478     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 479         !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") )) 
 481         wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") ); 
 485     m_widget 
= gtk_notebook_new(); 
 487     gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page", 
 488       GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent 
); 
 490     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 492     m_parent
->DoAddChild( this );