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 wxMDIClientWindowBase
*client_window
= parent
->GetClientWindow();
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;
89 bool wxMDIParentFrame::Create(wxWindow
*parent
,
91 const wxString
& title
,
95 const wxString
& name
)
97 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
100 m_clientWindow
= OnCreateClient();
101 if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) )
107 void wxMDIParentFrame::OnInternalIdle()
109 /* if a MDI child window has just been inserted
110 it has to be brought to the top in idle time. we
111 simply set the last notebook page active as new
112 pages can only be appended at the end */
116 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
117 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
119 /* need to set the menubar of the child */
120 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
121 if (active_child_frame
!= NULL
)
123 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
126 menu_bar
->SetInvokingWindow(active_child_frame
);
129 m_justInserted
= false;
133 wxFrame::OnInternalIdle();
135 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
136 bool visible_child_menu
= false;
138 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
141 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
145 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
148 if (child_frame
== active_child_frame
)
150 if (menu_bar
->Show(true))
152 menu_bar
->SetInvokingWindow( child_frame
);
154 visible_child_menu
= true;
158 if (menu_bar
->Show(false))
160 menu_bar
->UnsetInvokingWindow( child_frame
);
166 node
= node
->GetNext();
169 /* show/hide parent menu bar as required */
170 if ((m_frameMenuBar
) &&
171 (m_frameMenuBar
->IsShown() == visible_child_menu
))
173 if (visible_child_menu
)
175 m_frameMenuBar
->Show( false );
176 m_frameMenuBar
->UnsetInvokingWindow( this );
180 m_frameMenuBar
->Show( true );
181 m_frameMenuBar
->SetInvokingWindow( this );
186 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const
188 wxFrame::DoGetClientSize(width
, height
);
192 wxMDIChildFrame
* active_child_frame
= GetActiveChild();
193 if (active_child_frame
)
195 wxMenuBar
* menubar
= active_child_frame
->m_menuBar
;
196 if (menubar
&& menubar
->IsShown())
199 gtk_widget_size_request(menubar
->m_widget
, &req
);
200 *height
-= req
.height
;
201 if (*height
< 0) *height
= 0;
207 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
209 if (!m_clientWindow
) return NULL
;
211 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
212 if (!notebook
) return NULL
;
214 gint i
= gtk_notebook_get_current_page( notebook
);
215 if (i
< 0) return NULL
;
217 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
218 if (!page
) return NULL
;
220 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
223 if ( wxPendingDelete
.Member(node
->GetData()) )
226 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
231 if (child_frame
->m_page
== page
)
234 node
= node
->GetNext();
240 void wxMDIParentFrame::ActivateNext()
243 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
246 void wxMDIParentFrame::ActivatePrevious()
249 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
252 //-----------------------------------------------------------------------------
254 //-----------------------------------------------------------------------------
256 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
258 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
259 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
260 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
263 void wxMDIChildFrame::Init()
269 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
271 const wxString
& title
,
272 const wxPoint
& WXUNUSED(pos
),
275 const wxString
& name
)
277 m_mdiParent
= parent
;
280 return wxWindow::Create(parent
->GetClientWindow(), id
,
281 wxDefaultPosition
, size
,
285 wxMDIChildFrame::~wxMDIChildFrame()
289 // wxMDIClientWindow does not get redrawn properly after last child is removed
290 if (m_parent
&& m_parent
->GetChildren().size() <= 1)
291 gtk_widget_queue_draw(m_parent
->m_widget
);
294 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
296 wxASSERT_MSG( m_menuBar
== NULL
, "Only one menubar allowed" );
298 m_menuBar
= menu_bar
;
302 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
304 m_menuBar
->SetParent( mdi_frame
);
306 /* insert the invisible menu bar into the _parent_ mdi frame */
307 m_menuBar
->Show(false);
308 gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0);
309 gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0);
311 gulong handler_id
= g_signal_handler_find(
313 GSignalMatchType(G_SIGNAL_MATCH_ID
| G_SIGNAL_MATCH_DATA
),
314 g_signal_lookup("size_request", GTK_TYPE_WIDGET
),
315 0, NULL
, NULL
, m_menuBar
);
317 g_signal_handler_disconnect(m_menuBar
->m_widget
, handler_id
);
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
,
389 (gpointer
)gtk_mdi_page_change_callback
,
393 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
395 if ( !PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
396 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
,
397 style
, wxDefaultValidator
, "wxMDIClientWindow" ))
399 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
403 m_widget
= gtk_notebook_new();
404 g_object_ref(m_widget
);
406 g_signal_connect (m_widget
, "switch_page",
407 G_CALLBACK (gtk_mdi_page_change_callback
), 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 child_frame
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
436 wxMDIParentFrame
* parent_frame
= static_cast<wxMDIParentFrame
*>(GetParent());
437 parent_frame
->m_justInserted
= true;