]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
update GTK size hints when window decorations change
[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
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 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;
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;
002626c5
PC
296
297 // wxMDIClientWindow does not get redrawn properly after last child is removed
298 if (m_parent && m_parent->GetChildren().size() <= 1)
299 gtk_widget_queue_draw(m_parent->m_widget);
72c23f8e 300}
c801d85f
KB
301
302bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 303 wxWindowID id, const wxString& title,
33d0b396 304 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 305 long style, const wxString& name )
c801d85f 306{
83624f79 307 m_title = title;
c626a8b7 308
83624f79 309 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 310}
c801d85f 311
3811dacb
RR
312bool wxMDIChildFrame::Destroy()
313{
314 // delayed destruction: the frame will be deleted during
315 // the next idle loop iteration.
316 // I'm not sure if delayed destruction really makes so
317 // much sense for MDI child frames, actually, but hiding
318 // it doesn't make any sense.
319 if ( !wxPendingDelete.Member(this) )
320 wxPendingDelete.Append(this);
321
322 return true;
323}
324
ac0c857a
RR
325void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
326{
327 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
328}
329
7a903311 330void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 331{
7a903311 332 wxWindow::AddChild(child);
716b7364 333}
c626a8b7 334
716b7364
RR
335void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
336{
223d09f6 337 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 338
83624f79 339 m_menuBar = menu_bar;
a3622daa 340
83624f79 341 if (m_menuBar)
716b7364 342 {
f03fc89f 343 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 344
5bd9e519 345 m_menuBar->SetParent( mdi_frame );
c626a8b7 346
ab2b3dd4 347 /* insert the invisible menu bar into the _parent_ mdi frame */
cca410b3
PC
348 m_menuBar->Show(false);
349 gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
350 gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
351
352 gulong handler_id = g_signal_handler_find(
353 m_menuBar->m_widget,
354 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
355 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
356 0, NULL, NULL, m_menuBar);
357 if (handler_id != 0)
358 g_signal_handler_disconnect(m_menuBar->m_widget, handler_id);
359 gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
716b7364 360 }
ff7b1510 361}
cf4219e7 362
33b64e6f 363wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 364{
83624f79 365 return m_menuBar;
ff7b1510 366}
c801d85f 367
ab2b3dd4 368void wxMDIChildFrame::Activate()
c801d85f 369{
adde8c98 370 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 371 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
9e691f46 372 gint pageno = gtk_notebook_page_num( notebook, m_widget );
38f1df7c 373 gtk_notebook_set_current_page( notebook, pageno );
ff7b1510 374}
c801d85f 375
f6bcfd97
BP
376void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
377{
378}
379
380void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 381{
f6bcfd97
BP
382#if wxUSE_STATUSBAR
383 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 384 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
385 {
386 // we don't have any help text for this item, but may be the MDI frame
387 // does?
388 mdi_frame->OnMenuHighlight(event);
389 }
390#endif // wxUSE_STATUSBAR
391}
392
393void wxMDIChildFrame::SetTitle( const wxString &title )
394{
395 if ( title == m_title )
396 return;
397
398 m_title = title;
399
400 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
401 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
fab591c5 402 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 403}
9746a2ba 404
6ca41e57
RR
405//-----------------------------------------------------------------------------
406// InsertChild callback for wxMDIClientWindow
407//-----------------------------------------------------------------------------
408
c821db16 409static void wxInsertChildInMDI(wxWindow* parent, wxWindow* child)
6ca41e57 410{
c821db16
PC
411 wxMDIChildFrame* child_frame = wx_static_cast(wxMDIChildFrame*, child);
412 wxString s = child_frame->GetTitle();
83624f79 413 if (s.IsNull()) s = _("MDI child");
6ca41e57 414
ed9b9841 415 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 416 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 417
a2053b27 418 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 419
a2053b27 420 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 421
c821db16 422 child_frame->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 423
c821db16 424 wxMDIParentFrame *parent_frame = wx_static_cast(wxMDIParentFrame*, parent->GetParent());
b1d4dd7a 425 parent_frame->m_justInserted = true;
6ca41e57
RR
426}
427
c801d85f
KB
428//-----------------------------------------------------------------------------
429// wxMDIClientWindow
430//-----------------------------------------------------------------------------
431
432IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
433
ab2b3dd4 434wxMDIClientWindow::wxMDIClientWindow()
c801d85f 435{
ff7b1510 436}
c801d85f 437
debe6624 438wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 439{
83624f79 440 CreateClient( parent, style );
ff7b1510 441}
c801d85f 442
ab2b3dd4 443wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 444{
1631916e 445
ff7b1510 446}
c801d85f 447
debe6624 448bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 449{
c821db16 450 m_insertCallback = wxInsertChildInMDI;
a3622daa 451
4dcaf11a 452 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
72c23f8e 453 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 454 {
223d09f6 455 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 456 return false;
4dcaf11a 457 }
c801d85f 458
83624f79 459 m_widget = gtk_notebook_new();
a3622daa 460
9fa72bd2
MR
461 g_signal_connect (m_widget, "switch_page",
462 G_CALLBACK (gtk_mdi_page_change_callback), parent);
5e014a0c 463
83624f79 464 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 465
f03fc89f 466 m_parent->DoAddChild( this );
c626a8b7 467
83624f79 468 PostCreation();
a3622daa 469
b1d4dd7a 470 Show( true );
a3622daa 471
b1d4dd7a 472 return true;
ff7b1510 473}
c801d85f 474
e8375af8 475#endif // wxUSE_MDI