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