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"
20 #include "wx/dialog.h"
23 #include "wx/notebook.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 //-----------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------
54 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
55 GtkNotebookPage
*page
,
56 gint
WXUNUSED(page_num
),
57 wxMDIParentFrame
*parent
)
60 wxapp_install_idle_handler();
62 // send deactivate event to old child
64 wxMDIChildFrame
*child
= parent
->GetActiveChild();
67 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
68 event1
.SetEventObject( child
);
69 child
->GetEventHandler()->ProcessEvent( event1
);
72 // send activate event to new child
74 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
78 child
= (wxMDIChildFrame
*) NULL
;
80 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
83 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
84 // CE: we come here in the destructor with a null child_frame - I think because
85 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
86 // isn't deleted early enough
90 if (child_frame
->m_page
== page
)
95 node
= node
->GetNext();
101 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
102 event2
.SetEventObject( child
);
103 child
->GetEventHandler()->ProcessEvent( event2
);
107 //-----------------------------------------------------------------------------
109 //-----------------------------------------------------------------------------
111 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
113 void wxMDIParentFrame::Init()
115 m_justInserted
= false;
116 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
119 wxMDIParentFrame::~wxMDIParentFrame()
123 bool wxMDIParentFrame::Create(wxWindow
*parent
,
125 const wxString
& title
,
129 const wxString
& name
)
131 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
138 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
140 wxFrame::GtkOnSize( x
, y
, width
, height
);
142 wxMDIChildFrame
*child_frame
= GetActiveChild();
143 if (!child_frame
) return;
145 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
146 if (!menu_bar
) return;
147 if (!menu_bar
->m_widget
) return;
151 menu_bar
->m_width
= m_width
;
152 menu_bar
->m_height
= wxMENU_HEIGHT
;
153 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
155 0, 0, m_width
, wxMENU_HEIGHT
);
158 void wxMDIParentFrame::OnInternalIdle()
160 /* if a an MDI child window has just been inserted
161 it has to be brought to the top in idle time. we
162 simply set the last notebook page active as new
163 pages can only be appended at the end */
167 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
168 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
170 /* need to set the menubar of the child */
171 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
172 if (active_child_frame
!= NULL
)
174 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
177 menu_bar
->m_width
= m_width
;
178 menu_bar
->m_height
= wxMENU_HEIGHT
;
179 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
181 0, 0, m_width
, wxMENU_HEIGHT
);
182 menu_bar
->SetInvokingWindow(active_child_frame
);
185 m_justInserted
= false;
189 wxFrame::OnInternalIdle();
191 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
192 bool visible_child_menu
= false;
194 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
197 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
201 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
204 if (child_frame
== active_child_frame
)
206 if (menu_bar
->Show(true))
208 menu_bar
->m_width
= m_width
;
209 menu_bar
->m_height
= wxMENU_HEIGHT
;
210 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
212 0, 0, m_width
, wxMENU_HEIGHT
);
213 menu_bar
->SetInvokingWindow( child_frame
);
215 visible_child_menu
= true;
219 if (menu_bar
->Show(false))
221 menu_bar
->UnsetInvokingWindow( child_frame
);
227 node
= node
->GetNext();
230 /* show/hide parent menu bar as required */
231 if ((m_frameMenuBar
) &&
232 (m_frameMenuBar
->IsShown() == visible_child_menu
))
234 if (visible_child_menu
)
236 m_frameMenuBar
->Show( false );
237 m_frameMenuBar
->UnsetInvokingWindow( this );
241 m_frameMenuBar
->Show( true );
242 m_frameMenuBar
->SetInvokingWindow( this );
244 m_frameMenuBar
->m_width
= m_width
;
245 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
246 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
247 m_frameMenuBar
->m_widget
,
248 0, 0, m_width
, wxMENU_HEIGHT
);
253 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
255 wxFrame::DoGetClientSize( width
, height
);
258 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
260 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
262 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
263 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
265 gint i
= gtk_notebook_get_current_page( notebook
);
266 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
268 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
269 if (!page
) return (wxMDIChildFrame
*) NULL
;
271 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
274 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
276 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
278 if (child_frame
->m_page
== page
)
280 node
= node
->GetNext();
283 return (wxMDIChildFrame
*) NULL
;
286 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
288 return m_clientWindow
;
291 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
293 m_clientWindow
= new wxMDIClientWindow( this );
294 return m_clientWindow
;
297 void wxMDIParentFrame::ActivateNext()
300 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
303 void wxMDIParentFrame::ActivatePrevious()
306 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
309 //-----------------------------------------------------------------------------
311 //-----------------------------------------------------------------------------
313 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
315 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
316 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
317 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
320 wxMDIChildFrame::wxMDIChildFrame()
322 m_menuBar
= (wxMenuBar
*) NULL
;
323 m_page
= (GtkNotebookPage
*) NULL
;
326 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
327 wxWindowID id
, const wxString
& title
,
328 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
329 long style
, const wxString
& name
)
331 m_menuBar
= (wxMenuBar
*) NULL
;
332 m_page
= (GtkNotebookPage
*) NULL
;
333 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
336 wxMDIChildFrame::~wxMDIChildFrame()
342 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
343 wxWindowID id
, const wxString
& title
,
344 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
345 long style
, const wxString
& name
)
349 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
352 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
354 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
357 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
359 wxWindow::DoSetClientSize( width
, height
);
362 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
364 wxWindow::DoGetClientSize( width
, height
);
367 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
369 wxWindow::AddChild(child
);
372 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
374 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
376 m_menuBar
= menu_bar
;
380 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
382 m_menuBar
->SetParent( mdi_frame
);
384 /* insert the invisible menu bar into the _parent_ mdi frame */
385 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
387 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
391 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
396 void wxMDIChildFrame::Activate()
398 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
399 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
400 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
401 gtk_notebook_set_page( notebook
, pageno
);
404 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
408 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
411 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
412 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
414 // we don't have any help text for this item, but may be the MDI frame
416 mdi_frame
->OnMenuHighlight(event
);
418 #endif // wxUSE_STATUSBAR
421 void wxMDIChildFrame::SetTitle( const wxString
&title
)
423 if ( title
== m_title
)
428 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
429 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
430 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
433 //-----------------------------------------------------------------------------
435 //-----------------------------------------------------------------------------
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
);
455 //-----------------------------------------------------------------------------
456 // InsertChild callback for wxMDIClientWindow
457 //-----------------------------------------------------------------------------
459 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
461 wxString s
= child
->GetTitle();
462 if (s
.IsNull()) s
= _("MDI child");
464 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
465 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
467 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
468 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
470 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
472 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
474 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
476 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
477 parent_frame
->m_justInserted
= true;
480 //-----------------------------------------------------------------------------
482 //-----------------------------------------------------------------------------
484 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
486 wxMDIClientWindow::wxMDIClientWindow()
490 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
492 CreateClient( parent
, style
);
495 wxMDIClientWindow::~wxMDIClientWindow()
500 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
504 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
506 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
507 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
509 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
513 m_widget
= gtk_notebook_new();
515 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
516 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
518 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
520 m_parent
->DoAddChild( this );