]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
better fix for #11803, don't set iconized state for hidden window
[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 41 event1.SetEventObject( child);
937013e0 42 child->HandleWindowEvent( event1 );
e90196a5 43 }
f6bcfd97 44
e90196a5 45 // send activate event to new child
f6bcfd97 46
d2824cdb
VZ
47 wxMDIClientWindowBase *client_window = parent->GetClientWindow();
48 if ( !client_window )
e90196a5
RR
49 return;
50
d2824cdb 51 child = NULL;
e90196a5 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 73 event2.SetEventObject( child);
937013e0 74 child->HandleWindowEvent( 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;
ff7b1510 87}
c801d85f 88
f6bcfd97
BP
89bool wxMDIParentFrame::Create(wxWindow *parent,
90 wxWindowID id,
91 const wxString& title,
92 const wxPoint& pos,
93 const wxSize& size,
94 long style,
95 const wxString& name )
c801d85f 96{
6e42617a
VZ
97 if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
98 return false;
a3622daa 99
6e42617a 100 m_clientWindow = OnCreateClient();
d2824cdb
VZ
101 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
102 return false;
a3622daa 103
d2824cdb 104 return true;
ff7b1510 105}
c801d85f 106
ab2b3dd4
RR
107void wxMDIParentFrame::OnInternalIdle()
108{
d2824cdb 109 /* if a MDI child window has just been inserted
ab2b3dd4
RR
110 it has to be brought to the top in idle time. we
111 simply set the last notebook page active as new
112 pages can only be appended at the end */
113
114 if (m_justInserted)
83624f79 115 {
a2053b27 116 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
38f1df7c 117 gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
a0fdacee 118
147d6669 119 /* need to set the menubar of the child */
1d608029 120 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 121 if (active_child_frame != NULL)
147d6669 122 {
1b10056f
RD
123 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
124 if (menu_bar)
125 {
1b10056f
RD
126 menu_bar->SetInvokingWindow(active_child_frame);
127 }
147d6669 128 }
b1d4dd7a 129 m_justInserted = false;
a0fdacee 130 return;
83624f79 131 }
a0fdacee 132
ab2b3dd4 133 wxFrame::OnInternalIdle();
c626a8b7 134
ab2b3dd4 135 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 136 bool visible_child_menu = false;
a0fdacee 137
222ed1d6 138 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 139 while (node)
83624f79 140 {
b1d4dd7a
RL
141 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
142
f6bcfd97 143 if ( child_frame )
a0fdacee 144 {
f6bcfd97
BP
145 wxMenuBar *menu_bar = child_frame->m_menuBar;
146 if ( menu_bar )
f03fc89f 147 {
f6bcfd97
BP
148 if (child_frame == active_child_frame)
149 {
b1d4dd7a 150 if (menu_bar->Show(true))
f6bcfd97 151 {
f6bcfd97
BP
152 menu_bar->SetInvokingWindow( child_frame );
153 }
b1d4dd7a 154 visible_child_menu = true;
f6bcfd97
BP
155 }
156 else
157 {
b1d4dd7a 158 if (menu_bar->Show(false))
f6bcfd97
BP
159 {
160 menu_bar->UnsetInvokingWindow( child_frame );
161 }
162 }
f03fc89f 163 }
a0fdacee 164 }
f6bcfd97 165
b1d4dd7a 166 node = node->GetNext();
83624f79 167 }
a0fdacee 168
e27ce4e9 169 /* show/hide parent menu bar as required */
5bd9e519
RR
170 if ((m_frameMenuBar) &&
171 (m_frameMenuBar->IsShown() == visible_child_menu))
172 {
173 if (visible_child_menu)
f6bcfd97 174 {
b1d4dd7a 175 m_frameMenuBar->Show( false );
f6bcfd97
BP
176 m_frameMenuBar->UnsetInvokingWindow( this );
177 }
178 else
179 {
b1d4dd7a 180 m_frameMenuBar->Show( true );
f6bcfd97 181 m_frameMenuBar->SetInvokingWindow( this );
cca410b3
PC
182 }
183 }
184}
f6bcfd97 185
cca410b3
PC
186void wxMDIParentFrame::DoGetClientSize(int* width, int* height) const
187{
188 wxFrame::DoGetClientSize(width, height);
189
190 if (height)
191 {
192 wxMDIChildFrame* active_child_frame = GetActiveChild();
193 if (active_child_frame)
194 {
195 wxMenuBar* menubar = active_child_frame->m_menuBar;
196 if (menubar && menubar->IsShown())
197 {
198 GtkRequisition req;
199 gtk_widget_size_request(menubar->m_widget, &req);
200 *height -= req.height;
201 if (*height < 0) *height = 0;
202 }
f6bcfd97 203 }
5bd9e519 204 }
ff7b1510 205}
716b7364 206
ab2b3dd4
RR
207wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
208{
d2824cdb 209 if (!m_clientWindow) return NULL;
a0fdacee 210
a2053b27 211 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
d2824cdb 212 if (!notebook) return NULL;
a0fdacee 213
ab2b3dd4 214 gint i = gtk_notebook_get_current_page( notebook );
d2824cdb 215 if (i < 0) return NULL;
f4322df6 216
ab2b3dd4 217 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
d2824cdb 218 if (!page) return NULL;
a0fdacee 219
222ed1d6 220 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
221 while (node)
222 {
3811dacb 223 if ( wxPendingDelete.Member(node->GetData()) )
d2824cdb 224 return NULL;
f4322df6 225
b1d4dd7a
RL
226 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
227
3811dacb 228 if (!child_frame)
d2824cdb 229 return NULL;
b1d4dd7a 230
ab2b3dd4
RR
231 if (child_frame->m_page == page)
232 return child_frame;
f4322df6 233
b1d4dd7a 234 node = node->GetNext();
ab2b3dd4 235 }
a0fdacee 236
d2824cdb 237 return NULL;
ff7b1510 238}
c801d85f 239
ab2b3dd4 240void wxMDIParentFrame::ActivateNext()
c801d85f 241{
83624f79 242 if (m_clientWindow)
a2053b27 243 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 244}
c801d85f 245
ab2b3dd4 246void wxMDIParentFrame::ActivatePrevious()
716b7364 247{
83624f79 248 if (m_clientWindow)
a2053b27 249 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 250}
716b7364 251
c801d85f
KB
252//-----------------------------------------------------------------------------
253// wxMDIChildFrame
254//-----------------------------------------------------------------------------
255
cf4219e7 256IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 257
cf4219e7 258BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 259 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 260 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
261END_EVENT_TABLE()
262
d2824cdb 263void wxMDIChildFrame::Init()
c801d85f 264{
d2824cdb
VZ
265 m_menuBar = NULL;
266 m_page = NULL;
ff7b1510 267}
c801d85f 268
d2824cdb
VZ
269bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
270 wxWindowID id,
271 const wxString& title,
272 const wxPoint& WXUNUSED(pos),
273 const wxSize& size,
274 long style,
275 const wxString& name)
c801d85f 276{
d2824cdb
VZ
277 m_mdiParent = parent;
278 m_title = title;
279
280 return wxWindow::Create(parent->GetClientWindow(), id,
281 wxDefaultPosition, size,
282 style, name);
ff7b1510 283}
c801d85f 284
ab2b3dd4 285wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 286{
d2824cdb 287 delete m_menuBar;
002626c5
PC
288
289 // wxMDIClientWindow does not get redrawn properly after last child is removed
290 if (m_parent && m_parent->GetChildren().size() <= 1)
291 gtk_widget_queue_draw(m_parent->m_widget);
72c23f8e 292}
c801d85f 293
716b7364
RR
294void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
295{
d2824cdb 296 wxASSERT_MSG( m_menuBar == NULL, "Only one menubar allowed" );
5bd9e519 297
83624f79 298 m_menuBar = menu_bar;
a3622daa 299
83624f79 300 if (m_menuBar)
716b7364 301 {
f03fc89f 302 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 303
5bd9e519 304 m_menuBar->SetParent( mdi_frame );
c626a8b7 305
ab2b3dd4 306 /* insert the invisible menu bar into the _parent_ mdi frame */
cca410b3
PC
307 m_menuBar->Show(false);
308 gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
309 gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
310
311 gulong handler_id = g_signal_handler_find(
312 m_menuBar->m_widget,
313 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
314 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
315 0, NULL, NULL, m_menuBar);
316 if (handler_id != 0)
317 g_signal_handler_disconnect(m_menuBar->m_widget, handler_id);
318 gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
716b7364 319 }
ff7b1510 320}
cf4219e7 321
33b64e6f 322wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 323{
83624f79 324 return m_menuBar;
ff7b1510 325}
c801d85f 326
d2824cdb
VZ
327GtkNotebook *wxMDIChildFrame::GTKGetNotebook() const
328{
329 wxMDIClientWindow * const
330 client = wxStaticCast(GetParent(), wxMDIClientWindow);
331 wxCHECK( client, NULL );
332
333 return GTK_NOTEBOOK(client->m_widget);
334}
335
ab2b3dd4 336void wxMDIChildFrame::Activate()
c801d85f 337{
d2824cdb
VZ
338 GtkNotebook * const notebook = GTKGetNotebook();
339 wxCHECK_RET( notebook, "no parent notebook?" );
340
9e691f46 341 gint pageno = gtk_notebook_page_num( notebook, m_widget );
38f1df7c 342 gtk_notebook_set_current_page( notebook, pageno );
ff7b1510 343}
c801d85f 344
f6bcfd97
BP
345void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
346{
347}
348
349void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 350{
f6bcfd97
BP
351#if wxUSE_STATUSBAR
352 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 353 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
354 {
355 // we don't have any help text for this item, but may be the MDI frame
356 // does?
357 mdi_frame->OnMenuHighlight(event);
358 }
359#endif // wxUSE_STATUSBAR
360}
361
362void wxMDIChildFrame::SetTitle( const wxString &title )
363{
364 if ( title == m_title )
365 return;
366
367 m_title = title;
368
d2824cdb
VZ
369 GtkNotebook * const notebook = GTKGetNotebook();
370 wxCHECK_RET( notebook, "no parent notebook?" );
fab591c5 371 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 372}
9746a2ba 373
c801d85f
KB
374//-----------------------------------------------------------------------------
375// wxMDIClientWindow
376//-----------------------------------------------------------------------------
377
d2824cdb 378IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
c801d85f 379
5a0a15cf
FM
380wxMDIClientWindow::~wxMDIClientWindow()
381{
382 // disconnect our handler because our ~wxWindow (which is going to be called
383 // after this dtor) will call DestroyChildren(); in turns our children
384 // ~wxWindow dtors will call wxWindow::Show(false) and this will generate
385 // a call to gtk_mdi_page_change_callback with an invalid parent
386 // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but
387 // at that point of the dtor chain we are a simple wxWindow!)
03647350 388 g_signal_handlers_disconnect_by_func(m_widget,
5a0a15cf
FM
389 (gpointer)gtk_mdi_page_change_callback,
390 GetParent());
391}
392
d2824cdb 393bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
c801d85f 394{
d2824cdb
VZ
395 if ( !PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
396 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
397 style, wxDefaultValidator, "wxMDIClientWindow" ))
4dcaf11a 398 {
d2824cdb 399 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
b1d4dd7a 400 return false;
4dcaf11a 401 }
c801d85f 402
83624f79 403 m_widget = gtk_notebook_new();
9ff9d30c 404 g_object_ref(m_widget);
a3622daa 405
9fa72bd2
MR
406 g_signal_connect (m_widget, "switch_page",
407 G_CALLBACK (gtk_mdi_page_change_callback), parent);
5e014a0c 408
83624f79 409 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 410
f03fc89f 411 m_parent->DoAddChild( this );
c626a8b7 412
83624f79 413 PostCreation();
a3622daa 414
b1d4dd7a 415 Show( true );
a3622daa 416
b1d4dd7a 417 return true;
ff7b1510 418}
c801d85f 419
d2824cdb
VZ
420void wxMDIClientWindow::AddChildGTK(wxWindowGTK* child)
421{
422 wxMDIChildFrame* child_frame = static_cast<wxMDIChildFrame*>(child);
423 wxString s = child_frame->GetTitle();
424 if ( s.empty() )
425 s = _("MDI child");
426
427 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
428 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
429
430 GtkNotebook* notebook = GTK_NOTEBOOK(m_widget);
431
432 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
433
434 child_frame->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
435
436 wxMDIParentFrame* parent_frame = static_cast<wxMDIParentFrame*>(GetParent());
437 parent_frame->m_justInserted = true;
438}
439
e8375af8 440#endif // wxUSE_MDI