restructure fullscreen code dealing with hiding bars
[wxWidgets.git] / src / gtk / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/frame.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/frame.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/menu.h"
17 #include "wx/toolbar.h"
18 #include "wx/statusbr.h"
19 #endif // WX_PRECOMP
20
21 #include <gtk/gtk.h>
22 #include "wx/gtk/win_gtk.h"
23
24 // ----------------------------------------------------------------------------
25 // constants
26 // ----------------------------------------------------------------------------
27
28 static const int wxSTATUS_HEIGHT = 25;
29 static const int wxPLACE_HOLDER = 0;
30
31 // ----------------------------------------------------------------------------
32 // event tables
33 // ----------------------------------------------------------------------------
34
35 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxTopLevelWindow)
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // ----------------------------------------------------------------------------
42 // GTK callbacks
43 // ----------------------------------------------------------------------------
44
45 #if wxUSE_MENUS_NATIVE
46
47 //-----------------------------------------------------------------------------
48 // "child_attached" of menu bar
49 //-----------------------------------------------------------------------------
50
51 extern "C" {
52 static void gtk_menu_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
53 {
54 if (!win->m_hasVMT) return;
55
56 win->m_menuBarDetached = false;
57 win->GtkUpdateSize();
58 }
59 }
60
61 //-----------------------------------------------------------------------------
62 // "child_detached" of menu bar
63 //-----------------------------------------------------------------------------
64
65 extern "C" {
66 static void gtk_menu_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
67 {
68 if (!win->m_hasVMT) return;
69
70 // Raise the client area area
71 gdk_window_raise( win->m_wxwindow->window );
72
73 win->m_menuBarDetached = true;
74 win->GtkUpdateSize();
75 }
76 }
77
78 #endif // wxUSE_MENUS_NATIVE
79
80 #if wxUSE_TOOLBAR
81 //-----------------------------------------------------------------------------
82 // "child_attached" of tool bar
83 //-----------------------------------------------------------------------------
84
85 extern "C" {
86 static void gtk_toolbar_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
87 {
88 if (!win->m_hasVMT) return;
89
90 win->m_toolBarDetached = false;
91 win->GtkUpdateSize();
92 }
93 }
94
95 //-----------------------------------------------------------------------------
96 // "child_detached" of tool bar
97 //-----------------------------------------------------------------------------
98
99 extern "C" {
100 static void gtk_toolbar_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
101 {
102 if (!win->m_hasVMT) return;
103
104 // Raise the client area area
105 gdk_window_raise( win->m_wxwindow->window );
106
107 win->m_toolBarDetached = true;
108 win->GtkUpdateSize();
109 }
110 }
111 #endif // wxUSE_TOOLBAR
112
113
114 // ----------------------------------------------------------------------------
115 // wxFrame itself
116 // ----------------------------------------------------------------------------
117
118 //-----------------------------------------------------------------------------
119 // InsertChild for wxFrame
120 //-----------------------------------------------------------------------------
121
122 /* Callback for wxFrame. This very strange beast has to be used because
123 * C++ has no virtual methods in a constructor. We have to emulate a
124 * virtual function here as wxWidgets requires different ways to insert
125 * a child in container classes. */
126
127 static void wxInsertChildInFrame(wxWindow* parent, wxWindow* child)
128 {
129 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
130
131 // These are outside the client area
132 wxFrame* frame = wx_static_cast(wxFrame*, parent);
133 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
134 child->m_widget,
135 child->m_x,
136 child->m_y,
137 child->m_width,
138 child->m_height );
139
140 #if wxUSE_TOOLBAR_NATIVE
141 // We connect to these events for recalculating the client area
142 // space when the toolbar is floating
143 if (wxIS_KIND_OF(child,wxToolBar))
144 {
145 if (child->HasFlag(wxTB_DOCKABLE))
146 {
147 g_signal_connect (child->m_widget, "child_attached",
148 G_CALLBACK (gtk_toolbar_attached_callback),
149 parent);
150 g_signal_connect (child->m_widget, "child_detached",
151 G_CALLBACK (gtk_toolbar_detached_callback),
152 parent);
153 }
154 }
155 #endif // wxUSE_TOOLBAR
156 }
157
158 // ----------------------------------------------------------------------------
159 // wxFrame creation
160 // ----------------------------------------------------------------------------
161
162 void wxFrame::Init()
163 {
164 m_menuBarDetached = false;
165 m_toolBarDetached = false;
166 m_menuBarHeight = 2;
167 m_fsSaveFlag = 0;
168 }
169
170 bool wxFrame::Create( wxWindow *parent,
171 wxWindowID id,
172 const wxString& title,
173 const wxPoint& pos,
174 const wxSize& sizeOrig,
175 long style,
176 const wxString &name )
177 {
178 return wxFrameBase::Create(parent, id, title, pos, sizeOrig, style, name);
179 }
180
181 wxFrame::~wxFrame()
182 {
183 m_isBeingDeleted = true;
184 DeleteAllBars();
185 }
186
187 // ----------------------------------------------------------------------------
188 // overridden wxWindow methods
189 // ----------------------------------------------------------------------------
190
191 void wxFrame::DoGetClientSize( int *width, int *height ) const
192 {
193 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
194
195 wxFrameBase::DoGetClientSize(width, height);
196
197 if (height)
198 {
199 #if wxUSE_MENUS_NATIVE
200 // menu bar
201 if (m_frameMenuBar &&
202 GTK_WIDGET_VISIBLE(m_frameMenuBar->m_widget) && !m_menuBarDetached)
203 {
204 *height -= m_menuBarHeight;
205 }
206 #endif // wxUSE_MENUS_NATIVE
207
208 #if wxUSE_STATUSBAR
209 // status bar
210 if (m_frameStatusBar && GTK_WIDGET_VISIBLE(m_frameStatusBar->m_widget))
211 *height -= wxSTATUS_HEIGHT;
212 #endif // wxUSE_STATUSBAR
213 }
214
215 #if wxUSE_TOOLBAR
216 // tool bar
217 if (m_frameToolBar &&
218 GTK_WIDGET_VISIBLE(m_frameToolBar->m_widget) && !m_toolBarDetached)
219 {
220 if (m_frameToolBar->IsVertical())
221 {
222 if (width)
223 *width -= m_frameToolBar->GetSize().x;
224 }
225 else
226 {
227 if (height)
228 *height -= m_frameToolBar->GetSize().y;
229 }
230 }
231 #endif // wxUSE_TOOLBAR
232
233 if (width != NULL && *width < 0)
234 *width = 0;
235 if (height != NULL && *height < 0)
236 *height = 0;
237 }
238
239 bool wxFrame::ShowFullScreen(bool show, long style)
240 {
241 if (!wxFrameBase::ShowFullScreen(show, style))
242 return false;
243
244 wxWindow* const bar[] = {
245 m_frameMenuBar, m_frameToolBar, m_frameStatusBar
246 };
247 const long fsNoBar[] = {
248 wxFULLSCREEN_NOMENUBAR, wxFULLSCREEN_NOTOOLBAR, wxFULLSCREEN_NOSTATUSBAR
249 };
250 for (int i = 0; i < 3; i++)
251 {
252 if (show)
253 {
254 if (bar[i] && (style & fsNoBar[i]))
255 {
256 if (bar[i]->IsShown())
257 bar[i]->Show(false);
258 else
259 style &= ~fsNoBar[i];
260 }
261 }
262 else
263 {
264 if (bar[i] && (m_fsSaveFlag & fsNoBar[i]))
265 bar[i]->Show(true);
266 }
267 }
268 if (show)
269 m_fsSaveFlag = style;
270
271 return true;
272 }
273
274 void wxFrame::GtkOnSize()
275 {
276 // avoid recursions
277 if (m_resizing) return;
278 m_resizing = true;
279
280 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
281 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
282
283 // space occupied by m_frameToolBar and m_frameMenuBar
284 int client_area_x_offset = 0,
285 client_area_y_offset = 0;
286
287 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
288 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
289 set in wxFrame::Create so it is used to check what kind of frame we
290 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
291 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
292 importantly) m_mainWidget */
293
294 ConstrainSize();
295
296 if (m_mainWidget)
297 {
298 // TODO
299 // Rewrite this terrible code to using GtkVBox
300
301 // m_mainWidget holds the menubar, the toolbar and the client
302 // area, which is represented by m_wxwindow.
303
304 #if wxUSE_MENUS_NATIVE
305 if (m_frameMenuBar && m_frameMenuBar->IsShown())
306 {
307 int xx = m_miniEdge;
308 int yy = m_miniEdge + m_miniTitle;
309 int ww = m_width - 2*m_miniEdge;
310 if (ww < 0)
311 ww = 0;
312 int hh = m_menuBarHeight;
313 if (m_menuBarDetached) hh = wxPLACE_HOLDER;
314 m_frameMenuBar->m_x = xx;
315 m_frameMenuBar->m_y = yy;
316 m_frameMenuBar->m_width = ww;
317 m_frameMenuBar->m_height = hh;
318 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
319 m_frameMenuBar->m_widget,
320 xx, yy, ww, hh );
321 client_area_y_offset += hh;
322 }
323 #endif // wxUSE_MENUS_NATIVE
324
325 #if wxUSE_TOOLBAR
326 if ((m_frameToolBar) && m_frameToolBar->IsShown() &&
327 (m_frameToolBar->m_widget->parent == m_mainWidget))
328 {
329 int xx = m_miniEdge;
330 int yy = m_miniEdge + m_miniTitle;
331 #if wxUSE_MENUS_NATIVE
332 if (m_frameMenuBar)
333 {
334 if (!m_menuBarDetached)
335 yy += m_menuBarHeight;
336 else
337 yy += wxPLACE_HOLDER;
338 }
339 #endif // wxUSE_MENUS_NATIVE
340
341 m_frameToolBar->m_x = xx;
342 m_frameToolBar->m_y = yy;
343
344 // don't change the toolbar's reported height/width
345 int ww, hh;
346 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
347 {
348 ww = m_toolBarDetached ? wxPLACE_HOLDER
349 : m_frameToolBar->m_width;
350 hh = m_height - 2*m_miniEdge;
351
352 client_area_x_offset += ww;
353 }
354 else if( m_frameToolBar->HasFlag(wxTB_RIGHT) )
355 {
356 yy += 2;
357 ww = m_toolBarDetached ? wxPLACE_HOLDER
358 : m_frameToolBar->m_width;
359 xx = GetClientSize().x - 1;
360 hh = m_height - 2*m_miniEdge;
361 if( hh < 0 )
362 hh = 0;
363
364 }
365 else if( m_frameToolBar->GetWindowStyle() & wxTB_BOTTOM )
366 {
367 xx = m_miniEdge;
368 yy = GetClientSize().y;
369 #if wxUSE_MENUS_NATIVE
370 yy += m_menuBarHeight;
371 #endif // wxUSE_MENU_NATIVE
372 m_frameToolBar->m_x = xx;
373 m_frameToolBar->m_y = yy;
374 ww = m_width - 2*m_miniEdge;
375 hh = m_toolBarDetached ? wxPLACE_HOLDER
376 : m_frameToolBar->m_height;
377 }
378 else
379 {
380 ww = m_width - 2*m_miniEdge;
381 hh = m_toolBarDetached ? wxPLACE_HOLDER
382 : m_frameToolBar->m_height;
383
384 client_area_y_offset += hh;
385 }
386
387 if (ww < 0)
388 ww = 0;
389 if (hh < 0)
390 hh = 0;
391 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
392 m_frameToolBar->m_widget,
393 xx, yy, ww, hh );
394 }
395 #endif // wxUSE_TOOLBAR
396
397 int client_x = client_area_x_offset + m_miniEdge;
398 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
399 int client_w = m_width - client_area_x_offset - 2*m_miniEdge;
400 int client_h = m_height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
401 if (client_w < 0)
402 client_w = 0;
403 if (client_h < 0)
404 client_h = 0;
405 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
406 m_wxwindow,
407 client_x, client_y, client_w, client_h );
408 }
409 else
410 {
411 // If there is no m_mainWidget between m_widget and m_wxwindow there
412 // is no need to set the size or position of m_wxwindow.
413 }
414
415 #if wxUSE_STATUSBAR
416 if (m_frameStatusBar && m_frameStatusBar->IsShown())
417 {
418 int xx = 0 + m_miniEdge;
419 int yy = m_height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
420 int ww = m_width - 2*m_miniEdge;
421 if (ww < 0)
422 ww = 0;
423 int hh = wxSTATUS_HEIGHT;
424 m_frameStatusBar->m_x = xx;
425 m_frameStatusBar->m_y = yy;
426 m_frameStatusBar->m_width = ww;
427 m_frameStatusBar->m_height = hh;
428 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow),
429 m_frameStatusBar->m_widget,
430 xx, yy, ww, hh );
431 }
432 #endif // wxUSE_STATUSBAR
433
434 m_sizeSet = true;
435
436 // send size event to frame
437 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
438 event.SetEventObject( this );
439 GetEventHandler()->ProcessEvent( event );
440
441 #if wxUSE_STATUSBAR
442 // send size event to status bar
443 if (m_frameStatusBar)
444 {
445 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
446 event2.SetEventObject( m_frameStatusBar );
447 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
448 }
449 #endif // wxUSE_STATUSBAR
450
451 m_resizing = false;
452 }
453
454 void wxFrame::OnInternalIdle()
455 {
456 wxFrameBase::OnInternalIdle();
457
458 #if wxUSE_MENUS_NATIVE
459 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
460 #endif // wxUSE_MENUS_NATIVE
461 #if wxUSE_TOOLBAR
462 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
463 #endif
464 #if wxUSE_STATUSBAR
465 if (m_frameStatusBar)
466 {
467 m_frameStatusBar->OnInternalIdle();
468
469 // There may be controls in the status bar that
470 // need to be updated
471 for ( wxWindowList::compatibility_iterator node = m_frameStatusBar->GetChildren().GetFirst();
472 node;
473 node = node->GetNext() )
474 {
475 wxWindow *child = node->GetData();
476 child->OnInternalIdle();
477 }
478 }
479 #endif
480 }
481
482 // ----------------------------------------------------------------------------
483 // menu/tool/status bar stuff
484 // ----------------------------------------------------------------------------
485
486 #if wxUSE_MENUS_NATIVE
487
488 void wxFrame::DetachMenuBar()
489 {
490 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
491 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
492
493 if ( m_frameMenuBar )
494 {
495 m_frameMenuBar->UnsetInvokingWindow( this );
496
497 if (m_frameMenuBar->GetWindowStyle() & wxMB_DOCKABLE)
498 {
499 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
500 (gpointer) gtk_menu_attached_callback,
501 this);
502
503 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
504 (gpointer) gtk_menu_detached_callback,
505 this);
506 }
507
508 gtk_widget_ref( m_frameMenuBar->m_widget );
509
510 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
511 }
512
513 wxFrameBase::DetachMenuBar();
514 }
515
516 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
517 {
518 wxFrameBase::AttachMenuBar(menuBar);
519
520 if (m_frameMenuBar)
521 {
522 m_frameMenuBar->SetInvokingWindow( this );
523
524 m_frameMenuBar->SetParent(this);
525 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
526 m_frameMenuBar->m_widget,
527 m_frameMenuBar->m_x,
528 m_frameMenuBar->m_y,
529 m_frameMenuBar->m_width,
530 m_frameMenuBar->m_height );
531
532 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
533 {
534 g_signal_connect (menuBar->m_widget, "child_attached",
535 G_CALLBACK (gtk_menu_attached_callback),
536 this);
537 g_signal_connect (menuBar->m_widget, "child_detached",
538 G_CALLBACK (gtk_menu_detached_callback),
539 this);
540 }
541
542 gtk_widget_show( m_frameMenuBar->m_widget );
543
544 UpdateMenuBarSize();
545 }
546 else
547 {
548 m_menuBarHeight = 2;
549 GtkUpdateSize(); // resize window in OnInternalIdle
550 }
551 }
552
553 void wxFrame::UpdateMenuBarSize()
554 {
555 m_menuBarHeight = 2;
556
557 // this is called after Remove with a NULL m_frameMenuBar
558 if ( m_frameMenuBar )
559 {
560 GtkRequisition req;
561 gtk_widget_ensure_style(m_frameMenuBar->m_widget);
562 // have to call class method directly because
563 // "size_request" signal is overridden by wx
564 GTK_WIDGET_GET_CLASS(m_frameMenuBar->m_widget)->size_request(
565 m_frameMenuBar->m_widget, &req);
566
567 m_menuBarHeight = req.height;
568 }
569
570 // resize window in OnInternalIdle
571 GtkUpdateSize();
572 }
573
574 #endif // wxUSE_MENUS_NATIVE
575
576 #if wxUSE_TOOLBAR
577
578 wxToolBar* wxFrame::CreateToolBar( long style, wxWindowID id, const wxString& name )
579 {
580 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
581
582 InsertChildFunction save = m_insertCallback;
583 m_insertCallback = wxInsertChildInFrame;
584 m_frameToolBar = wxFrameBase::CreateToolBar( style, id, name );
585 m_insertCallback = save;
586
587 GtkUpdateSize();
588
589 return m_frameToolBar;
590 }
591
592 void wxFrame::SetToolBar(wxToolBar *toolbar)
593 {
594 bool hadTbar = m_frameToolBar != NULL;
595
596 wxFrameBase::SetToolBar(toolbar);
597
598 if ( m_frameToolBar )
599 {
600 // insert into toolbar area if not already there
601 if ((m_frameToolBar->m_widget->parent) &&
602 (m_frameToolBar->m_widget->parent != m_mainWidget))
603 {
604 GetChildren().DeleteObject( m_frameToolBar );
605
606 gtk_widget_reparent( m_frameToolBar->m_widget, m_mainWidget );
607 GtkUpdateSize();
608 }
609 }
610 else // toolbar unset
611 {
612 // still need to update size if it had been there before
613 if ( hadTbar )
614 {
615 GtkUpdateSize();
616 }
617 }
618 }
619
620 #endif // wxUSE_TOOLBAR
621
622 #if wxUSE_STATUSBAR
623
624 wxStatusBar* wxFrame::CreateStatusBar(int number,
625 long style,
626 wxWindowID id,
627 const wxString& name)
628 {
629 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
630
631 // because it will change when toolbar is added
632 GtkUpdateSize();
633
634 return wxFrameBase::CreateStatusBar( number, style, id, name );
635 }
636
637 void wxFrame::SetStatusBar(wxStatusBar *statbar)
638 {
639 bool hadStatBar = m_frameStatusBar != NULL;
640
641 wxFrameBase::SetStatusBar(statbar);
642
643 if (hadStatBar && !m_frameStatusBar)
644 GtkUpdateSize();
645 }
646
647 void wxFrame::PositionStatusBar()
648 {
649 if ( !m_frameStatusBar )
650 return;
651
652 GtkUpdateSize();
653 }
654 #endif // wxUSE_STATUSBAR