1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/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"
32 #include "wx/toolbar.h"
35 #include "wx/statusbr.h"
39 #include "wx/gtk1/private.h"
41 #include <gdk/gdkkeysyms.h>
44 #include "wx/gtk1/win_gtk.h"
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 const int wxSTATUS_HEIGHT
= 25;
51 const int wxPLACE_HOLDER
= 0;
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 extern void wxapp_install_idle_handler();
60 // ----------------------------------------------------------------------------
62 // ----------------------------------------------------------------------------
64 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
)
66 // ============================================================================
68 // ============================================================================
70 // ----------------------------------------------------------------------------
72 // ----------------------------------------------------------------------------
74 #if wxUSE_MENUS_NATIVE
76 //-----------------------------------------------------------------------------
77 // "child_attached" of menu bar
78 //-----------------------------------------------------------------------------
81 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
83 if (!win
->m_hasVMT
) return;
85 win
->m_menuBarDetached
= false;
90 //-----------------------------------------------------------------------------
91 // "child_detached" of menu bar
92 //-----------------------------------------------------------------------------
95 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
98 wxapp_install_idle_handler();
100 if (!win
->m_hasVMT
) return;
102 // Raise the client area area
103 gdk_window_raise( win
->m_wxwindow
->window
);
105 win
->m_menuBarDetached
= true;
106 win
->GtkUpdateSize();
110 #endif // wxUSE_MENUS_NATIVE
113 //-----------------------------------------------------------------------------
114 // "child_attached" of tool bar
115 //-----------------------------------------------------------------------------
118 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
120 if (!win
->m_hasVMT
) return;
122 win
->m_toolBarDetached
= false;
123 win
->GtkUpdateSize();
127 //-----------------------------------------------------------------------------
128 // "child_detached" of tool bar
129 //-----------------------------------------------------------------------------
132 static void gtk_toolbar_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
135 wxapp_install_idle_handler();
137 if (!win
->m_hasVMT
) return;
139 // Raise the client area area
140 gdk_window_raise( win
->m_wxwindow
->window
);
142 win
->m_toolBarDetached
= true;
143 win
->GtkUpdateSize();
146 #endif // wxUSE_TOOLBAR
149 // ----------------------------------------------------------------------------
151 // ----------------------------------------------------------------------------
153 //-----------------------------------------------------------------------------
154 // InsertChild for wxFrame
155 //-----------------------------------------------------------------------------
157 /* Callback for wxFrame. This very strange beast has to be used because
158 * C++ has no virtual methods in a constructor. We have to emulate a
159 * virtual function here as wxWidgets requires different ways to insert
160 * a child in container classes. */
162 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
164 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
166 if (!parent
->m_insertInClientArea
)
168 // These are outside the client area
169 wxFrame
* frame
= (wxFrame
*) parent
;
170 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
171 GTK_WIDGET(child
->m_widget
),
177 #if wxUSE_TOOLBAR_NATIVE
178 // We connect to these events for recalculating the client area
179 // space when the toolbar is floating
180 if (wxIS_KIND_OF(child
,wxToolBar
))
182 wxToolBar
*toolBar
= (wxToolBar
*) child
;
183 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
185 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached",
186 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent
);
188 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached",
189 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent
);
192 #endif // wxUSE_TOOLBAR
196 // These are inside the client area
197 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
198 GTK_WIDGET(child
->m_widget
),
205 // Resize on OnInternalIdle
206 parent
->GtkUpdateSize();
209 // ----------------------------------------------------------------------------
211 // ----------------------------------------------------------------------------
215 m_menuBarDetached
= false;
216 m_toolBarDetached
= false;
220 bool wxFrame::Create( wxWindow
*parent
,
222 const wxString
& title
,
224 const wxSize
& sizeOrig
,
226 const wxString
&name
)
228 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
230 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
237 m_isBeingDeleted
= true;
241 // ----------------------------------------------------------------------------
242 // overridden wxWindow methods
243 // ----------------------------------------------------------------------------
245 void wxFrame::DoGetClientSize( int *width
, int *height
) const
247 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
249 wxTopLevelWindow::DoGetClientSize( width
, height
);
253 #if wxUSE_MENUS_NATIVE
257 if (!m_menuBarDetached
)
258 (*height
) -= m_menuBarHeight
;
260 (*height
) -= wxPLACE_HOLDER
;
262 #endif // wxUSE_MENUS_NATIVE
266 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
267 (*height
) -= wxSTATUS_HEIGHT
;
268 #endif // wxUSE_STATUSBAR
272 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
274 if (m_toolBarDetached
)
276 *height
-= wxPLACE_HOLDER
;
281 m_frameToolBar
->GetSize( &x
, &y
);
282 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
292 #endif // wxUSE_TOOLBAR
296 void wxFrame::DoSetClientSize( int width
, int height
)
298 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
300 #if wxUSE_MENUS_NATIVE
304 if (!m_menuBarDetached
)
305 height
+= m_menuBarHeight
;
307 height
+= wxPLACE_HOLDER
;
309 #endif // wxUSE_MENUS_NATIVE
313 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
318 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
320 if (m_toolBarDetached
)
322 height
+= wxPLACE_HOLDER
;
327 m_frameToolBar
->GetSize( &x
, &y
);
328 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
340 wxTopLevelWindow::DoSetClientSize( width
, height
);
343 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
344 int width
, int height
)
346 // due to a bug in gtk, x,y are always 0
351 if (m_resizing
) return;
354 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
355 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
360 // space occupied by m_frameToolBar and m_frameMenuBar
361 int client_area_x_offset
= 0,
362 client_area_y_offset
= 0;
364 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
365 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
366 set in wxFrame::Create so it is used to check what kind of frame we
367 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
368 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
369 importantly) m_mainWidget */
371 int minWidth
= GetMinWidth(),
372 minHeight
= GetMinHeight(),
373 maxWidth
= GetMaxWidth(),
374 maxHeight
= GetMaxHeight();
376 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
377 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
378 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
379 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
384 gint flag
= 0; // GDK_HINT_POS;
385 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
386 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
388 geom
.min_width
= minWidth
;
389 geom
.min_height
= minHeight
;
390 geom
.max_width
= maxWidth
;
391 geom
.max_height
= maxHeight
;
392 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
395 (GdkWindowHints
) flag
);
397 // I revert back to wxGTK's original behaviour. m_mainWidget holds
398 // the menubar, the toolbar and the client area, which is represented
400 // This hurts in the eye, but I don't want to call SetSize()
401 // because I don't want to call any non-native functions here.
403 #if wxUSE_MENUS_NATIVE
407 int yy
= m_miniEdge
+ m_miniTitle
;
408 int ww
= m_width
- 2*m_miniEdge
;
409 int hh
= m_menuBarHeight
;
410 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
411 m_frameMenuBar
->m_x
= xx
;
412 m_frameMenuBar
->m_y
= yy
;
413 m_frameMenuBar
->m_width
= ww
;
414 m_frameMenuBar
->m_height
= hh
;
415 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
416 m_frameMenuBar
->m_widget
,
418 client_area_y_offset
+= hh
;
420 #endif // wxUSE_MENUS_NATIVE
423 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
424 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
427 int yy
= m_miniEdge
+ m_miniTitle
;
428 #if wxUSE_MENUS_NATIVE
431 if (!m_menuBarDetached
)
432 yy
+= m_menuBarHeight
;
434 yy
+= wxPLACE_HOLDER
;
436 #endif // wxUSE_MENUS_NATIVE
438 m_frameToolBar
->m_x
= xx
;
439 m_frameToolBar
->m_y
= yy
;
441 // don't change the toolbar's reported height/width
443 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
445 ww
= m_toolBarDetached
? wxPLACE_HOLDER
446 : m_frameToolBar
->m_width
;
447 hh
= m_height
- 2*m_miniEdge
;
449 client_area_x_offset
+= ww
;
453 ww
= m_width
- 2*m_miniEdge
;
454 hh
= m_toolBarDetached
? wxPLACE_HOLDER
455 : m_frameToolBar
->m_height
;
457 client_area_y_offset
+= hh
;
460 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
461 m_frameToolBar
->m_widget
,
464 #endif // wxUSE_TOOLBAR
466 int client_x
= client_area_x_offset
+ m_miniEdge
;
467 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
468 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
469 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
470 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
472 client_x
, client_y
, client_w
, client_h
);
476 // If there is no m_mainWidget between m_widget and m_wxwindow there
477 // is no need to set the size or position of m_wxwindow.
481 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
483 int xx
= 0 + m_miniEdge
;
484 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
485 int ww
= m_width
- 2*m_miniEdge
;
486 int hh
= wxSTATUS_HEIGHT
;
487 m_frameStatusBar
->m_x
= xx
;
488 m_frameStatusBar
->m_y
= yy
;
489 m_frameStatusBar
->m_width
= ww
;
490 m_frameStatusBar
->m_height
= hh
;
491 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
492 m_frameStatusBar
->m_widget
,
494 gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL
);
496 #endif // wxUSE_STATUSBAR
500 // send size event to frame
501 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
502 event
.SetEventObject( this );
503 GetEventHandler()->ProcessEvent( event
);
506 // send size event to status bar
507 if (m_frameStatusBar
)
509 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
510 event2
.SetEventObject( m_frameStatusBar
);
511 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
513 #endif // wxUSE_STATUSBAR
518 void wxFrame::OnInternalIdle()
520 wxFrameBase::OnInternalIdle();
522 #if wxUSE_MENUS_NATIVE
523 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
524 #endif // wxUSE_MENUS_NATIVE
526 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
529 if (m_frameStatusBar
)
531 m_frameStatusBar
->OnInternalIdle();
533 // There may be controls in the status bar that
534 // need to be updated
535 for ( wxWindowList::compatibility_iterator node
= m_frameStatusBar
->GetChildren().GetFirst();
537 node
= node
->GetNext() )
539 wxWindow
*child
= node
->GetData();
540 child
->OnInternalIdle();
546 // ----------------------------------------------------------------------------
547 // menu/tool/status bar stuff
548 // ----------------------------------------------------------------------------
550 #if wxUSE_MENUS_NATIVE
552 void wxFrame::DetachMenuBar()
554 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
555 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
557 if ( m_frameMenuBar
)
559 m_frameMenuBar
->UnsetInvokingWindow( this );
561 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
563 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
564 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
566 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
567 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
570 gtk_widget_ref( m_frameMenuBar
->m_widget
);
572 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
575 wxFrameBase::DetachMenuBar();
578 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
580 wxFrameBase::AttachMenuBar(menuBar
);
584 m_frameMenuBar
->SetInvokingWindow( this );
586 m_frameMenuBar
->SetParent(this);
587 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
588 m_frameMenuBar
->m_widget
,
591 m_frameMenuBar
->m_width
,
592 m_frameMenuBar
->m_height
);
594 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
596 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached",
597 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
599 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached",
600 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
603 gtk_widget_show( m_frameMenuBar
->m_widget
);
610 GtkUpdateSize(); // resize window in OnInternalIdle
614 void wxFrame::UpdateMenuBarSize()
621 // this is called after Remove with a NULL m_frameMenuBar
622 if ( m_frameMenuBar
)
623 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request
)
624 (m_frameMenuBar
->m_widget
, &req
);
626 m_menuBarHeight
= req
.height
;
628 // resize window in OnInternalIdle
633 #endif // wxUSE_MENUS_NATIVE
637 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
639 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
641 m_insertInClientArea
= false;
643 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
645 m_insertInClientArea
= true;
649 return m_frameToolBar
;
652 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
654 bool hadTbar
= m_frameToolBar
!= NULL
;
656 wxFrameBase::SetToolBar(toolbar
);
658 if ( m_frameToolBar
)
660 // insert into toolbar area if not already there
661 if ((m_frameToolBar
->m_widget
->parent
) &&
662 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
664 GetChildren().DeleteObject( m_frameToolBar
);
666 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
670 else // toolbar unset
672 // still need to update size if it had been there before
680 #endif // wxUSE_TOOLBAR
684 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
687 const wxString
& name
)
689 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
691 // because it will change when toolbar is added
694 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
697 void wxFrame::SetStatusBar(wxStatusBar
*statbar
)
699 bool hadStatBar
= m_frameStatusBar
!= NULL
;
701 wxFrameBase::SetStatusBar(statbar
);
703 if (hadStatBar
&& !m_frameStatusBar
)
707 void wxFrame::PositionStatusBar()
709 if ( !m_frameStatusBar
)
714 #endif // wxUSE_STATUSBAR