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" 
  20     #include "wx/dialog.h" 
  23 #include "wx/notebook.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 //----------------------------------------------------------------------------- 
  43 //----------------------------------------------------------------------------- 
  47 gtk_mdi_page_change_callback( GtkNotebook 
*WXUNUSED(widget
), 
  48                               GtkNotebookPage 
*page
, 
  49                               gint 
WXUNUSED(page_num
), 
  50                               wxMDIParentFrame 
*parent 
) 
  53         wxapp_install_idle_handler(); 
  55     // send deactivate event to old child 
  57     wxMDIChildFrame 
*child 
= parent
->GetActiveChild(); 
  60         wxActivateEvent 
event1( wxEVT_ACTIVATE
, false, child
->GetId() ); 
  61         event1
.SetEventObject( child
); 
  62         child
->GetEventHandler()->ProcessEvent( event1 
); 
  65     // send activate event to new child 
  67     wxMDIClientWindow 
*client_window 
= parent
->GetClientWindow(); 
  71     child 
= (wxMDIChildFrame
*) NULL
; 
  73     wxWindowList::compatibility_iterator node 
= client_window
->GetChildren().GetFirst(); 
  76         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
  78         // child_frame can be NULL when this is called from dtor, probably 
  79         // because g_signal_connect (m_widget, "switch_page", (see below) 
  80         // isn't deleted early enough 
  81         if ( child_frame 
&& child_frame
->m_page 
== page 
) 
  86         node 
= node
->GetNext(); 
  92     wxActivateEvent 
event2( wxEVT_ACTIVATE
, true, child
->GetId() ); 
  93     event2
.SetEventObject( child
); 
  94     child
->GetEventHandler()->ProcessEvent( event2 
); 
  98 //----------------------------------------------------------------------------- 
 100 //----------------------------------------------------------------------------- 
 102 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
) 
 104 void wxMDIParentFrame::Init() 
 106     m_justInserted 
= false; 
 107     m_clientWindow 
= (wxMDIClientWindow 
*) NULL
; 
 110 wxMDIParentFrame::~wxMDIParentFrame() 
 114 bool wxMDIParentFrame::Create(wxWindow 
*parent
, 
 116                               const wxString
& title
, 
 120                               const wxString
& name 
) 
 122     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 129 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height 
) 
 131     wxFrame::GtkOnSize( x
, y
, width
, height 
); 
 133     wxMDIChildFrame 
*child_frame 
= GetActiveChild(); 
 134     if (!child_frame
) return; 
 136     wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 137     if (!menu_bar
) return; 
 138     if (!menu_bar
->m_widget
) return; 
 142     menu_bar
->m_width 
= m_width
; 
 143     menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 144     gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 146                           0, 0, m_width
, wxMENU_HEIGHT 
); 
 149 void wxMDIParentFrame::OnInternalIdle() 
 151     /* if a an MDI child window has just been inserted 
 152        it has to be brought to the top in idle time. we 
 153        simply set the last notebook page active as new 
 154        pages can only be appended at the end */ 
 158         GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 159         gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children 
) - 1 ); 
 161         /* need to set the menubar of the child */ 
 162         wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 163         if (active_child_frame 
!= NULL
) 
 165             wxMenuBar 
*menu_bar 
= active_child_frame
->m_menuBar
; 
 168                 menu_bar
->m_width 
= m_width
; 
 169                 menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 170                 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 172                                     0, 0, m_width
, wxMENU_HEIGHT 
); 
 173                 menu_bar
->SetInvokingWindow(active_child_frame
); 
 176         m_justInserted 
= false; 
 180     wxFrame::OnInternalIdle(); 
 182     wxMDIChildFrame 
*active_child_frame 
= GetActiveChild(); 
 183     bool visible_child_menu 
= false; 
 185     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 188         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 192             wxMenuBar 
*menu_bar 
= child_frame
->m_menuBar
; 
 195                 if (child_frame 
== active_child_frame
) 
 197                     if (menu_bar
->Show(true)) 
 199                         menu_bar
->m_width 
= m_width
; 
 200                         menu_bar
