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