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