]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Upport hint window improvement using custom GTK+ code
[wxWidgets.git] / src / gtk / mdi.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
72c23f8e 2// Name: src/gtk/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"
88a7a4e1 20#endif
dcf924a3 21
fab591c5 22#include "wx/gtk/private.h"
716b7364 23
5e014a0c
RR
24//-----------------------------------------------------------------------------
25// "switch_page"
26//-----------------------------------------------------------------------------
27
865bb325 28extern "C" {
f6bcfd97 29static void
7941ba11 30gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5 31 GtkNotebookPage *page,
f6bcfd97
BP
32 gint WXUNUSED(page_num),
33 wxMDIParentFrame *parent )
5e014a0c 34{
e90196a5
RR
35 // send deactivate event to old child
36
5e014a0c 37 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
38 if (child)
39 {
b1d4dd7a 40 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5
RR
41 event1.SetEventObject( child);
42 child->GetEventHandler()->ProcessEvent( event1 );
43 }
f6bcfd97 44
e90196a5 45 // send activate event to new child
f6bcfd97 46
e90196a5
RR
47 wxMDIClientWindow *client_window = parent->GetClientWindow();
48 if (!client_window)
49 return;
50
51 child = (wxMDIChildFrame*) NULL;
52
222ed1d6 53 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
af6c0f1d 54 while ( node )
e90196a5 55 {
b1d4dd7a 56 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
b1d4dd7a 57
af6c0f1d
VZ
58 // child_frame can be NULL when this is called from dtor, probably
59 // because g_signal_connect (m_widget, "switch_page", (see below)
60 // isn't deleted early enough
61 if ( child_frame && child_frame->m_page == page )
f6bcfd97 62 {
e90196a5 63 child = child_frame;
f6bcfd97
BP
64 break;
65 }
b1d4dd7a 66 node = node->GetNext();
e90196a5 67 }
f6bcfd97 68
e90196a5
RR
69 if (!child)
70 return;
f6bcfd97 71
b1d4dd7a 72 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5
RR
73 event2.SetEventObject( child);
74 child->GetEventHandler()->ProcessEvent( event2 );
5e014a0c 75}
865bb325 76}
5e014a0c 77
6ca41e57
RR
78//-----------------------------------------------------------------------------
79// wxMDIParentFrame
33d0b396
RR
80//-----------------------------------------------------------------------------
81
c801d85f
KB
82IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
83
f6bcfd97 84void wxMDIParentFrame::Init()
c801d85f 85{
b1d4dd7a 86 m_justInserted = false;
83624f79 87 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 88}
c801d85f 89
ab2b3dd4 90wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 91{
ff7b1510 92}
c801d85f 93
f6bcfd97
BP
94bool wxMDIParentFrame::Create(wxWindow *parent,
95 wxWindowID id,
96 const wxString& title,
97 const wxPoint& pos,
98 const wxSize& size,
99 long style,
100 const wxString& name )
c801d85f 101{
83624f79 102 wxFrame::Create( parent, id, title, pos, size, style, name );
a3622daa 103
83624f79 104 OnCreateClient();
a3622daa 105
b1d4dd7a 106 return true;
ff7b1510 107}
c801d85f 108
ab2b3dd4
RR
109void wxMDIParentFrame::OnInternalIdle()
110{
111 /* if a an MDI child window has just been inserted
112 it has to be brought to the top in idle time. we
113 simply set the last notebook page active as new
114 pages can only be appended at the end */
115
116 if (m_justInserted)
83624f79 117 {
a2053b27 118 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
38f1df7c 119 gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
a0fdacee 120
147d6669 121 /* need to set the menubar of the child */
1d608029 122 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 123 if (active_child_frame != NULL)
147d6669 124 {
1b10056f
RD
125 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
126 if (menu_bar)
127 {
1b10056f
RD
128 menu_bar->SetInvokingWindow(active_child_frame);
129 }
147d6669 130 }
b1d4dd7a 131 m_justInserted = false;
a0fdacee 132 return;
83624f79 133 }
a0fdacee 134
ab2b3dd4 135 wxFrame::OnInternalIdle();
c626a8b7 136
ab2b3dd4 137 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 138 bool visible_child_menu = false;
a0fdacee 139
222ed1d6 140 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 141 while (node)
83624f79 142 {
b1d4dd7a
RL
143 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
144
f6bcfd97 145 if ( child_frame )
a0fdacee 146 {
f6bcfd97
BP
147 wxMenuBar *menu_bar = child_frame->m_menuBar;
148 if ( menu_bar )
f03fc89f 149 {
f6bcfd97
BP
150 if (child_frame == active_child_frame)
151 {
b1d4dd7a 152 if (menu_bar->Show(true))
f6bcfd97 153 {
f6bcfd97
BP
154 menu_bar->SetInvokingWindow( child_frame );
155 }
b1d4dd7a 156 visible_child_menu = true;
f6bcfd97
BP
157 }
158 else
159 {
b1d4dd7a 160 if (menu_bar->Show(false))
f6bcfd97
BP
161 {
162 menu_bar->UnsetInvokingWindow( child_frame );
163 }
164 }
f03fc89f 165 }
a0fdacee 166 }
f6bcfd97 167
b1d4dd7a 168 node = node->GetNext();
83624f79 169 }
a0fdacee 170
e27ce4e9 171 /* show/hide parent menu bar as required */
5bd9e519
RR
172 if ((m_frameMenuBar) &&
173 (m_frameMenuBar->IsShown() == visible_child_menu))
174 {
175 if (visible_child_menu)
f6bcfd97 176 {
b1d4dd7a 177 m_frameMenuBar->Show( false );
f6bcfd97
BP
178 m_frameMenuBar->UnsetInvokingWindow( this );
179 }
180 else
181 {
b1d4dd7a 182 m_frameMenuBar->Show( true );
f6bcfd97 183 m_frameMenuBar->SetInvokingWindow( this );
cca410b3
PC
184 }
185 }
186}
f6bcfd97 187
cca410b3
PC
188void wxMDIParentFrame::DoGetClientSize(int* width, int* height) const
189{
190 wxFrame::DoGetClientSize(width, height);
191
192 if (height)
193 {
194 wxMDIChildFrame* active_child_frame = GetActiveChild();
195 if (active_child_frame)
196 {
197 wxMenuBar* menubar = active_child_frame->m_menuBar;
198 if (menubar && menubar->IsShown())
199 {
200 GtkRequisition req;
201 gtk_widget_size_request(menubar->m_widget, &req);
202 *height -= req.height;
203 if (*height < 0) *height = 0;
204 }
f6bcfd97 205 }
5bd9e519 206 }
ff7b1510 207}
716b7364 208
ab2b3dd4
RR
209wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
210{
211 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 212
a2053b27 213 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 214 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee 215
ab2b3dd4
RR
216 gint i = gtk_notebook_get_current_page( notebook );
217 if (i < 0) return (wxMDIChildFrame*) NULL;
f4322df6 218
ab2b3dd4
RR
219 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
220 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 221
222ed1d6 222 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
223 while (node)
224 {
3811dacb
RR
225 if ( wxPendingDelete.Member(node->GetData()) )
226 return (wxMDIChildFrame*) NULL;
f4322df6 227
b1d4dd7a
RL
228 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
229
3811dacb
RR
230 if (!child_frame)
231 return (wxMDIChildFrame*) NULL;
b1d4dd7a 232
ab2b3dd4
RR
233 if (child_frame->m_page == page)
234 return child_frame;
f4322df6 235
b1d4dd7a 236 node = node->GetNext();
ab2b3dd4 237 }
a0fdacee 238
ab2b3dd4 239 return (wxMDIChildFrame*) NULL;
ff7b1510 240}
c801d85f 241
ab2b3dd4 242wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 243{
83624f79 244 return m_clientWindow;
ff7b1510 245}
c801d85f 246
ab2b3dd4 247wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 248{
83624f79
RR
249 m_clientWindow = new wxMDIClientWindow( this );
250 return m_clientWindow;
ff7b1510 251}
c801d85f 252
ab2b3dd4 253void wxMDIParentFrame::ActivateNext()
c801d85f 254{
83624f79 255 if (m_clientWindow)
a2053b27 256 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 257}
c801d85f 258
ab2b3dd4 259void wxMDIParentFrame::ActivatePrevious()
716b7364 260{
83624f79 261 if (m_clientWindow)
a2053b27 262 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 263}
716b7364 264
c801d85f
KB
265//-----------------------------------------------------------------------------
266// wxMDIChildFrame
267//-----------------------------------------------------------------------------
268
cf4219e7 269IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 270
cf4219e7 271BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 272 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 273 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
274END_EVENT_TABLE()
275
ab2b3dd4 276wxMDIChildFrame::wxMDIChildFrame()
c801d85f 277{
83624f79
RR
278 m_menuBar = (wxMenuBar *) NULL;
279 m_page = (GtkNotebookPage *) NULL;
ff7b1510 280}
c801d85f
KB
281
282wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 283 wxWindowID id, const wxString& title,
33d0b396 284 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 285 long style, const wxString& name )
c801d85f 286{
83624f79
RR
287 m_menuBar = (wxMenuBar *) NULL;
288 m_page = (GtkNotebookPage *) NULL;
289 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 290}
c801d85f 291
ab2b3dd4 292wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 293{
83624f79 294 if (m_menuBar)
83624f79 295 delete m_menuBar;
72c23f8e 296}
c801d85f
KB
297
298bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 299 wxWindowID id, const wxString& title,
33d0b396 300 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 301 long style, const wxString& name )
c801d85f 302{
83624f79 303 m_title = title;
c626a8b7 304
83624f79 305 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 306}
c801d85f 307
3811dacb
RR
308bool wxMDIChildFrame::Destroy()
309{
310 // delayed destruction: the frame will be deleted during
311 // the next idle loop iteration.
312 // I'm not sure if delayed destruction really makes so
313 // much sense for MDI child frames, actually, but hiding
314 // it doesn't make any sense.
315 if ( !wxPendingDelete.Member(this) )
316 wxPendingDelete.Append(this);
317
318 return true;
319}
320
ac0c857a
RR
321void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
322{
323 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
324}
325
7a903311 326void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 327{
7a903311 328 wxWindow::AddChild(child);
716b7364 329}
c626a8b7 330
716b7364
RR
331void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
332{
223d09f6 333 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 334
83624f79 335 m_menuBar = menu_bar;
a3622daa 336
83624f79 337 if (m_menuBar)
716b7364 338 {
f03fc89f 339 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 340
5bd9e519 341 m_menuBar->SetParent( mdi_frame );
c626a8b7 342
ab2b3dd4 343 /* insert the invisible menu bar into the _parent_ mdi frame */
cca410b3
PC
344 m_menuBar->Show(false);
345 gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
346 gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
347
348 gulong handler_id = g_signal_handler_find(
349 m_menuBar->m_widget,
350 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
351 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
352 0, NULL, NULL, m_menuBar);
353 if (handler_id != 0)
354 g_signal_handler_disconnect(m_menuBar->m_widget, handler_id);
355 gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
716b7364 356 }
ff7b1510 357}
cf4219e7 358
33b64e6f 359wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 360{
83624f79 361 return m_menuBar;
ff7b1510 362}
c801d85f 363
ab2b3dd4 364void wxMDIChildFrame::Activate()
c801d85f 365{
adde8c98 366 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 367 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
9e691f46 368 gint pageno = gtk_notebook_page_num( notebook, m_widget );
38f1df7c 369 gtk_notebook_set_current_page( notebook, pageno );
ff7b1510 370}
c801d85f 371
f6bcfd97
BP
372void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
373{
374}
375
376void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 377{
f6bcfd97
BP
378#if wxUSE_STATUSBAR
379 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 380 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
381 {
382 // we don't have any help text for this item, but may be the MDI frame
383 // does?
384 mdi_frame->OnMenuHighlight(event);
385 }
386#endif // wxUSE_STATUSBAR
387}
388
389void wxMDIChildFrame::SetTitle( const wxString &title )
390{
391 if ( title == m_title )
392 return;
393
394 m_title = title;
395
396 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
397 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
fab591c5 398 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 399}
9746a2ba 400
6ca41e57
RR
401//-----------------------------------------------------------------------------
402// InsertChild callback for wxMDIClientWindow
403//-----------------------------------------------------------------------------
404
c821db16 405static void wxInsertChildInMDI(wxWindow* parent, wxWindow* child)
6ca41e57 406{
c821db16
PC
407 wxMDIChildFrame* child_frame = wx_static_cast(wxMDIChildFrame*, child);
408 wxString s = child_frame->GetTitle();
83624f79 409 if (s.IsNull()) s = _("MDI child");
6ca41e57 410
ed9b9841 411 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 412 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 413
a2053b27 414 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 415
a2053b27 416 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 417
c821db16 418 child_frame->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 419
c821db16 420 wxMDIParentFrame *parent_frame = wx_static_cast(wxMDIParentFrame*, parent->GetParent());
b1d4dd7a 421 parent_frame->m_justInserted = true;
6ca41e57
RR
422}
423
c801d85f
KB
424//-----------------------------------------------------------------------------
425// wxMDIClientWindow
426//-----------------------------------------------------------------------------
427
428IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
429
ab2b3dd4 430wxMDIClientWindow::wxMDIClientWindow()
c801d85f 431{
ff7b1510 432}
c801d85f 433
debe6624 434wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 435{
83624f79 436 CreateClient( parent, style );
ff7b1510 437}
c801d85f 438
ab2b3dd4 439wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 440{
1631916e 441
ff7b1510 442}
c801d85f 443
debe6624 444bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 445{
c821db16 446 m_insertCallback = wxInsertChildInMDI;
a3622daa 447
4dcaf11a 448 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
72c23f8e 449 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 450 {
223d09f6 451 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 452 return false;
4dcaf11a 453 }
c801d85f 454
83624f79 455 m_widget = gtk_notebook_new();
a3622daa 456
9fa72bd2
MR
457 g_signal_connect (m_widget, "switch_page",
458 G_CALLBACK (gtk_mdi_page_change_callback), parent);
5e014a0c 459
83624f79 460 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 461
f03fc89f 462 m_parent->DoAddChild( this );
c626a8b7 463
83624f79 464 PostCreation();
a3622daa 465
b1d4dd7a 466 Show( true );
a3622daa 467
b1d4dd7a 468 return true;
ff7b1510 469}
c801d85f 470
e8375af8 471#endif // wxUSE_MDI