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
;
176 menu_bar
->m_width
= m_width
;
177 menu_bar
->m_height
= wxMENU_HEIGHT
;
178 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
180 0, 0, m_width
, wxMENU_HEIGHT
);
181 menu_bar
->SetInvokingWindow(active_child_frame
);
184 m_justInserted
= false;
188 wxFrame::OnInternalIdle();
190 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
191 bool visible_child_menu
= false;
193 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
196 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
200 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
203 if (child_frame
== active_child_frame
)
205 if (menu_bar
->Show(true))
207 menu_bar
->m_width
= m_width
;
208 menu_bar
->m_height
= wxMENU_HEIGHT
;
209 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
211 0, 0, m_width
, wxMENU_HEIGHT
);
212 menu_bar
->SetInvokingWindow( child_frame
);
214 visible_child_menu
= true;
218 if (menu_bar
->Show(false))
220 menu_bar
->UnsetInvokingWindow( child_frame
);
226 node
= node
->GetNext();
229 /* show/hide parent menu bar as required */
230 if ((m_frameMenuBar
) &&
231 (m_frameMenuBar
->IsShown() == visible_child_menu
))
233 if (visible_child_menu
)
235 m_frameMenuBar
->Show( false );
236 m_frameMenuBar
->UnsetInvokingWindow( this );
240 m_frameMenuBar
->Show( true );
241 m_frameMenuBar
->SetInvokingWindow( this );
243 m_frameMenuBar
->m_width
= m_width
;
244 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
245 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
246 m_frameMenuBar
->m_widget
,
247 0, 0, m_width
, wxMENU_HEIGHT
);
252 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
254 wxFrame::DoGetClientSize( width
, height
);
257 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
259 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
261 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
262 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
264 gint i
= gtk_notebook_get_current_page( notebook
);
265 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
267 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
268 if (!page
) return (wxMDIChildFrame
*) NULL
;
270 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
273 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
275 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
277 if (child_frame
->m_page
== page
)
279 node
= node
->GetNext();
282 return (wxMDIChildFrame
*) NULL
;
285 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
287 return m_clientWindow
;
290 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
292 m_clientWindow
= new wxMDIClientWindow( this );
293 return m_clientWindow
;
296 void wxMDIParentFrame::ActivateNext()
299 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
302 void wxMDIParentFrame::ActivatePrevious()
305 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
308 //-----------------------------------------------------------------------------
310 //-----------------------------------------------------------------------------
312 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
314 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
315 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
316 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
319 wxMDIChildFrame::wxMDIChildFrame()
321 m_menuBar
= (wxMenuBar
*) NULL
;
322 m_page
= (GtkNotebookPage
*) NULL
;
325 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
326 wxWindowID id
, const wxString
& title
,
327 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
328 long style
, const wxString
& name
)
330 m_menuBar
= (wxMenuBar
*) NULL
;
331 m_page
= (GtkNotebookPage
*) NULL
;
332 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
335 wxMDIChildFrame::~wxMDIChildFrame()
341 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
342 wxWindowID id
, const wxString
& title
,
343 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
344 long style
, const wxString
& name
)
348 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
351 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
353 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
356 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
358 wxWindow::DoSetClientSize( width
, height
);
361 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
363 wxWindow::DoGetClientSize( width
, height
);
366 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
368 wxWindow::AddChild(child
);
371 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
373 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
375 m_menuBar
= menu_bar
;
379 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
381 m_menuBar
->SetParent( mdi_frame
);
383 /* insert the invisible menu bar into the _parent_ mdi frame */
384 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
386 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
390 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
395 void wxMDIChildFrame::Activate()
397 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
398 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
399 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
400 gtk_notebook_set_page( notebook
, pageno
);
403 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
407 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
410 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
411 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
413 // we don't have any help text for this item, but may be the MDI frame
415 mdi_frame
->OnMenuHighlight(event
);
417 #endif // wxUSE_STATUSBAR
420 void wxMDIChildFrame::SetTitle( const wxString
&title
)
422 if ( title
== m_title
)
427 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
428 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
429 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
432 //-----------------------------------------------------------------------------
434 //-----------------------------------------------------------------------------
436 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
438 if (g_isIdle
) wxapp_install_idle_handler();
440 if ((win
->m_x
== alloc
->x
) &&
441 (win
->m_y
== alloc
->y
) &&
442 (win
->m_width
== alloc
->width
) &&
443 (win
->m_height
== alloc
->height
) &&
449 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
452 //-----------------------------------------------------------------------------
453 // InsertChild callback for wxMDIClientWindow
454 //-----------------------------------------------------------------------------
456 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
458 wxString s
= child
->m_title
;
459 if (s
.IsNull()) s
= _("MDI child");
461 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
462 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
464 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
465 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
467 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
469 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
471 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
473 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
474 parent_frame
->m_justInserted
= true;
477 //-----------------------------------------------------------------------------
479 //-----------------------------------------------------------------------------
481 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
483 wxMDIClientWindow::wxMDIClientWindow()
487 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
489 CreateClient( parent
, style
);
492 wxMDIClientWindow::~wxMDIClientWindow()
497 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
501 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
503 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
504 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
506 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
510 m_widget
= gtk_notebook_new();
512 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
513 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
515 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
517 m_parent
->DoAddChild( this );