1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/mdi.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
20 #include "wx/dialog.h"
23 #include "wx/notebook.h"
24 #include "wx/gtk/private.h"
29 #include "wx/gtk/win_gtk.h"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
35 const int wxMENU_HEIGHT
= 27;
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
47 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
48 GtkNotebookPage
*page
,
49 gint
WXUNUSED(page_num
),
50 wxMDIParentFrame
*parent
)
53 wxapp_install_idle_handler();
55 // send deactivate event to old child
57 wxMDIChildFrame
*child
= parent
->GetActiveChild();
60 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
61 event1
.SetEventObject( child
);
62 child
->GetEventHandler()->ProcessEvent( event1
);
65 // send activate event to new child
67 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
71 child
= (wxMDIChildFrame
*) NULL
;
73 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
76 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
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
)
86 node
= node
->GetNext();
92 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
93 event2
.SetEventObject( child
);
94 child
->GetEventHandler()->ProcessEvent( event2
);
98 //-----------------------------------------------------------------------------
100 //-----------------------------------------------------------------------------
102 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
104 void wxMDIParentFrame::Init()
106 m_justInserted
= false;
107 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
110 wxMDIParentFrame::~wxMDIParentFrame()
114 bool wxMDIParentFrame::Create(wxWindow
*parent
,
116 const wxString
& title
,
120 const wxString
& name
)
122 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
129 void wxMDIParentFrame::GtkOnSize()
131 wxFrame::GtkOnSize();
133 wxMDIChildFrame
*child_frame
= GetActiveChild();
134 if (!child_frame
) return;
136 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
137 if (!menu_bar
) return;
138 if (!menu_bar
->m_widget
) return;
142 menu_bar
->m_width
= m_width
;
143 menu_bar
->m_height
= wxMENU_HEIGHT
;
144 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
146 0, 0, m_width
, wxMENU_HEIGHT
);
149 void wxMDIParentFrame::OnInternalIdle()
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 */
158 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
159 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
161 /* need to set the menubar of the child */
162 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
163 if (active_child_frame
!= NULL
)
165 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
168 menu_bar
->m_width
= m_width
;
169 menu_bar
->m_height
= wxMENU_HEIGHT
;
170 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
172 0, 0, m_width
, wxMENU_HEIGHT
);
173 menu_bar
->SetInvokingWindow(active_child_frame
);
176 m_justInserted
= false;
180 wxFrame::OnInternalIdle();
182 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
183 bool visible_child_menu
= false;
185 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
188 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
192 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
195 if (child_frame
== active_child_frame
)
197 if (menu_bar
->Show(true))
199 menu_bar
->m_width
= m_width
;
200 menu_bar
->m_height
= wxMENU_HEIGHT
;
201 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
203 0, 0, m_width
, wxMENU_HEIGHT
);
204 menu_bar
->SetInvokingWindow( child_frame
);
206 visible_child_menu
= true;
210 if (menu_bar
->Show(false))
212 menu_bar
->UnsetInvokingWindow( child_frame
);
218 node
= node
->GetNext();
221 /* show/hide parent menu bar as required */
222 if ((m_frameMenuBar
) &&
223 (m_frameMenuBar
->IsShown() == visible_child_menu
))
225 if (visible_child_menu
)
227 m_frameMenuBar
->Show( false );
228 m_frameMenuBar
->UnsetInvokingWindow( this );
232 m_frameMenuBar
->Show( true );
233 m_frameMenuBar
->SetInvokingWindow( this );
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
);
244 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
246 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
248 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
249 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
251 gint i
= gtk_notebook_get_current_page( notebook
);
252 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
254 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
255 if (!page
) return (wxMDIChildFrame
*) NULL
;
257 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
260 if ( wxPendingDelete
.Member(node
->GetData()) )
261 return (wxMDIChildFrame
*) NULL
;
263 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
266 return (wxMDIChildFrame
*) NULL
;
268 if (child_frame
->m_page
== page
)
271 node
= node
->GetNext();
274 return (wxMDIChildFrame
*) NULL
;
277 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
279 return m_clientWindow
;
282 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
284 m_clientWindow
= new wxMDIClientWindow( this );
285 return m_clientWindow
;
288 void wxMDIParentFrame::ActivateNext()
291 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
294 void wxMDIParentFrame::ActivatePrevious()
297 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
300 //-----------------------------------------------------------------------------
302 //-----------------------------------------------------------------------------
304 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
306 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
307 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
308 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
311 wxMDIChildFrame::wxMDIChildFrame()
313 m_menuBar
= (wxMenuBar
*) NULL
;
314 m_page
= (GtkNotebookPage
*) NULL
;
317 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
318 wxWindowID id
, const wxString
& title
,
319 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
320 long style
, const wxString
& name
)
322 m_menuBar
= (wxMenuBar
*) NULL
;
323 m_page
= (GtkNotebookPage
*) NULL
;
324 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
327 wxMDIChildFrame::~wxMDIChildFrame()
333 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
334 wxWindowID id
, const wxString
& title
,
335 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
336 long style
, const wxString
& name
)
340 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
343 bool wxMDIChildFrame::Destroy()
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);
356 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
358 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
361 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
363 wxWindow::DoSetClientSize( width
, height
);
366 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
368 wxWindow::DoGetClientSize( width
, height
);
371 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
373 wxWindow::AddChild(child
);
376 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
378 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
380 m_menuBar
= menu_bar
;
384 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
386 m_menuBar
->SetParent( mdi_frame
);
388 /* insert the invisible menu bar into the _parent_ mdi frame */
389 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
391 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
395 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
400 void wxMDIChildFrame::Activate()
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
);
408 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
412 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
415 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
416 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
418 // we don't have any help text for this item, but may be the MDI frame
420 mdi_frame
->OnMenuHighlight(event
);
422 #endif // wxUSE_STATUSBAR
425 void wxMDIChildFrame::SetTitle( const wxString
&title
)
427 if ( title
== m_title
)
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
) );
437 //-----------------------------------------------------------------------------
439 //-----------------------------------------------------------------------------
442 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
444 if (g_isIdle
) wxapp_install_idle_handler();
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
) &&
455 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
459 //-----------------------------------------------------------------------------
460 // InsertChild callback for wxMDIClientWindow
461 //-----------------------------------------------------------------------------
463 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
465 wxString s
= child
->GetTitle();
466 if (s
.IsNull()) s
= _("MDI child");
468 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
469 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
471 g_signal_connect (child
->m_widget
, "size_allocate",
472 G_CALLBACK (gtk_page_size_callback
), child
);
474 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
476 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
478 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
480 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
481 parent_frame
->m_justInserted
= true;
484 //-----------------------------------------------------------------------------
486 //-----------------------------------------------------------------------------
488 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
490 wxMDIClientWindow::wxMDIClientWindow()
494 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
496 CreateClient( parent
, style
);
499 wxMDIClientWindow::~wxMDIClientWindow()
504 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
508 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
510 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
511 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
513 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
517 m_widget
= gtk_notebook_new();
519 g_signal_connect (m_widget
, "switch_page",
520 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
522 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
524 m_parent
->DoAddChild( this );