1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/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"
20 #include "wx/dialog.h"
23 #include "wx/notebook.h"
24 #include "wx/gtk1/private.h"
29 #include "wx/gtk1/win_gtk.h"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
35 const int wxMENU_HEIGHT
= 27;
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 extern void wxapp_install_idle_handler();
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------
54 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
55 GtkNotebookPage
*page
,
56 gint
WXUNUSED(page_num
),
57 wxMDIParentFrame
*parent
)
60 wxapp_install_idle_handler();
62 // send deactivate event to old child
64 wxMDIChildFrame
*child
= parent
->GetActiveChild();
67 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
68 event1
.SetEventObject( child
);
69 child
->HandleWindowEvent( event1
);
72 // send activate event to new child
74 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
78 child
= (wxMDIChildFrame
*) NULL
;
80 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
83 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
84 // CE: we come here in the destructor with a null child_frame - I think because
85 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
86 // isn't deleted early enough
90 if (child_frame
->m_page
== page
)
95 node
= node
->GetNext();
101 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
102 event2
.SetEventObject( child
);
103 child
->HandleWindowEvent( event2
);
107 //-----------------------------------------------------------------------------
109 //-----------------------------------------------------------------------------
111 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
113 void wxMDIParentFrame::Init()
115 m_justInserted
= false;
116 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
119 wxMDIParentFrame::~wxMDIParentFrame()
123 bool wxMDIParentFrame::Create(wxWindow
*parent
,
125 const wxString
& title
,
129 const wxString
& name
)
131 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
134 m_clientWindow
= OnCreateClient();
136 return m_clientWindow
!= NULL
;
139 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
141 wxFrame::GtkOnSize( x
, y
, width
, height
);
143 wxMDIChildFrame
*child_frame
= GetActiveChild();
144 if (!child_frame
) return;
146 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
147 if (!menu_bar
) return;
148 if (!menu_bar
->m_widget
) return;
152 menu_bar
->m_width
= m_width
;
153 menu_bar
->m_height
= wxMENU_HEIGHT
;
154 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
156 0, 0, m_width
, wxMENU_HEIGHT
);
159 void wxMDIParentFrame::OnInternalIdle()
161 /* if a an MDI child window has just been inserted
162 it has to be brought to the top in idle time. we
163 simply set the last notebook page active as new
164 pages can only be appended at the end */
168 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
169 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
171 /* need to set the menubar of the child */
172 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
173 if (active_child_frame
!= NULL
)
175 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
178 menu_bar
->m_width
= m_width
;
179 menu_bar
->m_height
= wxMENU_HEIGHT
;
180 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
182 0, 0, m_width
, wxMENU_HEIGHT
);
183 menu_bar
->SetInvokingWindow(active_child_frame
);
186 m_justInserted
= false;
190 wxFrame::OnInternalIdle();
192 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
193 bool visible_child_menu
= false;
195 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
198 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
202 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
205 if (child_frame
== active_child_frame
)
207 if (menu_bar
->Show(true))
209 menu_bar
->m_width
= m_width
;
210 menu_bar
->m_height
= wxMENU_HEIGHT
;
211 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
213 0, 0, m_width
, wxMENU_HEIGHT
);
214 menu_bar
->SetInvokingWindow( child_frame
);
216 visible_child_menu
= true;
220 if (menu_bar
->Show(false))
222 menu_bar
->UnsetInvokingWindow( child_frame
);
228 node
= node
->GetNext();
231 /* show/hide parent menu bar as required */
232 if ((m_frameMenuBar
) &&
233 (m_frameMenuBar
->IsShown() == visible_child_menu
))
235 if (visible_child_menu
)
237 m_frameMenuBar
->Show( false );
238 m_frameMenuBar
->UnsetInvokingWindow( this );
242 m_frameMenuBar
->Show( true );
243 m_frameMenuBar
->SetInvokingWindow( this );
245 m_frameMenuBar
->m_width
= m_width
;
246 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
247 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
248 m_frameMenuBar
->m_widget
,
249 0, 0, m_width
, wxMENU_HEIGHT
);
254 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
256 wxFrame::DoGetClientSize( width
, height
);
259 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
261 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
263 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
264 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
266 gint i
= gtk_notebook_get_current_page( notebook
);
267 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
269 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
270 if (!page
) return (wxMDIChildFrame
*) NULL
;
272 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
275 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
277 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
279 if (child_frame
->m_page
== page
)
281 node
= node
->GetNext();
284 return (wxMDIChildFrame
*) NULL
;
287 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
289 return m_clientWindow
;
292 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
294 return new wxMDIClientWindow( this );
297 void wxMDIParentFrame::ActivateNext()
300 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
303 void wxMDIParentFrame::ActivatePrevious()
306 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
309 //-----------------------------------------------------------------------------
311 //-----------------------------------------------------------------------------
313 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
315 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
316 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
317 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
320 wxMDIChildFrame::wxMDIChildFrame()
322 m_menuBar
= (wxMenuBar
*) NULL
;
323 m_page
= (GtkNotebookPage
*) NULL
;
326 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
327 wxWindowID id
, const wxString
& title
,
328 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
329 long style
, const wxString
& name
)
331 m_menuBar
= (wxMenuBar
*) NULL
;
332 m_page
= (GtkNotebookPage
*) NULL
;
333 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
336 wxMDIChildFrame::~wxMDIChildFrame()
342 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
343 wxWindowID id
, const wxString
& title
,
344 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
345 long style
, const wxString
& name
)
349 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
352 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
354 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
357 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
359 wxWindow::DoSetClientSize( width
, height
);
362 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
364 wxWindow::DoGetClientSize( width
, height
);
367 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
369 wxWindow::AddChild(child
);
372 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
374 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
376 m_menuBar
= menu_bar
;
380 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
382 m_menuBar
->SetParent( mdi_frame
);
384 /* insert the invisible menu bar into the _parent_ mdi frame */
385 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
387 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
391 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
396 void wxMDIChildFrame::Activate()
398 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
399 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
400 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
401 gtk_notebook_set_page( notebook
, pageno
);
404 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
408 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
411 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
412 if ( !ShowMenuHelp(event
.GetMenuId()) )
414 // we don't have any help text for this item, but may be the MDI frame
416 mdi_frame
->OnMenuHighlight(event
);
418 #endif // wxUSE_STATUSBAR
421 void wxMDIChildFrame::SetTitle( const wxString
&title
)
423 if ( title
== m_title
)
428 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
429 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
430 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
433 //-----------------------------------------------------------------------------
435 //-----------------------------------------------------------------------------
438 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
440 if (g_isIdle
) wxapp_install_idle_handler();
442 if ((win
->m_x
== alloc
->x
) &&
443 (win
->m_y
== alloc
->y
) &&
444 (win
->m_width
== alloc
->width
) &&
445 (win
->m_height
== alloc
->height
) &&
451 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
455 //-----------------------------------------------------------------------------
456 // InsertChild callback for wxMDIClientWindow
457 //-----------------------------------------------------------------------------
459 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
461 wxString s
= child
->GetTitle();
462 if (s
.IsNull()) s
= _("MDI child");
464 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
465 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
467 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
468 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
470 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
472 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
474 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
476 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
477 parent_frame
->m_justInserted
= true;
480 //-----------------------------------------------------------------------------
482 //-----------------------------------------------------------------------------
484 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
486 wxMDIClientWindow::wxMDIClientWindow()
490 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
492 CreateClient( parent
, style
);
495 wxMDIClientWindow::~wxMDIClientWindow()
500 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
504 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
506 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
507 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
509 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
513 m_widget
= gtk_notebook_new();
515 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
516 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
518 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
520 m_parent
->DoAddChild( this );