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