]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/mdi.cpp
fix compilation with wxUSE_EXTENDED_RTTI && !WXWIN_COMPATIBILITY_2_6 (bug 1688249)
[wxWidgets.git] / src / gtk / mdi.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/mdi.cpp
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#if wxUSE_MDI
14
15#include "wx/mdi.h"
16
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
19 #include "wx/menu.h"
20 #include "wx/dialog.h"
21#endif
22
23#include "wx/notebook.h"
24#include "wx/gtk/private.h"
25
26#include <glib.h>
27#include <gdk/gdk.h>
28#include <gtk/gtk.h>
29#include "wx/gtk/win_gtk.h"
30
31//-----------------------------------------------------------------------------
32// constants
33//-----------------------------------------------------------------------------
34
35const int wxMENU_HEIGHT = 27;
36
37//-----------------------------------------------------------------------------
38// globals
39//-----------------------------------------------------------------------------
40
41//-----------------------------------------------------------------------------
42// "switch_page"
43//-----------------------------------------------------------------------------
44
45extern "C" {
46static void
47gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
48 GtkNotebookPage *page,
49 gint WXUNUSED(page_num),
50 wxMDIParentFrame *parent )
51{
52 if (g_isIdle)
53 wxapp_install_idle_handler();
54
55 // send deactivate event to old child
56
57 wxMDIChildFrame *child = parent->GetActiveChild();
58 if (child)
59 {
60 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
61 event1.SetEventObject( child);
62 child->GetEventHandler()->ProcessEvent( event1 );
63 }
64
65 // send activate event to new child
66
67 wxMDIClientWindow *client_window = parent->GetClientWindow();
68 if (!client_window)
69 return;
70
71 child = (wxMDIChildFrame*) NULL;
72
73 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
74 while ( node )
75 {
76 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
77
78 // child_frame can be NULL when this is called from dtor, probably
79 // because g_signal_connect (m_widget, "switch_page", (see below)
80 // isn't deleted early enough
81 if ( child_frame && child_frame->m_page == page )
82 {
83 child = child_frame;
84 break;
85 }
86 node = node->GetNext();
87 }
88
89 if (!child)
90 return;
91
92 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
93 event2.SetEventObject( child);
94 child->GetEventHandler()->ProcessEvent( event2 );
95}
96}
97
98//-----------------------------------------------------------------------------
99// wxMDIParentFrame
100//-----------------------------------------------------------------------------
101
102IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
103
104void wxMDIParentFrame::Init()
105{
106 m_justInserted = false;
107 m_clientWindow = (wxMDIClientWindow *) NULL;
108}
109
110wxMDIParentFrame::~wxMDIParentFrame()
111{
112}
113
114bool wxMDIParentFrame::Create(wxWindow *parent,
115 wxWindowID id,
116 const wxString& title,
117 const wxPoint& pos,
118 const wxSize& size,
119 long style,
120 const wxString& name )
121{
122 wxFrame::Create( parent, id, title, pos, size, style, name );
123
124 OnCreateClient();
125
126 return true;
127}
128
129void wxMDIParentFrame::GtkOnSize()
130{
131 wxFrame::GtkOnSize();
132
133 wxMDIChildFrame *child_frame = GetActiveChild();
134 if (!child_frame) return;
135
136 wxMenuBar *menu_bar = child_frame->m_menuBar;
137 if (!menu_bar) return;
138 if (!menu_bar->m_widget) return;
139
140 menu_bar->m_x = 0;
141 menu_bar->m_y = 0;
142 menu_bar->m_width = m_width;
143 menu_bar->m_height = wxMENU_HEIGHT;
144 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
145 menu_bar->m_widget,
146 0, 0, m_width, wxMENU_HEIGHT );
147}
148
149void wxMDIParentFrame::OnInternalIdle()
150{
151 /* if a an MDI child window has just been inserted
152 it has to be brought to the top in idle time. we
153 simply set the last notebook page active as new
154 pages can only be appended at the end */
155
156 if (m_justInserted)
157 {
158 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
159 gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
160
161 /* need to set the menubar of the child */
162 wxMDIChildFrame *active_child_frame = GetActiveChild();
163 if (active_child_frame != NULL)
164 {
165 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
166 if (menu_bar)
167 {
168 menu_bar->m_width = m_width;
169 menu_bar->m_height = wxMENU_HEIGHT;
170 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
171 menu_bar->m_widget,
172 0, 0, m_width, wxMENU_HEIGHT );
173 menu_bar->SetInvokingWindow(active_child_frame);
174 }
175 }
176 m_justInserted = false;
177 return;
178 }
179
180 wxFrame::OnInternalIdle();
181
182 wxMDIChildFrame *active_child_frame = GetActiveChild();
183 bool visible_child_menu = false;
184
185 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
186 while (node)
187 {
188 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
189
190 if ( child_frame )
191 {
192 wxMenuBar *menu_bar = child_frame->m_menuBar;
193 if ( menu_bar )
194 {
195 if (child_frame == active_child_frame)
196 {
197 if (menu_bar->Show(true))
198 {
199 menu_bar->m_width = m_width;
200 menu_bar->m_height = wxMENU_HEIGHT;
201 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
202 menu_bar->m_widget,
203 0, 0, m_width, wxMENU_HEIGHT );
204 menu_bar->SetInvokingWindow( child_frame );
205 }
206 visible_child_menu = true;
207 }
208 else
209 {
210 if (menu_bar->Show(false))
211 {
212 menu_bar->UnsetInvokingWindow( child_frame );
213 }
214 }
215 }
216 }
217
218 node = node->GetNext();
219 }
220
221 /* show/hide parent menu bar as required */
222 if ((m_frameMenuBar) &&
223 (m_frameMenuBar->IsShown() == visible_child_menu))
224 {
225 if (visible_child_menu)
226 {
227 m_frameMenuBar->Show( false );
228 m_frameMenuBar->UnsetInvokingWindow( this );
229 }
230 else
231 {
232 m_frameMenuBar->Show( true );
233 m_frameMenuBar->SetInvokingWindow( this );
234
235 m_frameMenuBar->m_width = m_width;
236 m_frameMenuBar->m_height = wxMENU_HEIGHT;
237 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
238 m_frameMenuBar->m_widget,
239 0, 0, m_width, wxMENU_HEIGHT );
240 }
241 }
242}
243
244wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
245{
246 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
247
248 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
249 if (!notebook) return (wxMDIChildFrame*) NULL;
250
251 gint i = gtk_notebook_get_current_page( notebook );
252 if (i < 0) return (wxMDIChildFrame*) NULL;
253
254 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
255 if (!page) return (wxMDIChildFrame*) NULL;
256
257 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
258 while (node)
259 {
260 if ( wxPendingDelete.Member(node->GetData()) )
261 return (wxMDIChildFrame*) NULL;
262
263 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
264
265 if (!child_frame)
266 return (wxMDIChildFrame*) NULL;
267
268 if (child_frame->m_page == page)
269 return child_frame;
270
271 node = node->GetNext();
272 }
273
274 return (wxMDIChildFrame*) NULL;
275}
276
277wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
278{
279 return m_clientWindow;
280}
281
282wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
283{
284 m_clientWindow = new wxMDIClientWindow( this );
285 return m_clientWindow;
286}
287
288void wxMDIParentFrame::ActivateNext()
289{
290 if (m_clientWindow)
291 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
292}
293
294void wxMDIParentFrame::ActivatePrevious()
295{
296 if (m_clientWindow)
297 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
298}
299
300//-----------------------------------------------------------------------------
301// wxMDIChildFrame
302//-----------------------------------------------------------------------------
303
304IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
305
306BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
307 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
308 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
309END_EVENT_TABLE()
310
311wxMDIChildFrame::wxMDIChildFrame()
312{
313 m_menuBar = (wxMenuBar *) NULL;
314 m_page = (GtkNotebookPage *) NULL;
315}
316
317wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
318 wxWindowID id, const wxString& title,
319 const wxPoint& WXUNUSED(pos), const wxSize& size,
320 long style, const wxString& name )
321{
322 m_menuBar = (wxMenuBar *) NULL;
323 m_page = (GtkNotebookPage *) NULL;
324 Create( parent, id, title, wxDefaultPosition, size, style, name );
325}
326
327wxMDIChildFrame::~wxMDIChildFrame()
328{
329 if (m_menuBar)
330 delete m_menuBar;
331}
332
333bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
334 wxWindowID id, const wxString& title,
335 const wxPoint& WXUNUSED(pos), const wxSize& size,
336 long style, const wxString& name )
337{
338 m_title = title;
339
340 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
341}
342
343bool wxMDIChildFrame::Destroy()
344{
345 // delayed destruction: the frame will be deleted during
346 // the next idle loop iteration.
347 // I'm not sure if delayed destruction really makes so
348 // much sense for MDI child frames, actually, but hiding
349 // it doesn't make any sense.
350 if ( !wxPendingDelete.Member(this) )
351 wxPendingDelete.Append(this);
352
353 return true;
354}
355
356void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
357{
358 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
359}
360
361void wxMDIChildFrame::DoSetClientSize(int width, int height)
362{
363 wxWindow::DoSetClientSize( width, height );
364}
365
366void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
367{
368 wxWindow::DoGetClientSize( width, height );
369}
370
371void wxMDIChildFrame::AddChild( wxWindowBase *child )
372{
373 wxWindow::AddChild(child);
374}
375
376void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
377{
378 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
379
380 m_menuBar = menu_bar;
381
382 if (m_menuBar)
383 {
384 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
385
386 m_menuBar->SetParent( mdi_frame );
387
388 /* insert the invisible menu bar into the _parent_ mdi frame */
389 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
390 m_menuBar->m_widget,
391 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
392 }
393}
394
395wxMenuBar *wxMDIChildFrame::GetMenuBar() const
396{
397 return m_menuBar;
398}
399
400void wxMDIChildFrame::Activate()
401{
402 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
403 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
404 gint pageno = gtk_notebook_page_num( notebook, m_widget );
405 gtk_notebook_set_current_page( notebook, pageno );
406}
407
408void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
409{
410}
411
412void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
413{
414#if wxUSE_STATUSBAR
415 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
416 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
417 {
418 // we don't have any help text for this item, but may be the MDI frame
419 // does?
420 mdi_frame->OnMenuHighlight(event);
421 }
422#endif // wxUSE_STATUSBAR
423}
424
425void wxMDIChildFrame::SetTitle( const wxString &title )
426{
427 if ( title == m_title )
428 return;
429
430 m_title = title;
431
432 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
433 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
434 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
435}
436
437//-----------------------------------------------------------------------------
438// "size_allocate"
439//-----------------------------------------------------------------------------
440
441extern "C" {
442static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
443{
444 if (g_isIdle) wxapp_install_idle_handler();
445
446 if ((win->m_x == alloc->x) &&
447 (win->m_y == alloc->y) &&
448 (win->m_width == alloc->width) &&
449 (win->m_height == alloc->height) &&
450 (win->m_sizeSet))
451 {
452 return;
453 }
454
455 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
456}
457}
458
459//-----------------------------------------------------------------------------
460// InsertChild callback for wxMDIClientWindow
461//-----------------------------------------------------------------------------
462
463static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
464{
465 wxString s = child->GetTitle();
466 if (s.IsNull()) s = _("MDI child");
467
468 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
469 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
470
471 g_signal_connect (child->m_widget, "size_allocate",
472 G_CALLBACK (gtk_page_size_callback), child);
473
474 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
475
476 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
477
478 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
479
480 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
481 parent_frame->m_justInserted = true;
482}
483
484//-----------------------------------------------------------------------------
485// wxMDIClientWindow
486//-----------------------------------------------------------------------------
487
488IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
489
490wxMDIClientWindow::wxMDIClientWindow()
491{
492}
493
494wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
495{
496 CreateClient( parent, style );
497}
498
499wxMDIClientWindow::~wxMDIClientWindow()
500{
501
502}
503
504bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
505{
506 m_needParent = true;
507
508 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
509
510 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
511 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
512 {
513 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
514 return false;
515 }
516
517 m_widget = gtk_notebook_new();
518
519 g_signal_connect (m_widget, "switch_page",
520 G_CALLBACK (gtk_mdi_page_change_callback), parent);
521
522 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
523
524 m_parent->DoAddChild( this );
525
526 PostCreation();
527
528 Show( true );
529
530 return true;
531}
532
533#endif