1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  11 #pragma implementation "mdi.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  18 #include "wx/notebook.h" 
  22 #include "wx/dialog.h" 
  25 #include "wx/gtk/private.h" 
  30 #include "wx/gtk/win_gtk.h" 
  32 //----------------------------------------------------------------------------- 
  34 //----------------------------------------------------------------------------- 
  36 const int wxMENU_HEIGHT 
= 27; 
  38 //----------------------------------------------------------------------------- 
  40 //----------------------------------------------------------------------------- 
  42 extern void wxapp_install_idle_handler(); 
  45 //----------------------------------------------------------------------------- 
  47 //----------------------------------------------------------------------------- 
  49 extern wxList wxPendingDelete
; 
  51 //----------------------------------------------------------------------------- 
  53 //----------------------------------------------------------------------------- 
  56 gtk_mdi_page_change_callback( GtkNotebook 
*WXUNUSED(widget
), 
  57                               GtkNotebookPage 
*page
, 
  58                               gint 
WXUNUSED(page_num
), 
  59                               wxMDIParentFrame 
*parent 
) 
  62         wxapp_install_idle_handler(); 
  64     // send deactivate event to old child 
  66     wxMDIChildFrame 
*child 
= parent
->GetActiveChild(); 
  69         wxActivateEvent 
event1( wxEVT_ACTIVATE
, false, child
->GetId() ); 
  70         event1
.SetEventObject( child
); 
  71         child
->GetEventHandler()->ProcessEvent( event1 
); 
  74     // send activate event to new child 
  76     wxMDIClientWindow 
*client_window 
= parent
->GetClientWindow(); 
  80     child 
= (wxMDIChildFrame
*) NULL
; 
  82     wxWindowList::compatibility_iterator node 
= client_window
->GetChildren().GetFirst(); 
  85         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
  86         // CE: we come here in the destructor with a null child_frame - I think because 
  87         // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below) 
  88         // isn't deleted early enough 
  92         if (child_frame
->m_page 
== page
) 
  97         node 
= node
->GetNext(); 
 103     wxActivateEvent 
event2( wxEVT_ACTIVATE
, true, child
->GetId() ); 
 104     event2
.SetEventObject( child
); 
 105     child
->GetEventHandler()->ProcessEvent( event2 
); 
 108 //----------------------------------------------------------------------------- 
 110 //----------------------------------------------------------------------------- 
 112 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
) 
 114 void wxMDIParentFrame::Init() 
 116     m_justInserted 
= false; 
 117     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 120 wxMDIParentFrame::~wxMDIParentFrame() 
 124 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 126                               const wxString
& title
, 
 130                               const wxString
& name 
) 
 132     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 139 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height 
) 
 141     wxFrame::GtkOnSize( x
, y
, width
, height 
); 
 143     wxMDIChildFrame 
*child_frame 
= GetActiveChild(); 
 144     if (!child_frame
) return; 
 146     wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 147     if (!menu_bar
) return; 
 148     if (!menu_bar
->m_widget
) return; 
 152     menu_bar
->m_width 
= m_width
; 
 153     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 154     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 156                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 159 void wxMDIParentFrame::OnInternalIdle() 
 161     /* if a an MDI child window has just been inserted 
 162        it has to be brought to the top in idle time. we 
 163        simply set the last notebook page active as new 
 164        pages can only be appended at the end */ 
 168         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 169         gtk_notebook_set_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 171         /* need to set the menubar of the child */ 
 172         wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 173         if (active_child_frame 
!= NULL
) 
 175             wxMenuBar 
*menu_bar 
= active_child_frame
->m_menuBar
; 
 178                 menu_bar
->m_width 
= m_width
; 
 179                 menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 180                 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 182                                     0, 0, m_width
, wxMENU_HEIGHT 
); 
 183                 menu_bar
->SetInvokingWindow(active_child_frame
); 
 186         m_justInserted 
= false; 
 190     wxFrame::OnInternalIdle(); 
 192     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 193     bool visible_child_menu 
= false; 
 195     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 198         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 202             wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 205                 if (child_frame 
== active_child_frame
) 
 207                     if (menu_bar
->Show(true)) 
 209                         menu_bar
->m_width 
= m_width
; 
 210                         menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 211                         gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 213                                             0, 0, m_width
, wxMENU_HEIGHT 
); 
 214                         menu_bar
->SetInvokingWindow( child_frame 
); 
 216                     visible_child_menu 
= true; 
 220                     if (menu_bar
->Show(false)) 
 222                         menu_bar
->UnsetInvokingWindow( child_frame 
); 
 228         node 
= node
->GetNext(); 
 231     /* show/hide parent menu bar as required */ 
 232     if ((m_frameMenuBar
) && 
 233         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 235         if (visible_child_menu
) 
 237             m_frameMenuBar
->Show( false ); 
 238             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 242             m_frameMenuBar
->Show( true ); 
 243             m_frameMenuBar
->SetInvokingWindow( this ); 
 245             m_frameMenuBar
->m_width 
= m_width
; 
 246             m_frameMenuBar
->m_height 
= wxMENU_HEIGHT
; 
 247             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 248                                 m_frameMenuBar
->m_widget
, 
 249                                 0, 0, m_width
, wxMENU_HEIGHT 
); 
 254 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height 
) const 
 256     wxFrame::DoGetClientSize( width
, height 
); 
 259 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 261     if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
