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" 
  19 #if wxUSE_MDI_ARCHITECTURE 
  21 #include "wx/dialog.h" 
  24 #include "wx/gtk/private.h" 
  29 #include "wx/gtk/win_gtk.h" 
  31 //----------------------------------------------------------------------------- 
  33 //----------------------------------------------------------------------------- 
  35 const int wxMENU_HEIGHT 
= 27; 
  37 //----------------------------------------------------------------------------- 
  39 //----------------------------------------------------------------------------- 
  41 extern void wxapp_install_idle_handler(); 
  44 //----------------------------------------------------------------------------- 
  46 //----------------------------------------------------------------------------- 
  48 extern wxList wxPendingDelete
; 
  50 //----------------------------------------------------------------------------- 
  52 //----------------------------------------------------------------------------- 
  55 gtk_mdi_page_change_callback( GtkNotebook 
*WXUNUSED(widget
), 
  56                               GtkNotebookPage 
*page
, 
  57                               gint 
WXUNUSED(page_num
), 
  58                               wxMDIParentFrame 
*parent 
) 
  61         wxapp_install_idle_handler(); 
  63     // send deactivate event to old child 
  65     wxMDIChildFrame 
*child 
= parent
->GetActiveChild(); 
  68         wxActivateEvent 
event1( wxEVT_ACTIVATE
, false, child
->GetId() ); 
  69         event1
.SetEventObject( child
); 
  70         child
->GetEventHandler()->ProcessEvent( event1 
); 
  73     // send activate event to new child 
  75     wxMDIClientWindow 
*client_window 
= parent
->GetClientWindow(); 
  79     child 
= (wxMDIChildFrame
*) NULL
; 
  81     wxWindowList::compatibility_iterator node 
= client_window
->GetChildren().GetFirst(); 
  84         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
  86         wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") ); 
  88         if (child_frame
->m_page 
== page
) 
  93         node 
= node
->GetNext(); 
  99     wxActivateEvent 
event2( wxEVT_ACTIVATE
, true, child
->GetId() ); 
 100     event2
.SetEventObject( child
); 
 101     child
->GetEventHandler()->ProcessEvent( event2 
); 
 104 //----------------------------------------------------------------------------- 
 106 //----------------------------------------------------------------------------- 
 108 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
) 
 110 void wxMDIParentFrame::Init() 
 112     m_justInserted 
= false; 
 113     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 116 wxMDIParentFrame::~wxMDIParentFrame() 
 120 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 122                               const wxString
& title
, 
 126                               const wxString
& name 
) 
 128     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 135 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height 
) 
 137     wxFrame::GtkOnSize( x
, y
, width
, height 
); 
 139     wxMDIChildFrame 
*child_frame 
= GetActiveChild(); 
 140     if (!child_frame
) return; 
 142     wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 143     if (!menu_bar
) return; 
 144     if (!menu_bar
->m_widget
) return; 
 148     menu_bar
->m_width 
= m_width
; 
 149     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 150     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 152                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 155 void wxMDIParentFrame::OnInternalIdle() 
 157     /* if a an MDI child window has just been inserted 
 158        it has to be brought to the top in idle time. we 
 159        simply set the last notebook page active as new 
 160        pages can only be appended at the end */ 
 164         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 165         gtk_notebook_set_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 167         m_justInserted 
= false; 
 171     wxFrame::OnInternalIdle(); 
 173     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 174     bool visible_child_menu 
= false; 
 176     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 179         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 183             wxMenuBar 
*menu_bar 
= 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 
); 
 209         node 
= node
->GetNext(); 
 212     /* show/hide parent menu bar as required */ 
 213     if ((m_frameMenuBar
) && 
 214         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 216         if (visible_child_menu
) 
 218             m_frameMenuBar
->Show( false ); 
 219             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 223             m_frameMenuBar
->Show( true ); 
 224             m_frameMenuBar
->SetInvokingWindow( this ); 
 226             m_frameMenuBar
->m_width 
= m_width
; 
 227             m_frameMenuBar
->m_height 
= wxMENU_HEIGHT
; 
 228             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 229                                 m_frameMenuBar
->m_widget
, 
 230                                 0, 0, m_width
, wxMENU_HEIGHT 
); 
 235 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height 
) const 
 237     wxFrame::DoGetClientSize( width
, height 
); 
 240 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 242     if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
; 
 244     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 245     if (!notebook
) return (wxMDIChildFrame
*) NULL
; 
 247     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 248     if (i 
< 0) return (wxMDIChildFrame
*) NULL
; 
 250     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 251     if (!page
) return (wxMDIChildFrame
*) NULL
; 
 253     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 256         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 258         wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") ); 
 260         if (child_frame
->m_page 
== page
) 
 262         node 
