1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/frame.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"
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
25 #include "wx/dcclient.h"
27 #include "wx/dialog.h"
28 #include "wx/control.h"
29 #include "wx/toolbar.h"
30 #include "wx/statusbr.h"
34 #include "wx/gtk/private.h"
36 #include <gdk/gdkkeysyms.h>
39 #include "wx/gtk/win_gtk.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 const int wxSTATUS_HEIGHT
= 25;
46 const int wxPLACE_HOLDER
= 0;
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
)
54 // ============================================================================
56 // ============================================================================
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 #if wxUSE_MENUS_NATIVE
64 //-----------------------------------------------------------------------------
65 // "child_attached" of menu bar
66 //-----------------------------------------------------------------------------
69 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
71 if (!win
->m_hasVMT
) return;
73 win
->m_menuBarDetached
= false;
78 //-----------------------------------------------------------------------------
79 // "child_detached" of menu bar
80 //-----------------------------------------------------------------------------
83 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
86 wxapp_install_idle_handler();
88 if (!win
->m_hasVMT
) return;
90 // Raise the client area area
91 gdk_window_raise( win
->m_wxwindow
->window
);
93 win
->m_menuBarDetached
= true;
98 #endif // wxUSE_MENUS_NATIVE
101 //-----------------------------------------------------------------------------
102 // "child_attached" of tool bar
103 //-----------------------------------------------------------------------------
106 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
108 if (!win
->m_hasVMT
) return;
110 win
->m_toolBarDetached
= false;
111 win
->GtkUpdateSize();
115 //-----------------------------------------------------------------------------
116 // "child_detached" of tool bar
117 //-----------------------------------------------------------------------------
120 static void gtk_toolbar_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
123 wxapp_install_idle_handler();
125 if (!win
->m_hasVMT
) return;
127 // Raise the client area area
128 gdk_window_raise( win
->m_wxwindow
->window
);
130 win
->m_toolBarDetached
= true;
131 win
->GtkUpdateSize();
134 #endif // wxUSE_TOOLBAR
137 // ----------------------------------------------------------------------------
139 // ----------------------------------------------------------------------------
141 //-----------------------------------------------------------------------------
142 // InsertChild for wxFrame
143 //-----------------------------------------------------------------------------
145 /* Callback for wxFrame. This very strange beast has to be used because
146 * C++ has no virtual methods in a constructor. We have to emulate a
147 * virtual function here as wxWidgets requires different ways to insert
148 * a child in container classes. */
150 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
152 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
154 if (!parent
->m_insertInClientArea
)
156 // These are outside the client area
157 wxFrame
* frame
= (wxFrame
*) parent
;
158 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
159 GTK_WIDGET(child
->m_widget
),
165 #if wxUSE_TOOLBAR_NATIVE
166 // We connect to these events for recalculating the client area
167 // space when the toolbar is floating
168 if (wxIS_KIND_OF(child
,wxToolBar
))
170 wxToolBar
*toolBar
= (wxToolBar
*) child
;
171 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
173 g_signal_connect (toolBar
->m_widget
, "child_attached",
174 G_CALLBACK (gtk_toolbar_attached_callback
),
176 g_signal_connect (toolBar
->m_widget
, "child_detached",
177 G_CALLBACK (gtk_toolbar_detached_callback
),
181 #endif // wxUSE_TOOLBAR
185 // These are inside the client area
186 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
187 GTK_WIDGET(child
->m_widget
),
195 // ----------------------------------------------------------------------------
197 // ----------------------------------------------------------------------------
201 m_menuBarDetached
= false;
202 m_toolBarDetached
= false;
206 bool wxFrame::Create( wxWindow
*parent
,
208 const wxString
& title
,
210 const wxSize
& sizeOrig
,
212 const wxString
&name
)
214 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
216 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
223 m_isBeingDeleted
= true;
227 // ----------------------------------------------------------------------------
228 // overridden wxWindow methods
229 // ----------------------------------------------------------------------------
231 void wxFrame::DoGetClientSize( int *width
, int *height
) const
233 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
235 wxTopLevelWindow::DoGetClientSize( width
, height
);
239 #if wxUSE_MENUS_NATIVE
243 if (!m_menuBarDetached
)
244 (*height
) -= m_menuBarHeight
;
246 (*height
) -= wxPLACE_HOLDER
;
248 #endif // wxUSE_MENUS_NATIVE
252 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
253 (*height
) -= wxSTATUS_HEIGHT
;
254 #endif // wxUSE_STATUSBAR
258 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
260 if (m_toolBarDetached
)
262 *height
-= wxPLACE_HOLDER
;
267 m_frameToolBar
->GetSize( &x
, &y
);
268 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
278 #endif // wxUSE_TOOLBAR
282 void wxFrame::DoSetClientSize( int width
, int height
)
284 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
286 #if wxUSE_MENUS_NATIVE
290 if (!m_menuBarDetached
)
291 height
+= m_menuBarHeight
;
293 height
+= wxPLACE_HOLDER
;
295 #endif // wxUSE_MENUS_NATIVE
299 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
304 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
306 if (m_toolBarDetached
)
308 height
+= wxPLACE_HOLDER
;
313 m_frameToolBar
->GetSize( &x
, &y
);
314 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
326 wxTopLevelWindow::DoSetClientSize( width
, height
);
329 void wxFrame::GtkOnSize()
332 if (m_resizing
) return;
335 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
336 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
338 // space occupied by m_frameToolBar and m_frameMenuBar
339 int client_area_x_offset
= 0,
340 client_area_y_offset
= 0;
342 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
343 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
344 set in wxFrame::Create so it is used to check what kind of frame we
345 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
346 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
347 importantly) m_mainWidget */
349 int minWidth
= GetMinWidth(),
350 minHeight
= GetMinHeight(),
351 maxWidth
= GetMaxWidth(),
352 maxHeight
= GetMaxHeight();
354 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
355 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
356 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
357 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
362 gint flag
= 0; // GDK_HINT_POS;
363 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
364 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
366 geom
.min_width
= minWidth
;
367 geom
.min_height
= minHeight
;
368 geom
.max_width
= maxWidth
;
369 geom
.max_height
= maxHeight
;
370 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
373 (GdkWindowHints
) flag
);
375 // I revert back to wxGTK's original behaviour. m_mainWidget holds
376 // the menubar, the toolbar and the client area, which is represented
378 // This hurts in the eye, but I don't want to call SetSize()
379 // because I don't want to call any non-native functions here.
381 #if wxUSE_MENUS_NATIVE
385 int yy
= m_miniEdge
+ m_miniTitle
;
386 int ww
= m_width
- 2*m_miniEdge
;
389 int hh
= m_menuBarHeight
;
390 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
391 m_frameMenuBar
->m_x
= xx
;
392 m_frameMenuBar
->m_y
= yy
;
393 m_frameMenuBar
->m_width
= ww
;
394 m_frameMenuBar
->m_height
= hh
;
395 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
396 m_frameMenuBar
->m_widget
,
398 client_area_y_offset
+= hh
;
400 #endif // wxUSE_MENUS_NATIVE
403 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
404 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
407 int yy
= m_miniEdge
+ m_miniTitle
;
408 #if wxUSE_MENUS_NATIVE
411 if (!m_menuBarDetached
)
412 yy
+= m_menuBarHeight
;
414 yy
+= wxPLACE_HOLDER
;
416 #endif // wxUSE_MENUS_NATIVE
418 m_frameToolBar
->m_x
= xx
;
419 m_frameToolBar
->m_y
= yy
;
421 // don't change the toolbar's reported height/width
423 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
425 ww
= m_toolBarDetached
? wxPLACE_HOLDER
426 : m_frameToolBar
->m_width
;
427 hh
= m_height
- 2*m_miniEdge
;
431 client_area_x_offset
+= ww
;
435 ww
= m_width
- 2*m_miniEdge
;
436 hh
= m_toolBarDetached
? wxPLACE_HOLDER
437 : m_frameToolBar
->m_height
;
439 client_area_y_offset
+= hh
;
442 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
443 m_frameToolBar
->m_widget
,
446 #endif // wxUSE_TOOLBAR
448 int client_x
= client_area_x_offset
+ m_miniEdge
;
449 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
450 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
451 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
456 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
458 client_x
, client_y
, client_w
, client_h
);
462 // If there is no m_mainWidget between m_widget and m_wxwindow there
463 // is no need to set the size or position of m_wxwindow.
467 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
469 int xx
= 0 + m_miniEdge
;
470 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
471 int ww
= m_width
- 2*m_miniEdge
;
474 int hh
= wxSTATUS_HEIGHT
;
475 m_frameStatusBar
->m_x
= xx
;
476 m_frameStatusBar
->m_y
= yy
;
477 m_frameStatusBar
->m_width
= ww
;
478 m_frameStatusBar
->m_height
= hh
;
479 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
480 m_frameStatusBar
->m_widget
,
483 #endif // wxUSE_STATUSBAR
487 // send size event to frame
488 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
489 event
.SetEventObject( this );
490 GetEventHandler()->ProcessEvent( event
);
493 // send size event to status bar
494 if (m_frameStatusBar
)
496 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
497 event2
.SetEventObject( m_frameStatusBar
);
498 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
500 #endif // wxUSE_STATUSBAR
505 void wxFrame::OnInternalIdle()
507 wxFrameBase::OnInternalIdle();
509 #if wxUSE_MENUS_NATIVE
510 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
511 #endif // wxUSE_MENUS_NATIVE
513 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
516 if (m_frameStatusBar
)
518 m_frameStatusBar
->OnInternalIdle();
520 // There may be controls in the status bar that
521 // need to be updated
522 for ( wxWindowList::compatibility_iterator node
= m_frameStatusBar
->GetChildren().GetFirst();
524 node
= node
->GetNext() )
526 wxWindow
*child
= node
->GetData();
527 child
->OnInternalIdle();
533 // ----------------------------------------------------------------------------
534 // menu/tool/status bar stuff
535 // ----------------------------------------------------------------------------
537 #if wxUSE_MENUS_NATIVE
539 void wxFrame::DetachMenuBar()
541 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
542 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
544 if ( m_frameMenuBar
)
546 m_frameMenuBar
->UnsetInvokingWindow( this );
548 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
550 g_signal_handlers_disconnect_by_func (m_frameMenuBar
->m_widget
,
551 (gpointer
) gtk_menu_attached_callback
,
554 g_signal_handlers_disconnect_by_func (m_frameMenuBar
->m_widget
,
555 (gpointer
) gtk_menu_detached_callback
,
559 gtk_widget_ref( m_frameMenuBar
->m_widget
);
561 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
564 wxFrameBase::DetachMenuBar();
567 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
569 wxFrameBase::AttachMenuBar(menuBar
);
573 m_frameMenuBar
->SetInvokingWindow( this );
575 m_frameMenuBar
->SetParent(this);
576 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
577 m_frameMenuBar
->m_widget
,
580 m_frameMenuBar
->m_width
,
581 m_frameMenuBar
->m_height
);
583 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
585 g_signal_connect (menuBar
->m_widget
, "child_attached",
586 G_CALLBACK (gtk_menu_attached_callback
),
588 g_signal_connect (menuBar
->m_widget
, "child_detached",
589 G_CALLBACK (gtk_menu_detached_callback
),
593 gtk_widget_show( m_frameMenuBar
->m_widget
);
600 GtkUpdateSize(); // resize window in OnInternalIdle
604 void wxFrame::UpdateMenuBarSize()
611 // this is called after Remove with a NULL m_frameMenuBar
612 if ( m_frameMenuBar
)
613 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request
)
614 (m_frameMenuBar
->m_widget
, &req
);
616 m_menuBarHeight
= req
.height
;
618 // resize window in OnInternalIdle
623 #endif // wxUSE_MENUS_NATIVE
627 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
629 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
631 m_insertInClientArea
= false;
633 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
635 m_insertInClientArea
= true;
639 return m_frameToolBar
;
642 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
644 bool hadTbar
= m_frameToolBar
!= NULL
;
646 wxFrameBase::SetToolBar(toolbar
);
648 if ( m_frameToolBar
)
650 // insert into toolbar area if not already there
651 if ((m_frameToolBar
->m_widget
->parent
) &&
652 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
654 GetChildren().DeleteObject( m_frameToolBar
);
656 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
660 else // toolbar unset
662 // still need to update size if it had been there before
670 #endif // wxUSE_TOOLBAR
674 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
677 const wxString
& name
)
679 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
681 // because it will change when toolbar is added
684 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
687 void wxFrame::SetStatusBar(wxStatusBar
*statbar
)
689 bool hadStatBar
= m_frameStatusBar
!= NULL
;
691 wxFrameBase::SetStatusBar(statbar
);
693 if (hadStatBar
&& !m_frameStatusBar
)
697 void wxFrame::PositionStatusBar()
699 if ( !m_frameStatusBar
)
704 #endif // wxUSE_STATUSBAR