; 
 263     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 264     if (!notebook
) return (wxMDIChildFrame
*) NULL
; 
 266     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 267     if (i 
< 0) return (wxMDIChildFrame
*) NULL
; 
 269     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 270     if (!page
) return (wxMDIChildFrame
*) NULL
; 
 272     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 275         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 277         wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") ); 
 279         if (child_frame
->m_page 
== page
) 
 281         node 
= node
->GetNext(); 
 284     return (wxMDIChildFrame
*) NULL
; 
 287 wxMDIClientWindow 
*wxMDIParentFrame::GetClientWindow() const 
 289     return m_clientWindow
; 
 292 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 294     m_clientWindow 
= new wxMDIClientWindow( this ); 
 295     return m_clientWindow
; 
 298 void wxMDIParentFrame::ActivateNext() 
 301       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 304 void wxMDIParentFrame::ActivatePrevious() 
 307       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 310 //----------------------------------------------------------------------------- 
 312 //----------------------------------------------------------------------------- 
 314 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 316 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 317     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 318     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 321 wxMDIChildFrame::wxMDIChildFrame() 
 323     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 324     m_page 
= (GtkNotebookPage 
*) NULL
; 
 327 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame 
*parent
, 
 328       wxWindowID id
, const wxString
& title
, 
 329       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 330       long style
, const wxString
& name 
) 
 332     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 333     m_page 
= (GtkNotebookPage 
*) NULL
; 
 334     Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name 
); 
 337 wxMDIChildFrame::~wxMDIChildFrame() 
 343 bool wxMDIChildFrame::Create( wxMDIParentFrame 
*parent
, 
 344       wxWindowID id
, const wxString
& title
, 
 345       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 346       long style
, const wxString
& name 
) 
 350     return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name 
); 
 353 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 355     wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags 
); 
 358 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 360     wxWindow::DoSetClientSize( width
, height 
); 
 363 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height 
) const 
 365     wxWindow::DoGetClientSize( width
, height 
); 
 368 void wxMDIChildFrame::AddChild( wxWindowBase 
*child 
) 
 370     wxWindow::AddChild(child
); 
 373 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 375     wxASSERT_MSG( m_menuBar 
== NULL
, wxT("Only one menubar allowed") ); 
 377     m_menuBar 
= menu_bar
; 
 381         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 383         m_menuBar
->SetParent( mdi_frame 
); 
 385         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 386         gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
), 
 388                          0, 0,  mdi_frame
->m_width
, wxMENU_HEIGHT 
); 
 392 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 397 void wxMDIChildFrame::Activate() 
 399     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 400     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 401     gint pageno 
= gtk_notebook_page_num( notebook
, m_widget 
); 
 402     gtk_notebook_set_page( notebook
, pageno 
); 
 405 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 409 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 412     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 413     if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) ) 
 415         // we don't have any help text for this item, but may be the MDI frame 
 417         mdi_frame
->OnMenuHighlight(event
); 
 419 #endif // wxUSE_STATUSBAR 
 422 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 424     if ( title 
== m_title 
) 
 429     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 430     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 431     gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title 
) ); 
 434 //----------------------------------------------------------------------------- 
 436 //----------------------------------------------------------------------------- 
 438 static void gtk_page_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow 
*win 
) 
 440     if (g_isIdle
) wxapp_install_idle_handler(); 
 442     if ((win
->m_x 
== alloc
->x
) && 
 443         (win
->m_y 
== alloc
->y
) && 
 444         (win
->m_width 
== alloc
->width
) && 
 445         (win
->m_height 
== alloc
->height
) && 
 451     win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height 
); 
 454 //----------------------------------------------------------------------------- 
 455 // InsertChild callback for wxMDIClientWindow 
 456 //----------------------------------------------------------------------------- 
 458 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child 
) 
 460     wxString s 
= child
->m_title
; 
 461     if (s
.IsNull()) s 
= _("MDI child"); 
 463     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 464     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 466     gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate", 
 467       GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child 
); 
 469     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 471     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 473     child
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 475     wxMDIParentFrame 
*parent_frame 
= (wxMDIParentFrame
*) parent
->GetParent(); 
 476     parent_frame
->m_justInserted 
= true; 
 479 //----------------------------------------------------------------------------- 
 481 //----------------------------------------------------------------------------- 
 483 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
) 
 485 wxMDIClientWindow::wxMDIClientWindow() 
 489 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame 
*parent
, long style 
) 
 491     CreateClient( parent
, style 
); 
 494 wxMDIClientWindow::~wxMDIClientWindow() 
 499 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame 
*parent
, long style 
) 
 503     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInMDI
; 
 505     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 506         !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") )) 
 508         wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") ); 
 512     m_widget 
= gtk_notebook_new(); 
 514     gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page", 
 515       GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent 
); 
 517     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 519     m_parent
->DoAddChild( this );