]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/mdi.cpp
Make keyboard input to controls in a wxPopupWindow work in at least some cases, embed...
[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"
3b3dc801 19 #include "wx/menu.h"
fdf565fe 20 #include "wx/dialog.h"
88a7a4e1 21#endif
dcf924a3 22
88a7a4e1 23#include "wx/notebook.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
5e014a0c
RR
48//-----------------------------------------------------------------------------
49// "switch_page"
50//-----------------------------------------------------------------------------
51
865bb325 52extern "C" {
f6bcfd97 53static void
7941ba11 54gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5 55 GtkNotebookPage *page,
f6bcfd97
BP
56 gint WXUNUSED(page_num),
57 wxMDIParentFrame *parent )
5e014a0c 58{
f6bcfd97 59 if (g_isIdle)
5e014a0c
RR
60 wxapp_install_idle_handler();
61
e90196a5
RR
62 // send deactivate event to old child
63
5e014a0c 64 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
65 if (child)
66 {
b1d4dd7a 67 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5 68 event1.SetEventObject( child);
937013e0 69 child->HandleWindowEvent( event1 );
e90196a5 70 }
f6bcfd97 71
e90196a5 72 // send activate event to new child
f6bcfd97 73
e90196a5
RR
74 wxMDIClientWindow *client_window = parent->GetClientWindow();
75 if (!client_window)
76 return;
77
78 child = (wxMDIChildFrame*) NULL;
79
222ed1d6 80 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
e90196a5
RR
81 while (node)
82 {
b1d4dd7a 83 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
1631916e
CE
84 // CE: we come here in the destructor with a null child_frame - I think because
85 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
86 // isn't deleted early enough
87 if (!child_frame)
88 return ;
b1d4dd7a 89
e90196a5 90 if (child_frame->m_page == page)
f6bcfd97 91 {
e90196a5 92 child = child_frame;
f6bcfd97
BP
93 break;
94 }
b1d4dd7a 95 node = node->GetNext();
e90196a5 96 }
f6bcfd97 97
e90196a5
RR
98 if (!child)
99 return;
f6bcfd97 100
b1d4dd7a 101 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5 102 event2.SetEventObject( child);
937013e0 103 child->HandleWindowEvent( event2 );
5e014a0c 104}
865bb325 105}
5e014a0c 106
6ca41e57
RR
107//-----------------------------------------------------------------------------
108// wxMDIParentFrame
33d0b396
RR
109//-----------------------------------------------------------------------------
110
c801d85f
KB
111IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
112
f6bcfd97 113void wxMDIParentFrame::Init()
c801d85f 114{
b1d4dd7a 115 m_justInserted = false;
83624f79 116 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 117}
c801d85f 118
ab2b3dd4 119wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 120{
ff7b1510 121}
c801d85f 122
f6bcfd97
BP
123bool wxMDIParentFrame::Create(wxWindow *parent,
124 wxWindowID id,
125 const wxString& title,
126 const wxPoint& pos,
127 const wxSize& size,
128 long style,
129 const wxString& name )
c801d85f 130{
6e42617a
VZ
131 if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
132 return false;
a3622daa 133
6e42617a 134 m_clientWindow = OnCreateClient();
a3622daa 135
6e42617a 136 return m_clientWindow != NULL;
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{
6e42617a 294 return new wxMDIClientWindow( this );
ff7b1510 295}
c801d85f 296
ab2b3dd4 297void wxMDIParentFrame::ActivateNext()
c801d85f 298{
83624f79 299 if (m_clientWindow)
a2053b27 300 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 301}
c801d85f 302
ab2b3dd4 303void wxMDIParentFrame::ActivatePrevious()
716b7364 304{
83624f79 305 if (m_clientWindow)
a2053b27 306 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 307}
716b7364 308
c801d85f
KB
309//-----------------------------------------------------------------------------
310// wxMDIChildFrame
311//-----------------------------------------------------------------------------
312
cf4219e7 313IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 314
cf4219e7 315BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 316 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 317 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
318END_EVENT_TABLE()
319
ab2b3dd4 320wxMDIChildFrame::wxMDIChildFrame()
c801d85f 321{
83624f79
RR
322 m_menuBar = (wxMenuBar *) NULL;
323 m_page = (GtkNotebookPage *) NULL;
ff7b1510 324}
c801d85f
KB
325
326wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 327 wxWindowID id, const wxString& title,
33d0b396 328 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 329 long style, const wxString& name )
c801d85f 330{
83624f79
RR
331 m_menuBar = (wxMenuBar *) NULL;
332 m_page = (GtkNotebookPage *) NULL;
333 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 334}
c801d85f 335
ab2b3dd4 336wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 337{
83624f79 338 if (m_menuBar)
83624f79 339 delete m_menuBar;
72c23f8e 340}
c801d85f
KB
341
342bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 343 wxWindowID id, const wxString& title,
33d0b396 344 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 345 long style, const wxString& name )
c801d85f 346{
83624f79 347 m_title = title;
c626a8b7 348
83624f79 349 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 350}
c801d85f 351
ac0c857a
RR
352void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
353{
354 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
355}
356
357void wxMDIChildFrame::DoSetClientSize(int width, int height)
358{
359 wxWindow::DoSetClientSize( width, height );
360}
361
40d432c4 362void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
c801d85f 363{
40d432c4 364 wxWindow::DoGetClientSize( width, height );
cf4219e7 365}
9746a2ba 366
7a903311 367void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 368{
7a903311 369 wxWindow::AddChild(child);
716b7364 370}
c626a8b7 371
716b7364
RR
372void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
373{
223d09f6 374 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 375
83624f79 376 m_menuBar = menu_bar;
a3622daa 377
83624f79 378 if (m_menuBar)
716b7364 379 {
f03fc89f 380 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 381
5bd9e519 382 m_menuBar->SetParent( mdi_frame );
c626a8b7 383
ab2b3dd4 384 /* insert the invisible menu bar into the _parent_ mdi frame */
f6bcfd97
BP
385 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
386 m_menuBar->m_widget,
a2053b27 387 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
716b7364 388 }
ff7b1510 389}
cf4219e7 390
33b64e6f 391wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 392{
83624f79 393 return m_menuBar;
ff7b1510 394}
c801d85f 395
ab2b3dd4 396void wxMDIChildFrame::Activate()
c801d85f 397{
adde8c98 398 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 399 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
9e691f46 400 gint pageno = gtk_notebook_page_num( notebook, m_widget );
adde8c98 401 gtk_notebook_set_page( notebook, pageno );
ff7b1510 402}
c801d85f 403
f6bcfd97
BP
404void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
405{
406}
407
408void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 409{
f6bcfd97
BP
410#if wxUSE_STATUSBAR
411 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 412 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
413 {
414 // we don't have any help text for this item, but may be the MDI frame
415 // does?
416 mdi_frame->OnMenuHighlight(event);
417 }
418#endif // wxUSE_STATUSBAR
419}
420
421void wxMDIChildFrame::SetTitle( const wxString &title )
422{
423 if ( title == m_title )
424 return;
425
426 m_title = title;
427
428 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
429 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
fab591c5 430 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 431}
9746a2ba 432
ab2b3dd4
RR
433//-----------------------------------------------------------------------------
434// "size_allocate"
435//-----------------------------------------------------------------------------
436
865bb325 437extern "C" {
ab2b3dd4
RR
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}
865bb325 453}
ab2b3dd4 454
6ca41e57
RR
455//-----------------------------------------------------------------------------
456// InsertChild callback for wxMDIClientWindow
457//-----------------------------------------------------------------------------
458
459static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
460{
72c23f8e 461 wxString s = child->GetTitle();
83624f79 462 if (s.IsNull()) s = _("MDI child");
6ca41e57 463
ed9b9841 464 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 465 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 466
a2053b27 467 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 468 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 469
a2053b27 470 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 471
a2053b27 472 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 473
83624f79 474 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 475
f03fc89f 476 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
b1d4dd7a 477 parent_frame->m_justInserted = true;
6ca41e57
RR
478}
479
c801d85f
KB
480//-----------------------------------------------------------------------------
481// wxMDIClientWindow
482//-----------------------------------------------------------------------------
483
484IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
485
ab2b3dd4 486wxMDIClientWindow::wxMDIClientWindow()
c801d85f 487{
ff7b1510 488}
c801d85f 489
debe6624 490wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 491{
83624f79 492 CreateClient( parent, style );
ff7b1510 493}
c801d85f 494
ab2b3dd4 495wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 496{
1631916e 497
ff7b1510 498}
c801d85f 499
debe6624 500bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 501{
b1d4dd7a 502 m_needParent = true;
c626a8b7 503
83624f79 504 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 505
4dcaf11a 506 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
72c23f8e 507 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 508 {
223d09f6 509 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 510 return false;
4dcaf11a 511 }
c801d85f 512
83624f79 513 m_widget = gtk_notebook_new();
a3622daa 514
5e014a0c
RR
515 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
516 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
517
83624f79 518 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 519
f03fc89f 520 m_parent->DoAddChild( this );
c626a8b7 521
83624f79 522 PostCreation();
a3622daa 523
b1d4dd7a 524 Show( true );
a3622daa 525
b1d4dd7a 526 return true;
ff7b1510 527}
c801d85f 528
dcf924a3 529#endif