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"
20 #include "wx/dialog.h"
23 #include "wx/notebook.h"
24 #include "wx/gtk/private.h"
27 #include "wx/gtk/win_gtk.h"
29 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
33 const int wxMENU_HEIGHT
= 27;
35 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 //-----------------------------------------------------------------------------
45 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
46 GtkNotebookPage
*page
,
47 gint
WXUNUSED(page_num
),
48 wxMDIParentFrame
*parent
)
50 // send deactivate event to old child
52 wxMDIChildFrame
*child
= parent
->GetActiveChild();
55 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
56 event1
.SetEventObject( child
);
57 child
->GetEventHandler()->ProcessEvent( event1
);
60 // send activate event to new child
62 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
66 child
= (wxMDIChildFrame
*) NULL
;
68 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
71 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
73 // child_frame can be NULL when this is called from dtor, probably
74 // because g_signal_connect (m_widget, "switch_page", (see below)
75 // isn't deleted early enough
76 if ( child_frame
&& child_frame
->m_page
== page
)
81 node
= node
->GetNext();
87 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
88 event2
.SetEventObject( child
);
89 child
->GetEventHandler()->ProcessEvent( event2
);
93 //-----------------------------------------------------------------------------
95 //-----------------------------------------------------------------------------
97 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
99 void wxMDIParentFrame::Init()
101 m_justInserted
= false;
102 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
105 wxMDIParentFrame::~wxMDIParentFrame()
109 bool wxMDIParentFrame::Create(wxWindow
*parent
,
111 const wxString
& title
,
115 const wxString
& name
)
117 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
124 void wxMDIParentFrame::GtkOnSize()
126 wxFrame::GtkOnSize();
128 wxMDIChildFrame
*child_frame
= GetActiveChild();
129 if (!child_frame
) return;
131 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
132 if (!menu_bar
) return;
133 if (!menu_bar
->m_widget
) return;
137 GTKDoGetSize(&menu_bar
->m_width
, NULL
);
138 menu_bar
->m_height
= wxMENU_HEIGHT
;
139 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
141 0, 0, menu_bar
->m_width
, menu_bar
->m_height
);
144 void wxMDIParentFrame::OnInternalIdle()
146 /* if a an MDI child window has just been inserted
147 it has to be brought to the top in idle time. we
148 simply set the last notebook page active as new
149 pages can only be appended at the end */
153 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
154 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
156 /* need to set the menubar of the child */
157 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
158 if (active_child_frame
!= NULL
)
160 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
163 GTKDoGetSize(&menu_bar
->m_width
, NULL
);
164 menu_bar
->m_height
= wxMENU_HEIGHT
;
165 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
167 0, 0, menu_bar
->m_width
, menu_bar
->m_height
);
168 menu_bar
->SetInvokingWindow(active_child_frame
);
171 m_justInserted
= false;
175 wxFrame::OnInternalIdle();
177 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
178 bool visible_child_menu
= false;
180 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
183 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
187 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
190 if (child_frame
== active_child_frame
)
192 if (menu_bar
->Show(true))
194 GTKDoGetSize(&menu_bar
->m_width
, NULL
);
195 menu_bar
->m_height
= wxMENU_HEIGHT
;
196 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
198 0, 0, menu_bar
->m_width
, menu_bar
->m_height
);
199 menu_bar
->SetInvokingWindow( child_frame
);
201 visible_child_menu
= true;
205 if (menu_bar
->Show(false))
207 menu_bar
->UnsetInvokingWindow( child_frame
);
213 node
= node
->GetNext();
216 /* show/hide parent menu bar as required */
217 if ((m_frameMenuBar
) &&
218 (m_frameMenuBar
->IsShown() == visible_child_menu
))
220 if (visible_child_menu
)
222 m_frameMenuBar
->Show( false );
223 m_frameMenuBar
->UnsetInvokingWindow( this );
227 m_frameMenuBar
->Show( true );
228 m_frameMenuBar
->SetInvokingWindow( this );
230 GTKDoGetSize(&m_frameMenuBar
->m_width
, NULL
);
231 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
232 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
233 m_frameMenuBar
->m_widget
,
234 0, 0, m_frameMenuBar
->m_width
, m_frameMenuBar
->m_height
);
239 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
241 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
243 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
244 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
246 gint i
= gtk_notebook_get_current_page( notebook
);
247 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
249 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
250 if (!page
) return (wxMDIChildFrame
*) NULL
;
252 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
255 if ( wxPendingDelete
.Member(node
->GetData()) )
256 return (wxMDIChildFrame
*) NULL
;
258 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
261 return (wxMDIChildFrame
*) NULL
;
263 if (child_frame
->m_page
== page
)
266 node
= node
->GetNext();
269 return (wxMDIChildFrame
*) NULL
;
272 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
274 return m_clientWindow
;
277 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
279 m_clientWindow
= new wxMDIClientWindow( this );
280 return m_clientWindow
;
283 void wxMDIParentFrame::ActivateNext()
286 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
289 void wxMDIParentFrame::ActivatePrevious()
292 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
295 bool wxMDIParentFrame::HasVisibleMenubar() const
297 if (wxFrame::HasVisibleMenubar())
300 wxMDIChildFrame
* active_child_frame
= GetActiveChild();
301 wxMenuBar
* menubar
= NULL
;
302 if (active_child_frame
)
303 menubar
= active_child_frame
->m_menuBar
;
304 return menubar
&& menubar
->IsShown();
307 //-----------------------------------------------------------------------------
309 //-----------------------------------------------------------------------------
311 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
313 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
314 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
315 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
318 wxMDIChildFrame::wxMDIChildFrame()
320 m_menuBar
= (wxMenuBar
*) NULL
;
321 m_page
= (GtkNotebookPage
*) NULL
;
324 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
325 wxWindowID id
, const wxString
& title
,
326 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
327 long style
, const wxString
& name
)
329 m_menuBar
= (wxMenuBar
*) NULL
;
330 m_page
= (GtkNotebookPage
*) NULL
;
331 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
334 wxMDIChildFrame::~wxMDIChildFrame()
340 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
341 wxWindowID id
, const wxString
& title
,
342 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
343 long style
, const wxString
& name
)
347 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
350 bool wxMDIChildFrame::Destroy()
352 // delayed destruction: the frame will be deleted during
353 // the next idle loop iteration.
354 // I'm not sure if delayed destruction really makes so
355 // much sense for MDI child frames, actually, but hiding
356 // it doesn't make any sense.
357 if ( !wxPendingDelete
.Member(this) )
358 wxPendingDelete
.Append(this);
363 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
365 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
368 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
370 wxWindow::AddChild(child
);
373 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
375 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
377 m_menuBar
= menu_bar
;
381 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
383 m_menuBar
->SetParent( mdi_frame
);
385 /* insert the invisible menu bar into the _parent_ mdi frame */
387 mdi_frame
->GTKDoGetSize(&w
, NULL
);
388 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
390 0, 0, w
, wxMENU_HEIGHT
);
394 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
399 void wxMDIChildFrame::Activate()
401 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
402 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
403 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
404 gtk_notebook_set_current_page( notebook
, pageno
);
407 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
411 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
414 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
415 if ( !ShowMenuHelp(event
.GetMenuId()) )
417 // we don't have any help text for this item, but may be the MDI frame
419 mdi_frame
->OnMenuHighlight(event
);
421 #endif // wxUSE_STATUSBAR
424 void wxMDIChildFrame::SetTitle( const wxString
&title
)
426 if ( title
== m_title
)
431 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
432 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
433 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
436 //-----------------------------------------------------------------------------
438 //-----------------------------------------------------------------------------
441 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxMDIChildFrame
*win
)
443 if ((win
->m_x
== alloc
->x
) &&
444 (win
->m_y
== alloc
->y
) &&
445 (win
->m_width
== alloc
->width
) &&
446 (win
->m_height
== alloc
->height
) &&
452 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
456 //-----------------------------------------------------------------------------
457 // InsertChild callback for wxMDIClientWindow
458 //-----------------------------------------------------------------------------
460 static void wxInsertChildInMDI(wxWindow
* parent
, wxWindow
* child
)
462 wxMDIChildFrame
* child_frame
= wx_static_cast(wxMDIChildFrame
*, child
);
463 wxString s
= child_frame
->GetTitle();
464 if (s
.IsNull()) s
= _("MDI child");
466 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
467 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
469 g_signal_connect (child
->m_widget
, "size_allocate",
470 G_CALLBACK (gtk_page_size_callback
), child
);
472 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
474 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
476 child_frame
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
478 wxMDIParentFrame
*parent_frame
= wx_static_cast(wxMDIParentFrame
*, parent
->GetParent());
479 parent_frame
->m_justInserted
= true;
482 //-----------------------------------------------------------------------------
484 //-----------------------------------------------------------------------------
486 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
488 wxMDIClientWindow::wxMDIClientWindow()
492 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
494 CreateClient( parent
, style
);
497 wxMDIClientWindow::~wxMDIClientWindow()
502 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
504 m_insertCallback
= 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 g_signal_connect (m_widget
, "switch_page",
516 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
518 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
520 m_parent
->DoAddChild( this );