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