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 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
31 GtkNotebookPage
*page
,
32 gint
WXUNUSED(page_num
),
33 wxMDIParentFrame
*parent
)
35 // send deactivate event to old child
37 wxMDIChildFrame
*child
= parent
->GetActiveChild();
40 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
41 event1
.SetEventObject( child
);
42 child
->GetEventHandler()->ProcessEvent( event1
);
45 // send activate event to new child
47 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
51 child
= (wxMDIChildFrame
*) NULL
;
53 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
56 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
58 // child_frame can be NULL when this is called from dtor, probably
59 // because g_signal_connect (m_widget, "switch_page", (see below)
60 // isn't deleted early enough
61 if ( child_frame
&& child_frame
->m_page
== page
)
66 node
= node
->GetNext();
72 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
73 event2
.SetEventObject( child
);
74 child
->GetEventHandler()->ProcessEvent( event2
);
78 //-----------------------------------------------------------------------------
80 //-----------------------------------------------------------------------------
82 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
84 void wxMDIParentFrame::Init()
86 m_justInserted
= false;
87 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
90 wxMDIParentFrame::~wxMDIParentFrame()
94 bool wxMDIParentFrame::Create(wxWindow
*parent
,
96 const wxString
& title
,
100 const wxString
& name
)
102 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
109 void wxMDIParentFrame::OnInternalIdle()
111 /* if a an MDI child window has just been inserted
112 it has to be brought to the top in idle time. we
113 simply set the last notebook page active as new
114 pages can only be appended at the end */
118 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
119 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
121 /* need to set the menubar of the child */
122 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
123 if (active_child_frame
!= NULL
)
125 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
128 menu_bar
->SetInvokingWindow(active_child_frame
);
131 m_justInserted
= false;
135 wxFrame::OnInternalIdle();
137 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
138 bool visible_child_menu
= false;
140 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
143 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
147 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
150 if (child_frame
== active_child_frame
)
152 if (menu_bar
->Show(true))
154 menu_bar
->SetInvokingWindow( child_frame
);
156 visible_child_menu
= true;
160 if (menu_bar
->Show(false))
162 menu_bar
->UnsetInvokingWindow( child_frame
);
168 node
= node
->GetNext();
171 /* show/hide parent menu bar as required */
172 if ((m_frameMenuBar
) &&
173 (m_frameMenuBar
->IsShown() == visible_child_menu
))
175 if (visible_child_menu
)
177 m_frameMenuBar
->Show( false );
178 m_frameMenuBar
->UnsetInvokingWindow( this );
182 m_frameMenuBar
->Show( true );
183 m_frameMenuBar
->SetInvokingWindow( this );
188 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const
190 wxFrame::DoGetClientSize(width
, height
);
194 wxMDIChildFrame
* active_child_frame
= GetActiveChild();
195 if (active_child_frame
)
197 wxMenuBar
* menubar
= active_child_frame
->m_menuBar
;
198 if (menubar
&& menubar
->IsShown())
201 gtk_widget_size_request(menubar
->m_widget
, &req
);
202 *height
-= req
.height
;
203 if (*height
< 0) *height
= 0;
209 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
211 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
213 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
214 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
216 gint i
= gtk_notebook_get_current_page( notebook
);
217 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
219 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
220 if (!page
) return (wxMDIChildFrame
*) NULL
;
222 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
225 if ( wxPendingDelete
.Member(node
->GetData()) )
226 return (wxMDIChildFrame
*) NULL
;
228 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
231 return (wxMDIChildFrame
*) NULL
;
233 if (child_frame
->m_page
== page
)
236 node
= node
->GetNext();
239 return (wxMDIChildFrame
*) NULL
;
242 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
244 return m_clientWindow
;
247 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
249 m_clientWindow
= new wxMDIClientWindow( this );
250 return m_clientWindow
;
253 void wxMDIParentFrame::ActivateNext()
256 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
259 void wxMDIParentFrame::ActivatePrevious()
262 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
265 //-----------------------------------------------------------------------------
267 //-----------------------------------------------------------------------------
269 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
271 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
272 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
273 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
276 wxMDIChildFrame::wxMDIChildFrame()
278 m_menuBar
= (wxMenuBar
*) NULL
;
279 m_page
= (GtkNotebookPage
*) NULL
;
282 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
283 wxWindowID id
, const wxString
& title
,
284 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
285 long style
, const wxString
& name
)
287 m_menuBar
= (wxMenuBar
*) NULL
;
288 m_page
= (GtkNotebookPage
*) NULL
;
289 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
292 wxMDIChildFrame::~wxMDIChildFrame()
298 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
299 wxWindowID id
, const wxString
& title
,
300 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
301 long style
, const wxString
& name
)
305 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
308 bool wxMDIChildFrame::Destroy()
310 // delayed destruction: the frame will be deleted during
311 // the next idle loop iteration.
312 // I'm not sure if delayed destruction really makes so
313 // much sense for MDI child frames, actually, but hiding
314 // it doesn't make any sense.
315 if ( !wxPendingDelete
.Member(this) )
316 wxPendingDelete
.Append(this);
321 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
323 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
326 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
328 wxWindow::AddChild(child
);
331 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
333 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
335 m_menuBar
= menu_bar
;
339 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
341 m_menuBar
->SetParent( mdi_frame
);
343 /* insert the invisible menu bar into the _parent_ mdi frame */
344 m_menuBar
->Show(false);
345 gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0);
346 gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0);
348 gulong handler_id
= g_signal_handler_find(
350 GSignalMatchType(G_SIGNAL_MATCH_ID
| G_SIGNAL_MATCH_DATA
),
351 g_signal_lookup("size_request", GTK_TYPE_WIDGET
),
352 0, NULL
, NULL
, m_menuBar
);
354 g_signal_handler_disconnect(m_menuBar
->m_widget
, handler_id
);
355 gtk_widget_set_size_request(m_menuBar
->m_widget
, -1, -1);
359 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
364 void wxMDIChildFrame::Activate()
366 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
367 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
368 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
369 gtk_notebook_set_current_page( notebook
, pageno
);
372 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
376 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
379 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
380 if ( !ShowMenuHelp(event
.GetMenuId()) )
382 // we don't have any help text for this item, but may be the MDI frame
384 mdi_frame
->OnMenuHighlight(event
);
386 #endif // wxUSE_STATUSBAR
389 void wxMDIChildFrame::SetTitle( const wxString
&title
)
391 if ( title
== m_title
)
396 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
397 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
398 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
401 //-----------------------------------------------------------------------------
402 // InsertChild callback for wxMDIClientWindow
403 //-----------------------------------------------------------------------------
405 static void wxInsertChildInMDI(wxWindow
* parent
, wxWindow
* child
)
407 wxMDIChildFrame
* child_frame
= wx_static_cast(wxMDIChildFrame
*, child
);
408 wxString s
= child_frame
->GetTitle();
409 if (s
.IsNull()) s
= _("MDI child");
411 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
412 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
414 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
416 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
418 child_frame
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
420 wxMDIParentFrame
*parent_frame
= wx_static_cast(wxMDIParentFrame
*, parent
->GetParent());
421 parent_frame
->m_justInserted
= true;
424 //-----------------------------------------------------------------------------
426 //-----------------------------------------------------------------------------
428 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
430 wxMDIClientWindow::wxMDIClientWindow()
434 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
436 CreateClient( parent
, style
);
439 wxMDIClientWindow::~wxMDIClientWindow()
444 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
446 m_insertCallback
= wxInsertChildInMDI
;
448 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
449 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
451 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
455 m_widget
= gtk_notebook_new();
457 g_signal_connect (m_widget
, "switch_page",
458 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
460 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
462 m_parent
->DoAddChild( this );