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 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 m_clientWindow
= new wxMDIClientWindow( this );
295 return m_clientWindow
;
298 void wxMDIParentFrame::ActivateNext()
301 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
304 void wxMDIParentFrame::ActivatePrevious()
307 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
310 //-----------------------------------------------------------------------------
312 //-----------------------------------------------------------------------------
314 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
316 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
317 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
318 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
321 wxMDIChildFrame::wxMDIChildFrame()
323 m_menuBar
= (wxMenuBar
*) NULL
;
324 m_page
= (GtkNotebookPage
*) NULL
;
327 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
328 wxWindowID id
, const wxString
& title
,
329 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
330 long style
, const wxString
& name
)
332 m_menuBar
= (wxMenuBar
*) NULL
;
333 m_page
= (GtkNotebookPage
*) NULL
;
334 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
337 wxMDIChildFrame::~wxMDIChildFrame()
343 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
344 wxWindowID id
, const wxString
& title
,
345 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
346 long style
, const wxString
& name
)
350 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
353 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
355 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
358 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
360 wxWindow::DoSetClientSize( width
, height
);
363 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
365 wxWindow::DoGetClientSize( width
, height
);
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 */
386 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
388 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
392 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
397 void wxMDIChildFrame::Activate()
399 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
400 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
401 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
402 gtk_notebook_set_page( notebook
, pageno
);
405 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
409 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
412 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
413 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
415 // we don't have any help text for this item, but may be the MDI frame
417 mdi_frame
->OnMenuHighlight(event
);
419 #endif // wxUSE_STATUSBAR
422 void wxMDIChildFrame::SetTitle( const wxString
&title
)
424 if ( title
== m_title
)
429 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
430 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
431 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
434 //-----------------------------------------------------------------------------
436 //-----------------------------------------------------------------------------
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
);
454 //-----------------------------------------------------------------------------
455 // InsertChild callback for wxMDIClientWindow
456 //-----------------------------------------------------------------------------
458 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
460 wxString s
= child
->m_title
;
461 if (s
.IsNull()) s
= _("MDI child");
463 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
464 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
466 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
467 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
469 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
471 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
473 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
475 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
476 parent_frame
->m_justInserted
= true;
479 //-----------------------------------------------------------------------------
481 //-----------------------------------------------------------------------------
483 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
485 wxMDIClientWindow::wxMDIClientWindow()
489 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
491 CreateClient( parent
, style
);
494 wxMDIClientWindow::~wxMDIClientWindow()
499 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
503 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
505 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
506 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
508 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
512 m_widget
= gtk_notebook_new();
514 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
515 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
517 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
519 m_parent
->DoAddChild( this );