->m_height 
= wxMENU_HEIGHT
; 
 201                         gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 203                                             0, 0, m_width
, wxMENU_HEIGHT 
); 
 204                         menu_bar
->SetInvokingWindow( child_frame 
); 
 206                     visible_child_menu 
= true; 
 210                     if (menu_bar
->Show(false)) 
 212                         menu_bar
->UnsetInvokingWindow( child_frame 
); 
 218         node 
= node
->GetNext(); 
 221     /* show/hide parent menu bar as required */ 
 222     if ((m_frameMenuBar
) && 
 223         (m_frameMenuBar
->IsShown() == visible_child_menu
)) 
 225         if (visible_child_menu
) 
 227             m_frameMenuBar
->Show( false ); 
 228             m_frameMenuBar
->UnsetInvokingWindow( this ); 
 232             m_frameMenuBar
->Show( true ); 
 233             m_frameMenuBar
->SetInvokingWindow( this ); 
 235             m_frameMenuBar
->m_width 
= m_width
; 
 236             m_frameMenuBar
->m_height 
= wxMENU_HEIGHT
; 
 237             gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
), 
 238                                 m_frameMenuBar
->m_widget
, 
 239                                 0, 0, m_width
, wxMENU_HEIGHT 
); 
 244 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height 
) const 
 246     wxFrame::DoGetClientSize( width
, height 
); 
 249 wxMDIChildFrame 
*wxMDIParentFrame::GetActiveChild() const 
 251     if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
; 
 253     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(m_clientWindow
->m_widget
); 
 254     if (!notebook
) return (wxMDIChildFrame
*) NULL
; 
 256     gint i 
= gtk_notebook_get_current_page( notebook 
); 
 257     if (i 
< 0) return (wxMDIChildFrame
*) NULL
; 
 259     GtkNotebookPage
* page 
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
); 
 260     if (!page
) return (wxMDIChildFrame
*) NULL
; 
 262     wxWindowList::compatibility_iterator node 
= m_clientWindow
->GetChildren().GetFirst(); 
 265         wxMDIChildFrame 
*child_frame 
= wxDynamicCast( node
->GetData(), wxMDIChildFrame 
); 
 267         wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") ); 
 269         if (child_frame
->m_page 
== page
) 
 271         node 
= node
->GetNext(); 
 274     return (wxMDIChildFrame
*) NULL
; 
 277 wxMDIClientWindow 
*wxMDIParentFrame::GetClientWindow() const 
 279     return m_clientWindow
; 
 282 wxMDIClientWindow 
*wxMDIParentFrame::OnCreateClient() 
 284     m_clientWindow 
= new wxMDIClientWindow( this ); 
 285     return m_clientWindow
; 
 288 void wxMDIParentFrame::ActivateNext() 
 291       gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 294 void wxMDIParentFrame::ActivatePrevious() 
 297       gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) ); 
 300 //----------------------------------------------------------------------------- 
 302 //----------------------------------------------------------------------------- 
 304 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
) 
 306 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
) 
 307     EVT_ACTIVATE(wxMDIChildFrame::OnActivate
) 
 308     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
) 
 311 wxMDIChildFrame::wxMDIChildFrame() 
 313     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 314     m_page 
= (GtkNotebookPage 
*) NULL
; 
 317 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame 
*parent
, 
 318       wxWindowID id
, const wxString
& title
, 
 319       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 320       long style
, const wxString
& name 
) 
 322     m_menuBar 
= (wxMenuBar 
*) NULL
; 
 323     m_page 
= (GtkNotebookPage 
*) NULL
; 
 324     Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name 
); 
 327 wxMDIChildFrame::~wxMDIChildFrame() 
 333 bool wxMDIChildFrame::Create( wxMDIParentFrame 
*parent
, 
 334       wxWindowID id
, const wxString
& title
, 
 335       const wxPoint
& WXUNUSED(pos
), const wxSize
& size
, 
 336       long style
, const wxString
& name 
) 
 340     return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name 
); 
 343 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 345     wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags 
); 
 348 void wxMDIChildFrame::DoSetClientSize(int width
, int height
) 
 350     wxWindow::DoSetClientSize( width
, height 
); 
 353 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height 
) const 
 355     wxWindow::DoGetClientSize( width
, height 
); 
 358 void wxMDIChildFrame::AddChild( wxWindowBase 
*child 
) 
 360     wxWindow::AddChild(child
); 
 363 void wxMDIChildFrame::SetMenuBar( wxMenuBar 
*menu_bar 
) 
 365     wxASSERT_MSG( m_menuBar 
== NULL
, wxT("Only one menubar allowed") ); 
 367     m_menuBar 
