1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "mdi.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
18 #include "wx/notebook.h"
22 #include "wx/dialog.h"
25 #include "wx/gtk/private.h"
30 #include "wx/gtk/win_gtk.h"
32 //-----------------------------------------------------------------------------
34 //-----------------------------------------------------------------------------
36 const int wxMENU_HEIGHT
= 27;
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
42 extern void wxapp_install_idle_handler();
45 //-----------------------------------------------------------------------------
47 //-----------------------------------------------------------------------------
49 extern wxList wxPendingDelete
;
51 //-----------------------------------------------------------------------------
53 //-----------------------------------------------------------------------------
57 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
58 GtkNotebookPage
*page
,
59 gint
WXUNUSED(page_num
),
60 wxMDIParentFrame
*parent
)
63 wxapp_install_idle_handler();
65 // send deactivate event to old child
67 wxMDIChildFrame
*child
= parent
->GetActiveChild();
70 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
71 event1
.SetEventObject( child
);
72 child
->GetEventHandler()->ProcessEvent( event1
);
75 // send activate event to new child
77 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
81 child
= (wxMDIChildFrame
*) NULL
;
83 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
86 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
87 // CE: we come here in the destructor with a null child_frame - I think because
88 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
89 // isn't deleted early enough
93 if (child_frame
->m_page
== page
)
98 node
= node
->GetNext();
104 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
105 event2
.SetEventObject( child
);
106 child
->GetEventHandler()->ProcessEvent( event2
);
110 //-----------------------------------------------------------------------------
112 //-----------------------------------------------------------------------------
114 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
116 void wxMDIParentFrame::Init()
118 m_justInserted
= false;
119 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
122 wxMDIParentFrame::~wxMDIParentFrame()
126 bool wxMDIParentFrame::Create(wxWindow
*parent
,
128 const wxString
& title
,
132 const wxString
& name
)
134 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
141 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
143 wxFrame::GtkOnSize( x
, y
, width
, height
);
145 wxMDIChildFrame
*child_frame
= GetActiveChild();
146 if (!child_frame
) return;
148 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
149 if (!menu_bar
) return;
150 if (!menu_bar
->m_widget
) return;
154 menu_bar
->m_width
= m_width
;
155 menu_bar
->m_height
= wxMENU_HEIGHT
;
156 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
158 0, 0, m_width
, wxMENU_HEIGHT
);
161 void wxMDIParentFrame::OnInternalIdle()
163 /* if a an MDI child window has just been inserted
164 it has to be brought to the top in idle time. we
165 simply set the last notebook page active as new
166 pages can only be appended at the end */
170 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
171 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
173 /* need to set the menubar of the child */
174 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
175 if (active_child_frame
!= NULL
)
177 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
180 menu_bar
->m_width
= m_width
;
181 menu_bar
->m_height
= wxMENU_HEIGHT
;
182 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
184 0, 0, m_width
, wxMENU_HEIGHT
);
185 menu_bar
->SetInvokingWindow(active_child_frame
);
188 m_justInserted
= false;
192 wxFrame::OnInternalIdle();
194 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
195 bool visible_child_menu
= false;
197 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
200 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
204 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
207 if (child_frame
== active_child_frame
)
209 if (menu_bar
->Show(true))
211 menu_bar
->m_width
= m_width
;
212 menu_bar
->m_height
= wxMENU_HEIGHT
;
213 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
215 0, 0, m_width
, wxMENU_HEIGHT
);
216 menu_bar
->SetInvokingWindow( child_frame
);
218 visible_child_menu
= true;
222 if (menu_bar
->Show(false))
224 menu_bar
->UnsetInvokingWindow( child_frame
);
230 node
= node
->GetNext();
233 /* show/hide parent menu bar as required */
234 if ((m_frameMenuBar
) &&
235 (m_frameMenuBar
->IsShown() == visible_child_menu
))
237 if (visible_child_menu
)
239 m_frameMenuBar
->Show( false );
240 m_frameMenuBar
->UnsetInvokingWindow( this );
244 m_frameMenuBar
->Show( true );
245 m_frameMenuBar
->SetInvokingWindow( this );
247 m_frameMenuBar
->m_width
= m_width
;
248 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
249 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
250 m_frameMenuBar
->m_widget
,
251 0, 0, m_width
, wxMENU_HEIGHT
);
256 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
258 wxFrame::DoGetClientSize( width
, height
);
261 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
263 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
265 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
266 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
268 gint i
= gtk_notebook_get_current_page( notebook
);
269 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
271 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
272 if (!page
) return (wxMDIChildFrame
*) NULL
;
274 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
277 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
279 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
281 if (child_frame
->m_page
== page
)
283 node
= node
->GetNext();
286 return (wxMDIChildFrame
*) NULL
;
289 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
291 return m_clientWindow
;
294 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
296 m_clientWindow
= new wxMDIClientWindow( this );
297 return m_clientWindow
;
300 void wxMDIParentFrame::ActivateNext()
303 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
306 void wxMDIParentFrame::ActivatePrevious()
309 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
312 //-----------------------------------------------------------------------------
314 //-----------------------------------------------------------------------------
316 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
318 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
319 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
320 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
323 wxMDIChildFrame::wxMDIChildFrame()
325 m_menuBar
= (wxMenuBar
*) NULL
;
326 m_page
= (GtkNotebookPage
*) NULL
;
329 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
330 wxWindowID id
, const wxString
& title
,
331 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
332 long style
, const wxString
& name
)
334 m_menuBar
= (wxMenuBar
*) NULL
;
335 m_page
= (GtkNotebookPage
*) NULL
;
336 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
339 wxMDIChildFrame::~wxMDIChildFrame()
345 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
346 wxWindowID id
, const wxString
& title
,
347 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
348 long style
, const wxString
& name
)
352 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
355 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
357 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
360 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
362 wxWindow::DoSetClientSize( width
, height
);
365 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
367 wxWindow::DoGetClientSize( width
, height
);
370 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
372 wxWindow::AddChild(child
);
375 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
377 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
379 m_menuBar
= menu_bar
;
383 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
385 m_menuBar
->SetParent( mdi_frame
);
387 /* insert the invisible menu bar into the _parent_ mdi frame */
388 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
390 0, 0, mdi_frame
->m_width
, 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_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(mdi_frame
->GetStatusBar(), 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
, wxWindow
*win
)
443 if (g_isIdle
) wxapp_install_idle_handler();
445 if ((win
->m_x
== alloc
->x
) &&
446 (win
->m_y
== alloc
->y
) &&
447 (win
->m_width
== alloc
->width
) &&
448 (win
->m_height
== alloc
->height
) &&
454 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
458 //-----------------------------------------------------------------------------
459 // InsertChild callback for wxMDIClientWindow
460 //-----------------------------------------------------------------------------
462 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
464 wxString s
= child
->m_title
;
465 if (s
.IsNull()) s
= _("MDI child");
467 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
468 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
470 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
471 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
473 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
475 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
477 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
479 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
480 parent_frame
->m_justInserted
= true;
483 //-----------------------------------------------------------------------------
485 //-----------------------------------------------------------------------------
487 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
489 wxMDIClientWindow::wxMDIClientWindow()
493 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
495 CreateClient( parent
, style
);
498 wxMDIClientWindow::~wxMDIClientWindow()
503 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
507 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
509 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
510 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
512 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
516 m_widget
= gtk_notebook_new();
518 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
519 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
521 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
523 m_parent
->DoAddChild( this );