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"
14 #include "wx/notebook.h"
18 #include "wx/dialog.h"
21 #include "wx/gtk/private.h"
26 #include "wx/gtk/win_gtk.h"
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 const int wxMENU_HEIGHT
= 27;
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
38 extern wxList wxPendingDelete
;
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
46 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
47 GtkNotebookPage
*page
,
48 gint
WXUNUSED(page_num
),
49 wxMDIParentFrame
*parent
)
52 wxapp_install_idle_handler();
54 // send deactivate event to old child
56 wxMDIChildFrame
*child
= parent
->GetActiveChild();
59 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
60 event1
.SetEventObject( child
);
61 child
->GetEventHandler()->ProcessEvent( event1
);
64 // send activate event to new child
66 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
70 child
= (wxMDIChildFrame
*) NULL
;
72 wxWindowList
::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
75 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
77 // child_frame can be NULL when this is called from dtor, probably
78 // because g_signal_connect (m_widget, "switch_page", (see below)
79 // isn't deleted early enough
80 if ( child_frame
&& child_frame
->m_page
== page
)
85 node
= node
->GetNext();
91 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
92 event2
.SetEventObject( child
);
93 child
->GetEventHandler()->ProcessEvent( event2
);
97 //-----------------------------------------------------------------------------
99 //-----------------------------------------------------------------------------
101 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
103 void wxMDIParentFrame
::Init()
105 m_justInserted
= false;
106 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
109 wxMDIParentFrame
::~wxMDIParentFrame()
113 bool wxMDIParentFrame
::Create(wxWindow
*parent
,
115 const wxString
& title
,
119 const wxString
& name
)
121 wxFrame
::Create( parent
, id
, title
, pos
, size
, style
, name
);
128 void wxMDIParentFrame
::GtkOnSize( int x
, int y
, int width
, int height
)
130 wxFrame
::GtkOnSize( x
, y
, width
, height
);
132 wxMDIChildFrame
*child_frame
= GetActiveChild();
133 if (!child_frame
) return;
135 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
136 if (!menu_bar
) return;
137 if (!menu_bar
->m_widget
) return;
141 menu_bar
->m_width
= m_width
;
142 menu_bar
->m_height
= wxMENU_HEIGHT
;
143 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
145 0, 0, m_width
, wxMENU_HEIGHT
);
148 void wxMDIParentFrame
::OnInternalIdle()
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 */
157 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
158 gtk_notebook_set_current_page( notebook
, g_list_length( notebook
->children
) - 1 );
160 /* need to set the menubar of the child */
161 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
162 if (active_child_frame
!= NULL
)
164 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
167 menu_bar
->m_width
= m_width
;
168 menu_bar
->m_height
= wxMENU_HEIGHT
;
169 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
171 0, 0, m_width
, wxMENU_HEIGHT
);
172 menu_bar
->SetInvokingWindow(active_child_frame
);
175 m_justInserted
= false;
179 wxFrame
::OnInternalIdle();
181 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
182 bool visible_child_menu
= false;
184 wxWindowList
::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
187 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
191 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
194 if (child_frame
== active_child_frame
)
196 if (menu_bar
->Show(true))
198 menu_bar
->m_width
= m_width
;
199 menu_bar
->m_height
= wxMENU_HEIGHT
;
200 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
202 0, 0, m_width
, wxMENU_HEIGHT
);
203 menu_bar
->SetInvokingWindow( child_frame
);
205 visible_child_menu
= true;
209 if (menu_bar
->Show(false))
211 menu_bar
->UnsetInvokingWindow( child_frame
);
217 node
= node
->GetNext();
220 /* show/hide parent menu bar as required */
221 if ((m_frameMenuBar
) &&
222 (m_frameMenuBar
->IsShown() == visible_child_menu
))
224 if (visible_child_menu
)
226 m_frameMenuBar
->Show( false );
227 m_frameMenuBar
->UnsetInvokingWindow( this );
231 m_frameMenuBar
->Show( true );
232 m_frameMenuBar
->SetInvokingWindow( this );
234 m_frameMenuBar
->m_width
= m_width
;
235 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
236 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
237 m_frameMenuBar
->m_widget
,
238 0, 0, m_width
, wxMENU_HEIGHT
);
243 void wxMDIParentFrame
::DoGetClientSize(int *width
, int *height
) const
245 wxFrame
::DoGetClientSize( width
, height
);
248 wxMDIChildFrame
*wxMDIParentFrame
::GetActiveChild() const
250 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
252 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
253 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
255 gint i
= gtk_notebook_get_current_page( notebook
);
256 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
258 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
259 if (!page
) return (wxMDIChildFrame
*) NULL
;
261 wxWindowList
::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
264 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
266 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
268 if (child_frame
->m_page
== page
)
270 node
= node
->GetNext();
273 return (wxMDIChildFrame
*) NULL
;
276 wxMDIClientWindow
*wxMDIParentFrame
::GetClientWindow() const
278 return m_clientWindow
;
281 wxMDIClientWindow
*wxMDIParentFrame
::OnCreateClient()
283 m_clientWindow
= new wxMDIClientWindow( this );
284 return m_clientWindow
;
287 void wxMDIParentFrame
::ActivateNext()
290 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
293 void wxMDIParentFrame
::ActivatePrevious()
296 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
299 //-----------------------------------------------------------------------------
301 //-----------------------------------------------------------------------------
303 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
305 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
306 EVT_ACTIVATE(wxMDIChildFrame
::OnActivate
)
307 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame
::OnMenuHighlight
)
310 wxMDIChildFrame
::wxMDIChildFrame()
312 m_menuBar
= (wxMenuBar
*) NULL
;
313 m_page
= (GtkNotebookPage
*) NULL
;
316 wxMDIChildFrame
::wxMDIChildFrame( wxMDIParentFrame
*parent
,
317 wxWindowID id
, const wxString
& title
,
318 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
319 long style
, const wxString
& name
)
321 m_menuBar
= (wxMenuBar
*) NULL
;
322 m_page
= (GtkNotebookPage
*) NULL
;
323 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
326 wxMDIChildFrame
::~wxMDIChildFrame()
332 bool wxMDIChildFrame
::Create( wxMDIParentFrame
*parent
,
333 wxWindowID id
, const wxString
& title
,
334 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
335 long style
, const wxString
& name
)
339 return wxWindow
::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
342 void wxMDIChildFrame
::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
344 wxWindow
::DoSetSize( x
, y
, width
, height
, sizeFlags
);
347 void wxMDIChildFrame
::DoSetClientSize(int width
, int height
)
349 wxWindow
::DoSetClientSize( width
, height
);
352 void wxMDIChildFrame
::DoGetClientSize( int *width
, int *height
) const
354 wxWindow
::DoGetClientSize( width
, height
);
357 void wxMDIChildFrame
::AddChild( wxWindowBase
*child
)
359 wxWindow
::AddChild(child
);
362 void wxMDIChildFrame
::SetMenuBar( wxMenuBar
*menu_bar
)
364 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
366 m_menuBar
= menu_bar
;
370 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
372 m_menuBar
->SetParent( mdi_frame
);
374 /* insert the invisible menu bar into the _parent_ mdi frame */
375 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
377 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
381 wxMenuBar
*wxMDIChildFrame
::GetMenuBar() const
386 void wxMDIChildFrame
::Activate()
388 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
389 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
390 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
391 gtk_notebook_set_current_page( notebook
, pageno
);
394 void wxMDIChildFrame
::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
398 void wxMDIChildFrame
::OnMenuHighlight( wxMenuEvent
& event
)
401 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
402 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
404 // we don't have any help text for this item, but may be the MDI frame
406 mdi_frame
->OnMenuHighlight(event
);
408 #endif // wxUSE_STATUSBAR
411 void wxMDIChildFrame
::SetTitle( const wxString
&title
)
413 if ( title
== m_title
)
418 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
419 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
420 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
423 //-----------------------------------------------------------------------------
425 //-----------------------------------------------------------------------------
428 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
430 if (g_isIdle
) wxapp_install_idle_handler();
432 if ((win
->m_x
== alloc
->x
) &&
433 (win
->m_y
== alloc
->y
) &&
434 (win
->m_width
== alloc
->width
) &&
435 (win
->m_height
== alloc
->height
) &&
441 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
445 //-----------------------------------------------------------------------------
446 // InsertChild callback for wxMDIClientWindow
447 //-----------------------------------------------------------------------------
449 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
451 wxString s
= child
->GetTitle();
452 if (s
.IsNull()) s
= _("MDI child");
454 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
455 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
457 g_signal_connect (child
->m_widget
, "size_allocate",
458 G_CALLBACK (gtk_page_size_callback
), child
);
460 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
462 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
464 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
466 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
467 parent_frame
->m_justInserted
= true;
470 //-----------------------------------------------------------------------------
472 //-----------------------------------------------------------------------------
474 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
476 wxMDIClientWindow
::wxMDIClientWindow()
480 wxMDIClientWindow
::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
482 CreateClient( parent
, style
);
485 wxMDIClientWindow
::~wxMDIClientWindow()
490 bool wxMDIClientWindow
::CreateClient( wxMDIParentFrame
*parent
, long style
)
494 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
496 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
497 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
499 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
503 m_widget
= gtk_notebook_new();
505 g_signal_connect (m_widget
, "switch_page",
506 G_CALLBACK (gtk_mdi_page_change_callback
), parent
);
508 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
510 m_parent
->DoAddChild( this );