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"
20 #include "wx/dialog.h"
23 #include "wx/notebook.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 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
47 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
48 GtkNotebookPage
*page
,
49 gint
WXUNUSED(page_num
),
50 wxMDIParentFrame
*parent
)
53 wxapp_install_idle_handler();
55 // send deactivate event to old child
57 wxMDIChildFrame
*child
= parent
->GetActiveChild();
60 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
61 event1
.SetEventObject( child
);
62 child
->GetEventHandler()->ProcessEvent( event1
);
65 // send activate event to new child
67 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
71 child
= (wxMDIChildFrame
*) NULL
;
73 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
76 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
78 // child_frame can be NULL when this is called from dtor, probably
79 // because g_signal_connect (m_widget, "switch_page", (see below)
80 // isn't deleted early enough
81 if ( child_frame
&& child_frame
->m_page
== page
)
86 node
= node
->GetNext();
92 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
93 event2
.SetEventObject( child
);
94 child
->GetEventHandler()->ProcessEvent( event2
);
98 //-----------------------------------------------------------------------------
100 //-----------------------------------------------------------------------------
102 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
104 void wxMDIParentFrame::Init()
106 m_justInserted
= false;
107 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
110 wxMDIParentFrame::~wxMDIParentFrame()
114 bool wxMDIParentFrame::Create(wxWindow
*parent
,
116 const wxString
& title
,
120 const wxString
& name
)
122 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
129 void wxMDIParentFrame::GtkOnSize()
131 wxFrame::GtkOnSize();
133 wxMDIChildFrame
*child_frame
= GetActiveChild();
134 if (!child_frame
) return;
136 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
137 if (!menu_bar
) return;
138 if (!menu_bar
->m_widget
) return;
142 menu_bar
->m_width
= m_width
;
143 menu_bar
->m_height
= wxMENU_HEIGHT
;
144 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
146 0, 0, m_width
, wxMENU_HEIGHT
);
149 void wxMDIParentFrame::OnInternalIdle()
151 /* if a an MDI child window has just been inserted
152 it has to be brought to the top in idle time. we
153 simply set the last notebook page active as new
154 pages can only be appended at the end */
158 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
159 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
161 /* need to set the menubar of the child */
162 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
163 if (active_child_frame
!= NULL
)
165 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
168 menu_bar
->m_width
= m_width
;
169 menu_bar
->m_height
= wxMENU_HEIGHT
;
170 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
172 0, 0, m_width
, wxMENU_HEIGHT
);
173 menu_bar
->SetInvokingWindow(active_child_frame
);
176 m_justInserted
= false;
180 wxFrame::OnInternalIdle();
182 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
183 bool visible_child_menu
= false;
185 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
188 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
192 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
195 if (child_frame
== active_child_frame
)
197 if (menu_bar
->Show(true))
199 menu_bar
->m_width
= m_width
;
200 menu_bar
->m_height
= wxMENU_HEIGHT
;
201 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
203 0, 0, m_width
, wxMENU_HEIGHT
);
204 menu_bar
->SetInvokingWindow( child_frame
);
206 visible_child_menu
= true;
210 if (menu_bar
->Show(false))
212 menu_bar
->UnsetInvokingWindow( child_frame
);
218 node
= node
->GetNext();
221 /* show/hide parent menu bar as required */
222 if ((m_frameMenuBar
) &&
223 (m_frameMenuBar
->IsShown() == visible_child_menu
))
225 if (visible_child_menu
)
227 m_frameMenuBar
->Show( false );
228 m_frameMenuBar
->UnsetInvokingWindow( this );
232 m_frameMenuBar
->Show( true );
233 m_frameMenuBar
->SetInvokingWindow( this );
235 m_frameMenuBar
->m_width
= m_width
;
236 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
237 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
238 m_frameMenuBar
->m_widget
,
239 0, 0, m_width
, wxMENU_HEIGHT
);
244 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
246 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
248 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
249 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
251 gint i
= gtk_notebook_get_current_page( notebook
);
252 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
254 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
255 if (!page
) return (wxMDIChildFrame
*) NULL
;
257 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
260 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
262 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
264 if (child_frame
->m_page
== page
)
266 node
= node
->GetNext();
269 return (wxMDIChildFrame
*) NULL
;
272 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
274 return m_clientWindow
;
277 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
279 m_clientWindow
= new wxMDIClientWindow( this );
280 return m_clientWindow
;
283 void wxMDIParentFrame::ActivateNext()
286 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
289 void wxMDIParentFrame::ActivatePrevious()
292 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
295 //-----------------------------------------------------------------------------
297 //-----------------------------------------------------------------------------
299 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
301 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
302 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
303 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
306 wxMDIChildFrame::wxMDIChildFrame()
308 m_menuBar
= (wxMenuBar
*) NULL
;
309 m_page
= (GtkNotebookPage
*) NULL
;
312 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
313 wxWindowID id
, const wxString
& title
,
314 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
315 long style
, const wxString
& name
)
317 m_menuBar
= (wxMenuBar
*) NULL
;
318 m_page
= (GtkNotebookPage
*) NULL
;
319 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
322 wxMDIChildFrame::~wxMDIChildFrame()
328 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
329 wxWindowID id
, const wxString
& title
,
330 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
331 long style
, const wxString
& name
)
335 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
338 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
340 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
343 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
345 wxWindow::DoSetClientSize( width
, height
);
348 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
350 wxWindow::DoGetClientSize( width
, height
);
353 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
355 wxWindow::AddChild(child
);
358 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
360 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
362 m_menuBar
= menu_bar
;
366 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
368 m_menuBar
->SetParent( mdi_frame
);
370 /* insert the invisible menu bar into the _parent_ mdi frame */
371 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
373 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
377 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
382 void wxMDIChildFrame::Activate()
384 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
385 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
386 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
387 gtk_notebook_set_current_page( notebook
, pageno
);
390 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
394 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
397 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
398 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
400 // we don't have any help text for this item, but may be the MDI frame
402 mdi_frame
->OnMenuHighlight(event
);
404 #endif // wxUSE_STATUSBAR
407 void wxMDIChildFrame::SetTitle( const wxString
&title
)
409 if ( title
== m_title
)
414 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
415 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
416 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
419 //-----------------------------------------------------------------------------
421 //-----------------------------------------------------------------------------
424 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
426 if (g_isIdle
) wxapp_install_idle_handler();
428 if ((win
->m_x
== alloc
->x
) &&
429 (win
->m_y
== alloc
->y
) &&
430 (win
->m_width
== alloc
->width
) &&
431 (win
->m_height
== alloc
->height
) &&
437 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
441 //-----------------------------------------------------------------------------
442 // InsertChild callback for wxMDIClientWindow
443 //-----------------------------------------------------------------------------
445 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
447 wxString s
= child
->GetTitle();
448 if (s
.IsNull()) s
= _("MDI child");
450 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
451 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
453 g_signal_connect (child
->m_widget
, "size_allocate",
454 G_CALLBACK (gtk_page_size_callback
), child
);
456 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
458 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
460 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
462 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
463 parent_frame
->m_justInserted
= true;
466 //-----------------------------------------------------------------------------
468 //-----------------------------------------------------------------------------
470 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
472 wxMDIClientWindow::wxMDIClientWindow()
476 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
478 CreateClient( parent
, style
);
481 wxMDIClientWindow::~wxMDIClientWindow()
486 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
490 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
492 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
493 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
495 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
499 m_widget
= gtk_notebook_new();
501 g_signal_connect (m_widget
, "switch_page",
502 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
504 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
506 m_parent
->DoAddChild( this );