1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/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/gtk1/private.h"
29 #include "wx/gtk1/win_gtk.h"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
35 const int wxMENU_HEIGHT
= 27;
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 extern void wxapp_install_idle_handler();
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------
54 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
55 GtkNotebookPage
*page
,
56 gint
WXUNUSED(page_num
),
57 wxMDIParentFrame
*parent
)
60 wxapp_install_idle_handler();
62 // send deactivate event to old child
64 wxMDIChildFrame
*child
= parent
->GetActiveChild();
67 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
68 event1
.SetEventObject( child
);
69 child
->HandleWindowEvent( event1
);
72 // send activate event to new child
74 wxMDIClientWindowBase
* const client_window
= parent
->GetClientWindow();
80 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
83 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
84 // CE: we come here in the destructor with a null child_frame - I think because
85 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
86 // isn't deleted early enough
90 if (child_frame
->m_page
== page
)
95 node
= node
->GetNext();
101 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
102 event2
.SetEventObject( child
);
103 child
->HandleWindowEvent( event2
);
107 //-----------------------------------------------------------------------------
109 //-----------------------------------------------------------------------------
111 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
113 void wxMDIParentFrame::Init()
115 m_justInserted
= false;
116 m_clientWindow
= NULL
;
119 bool wxMDIParentFrame::Create(wxWindow
*parent
,
121 const wxString
& title
,
125 const wxString
& name
)
127 if ( !wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) )
130 m_clientWindow
= OnCreateClient();
131 if ( !m_clientWindow
->CreateClient(this, GetWindowStyleFlag()) )
137 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
139 wxFrame::GtkOnSize( x
, y
, width
, height
);
141 wxMDIChildFrame
*child_frame
= GetActiveChild();
142 if (!child_frame
) return;
144 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
145 if (!menu_bar
) return;
146 if (!menu_bar
->m_widget
) return;
150 menu_bar
->m_width
= m_width
;
151 menu_bar
->m_height
= wxMENU_HEIGHT
;
152 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
154 0, 0, m_width
, wxMENU_HEIGHT
);
157 void wxMDIParentFrame::OnInternalIdle()
159 /* if a an MDI child window has just been inserted
160 it has to be brought to the top in idle time. we
161 simply set the last notebook page active as new
162 pages can only be appended at the end */
166 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
167 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
169 /* need to set the menubar of the child */
170 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
171 if (active_child_frame
!= NULL
)
173 wxMenuBar
*menu_bar
= active_child_frame
->m_menuBar
;
176 menu_bar
->m_width
= m_width
;
177 menu_bar
->m_height
= wxMENU_HEIGHT
;
178 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
180 0, 0, m_width
, wxMENU_HEIGHT
);
181 menu_bar
->Attach(active_child_frame
);
184 m_justInserted
= false;
188 wxFrame::OnInternalIdle();
190 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
191 bool visible_child_menu
= false;
193 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
196 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
200 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
203 if (child_frame
== active_child_frame
)
205 if (menu_bar
->Show(true))
207 menu_bar
->m_width
= m_width
;
208 menu_bar
->m_height
= wxMENU_HEIGHT
;
209 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
211 0, 0, m_width
, wxMENU_HEIGHT
);
213 // Attach() asserts if we call it for an already
214 // attached menu bar so don't do it if we're already
215 // associated with this frame (it would be nice to get
216 // rid of this check and ensure that this doesn't
218 if ( menu_bar
->GetFrame() != child_frame
)
219 menu_bar
->Attach( child_frame
);
221 visible_child_menu
= true;
225 if (menu_bar
->Show(false))
233 node
= node
->GetNext();
236 /* show/hide parent menu bar as required */
237 if ((m_frameMenuBar
) &&
238 (m_frameMenuBar
->IsShown() == visible_child_menu
))
240 if (visible_child_menu
)
242 m_frameMenuBar
->Show( false );
243 m_frameMenuBar
->Detach();
247 m_frameMenuBar
->Show( true );
248 m_frameMenuBar
->Attach( this );
250 m_frameMenuBar
->m_width
= m_width
;
251 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
252 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
253 m_frameMenuBar
->m_widget
,
254 0, 0, m_width
, wxMENU_HEIGHT
);
259 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
261 if (!m_clientWindow
) return NULL
;
263 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
264 if (!notebook
) return NULL
;
266 gint i
= gtk_notebook_get_current_page( notebook
);
267 if (i
< 0) return NULL
;
269 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
270 if (!page
) return NULL
;
272 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
275 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
277 wxASSERT_MSG( child_frame
, wxT("child is not a wxMDIChildFrame") );
279 if (child_frame
->m_page
== page
)
281 node
= node
->GetNext();
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 void wxMDIChildFrame::Init()
316 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
317 wxWindowID id
, const wxString
& title
,
318 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
319 long style
, const wxString
& name
)
323 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
326 wxMDIChildFrame::~wxMDIChildFrame()
331 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
333 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
335 m_menuBar
= menu_bar
;
339 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
341 m_menuBar
->SetParent( mdi_frame
);
343 /* insert the invisible menu bar into the _parent_ mdi frame */
344 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
346 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
350 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
355 GtkNotebook
*wxMDIChildFrame::GTKGetNotebook() const
357 wxMDIClientWindow
* const
358 client
= wxStaticCast(GetParent(), wxMDIClientWindow
);
359 wxCHECK( client
, NULL
);
361 return GTK_NOTEBOOK(client
->m_widget
);
364 void wxMDIChildFrame::Activate()
366 GtkNotebook
* const notebook
= GTKGetNotebook();
367 wxCHECK_RET( notebook
, "no parent notebook?" );
369 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
370 gtk_notebook_set_page( notebook
, pageno
);
373 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
377 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
380 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
381 if ( !ShowMenuHelp(event
.GetMenuId()) )
383 // we don't have any help text for this item, but may be the MDI frame
385 mdi_frame
->OnMenuHighlight(event
);
387 #endif // wxUSE_STATUSBAR
390 void wxMDIChildFrame::SetTitle( const wxString
&title
)
392 if ( title
== m_title
)
397 GtkNotebook
* const notebook
= GTKGetNotebook();
398 wxCHECK_RET( notebook
, "no parent notebook?" );
400 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
403 //-----------------------------------------------------------------------------
405 //-----------------------------------------------------------------------------
408 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
410 if (g_isIdle
) wxapp_install_idle_handler();
412 if ((win
->m_x
== alloc
->x
) &&
413 (win
->m_y
== alloc
->y
) &&
414 (win
->m_width
== alloc
->width
) &&
415 (win
->m_height
== alloc
->height
) &&
421 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
425 //-----------------------------------------------------------------------------
426 // InsertChild callback for wxMDIClientWindow
427 //-----------------------------------------------------------------------------
429 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
431 wxString s
= child
->GetTitle();
432 if (s
.IsNull()) s
= _("MDI child");
434 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
435 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
437 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
438 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
440 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
442 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
444 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
446 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
447 parent_frame
->m_justInserted
= true;
450 //-----------------------------------------------------------------------------
452 //-----------------------------------------------------------------------------
454 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
456 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
460 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
462 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
463 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
465 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
469 m_widget
= gtk_notebook_new();
471 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
472 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
474 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
476 m_parent
->DoAddChild( this );