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"
22 #include "wx/gtk/private.h"
24 //-----------------------------------------------------------------------------
26 //-----------------------------------------------------------------------------
30 switch_page(GtkNotebook
* widget
, GtkNotebookPage
*, guint page_num
, wxMDIParentFrame
* parent
)
32 // send deactivate event to old child
34 wxMDIChildFrame
*child
= parent
->GetActiveChild();
37 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
38 event1
.SetEventObject( child
);
39 child
->HandleWindowEvent( event1
);
42 // send activate event to new child
44 wxMDIClientWindowBase
*client_window
= parent
->GetClientWindow();
49 GtkWidget
* page
= gtk_notebook_get_nth_page(widget
, page_num
);
51 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
54 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
56 // child_frame can be NULL when this is called from dtor, probably
57 // because g_signal_connect (m_widget, "switch_page", (see below)
58 // isn't deleted early enough
59 if (child_frame
&& child_frame
->m_widget
== page
)
64 node
= node
->GetNext();
70 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
71 event2
.SetEventObject( child
);
72 child
->HandleWindowEvent( event2
);
76 //-----------------------------------------------------------------------------
78 //-----------------------------------------------------------------------------
80 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
82 void wxMDIParentFrame::Init()
84 m_justInserted
= false;
87 bool wxMDIParentFrame::Create(wxWindow
*parent
,
89 const wxString
& title
,
93 const wxString
& name
)
95 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
98 m_clientWindow
= OnCreateClient();
99 if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) )
105 void wxMDIParentFrame::OnInternalIdle()
107 /* if a MDI child window has just been inserted
108 it has to be brought to the top in idle time. we
109 simply set the last notebook page active as new
110 pages can only be appended at the end */
114 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
115 gtk_notebook_set_current_page(notebook
, -1);
117 /* need to set the menubar of the child */
118 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
119 if (active_child_frame
!= NULL
)
121 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
124 menu_bar
->Attach(active_child_frame
);
127 m_justInserted
= false;
131 wxFrame::OnInternalIdle();
133 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
134 bool visible_child_menu
= false;
136 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
139 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
143 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
146 if (child_frame
== active_child_frame
)
148 if (menu_bar
->Show(true))
150 // Attach() asserts if we call it for an already
151 // attached menu bar so don't do it if we're already
152 // associated with this frame (it would be nice to get
153 // rid of this check and ensure that this doesn't
155 if ( menu_bar
->GetFrame() != child_frame
)
156 menu_bar
->Attach( child_frame
);
158 visible_child_menu
= true;
162 if (menu_bar
->Show(false))
170 node
= node
->GetNext();
173 /* show/hide parent menu bar as required */
174 if ((m_frameMenuBar
) &&
175 (m_frameMenuBar
->IsShown() == visible_child_menu
))
177 if (visible_child_menu
)
179 m_frameMenuBar
->Show( false );
180 m_frameMenuBar
->Detach();
184 m_frameMenuBar
->Show( true );
185 m_frameMenuBar
->Attach( this );
190 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const
192 wxFrame::DoGetClientSize(width
, height
);
196 wxMDIChildFrame
* active_child_frame
= GetActiveChild();
197 if (active_child_frame
)
199 wxMenuBar
* menubar
= active_child_frame
->m_menuBar
;
200 if (menubar
&& menubar
->IsShown())
203 gtk_widget_size_request(menubar
->m_widget
, &req
);
204 *height
-= req
.height
;
205 if (*height
< 0) *height
= 0;
211 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
213 if (!m_clientWindow
) return NULL
;
215 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
216 if (!notebook
) return NULL
;
218 gint i
= gtk_notebook_get_current_page( notebook
);
219 if (i
< 0) return NULL
;
221 GtkWidget
* page
= gtk_notebook_get_nth_page(notebook
, i
);
222 if (!page
) return NULL
;
224 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
227 if ( wxPendingDelete
.Member(node
->GetData()) )
230 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
235 if (child_frame
->m_widget
== page
)
238 node
= node
->GetNext();
244 void wxMDIParentFrame::ActivateNext()
247 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
250 void wxMDIParentFrame::ActivatePrevious()
253 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
256 //-----------------------------------------------------------------------------
258 //-----------------------------------------------------------------------------
260 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
262 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
263 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
264 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
267 void wxMDIChildFrame::Init()
272 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
274 const wxString
& title
,
275 const wxPoint
& WXUNUSED(pos
),
278 const wxString
& name
)
280 m_mdiParent
= parent
;
283 return wxWindow::Create(parent
->GetClientWindow(), id
,
284 wxDefaultPosition
, size
,
288 wxMDIChildFrame::~wxMDIChildFrame()
292 // wxMDIClientWindow does not get redrawn properly after last child is removed
293 if (m_parent
&& m_parent
->GetChildren().size() <= 1)
294 gtk_widget_queue_draw(m_parent
->m_widget
);
297 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
299 wxASSERT_MSG( m_menuBar
== NULL
, "Only one menubar allowed" );
301 m_menuBar
= menu_bar
;
305 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
307 m_menuBar
->SetParent( mdi_frame
);
309 /* insert the invisible menu bar into the _parent_ mdi frame */
310 m_menuBar
->Show(false);
311 gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0);
312 gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0);
314 gulong handler_id
= g_signal_handler_find(
316 GSignalMatchType(G_SIGNAL_MATCH_ID
| G_SIGNAL_MATCH_DATA
),
317 g_signal_lookup("size_request", GTK_TYPE_WIDGET
),
318 0, NULL
, NULL
, m_menuBar
);
320 g_signal_handler_disconnect(m_menuBar
->m_widget
, handler_id
);
321 gtk_widget_set_size_request(m_menuBar
->m_widget
, -1, -1);
325 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
330 GtkNotebook
*wxMDIChildFrame::GTKGetNotebook() const
332 wxMDIClientWindow
* const
333 client
= wxStaticCast(GetParent(), wxMDIClientWindow
);
334 wxCHECK( client
, NULL
);
336 return GTK_NOTEBOOK(client
->m_widget
);
339 void wxMDIChildFrame::Activate()
341 GtkNotebook
* const notebook
= GTKGetNotebook();
342 wxCHECK_RET( notebook
, "no parent notebook?" );
344 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
345 gtk_notebook_set_current_page( notebook
, pageno
);
348 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
352 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
355 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
356 if ( !ShowMenuHelp(event
.GetMenuId()) )
358 // we don't have any help text for this item, but may be the MDI frame
360 mdi_frame
->OnMenuHighlight(event
);
362 #endif // wxUSE_STATUSBAR
365 void wxMDIChildFrame::SetTitle( const wxString
&title
)
367 if ( title
== m_title
)
372 GtkNotebook
* const notebook
= GTKGetNotebook();
373 wxCHECK_RET( notebook
, "no parent notebook?" );
374 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
377 //-----------------------------------------------------------------------------
379 //-----------------------------------------------------------------------------
381 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
383 wxMDIClientWindow::~wxMDIClientWindow()
385 // disconnect our handler because our ~wxWindow (which is going to be called
386 // after this dtor) will call DestroyChildren(); in turns our children
387 // ~wxWindow dtors will call wxWindow::Show(false) and this will generate
388 // a call to gtk_mdi_page_change_callback with an invalid parent
389 // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but
390 // at that point of the dtor chain we are a simple wxWindow!)
391 g_signal_handlers_disconnect_by_func(m_widget
, (void*)switch_page
, GetParent());
394 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
396 if ( !PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
397 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
,
398 style
, wxDefaultValidator
, "wxMDIClientWindow" ))
400 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
404 m_widget
= gtk_notebook_new();
405 g_object_ref(m_widget
);
407 g_signal_connect(m_widget
, "switch_page", G_CALLBACK(switch_page
), parent
);
409 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
411 m_parent
->DoAddChild( this );
420 void wxMDIClientWindow::AddChildGTK(wxWindowGTK
* child
)
422 wxMDIChildFrame
* child_frame
= static_cast<wxMDIChildFrame
*>(child
);
423 wxString s
= child_frame
->GetTitle();
427 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
428 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
430 GtkNotebook
* notebook
= GTK_NOTEBOOK(m_widget
);
432 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
434 wxMDIParentFrame
* parent_frame
= static_cast<wxMDIParentFrame
*>(GetParent());
435 parent_frame
->m_justInserted
= true;