]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Fixed missing focus problem.
[wxWidgets.git] / src / gtk / mdi.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: mdi.cpp
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 10#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
c801d85f
KB
11#pragma implementation "mdi.h"
12#endif
13
14f355c2
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
c801d85f 17#include "wx/mdi.h"
1631916e 18#include "wx/notebook.h"
dcf924a3 19
efd17a1d 20#if wxUSE_MDI
dcf924a3 21
e3e65dac 22#include "wx/dialog.h"
cf4219e7 23#include "wx/menu.h"
3096bd2f 24#include "wx/intl.h"
fab591c5 25#include "wx/gtk/private.h"
716b7364 26
16c1f79c
RR
27#include <glib.h>
28#include <gdk/gdk.h>
29#include <gtk/gtk.h>
83624f79
RR
30#include "wx/gtk/win_gtk.h"
31
6ca41e57
RR
32//-----------------------------------------------------------------------------
33// constants
34//-----------------------------------------------------------------------------
35
a0fdacee 36const int wxMENU_HEIGHT = 27;
6ca41e57 37
acfd422a
RR
38//-----------------------------------------------------------------------------
39// idle system
40//-----------------------------------------------------------------------------
41
42extern void wxapp_install_idle_handler();
43extern bool g_isIdle;
44
6ca41e57
RR
45//-----------------------------------------------------------------------------
46// globals
716b7364
RR
47//-----------------------------------------------------------------------------
48
49extern wxList wxPendingDelete;
c801d85f 50
5e014a0c
RR
51//-----------------------------------------------------------------------------
52// "switch_page"
53//-----------------------------------------------------------------------------
54
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
RR
106}
107
6ca41e57
RR
108//-----------------------------------------------------------------------------
109// wxMDIParentFrame
33d0b396
RR
110//-----------------------------------------------------------------------------
111
c801d85f
KB
112IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
113
f6bcfd97 114void wxMDIParentFrame::Init()
c801d85f 115{
b1d4dd7a 116 m_justInserted = false;
83624f79 117 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 118}
c801d85f 119
ab2b3dd4 120wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 121{
ff7b1510 122}
c801d85f 123
f6bcfd97
BP
124bool wxMDIParentFrame::Create(wxWindow *parent,
125 wxWindowID id,
126 const wxString& title,
127 const wxPoint& pos,
128 const wxSize& size,
129 long style,
130 const wxString& name )
c801d85f 131{
83624f79 132 wxFrame::Create( parent, id, title, pos, size, style, name );
a3622daa 133
83624f79 134 OnCreateClient();
a3622daa 135
b1d4dd7a 136 return true;
ff7b1510 137}
c801d85f 138
716b7364 139void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
c801d85f 140{
83624f79 141 wxFrame::GtkOnSize( x, y, width, height );
a0fdacee 142
ab2b3dd4
RR
143 wxMDIChildFrame *child_frame = GetActiveChild();
144 if (!child_frame) return;
a0fdacee 145
ab2b3dd4
RR
146 wxMenuBar *menu_bar = child_frame->m_menuBar;
147 if (!menu_bar) return;
a2053b27 148 if (!menu_bar->m_widget) return;
a0fdacee 149
121a3581
RR
150 menu_bar->m_x = 0;
151 menu_bar->m_y = 0;
152 menu_bar->m_width = m_width;
153 menu_bar->m_height = wxMENU_HEIGHT;
f6bcfd97
BP
154 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
155 menu_bar->m_widget,
f03fc89f 156 0, 0, m_width, wxMENU_HEIGHT );
ab2b3dd4
RR
157}
158
159void wxMDIParentFrame::OnInternalIdle()
160{
161 /* if a an MDI child window has just been inserted
162 it has to be brought to the top in idle time. we
163 simply set the last notebook page active as new
164 pages can only be appended at the end */
165
166 if (m_justInserted)
83624f79 167 {
a2053b27 168 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
a0fdacee
VZ
169 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
170
147d6669 171 /* need to set the menubar of the child */
1d608029
CE
172 wxMDIChildFrame *active_child_frame = GetActiveChild();
173 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
147d6669
RD
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 }
1d608029 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;
1631916e 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
436static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
437{
acfd422a
RR
438 if (g_isIdle) wxapp_install_idle_handler();
439
a2053b27
RR
440 if ((win->m_x == alloc->x) &&
441 (win->m_y == alloc->y) &&
442 (win->m_width == alloc->width) &&
443 (win->m_height == alloc->height) &&
444 (win->m_sizeSet))
ab2b3dd4
RR
445 {
446 return;
447 }
448
449 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
450}
451
6ca41e57
RR
452//-----------------------------------------------------------------------------
453// InsertChild callback for wxMDIClientWindow
454//-----------------------------------------------------------------------------
455
456static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
457{
83624f79
RR
458 wxString s = child->m_title;
459 if (s.IsNull()) s = _("MDI child");
6ca41e57 460
ed9b9841 461 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 462 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 463
a2053b27 464 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 465 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 466
a2053b27 467 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 468
a2053b27 469 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 470
83624f79 471 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 472
f03fc89f 473 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
b1d4dd7a 474 parent_frame->m_justInserted = true;
6ca41e57
RR
475}
476
c801d85f
KB
477//-----------------------------------------------------------------------------
478// wxMDIClientWindow
479//-----------------------------------------------------------------------------
480
481IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
482
ab2b3dd4 483wxMDIClientWindow::wxMDIClientWindow()
c801d85f 484{
ff7b1510 485}
c801d85f 486
debe6624 487wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 488{
83624f79 489 CreateClient( parent, style );
ff7b1510 490}
c801d85f 491
ab2b3dd4 492wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 493{
1631916e 494
ff7b1510 495}
c801d85f 496
debe6624 497bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 498{
b1d4dd7a 499 m_needParent = true;
c626a8b7 500
83624f79 501 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 502
4dcaf11a 503 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
223d09f6 504 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 505 {
223d09f6 506 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 507 return false;
4dcaf11a 508 }
c801d85f 509
83624f79 510 m_widget = gtk_notebook_new();
a3622daa 511
5e014a0c
RR
512 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
513 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
514
83624f79 515 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 516
f03fc89f 517 m_parent->DoAddChild( this );
c626a8b7 518
83624f79 519 PostCreation();
a3622daa 520
b1d4dd7a 521 Show( true );
a3622daa 522
b1d4dd7a 523 return true;
ff7b1510 524}
c801d85f 525
dcf924a3 526#endif