]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/mdi.cpp
Fix memory leak when a spacer is added, and crash when a window is added before wxSiz...
[wxWidgets.git] / src / gtk1 / mdi.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: mdi.cpp
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 10#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
c801d85f
KB
11#pragma implementation "mdi.h"
12#endif
13
14f355c2
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
c801d85f 17#include "wx/mdi.h"
1631916e 18#include "wx/notebook.h"
dcf924a3 19
efd17a1d 20#if wxUSE_MDI
dcf924a3 21
e3e65dac 22#include "wx/dialog.h"
cf4219e7 23#include "wx/menu.h"
3096bd2f 24#include "wx/intl.h"
fab591c5 25#include "wx/gtk/private.h"
716b7364 26
16c1f79c
RR
27#include <glib.h>
28#include <gdk/gdk.h>
29#include <gtk/gtk.h>
83624f79
RR
30#include "wx/gtk/win_gtk.h"
31
6ca41e57
RR
32//-----------------------------------------------------------------------------
33// constants
34//-----------------------------------------------------------------------------
35
a0fdacee 36const int wxMENU_HEIGHT = 27;
6ca41e57 37
acfd422a
RR
38//-----------------------------------------------------------------------------
39// idle system
40//-----------------------------------------------------------------------------
41
42extern void wxapp_install_idle_handler();
43extern bool g_isIdle;
44
6ca41e57
RR
45//-----------------------------------------------------------------------------
46// globals
716b7364
RR
47//-----------------------------------------------------------------------------
48
49extern wxList wxPendingDelete;
c801d85f 50
5e014a0c
RR
51//-----------------------------------------------------------------------------
52// "switch_page"
53//-----------------------------------------------------------------------------
54
865bb325 55extern "C" {
f6bcfd97 56static void
7941ba11 57gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5 58 GtkNotebookPage *page,
f6bcfd97
BP
59 gint WXUNUSED(page_num),
60 wxMDIParentFrame *parent )
5e014a0c 61{
f6bcfd97 62 if (g_isIdle)
5e014a0c
RR
63 wxapp_install_idle_handler();
64
e90196a5
RR
65 // send deactivate event to old child
66
5e014a0c 67 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
68 if (child)
69 {
b1d4dd7a 70 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5
RR
71 event1.SetEventObject( child);
72 child->GetEventHandler()->ProcessEvent( event1 );
73 }
f6bcfd97 74
e90196a5 75 // send activate event to new child
f6bcfd97 76
e90196a5
RR
77 wxMDIClientWindow *client_window = parent->GetClientWindow();
78 if (!client_window)
79 return;
80
81 child = (wxMDIChildFrame*) NULL;
82
222ed1d6 83 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
e90196a5
RR
84 while (node)
85 {
b1d4dd7a 86 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
1631916e
CE
87 // CE: we come here in the destructor with a null child_frame - I think because
88 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
89 // isn't deleted early enough
90 if (!child_frame)
91 return ;
b1d4dd7a 92
e90196a5 93 if (child_frame->m_page == page)
f6bcfd97 94 {
e90196a5 95 child = child_frame;
f6bcfd97
BP
96 break;
97 }
b1d4dd7a 98 node = node->GetNext();
e90196a5 99 }
f6bcfd97 100
e90196a5
RR
101 if (!child)
102 return;
f6bcfd97 103
b1d4dd7a 104 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5
RR
105 event2.SetEventObject( child);
106 child->GetEventHandler()->ProcessEvent( event2 );
5e014a0c 107}
865bb325 108}
5e014a0c 109
6ca41e57
RR
110//-----------------------------------------------------------------------------
111// wxMDIParentFrame
33d0b396
RR
112//-----------------------------------------------------------------------------
113
c801d85f
KB
114IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
115
f6bcfd97 116void wxMDIParentFrame::Init()
c801d85f 117{
b1d4dd7a 118 m_justInserted = false;
83624f79 119 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 120}
c801d85f 121
ab2b3dd4 122wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 123{
ff7b1510 124}
c801d85f 125
f6bcfd97
BP
126bool wxMDIParentFrame::Create(wxWindow *parent,
127 wxWindowID id,
128 const wxString& title,
129 const wxPoint& pos,
130 const wxSize& size,
131 long style,
132 const wxString& name )
c801d85f 133{
83624f79 134 wxFrame::Create( parent, id, title, pos, size, style, name );
a3622daa 135
83624f79 136 OnCreateClient();
a3622daa 137
b1d4dd7a 138 return true;
ff7b1510 139}
c801d85f 140
716b7364 141void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
c801d85f 142{
83624f79 143 wxFrame::GtkOnSize( x, y, width, height );
a0fdacee 144
ab2b3dd4
RR
145 wxMDIChildFrame *child_frame = GetActiveChild();
146 if (!child_frame) return;
a0fdacee 147
ab2b3dd4
RR
148 wxMenuBar *menu_bar = child_frame->m_menuBar;
149 if (!menu_bar) return;
a2053b27 150 if (!menu_bar->m_widget) return;
a0fdacee 151
121a3581
RR
152 menu_bar->m_x = 0;
153 menu_bar->m_y = 0;
154 menu_bar->m_width = m_width;
155 menu_bar->m_height = wxMENU_HEIGHT;
f6bcfd97
BP
156 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
157 menu_bar->m_widget,
f03fc89f 158 0, 0, m_width, wxMENU_HEIGHT );
ab2b3dd4
RR
159}
160
161void wxMDIParentFrame::OnInternalIdle()
162{
163 /* if a an MDI child window has just been inserted
164 it has to be brought to the top in idle time. we
165 simply set the last notebook page active as new
166 pages can only be appended at the end */
167
168 if (m_justInserted)
83624f79 169 {
a2053b27 170 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
a0fdacee
VZ
171 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
172
147d6669 173 /* need to set the menubar of the child */
1d608029 174 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 175 if (active_child_frame != NULL)
147d6669 176 {
1b10056f
RD
177 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
178 if (menu_bar)
179 {
180 menu_bar->m_width = m_width;
181 menu_bar->m_height = wxMENU_HEIGHT;
182 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
183 menu_bar->m_widget,
184 0, 0, m_width, wxMENU_HEIGHT );
185 menu_bar->SetInvokingWindow(active_child_frame);
186 }
147d6669 187 }
b1d4dd7a 188 m_justInserted = false;
a0fdacee 189 return;
83624f79 190 }
a0fdacee 191
ab2b3dd4 192 wxFrame::OnInternalIdle();
c626a8b7 193
ab2b3dd4 194 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 195 bool visible_child_menu = false;
a0fdacee 196
222ed1d6 197 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 198 while (node)
83624f79 199 {
b1d4dd7a
RL
200 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
201
f6bcfd97 202 if ( child_frame )
a0fdacee 203 {
f6bcfd97
BP
204 wxMenuBar *menu_bar = child_frame->m_menuBar;
205 if ( menu_bar )
f03fc89f 206 {
f6bcfd97
BP
207 if (child_frame == active_child_frame)
208 {
b1d4dd7a 209 if (menu_bar->Show(true))
f6bcfd97
BP
210 {
211 menu_bar->m_width = m_width;
212 menu_bar->m_height = wxMENU_HEIGHT;
213 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
214 menu_bar->m_widget,
215 0, 0, m_width, wxMENU_HEIGHT );
216 menu_bar->SetInvokingWindow( child_frame );
217 }
b1d4dd7a 218 visible_child_menu = true;
f6bcfd97
BP
219 }
220 else
221 {
b1d4dd7a 222 if (menu_bar->Show(false))
f6bcfd97
BP
223 {
224 menu_bar->UnsetInvokingWindow( child_frame );
225 }
226 }
f03fc89f 227 }
a0fdacee 228 }
f6bcfd97 229
b1d4dd7a 230 node = node->GetNext();
83624f79 231 }
a0fdacee 232
e27ce4e9 233 /* show/hide parent menu bar as required */
5bd9e519
RR
234 if ((m_frameMenuBar) &&
235 (m_frameMenuBar->IsShown() == visible_child_menu))
236 {
237 if (visible_child_menu)
f6bcfd97 238 {
b1d4dd7a 239 m_frameMenuBar->Show( false );
f6bcfd97
BP
240 m_frameMenuBar->UnsetInvokingWindow( this );
241 }
242 else
243 {
b1d4dd7a 244 m_frameMenuBar->Show( true );
f6bcfd97
BP
245 m_frameMenuBar->SetInvokingWindow( this );
246
247 m_frameMenuBar->m_width = m_width;
248 m_frameMenuBar->m_height = wxMENU_HEIGHT;
249 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
250 m_frameMenuBar->m_widget,
251 0, 0, m_width, wxMENU_HEIGHT );
252 }
5bd9e519 253 }
ff7b1510 254}
716b7364 255
40d432c4 256void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
c801d85f 257{
40d432c4 258 wxFrame::DoGetClientSize( width, height );
ff7b1510 259}
c801d85f 260
ab2b3dd4
RR
261wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
262{
263 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 264
a2053b27 265 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 266 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee 267
ab2b3dd4
RR
268 gint i = gtk_notebook_get_current_page( notebook );
269 if (i < 0) return (wxMDIChildFrame*) NULL;
a0fdacee 270
ab2b3dd4
RR
271 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
272 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 273
222ed1d6 274 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
275 while (node)
276 {
b1d4dd7a
RL
277 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
278
279 wxASSERT_MSG( child_frame, _T("child is not a wxMDIChildFrame") );
280
ab2b3dd4
RR
281 if (child_frame->m_page == page)
282 return child_frame;
b1d4dd7a 283 node = node->GetNext();
ab2b3dd4 284 }
a0fdacee 285
ab2b3dd4 286 return (wxMDIChildFrame*) NULL;
ff7b1510 287}
c801d85f 288
ab2b3dd4 289wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 290{
83624f79 291 return m_clientWindow;
ff7b1510 292}
c801d85f 293
ab2b3dd4 294wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 295{
83624f79
RR
296 m_clientWindow = new wxMDIClientWindow( this );
297 return m_clientWindow;
ff7b1510 298}
c801d85f 299
ab2b3dd4 300void wxMDIParentFrame::ActivateNext()
c801d85f 301{
83624f79 302 if (m_clientWindow)
a2053b27 303 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 304}
c801d85f 305
ab2b3dd4 306void wxMDIParentFrame::ActivatePrevious()
716b7364 307{
83624f79 308 if (m_clientWindow)
a2053b27 309 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 310}
716b7364 311
c801d85f
KB
312//-----------------------------------------------------------------------------
313// wxMDIChildFrame
314//-----------------------------------------------------------------------------
315
cf4219e7 316IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 317
cf4219e7 318BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 319 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 320 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
321END_EVENT_TABLE()
322
ab2b3dd4 323wxMDIChildFrame::wxMDIChildFrame()
c801d85f 324{
83624f79
RR
325 m_menuBar = (wxMenuBar *) NULL;
326 m_page = (GtkNotebookPage *) NULL;
ff7b1510 327}
c801d85f
KB
328
329wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 330 wxWindowID id, const wxString& title,
33d0b396 331 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 332 long style, const wxString& name )
c801d85f 333{
83624f79
RR
334 m_menuBar = (wxMenuBar *) NULL;
335 m_page = (GtkNotebookPage *) NULL;
336 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 337}
c801d85f 338
ab2b3dd4 339wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 340{
83624f79 341 if (m_menuBar)
83624f79 342 delete m_menuBar;
1631916e 343}
c801d85f
KB
344
345bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 346 wxWindowID id, const wxString& title,
33d0b396 347 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 348 long style, const wxString& name )
c801d85f 349{
83624f79 350 m_title = title;
c626a8b7 351
83624f79 352 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 353}
c801d85f 354
ac0c857a
RR
355void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
356{
357 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
358}
359
360void wxMDIChildFrame::DoSetClientSize(int width, int height)
361{
362 wxWindow::DoSetClientSize( width, height );
363}
364
40d432c4 365void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
c801d85f 366{
40d432c4 367 wxWindow::DoGetClientSize( width, height );
cf4219e7 368}
9746a2ba 369
7a903311 370void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 371{
7a903311 372 wxWindow::AddChild(child);
716b7364 373}
c626a8b7 374
716b7364
RR
375void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
376{
223d09f6 377 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 378
83624f79 379 m_menuBar = menu_bar;
a3622daa 380
83624f79 381 if (m_menuBar)
716b7364 382 {
f03fc89f 383 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 384
5bd9e519 385 m_menuBar->SetParent( mdi_frame );
c626a8b7 386
ab2b3dd4 387 /* insert the invisible menu bar into the _parent_ mdi frame */
f6bcfd97
BP
388 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
389 m_menuBar->m_widget,
a2053b27 390 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
716b7364 391 }
ff7b1510 392}
cf4219e7 393
33b64e6f 394wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 395{
83624f79 396 return m_menuBar;
ff7b1510 397}
c801d85f 398
ab2b3dd4 399void wxMDIChildFrame::Activate()
c801d85f 400{
adde8c98 401 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 402 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
9e691f46 403 gint pageno = gtk_notebook_page_num( notebook, m_widget );
adde8c98 404 gtk_notebook_set_page( notebook, pageno );
ff7b1510 405}
c801d85f 406
f6bcfd97
BP
407void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
408{
409}
410
411void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 412{
f6bcfd97
BP
413#if wxUSE_STATUSBAR
414 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
415 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
416 {
417 // we don't have any help text for this item, but may be the MDI frame
418 // does?
419 mdi_frame->OnMenuHighlight(event);
420 }
421#endif // wxUSE_STATUSBAR
422}
423
424void wxMDIChildFrame::SetTitle( const wxString &title )
425{
426 if ( title == m_title )
427 return;
428
429 m_title = title;
430
431 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
432 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
fab591c5 433 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 434}
9746a2ba 435
ab2b3dd4
RR
436//-----------------------------------------------------------------------------
437// "size_allocate"
438//-----------------------------------------------------------------------------
439
865bb325 440extern "C" {
ab2b3dd4
RR
441static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
442{
acfd422a
RR
443 if (g_isIdle) wxapp_install_idle_handler();
444
a2053b27
RR
445 if ((win->m_x == alloc->x) &&
446 (win->m_y == alloc->y) &&
447 (win->m_width == alloc->width) &&
448 (win->m_height == alloc->height) &&
449 (win->m_sizeSet))
ab2b3dd4
RR
450 {
451 return;
452 }
453
454 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
455}
865bb325 456}
ab2b3dd4 457
6ca41e57
RR
458//-----------------------------------------------------------------------------
459// InsertChild callback for wxMDIClientWindow
460//-----------------------------------------------------------------------------
461
462static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
463{
83624f79
RR
464 wxString s = child->m_title;
465 if (s.IsNull()) s = _("MDI child");
6ca41e57 466
ed9b9841 467 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 468 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 469
a2053b27 470 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 471 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 472
a2053b27 473 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 474
a2053b27 475 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 476
83624f79 477 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 478
f03fc89f 479 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
b1d4dd7a 480 parent_frame->m_justInserted = true;
6ca41e57
RR
481}
482
c801d85f
KB
483//-----------------------------------------------------------------------------
484// wxMDIClientWindow
485//-----------------------------------------------------------------------------
486
487IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
488
ab2b3dd4 489wxMDIClientWindow::wxMDIClientWindow()
c801d85f 490{
ff7b1510 491}
c801d85f 492
debe6624 493wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 494{
83624f79 495 CreateClient( parent, style );
ff7b1510 496}
c801d85f 497
ab2b3dd4 498wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 499{
1631916e 500
ff7b1510 501}
c801d85f 502
debe6624 503bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 504{
b1d4dd7a 505 m_needParent = true;
c626a8b7 506
83624f79 507 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 508
4dcaf11a 509 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
223d09f6 510 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 511 {
223d09f6 512 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 513 return false;
4dcaf11a 514 }
c801d85f 515
83624f79 516 m_widget = gtk_notebook_new();
a3622daa 517
5e014a0c
RR
518 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
519 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
520
83624f79 521 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 522
f03fc89f 523 m_parent->DoAddChild( this );
c626a8b7 524
83624f79 525 PostCreation();
a3622daa 526
b1d4dd7a 527 Show( true );
a3622daa 528
b1d4dd7a 529 return true;
ff7b1510 530}
c801d85f 531
dcf924a3 532#endif