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
->HandleWindowEvent( 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
->HandleWindowEvent( 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 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
105 m_clientWindow
= OnCreateClient();
107 return m_clientWindow
!= NULL
;
110 void wxMDIParentFrame::OnInternalIdle()
112 /* if a an MDI child window has just been inserted
113 it has to be brought to the top in idle time. we
114 simply set the last notebook page active as new
115 pages can only be appended at the end */
119 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
120 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
122 /* need to set the menubar of the child */
123 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
124 if (active_child_frame
!= NULL
)
126 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
129 menu_bar
->SetInvokingWindow(active_child_frame
);
132 m_justInserted
= false;
136 wxFrame::OnInternalIdle();
138 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
139 bool visible_child_menu
= false;
141 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
144 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
148 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
151 if (child_frame
== active_child_frame
)
153 if (menu_bar
->Show(true))
155 menu_bar
->SetInvokingWindow( child_frame
);
157 visible_child_menu
= true;
161 if (menu_bar
->Show(false))
163 menu_bar
->UnsetInvokingWindow( child_frame
);
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
->UnsetInvokingWindow( this );
183 m_frameMenuBar
->Show( true );
184 m_frameMenuBar
->SetInvokingWindow( this );
189 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const
191 wxFrame::DoGetClientSize(width
, 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_size_request(menubar
->m_widget
, &req
);
203 *height
-= req
.height
;
204 if (*height
< 0) *height
= 0;
210 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
212 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
214 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
215 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
217 gint i
= gtk_notebook_get_current_page( notebook
);
218 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
220 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
221 if (!page
) return (wxMDIChildFrame
*) NULL
;
223 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
226 if ( wxPendingDelete
.Member(node
->GetData()) )
227 return (wxMDIChildFrame
*) NULL
;
229 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
232 return (wxMDIChildFrame
*) NULL
;
234 if (child_frame
->m_page
== page
)
237 node
= node
->GetNext();
240 return (wxMDIChildFrame
*) NULL
;
243 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
245 return m_clientWindow
;
248 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
250 return new wxMDIClientWindow( this );
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()
297 // wxMDIClientWindow does not get redrawn properly after last child is removed
298 if (m_parent
&& m_parent
->GetChildren().size() <= 1)
299 gtk_widget_queue_draw(m_parent
->m_widget
);
302 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
303 wxWindowID id
, const wxString
& title
,
304 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
305 long style
, const wxString
& name
)
309 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
312 bool wxMDIChildFrame::Destroy()
314 // delayed destruction: the frame will be deleted during
315 // the next idle loop iteration.
316 // I'm not sure if delayed destruction really makes so
317 // much sense for MDI child frames, actually, but hiding
318 // it doesn't make any sense.
319 if ( !wxPendingDelete
.Member(this) )
320 wxPendingDelete
.Append(this);
325 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
327 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
330 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
332 wxWindow::AddChild(child
);
335 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
337 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
339 m_menuBar
= menu_bar
;
343 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
345 m_menuBar
->SetParent( mdi_frame
);
347 /* insert the invisible menu bar into the _parent_ mdi frame */
348 m_menuBar
->Show(false);
349 gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0);
350 gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0);
352 gulong handler_id
= g_signal_handler_find(
354 GSignalMatchType(G_SIGNAL_MATCH_ID
| G_SIGNAL_MATCH_DATA
),
355 g_signal_lookup("size_request", GTK_TYPE_WIDGET
),
356 0, NULL
, NULL
, m_menuBar
);
358 g_signal_handler_disconnect(m_menuBar
->m_widget
, handler_id
);
359 gtk_widget_set_size_request(m_menuBar
->m_widget
, -1, -1);
363 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
368 void wxMDIChildFrame::Activate()
370 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
371 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
372 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
373 gtk_notebook_set_current_page( notebook
, pageno
);
376 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
380 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
383 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
384 if ( !ShowMenuHelp(event
.GetMenuId()) )
386 // we don't have any help text for this item, but may be the MDI frame
388 mdi_frame
->OnMenuHighlight(event
);
390 #endif // wxUSE_STATUSBAR
393 void wxMDIChildFrame::SetTitle( const wxString
&title
)
395 if ( title
== m_title
)
400 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
401 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
402 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
405 //-----------------------------------------------------------------------------
406 // InsertChild callback for wxMDIClientWindow
407 //-----------------------------------------------------------------------------
409 static void wxInsertChildInMDI(wxWindow
* parent
, wxWindow
* child
)
411 wxMDIChildFrame
* child_frame
= wx_static_cast(wxMDIChildFrame
*, child
);
412 wxString s
= child_frame
->GetTitle();
413 if (s
.IsNull()) s
= _("MDI child");
415 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
416 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
418 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
420 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
422 child_frame
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
424 wxMDIParentFrame
*parent_frame
= wx_static_cast(wxMDIParentFrame
*, parent
->GetParent());
425 parent_frame
->m_justInserted
= true;
428 //-----------------------------------------------------------------------------
430 //-----------------------------------------------------------------------------
432 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
434 wxMDIClientWindow::wxMDIClientWindow()
438 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
440 CreateClient( parent
, style
);
443 wxMDIClientWindow::~wxMDIClientWindow()
448 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
450 m_insertCallback
= wxInsertChildInMDI
;
452 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
453 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
455 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
459 m_widget
= gtk_notebook_new();
461 g_signal_connect (m_widget
, "switch_page",
462 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
464 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
466 m_parent
->DoAddChild( this );