]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/frame.cpp
update frm Ivan Masar
[wxWidgets.git] / src / gtk / frame.cpp
... / ...
CommitLineData
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
28static const int wxSTATUS_HEIGHT = 25;
29static const int wxPLACE_HOLDER = 0;
30
31// ----------------------------------------------------------------------------
32// event tables
33// ----------------------------------------------------------------------------
34
35IMPLEMENT_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
51extern "C" {
52static 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
65extern "C" {
66static 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
85extern "C" {
86static 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
99extern "C" {
100static 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
127static void wxInsertChildInFrame( wxFrame* parent, wxWindow* child )
128{
129 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
130
131 if (!parent->m_insertInClientArea)
132 {
133 // These are outside the client area
134 wxFrame* frame = (wxFrame*) parent;
135 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
136 child->m_widget,
137 child->m_x,
138 child->m_y,
139 child->m_width,
140 child->m_height );
141
142#if wxUSE_TOOLBAR_NATIVE
143 // We connect to these events for recalculating the client area
144 // space when the toolbar is floating
145 if (wxIS_KIND_OF(child,wxToolBar))
146 {
147 wxToolBar *toolBar = (wxToolBar*) child;
148 if (toolBar->GetWindowStyle() & wxTB_DOCKABLE)
149 {
150 g_signal_connect (toolBar->m_widget, "child_attached",
151 G_CALLBACK (gtk_toolbar_attached_callback),
152 parent);
153 g_signal_connect (toolBar->m_widget, "child_detached",
154 G_CALLBACK (gtk_toolbar_detached_callback),
155 parent);
156 }
157 }
158#endif // wxUSE_TOOLBAR
159 }
160 else
161 {
162 // These are inside the client area
163 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
164 child->m_widget,
165 child->m_x,
166 child->m_y,
167 child->m_width,
168 child->m_height );
169 }
170}
171
172// ----------------------------------------------------------------------------
173// wxFrame creation
174// ----------------------------------------------------------------------------
175
176void wxFrame::Init()
177{
178 m_menuBarDetached = false;
179 m_toolBarDetached = false;
180 m_menuBarHeight = 2;
181}
182
183bool wxFrame::Create( wxWindow *parent,
184 wxWindowID id,
185 const wxString& title,
186 const wxPoint& pos,
187 const wxSize& sizeOrig,
188 long style,
189 const wxString &name )
190{
191 bool rt = wxTopLevelWindow::Create(parent, id, title, pos, sizeOrig,
192 style, name);
193 m_insertCallback = (wxInsertChildFunction) wxInsertChildInFrame;
194
195 return rt;
196}
197
198wxFrame::~wxFrame()
199{
200 m_isBeingDeleted = true;
201 DeleteAllBars();
202}
203
204// ----------------------------------------------------------------------------
205// overridden wxWindow methods
206// ----------------------------------------------------------------------------
207
208void wxFrame::DoGetClientSize( int *width, int *height ) const
209{
210 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
211
212 wxTopLevelWindow::DoGetClientSize( width, height );
213
214 if (height)
215 {
216#if wxUSE_MENUS_NATIVE
217 // menu bar
218 if (m_frameMenuBar && !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOMENUBAR) != 0))
219 {
220 if (!m_menuBarDetached)
221 (*height) -= m_menuBarHeight;
222 else
223 (*height) -= wxPLACE_HOLDER;
224 }
225#endif // wxUSE_MENUS_NATIVE
226
227#if wxUSE_STATUSBAR
228 // status bar
229 if (m_frameStatusBar && m_frameStatusBar->IsShown() &&
230 !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOSTATUSBAR) != 0))
231 (*height) -= wxSTATUS_HEIGHT;
232#endif // wxUSE_STATUSBAR
233 }
234
235#if wxUSE_TOOLBAR
236 // tool bar
237 if (m_frameToolBar && m_frameToolBar->IsShown())
238 {
239 if (m_toolBarDetached)
240 {
241 if (height != NULL)
242 *height -= wxPLACE_HOLDER;
243 }
244 else
245 {
246 int x, y;
247 m_frameToolBar->GetSize( &x, &y );
248 if ( m_frameToolBar->IsVertical() )
249 {
250 if (width != NULL)
251 *width -= x;
252 }
253 else
254 {
255 if (height != NULL)
256 *height -= y;
257 }
258 }
259 }
260#endif // wxUSE_TOOLBAR
261
262 if (width != NULL && *width < 0)
263 *width = 0;
264 if (height != NULL && *height < 0)
265 *height = 0;
266}
267
268void wxFrame::DoSetClientSize( int width, int height )
269{
270 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
271
272#if wxUSE_MENUS_NATIVE
273 // menu bar
274 if (m_frameMenuBar && !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOMENUBAR) != 0))
275 {
276 if (!m_menuBarDetached)
277 height += m_menuBarHeight;
278 else
279 height += wxPLACE_HOLDER;
280 }
281#endif // wxUSE_MENUS_NATIVE
282
283#if wxUSE_STATUSBAR
284 // status bar
285 if (m_frameStatusBar && m_frameStatusBar->IsShown() &&
286 !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOSTATUSBAR) != 0))
287 height += wxSTATUS_HEIGHT;
288#endif
289
290#if wxUSE_TOOLBAR
291 // tool bar
292 if (m_frameToolBar && m_frameToolBar->IsShown())
293 {
294 if (m_toolBarDetached)
295 {
296 height += wxPLACE_HOLDER;
297 }
298 else
299 {
300 int x, y;
301 m_frameToolBar->GetSize( &x, &y );
302 if ( m_frameToolBar->IsVertical() )
303 {
304 width += x;
305 }
306 else
307 {
308 height += y;
309 }
310 }
311 }
312#endif
313
314 wxTopLevelWindow::DoSetClientSize( width, height );
315}
316
317void wxFrame::GtkOnSize()
318{
319 // avoid recursions
320 if (m_resizing) return;
321 m_resizing = true;
322
323 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
324 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
325
326 // space occupied by m_frameToolBar and m_frameMenuBar
327 int client_area_x_offset = 0,
328 client_area_y_offset = 0;
329
330 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
331 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
332 set in wxFrame::Create so it is used to check what kind of frame we
333 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
334 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
335 importantly) m_mainWidget */
336
337 ConstrainSize();
338
339 if (m_mainWidget)
340 {
341 // TODO
342 // Rewrite this terrible code to using GtkVBox
343
344 // m_mainWidget holds the menubar, the toolbar and the client
345 // area, which is represented by m_wxwindow.
346
347#if wxUSE_MENUS_NATIVE
348 if (m_frameMenuBar && !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOMENUBAR) != 0))
349 {
350 if (!GTK_WIDGET_VISIBLE(m_frameMenuBar->m_widget))
351 gtk_widget_show( m_frameMenuBar->m_widget );
352 int xx = m_miniEdge;
353 int yy = m_miniEdge + m_miniTitle;
354 int ww = m_width - 2*m_miniEdge;
355 if (ww < 0)
356 ww = 0;
357 int hh = m_menuBarHeight;
358 if (m_menuBarDetached) hh = wxPLACE_HOLDER;
359 m_frameMenuBar->m_x = xx;
360 m_frameMenuBar->m_y = yy;
361 m_frameMenuBar->m_width = ww;
362 m_frameMenuBar->m_height = hh;
363 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
364 m_frameMenuBar->m_widget,
365 xx, yy, ww, hh );
366 client_area_y_offset += hh;
367 }
368 else
369 {
370 if (m_frameMenuBar)
371 {
372 if (GTK_WIDGET_VISIBLE(m_frameMenuBar->m_widget))
373 gtk_widget_hide( m_frameMenuBar->m_widget );
374 }
375 }
376#endif // wxUSE_MENUS_NATIVE
377
378#if wxUSE_TOOLBAR
379 if ((m_frameToolBar) && m_frameToolBar->IsShown() &&
380 (m_frameToolBar->m_widget->parent == m_mainWidget))
381 {
382 int xx = m_miniEdge;
383 int yy = m_miniEdge + m_miniTitle;
384#if wxUSE_MENUS_NATIVE
385 if (m_frameMenuBar)
386 {
387 if (!m_menuBarDetached)
388 yy += m_menuBarHeight;
389 else
390 yy += wxPLACE_HOLDER;
391 }
392#endif // wxUSE_MENUS_NATIVE
393
394 m_frameToolBar->m_x = xx;
395 m_frameToolBar->m_y = yy;
396
397 // don't change the toolbar's reported height/width
398 int ww, hh;
399 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
400 {
401 ww = m_toolBarDetached ? wxPLACE_HOLDER
402 : m_frameToolBar->m_width;
403 hh = m_height - 2*m_miniEdge;
404
405 client_area_x_offset += ww;
406 }
407 else if( m_frameToolBar->HasFlag(wxTB_RIGHT) )
408 {
409 yy += 2;
410 ww = m_toolBarDetached ? wxPLACE_HOLDER
411 : m_frameToolBar->m_width;
412 xx = GetClientSize().x - 1;
413 hh = m_height - 2*m_miniEdge;
414 if( hh < 0 )
415 hh = 0;
416
417 }
418 else if( m_frameToolBar->GetWindowStyle() & wxTB_BOTTOM )
419 {
420 xx = m_miniEdge;
421 yy = GetClientSize().y;
422#if wxUSE_MENUS_NATIVE
423 yy += m_menuBarHeight;
424#endif // wxUSE_MENU_NATIVE
425 m_frameToolBar->m_x = xx;
426 m_frameToolBar->m_y = yy;
427 ww = m_width - 2*m_miniEdge;
428 hh = m_toolBarDetached ? wxPLACE_HOLDER
429 : m_frameToolBar->m_height;
430 }
431 else
432 {
433 ww = m_width - 2*m_miniEdge;
434 hh = m_toolBarDetached ? wxPLACE_HOLDER
435 : m_frameToolBar->m_height;
436
437 client_area_y_offset += hh;
438 }
439
440 if (ww < 0)
441 ww = 0;
442 if (hh < 0)
443 hh = 0;
444 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
445 m_frameToolBar->m_widget,
446 xx, yy, ww, hh );
447 }
448#endif // wxUSE_TOOLBAR
449
450 int client_x = client_area_x_offset + m_miniEdge;
451 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
452 int client_w = m_width - client_area_x_offset - 2*m_miniEdge;
453 int client_h = m_height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
454 if (client_w < 0)
455 client_w = 0;
456 if (client_h < 0)
457 client_h = 0;
458 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
459 m_wxwindow,
460 client_x, client_y, client_w, client_h );
461 }
462 else
463 {
464 // If there is no m_mainWidget between m_widget and m_wxwindow there
465 // is no need to set the size or position of m_wxwindow.
466 }
467
468#if wxUSE_STATUSBAR
469 if (m_frameStatusBar && m_frameStatusBar->IsShown() &&
470 !(m_fsIsShowing && (m_fsSaveFlag & wxFULLSCREEN_NOSTATUSBAR) != 0))
471 {
472 if (!GTK_WIDGET_VISIBLE(m_frameStatusBar->m_widget))
473 gtk_widget_show( m_frameStatusBar->m_widget );
474
475 int xx = 0 + m_miniEdge;
476 int yy = m_height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
477 int ww = m_width - 2*m_miniEdge;
478 if (ww < 0)
479 ww = 0;
480 int hh = wxSTATUS_HEIGHT;
481 m_frameStatusBar->m_x = xx;
482 m_frameStatusBar->m_y = yy;
483 m_frameStatusBar->m_width = ww;
484 m_frameStatusBar->m_height = hh;
485 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow),
486 m_frameStatusBar->m_widget,
487 xx, yy, ww, hh );
488 }
489 else
490 {
491 if (m_frameStatusBar)
492 {
493 if (GTK_WIDGET_VISIBLE(m_frameStatusBar->m_widget))
494 gtk_widget_hide( m_frameStatusBar->m_widget );
495 }
496 }
497#endif // wxUSE_STATUSBAR
498
499 m_sizeSet = true;
500
501 // send size event to frame
502 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
503 event.SetEventObject( this );
504 GetEventHandler()->ProcessEvent( event );
505
506#if wxUSE_STATUSBAR
507 // send size event to status bar
508 if (m_frameStatusBar)
509 {
510 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
511 event2.SetEventObject( m_frameStatusBar );
512 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
513 }
514#endif // wxUSE_STATUSBAR
515
516 m_resizing = false;
517}
518
519void wxFrame::OnInternalIdle()
520{
521 wxFrameBase::OnInternalIdle();
522
523#if wxUSE_MENUS_NATIVE
524 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
525#endif // wxUSE_MENUS_NATIVE
526#if wxUSE_TOOLBAR
527 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
528#endif
529#if wxUSE_STATUSBAR
530 if (m_frameStatusBar)
531 {
532 m_frameStatusBar->OnInternalIdle();
533
534 // There may be controls in the status bar that
535 // need to be updated
536 for ( wxWindowList::compatibility_iterator node = m_frameStatusBar->GetChildren().GetFirst();
537 node;
538 node = node->GetNext() )
539 {
540 wxWindow *child = node->GetData();
541 child->OnInternalIdle();
542 }
543 }
544#endif
545}
546
547// ----------------------------------------------------------------------------
548// menu/tool/status bar stuff
549// ----------------------------------------------------------------------------
550
551#if wxUSE_MENUS_NATIVE
552
553void wxFrame::DetachMenuBar()
554{
555 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
556 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
557
558 if ( m_frameMenuBar )
559 {
560 m_frameMenuBar->UnsetInvokingWindow( this );
561
562 if (m_frameMenuBar->GetWindowStyle() & wxMB_DOCKABLE)
563 {
564 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
565 (gpointer) gtk_menu_attached_callback,
566 this);
567
568 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
569 (gpointer) gtk_menu_detached_callback,
570 this);
571 }
572
573 gtk_widget_ref( m_frameMenuBar->m_widget );
574
575 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
576 }
577
578 wxFrameBase::DetachMenuBar();
579}
580
581void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
582{
583 wxFrameBase::AttachMenuBar(menuBar);
584
585 if (m_frameMenuBar)
586 {
587 m_frameMenuBar->SetInvokingWindow( this );
588
589 m_frameMenuBar->SetParent(this);
590 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
591 m_frameMenuBar->m_widget,
592 m_frameMenuBar->m_x,
593 m_frameMenuBar->m_y,
594 m_frameMenuBar->m_width,
595 m_frameMenuBar->m_height );
596
597 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
598 {
599 g_signal_connect (menuBar->m_widget, "child_attached",
600 G_CALLBACK (gtk_menu_attached_callback),
601 this);
602 g_signal_connect (menuBar->m_widget, "child_detached",
603 G_CALLBACK (gtk_menu_detached_callback),
604 this);
605 }
606
607 gtk_widget_show( m_frameMenuBar->m_widget );
608
609 UpdateMenuBarSize();
610 }
611 else
612 {
613 m_menuBarHeight = 2;
614 GtkUpdateSize(); // resize window in OnInternalIdle
615 }
616}
617
618void wxFrame::UpdateMenuBarSize()
619{
620 m_menuBarHeight = 2;
621
622 // this is called after Remove with a NULL m_frameMenuBar
623 if ( m_frameMenuBar )
624 {
625 GtkRequisition req;
626 gtk_widget_ensure_style(m_frameMenuBar->m_widget);
627 // have to call class method directly because
628 // "size_request" signal is overridden by wx
629 GTK_WIDGET_GET_CLASS(m_frameMenuBar->m_widget)->size_request(
630 m_frameMenuBar->m_widget, &req);
631
632 m_menuBarHeight = req.height;
633 }
634
635 // resize window in OnInternalIdle
636 GtkUpdateSize();
637}
638
639#endif // wxUSE_MENUS_NATIVE
640
641#if wxUSE_TOOLBAR
642
643wxToolBar* wxFrame::CreateToolBar( long style, wxWindowID id, const wxString& name )
644{
645 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
646
647 m_insertInClientArea = false;
648
649 m_frameToolBar = wxFrameBase::CreateToolBar( style, id, name );
650
651 m_insertInClientArea = true;
652
653 GtkUpdateSize();
654
655 return m_frameToolBar;
656}
657
658void wxFrame::SetToolBar(wxToolBar *toolbar)
659{
660 bool hadTbar = m_frameToolBar != NULL;
661
662 wxFrameBase::SetToolBar(toolbar);
663
664 if ( m_frameToolBar )
665 {
666 // insert into toolbar area if not already there
667 if ((m_frameToolBar->m_widget->parent) &&
668 (m_frameToolBar->m_widget->parent != m_mainWidget))
669 {
670 GetChildren().DeleteObject( m_frameToolBar );
671
672 gtk_widget_reparent( m_frameToolBar->m_widget, m_mainWidget );
673 GtkUpdateSize();
674 }
675 }
676 else // toolbar unset
677 {
678 // still need to update size if it had been there before
679 if ( hadTbar )
680 {
681 GtkUpdateSize();
682 }
683 }
684}
685
686#endif // wxUSE_TOOLBAR
687
688#if wxUSE_STATUSBAR
689
690wxStatusBar* wxFrame::CreateStatusBar(int number,
691 long style,
692 wxWindowID id,
693 const wxString& name)
694{
695 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
696
697 // because it will change when toolbar is added
698 GtkUpdateSize();
699
700 return wxFrameBase::CreateStatusBar( number, style, id, name );
701}
702
703void wxFrame::SetStatusBar(wxStatusBar *statbar)
704{
705 bool hadStatBar = m_frameStatusBar != NULL;
706
707 wxFrameBase::SetStatusBar(statbar);
708
709 if (hadStatBar && !m_frameStatusBar)
710 GtkUpdateSize();
711}
712
713void wxFrame::PositionStatusBar()
714{
715 if ( !m_frameStatusBar )
716 return;
717
718 GtkUpdateSize();
719}
720#endif // wxUSE_STATUSBAR