moved wxapp_install_idle_handler and g_isIdle from many cpp files into gtk/private...
[wxWidgets.git] / src / gtk / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/mdi.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #include "wx/mdi.h"
14 #include "wx/notebook.h"
15
16 #if wxUSE_MDI
17
18 #include "wx/dialog.h"
19 #include "wx/menu.h"
20 #include "wx/intl.h"
21 #include "wx/gtk/private.h"
22
23 #include <glib.h>
24 #include <gdk/gdk.h>
25 #include <gtk/gtk.h>
26 #include "wx/gtk/win_gtk.h"
27
28 //-----------------------------------------------------------------------------
29 // constants
30 //-----------------------------------------------------------------------------
31
32 const int wxMENU_HEIGHT = 27;
33
34 //-----------------------------------------------------------------------------
35 // globals
36 //-----------------------------------------------------------------------------
37
38 extern wxList wxPendingDelete;
39
40 //-----------------------------------------------------------------------------
41 // "switch_page"
42 //-----------------------------------------------------------------------------
43
44 extern "C" {
45 static void
46 gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
47 GtkNotebookPage *page,
48 gint WXUNUSED(page_num),
49 wxMDIParentFrame *parent )
50 {
51 if (g_isIdle)
52 wxapp_install_idle_handler();
53
54 // send deactivate event to old child
55
56 wxMDIChildFrame *child = parent->GetActiveChild();
57 if (child)
58 {
59 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
60 event1.SetEventObject( child);
61 child->GetEventHandler()->ProcessEvent( event1 );
62 }
63
64 // send activate event to new child
65
66 wxMDIClientWindow *client_window = parent->GetClientWindow();
67 if (!client_window)
68 return;
69
70 child = (wxMDIChildFrame*) NULL;
71
72 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
73 while (node)
74 {
75 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
76 // CE: we come here in the destructor with a null child_frame - I think because
77 // g_signal_connect (m_widget, "switch_page", (see below)
78 // isn't deleted early enough
79 if (!child_frame)
80 return ;
81
82 if (child_frame->m_page == page)
83 {
84 child = child_frame;
85 break;
86 }
87 node = node->GetNext();
88 }
89
90 if (!child)
91 return;
92
93 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
94 event2.SetEventObject( child);
95 child->GetEventHandler()->ProcessEvent( event2 );
96 }
97 }
98
99 //-----------------------------------------------------------------------------
100 // wxMDIParentFrame
101 //-----------------------------------------------------------------------------
102
103 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
104
105 void wxMDIParentFrame::Init()
106 {
107 m_justInserted = false;
108 m_clientWindow = (wxMDIClientWindow *) NULL;
109 }
110
111 wxMDIParentFrame::~wxMDIParentFrame()
112 {
113 }
114
115 bool wxMDIParentFrame::Create(wxWindow *parent,
116 wxWindowID id,
117 const wxString& title,
118 const wxPoint& pos,
119 const wxSize& size,
120 long style,
121 const wxString& name )
122 {
123 wxFrame::Create( parent, id, title, pos, size, style, name );
124
125 OnCreateClient();
126
127 return true;
128 }
129
130 void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
131 {
132 wxFrame::GtkOnSize( x, y, width, height );
133
134 wxMDIChildFrame *child_frame = GetActiveChild();
135 if (!child_frame) return;
136
137 wxMenuBar *menu_bar = child_frame->m_menuBar;
138 if (!menu_bar) return;
139 if (!menu_bar->m_widget) return;
140
141 menu_bar->m_x = 0;
142 menu_bar->m_y = 0;
143 menu_bar->m_width = m_width;
144 menu_bar->m_height = wxMENU_HEIGHT;
145 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
146 menu_bar->m_widget,
147 0, 0, m_width, wxMENU_HEIGHT );
148 }
149
150 void wxMDIParentFrame::OnInternalIdle()
151 {
152 /* if a an MDI child window has just been inserted
153 it has to be brought to the top in idle time. we
154 simply set the last notebook page active as new
155 pages can only be appended at the end */
156
157 if (m_justInserted)
158 {
159 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
160 gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
161
162 /* need to set the menubar of the child */
163 wxMDIChildFrame *active_child_frame = GetActiveChild();
164 if (active_child_frame != NULL)
165 {
166 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
167 if (menu_bar)
168 {
169 menu_bar->m_width = m_width;
170 menu_bar->m_height = wxMENU_HEIGHT;
171 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
172 menu_bar->m_widget,
173 0, 0, m_width, wxMENU_HEIGHT );
174 menu_bar->SetInvokingWindow(active_child_frame);
175 }
176 }
177 m_justInserted = false;
178 return;
179 }
180
181 wxFrame::OnInternalIdle();
182
183 wxMDIChildFrame *active_child_frame = GetActiveChild();
184 bool visible_child_menu = false;
185
186 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
187 while (node)
188 {
189 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
190
191 if ( child_frame )
192 {
193 wxMenuBar *menu_bar = child_frame->m_menuBar;
194 if ( menu_bar )
195 {
196 if (child_frame == active_child_frame)
197 {
198 if (menu_bar->Show(true))
199 {
200 menu_bar->m_width = m_width;
201 menu_bar->m_height = wxMENU_HEIGHT;
202 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
203 menu_bar->m_widget,
204 0, 0, m_width, wxMENU_HEIGHT );
205 menu_bar->SetInvokingWindow( child_frame );
206 }
207 visible_child_menu = true;
208 }
209 else
210 {
211 if (menu_bar->Show(false))
212 {
213 menu_bar->UnsetInvokingWindow( child_frame );
214 }
215 }
216 }
217 }
218
219 node = node->GetNext();
220 }
221
222 /* show/hide parent menu bar as required */
223 if ((m_frameMenuBar) &&
224 (m_frameMenuBar->IsShown() == visible_child_menu))
225 {
226 if (visible_child_menu)
227 {
228 m_frameMenuBar->Show( false );
229 m_frameMenuBar->UnsetInvokingWindow( this );
230 }
231 else
232 {
233 m_frameMenuBar->Show( true );
234 m_frameMenuBar->SetInvokingWindow( this );
235
236 m_frameMenuBar->m_width = m_width;
237 m_frameMenuBar->m_height = wxMENU_HEIGHT;
238 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
239 m_frameMenuBar->m_widget,
240 0, 0, m_width, wxMENU_HEIGHT );
241 }
242 }
243 }
244
245 void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
246 {
247 wxFrame::DoGetClientSize( width, height );
248 }
249
250 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
251 {
252 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
253
254 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
255 if (!notebook) return (wxMDIChildFrame*) NULL;
256
257 gint i = gtk_notebook_get_current_page( notebook );
258 if (i < 0) return (wxMDIChildFrame*) NULL;
259
260 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
261 if (!page) return (wxMDIChildFrame*) NULL;
262
263 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
264 while (node)
265 {
266 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
267
268 wxASSERT_MSG( child_frame, _T("child is not a wxMDIChildFrame") );
269
270 if (child_frame->m_page == page)
271 return child_frame;
272 node = node->GetNext();
273 }
274
275 return (wxMDIChildFrame*) NULL;
276 }
277
278 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
279 {
280 return m_clientWindow;
281 }
282
283 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
284 {
285 m_clientWindow = new wxMDIClientWindow( this );
286 return m_clientWindow;
287 }
288
289 void wxMDIParentFrame::ActivateNext()
290 {
291 if (m_clientWindow)
292 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
293 }
294
295 void wxMDIParentFrame::ActivatePrevious()
296 {
297 if (m_clientWindow)
298 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
299 }
300
301 //-----------------------------------------------------------------------------
302 // wxMDIChildFrame
303 //-----------------------------------------------------------------------------
304
305 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
306
307 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
308 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
309 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
310 END_EVENT_TABLE()
311
312 wxMDIChildFrame::wxMDIChildFrame()
313 {
314 m_menuBar = (wxMenuBar *) NULL;
315 m_page = (GtkNotebookPage *) NULL;
316 }
317
318 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
319 wxWindowID id, const wxString& title,
320 const wxPoint& WXUNUSED(pos), const wxSize& size,
321 long style, const wxString& name )
322 {
323 m_menuBar = (wxMenuBar *) NULL;
324 m_page = (GtkNotebookPage *) NULL;
325 Create( parent, id, title, wxDefaultPosition, size, style, name );
326 }
327
328 wxMDIChildFrame::~wxMDIChildFrame()
329 {
330 if (m_menuBar)
331 delete m_menuBar;
332 }
333
334 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
335 wxWindowID id, const wxString& title,
336 const wxPoint& WXUNUSED(pos), const wxSize& size,
337 long style, const wxString& name )
338 {
339 m_title = title;
340
341 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
342 }
343
344 void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
345 {
346 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
347 }
348
349 void wxMDIChildFrame::DoSetClientSize(int width, int height)
350 {
351 wxWindow::DoSetClientSize( width, height );
352 }
353
354 void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
355 {
356 wxWindow::DoGetClientSize( width, height );
357 }
358
359 void wxMDIChildFrame::AddChild( wxWindowBase *child )
360 {
361 wxWindow::AddChild(child);
362 }
363
364 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
365 {
366 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
367
368 m_menuBar = menu_bar;
369
370 if (m_menuBar)
371 {
372 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
373
374 m_menuBar->SetParent( mdi_frame );
375
376 /* insert the invisible menu bar into the _parent_ mdi frame */
377 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
378 m_menuBar->m_widget,
379 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
380 }
381 }
382
383 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
384 {
385 return m_menuBar;
386 }
387
388 void wxMDIChildFrame::Activate()
389 {
390 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
391 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
392 gint pageno = gtk_notebook_page_num( notebook, m_widget );
393 gtk_notebook_set_current_page( notebook, pageno );
394 }
395
396 void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
397 {
398 }
399
400 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
401 {
402 #if wxUSE_STATUSBAR
403 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
404 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
405 {
406 // we don't have any help text for this item, but may be the MDI frame
407 // does?
408 mdi_frame->OnMenuHighlight(event);
409 }
410 #endif // wxUSE_STATUSBAR
411 }
412
413 void wxMDIChildFrame::SetTitle( const wxString &title )
414 {
415 if ( title == m_title )
416 return;
417
418 m_title = title;
419
420 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
421 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
422 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
423 }
424
425 //-----------------------------------------------------------------------------
426 // "size_allocate"
427 //-----------------------------------------------------------------------------
428
429 extern "C" {
430 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
431 {
432 if (g_isIdle) wxapp_install_idle_handler();
433
434 if ((win->m_x == alloc->x) &&
435 (win->m_y == alloc->y) &&
436 (win->m_width == alloc->width) &&
437 (win->m_height == alloc->height) &&
438 (win->m_sizeSet))
439 {
440 return;
441 }
442
443 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
444 }
445 }
446
447 //-----------------------------------------------------------------------------
448 // InsertChild callback for wxMDIClientWindow
449 //-----------------------------------------------------------------------------
450
451 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
452 {
453 wxString s = child->GetTitle();
454 if (s.IsNull()) s = _("MDI child");
455
456 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
457 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
458
459 g_signal_connect (child->m_widget, "size_allocate",
460 G_CALLBACK (gtk_page_size_callback), child);
461
462 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
463
464 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
465
466 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
467
468 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
469 parent_frame->m_justInserted = true;
470 }
471
472 //-----------------------------------------------------------------------------
473 // wxMDIClientWindow
474 //-----------------------------------------------------------------------------
475
476 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
477
478 wxMDIClientWindow::wxMDIClientWindow()
479 {
480 }
481
482 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
483 {
484 CreateClient( parent, style );
485 }
486
487 wxMDIClientWindow::~wxMDIClientWindow()
488 {
489
490 }
491
492 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
493 {
494 m_needParent = true;
495
496 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
497
498 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
499 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
500 {
501 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
502 return false;
503 }
504
505 m_widget = gtk_notebook_new();
506
507 g_signal_connect (m_widget, "switch_page",
508 G_CALLBACK (gtk_mdi_page_change_callback), parent);
509
510 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
511
512 m_parent->DoAddChild( this );
513
514 PostCreation();
515
516 Show( true );
517
518 return true;
519 }
520
521 #endif