= node
->GetNext(); 
 265     return (wxMDIChildFrame
*) NULL
; 
 268 wxMDIClientWindow 
*wxMDIParentFrame::GetClientWindow() const 
 270     return m_clientWindow
; 
 273 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 275     m_clientWindow 
= new wxMDIClientWindow( this ); 
 276     return m_clientWindow
; 
 279 void wxMDIParentFrame::ActivateNext() 
 282       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 285 void wxMDIParentFrame::ActivatePrevious() 
 288       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 291 //----------------------------------------------------------------------------- 
 293 //----------------------------------------------------------------------------- 
 295 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 297 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 298     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 299     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 302 wxMDIChildFrame::wxMDIChildFrame() 
 304     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 305     m_page 
= (GtkNotebookPage 
*) NULL
; 
 308 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame 
*parent
, 
 309       wxWindowID id
, const wxString
& title
, 
 310       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 311       long style
, const wxString
& name 
) 
 313     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 314     m_page 
= (GtkNotebookPage 
*) NULL
; 
 315     Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name 
); 
 318 wxMDIChildFrame::~wxMDIChildFrame() 
 324 bool wxMDIChildFrame::Create( wxMDIParentFrame 
*parent
, 
 325       wxWindowID id
, const wxString
& title
, 
 326       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 327       long style
, const wxString
& name 
) 
 331     return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name 
); 
 334 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 336     wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags 
); 
 339 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 341     wxWindow::DoSetClientSize( width
, height 
); 
 344 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height 
) const 
 346     wxWindow::DoGetClientSize( width
, height 
); 
 349 void wxMDIChildFrame::AddChild( wxWindowBase 
*child 
) 
 351     wxWindow::AddChild(child
); 
 354 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 356     wxASSERT_MSG( m_menuBar 
== NULL
, wxT("Only one menubar allowed") ); 
 358     m_menuBar 
= menu_bar
; 
 362         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 364         m_menuBar
->SetParent( mdi_frame 
); 
 366         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 367         gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
), 
 369                          0, 0,  mdi_frame
->m_width
, wxMENU_HEIGHT 
); 
 373 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 378 void wxMDIChildFrame::Activate() 
 380     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 381     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 382     gint pageno 
= gtk_notebook_page_num( notebook
, m_widget 
); 
 383     gtk_notebook_set_page( notebook
, pageno 
); 
 386 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 390 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 393     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 394     if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) ) 
 396         // we don't have any help text for this item, but may be the MDI frame 
 398         mdi_frame
->OnMenuHighlight(event
); 
 400 #endif // wxUSE_STATUSBAR 
 403 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 405     if ( title 
== m_title 
) 
 410     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 411     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 412     gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title 
) ); 
 415 //----------------------------------------------------------------------------- 
 417 //----------------------------------------------------------------------------- 
 419 static void gtk_page_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow 
*win 
) 
 421     if (g_isIdle
) wxapp_install_idle_handler(); 
 423     if ((win
->m_x 
== alloc
->x
) && 
 424         (win
->m_y 
== alloc
->y
) && 
 425         (win
->m_width 
== alloc
->width
) && 
 426         (win
->m_height 
== alloc
->height
) && 
 432     win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height 
); 
 435 //----------------------------------------------------------------------------- 
 436 // InsertChild callback for wxMDIClientWindow 
 437 //----------------------------------------------------------------------------- 
 439 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child 
) 
 441     wxString s 
= child
->m_title
; 
 442     if (s
.IsNull()) s 
= _("MDI child"); 
 444     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 445     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 447     gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate", 
 448       GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child 
); 
 450     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 452     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 454     child
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 456     wxMDIParentFrame 
*parent_frame 
= (wxMDIParentFrame
*) parent
->GetParent(); 
 457     parent_frame
->m_justInserted 
= true; 
 460 //----------------------------------------------------------------------------- 
 462 //----------------------------------------------------------------------------- 
 464 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
) 
 466 wxMDIClientWindow::wxMDIClientWindow() 
 470 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame 
*parent
, long style 
) 
 472     CreateClient( parent
, style 
); 
 475 wxMDIClientWindow::~wxMDIClientWindow() 
 479 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame 
*parent
, long style 
) 
 483     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInMDI
; 
 485     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 486         !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") )) 
 488         wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") ); 
 492     m_widget 
= gtk_notebook_new(); 
 494     gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page", 
 495       GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent 
); 
 497     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 499     m_parent
->DoAddChild( this );