]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
partially fix bug [ wxwindows-Bugs-1145813 ] Centre() Doesn't Work With Dual Monitors...
[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 172 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 173 if (active_child_frame != NULL)
147d6669 174 {
1b10056f
RD
175 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
176 if (menu_bar)
177 {
178 menu_bar->m_width = m_width;
179 menu_bar->m_height = wxMENU_HEIGHT;
180 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
181 menu_bar->m_widget,
182 0, 0, m_width, wxMENU_HEIGHT );
183 menu_bar->SetInvokingWindow(active_child_frame);
184 }
147d6669 185 }
b1d4dd7a 186 m_justInserted = false;
a0fdacee 187 return;
83624f79 188 }
a0fdacee 189
ab2b3dd4 190 wxFrame::OnInternalIdle();
c626a8b7 191
ab2b3dd4 192 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 193 bool visible_child_menu = false;
a0fdacee 194
222ed1d6 195 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 196 while (node)
83624f79 197 {
b1d4dd7a
RL
198 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
199
f6bcfd97 200 if ( child_frame )
a0fdacee 201 {
f6bcfd97
BP
202 wxMenuBar *menu_bar = child_frame->m_menuBar;
203 if ( menu_bar )
f03fc89f 204 {
f6bcfd97
BP
205 if (child_frame == active_child_frame)
206 {
b1d4dd7a 207 if (menu_bar->Show(true))
f6bcfd97
BP
208 {
209 menu_bar->m_width = m_width;
210 menu_bar->m_height = wxMENU_HEIGHT;
211 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
212 menu_bar->m_widget,
213 0, 0, m_width, wxMENU_HEIGHT );
214 menu_bar->SetInvokingWindow( child_frame );
215 }
b1d4dd7a 216 visible_child_menu = true;
f6bcfd97
BP
217 }
218 else
219 {
b1d4dd7a 220 if (menu_bar->Show(false))
f6bcfd97
BP
221 {
222 menu_bar->UnsetInvokingWindow( child_frame );
223 }
224 }
f03fc89f 225 }
a0fdacee 226 }
f6bcfd97 227
b1d4dd7a 228 node = node->GetNext();
83624f79 229 }
a0fdacee 230
e27ce4e9 231 /* show/hide parent menu bar as required */
5bd9e519
RR
232 if ((m_frameMenuBar) &&
233 (m_frameMenuBar->IsShown() == visible_child_menu))
234 {
235 if (visible_child_menu)
f6bcfd97 236 {
b1d4dd7a 237 m_frameMenuBar->Show( false );
f6bcfd97
BP
238 m_frameMenuBar->UnsetInvokingWindow( this );
239 }
240 else
241 {
b1d4dd7a 242 m_frameMenuBar->Show( true );
f6bcfd97
BP
243 m_frameMenuBar->SetInvokingWindow( this );
244
245 m_frameMenuBar->m_width = m_width;
246 m_frameMenuBar->m_height = wxMENU_HEIGHT;
247 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
248 m_frameMenuBar->m_widget,
249 0, 0, m_width, wxMENU_HEIGHT );
250 }
5bd9e519 251 }
ff7b1510 252}
716b7364 253
40d432c4 254void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
c801d85f 255{
40d432c4 256 wxFrame::DoGetClientSize( width, height );
ff7b1510 257}
c801d85f 258
ab2b3dd4
RR
259wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
260{
261 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 262
a2053b27 263 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 264 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee 265
ab2b3dd4
RR
266 gint i = gtk_notebook_get_current_page( notebook );
267 if (i < 0) return (wxMDIChildFrame*) NULL;
a0fdacee 268
ab2b3dd4
RR
269 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
270 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 271
222ed1d6 272 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
273 while (node)
274 {
b1d4dd7a
RL
275 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
276
277 wxASSERT_MSG( child_frame, _T("child is not a wxMDIChildFrame") );
278
ab2b3dd4
RR
279 if (child_frame->m_page == page)
280 return child_frame;
b1d4dd7a 281 node = node->GetNext();
ab2b3dd4 282 }
a0fdacee 283
ab2b3dd4 284 return (wxMDIChildFrame*) NULL;
ff7b1510 285}
c801d85f 286
ab2b3dd4 287wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 288{
83624f79 289 return m_clientWindow;
ff7b1510 290}
c801d85f 291
ab2b3dd4 292wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 293{
83624f79
RR
294 m_clientWindow = new wxMDIClientWindow( this );
295 return m_clientWindow;
ff7b1510 296}
c801d85f 297
ab2b3dd4 298void wxMDIParentFrame::ActivateNext()
c801d85f 299{
83624f79 300 if (m_clientWindow)
a2053b27 301 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 302}
c801d85f 303
ab2b3dd4 304void wxMDIParentFrame::ActivatePrevious()
716b7364 305{
83624f79 306 if (m_clientWindow)
a2053b27 307 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 308}
716b7364 309
c801d85f
KB
310//-----------------------------------------------------------------------------
311// wxMDIChildFrame
312//-----------------------------------------------------------------------------
313
cf4219e7 314IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 315
cf4219e7 316BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 317 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 318 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
319END_EVENT_TABLE()
320
ab2b3dd4 321wxMDIChildFrame::wxMDIChildFrame()
c801d85f 322{
83624f79
RR
323 m_menuBar = (wxMenuBar *) NULL;
324 m_page = (GtkNotebookPage *) NULL;
ff7b1510 325}
c801d85f
KB
326
327wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 328 wxWindowID id, const wxString& title,
33d0b396 329 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 330 long style, const wxString& name )
c801d85f 331{
83624f79
RR
332 m_menuBar = (wxMenuBar *) NULL;
333 m_page = (GtkNotebookPage *) NULL;
334 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 335}
c801d85f 336
ab2b3dd4 337wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 338{
83624f79 339 if (m_menuBar)
83624f79 340 delete m_menuBar;
1631916e 341}
c801d85f
KB
342
343bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 344 wxWindowID id, const wxString& title,
33d0b396 345 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 346 long style, const wxString& name )
c801d85f 347{
83624f79 348 m_title = title;
c626a8b7 349
83624f79 350 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 351}
c801d85f 352
ac0c857a
RR
353void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
354{
355 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
356}
357
358void wxMDIChildFrame::DoSetClientSize(int width, int height)
359{
360 wxWindow::DoSetClientSize( width, height );
361}
362
40d432c4 363void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
c801d85f 364{
40d432c4 365 wxWindow::DoGetClientSize( width, height );
cf4219e7 366}
9746a2ba 367
7a903311 368void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 369{
7a903311 370 wxWindow::AddChild(child);
716b7364 371}
c626a8b7 372
716b7364
RR
373void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
374{
223d09f6 375 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 376
83624f79 377 m_menuBar = menu_bar;
a3622daa 378
83624f79 379 if (m_menuBar)
716b7364 380 {
f03fc89f 381 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 382
5bd9e519 383 m_menuBar->SetParent( mdi_frame );
c626a8b7 384
ab2b3dd4 385 /* insert the invisible menu bar into the _parent_ mdi frame */
f6bcfd97
BP
386 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
387 m_menuBar->m_widget,
a2053b27 388 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
716b7364 389 }
ff7b1510 390}
cf4219e7 391
33b64e6f 392wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 393{
83624f79 394 return m_menuBar;
ff7b1510 395}
c801d85f 396
ab2b3dd4 397void wxMDIChildFrame::Activate()
c801d85f 398{
adde8c98 399 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 400 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
9e691f46 401 gint pageno = gtk_notebook_page_num( notebook, m_widget );
adde8c98 402 gtk_notebook_set_page( notebook, pageno );
ff7b1510 403}
c801d85f 404
f6bcfd97
BP
405void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
406{
407}
408
409void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 410{
f6bcfd97
BP
411#if wxUSE_STATUSBAR
412 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
413 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
414 {
415 // we don't have any help text for this item, but may be the MDI frame
416 // does?
417 mdi_frame->OnMenuHighlight(event);
418 }
419#endif // wxUSE_STATUSBAR
420}
421
422void wxMDIChildFrame::SetTitle( const wxString &title )
423{
424 if ( title == m_title )
425 return;
426
427 m_title = title;
428
429 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
430 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
fab591c5 431 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 432}
9746a2ba 433
ab2b3dd4
RR
434//-----------------------------------------------------------------------------
435// "size_allocate"
436//-----------------------------------------------------------------------------
437
438static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
439{
acfd422a
RR
440 if (g_isIdle) wxapp_install_idle_handler();
441
a2053b27
RR
442 if ((win->m_x == alloc->x) &&
443 (win->m_y == alloc->y) &&
444 (win->m_width == alloc->width) &&
445 (win->m_height == alloc->height) &&
446 (win->m_sizeSet))
ab2b3dd4
RR
447 {
448 return;
449 }
450
451 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
452}
453
6ca41e57
RR
454//-----------------------------------------------------------------------------
455// InsertChild callback for wxMDIClientWindow
456//-----------------------------------------------------------------------------
457
458static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
459{
83624f79
RR
460 wxString s = child->m_title;
461 if (s.IsNull()) s = _("MDI child");
6ca41e57 462
ed9b9841 463 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 464 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 465
a2053b27 466 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 467 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 468
a2053b27 469 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 470
a2053b27 471 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 472
83624f79 473 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 474
f03fc89f 475 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
b1d4dd7a 476 parent_frame->m_justInserted = true;
6ca41e57
RR
477}
478
c801d85f
KB
479//-----------------------------------------------------------------------------
480// wxMDIClientWindow
481//-----------------------------------------------------------------------------
482
483IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
484
ab2b3dd4 485wxMDIClientWindow::wxMDIClientWindow()
c801d85f 486{
ff7b1510 487}
c801d85f 488
debe6624 489wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 490{
83624f79 491 CreateClient( parent, style );
ff7b1510 492}
c801d85f 493
ab2b3dd4 494wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 495{
1631916e 496
ff7b1510 497}
c801d85f 498
debe6624 499bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 500{
b1d4dd7a 501 m_needParent = true;
c626a8b7 502
83624f79 503 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 504
4dcaf11a 505 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
223d09f6 506 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 507 {
223d09f6 508 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 509 return false;
4dcaf11a 510 }
c801d85f 511
83624f79 512 m_widget = gtk_notebook_new();
a3622daa 513
5e014a0c
RR
514 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
515 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
516
83624f79 517 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 518
f03fc89f 519 m_parent->DoAddChild( this );
c626a8b7 520
83624f79 521 PostCreation();
a3622daa 522
b1d4dd7a 523 Show( true );
a3622daa 524
b1d4dd7a 525 return true;
ff7b1510 526}
c801d85f 527
dcf924a3 528#endif