]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Disable wxUSE_ENH_METAFILE for wxGTK builds.
[wxWidgets.git] / src / gtk / mdi.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
72c23f8e 2// Name: src/gtk/mdi.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
a81258be
RR
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
88a7a4e1
WS
13#if wxUSE_MDI
14
c801d85f 15#include "wx/mdi.h"
dcf924a3 16
88a7a4e1
WS
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
3b3dc801 19 #include "wx/menu.h"
88a7a4e1 20#endif
dcf924a3 21
fab591c5 22#include "wx/gtk/private.h"
716b7364 23
5e014a0c
RR
24//-----------------------------------------------------------------------------
25// "switch_page"
26//-----------------------------------------------------------------------------
27
865bb325 28extern "C" {
f6bcfd97 29static void
385e8575 30switch_page(GtkNotebook* widget, GtkNotebookPage*, guint page_num, wxMDIParentFrame* parent)
5e014a0c 31{
e90196a5
RR
32 // send deactivate event to old child
33
5e014a0c 34 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
35 if (child)
36 {
b1d4dd7a 37 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5 38 event1.SetEventObject( child);
937013e0 39 child->HandleWindowEvent( event1 );
e90196a5 40 }
f6bcfd97 41
e90196a5 42 // send activate event to new child
f6bcfd97 43
d2824cdb
VZ
44 wxMDIClientWindowBase *client_window = parent->GetClientWindow();
45 if ( !client_window )
e90196a5
RR
46 return;
47
d2824cdb 48 child = NULL;
385e8575 49 GtkWidget* page = gtk_notebook_get_nth_page(widget, page_num);
e90196a5 50
222ed1d6 51 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
af6c0f1d 52 while ( node )
e90196a5 53 {
b1d4dd7a 54 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
b1d4dd7a 55
af6c0f1d
VZ
56 // child_frame can be NULL when this is called from dtor, probably
57 // because g_signal_connect (m_widget, "switch_page", (see below)
58 // isn't deleted early enough
385e8575 59 if (child_frame && child_frame->m_widget == page)
f6bcfd97 60 {
e90196a5 61 child = child_frame;
f6bcfd97
BP
62 break;
63 }
b1d4dd7a 64 node = node->GetNext();
e90196a5 65 }
f6bcfd97 66
e90196a5
RR
67 if (!child)
68 return;
f6bcfd97 69
b1d4dd7a 70 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5 71 event2.SetEventObject( child);
937013e0 72 child->HandleWindowEvent( event2 );
5e014a0c 73}
865bb325 74}
5e014a0c 75
6ca41e57
RR
76//-----------------------------------------------------------------------------
77// wxMDIParentFrame
33d0b396
RR
78//-----------------------------------------------------------------------------
79
c801d85f
KB
80IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
81
f6bcfd97 82void wxMDIParentFrame::Init()
c801d85f 83{
b1d4dd7a 84 m_justInserted = false;
ff7b1510 85}
c801d85f 86
f6bcfd97
BP
87bool wxMDIParentFrame::Create(wxWindow *parent,
88 wxWindowID id,
89 const wxString& title,
90 const wxPoint& pos,
91 const wxSize& size,
92 long style,
93 const wxString& name )
c801d85f 94{
6e42617a
VZ
95 if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
96 return false;
a3622daa 97
6e42617a 98 m_clientWindow = OnCreateClient();
d2824cdb
VZ
99 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
100 return false;
a3622daa 101
d2824cdb 102 return true;
ff7b1510 103}
c801d85f 104
ab2b3dd4
RR
105void wxMDIParentFrame::OnInternalIdle()
106{
d2824cdb 107 /* if a MDI child window has just been inserted
ab2b3dd4
RR
108 it has to be brought to the top in idle time. we
109 simply set the last notebook page active as new
110 pages can only be appended at the end */
111
112 if (m_justInserted)
83624f79 113 {
a2053b27 114 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
385e8575 115 gtk_notebook_set_current_page(notebook, -1);
a0fdacee 116
147d6669 117 /* need to set the menubar of the child */
1d608029 118 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 119 if (active_child_frame != NULL)
147d6669 120 {
1b10056f
RD
121 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
122 if (menu_bar)
123 {
6abf7b63 124 menu_bar->Attach(active_child_frame);
1b10056f 125 }
147d6669 126 }
b1d4dd7a 127 m_justInserted = false;
a0fdacee 128 return;
83624f79 129 }
a0fdacee 130
ab2b3dd4 131 wxFrame::OnInternalIdle();
c626a8b7 132
ab2b3dd4 133 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 134 bool visible_child_menu = false;
a0fdacee 135
222ed1d6 136 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 137 while (node)
83624f79 138 {
b1d4dd7a
RL
139 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
140
f6bcfd97 141 if ( child_frame )
a0fdacee 142 {
f6bcfd97
BP
143 wxMenuBar *menu_bar = child_frame->m_menuBar;
144 if ( menu_bar )
f03fc89f 145 {
f6bcfd97
BP
146 if (child_frame == active_child_frame)
147 {
b1d4dd7a 148 if (menu_bar->Show(true))
f6bcfd97 149 {
6abf7b63
VZ
150 // Attach() asserts if we call it for an already
151 // attached menu bar so don't do it if we're already
152 // associated with this frame (it would be nice to get
153 // rid of this check and ensure that this doesn't
154 // happen...)
155 if ( menu_bar->GetFrame() != child_frame )
156 menu_bar->Attach( child_frame );
f6bcfd97 157 }
b1d4dd7a 158 visible_child_menu = true;
f6bcfd97
BP
159 }
160 else
161 {
b1d4dd7a 162 if (menu_bar->Show(false))
f6bcfd97 163 {
6abf7b63 164 menu_bar->Detach();
f6bcfd97
BP
165 }
166 }
f03fc89f 167 }
a0fdacee 168 }
f6bcfd97 169
b1d4dd7a 170 node = node->GetNext();
83624f79 171 }
a0fdacee 172
e27ce4e9 173 /* show/hide parent menu bar as required */
5bd9e519
RR
174 if ((m_frameMenuBar) &&
175 (m_frameMenuBar->IsShown() == visible_child_menu))
176 {
177 if (visible_child_menu)
f6bcfd97 178 {
b1d4dd7a 179 m_frameMenuBar->Show( false );
6abf7b63 180 m_frameMenuBar->Detach();
f6bcfd97
BP
181 }
182 else
183 {
b1d4dd7a 184 m_frameMenuBar->Show( true );
6abf7b63 185 m_frameMenuBar->Attach( this );
cca410b3
PC
186 }
187 }
188}
f6bcfd97 189
cca410b3
PC
190void wxMDIParentFrame::DoGetClientSize(int* width, int* height) const
191{
192 wxFrame::DoGetClientSize(width, height);
193
b0d053c1 194 if (!m_useCachedClientSize && height)
cca410b3
PC
195 {
196 wxMDIChildFrame* active_child_frame = GetActiveChild();
197 if (active_child_frame)
198 {
199 wxMenuBar* menubar = active_child_frame->m_menuBar;
200 if (menubar && menubar->IsShown())
201 {
202 GtkRequisition req;
1897abe1 203 gtk_widget_get_preferred_height(menubar->m_widget, NULL, &req.height);
cca410b3
PC
204 *height -= req.height;
205 if (*height < 0) *height = 0;
206 }
f6bcfd97 207 }
5bd9e519 208 }
ff7b1510 209}
716b7364 210
ab2b3dd4
RR
211wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
212{
d2824cdb 213 if (!m_clientWindow) return NULL;
a0fdacee 214
a2053b27 215 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
d2824cdb 216 if (!notebook) return NULL;
a0fdacee 217
ab2b3dd4 218 gint i = gtk_notebook_get_current_page( notebook );
d2824cdb 219 if (i < 0) return NULL;
f4322df6 220
385e8575 221 GtkWidget* page = gtk_notebook_get_nth_page(notebook, i);
d2824cdb 222 if (!page) return NULL;
a0fdacee 223
222ed1d6 224 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
225 while (node)
226 {
3811dacb 227 if ( wxPendingDelete.Member(node->GetData()) )
d2824cdb 228 return NULL;
f4322df6 229
b1d4dd7a
RL
230 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
231
3811dacb 232 if (!child_frame)
d2824cdb 233 return NULL;
b1d4dd7a 234
385e8575 235 if (child_frame->m_widget == page)
ab2b3dd4 236 return child_frame;
f4322df6 237
b1d4dd7a 238 node = node->GetNext();
ab2b3dd4 239 }
a0fdacee 240
d2824cdb 241 return NULL;
ff7b1510 242}
c801d85f 243
ab2b3dd4 244void wxMDIParentFrame::ActivateNext()
c801d85f 245{
83624f79 246 if (m_clientWindow)
a2053b27 247 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 248}
c801d85f 249
ab2b3dd4 250void wxMDIParentFrame::ActivatePrevious()
716b7364 251{
83624f79 252 if (m_clientWindow)
a2053b27 253 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 254}
716b7364 255
c801d85f
KB
256//-----------------------------------------------------------------------------
257// wxMDIChildFrame
258//-----------------------------------------------------------------------------
259
cf4219e7 260IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 261
cf4219e7 262BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 263 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 264 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
265END_EVENT_TABLE()
266
d2824cdb 267void wxMDIChildFrame::Init()
c801d85f 268{
d2824cdb 269 m_menuBar = NULL;
ff7b1510 270}
c801d85f 271
d2824cdb
VZ
272bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
273 wxWindowID id,
274 const wxString& title,
275 const wxPoint& WXUNUSED(pos),
276 const wxSize& size,
277 long style,
278 const wxString& name)
c801d85f 279{
d2824cdb
VZ
280 m_mdiParent = parent;
281 m_title = title;
282
283 return wxWindow::Create(parent->GetClientWindow(), id,
284 wxDefaultPosition, size,
285 style, name);
ff7b1510 286}
c801d85f 287
ab2b3dd4 288wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 289{
d2824cdb 290 delete m_menuBar;
002626c5
PC
291
292 // wxMDIClientWindow does not get redrawn properly after last child is removed
293 if (m_parent && m_parent->GetChildren().size() <= 1)
294 gtk_widget_queue_draw(m_parent->m_widget);
72c23f8e 295}
c801d85f 296
3ec3c160
PC
297void wxMDIChildFrame::GTKHandleRealized()
298{
299 // since m_widget is not a GtkWindow, must bypass wxTopLevelWindowGTK
300 wxTopLevelWindowBase::GTKHandleRealized();
301}
302
716b7364
RR
303void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
304{
d2824cdb 305 wxASSERT_MSG( m_menuBar == NULL, "Only one menubar allowed" );
5bd9e519 306
83624f79 307 m_menuBar = menu_bar;
a3622daa 308
83624f79 309 if (m_menuBar)
716b7364 310 {
f03fc89f 311 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 312
5bd9e519 313 m_menuBar->SetParent( mdi_frame );
c626a8b7 314
ab2b3dd4 315 /* insert the invisible menu bar into the _parent_ mdi frame */
cca410b3
PC
316 m_menuBar->Show(false);
317 gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
318 gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
cca410b3 319 gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
716b7364 320 }
ff7b1510 321}
cf4219e7 322
33b64e6f 323wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 324{
83624f79 325 return m_menuBar;
ff7b1510 326}
c801d85f 327
d2824cdb
VZ
328GtkNotebook *wxMDIChildFrame::GTKGetNotebook() const
329{
330 wxMDIClientWindow * const
331 client = wxStaticCast(GetParent(), wxMDIClientWindow);
332 wxCHECK( client, NULL );
333
334 return GTK_NOTEBOOK(client->m_widget);
335}
336
ab2b3dd4 337void wxMDIChildFrame::Activate()
c801d85f 338{
d2824cdb
VZ
339 GtkNotebook * const notebook = GTKGetNotebook();
340 wxCHECK_RET( notebook, "no parent notebook?" );
341
9e691f46 342 gint pageno = gtk_notebook_page_num( notebook, m_widget );
38f1df7c 343 gtk_notebook_set_current_page( notebook, pageno );
ff7b1510 344}
c801d85f 345
f6bcfd97
BP
346void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
347{
348}
349
350void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 351{
f6bcfd97
BP
352#if wxUSE_STATUSBAR
353 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 354 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
355 {
356 // we don't have any help text for this item, but may be the MDI frame
357 // does?
358 mdi_frame->OnMenuHighlight(event);
359 }
360#endif // wxUSE_STATUSBAR
361}
362
363void wxMDIChildFrame::SetTitle( const wxString &title )
364{
365 if ( title == m_title )
366 return;
367
368 m_title = title;
369
d2824cdb
VZ
370 GtkNotebook * const notebook = GTKGetNotebook();
371 wxCHECK_RET( notebook, "no parent notebook?" );
fab591c5 372 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 373}
9746a2ba 374
c801d85f
KB
375//-----------------------------------------------------------------------------
376// wxMDIClientWindow
377//-----------------------------------------------------------------------------
378
d2824cdb 379IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
c801d85f 380
5a0a15cf
FM
381wxMDIClientWindow::~wxMDIClientWindow()
382{
383 // disconnect our handler because our ~wxWindow (which is going to be called
384 // after this dtor) will call DestroyChildren(); in turns our children
385 // ~wxWindow dtors will call wxWindow::Show(false) and this will generate
386 // a call to gtk_mdi_page_change_callback with an invalid parent
387 // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but
388 // at that point of the dtor chain we are a simple wxWindow!)
385e8575 389 g_signal_handlers_disconnect_by_func(m_widget, (void*)switch_page, GetParent());
5a0a15cf
FM
390}
391
d2824cdb 392bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
c801d85f 393{
d2824cdb
VZ
394 if ( !PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
395 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
396 style, wxDefaultValidator, "wxMDIClientWindow" ))
4dcaf11a 397 {
d2824cdb 398 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
b1d4dd7a 399 return false;
4dcaf11a 400 }
c801d85f 401
83624f79 402 m_widget = gtk_notebook_new();
9ff9d30c 403 g_object_ref(m_widget);
a3622daa 404
385e8575 405 g_signal_connect(m_widget, "switch_page", G_CALLBACK(switch_page), parent);
5e014a0c 406
83624f79 407 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 408
f03fc89f 409 m_parent->DoAddChild( this );
c626a8b7 410
83624f79 411 PostCreation();
a3622daa 412
b1d4dd7a 413 Show( true );
a3622daa 414
b1d4dd7a 415 return true;
ff7b1510 416}
c801d85f 417
d2824cdb
VZ
418void wxMDIClientWindow::AddChildGTK(wxWindowGTK* child)
419{
420 wxMDIChildFrame* child_frame = static_cast<wxMDIChildFrame*>(child);
421 wxString s = child_frame->GetTitle();
422 if ( s.empty() )
423 s = _("MDI child");
424
425 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
426 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
427
428 GtkNotebook* notebook = GTK_NOTEBOOK(m_widget);
429
430 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
431
d2824cdb
VZ
432 wxMDIParentFrame* parent_frame = static_cast<wxMDIParentFrame*>(GetParent());
433 parent_frame->m_justInserted = true;
434}
435
e8375af8 436#endif // wxUSE_MDI