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 //-----------------------------------------------------------------------------
56 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
57 GtkNotebookPage
*page
,
58 gint
WXUNUSED(page_num
),
59 wxMDIParentFrame
*parent
)
62 wxapp_install_idle_handler();
64 // send deactivate event to old child
66 wxMDIChildFrame
*child
= parent
->GetActiveChild();
69 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
70 event1
.SetEventObject( child
);
71 child
->GetEventHandler()->ProcessEvent( event1
);
74 // send activate event to new child
76 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
80 child
= (wxMDIChildFrame
*) NULL
;
82 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
85 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
86 // CE: we come here in the destructor with a null child_frame - I think because
87 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
88 // isn't deleted early enough
92 if (child_frame
->m_page
== page
)
97 node
= node
->GetNext();
103 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
104 event2
.SetEventObject( child
);
105 child
->GetEventHandler()->ProcessEvent( event2
);
108 //-----------------------------------------------------------------------------
110 //-----------------------------------------------------------------------------
112 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
114 void wxMDIParentFrame::Init()
116 m_justInserted
= false;
117 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
120 wxMDIParentFrame::~wxMDIParentFrame()
124 bool wxMDIParentFrame::Create(wxWindow
*parent
,
126 const wxString
& title
,
130 const wxString
& name
)
132 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
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 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
174 menu_bar
->m_width
= m_width
;
175 menu_bar
->m_height
= wxMENU_HEIGHT
;
176 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
178 0, 0, m_width
, wxMENU_HEIGHT
);
179 menu_bar
->SetInvokingWindow(active_child_frame
);
181 m_justInserted
= false;
185 wxFrame::OnInternalIdle();
187 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
188 bool visible_child_menu
= false;
190 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
193 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
197 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
200 if (child_frame
== active_child_frame
)
202 if (menu_bar
->Show(true))
204 menu_bar
->m_width
= m_width
;
205 menu_bar
->m_height
= wxMENU_HEIGHT
;
206 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
208 0, 0, m_width
, wxMENU_HEIGHT
);
209 menu_bar
->SetInvokingWindow( child_frame
);
211 visible_child_menu
= true;
215 if (menu_bar
->Show(false))
217 menu_bar
->UnsetInvokingWindow( child_frame
);
223 node
= node
->GetNext();
226 /* show/hide parent menu bar as required */
227 if ((m_frameMenuBar
) &&
228 (m_frameMenuBar
->IsShown() == visible_child_menu
))
230 if (visible_child_menu
)
232 m_frameMenuBar
->Show( false );
233 m_frameMenuBar
->UnsetInvokingWindow( this );
237 m_frameMenuBar
->Show( true );
238 m_frameMenuBar
->SetInvokingWindow( this );
240 m_frameMenuBar
->m_width
= m_width
;
241 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
242 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
243 m_frameMenuBar
->m_widget
,
244 0, 0, m_width
, wxMENU_HEIGHT
);
249 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
251 wxFrame::DoGetClientSize( width
, height
);
254 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
256 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
258 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
259 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
261 gint i
= gtk_notebook_get_current_page( notebook
);
262 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
264 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
265 if (!page
) return (wxMDIChildFrame
*) NULL
;
267 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
270 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
272 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
274 if (child_frame
->m_page
== page
)
276 node
= node
->GetNext();
279 return (wxMDIChildFrame
*) NULL
;
282 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
284 return m_clientWindow
;
287 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
289 m_clientWindow
= new wxMDIClientWindow( this );
290 return m_clientWindow
;
293 void wxMDIParentFrame::ActivateNext()
296 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
299 void wxMDIParentFrame::ActivatePrevious()
302 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
305 //-----------------------------------------------------------------------------
307 //-----------------------------------------------------------------------------
309 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
311 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
312 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
313 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
316 wxMDIChildFrame::wxMDIChildFrame()
318 m_menuBar
= (wxMenuBar
*) NULL
;
319 m_page
= (GtkNotebookPage
*) NULL
;
322 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
323 wxWindowID id
, const wxString
& title
,
324 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
325 long style
, const wxString
& name
)
327 m_menuBar
= (wxMenuBar
*) NULL
;
328 m_page
= (GtkNotebookPage
*) NULL
;
329 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
332 wxMDIChildFrame::~wxMDIChildFrame()
338 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
339 wxWindowID id
, const wxString
& title
,
340 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
341 long style
, const wxString
& name
)
345 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
348 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
350 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
353 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
355 wxWindow::DoSetClientSize( width
, height
);
358 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
360 wxWindow::DoGetClientSize( width
, height
);
363 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
365 wxWindow::AddChild(child
);
368 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
370 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
372 m_menuBar
= menu_bar
;
376 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
378 m_menuBar
->SetParent( mdi_frame
);
380 /* insert the invisible menu bar into the _parent_ mdi frame */
381 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
383 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
387 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
392 void wxMDIChildFrame::Activate()
394 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
395 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
396 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
397 gtk_notebook_set_page( notebook
, pageno
);
400 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
404 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
407 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
408 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
410 // we don't have any help text for this item, but may be the MDI frame
412 mdi_frame
->OnMenuHighlight(event
);
414 #endif // wxUSE_STATUSBAR
417 void wxMDIChildFrame::SetTitle( const wxString
&title
)
419 if ( title
== m_title
)
424 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
425 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
426 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
429 //-----------------------------------------------------------------------------
431 //-----------------------------------------------------------------------------
433 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
435 if (g_isIdle
) wxapp_install_idle_handler();
437 if ((win
->m_x
== alloc
->x
) &&
438 (win
->m_y
== alloc
->y
) &&
439 (win
->m_width
== alloc
->width
) &&
440 (win
->m_height
== alloc
->height
) &&
446 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
449 //-----------------------------------------------------------------------------
450 // InsertChild callback for wxMDIClientWindow
451 //-----------------------------------------------------------------------------
453 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
455 wxString s
= child
->m_title
;
456 if (s
.IsNull()) s
= _("MDI child");
458 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
459 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
461 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
462 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
464 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
466 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
468 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
470 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
471 parent_frame
->m_justInserted
= true;
474 //-----------------------------------------------------------------------------
476 //-----------------------------------------------------------------------------
478 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
480 wxMDIClientWindow::wxMDIClientWindow()
484 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
486 CreateClient( parent
, style
);
489 wxMDIClientWindow::~wxMDIClientWindow()
494 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
498 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
500 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
501 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
503 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
507 m_widget
= gtk_notebook_new();
509 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
510 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
512 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
514 m_parent
->DoAddChild( this );