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 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
382 if ( !PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
383 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
,
384 style
, wxDefaultValidator
, "wxMDIClientWindow" ))
386 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
390 m_widget
= gtk_notebook_new();
391 g_object_ref(m_widget
);
393 g_signal_connect (m_widget
, "switch_page",
394 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
396 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
398 m_parent
->DoAddChild( this );
407 void wxMDIClientWindow::AddChildGTK(wxWindowGTK
* child
)
409 wxMDIChildFrame
* child_frame
= static_cast<wxMDIChildFrame
*>(child
);
410 wxString s
= child_frame
->GetTitle();
414 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
415 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
417 GtkNotebook
* notebook
= GTK_NOTEBOOK(m_widget
);
419 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
421 child_frame
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
423 wxMDIParentFrame
* parent_frame
= static_cast<wxMDIParentFrame
*>(GetParent());
424 parent_frame
->m_justInserted
= true;