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 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
) 
 106 wxMDIParentFrame::wxMDIParentFrame() 
 108     m_justInserted 
= FALSE
; 
 109     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 112 wxMDIParentFrame::wxMDIParentFrame( wxWindow 
*parent
, 
 113       wxWindowID id
, const wxString
& title
, 
 114       const wxPoint
& pos
, const wxSize
& size
, 
 115       long style
, const wxString
& name 
) 
 117     m_justInserted 
= FALSE
; 
 118     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 119     Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 122 wxMDIParentFrame::~wxMDIParentFrame() 
 126 bool wxMDIParentFrame::Create( wxWindow 
*parent
, 
 127       wxWindowID id
, const wxString
& title
, 
 128       const wxPoint
& pos
, const wxSize
& size
, 
 129       long style
, const wxString
& name 
) 
 131     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 138 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height 
) 
 140     wxFrame::GtkOnSize( x
, y
, width
, height 
); 
 142     wxMDIChildFrame 
*child_frame 
= GetActiveChild(); 
 143     if (!child_frame
) return; 
 145     wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 146     if (!menu_bar
) return; 
 147     if (!menu_bar
->m_widget
) return; 
 151     menu_bar
->m_width 
= m_width
; 
 152     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 153     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),  
 155                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 158 void wxMDIParentFrame::OnInternalIdle() 
 160     /* if a an MDI child window has just been inserted 
 161        it has to be brought to the top in idle time. we 
 162        simply set the last notebook page active as new 
 163        pages can only be appended at the end */ 
 167         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 168         gtk_notebook_set_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 170         m_justInserted 
= FALSE
; 
 174     wxFrame::OnInternalIdle(); 
 176     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 177     bool visible_child_menu 
= FALSE
; 
 179     wxNode 
*node 
= m_clientWindow
->GetChildren().First(); 
 182         wxMDIChildFrame 
*child_frame 
= (wxMDIChildFrame 
*)node
->Data(); 
 183         wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 184         if (child_frame
->m_menuBar
) 
 186             if (child_frame 
== active_child_frame
) 
 188                 if (menu_bar
->Show(TRUE
)) 
 190                     menu_bar
->m_width 
= m_width
; 
 191                     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 192                     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),  
 194                                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 195                     menu_bar
->SetInvokingWindow( child_frame 
); 
 197                 visible_child_menu 
= TRUE
; 
 201                 if (menu_bar
->Show(FALSE
)) 
 203                     menu_bar
->UnsetInvokingWindow( child_frame 
); 
 210     /* show/hide parent menu bar as required */ 
 211     if ((m_frameMenuBar
) && 
 212         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 214         if (visible_child_menu
) 
 216             m_frameMenuBar
->Show( FALSE 
); 
 217             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 221             m_frameMenuBar
->Show( TRUE 
); 
 222             m_frameMenuBar
->SetInvokingWindow( this ); 
 224             m_frameMenuBar
->m_width 
= m_width
; 
 225             m_frameMenuBar
->m_height 
= wxMENU_HEIGHT
; 
 226             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),  
 227                                   m_frameMenuBar
->m_widget
,  
 228                                   0, 0, m_width
, wxMENU_HEIGHT 
); 
 233 void wxMDIParentFrame::GetClientSize(int *width
, int *height 
) const 
 235     wxFrame::GetClientSize( width
, height 
); 
 238 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 240     if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
; 
 242     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 243     if (!notebook
) return (wxMDIChildFrame
*) NULL
; 
 245 #if (GTK_MINOR_VERSION > 0) 
 246     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 248     gint i 
= gtk_notebook_current_page( notebook 
); 
 250     if (i 
< 0) return (wxMDIChildFrame
*) NULL
; 
 252     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 253     if (!page
) return (wxMDIChildFrame
*) NULL
; 
 255     wxNode 
*node 
= m_clientWindow
->GetChildren().First(); 
 258         wxMDIChildFrame 
*child_frame 
= (wxMDIChildFrame 
*)node
->Data(); 
 259         if (child_frame
->m_page 
== page
) 
 264     return (wxMDIChildFrame
*) NULL
; 
 267 wxMDIClientWindow 
*wxMDIParentFrame::GetClientWindow() const 
 269     return m_clientWindow
; 
 272 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 274     m_clientWindow 
= new wxMDIClientWindow( this ); 
 275     return m_clientWindow
