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"
14 #include "wx/notebook.h"
18 #include "wx/dialog.h"
21 #include "wx/gtk/private.h"
26 #include "wx/gtk/win_gtk.h"
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 const int wxMENU_HEIGHT
= 27;
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
38 extern wxList wxPendingDelete
;
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
46 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
47 GtkNotebookPage
*page
,
48 gint
WXUNUSED(page_num
),
49 wxMDIParentFrame
*parent
)
52 wxapp_install_idle_handler();
54 // send deactivate event to old child
56 wxMDIChildFrame
*child
= parent
->GetActiveChild();
59 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
60 event1
.SetEventObject( child
);
61 child
->GetEventHandler()->ProcessEvent( event1
);
64 // send activate event to new child
66 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
70 child
= (wxMDIChildFrame
*) NULL
;
72 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
75 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
76 // CE: we come here in the destructor with a null child_frame - I think because
77 // g_signal_connect (m_widget, "switch_page", (see below)
78 // isn't deleted early enough
82 if (child_frame
->m_page
== page
)
87 node
= node
->GetNext();
93 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
94 event2
.SetEventObject( child
);
95 child
->GetEventHandler()->ProcessEvent( event2
);
99 //-----------------------------------------------------------------------------
101 //-----------------------------------------------------------------------------
103 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
105 void wxMDIParentFrame::Init()
107 m_justInserted
= false;
108 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
111 wxMDIParentFrame::~wxMDIParentFrame()
115 bool wxMDIParentFrame::Create(wxWindow
*parent
,
117 const wxString
& title
,
121 const wxString
& name
)
123 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
130 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
132 wxFrame::GtkOnSize( x
, y
, width
, height
);
134 wxMDIChildFrame
*child_frame
= GetActiveChild();
135 if (!child_frame
) return;
137 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
138 if (!menu_bar
) return;
139 if (!menu_bar
->m_widget
) return;
143 menu_bar
->m_width
= m_width
;
144 menu_bar
->m_height
= wxMENU_HEIGHT
;
145 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
147 0, 0, m_width
, wxMENU_HEIGHT
);
150 void wxMDIParentFrame::OnInternalIdle()
152 /* if a an MDI child window has just been inserted
153 it has to be brought to the top in idle time. we
154 simply set the last notebook page active as new
155 pages can only be appended at the end */
159 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
160 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
162 /* need to set the menubar of the child */
163 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
164 if (active_child_frame
!= NULL
)
166 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
169 menu_bar
->m_width
= m_width
;
170 menu_bar
->m_height
= wxMENU_HEIGHT
;
171 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
173 0, 0, m_width
, wxMENU_HEIGHT
);
174 menu_bar
->SetInvokingWindow(active_child_frame
);
177 m_justInserted
= false;
181 wxFrame::OnInternalIdle();
183 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
184 bool visible_child_menu
= false;
186 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
189 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
193 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
196 if (child_frame
== active_child_frame
)
198 if (menu_bar
->Show(true))
200 menu_bar
->m_width
= m_width
;
201 menu_bar
->m_height
= wxMENU_HEIGHT
;
202 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
204 0, 0, m_width
, wxMENU_HEIGHT
);
205 menu_bar
->SetInvokingWindow( child_frame
);
207 visible_child_menu
= true;
211 if (menu_bar
->Show(false))
213 menu_bar
->UnsetInvokingWindow( child_frame
);
219 node
= node
->GetNext();
222 /* show/hide parent menu bar as required */
223 if ((m_frameMenuBar
) &&
224 (m_frameMenuBar
->IsShown() == visible_child_menu
))
226 if (visible_child_menu
)
228 m_frameMenuBar
->Show( false );
229 m_frameMenuBar
->UnsetInvokingWindow( this );
233 m_frameMenuBar
->Show( true );
234 m_frameMenuBar
->SetInvokingWindow( this );
236 m_frameMenuBar
->m_width
= m_width
;
237 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
238 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
239 m_frameMenuBar
->m_widget
,
240 0, 0, m_width
, wxMENU_HEIGHT
);
245 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
247 wxFrame::DoGetClientSize( width
, height
);
250 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
252 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
254 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
255 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
257 gint i
= gtk_notebook_get_current_page( notebook
);
258 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
260 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
261 if (!page
) return (wxMDIChildFrame
*) NULL
;
263 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
266 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
268 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
270 if (child_frame
->m_page
== page
)
272 node
= node
->GetNext();
275 return (wxMDIChildFrame
*) NULL
;
278 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
280 return m_clientWindow
;
283 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
285 m_clientWindow
= new wxMDIClientWindow( this );
286 return m_clientWindow
;
289 void wxMDIParentFrame::ActivateNext()
292 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
295 void wxMDIParentFrame::ActivatePrevious()
298 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
301 //-----------------------------------------------------------------------------
303 //-----------------------------------------------------------------------------
305 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
307 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
308 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
309 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
312 wxMDIChildFrame::wxMDIChildFrame()
314 m_menuBar
= (wxMenuBar
*) NULL
;
315 m_page
= (GtkNotebookPage
*) NULL
;
318 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
319 wxWindowID id
, const wxString
& title
,
320 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
321 long style
, const wxString
& name
)
323 m_menuBar
= (wxMenuBar
*) NULL
;
324 m_page
= (GtkNotebookPage
*) NULL
;
325 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
328 wxMDIChildFrame::~wxMDIChildFrame()
334 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
335 wxWindowID id
, const wxString
& title
,
336 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
337 long style
, const wxString
& name
)
341 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
344 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
346 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
349 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
351 wxWindow::DoSetClientSize( width
, height
);
354 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
356 wxWindow::DoGetClientSize( width
, height
);
359 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
361 wxWindow::AddChild(child
);
364 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
366 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
368 m_menuBar
= menu_bar
;
372 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
374 m_menuBar
->SetParent( mdi_frame
);
376 /* insert the invisible menu bar into the _parent_ mdi frame */
377 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
379 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
383 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
388 void wxMDIChildFrame::Activate()
390 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
391 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
392 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
393 gtk_notebook_set_current_page( notebook
, pageno
);
396 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
400 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
403 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
404 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
406 // we don't have any help text for this item, but may be the MDI frame
408 mdi_frame
->OnMenuHighlight(event
);
410 #endif // wxUSE_STATUSBAR
413 void wxMDIChildFrame::SetTitle( const wxString
&title
)
415 if ( title
== m_title
)
420 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
421 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
422 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
425 //-----------------------------------------------------------------------------
427 //-----------------------------------------------------------------------------
430 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
432 if (g_isIdle
) wxapp_install_idle_handler();
434 if ((win
->m_x
== alloc
->x
) &&
435 (win
->m_y
== alloc
->y
) &&
436 (win
->m_width
== alloc
->width
) &&
437 (win
->m_height
== alloc
->height
) &&
443 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
447 //-----------------------------------------------------------------------------
448 // InsertChild callback for wxMDIClientWindow
449 //-----------------------------------------------------------------------------
451 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
453 wxString s
= child
->GetTitle();
454 if (s
.IsNull()) s
= _("MDI child");
456 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
457 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
459 g_signal_connect (child
->m_widget
, "size_allocate",
460 G_CALLBACK (gtk_page_size_callback
), child
);
462 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
464 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
466 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
468 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
469 parent_frame
->m_justInserted
= true;
472 //-----------------------------------------------------------------------------
474 //-----------------------------------------------------------------------------
476 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
478 wxMDIClientWindow::wxMDIClientWindow()
482 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
484 CreateClient( parent
, style
);
487 wxMDIClientWindow::~wxMDIClientWindow()
492 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
496 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
498 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
499 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
501 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
505 m_widget
= gtk_notebook_new();
507 g_signal_connect (m_widget
, "switch_page",
508 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
510 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
512 m_parent
->DoAddChild( this );