]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
reverted Chris' MSW additions patch (we should use IPC, not Windows-only functions...
[wxWidgets.git] / src / gtk / mdi.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: mdi.cpp
3// Purpose:
4// Author: Robert Roebling
a81258be
RR
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
a3622daa 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
11#pragma implementation "mdi.h"
12#endif
13
14#include "wx/mdi.h"
dcf924a3
RR
15
16#if wxUSE_MDI_ARCHITECTURE
17
e3e65dac 18#include "wx/dialog.h"
cf4219e7 19#include "wx/menu.h"
3096bd2f 20#include "wx/intl.h"
716b7364 21
16c1f79c
RR
22#include <glib.h>
23#include <gdk/gdk.h>
24#include <gtk/gtk.h>
83624f79
RR
25#include "wx/gtk/win_gtk.h"
26
6ca41e57
RR
27//-----------------------------------------------------------------------------
28// constants
29//-----------------------------------------------------------------------------
30
a0fdacee 31const int wxMENU_HEIGHT = 27;
6ca41e57 32
acfd422a
RR
33//-----------------------------------------------------------------------------
34// idle system
35//-----------------------------------------------------------------------------
36
37extern void wxapp_install_idle_handler();
38extern bool g_isIdle;
39
6ca41e57
RR
40//-----------------------------------------------------------------------------
41// globals
716b7364
RR
42//-----------------------------------------------------------------------------
43
44extern wxList wxPendingDelete;
c801d85f 45
5e014a0c
RR
46//-----------------------------------------------------------------------------
47// "switch_page"
48//-----------------------------------------------------------------------------
49
f6bcfd97 50static void
7941ba11 51gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5 52 GtkNotebookPage *page,
f6bcfd97
BP
53 gint WXUNUSED(page_num),
54 wxMDIParentFrame *parent )
5e014a0c 55{
f6bcfd97 56 if (g_isIdle)
5e014a0c
RR
57 wxapp_install_idle_handler();
58
e90196a5
RR
59 // send deactivate event to old child
60
5e014a0c 61 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
62 if (child)
63 {
64 wxActivateEvent event1( wxEVT_ACTIVATE, FALSE, child->GetId() );
65 event1.SetEventObject( child);
66 child->GetEventHandler()->ProcessEvent( event1 );
67 }
f6bcfd97 68
e90196a5 69 // send activate event to new child
f6bcfd97 70
e90196a5
RR
71 wxMDIClientWindow *client_window = parent->GetClientWindow();
72 if (!client_window)
73 return;
74
75 child = (wxMDIChildFrame*) NULL;
76
77 wxNode *node = client_window->GetChildren().First();
78 while (node)
79 {
80 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
81 if (child_frame->m_page == page)
f6bcfd97 82 {
e90196a5 83 child = child_frame;
f6bcfd97
BP
84 break;
85 }
e90196a5
RR
86 node = node->Next();
87 }
f6bcfd97 88
e90196a5
RR
89 if (!child)
90 return;
f6bcfd97 91
e90196a5
RR
92 wxActivateEvent event2( wxEVT_ACTIVATE, TRUE, child->GetId() );
93 event2.SetEventObject( child);
94 child->GetEventHandler()->ProcessEvent( event2 );
5e014a0c
RR
95}
96
6ca41e57
RR
97//-----------------------------------------------------------------------------
98// wxMDIParentFrame
33d0b396
RR
99//-----------------------------------------------------------------------------
100
c801d85f
KB
101IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
102
f6bcfd97 103void wxMDIParentFrame::Init()
c801d85f 104{
ab2b3dd4 105 m_justInserted = FALSE;
83624f79 106 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 107}
c801d85f 108
ab2b3dd4 109wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 110{
ff7b1510 111}
c801d85f 112
f6bcfd97
BP
113bool wxMDIParentFrame::Create(wxWindow *parent,
114 wxWindowID id,
115 const wxString& title,
116 const wxPoint& pos,
117 const wxSize& size,
118 long style,
119 const wxString& name )
c801d85f 120{
83624f79 121 wxFrame::Create( parent, id, title, pos, size, style, name );
a3622daa 122
83624f79 123 OnCreateClient();
a3622daa 124
83624f79 125 return TRUE;
ff7b1510 126}
c801d85f 127
716b7364 128void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
c801d85f 129{
83624f79 130 wxFrame::GtkOnSize( x, y, width, height );
a0fdacee 131
ab2b3dd4
RR
132 wxMDIChildFrame *child_frame = GetActiveChild();
133 if (!child_frame) return;
a0fdacee 134
ab2b3dd4
RR
135 wxMenuBar *menu_bar = child_frame->m_menuBar;
136 if (!menu_bar) return;
a2053b27 137 if (!menu_bar->m_widget) return;
a0fdacee 138
121a3581
RR
139 menu_bar->m_x = 0;
140 menu_bar->m_y = 0;
141 menu_bar->m_width = m_width;
142 menu_bar->m_height = wxMENU_HEIGHT;
f6bcfd97
BP
143 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
144 menu_bar->m_widget,
f03fc89f 145 0, 0, m_width, wxMENU_HEIGHT );
ab2b3dd4
RR
146}
147
148void wxMDIParentFrame::OnInternalIdle()
149{
150 /* if a an MDI child window has just been inserted
151 it has to be brought to the top in idle time. we
152 simply set the last notebook page active as new
153 pages can only be appended at the end */
154
155 if (m_justInserted)
83624f79 156 {
a2053b27 157 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
a0fdacee
VZ
158 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
159
160 m_justInserted = FALSE;
161 return;
83624f79 162 }
a0fdacee 163
ab2b3dd4 164 wxFrame::OnInternalIdle();
c626a8b7 165
ab2b3dd4 166 wxMDIChildFrame *active_child_frame = GetActiveChild();
a260fe6a 167 bool visible_child_menu = FALSE;
a0fdacee 168
f03fc89f 169 wxNode *node = m_clientWindow->GetChildren().First();
ab2b3dd4 170 while (node)
83624f79 171 {
f6bcfd97
BP
172 wxObject *child = node->Data();
173 wxMDIChildFrame *child_frame = wxDynamicCast(child, wxMDIChildFrame);
174 if ( child_frame )
a0fdacee 175 {
f6bcfd97
BP
176 wxMenuBar *menu_bar = child_frame->m_menuBar;
177 if ( menu_bar )
f03fc89f 178 {
f6bcfd97
BP
179 if (child_frame == active_child_frame)
180 {
181 if (menu_bar->Show(TRUE))
182 {
183 menu_bar->m_width = m_width;
184 menu_bar->m_height = wxMENU_HEIGHT;
185 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
186 menu_bar->m_widget,
187 0, 0, m_width, wxMENU_HEIGHT );
188 menu_bar->SetInvokingWindow( child_frame );
189 }
190 visible_child_menu = TRUE;
191 }
192 else
193 {
194 if (menu_bar->Show(FALSE))
195 {
196 menu_bar->UnsetInvokingWindow( child_frame );
197 }
198 }
f03fc89f 199 }
a0fdacee 200 }
f6bcfd97 201
ab2b3dd4 202 node = node->Next();
83624f79 203 }
a0fdacee 204
e27ce4e9 205 /* show/hide parent menu bar as required */
5bd9e519
RR
206 if ((m_frameMenuBar) &&
207 (m_frameMenuBar->IsShown() == visible_child_menu))
208 {
209 if (visible_child_menu)
f6bcfd97 210 {
5bd9e519 211 m_frameMenuBar->Show( FALSE );
f6bcfd97
BP
212 m_frameMenuBar->UnsetInvokingWindow( this );
213 }
214 else
215 {
5bd9e519 216 m_frameMenuBar->Show( TRUE );
f6bcfd97
BP
217 m_frameMenuBar->SetInvokingWindow( this );
218
219 m_frameMenuBar->m_width = m_width;
220 m_frameMenuBar->m_height = wxMENU_HEIGHT;
221 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
222 m_frameMenuBar->m_widget,
223 0, 0, m_width, wxMENU_HEIGHT );
224 }
5bd9e519 225 }
ff7b1510 226}
716b7364 227
40d432c4 228void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
c801d85f 229{
40d432c4 230 wxFrame::DoGetClientSize( width, height );
ff7b1510 231}
c801d85f 232
ab2b3dd4
RR
233wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
234{
235 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 236
a2053b27 237 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 238 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee 239
ab2b3dd4
RR
240 gint i = gtk_notebook_get_current_page( notebook );
241 if (i < 0) return (wxMDIChildFrame*) NULL;
a0fdacee 242
ab2b3dd4
RR
243 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
244 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 245
f03fc89f 246 wxNode *node = m_clientWindow->GetChildren().First();
ab2b3dd4
RR
247 while (node)
248 {
249 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
250 if (child_frame->m_page == page)
251 return child_frame;
252 node = node->Next();
253 }
a0fdacee 254
ab2b3dd4 255 return (wxMDIChildFrame*) NULL;
ff7b1510 256}
c801d85f 257
ab2b3dd4 258wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 259{
83624f79 260 return m_clientWindow;
ff7b1510 261}
c801d85f 262
ab2b3dd4 263wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 264{
83624f79
RR
265 m_clientWindow = new wxMDIClientWindow( this );
266 return m_clientWindow;
ff7b1510 267}
c801d85f 268
ab2b3dd4 269void wxMDIParentFrame::ActivateNext()
c801d85f 270{
83624f79 271 if (m_clientWindow)
a2053b27 272 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 273}
c801d85f 274
ab2b3dd4 275void wxMDIParentFrame::ActivatePrevious()
716b7364 276{
83624f79 277 if (m_clientWindow)
a2053b27 278 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 279}
716b7364 280
c801d85f
KB
281//-----------------------------------------------------------------------------
282// wxMDIChildFrame
283//-----------------------------------------------------------------------------
284
cf4219e7 285IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 286
cf4219e7 287BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 288 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 289 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
290END_EVENT_TABLE()
291
ab2b3dd4 292wxMDIChildFrame::wxMDIChildFrame()
c801d85f 293{
83624f79
RR
294 m_menuBar = (wxMenuBar *) NULL;
295 m_page = (GtkNotebookPage *) NULL;
ff7b1510 296}
c801d85f
KB
297
298wxMDIChildFrame::wxMDIChildFrame( 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
RR
303 m_menuBar = (wxMenuBar *) NULL;
304 m_page = (GtkNotebookPage *) NULL;
305 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 306}
c801d85f 307
ab2b3dd4 308wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 309{
83624f79 310 if (m_menuBar)
83624f79 311 delete m_menuBar;
ff7b1510 312}
c801d85f
KB
313
314bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 315 wxWindowID id, const wxString& title,
33d0b396 316 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 317 long style, const wxString& name )
c801d85f 318{
83624f79 319 m_title = title;
c626a8b7 320
83624f79 321 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 322}
c801d85f 323
ac0c857a
RR
324void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
325{
326 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
327}
328
329void wxMDIChildFrame::DoSetClientSize(int width, int height)
330{
331 wxWindow::DoSetClientSize( width, height );
332}
333
40d432c4 334void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
c801d85f 335{
40d432c4 336 wxWindow::DoGetClientSize( width, height );
cf4219e7 337}
9746a2ba 338
7a903311 339void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 340{
7a903311 341 wxWindow::AddChild(child);
716b7364 342}
c626a8b7 343
716b7364
RR
344void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
345{
223d09f6 346 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 347
83624f79 348 m_menuBar = menu_bar;
a3622daa 349
83624f79 350 if (m_menuBar)
716b7364 351 {
f03fc89f 352 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 353
5bd9e519 354 m_menuBar->SetParent( mdi_frame );
c626a8b7 355
ab2b3dd4 356 /* insert the invisible menu bar into the _parent_ mdi frame */
f6bcfd97
BP
357 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
358 m_menuBar->m_widget,
a2053b27 359 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
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 );
adde8c98 373 gtk_notebook_set_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();
384 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
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);
9e691f46 402 gtk_notebook_set_tab_label_text(notebook, m_widget, title.mbc_str());
ff7b1510 403}
9746a2ba 404
ab2b3dd4
RR
405//-----------------------------------------------------------------------------
406// "size_allocate"
407//-----------------------------------------------------------------------------
408
409static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
410{
acfd422a
RR
411 if (g_isIdle) wxapp_install_idle_handler();
412
a2053b27
RR
413 if ((win->m_x == alloc->x) &&
414 (win->m_y == alloc->y) &&
415 (win->m_width == alloc->width) &&
416 (win->m_height == alloc->height) &&
417 (win->m_sizeSet))
ab2b3dd4
RR
418 {
419 return;
420 }
421
422 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
423}
424
6ca41e57
RR
425//-----------------------------------------------------------------------------
426// InsertChild callback for wxMDIClientWindow
427//-----------------------------------------------------------------------------
428
429static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
430{
83624f79
RR
431 wxString s = child->m_title;
432 if (s.IsNull()) s = _("MDI child");
6ca41e57 433
ed9b9841 434 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 435 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 436
a2053b27 437 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 438 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 439
a2053b27 440 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 441
a2053b27 442 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 443
83624f79 444 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 445
f03fc89f 446 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
ab2b3dd4 447 parent_frame->m_justInserted = TRUE;
6ca41e57
RR
448}
449
c801d85f
KB
450//-----------------------------------------------------------------------------
451// wxMDIClientWindow
452//-----------------------------------------------------------------------------
453
454IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
455
ab2b3dd4 456wxMDIClientWindow::wxMDIClientWindow()
c801d85f 457{
ff7b1510 458}
c801d85f 459
debe6624 460wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 461{
83624f79 462 CreateClient( parent, style );
ff7b1510 463}
c801d85f 464
ab2b3dd4 465wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 466{
ff7b1510 467}
c801d85f 468
debe6624 469bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 470{
83624f79 471 m_needParent = TRUE;
c626a8b7 472
83624f79 473 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 474
4dcaf11a 475 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
223d09f6 476 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 477 {
223d09f6 478 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
f6bcfd97 479 return FALSE;
4dcaf11a 480 }
c801d85f 481
83624f79 482 m_widget = gtk_notebook_new();
a3622daa 483
5e014a0c
RR
484 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
485 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
486
83624f79 487 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 488
f03fc89f 489 m_parent->DoAddChild( this );
c626a8b7 490
83624f79 491 PostCreation();
a3622daa 492
83624f79 493 Show( TRUE );
a3622daa 494
83624f79 495 return TRUE;
ff7b1510 496}
c801d85f 497
dcf924a3 498#endif