; 
 278 void wxMDIParentFrame::ActivateNext() 
 281       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 284 void wxMDIParentFrame::ActivatePrevious() 
 287       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 290 void wxMDIParentFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 294 void wxMDIParentFrame::OnSysColourChanged( wxSysColourChangedEvent
& WXUNUSED(event
) ) 
 298 //----------------------------------------------------------------------------- 
 300 //----------------------------------------------------------------------------- 
 302 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 304 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 305     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 308 wxMDIChildFrame::wxMDIChildFrame() 
 310     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 311     m_page 
= (GtkNotebookPage 
*) NULL
; 
 314 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame 
*parent
, 
 315       wxWindowID id
, const wxString
& title
, 
 316       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 317       long style
, const wxString
& name 
) 
 319     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 320     m_page 
= (GtkNotebookPage 
*) NULL
; 
 321     Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name 
); 
 324 wxMDIChildFrame::~wxMDIChildFrame() 
 330 bool wxMDIChildFrame::Create( wxMDIParentFrame 
*parent
, 
 331       wxWindowID id
, const wxString
& title
, 
 332       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 333       long style
, const wxString
& name 
) 
 337     return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name 
); 
 340 void wxMDIChildFrame::GetClientSize( int *width
, int *height 
) const 
 342     wxWindow::GetClientSize( width
, height 
); 
 345 void wxMDIChildFrame::AddChild( wxWindowBase 
*child 
) 
 347     wxWindow::AddChild(child
); 
 350 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 352     wxASSERT_MSG( m_menuBar 
== NULL
, wxT("Only one menubar allowed") ); 
 354     m_menuBar 
= menu_bar
; 
 358         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 360         m_menuBar
->SetParent( mdi_frame 
); 
 362         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 363         gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),  
 365                          0, 0,  mdi_frame
->m_width
, wxMENU_HEIGHT 
); 
 369 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 374 void wxMDIChildFrame::Activate() 
 376 #if (GTK_MINOR_VERSION > 0) 
 377     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 378     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 379     gint pageno 
= gtk_notebook_page_num( notebook
, m_page
->child 
); 
 380     gtk_notebook_set_page( notebook
, pageno 
); 
 382     // the only way I can see to do this under gtk+ 1.0.X would 
 383     // be to keep track of page numbers, start at first and  
 384     // do "next" enough times to get to this page number - messy 
 385     // - J. Russell Smyth 
 389 void wxMDIChildFrame::OnActivate( wxActivateEvent 
&WXUNUSED(event
) ) 
 393 //----------------------------------------------------------------------------- 
 395 //----------------------------------------------------------------------------- 
 397 static void gtk_page_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow 
*win 
) 
 399     if (g_isIdle
) wxapp_install_idle_handler(); 
 401     if ((win
->m_x 
== alloc
->x
) && 
 402         (win
->m_y 
== alloc
->y
) && 
 403         (win
->m_width 
== alloc
->width
) && 
 404         (win
->m_height 
== alloc
->height
) && 
 410     win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height 
); 
 413 //----------------------------------------------------------------------------- 
 414 // InsertChild callback for wxMDIClientWindow 
 415 //----------------------------------------------------------------------------- 
 417 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child 
) 
 419     wxString s 
= child
->m_title
; 
 420     if (s
.IsNull()) s 
= _("MDI child"); 
 422     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 423     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 425     gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate", 
 426       GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child 
); 
 428     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 430     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 432     child
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 434     wxMDIParentFrame 
*parent_frame 
= (wxMDIParentFrame
*) parent
->GetParent(); 
 435     parent_frame
->m_justInserted 
= TRUE
; 
 438 //----------------------------------------------------------------------------- 
 440 //----------------------------------------------------------------------------- 
 442 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
) 
 444 wxMDIClientWindow::wxMDIClientWindow() 
 448 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame 
*parent
, long style 
) 
 450     CreateClient( parent
, style 
); 
 453 wxMDIClientWindow::~wxMDIClientWindow() 
 457 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame 
*parent
, long style 
) 
 461     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInMDI
; 
 463     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 464         !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") )) 
 466         wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") ); 
 470     m_widget 
= gtk_notebook_new(); 
 472     gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page", 
 473       GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent 
); 
 475     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 477     m_parent
->DoAddChild( this );