1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/mdi.cpp
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
21 #include "wx/gtk/private.h"
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
29 switch_page(GtkNotebook
* widget
, GtkNotebookPage
*, guint page_num
, wxMDIParentFrame
* parent
)
31 // send deactivate event to old child
33 wxMDIChildFrame
*child
= parent
->GetActiveChild();
36 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
37 event1
.SetEventObject( child
);
38 child
->HandleWindowEvent( event1
);
41 // send activate event to new child
43 wxMDIClientWindowBase
*client_window
= parent
->GetClientWindow();
48 GtkWidget
* page
= gtk_notebook_get_nth_page(widget
, page_num
);
50 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
53 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
55 // child_frame can be NULL when this is called from dtor, probably
56 // because g_signal_connect (m_widget, "switch_page", (see below)
57 // isn't deleted early enough
58 if (child_frame
&& child_frame
->m_widget
== page
)
63 node
= node
->GetNext();
69 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
70 event2
.SetEventObject( child
);
71 child
->HandleWindowEvent( event2
);
75 //-----------------------------------------------------------------------------
77 //-----------------------------------------------------------------------------
79 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
81 void wxMDIParentFrame::Init()
83 m_justInserted
= false;
86 bool wxMDIParentFrame::Create(wxWindow
*parent
,
88 const wxString
& title
,
92 const wxString
& name
)
94 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
97 m_clientWindow
= OnCreateClient();
98 if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) )
104 void wxMDIParentFrame::OnInternalIdle()
106 /* if a MDI child window has just been inserted
107 it has to be brought to the top in idle time. we
108 simply set the last notebook page active as new
109 pages can only be appended at the end */
113 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
114 gtk_notebook_set_current_page(notebook
, -1);
116 /* need to set the menubar of the child */
117 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
118 if (active_child_frame
!= NULL
)
120 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
123 menu_bar
->Attach(active_child_frame
);
126 m_justInserted
= false;
130 wxFrame::OnInternalIdle();
132 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
133 bool visible_child_menu
= false;
135 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
138 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
142 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
145 if (child_frame
== active_child_frame
)
147 if (menu_bar
->Show(true))
149 // Attach() asserts if we call it for an already
150 // attached menu bar so don't do it if we're already
151 // associated with this frame (it would be nice to get
152 // rid of this check and ensure that this doesn't
154 if ( menu_bar
->GetFrame() != child_frame
)
155 menu_bar
->Attach( child_frame
);
157 visible_child_menu
= true;
161 if (menu_bar
->Show(false))
169 node
= node
->GetNext();
172 /* show/hide parent menu bar as required */
173 if ((m_frameMenuBar
) &&
174 (m_frameMenuBar
->IsShown() == visible_child_menu
))
176 if (visible_child_menu
)
178 m_frameMenuBar
->Show( false );
179 m_frameMenuBar
->Detach();
183 m_frameMenuBar
->Show( true );
184 m_frameMenuBar
->Attach( this );
189 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const
191 wxFrame::DoGetClientSize(width
, height
);
193 if (!m_useCachedClientSize
&& height
)
195 wxMDIChildFrame
* active_child_frame
= GetActiveChild();
196 if (active_child_frame
)
198 wxMenuBar
* menubar
= active_child_frame
->m_menuBar
;
199 if (menubar
&& menubar
->IsShown())
202 gtk_widget_get_preferred_height(menubar
->m_widget
, NULL
, &req
.height
);
203 *height
-= req
.height
;
204 if (*height
< 0) *height
= 0;
210 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
212 if (!m_clientWindow
) return NULL
;
214 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
215 if (!notebook
) return NULL
;
217 gint i
= gtk_notebook_get_current_page( notebook
);
218 if (i
< 0) return NULL
;
220 GtkWidget
* page
= gtk_notebook_get_nth_page(notebook
, i
);
221 if (!page
) return NULL
;
223 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
226 if ( wxPendingDelete
.Member(node
->GetData()) )
229 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
234 if (child_frame
->m_widget
== page
)
237 node
= node
->GetNext();
243 void wxMDIParentFrame::ActivateNext()
246 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
249 void wxMDIParentFrame::ActivatePrevious()
252 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
255 //-----------------------------------------------------------------------------
257 //-----------------------------------------------------------------------------
259 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
261 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
262 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
263 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
266 void wxMDIChildFrame::Init()
271 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
273 const wxString
& title
,
274 const wxPoint
& WXUNUSED(pos
),
277 const wxString
& name
)
279 m_mdiParent
= parent
;
282 return wxWindow::Create(parent
->GetClientWindow(), id
,
283 wxDefaultPosition
, size
,
287 wxMDIChildFrame::~wxMDIChildFrame()
291 // wxMDIClientWindow does not get redrawn properly after last child is removed
292 if (m_parent
&& m_parent
->GetChildren().size() <= 1)
293 gtk_widget_queue_draw(m_parent
->m_widget
);
296 void wxMDIChildFrame::GTKHandleRealized()
298 // since m_widget is not a GtkWindow, must bypass wxTopLevelWindowGTK
299 wxTopLevelWindowBase::GTKHandleRealized();
302 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
304 wxASSERT_MSG( m_menuBar
== NULL
, "Only one menubar allowed" );
306 m_menuBar
= menu_bar
;
310 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
312 m_menuBar
->SetParent( mdi_frame
);
314 /* insert the invisible menu bar into the _parent_ mdi frame */
315 m_menuBar
->Show(false);
316 gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0);
317 gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0);
318 gtk_widget_set_size_request(m_menuBar
->m_widget
, -1, -1);
322 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
327 GtkNotebook
*wxMDIChildFrame::GTKGetNotebook() const
329 wxMDIClientWindow
* const
330 client
= wxStaticCast(GetParent(), wxMDIClientWindow
);
331 wxCHECK( client
, NULL
);
333 return GTK_NOTEBOOK(client
->m_widget
);
336 void wxMDIChildFrame::Activate()
338 GtkNotebook
* const notebook
= GTKGetNotebook();
339 wxCHECK_RET( notebook
, "no parent notebook?" );
341 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
342 gtk_notebook_set_current_page( notebook
, pageno
);
345 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
349 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
352 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
353 if ( !ShowMenuHelp(event
.GetMenuId()) )
355 // we don't have any help text for this item, but may be the MDI frame
357 mdi_frame
->OnMenuHighlight(event
);
359 #endif // wxUSE_STATUSBAR
362 void wxMDIChildFrame::SetTitle( const wxString
&title
)
364 if ( title
== m_title
)
369 GtkNotebook
* const notebook
= GTKGetNotebook();
370 wxCHECK_RET( notebook
, "no parent notebook?" );
371 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
374 //-----------------------------------------------------------------------------
376 //-----------------------------------------------------------------------------
378 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
380 wxMDIClientWindow::~wxMDIClientWindow()
382 // disconnect our handler because our ~wxWindow (which is going to be called
383 // after this dtor) will call DestroyChildren(); in turns our children
384 // ~wxWindow dtors will call wxWindow::Show(false) and this will generate
385 // a call to gtk_mdi_page_change_callback with an invalid parent
386 // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but
387 // at that point of the dtor chain we are a simple wxWindow!)
388 g_signal_handlers_disconnect_by_func(m_widget
, (void*)switch_page
, GetParent());
391 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
393 if ( !PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
394 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
,
395 style
, wxDefaultValidator
, "wxMDIClientWindow" ))
397 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
401 m_widget
= gtk_notebook_new();
402 g_object_ref(m_widget
);
404 g_signal_connect(m_widget
, "switch_page", G_CALLBACK(switch_page
), parent
);
406 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
408 m_parent
->DoAddChild( this );
417 void wxMDIClientWindow::AddChildGTK(wxWindowGTK
* child
)
419 wxMDIChildFrame
* child_frame
= static_cast<wxMDIChildFrame
*>(child
);
420 wxString s
= child_frame
->GetTitle();
424 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
425 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
427 GtkNotebook
* notebook
= GTK_NOTEBOOK(m_widget
);
429 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
431 wxMDIParentFrame
* parent_frame
= static_cast<wxMDIParentFrame
*>(GetParent());
432 parent_frame
->m_justInserted
= true;