New idle handling. Only that.
[wxWidgets.git] / src / gtk / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mdi.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "mdi.h"
12 #endif
13
14 #include "wx/mdi.h"
15 #include "wx/dialog.h"
16 #include "wx/menu.h"
17 #include <wx/intl.h>
18
19 #include "glib.h"
20 #include "gdk/gdk.h"
21 #include "gtk/gtk.h"
22 #include "wx/gtk/win_gtk.h"
23
24 //-----------------------------------------------------------------------------
25 // constants
26 //-----------------------------------------------------------------------------
27
28 const int wxMENU_HEIGHT = 27;
29
30 //-----------------------------------------------------------------------------
31 // idle system
32 //-----------------------------------------------------------------------------
33
34 extern void wxapp_install_idle_handler();
35 extern bool g_isIdle;
36
37 //-----------------------------------------------------------------------------
38 // globals
39 //-----------------------------------------------------------------------------
40
41 extern wxList wxPendingDelete;
42
43 //-----------------------------------------------------------------------------
44 // wxMDIParentFrame
45 //-----------------------------------------------------------------------------
46
47 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
48
49 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
50 END_EVENT_TABLE()
51
52 wxMDIParentFrame::wxMDIParentFrame()
53 {
54 m_justInserted = FALSE;
55 m_clientWindow = (wxMDIClientWindow *) NULL;
56 }
57
58 wxMDIParentFrame::wxMDIParentFrame( wxWindow *parent,
59 wxWindowID id, const wxString& title,
60 const wxPoint& pos, const wxSize& size,
61 long style, const wxString& name )
62 {
63 m_justInserted = FALSE;
64 m_clientWindow = (wxMDIClientWindow *) NULL;
65 Create( parent, id, title, pos, size, style, name );
66 }
67
68 wxMDIParentFrame::~wxMDIParentFrame()
69 {
70 }
71
72 bool wxMDIParentFrame::Create( wxWindow *parent,
73 wxWindowID id, const wxString& title,
74 const wxPoint& pos, const wxSize& size,
75 long style, const wxString& name )
76 {
77 wxFrame::Create( parent, id, title, pos, size, style, name );
78
79 OnCreateClient();
80
81 return TRUE;
82 }
83
84 void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
85 {
86 wxFrame::GtkOnSize( x, y, width, height );
87
88 wxMDIChildFrame *child_frame = GetActiveChild();
89 if (!child_frame) return;
90
91 wxMenuBar *menu_bar = child_frame->m_menuBar;
92 if (!menu_bar) return;
93 if (!menu_bar->m_widget) return;
94
95 menu_bar->m_x = 0;
96 menu_bar->m_y = 0;
97 menu_bar->m_width = m_width;
98 menu_bar->m_height = wxMENU_HEIGHT;
99 gtk_myfixed_move( GTK_MYFIXED(m_mainWidget), menu_bar->m_widget, 0, 0 );
100 gtk_widget_set_usize( menu_bar->m_widget, m_width, wxMENU_HEIGHT );
101 }
102
103 void wxMDIParentFrame::OnInternalIdle()
104 {
105 /* if a an MDI child window has just been inserted
106 it has to be brought to the top in idle time. we
107 simply set the last notebook page active as new
108 pages can only be appended at the end */
109
110 if (m_justInserted)
111 {
112 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
113 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
114
115 m_justInserted = FALSE;
116 return;
117 }
118
119 wxFrame::OnInternalIdle();
120
121 wxMDIChildFrame *active_child_frame = GetActiveChild();
122 bool visible_child_menu = FALSE;
123
124 wxNode *node = m_clientWindow->m_children.First();
125 while (node)
126 {
127 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
128 if (child_frame->m_menuBar)
129 {
130 if (child_frame == active_child_frame)
131 {
132 gtk_widget_show( child_frame->m_menuBar->m_widget );
133 visible_child_menu = TRUE;
134 }
135 else
136 gtk_widget_hide( child_frame->m_menuBar->m_widget );
137 }
138 node = node->Next();
139 }
140
141 /* show/hide parent menu bar as required */
142 if (m_frameMenuBar) m_frameMenuBar->Show( !visible_child_menu );
143 }
144
145 void wxMDIParentFrame::GetClientSize(int *width, int *height ) const
146 {
147 wxFrame::GetClientSize( width, height );
148 }
149
150 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
151 {
152 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
153
154 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
155 if (!notebook) return (wxMDIChildFrame*) NULL;
156
157 #if (GTK_MINOR_VERSION > 0)
158 gint i = gtk_notebook_get_current_page( notebook );
159 #else
160 gint i = gtk_notebook_current_page( notebook );
161 #endif
162 if (i < 0) return (wxMDIChildFrame*) NULL;
163
164 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
165 if (!page) return (wxMDIChildFrame*) NULL;
166
167 wxNode *node = m_clientWindow->m_children.First();
168 while (node)
169 {
170 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
171 if (child_frame->m_page == page)
172 return child_frame;
173 node = node->Next();
174 }
175
176 return (wxMDIChildFrame*) NULL;
177 }
178
179 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
180 {
181 return m_clientWindow;
182 }
183
184 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
185 {
186 m_clientWindow = new wxMDIClientWindow( this );
187 return m_clientWindow;
188 }
189
190 void wxMDIParentFrame::ActivateNext()
191 {
192 if (m_clientWindow)
193 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
194 }
195
196 void wxMDIParentFrame::ActivatePrevious()
197 {
198 if (m_clientWindow)
199 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
200 }
201
202 void wxMDIParentFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
203 {
204 }
205
206 void wxMDIParentFrame::OnSysColourChanged( wxSysColourChangedEvent& WXUNUSED(event) )
207 {
208 }
209
210 //-----------------------------------------------------------------------------
211 // wxMDIChildFrame
212 //-----------------------------------------------------------------------------
213
214 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
215
216 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
217 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
218 END_EVENT_TABLE()
219
220 wxMDIChildFrame::wxMDIChildFrame()
221 {
222 m_menuBar = (wxMenuBar *) NULL;
223 m_page = (GtkNotebookPage *) NULL;
224 }
225
226 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
227 wxWindowID id, const wxString& title,
228 const wxPoint& WXUNUSED(pos), const wxSize& size,
229 long style, const wxString& name )
230 {
231 m_menuBar = (wxMenuBar *) NULL;
232 m_page = (GtkNotebookPage *) NULL;
233 Create( parent, id, title, wxDefaultPosition, size, style, name );
234 }
235
236 wxMDIChildFrame::~wxMDIChildFrame()
237 {
238 if (m_menuBar)
239 delete m_menuBar;
240 }
241
242 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
243 wxWindowID id, const wxString& title,
244 const wxPoint& WXUNUSED(pos), const wxSize& size,
245 long style, const wxString& name )
246 {
247 m_title = title;
248
249 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
250 }
251
252 void wxMDIChildFrame::GetClientSize( int *width, int *height ) const
253 {
254 wxWindow::GetClientSize( width, height );
255 }
256
257 void wxMDIChildFrame::AddChild( wxWindow *child )
258 {
259 wxWindow::AddChild( child );
260 }
261
262 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
263 {
264 menu->SetInvokingWindow( win );
265 wxNode *node = menu->GetItems().First();
266 while (node)
267 {
268 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
269 if (menuitem->IsSubMenu())
270 SetInvokingWindow( menuitem->GetSubMenu(), win );
271 node = node->Next();
272 }
273 }
274
275 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
276 {
277 m_menuBar = menu_bar;
278
279 if (m_menuBar)
280 {
281 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->m_parent;
282
283 if (m_menuBar->m_parent != this)
284 {
285 wxNode *node = m_menuBar->GetMenus().First();
286 while (node)
287 {
288 wxMenu *menu = (wxMenu*)node->Data();
289 SetInvokingWindow( menu, this );
290 node = node->Next();
291 }
292
293 m_menuBar->m_parent = mdi_frame;
294 }
295
296 /* the menu bar of the child window is shown in idle time as needed */
297 gtk_widget_hide( m_menuBar->m_widget );
298
299 /* insert the invisible menu bar into the _parent_ mdi frame */
300 gtk_myfixed_put( GTK_MYFIXED(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0, 0 );
301 gtk_widget_set_usize( menu_bar->m_widget, mdi_frame->m_width, wxMENU_HEIGHT );
302 }
303 }
304
305 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
306 {
307 return m_menuBar;
308 }
309
310 void wxMDIChildFrame::Activate()
311 {
312 }
313
314 void wxMDIChildFrame::OnActivate( wxActivateEvent &WXUNUSED(event) )
315 {
316 }
317
318 //-----------------------------------------------------------------------------
319 // "size_allocate"
320 //-----------------------------------------------------------------------------
321
322 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
323 {
324 if (g_isIdle) wxapp_install_idle_handler();
325
326 if ((win->m_x == alloc->x) &&
327 (win->m_y == alloc->y) &&
328 (win->m_width == alloc->width) &&
329 (win->m_height == alloc->height) &&
330 (win->m_sizeSet))
331 {
332 return;
333 }
334
335 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
336 }
337
338 //-----------------------------------------------------------------------------
339 // InsertChild callback for wxMDIClientWindow
340 //-----------------------------------------------------------------------------
341
342 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
343 {
344 wxString s = child->m_title;
345 if (s.IsNull()) s = _("MDI child");
346
347 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
348 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
349
350 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
351 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
352
353 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
354
355 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
356
357 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
358
359 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->m_parent;
360 parent_frame->m_justInserted = TRUE;
361 }
362
363 //-----------------------------------------------------------------------------
364 // wxMDIClientWindow
365 //-----------------------------------------------------------------------------
366
367 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
368
369 wxMDIClientWindow::wxMDIClientWindow()
370 {
371 }
372
373 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
374 {
375 CreateClient( parent, style );
376 }
377
378 wxMDIClientWindow::~wxMDIClientWindow()
379 {
380 }
381
382 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
383 {
384 m_needParent = TRUE;
385
386 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
387
388 PreCreation( parent, -1, wxPoint(10,10), wxSize(100,100), style, "wxMDIClientWindow" );
389
390 m_widget = gtk_notebook_new();
391
392 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
393
394 m_parent->AddChild( this );
395
396 (m_parent->m_insertCallback)( m_parent, this );
397
398 PostCreation();
399
400 Show( TRUE );
401
402 return TRUE;
403 }
404
405
406