= menu_bar
; 
 371         wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 373         m_menuBar
->SetParent( mdi_frame 
); 
 375         /* insert the invisible menu bar into the _parent_ mdi frame */ 
 376         gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
), 
 378                          0, 0,  mdi_frame
->m_width
, wxMENU_HEIGHT 
); 
 382 wxMenuBar 
*wxMDIChildFrame::GetMenuBar() const 
 387 void wxMDIChildFrame::Activate() 
 389     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 390     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 391     gint pageno 
= gtk_notebook_page_num( notebook
, m_widget 
); 
 392     gtk_notebook_set_current_page( notebook
, pageno 
); 
 395 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) ) 
 399 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event 
) 
 402     wxMDIParentFrame 
*mdi_frame 
= (wxMDIParentFrame
*)m_parent
->GetParent(); 
 403     if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) ) 
 405         // we don't have any help text for this item, but may be the MDI frame 
 407         mdi_frame
->OnMenuHighlight(event
); 
 409 #endif // wxUSE_STATUSBAR 
 412 void wxMDIChildFrame::SetTitle( const wxString 
&title 
) 
 414     if ( title 
== m_title 
) 
 419     wxMDIParentFrame
* parent 
= (wxMDIParentFrame
*) GetParent(); 
 420     GtkNotebook
* notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 421     gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title 
) ); 
 424 //----------------------------------------------------------------------------- 
 426 //----------------------------------------------------------------------------- 
 429 static void gtk_page_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow 
*win 
) 
 431     if (g_isIdle
) wxapp_install_idle_handler(); 
 433     if ((win
->m_x 
== alloc
->x
) && 
 434         (win
->m_y 
== alloc
->y
) && 
 435         (win
->m_width 
== alloc
->width
) && 
 436         (win
->m_height 
== alloc
->height
) && 
 442     win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height 
); 
 446 //----------------------------------------------------------------------------- 
 447 // InsertChild callback for wxMDIClientWindow 
 448 //----------------------------------------------------------------------------- 
 450 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child 
) 
 452     wxString s 
= child
->GetTitle(); 
 453     if (s
.IsNull()) s 
= _("MDI child"); 
 455     GtkWidget 
*label_widget 
= gtk_label_new( s
.mbc_str() ); 
 456     gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 ); 
 458     g_signal_connect (child
->m_widget
, "size_allocate", 
 459                       G_CALLBACK (gtk_page_size_callback
), child
); 
 461     GtkNotebook 
*notebook 
= GTK_NOTEBOOK(parent
->m_widget
); 
 463     gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget 
); 
 465     child
->m_page 
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
); 
 467     wxMDIParentFrame 
*parent_frame 
= (wxMDIParentFrame
*) parent
->GetParent(); 
 468     parent_frame
->m_justInserted 
= true; 
 471 //----------------------------------------------------------------------------- 
 473 //----------------------------------------------------------------------------- 
 475 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
) 
 477 wxMDIClientWindow::wxMDIClientWindow() 
 481 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame 
*parent
, long style 
) 
 483     CreateClient( parent
, style 
); 
 486 wxMDIClientWindow::~wxMDIClientWindow() 
 491 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame 
*parent
, long style 
) 
 495     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInMDI
; 
 497     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 498         !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") )) 
 500         wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") ); 
 504     m_widget 
= gtk_notebook_new(); 
 506     g_signal_connect (m_widget
, "switch_page", 
 507                       G_CALLBACK (gtk_mdi_page_change_callback
), parent
); 
 509     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 ); 
 511     m_parent
->DoAddChild( this );