1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/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/gtk1/private.h"
29 #include "wx/gtk1/win_gtk.h"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
35 const int wxMENU_HEIGHT
= 27;
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 extern void wxapp_install_idle_handler();
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 extern wxList wxPendingDelete
;
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
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
);
109 //-----------------------------------------------------------------------------
111 //-----------------------------------------------------------------------------
113 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
115 void wxMDIParentFrame::Init()
117 m_justInserted
= false;
118 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
121 wxMDIParentFrame::~wxMDIParentFrame()
125 bool wxMDIParentFrame::Create(wxWindow
*parent
,
127 const wxString
& title
,
131 const wxString
& name
)
133 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
140 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
142 wxFrame::GtkOnSize( x
, y
, width
, height
);
144 wxMDIChildFrame
*child_frame
= GetActiveChild();
145 if (!child_frame
) return;
147 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
148 if (!menu_bar
) return;
149 if (!menu_bar
->m_widget
) return;
153 menu_bar
->m_width
= m_width
;
154 menu_bar
->m_height
= wxMENU_HEIGHT
;
155 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
157 0, 0, m_width
, wxMENU_HEIGHT
);
160 void wxMDIParentFrame::OnInternalIdle()
162 /* if a an MDI child window has just been inserted
163 it has to be brought to the top in idle time. we
164 simply set the last notebook page active as new
165 pages can only be appended at the end */
169 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
170 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
172 /* need to set the menubar of the child */
173 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
174 if (active_child_frame
!= NULL
)
176 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
179 menu_bar
->m_width
= m_width
;
180 menu_bar
->m_height
= wxMENU_HEIGHT
;
181 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
183 0, 0, m_width
, wxMENU_HEIGHT
);
184 menu_bar
->SetInvokingWindow(active_child_frame
);
187 m_justInserted
= false;
191 wxFrame::OnInternalIdle();
193 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
194 bool visible_child_menu
= false;
196 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
199 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
203 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
206 if (child_frame
== active_child_frame
)
208 if (menu_bar
->Show(true))
210 menu_bar
->m_width
= m_width
;
211 menu_bar
->m_height
= wxMENU_HEIGHT
;
212 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
214 0, 0, m_width
, wxMENU_HEIGHT
);
215 menu_bar
->SetInvokingWindow( child_frame
);
217 visible_child_menu
= true;
221 if (menu_bar
->Show(false))
223 menu_bar
->UnsetInvokingWindow( child_frame
);
229 node
= node
->GetNext();
232 /* show/hide parent menu bar as required */
233 if ((m_frameMenuBar
) &&
234 (m_frameMenuBar
->IsShown() == visible_child_menu
))
236 if (visible_child_menu
)
238 m_frameMenuBar
->Show( false );
239 m_frameMenuBar
->UnsetInvokingWindow( this );
243 m_frameMenuBar
->Show( true );
244 m_frameMenuBar
->SetInvokingWindow( this );
246 m_frameMenuBar
->m_width
= m_width
;
247 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
248 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
249 m_frameMenuBar
->m_widget
,
250 0, 0, m_width
, wxMENU_HEIGHT
);
255 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
257 wxFrame::DoGetClientSize( width
, height
);
260 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
262 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
264 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
265 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
267 gint i
= gtk_notebook_get_current_page( notebook
);
268 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
270 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
271 if (!page
) return (wxMDIChildFrame
*) NULL
;
273 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
276 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
278 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
280 if (child_frame
->m_page
== page
)
282 node
= node
->GetNext();
285 return (wxMDIChildFrame
*) NULL
;
288 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
290 return m_clientWindow
;
293 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
295 m_clientWindow
= new wxMDIClientWindow( this );
296 return m_clientWindow
;
299 void wxMDIParentFrame::ActivateNext()
302 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
305 void wxMDIParentFrame::ActivatePrevious()
308 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
311 //-----------------------------------------------------------------------------
313 //-----------------------------------------------------------------------------
315 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
317 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
318 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
319 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
322 wxMDIChildFrame::wxMDIChildFrame()
324 m_menuBar
= (wxMenuBar
*) NULL
;
325 m_page
= (GtkNotebookPage
*) NULL
;
328 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
329 wxWindowID id
, const wxString
& title
,
330 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
331 long style
, const wxString
& name
)
333 m_menuBar
= (wxMenuBar
*) NULL
;
334 m_page
= (GtkNotebookPage
*) NULL
;
335 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
338 wxMDIChildFrame::~wxMDIChildFrame()
344 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
345 wxWindowID id
, const wxString
& title
,
346 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
347 long style
, const wxString
& name
)
351 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
354 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
356 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
359 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
361 wxWindow::DoSetClientSize( width
, height
);
364 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
366 wxWindow::DoGetClientSize( width
, height
);
369 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
371 wxWindow::AddChild(child
);
374 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
376 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
378 m_menuBar
= menu_bar
;
382 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
384 m_menuBar
->SetParent( mdi_frame
);
386 /* insert the invisible menu bar into the _parent_ mdi frame */
387 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
389 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
393 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
398 void wxMDIChildFrame::Activate()
400 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
401 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
402 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
403 gtk_notebook_set_page( notebook
, pageno
);
406 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
410 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
413 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
414 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
416 // we don't have any help text for this item, but may be the MDI frame
418 mdi_frame
->OnMenuHighlight(event
);
420 #endif // wxUSE_STATUSBAR
423 void wxMDIChildFrame::SetTitle( const wxString
&title
)
425 if ( title
== m_title
)
430 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
431 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
432 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
435 //-----------------------------------------------------------------------------
437 //-----------------------------------------------------------------------------
440 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
442 if (g_isIdle
) wxapp_install_idle_handler();
444 if ((win
->m_x
== alloc
->x
) &&
445 (win
->m_y
== alloc
->y
) &&
446 (win
->m_width
== alloc
->width
) &&
447 (win
->m_height
== alloc
->height
) &&
453 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
457 //-----------------------------------------------------------------------------
458 // InsertChild callback for wxMDIClientWindow
459 //-----------------------------------------------------------------------------
461 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
463 wxString s
= child
->GetTitle();
464 if (s
.IsNull()) s
= _("MDI child");
466 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
467 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
469 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
470 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
472 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
474 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
476 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
478 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
479 parent_frame
->m_justInserted
= true;
482 //-----------------------------------------------------------------------------
484 //-----------------------------------------------------------------------------
486 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
488 wxMDIClientWindow::wxMDIClientWindow()
492 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
494 CreateClient( parent
, style
);
497 wxMDIClientWindow::~wxMDIClientWindow()
502 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
506 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
508 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
509 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
511 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
515 m_widget
= gtk_notebook_new();
517 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
518 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
520 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
522 m_parent
->DoAddChild( this );