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