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
->HandleWindowEvent( event1
);
72 // send activate event to new child
74 wxMDIClientWindowBase
* const client_window
= parent
->GetClientWindow();
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
->HandleWindowEvent( event2
);
107 //-----------------------------------------------------------------------------
109 //-----------------------------------------------------------------------------
111 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
113 void wxMDIParentFrame::Init()
115 m_justInserted
= false;
116 m_clientWindow
= NULL
;
119 bool wxMDIParentFrame::Create(wxWindow
*parent
,
121 const wxString
& title
,
125 const wxString
& name
)
127 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
130 m_clientWindow
= OnCreateClient();
131 if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) )
137 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
139 wxFrame::GtkOnSize( x
, y
, width
, height
);
141 wxMDIChildFrame
*child_frame
= GetActiveChild();
142 if (!child_frame
) return;
144 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
145 if (!menu_bar
) return;
146 if (!menu_bar
->m_widget
) return;
150 menu_bar
->m_width
= m_width
;
151 menu_bar
->m_height
= wxMENU_HEIGHT
;
152 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
154 0, 0, m_width
, wxMENU_HEIGHT
);
157 void wxMDIParentFrame::OnInternalIdle()
159 /* if a an MDI child window has just been inserted
160 it has to be brought to the top in idle time. we
161 simply set the last notebook page active as new
162 pages can only be appended at the end */
166 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
167 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
169 /* need to set the menubar of the child */
170 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
171 if (active_child_frame
!= NULL
)
173 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
176 menu_bar
->m_width
= m_width
;
177 menu_bar
->m_height
= wxMENU_HEIGHT
;
178 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
180 0, 0, m_width
, wxMENU_HEIGHT
);
181 menu_bar
->SetInvokingWindow(active_child_frame
);
184 m_justInserted
= false;
188 wxFrame::OnInternalIdle();
190 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
191 bool visible_child_menu
= false;
193 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
196 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
200 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
203 if (child_frame
== active_child_frame
)
205 if (menu_bar
->Show(true))
207 menu_bar
->m_width
= m_width
;
208 menu_bar
->m_height
= wxMENU_HEIGHT
;
209 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
211 0, 0, m_width
, wxMENU_HEIGHT
);
212 menu_bar
->SetInvokingWindow( child_frame
);
214 visible_child_menu
= true;
218 if (menu_bar
->Show(false))
220 menu_bar
->UnsetInvokingWindow( child_frame
);
226 node
= node
->GetNext();
229 /* show/hide parent menu bar as required */
230 if ((m_frameMenuBar
) &&
231 (m_frameMenuBar
->IsShown() == visible_child_menu
))
233 if (visible_child_menu
)
235 m_frameMenuBar
->Show( false );
236 m_frameMenuBar
->UnsetInvokingWindow( this );
240 m_frameMenuBar
->Show( true );
241 m_frameMenuBar
->SetInvokingWindow( this );
243 m_frameMenuBar
->m_width
= m_width
;
244 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
245 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
246 m_frameMenuBar
->m_widget
,
247 0, 0, m_width
, wxMENU_HEIGHT
);
252 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
254 if (!m_clientWindow
) return NULL
;
256 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
257 if (!notebook
) return NULL
;
259 gint i
= gtk_notebook_get_current_page( notebook
);
260 if (i
< 0) return NULL
;
262 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
263 if (!page
) return NULL
;
265 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
268 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
270 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
272 if (child_frame
->m_page
== page
)
274 node
= node
->GetNext();
280 void wxMDIParentFrame::ActivateNext()
283 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
286 void wxMDIParentFrame::ActivatePrevious()
289 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
292 //-----------------------------------------------------------------------------
294 //-----------------------------------------------------------------------------
296 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
298 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
299 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
300 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
303 void wxMDIChildFrame::Init()
309 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
310 wxWindowID id
, const wxString
& title
,
311 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
312 long style
, const wxString
& name
)
316 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
319 wxMDIChildFrame::~wxMDIChildFrame()
324 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
326 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
328 m_menuBar
= menu_bar
;
332 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
334 m_menuBar
->SetParent( mdi_frame
);
336 /* insert the invisible menu bar into the _parent_ mdi frame */
337 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
339 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
343 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
348 GtkNotebook
*wxMDIChildFrame::GTKGetNotebook() const
350 wxMDIClientWindow
* const
351 client
= wxStaticCast(GetParent(), wxMDIClientWindow
);
352 wxCHECK( client
, NULL
);
354 return GTK_NOTEBOOK(client
->m_widget
);
357 void wxMDIChildFrame::Activate()
359 GtkNotebook
* const notebook
= GTKGetNotebook();
360 wxCHECK_RET( notebook
, "no parent notebook?" );
362 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
363 gtk_notebook_set_page( notebook
, pageno
);
366 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
370 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
373 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
374 if ( !ShowMenuHelp(event
.GetMenuId()) )
376 // we don't have any help text for this item, but may be the MDI frame
378 mdi_frame
->OnMenuHighlight(event
);
380 #endif // wxUSE_STATUSBAR
383 void wxMDIChildFrame::SetTitle( const wxString
&title
)
385 if ( title
== m_title
)
390 GtkNotebook
* const notebook
= GTKGetNotebook();
391 wxCHECK_RET( notebook
, "no parent notebook?" );
393 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
396 //-----------------------------------------------------------------------------
398 //-----------------------------------------------------------------------------
401 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
403 if (g_isIdle
) wxapp_install_idle_handler();
405 if ((win
->m_x
== alloc
->x
) &&
406 (win
->m_y
== alloc
->y
) &&
407 (win
->m_width
== alloc
->width
) &&
408 (win
->m_height
== alloc
->height
) &&
414 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
418 //-----------------------------------------------------------------------------
419 // InsertChild callback for wxMDIClientWindow
420 //-----------------------------------------------------------------------------
422 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
424 wxString s
= child
->GetTitle();
425 if (s
.IsNull()) s
= _("MDI child");
427 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
428 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
430 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
431 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
433 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
435 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
437 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
439 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
440 parent_frame
->m_justInserted
= true;
443 //-----------------------------------------------------------------------------
445 //-----------------------------------------------------------------------------
447 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
449 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
453 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
455 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
456 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
458 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
462 m_widget
= gtk_notebook_new();
464 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
465 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
467 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
469 m_parent
->DoAddChild( this );