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
->Attach(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 // Attach() asserts if we call it for an already
153 // attached menu bar so don't do it if we're already
154 // associated with this frame (it would be nice to get
155 // rid of this check and ensure that this doesn't
157 if ( menu_bar
->GetFrame() != child_frame
)
158 menu_bar
->Attach( child_frame
);
160 visible_child_menu
= true;
164 if (menu_bar
->Show(false))
172 node
= node
->GetNext();
175 /* show/hide parent menu bar as required */
176 if ((m_frameMenuBar
) &&
177 (m_frameMenuBar
->IsShown() == visible_child_menu
))
179 if (visible_child_menu
)
181 m_frameMenuBar
->Show( false );
182 m_frameMenuBar
->Detach();
186 m_frameMenuBar
->Show( true );
187 m_frameMenuBar
->Attach( this );
192 void wxMDIParentFrame::DoGetClientSize(int* width
, int* height
) const
194 wxFrame::DoGetClientSize(width
, height
);
198 wxMDIChildFrame
* active_child_frame
= GetActiveChild();
199 if (active_child_frame
)
201 wxMenuBar
* menubar
= active_child_frame
->m_menuBar
;
202 if (menubar
&& menubar
->IsShown())
205 gtk_widget_size_request(menubar
->m_widget
, &req
);
206 *height
-= req
.height
;
207 if (*height
< 0) *height
= 0;
213 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
215 if (!m_clientWindow
) return NULL
;
217 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
218 if (!notebook
) return NULL
;
220 gint i
= gtk_notebook_get_current_page( notebook
);
221 if (i
< 0) return NULL
;
223 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
224 if (!page
) return NULL
;
226 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
229 if ( wxPendingDelete
.Member(node
->GetData()) )
232 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
237 if (child_frame
->m_page
== page
)
240 node
= node
->GetNext();
246 void wxMDIParentFrame::ActivateNext()
249 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
252 void wxMDIParentFrame::ActivatePrevious()
255 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
262 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
264 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
265 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
266 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
269 void wxMDIChildFrame::Init()
275 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
277 const wxString
& title
,
278 const wxPoint
& WXUNUSED(pos
),
281 const wxString
& name
)
283 m_mdiParent
= parent
;
286 return wxWindow::Create(parent
->GetClientWindow(), id
,
287 wxDefaultPosition
, size
,
291 wxMDIChildFrame::~wxMDIChildFrame()
295 // wxMDIClientWindow does not get redrawn properly after last child is removed
296 if (m_parent
&& m_parent
->GetChildren().size() <= 1)
297 gtk_widget_queue_draw(m_parent
->m_widget
);
300 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
302 wxASSERT_MSG( m_menuBar
== NULL
, "Only one menubar allowed" );
304 m_menuBar
= menu_bar
;
308 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
310 m_menuBar
->SetParent( mdi_frame
);
312 /* insert the invisible menu bar into the _parent_ mdi frame */
313 m_menuBar
->Show(false);
314 gtk_box_pack_start(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, false, false, 0);
315 gtk_box_reorder_child(GTK_BOX(mdi_frame
->m_mainWidget
), m_menuBar
->m_widget
, 0);
317 gulong handler_id
= g_signal_handler_find(
319 GSignalMatchType(G_SIGNAL_MATCH_ID
| G_SIGNAL_MATCH_DATA
),
320 g_signal_lookup("size_request", GTK_TYPE_WIDGET
),
321 0, NULL
, NULL
, m_menuBar
);
323 g_signal_handler_disconnect(m_menuBar
->m_widget
, handler_id
);
324 gtk_widget_set_size_request(m_menuBar
->m_widget
, -1, -1);
328 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
333 GtkNotebook
*wxMDIChildFrame::GTKGetNotebook() const
335 wxMDIClientWindow
* const
336 client
= wxStaticCast(GetParent(), wxMDIClientWindow
);
337 wxCHECK( client
, NULL
);
339 return GTK_NOTEBOOK(client
->m_widget
);
342 void wxMDIChildFrame::Activate()
344 GtkNotebook
* const notebook
= GTKGetNotebook();
345 wxCHECK_RET( notebook
, "no parent notebook?" );
347 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
348 gtk_notebook_set_current_page( notebook
, pageno
);
351 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
355 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
358 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
359 if ( !ShowMenuHelp(event
.GetMenuId()) )
361 // we don't have any help text for this item, but may be the MDI frame
363 mdi_frame
->OnMenuHighlight(event
);
365 #endif // wxUSE_STATUSBAR
368 void wxMDIChildFrame::SetTitle( const wxString
&title
)
370 if ( title
== m_title
)
375 GtkNotebook
* const notebook
= GTKGetNotebook();
376 wxCHECK_RET( notebook
, "no parent notebook?" );
377 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
380 //-----------------------------------------------------------------------------
382 //-----------------------------------------------------------------------------
384 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
386 wxMDIClientWindow::~wxMDIClientWindow()
388 // disconnect our handler because our ~wxWindow (which is going to be called
389 // after this dtor) will call DestroyChildren(); in turns our children
390 // ~wxWindow dtors will call wxWindow::Show(false) and this will generate
391 // a call to gtk_mdi_page_change_callback with an invalid parent
392 // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but
393 // at that point of the dtor chain we are a simple wxWindow!)
394 g_signal_handlers_disconnect_by_func(m_widget
,
395 (gpointer
)gtk_mdi_page_change_callback
,
399 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
401 if ( !PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
402 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
,
403 style
, wxDefaultValidator
, "wxMDIClientWindow" ))
405 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
409 m_widget
= gtk_notebook_new();
410 g_object_ref(m_widget
);
412 g_signal_connect (m_widget
, "switch_page",
413 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
415 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
417 m_parent
->DoAddChild( this );
426 void wxMDIClientWindow::AddChildGTK(wxWindowGTK
* child
)
428 wxMDIChildFrame
* child_frame
= static_cast<wxMDIChildFrame
*>(child
);
429 wxString s
= child_frame
->GetTitle();
433 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
434 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
436 GtkNotebook
* notebook
= GTK_NOTEBOOK(m_widget
);
438 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
440 child_frame
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
442 wxMDIParentFrame
* parent_frame
= static_cast<wxMDIParentFrame
*>(GetParent());
443 parent_frame
->m_justInserted
= true;