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( int x
, int y
, int width
, int height
)
131 wxFrame::GtkOnSize( x
, y
, width
, height
);
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 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
246 wxFrame::DoGetClientSize( width
, height
);
249 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
251 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
253 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
254 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
256 gint i
= gtk_notebook_get_current_page( notebook
);
257 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
259 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
260 if (!page
) return (wxMDIChildFrame
*) NULL
;
262 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
265 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
267 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
269 if (child_frame
->m_page
== page
)
271 node
= node
->GetNext();
274 return (wxMDIChildFrame
*) NULL
;
277 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
279 return m_clientWindow
;
282 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
284 m_clientWindow
= new wxMDIClientWindow( this );
285 return m_clientWindow
;
288 void wxMDIParentFrame::ActivateNext()
291 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
294 void wxMDIParentFrame::ActivatePrevious()
297 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
300 //-----------------------------------------------------------------------------
302 //-----------------------------------------------------------------------------
304 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
306 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
307 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
308 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
311 wxMDIChildFrame::wxMDIChildFrame()
313 m_menuBar
= (wxMenuBar
*) NULL
;
314 m_page
= (GtkNotebookPage
*) NULL
;
317 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
318 wxWindowID id
, const wxString
& title
,
319 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
320 long style
, const wxString
& name
)
322 m_menuBar
= (wxMenuBar
*) NULL
;
323 m_page
= (GtkNotebookPage
*) NULL
;
324 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
327 wxMDIChildFrame::~wxMDIChildFrame()
333 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
334 wxWindowID id
, const wxString
& title
,
335 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
336 long style
, const wxString
& name
)
340 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
343 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
345 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
348 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
350 wxWindow::DoSetClientSize( width
, height
);
353 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
355 wxWindow::DoGetClientSize( width
, height
);
358 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
360 wxWindow::AddChild(child
);
363 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
365 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
367 m_menuBar
= menu_bar
;
371 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
373 m_menuBar
->SetParent( mdi_frame
);
375 /* insert the invisible menu bar into the _parent_ mdi frame */
376 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
378 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
382 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
387 void wxMDIChildFrame::Activate()
389 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
390 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
391 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
392 gtk_notebook_set_current_page( notebook
, pageno
);
395 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
399 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
402 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
403 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
405 // we don't have any help text for this item, but may be the MDI frame
407 mdi_frame
->OnMenuHighlight(event
);
409 #endif // wxUSE_STATUSBAR
412 void wxMDIChildFrame::SetTitle( const wxString
&title
)
414 if ( title
== m_title
)
419 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
420 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
421 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
424 //-----------------------------------------------------------------------------
426 //-----------------------------------------------------------------------------
429 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
431 if (g_isIdle
) wxapp_install_idle_handler();
433 if ((win
->m_x
== alloc
->x
) &&
434 (win
->m_y
== alloc
->y
) &&
435 (win
->m_width
== alloc
->width
) &&
436 (win
->m_height
== alloc
->height
) &&
442 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
446 //-----------------------------------------------------------------------------
447 // InsertChild callback for wxMDIClientWindow
448 //-----------------------------------------------------------------------------
450 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
452 wxString s
= child
->GetTitle();
453 if (s
.IsNull()) s
= _("MDI child");
455 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
456 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
458 g_signal_connect (child
->m_widget
, "size_allocate",
459 G_CALLBACK (gtk_page_size_callback
), child
);
461 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
463 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
465 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
467 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
468 parent_frame
->m_justInserted
= true;
471 //-----------------------------------------------------------------------------
473 //-----------------------------------------------------------------------------
475 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
477 wxMDIClientWindow::wxMDIClientWindow()
481 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
483 CreateClient( parent
, style
);
486 wxMDIClientWindow::~wxMDIClientWindow()
491 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
495 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
497 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
498 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
500 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
504 m_widget
= gtk_notebook_new();
506 g_signal_connect (m_widget
, "switch_page",
507 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
509 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
511 m_parent
->DoAddChild( this );