]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
fixed (rare but fatal) bug in wxWindowDisabler
[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
a3622daa 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
11#pragma implementation "mdi.h"
12#endif
13
14#include "wx/mdi.h"
dcf924a3
RR
15
16#if wxUSE_MDI_ARCHITECTURE
17
e3e65dac 18#include "wx/dialog.h"
cf4219e7 19#include "wx/menu.h"
3096bd2f 20#include "wx/intl.h"
716b7364 21
16c1f79c
RR
22#include <glib.h>
23#include <gdk/gdk.h>
24#include <gtk/gtk.h>
83624f79
RR
25#include "wx/gtk/win_gtk.h"
26
6ca41e57
RR
27//-----------------------------------------------------------------------------
28// constants
29//-----------------------------------------------------------------------------
30
a0fdacee 31const int wxMENU_HEIGHT = 27;
6ca41e57 32
acfd422a
RR
33//-----------------------------------------------------------------------------
34// idle system
35//-----------------------------------------------------------------------------
36
37extern void wxapp_install_idle_handler();
38extern bool g_isIdle;
39
6ca41e57
RR
40//-----------------------------------------------------------------------------
41// globals
716b7364
RR
42//-----------------------------------------------------------------------------
43
44extern wxList wxPendingDelete;
c801d85f 45
5e014a0c
RR
46//-----------------------------------------------------------------------------
47// "switch_page"
48//-----------------------------------------------------------------------------
49
e90196a5 50static void
7941ba11 51gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5
RR
52 GtkNotebookPage *page,
53 gint WXUNUSED(page_num),
54 wxMDIParentFrame *parent )
5e014a0c
RR
55{
56 if (g_isIdle)
57 wxapp_install_idle_handler();
58
e90196a5
RR
59 // send deactivate event to old child
60
5e014a0c 61 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
62 if (child)
63 {
64 wxActivateEvent event1( wxEVT_ACTIVATE, FALSE, child->GetId() );
65 event1.SetEventObject( child);
66 child->GetEventHandler()->ProcessEvent( event1 );
67 }
5e014a0c 68
e90196a5
RR
69 // send activate event to new child
70
71 wxMDIClientWindow *client_window = parent->GetClientWindow();
72 if (!client_window)
73 return;
74
75 child = (wxMDIChildFrame*) NULL;
76
77 wxNode *node = client_window->GetChildren().First();
78 while (node)
79 {
80 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
81 if (child_frame->m_page == page)
82 {
83 child = child_frame;
84 break;
85 }
86 node = node->Next();
87 }
88
89 if (!child)
90 return;
91
92 wxActivateEvent event2( wxEVT_ACTIVATE, TRUE, child->GetId() );
93 event2.SetEventObject( child);
94 child->GetEventHandler()->ProcessEvent( event2 );
5e014a0c
RR
95}
96
6ca41e57
RR
97//-----------------------------------------------------------------------------
98// wxMDIParentFrame
33d0b396
RR
99//-----------------------------------------------------------------------------
100
c801d85f
KB
101IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
102
716b7364
RR
103BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
104END_EVENT_TABLE()
105
ab2b3dd4 106wxMDIParentFrame::wxMDIParentFrame()
c801d85f 107{
ab2b3dd4 108 m_justInserted = FALSE;
83624f79 109 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 110}
c801d85f
KB
111
112wxMDIParentFrame::wxMDIParentFrame( wxWindow *parent,
debe6624 113 wxWindowID id, const wxString& title,
c801d85f 114 const wxPoint& pos, const wxSize& size,
debe6624 115 long style, const wxString& name )
c801d85f 116{
ab2b3dd4 117 m_justInserted = FALSE;
83624f79 118 m_clientWindow = (wxMDIClientWindow *) NULL;
83624f79 119 Create( parent, id, title, pos, size, style, name );
ff7b1510 120}
c801d85f 121
ab2b3dd4 122wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 123{
ff7b1510 124}
c801d85f
KB
125
126bool wxMDIParentFrame::Create( wxWindow *parent,
debe6624 127 wxWindowID id, const wxString& title,
c801d85f 128 const wxPoint& pos, const wxSize& size,
debe6624 129 long style, const wxString& name )
c801d85f 130{
83624f79 131 wxFrame::Create( parent, id, title, pos, size, style, name );
a3622daa 132
83624f79 133 OnCreateClient();
a3622daa 134
83624f79 135 return TRUE;
ff7b1510 136}
c801d85f 137
716b7364 138void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
c801d85f 139{
83624f79 140 wxFrame::GtkOnSize( x, y, width, height );
a0fdacee 141
ab2b3dd4
RR
142 wxMDIChildFrame *child_frame = GetActiveChild();
143 if (!child_frame) return;
a0fdacee 144
ab2b3dd4
RR
145 wxMenuBar *menu_bar = child_frame->m_menuBar;
146 if (!menu_bar) return;
a2053b27 147 if (!menu_bar->m_widget) return;
a0fdacee 148
121a3581
RR
149 menu_bar->m_x = 0;
150 menu_bar->m_y = 0;
151 menu_bar->m_width = m_width;
152 menu_bar->m_height = wxMENU_HEIGHT;
da048e3d 153 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
a2053b27 154 menu_bar->m_widget,
f03fc89f 155 0, 0, m_width, wxMENU_HEIGHT );
ab2b3dd4
RR
156}
157
158void wxMDIParentFrame::OnInternalIdle()
159{
160 /* if a an MDI child window has just been inserted
161 it has to be brought to the top in idle time. we
162 simply set the last notebook page active as new
163 pages can only be appended at the end */
164
165 if (m_justInserted)
83624f79 166 {
a2053b27 167 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
a0fdacee
VZ
168 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
169
170 m_justInserted = FALSE;
171 return;
83624f79 172 }
a0fdacee 173
ab2b3dd4 174 wxFrame::OnInternalIdle();
c626a8b7 175
ab2b3dd4 176 wxMDIChildFrame *active_child_frame = GetActiveChild();
a260fe6a 177 bool visible_child_menu = FALSE;
a0fdacee 178
f03fc89f 179 wxNode *node = m_clientWindow->GetChildren().First();
ab2b3dd4 180 while (node)
83624f79 181 {
ab2b3dd4 182 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
5bd9e519 183 wxMenuBar *menu_bar = child_frame->m_menuBar;
a0fdacee
VZ
184 if (child_frame->m_menuBar)
185 {
186 if (child_frame == active_child_frame)
f03fc89f 187 {
5bd9e519
RR
188 if (menu_bar->Show(TRUE))
189 {
190 menu_bar->m_width = m_width;
191 menu_bar->m_height = wxMENU_HEIGHT;
da048e3d 192 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
5bd9e519
RR
193 menu_bar->m_widget,
194 0, 0, m_width, wxMENU_HEIGHT );
195 menu_bar->SetInvokingWindow( child_frame );
196 }
197 visible_child_menu = TRUE;
f03fc89f 198 }
a0fdacee 199 else
5bd9e519
RR
200 {
201 if (menu_bar->Show(FALSE))
202 {
203 menu_bar->UnsetInvokingWindow( child_frame );
204 }
205 }
a0fdacee 206 }
ab2b3dd4 207 node = node->Next();
83624f79 208 }
a0fdacee 209
e27ce4e9 210 /* show/hide parent menu bar as required */
5bd9e519
RR
211 if ((m_frameMenuBar) &&
212 (m_frameMenuBar->IsShown() == visible_child_menu))
213 {
214 if (visible_child_menu)
215 {
216 m_frameMenuBar->Show( FALSE );
217 m_frameMenuBar->UnsetInvokingWindow( this );
218 }
219 else
220 {
221 m_frameMenuBar->Show( TRUE );
222 m_frameMenuBar->SetInvokingWindow( this );
223
224 m_frameMenuBar->m_width = m_width;
225 m_frameMenuBar->m_height = wxMENU_HEIGHT;
da048e3d 226 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
5bd9e519
RR
227 m_frameMenuBar->m_widget,
228 0, 0, m_width, wxMENU_HEIGHT );
229 }
230 }
ff7b1510 231}
716b7364
RR
232
233void wxMDIParentFrame::GetClientSize(int *width, int *height ) const
c801d85f 234{
83624f79 235 wxFrame::GetClientSize( width, height );
ff7b1510 236}
c801d85f 237
ab2b3dd4
RR
238wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
239{
240 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 241
a2053b27 242 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 243 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee
VZ
244
245#if (GTK_MINOR_VERSION > 0)
ab2b3dd4 246 gint i = gtk_notebook_get_current_page( notebook );
a0fdacee
VZ
247#else
248 gint i = gtk_notebook_current_page( notebook );
249#endif
ab2b3dd4 250 if (i < 0) return (wxMDIChildFrame*) NULL;
a0fdacee 251
ab2b3dd4
RR
252 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
253 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 254
f03fc89f 255 wxNode *node = m_clientWindow->GetChildren().First();
ab2b3dd4
RR
256 while (node)
257 {
258 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
259 if (child_frame->m_page == page)
260 return child_frame;
261 node = node->Next();
262 }
a0fdacee 263
ab2b3dd4 264 return (wxMDIChildFrame*) NULL;
ff7b1510 265}
c801d85f 266
ab2b3dd4 267wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 268{
83624f79 269 return m_clientWindow;
ff7b1510 270}
c801d85f 271
ab2b3dd4 272wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 273{
83624f79
RR
274 m_clientWindow = new wxMDIClientWindow( this );
275 return m_clientWindow;
ff7b1510 276}
c801d85f 277
ab2b3dd4 278void wxMDIParentFrame::ActivateNext()
c801d85f 279{
83624f79 280 if (m_clientWindow)
a2053b27 281 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 282}
c801d85f 283
ab2b3dd4 284void wxMDIParentFrame::ActivatePrevious()
716b7364 285{
83624f79 286 if (m_clientWindow)
a2053b27 287 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 288}
716b7364
RR
289
290void wxMDIParentFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
c801d85f 291{
ff7b1510 292}
c801d85f
KB
293
294void wxMDIParentFrame::OnSysColourChanged( wxSysColourChangedEvent& WXUNUSED(event) )
295{
ff7b1510 296}
c801d85f
KB
297
298//-----------------------------------------------------------------------------
299// wxMDIChildFrame
300//-----------------------------------------------------------------------------
301
cf4219e7 302IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 303
cf4219e7 304BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 305 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
716b7364
RR
306END_EVENT_TABLE()
307
ab2b3dd4 308wxMDIChildFrame::wxMDIChildFrame()
c801d85f 309{
83624f79
RR
310 m_menuBar = (wxMenuBar *) NULL;
311 m_page = (GtkNotebookPage *) NULL;
ff7b1510 312}
c801d85f
KB
313
314wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 315 wxWindowID id, const wxString& title,
33d0b396 316 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 317 long style, const wxString& name )
c801d85f 318{
83624f79
RR
319 m_menuBar = (wxMenuBar *) NULL;
320 m_page = (GtkNotebookPage *) NULL;
321 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 322}
c801d85f 323
ab2b3dd4 324wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 325{
83624f79 326 if (m_menuBar)
83624f79 327 delete m_menuBar;
ff7b1510 328}
c801d85f
KB
329
330bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 331 wxWindowID id, const wxString& title,
33d0b396 332 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 333 long style, const wxString& name )
c801d85f 334{
83624f79 335 m_title = title;
c626a8b7 336
83624f79 337 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 338}
c801d85f 339
cf4219e7 340void wxMDIChildFrame::GetClientSize( int *width, int *height ) const
c801d85f 341{
83624f79 342 wxWindow::GetClientSize( width, height );
cf4219e7 343}
9746a2ba 344
7a903311 345void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 346{
7a903311 347 wxWindow::AddChild(child);
716b7364 348}
c626a8b7 349
716b7364
RR
350void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
351{
223d09f6 352 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 353
83624f79 354 m_menuBar = menu_bar;
a3622daa 355
83624f79 356 if (m_menuBar)
716b7364 357 {
f03fc89f 358 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 359
5bd9e519 360 m_menuBar->SetParent( mdi_frame );
c626a8b7 361
ab2b3dd4 362 /* insert the invisible menu bar into the _parent_ mdi frame */
da048e3d 363 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
a2053b27
RR
364 m_menuBar->m_widget,
365 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
716b7364 366 }
ff7b1510 367}
cf4219e7 368
33b64e6f 369wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 370{
83624f79 371 return m_menuBar;
ff7b1510 372}
c801d85f 373
ab2b3dd4 374void wxMDIChildFrame::Activate()
c801d85f 375{
adde8c98
RR
376#if (GTK_MINOR_VERSION > 0)
377 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 378 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
adde8c98
RR
379 gint pageno = gtk_notebook_page_num( notebook, m_page->child );
380 gtk_notebook_set_page( notebook, pageno );
97560ce3
RS
381#else
382 // the only way I can see to do this under gtk+ 1.0.X would
383 // be to keep track of page numbers, start at first and
384 // do "next" enough times to get to this page number - messy
385 // - J. Russell Smyth
386#endif
ff7b1510 387}
c801d85f 388
9746a2ba
RR
389void wxMDIChildFrame::OnActivate( wxActivateEvent &WXUNUSED(event) )
390{
ff7b1510 391}
9746a2ba 392
ab2b3dd4
RR
393//-----------------------------------------------------------------------------
394// "size_allocate"
395//-----------------------------------------------------------------------------
396
397static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
398{
acfd422a
RR
399 if (g_isIdle) wxapp_install_idle_handler();
400
a2053b27
RR
401 if ((win->m_x == alloc->x) &&
402 (win->m_y == alloc->y) &&
403 (win->m_width == alloc->width) &&
404 (win->m_height == alloc->height) &&
405 (win->m_sizeSet))
ab2b3dd4
RR
406 {
407 return;
408 }
409
410 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
411}
412
6ca41e57
RR
413//-----------------------------------------------------------------------------
414// InsertChild callback for wxMDIClientWindow
415//-----------------------------------------------------------------------------
416
417static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
418{
83624f79
RR
419 wxString s = child->m_title;
420 if (s.IsNull()) s = _("MDI child");
6ca41e57 421
ed9b9841 422 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 423 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 424
a2053b27 425 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 426 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 427
a2053b27 428 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 429
a2053b27 430 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 431
83624f79 432 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 433
f03fc89f 434 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
ab2b3dd4 435 parent_frame->m_justInserted = TRUE;
6ca41e57
RR
436}
437
c801d85f
KB
438//-----------------------------------------------------------------------------
439// wxMDIClientWindow
440//-----------------------------------------------------------------------------
441
442IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
443
ab2b3dd4 444wxMDIClientWindow::wxMDIClientWindow()
c801d85f 445{
ff7b1510 446}
c801d85f 447
debe6624 448wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 449{
83624f79 450 CreateClient( parent, style );
ff7b1510 451}
c801d85f 452
ab2b3dd4 453wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 454{
ff7b1510 455}
c801d85f 456
debe6624 457bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 458{
83624f79 459 m_needParent = TRUE;
c626a8b7 460
83624f79 461 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 462
4dcaf11a 463 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
223d09f6 464 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 465 {
223d09f6 466 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
4dcaf11a
RR
467 return FALSE;
468 }
c801d85f 469
83624f79 470 m_widget = gtk_notebook_new();
a3622daa 471
5e014a0c
RR
472 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
473 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
474
83624f79 475 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 476
f03fc89f 477 m_parent->DoAddChild( this );
c626a8b7 478
83624f79 479 PostCreation();
a3622daa 480
83624f79 481 Show( TRUE );
a3622daa 482
83624f79 483 return TRUE;
ff7b1510 484}
c801d85f 485
dcf924a3 486#endif