1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/mdi.cpp
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
19 #include "wx/dialog.h"
22 #include "wx/notebook.h"
23 #include "wx/gtk1/private.h"
28 #include "wx/gtk1/win_gtk.h"
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
34 const int wxMENU_HEIGHT
= 27;
36 //-----------------------------------------------------------------------------
38 //-----------------------------------------------------------------------------
40 extern void wxapp_install_idle_handler();
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
53 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
54 GtkNotebookPage
*page
,
55 gint
WXUNUSED(page_num
),
56 wxMDIParentFrame
*parent
)
59 wxapp_install_idle_handler();
61 // send deactivate event to old child
63 wxMDIChildFrame
*child
= parent
->GetActiveChild();
66 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
67 event1
.SetEventObject( child
);
68 child
->HandleWindowEvent( event1
);
71 // send activate event to new child
73 wxMDIClientWindowBase
* const client_window
= parent
->GetClientWindow();
79 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
82 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
83 // CE: we come here in the destructor with a null child_frame - I think because
84 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
85 // isn't deleted early enough
89 if (child_frame
->m_page
== page
)
94 node
= node
->GetNext();
100 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
101 event2
.SetEventObject( child
);
102 child
->HandleWindowEvent( event2
);
106 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
110 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
112 void wxMDIParentFrame::Init()
114 m_justInserted
= false;
115 m_clientWindow
= NULL
;
118 bool wxMDIParentFrame::Create(wxWindow
*parent
,
120 const wxString
& title
,
124 const wxString
& name
)
126 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
129 m_clientWindow
= OnCreateClient();
130 if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) )
136 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
138 wxFrame::GtkOnSize( x
, y
, width
, height
);
140 wxMDIChildFrame
*child_frame
= GetActiveChild();
141 if (!child_frame
) return;
143 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
144 if (!menu_bar
) return;
145 if (!menu_bar
->m_widget
) return;
149 menu_bar
->m_width
= m_width
;
150 menu_bar
->m_height
= wxMENU_HEIGHT
;
151 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
153 0, 0, m_width
, wxMENU_HEIGHT
);
156 void wxMDIParentFrame::OnInternalIdle()
158 /* if a an MDI child window has just been inserted
159 it has to be brought to the top in idle time. we
160 simply set the last notebook page active as new
161 pages can only be appended at the end */
165 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
166 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
168 /* need to set the menubar of the child */
169 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
170 if (active_child_frame
!= NULL
)
172 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
175 menu_bar
->m_width
= m_width
;
176 menu_bar
->m_height
= wxMENU_HEIGHT
;
177 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
179 0, 0, m_width
, wxMENU_HEIGHT
);
180 menu_bar
->Attach(active_child_frame
);
183 m_justInserted
= false;
187 wxFrame::OnInternalIdle();
189 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
190 bool visible_child_menu
= false;
192 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
195 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
199 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
202 if (child_frame
== active_child_frame
)
204 if (menu_bar
->Show(true))
206 menu_bar
->m_width
= m_width
;
207 menu_bar
->m_height
= wxMENU_HEIGHT
;
208 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
210 0, 0, m_width
, wxMENU_HEIGHT
);
212 // Attach() asserts if we call it for an already
213 // attached menu bar so don't do it if we're already
214 // associated with this frame (it would be nice to get
215 // rid of this check and ensure that this doesn't
217 if ( menu_bar
->GetFrame() != child_frame
)
218 menu_bar
->Attach( child_frame
);
220 visible_child_menu
= true;
224 if (menu_bar
->Show(false))
232 node
= node
->GetNext();
235 /* show/hide parent menu bar as required */
236 if ((m_frameMenuBar
) &&
237 (m_frameMenuBar
->IsShown() == visible_child_menu
))
239 if (visible_child_menu
)
241 m_frameMenuBar
->Show( false );
242 m_frameMenuBar
->Detach();
246 m_frameMenuBar
->Show( true );
247 m_frameMenuBar
->Attach( this );
249 m_frameMenuBar
->m_width
= m_width
;
250 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
251 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
252 m_frameMenuBar
->m_widget
,
253 0, 0, m_width
, wxMENU_HEIGHT
);
258 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
260 if (!m_clientWindow
) return NULL
;
262 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
263 if (!notebook
) return NULL
;
265 gint i
= gtk_notebook_get_current_page( notebook
);
266 if (i
< 0) return NULL
;
268 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
269 if (!page
) return NULL
;
271 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
274 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
276 wxASSERT_MSG( child_frame
, wxT("child is not a wxMDIChildFrame") );
278 if (child_frame
->m_page
== page
)
280 node
= node
->GetNext();
286 void wxMDIParentFrame::ActivateNext()
289 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
292 void wxMDIParentFrame::ActivatePrevious()
295 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
298 //-----------------------------------------------------------------------------
300 //-----------------------------------------------------------------------------
302 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
304 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
305 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
306 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
309 void wxMDIChildFrame::Init()
315 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
316 wxWindowID id
, const wxString
& title
,
317 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
318 long style
, const wxString
& name
)
322 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
325 wxMDIChildFrame::~wxMDIChildFrame()
330 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
332 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
334 m_menuBar
= menu_bar
;
338 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
340 m_menuBar
->SetParent( mdi_frame
);
342 /* insert the invisible menu bar into the _parent_ mdi frame */
343 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
345 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
349 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
354 GtkNotebook
*wxMDIChildFrame::GTKGetNotebook() const
356 wxMDIClientWindow
* const
357 client
= wxStaticCast(GetParent(), wxMDIClientWindow
);
358 wxCHECK( client
, NULL
);
360 return GTK_NOTEBOOK(client
->m_widget
);
363 void wxMDIChildFrame::Activate()
365 GtkNotebook
* const notebook
= GTKGetNotebook();
366 wxCHECK_RET( notebook
, "no parent notebook?" );
368 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
369 gtk_notebook_set_page( notebook
, pageno
);
372 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
376 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
379 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
380 if ( !ShowMenuHelp(event
.GetMenuId()) )
382 // we don't have any help text for this item, but may be the MDI frame
384 mdi_frame
->OnMenuHighlight(event
);
386 #endif // wxUSE_STATUSBAR
389 void wxMDIChildFrame::SetTitle( const wxString
&title
)
391 if ( title
== m_title
)
396 GtkNotebook
* const notebook
= GTKGetNotebook();
397 wxCHECK_RET( notebook
, "no parent notebook?" );
399 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
402 //-----------------------------------------------------------------------------
404 //-----------------------------------------------------------------------------
407 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
409 if (g_isIdle
) wxapp_install_idle_handler();
411 if ((win
->m_x
== alloc
->x
) &&
412 (win
->m_y
== alloc
->y
) &&
413 (win
->m_width
== alloc
->width
) &&
414 (win
->m_height
== alloc
->height
) &&
420 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
424 //-----------------------------------------------------------------------------
425 // InsertChild callback for wxMDIClientWindow
426 //-----------------------------------------------------------------------------
428 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
430 wxString s
= child
->GetTitle();
431 if ( s
.empty() ) s
= _("MDI child");
433 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
434 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
436 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
437 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
439 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
441 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
443 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
445 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
446 parent_frame
->m_justInserted
= true;
449 //-----------------------------------------------------------------------------
451 //-----------------------------------------------------------------------------
453 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
455 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
459 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
461 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
462 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
464 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
468 m_widget
= gtk_notebook_new();
470 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
471 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
473 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
475 m_parent
->DoAddChild( this );