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"
21 #include "wx/notebook.h"
22 #include "wx/dialog.h"
24 #include "wx/gtk/private.h"
29 #include "wx/gtk/win_gtk.h"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
35 const int wxMENU_HEIGHT
= 27;
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 extern wxList wxPendingDelete
;
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
49 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
50 GtkNotebookPage
*page
,
51 gint
WXUNUSED(page_num
),
52 wxMDIParentFrame
*parent
)
55 wxapp_install_idle_handler();
57 // send deactivate event to old child
59 wxMDIChildFrame
*child
= parent
->GetActiveChild();
62 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
63 event1
.SetEventObject( child
);
64 child
->GetEventHandler()->ProcessEvent( event1
);
67 // send activate event to new child
69 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
73 child
= (wxMDIChildFrame
*) NULL
;
75 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
78 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
80 // child_frame can be NULL when this is called from dtor, probably
81 // because g_signal_connect (m_widget, "switch_page", (see below)
82 // isn't deleted early enough
83 if ( child_frame
&& child_frame
->m_page
== page
)
88 node
= node
->GetNext();
94 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
95 event2
.SetEventObject( child
);
96 child
->GetEventHandler()->ProcessEvent( event2
);
100 //-----------------------------------------------------------------------------
102 //-----------------------------------------------------------------------------
104 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
106 void wxMDIParentFrame::Init()
108 m_justInserted
= false;
109 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
112 wxMDIParentFrame::~wxMDIParentFrame()
116 bool wxMDIParentFrame::Create(wxWindow
*parent
,
118 const wxString
& title
,
122 const wxString
& name
)
124 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
131 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
133 wxFrame::GtkOnSize( x
, y
, width
, height
);
135 wxMDIChildFrame
*child_frame
= GetActiveChild();
136 if (!child_frame
) return;
138 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
139 if (!menu_bar
) return;
140 if (!menu_bar
->m_widget
) return;
144 menu_bar
->m_width
= m_width
;
145 menu_bar
->m_height
= wxMENU_HEIGHT
;
146 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
148 0, 0, m_width
, wxMENU_HEIGHT
);
151 void wxMDIParentFrame::OnInternalIdle()
153 /* if a an MDI child window has just been inserted
154 it has to be brought to the top in idle time. we
155 simply set the last notebook page active as new
156 pages can only be appended at the end */
160 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
161 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
163 /* need to set the menubar of the child */
164 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
165 if (active_child_frame
!= NULL
)
167 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
170 menu_bar
->m_width
= m_width
;
171 menu_bar
->m_height
= wxMENU_HEIGHT
;
172 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
174 0, 0, m_width
, wxMENU_HEIGHT
);
175 menu_bar
->SetInvokingWindow(active_child_frame
);
178 m_justInserted
= false;
182 wxFrame::OnInternalIdle();
184 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
185 bool visible_child_menu
= false;
187 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
190 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
194 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
197 if (child_frame
== active_child_frame
)
199 if (menu_bar
->Show(true))
201 menu_bar
->m_width
= m_width
;
202 menu_bar
->m_height
= wxMENU_HEIGHT
;
203 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
205 0, 0, m_width
, wxMENU_HEIGHT
);
206 menu_bar
->SetInvokingWindow( child_frame
);
208 visible_child_menu
= true;
212 if (menu_bar
->Show(false))
214 menu_bar
->UnsetInvokingWindow( child_frame
);
220 node
= node
->GetNext();
223 /* show/hide parent menu bar as required */
224 if ((m_frameMenuBar
) &&
225 (m_frameMenuBar
->IsShown() == visible_child_menu
))
227 if (visible_child_menu
)
229 m_frameMenuBar
->Show( false );
230 m_frameMenuBar
->UnsetInvokingWindow( this );
234 m_frameMenuBar
->Show( true );
235 m_frameMenuBar
->SetInvokingWindow( this );
237 m_frameMenuBar
->m_width
= m_width
;
238 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
239 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
240 m_frameMenuBar
->m_widget
,
241 0, 0, m_width
, wxMENU_HEIGHT
);
246 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
248 wxFrame::DoGetClientSize( width
, height
);
251 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
253 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
255 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
256 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
258 gint i
= gtk_notebook_get_current_page( notebook
);
259 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
261 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
262 if (!page
) return (wxMDIChildFrame
*) NULL
;
264 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
267 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
269 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
271 if (child_frame
->m_page
== page
)
273 node
= node
->GetNext();
276 return (wxMDIChildFrame
*) NULL
;
279 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
281 return m_clientWindow
;
284 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
286 m_clientWindow
= new wxMDIClientWindow( this );
287 return m_clientWindow
;
290 void wxMDIParentFrame::ActivateNext()
293 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
296 void wxMDIParentFrame::ActivatePrevious()
299 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
302 //-----------------------------------------------------------------------------
304 //-----------------------------------------------------------------------------
306 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
308 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
309 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
310 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
313 wxMDIChildFrame::wxMDIChildFrame()
315 m_menuBar
= (wxMenuBar
*) NULL
;
316 m_page
= (GtkNotebookPage
*) NULL
;
319 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
320 wxWindowID id
, const wxString
& title
,
321 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
322 long style
, const wxString
& name
)
324 m_menuBar
= (wxMenuBar
*) NULL
;
325 m_page
= (GtkNotebookPage
*) NULL
;
326 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
329 wxMDIChildFrame::~wxMDIChildFrame()
335 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
336 wxWindowID id
, const wxString
& title
,
337 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
338 long style
, const wxString
& name
)
342 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
345 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
347 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
350 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
352 wxWindow::DoSetClientSize( width
, height
);
355 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
357 wxWindow::DoGetClientSize( width
, height
);
360 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
362 wxWindow::AddChild(child
);
365 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
367 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
369 m_menuBar
= menu_bar
;
373 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
375 m_menuBar
->SetParent( mdi_frame
);
377 /* insert the invisible menu bar into the _parent_ mdi frame */
378 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
380 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
384 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
389 void wxMDIChildFrame::Activate()
391 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
392 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
393 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
394 gtk_notebook_set_current_page( notebook
, pageno
);
397 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
401 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
404 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
405 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
407 // we don't have any help text for this item, but may be the MDI frame
409 mdi_frame
->OnMenuHighlight(event
);
411 #endif // wxUSE_STATUSBAR
414 void wxMDIChildFrame::SetTitle( const wxString
&title
)
416 if ( title
== m_title
)
421 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
422 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
423 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
426 //-----------------------------------------------------------------------------
428 //-----------------------------------------------------------------------------
431 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
433 if (g_isIdle
) wxapp_install_idle_handler();
435 if ((win
->m_x
== alloc
->x
) &&
436 (win
->m_y
== alloc
->y
) &&
437 (win
->m_width
== alloc
->width
) &&
438 (win
->m_height
== alloc
->height
) &&
444 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
448 //-----------------------------------------------------------------------------
449 // InsertChild callback for wxMDIClientWindow
450 //-----------------------------------------------------------------------------
452 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
454 wxString s
= child
->GetTitle();
455 if (s
.IsNull()) s
= _("MDI child");
457 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
458 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
460 g_signal_connect (child
->m_widget
, "size_allocate",
461 G_CALLBACK (gtk_page_size_callback
), child
);
463 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
465 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
467 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
469 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
470 parent_frame
->m_justInserted
= true;
473 //-----------------------------------------------------------------------------
475 //-----------------------------------------------------------------------------
477 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
479 wxMDIClientWindow::wxMDIClientWindow()
483 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
485 CreateClient( parent
, style
);
488 wxMDIClientWindow::~wxMDIClientWindow()
493 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
497 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
499 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
500 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
502 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
506 m_widget
= gtk_notebook_new();
508 g_signal_connect (m_widget
, "switch_page",
509 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
511 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
513 m_parent
->DoAddChild( this );