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 void wxapp_install_idle_handler();
41 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
45 extern wxList wxPendingDelete
;
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
53 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
54 GtkNotebookPage
*page
,
55 gint
WXUNUSED(page_num
),
56 wxMDIParentFrame
*parent
)
59 wxapp_install_idle_handler();
61 // send deactivate event to old child
63 wxMDIChildFrame
*child
= parent
->GetActiveChild();
66 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
67 event1
.SetEventObject( child
);
68 child
->GetEventHandler()->ProcessEvent( event1
);
71 // send activate event to new child
73 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
77 child
= (wxMDIChildFrame
*) NULL
;
79 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
82 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
83 // CE: we come here in the destructor with a null child_frame - I think because
84 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
85 // isn't deleted early enough
89 if (child_frame
->m_page
== page
)
94 node
= node
->GetNext();
100 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
101 event2
.SetEventObject( child
);
102 child
->GetEventHandler()->ProcessEvent( event2
);
106 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
110 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
112 void wxMDIParentFrame::Init()
114 m_justInserted
= false;
115 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
118 wxMDIParentFrame::~wxMDIParentFrame()
122 bool wxMDIParentFrame::Create(wxWindow
*parent
,
124 const wxString
& title
,
128 const wxString
& name
)
130 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
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
->SetInvokingWindow(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
);
212 menu_bar
->SetInvokingWindow( child_frame
);
214 visible_child_menu
= true;
218 if (menu_bar
->Show(false))
220 menu_bar
->UnsetInvokingWindow( child_frame
);
226 node
= node
->GetNext();
229 /* show/hide parent menu bar as required */
230 if ((m_frameMenuBar
) &&
231 (m_frameMenuBar
->IsShown() == visible_child_menu
))
233 if (visible_child_menu
)
235 m_frameMenuBar
->Show( false );
236 m_frameMenuBar
->UnsetInvokingWindow( this );
240 m_frameMenuBar
->Show( true );
241 m_frameMenuBar
->SetInvokingWindow( this );
243 m_frameMenuBar
->m_width
= m_width
;
244 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
245 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
246 m_frameMenuBar
->m_widget
,
247 0, 0, m_width
, wxMENU_HEIGHT
);
252 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
254 wxFrame::DoGetClientSize( width
, height
);
257 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
259 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
261 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
262 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
264 gint i
= gtk_notebook_get_current_page( notebook
);
265 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
267 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
268 if (!page
) return (wxMDIChildFrame
*) NULL
;
270 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
273 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
275 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
277 if (child_frame
->m_page
== page
)
279 node
= node
->GetNext();
282 return (wxMDIChildFrame
*) NULL
;
285 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
287 return m_clientWindow
;
290 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
292 m_clientWindow
= new wxMDIClientWindow( this );
293 return m_clientWindow
;
296 void wxMDIParentFrame::ActivateNext()
299 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
302 void wxMDIParentFrame::ActivatePrevious()
305 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
308 //-----------------------------------------------------------------------------
310 //-----------------------------------------------------------------------------
312 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
314 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
315 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
316 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
319 wxMDIChildFrame::wxMDIChildFrame()
321 m_menuBar
= (wxMenuBar
*) NULL
;
322 m_page
= (GtkNotebookPage
*) NULL
;
325 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
326 wxWindowID id
, const wxString
& title
,
327 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
328 long style
, const wxString
& name
)
330 m_menuBar
= (wxMenuBar
*) NULL
;
331 m_page
= (GtkNotebookPage
*) NULL
;
332 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
335 wxMDIChildFrame::~wxMDIChildFrame()
341 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
342 wxWindowID id
, const wxString
& title
,
343 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
344 long style
, const wxString
& name
)
348 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
351 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
353 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
356 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
358 wxWindow::DoSetClientSize( width
, height
);
361 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
363 wxWindow::DoGetClientSize( width
, height
);
366 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
368 wxWindow::AddChild(child
);
371 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
373 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
375 m_menuBar
= menu_bar
;
379 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
381 m_menuBar
->SetParent( mdi_frame
);
383 /* insert the invisible menu bar into the _parent_ mdi frame */
384 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
386 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
390 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
395 void wxMDIChildFrame::Activate()
397 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
398 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
399 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
400 gtk_notebook_set_page( notebook
, pageno
);
403 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
407 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
410 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
411 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
413 // we don't have any help text for this item, but may be the MDI frame
415 mdi_frame
->OnMenuHighlight(event
);
417 #endif // wxUSE_STATUSBAR
420 void wxMDIChildFrame::SetTitle( const wxString
&title
)
422 if ( title
== m_title
)
427 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
428 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
429 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
432 //-----------------------------------------------------------------------------
434 //-----------------------------------------------------------------------------
437 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
439 if (g_isIdle
) wxapp_install_idle_handler();
441 if ((win
->m_x
== alloc
->x
) &&
442 (win
->m_y
== alloc
->y
) &&
443 (win
->m_width
== alloc
->width
) &&
444 (win
->m_height
== alloc
->height
) &&
450 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
454 //-----------------------------------------------------------------------------
455 // InsertChild callback for wxMDIClientWindow
456 //-----------------------------------------------------------------------------
458 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
460 wxString s
= child
->GetTitle();
461 if (s
.IsNull()) s
= _("MDI child");
463 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
464 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
466 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
467 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
469 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
471 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
473 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
475 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
476 parent_frame
->m_justInserted
= true;
479 //-----------------------------------------------------------------------------
481 //-----------------------------------------------------------------------------
483 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
485 wxMDIClientWindow::wxMDIClientWindow()
489 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
491 CreateClient( parent
, style
);
494 wxMDIClientWindow::~wxMDIClientWindow()
499 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
503 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
505 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
506 !CreateBase( parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
508 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
512 m_widget
= gtk_notebook_new();
514 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
515 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
517 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
519 m_parent
->DoAddChild( this );