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"
29 #include "wx/toolbar.h"
30 #include "wx/statusbr.h"
34 #include "wx/gtk1/private.h"
36 #include <gdk/gdkkeysyms.h>
39 #include "wx/gtk1/win_gtk.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 const int wxSTATUS_HEIGHT
= 25;
46 const int wxPLACE_HOLDER
= 0;
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 extern void wxapp_install_idle_handler();
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
)
61 // ============================================================================
63 // ============================================================================
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 #if wxUSE_MENUS_NATIVE
71 //-----------------------------------------------------------------------------
72 // "child_attached" of menu bar
73 //-----------------------------------------------------------------------------
76 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
78 if (!win
->m_hasVMT
) return;
80 win
->m_menuBarDetached
= false;
85 //-----------------------------------------------------------------------------
86 // "child_detached" of menu bar
87 //-----------------------------------------------------------------------------
90 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
93 wxapp_install_idle_handler();
95 if (!win
->m_hasVMT
) return;
97 // Raise the client area area
98 gdk_window_raise( win
->m_wxwindow
->window
);
100 win
->m_menuBarDetached
= true;
101 win
->GtkUpdateSize();
105 #endif // wxUSE_MENUS_NATIVE
108 //-----------------------------------------------------------------------------
109 // "child_attached" of tool bar
110 //-----------------------------------------------------------------------------
113 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
115 if (!win
->m_hasVMT
) return;
117 win
->m_toolBarDetached
= false;
118 win
->GtkUpdateSize();
122 //-----------------------------------------------------------------------------
123 // "child_detached" of tool bar
124 //-----------------------------------------------------------------------------
127 static void gtk_toolbar_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
130 wxapp_install_idle_handler();
132 if (!win
->m_hasVMT
) return;
134 // Raise the client area area
135 gdk_window_raise( win
->m_wxwindow
->window
);
137 win
->m_toolBarDetached
= true;
138 win
->GtkUpdateSize();
141 #endif // wxUSE_TOOLBAR
144 // ----------------------------------------------------------------------------
146 // ----------------------------------------------------------------------------
148 //-----------------------------------------------------------------------------
149 // InsertChild for wxFrame
150 //-----------------------------------------------------------------------------
152 /* Callback for wxFrame. This very strange beast has to be used because
153 * C++ has no virtual methods in a constructor. We have to emulate a
154 * virtual function here as wxWidgets requires different ways to insert
155 * a child in container classes. */
157 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
159 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
161 if (!parent
->m_insertInClientArea
)
163 // These are outside the client area
164 wxFrame
* frame
= (wxFrame
*) parent
;
165 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
166 GTK_WIDGET(child
->m_widget
),
172 #if wxUSE_TOOLBAR_NATIVE
173 // We connect to these events for recalculating the client area
174 // space when the toolbar is floating
175 if (wxIS_KIND_OF(child
,wxToolBar
))
177 wxToolBar
*toolBar
= (wxToolBar
*) child
;
178 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
180 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached",
181 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent
);
183 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached",
184 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent
);
187 #endif // wxUSE_TOOLBAR
191 // These are inside the client area
192 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
193 GTK_WIDGET(child
->m_widget
),
200 // Resize on OnInternalIdle
201 parent
->GtkUpdateSize();
204 // ----------------------------------------------------------------------------
206 // ----------------------------------------------------------------------------
210 m_menuBarDetached
= false;
211 m_toolBarDetached
= false;
215 bool wxFrame::Create( wxWindow
*parent
,
217 const wxString
& title
,
219 const wxSize
& sizeOrig
,
221 const wxString
&name
)
223 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
225 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
237 // ----------------------------------------------------------------------------
238 // overridden wxWindow methods
239 // ----------------------------------------------------------------------------
241 void wxFrame::DoGetClientSize( int *width
, int *height
) const
243 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
245 wxTopLevelWindow::DoGetClientSize( width
, height
);
249 #if wxUSE_MENUS_NATIVE
253 if (!m_menuBarDetached
)
254 (*height
) -= m_menuBarHeight
;
256 (*height
) -= wxPLACE_HOLDER
;
258 #endif // wxUSE_MENUS_NATIVE
262 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
263 (*height
) -= wxSTATUS_HEIGHT
;
264 #endif // wxUSE_STATUSBAR
268 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
270 if (m_toolBarDetached
)
272 *height
-= wxPLACE_HOLDER
;
277 m_frameToolBar
->GetSize( &x
, &y
);
278 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
288 #endif // wxUSE_TOOLBAR
292 void wxFrame::DoSetClientSize( int width
, int height
)
294 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
296 #if wxUSE_MENUS_NATIVE
300 if (!m_menuBarDetached
)
301 height
+= m_menuBarHeight
;
303 height
+= wxPLACE_HOLDER
;
305 #endif // wxUSE_MENUS_NATIVE
309 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
314 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
316 if (m_toolBarDetached
)
318 height
+= wxPLACE_HOLDER
;
323 m_frameToolBar
->GetSize( &x
, &y
);
324 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
336 wxTopLevelWindow::DoSetClientSize( width
, height
);
339 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
340 int width
, int height
)
342 // due to a bug in gtk, x,y are always 0
347 if (m_resizing
) return;
350 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
351 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
356 // space occupied by m_frameToolBar and m_frameMenuBar
357 int client_area_x_offset
= 0,
358 client_area_y_offset
= 0;
360 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
361 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
362 set in wxFrame::Create so it is used to check what kind of frame we
363 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
364 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
365 importantly) m_mainWidget */
367 int minWidth
= GetMinWidth(),
368 minHeight
= GetMinHeight(),
369 maxWidth
= GetMaxWidth(),
370 maxHeight
= GetMaxHeight();
372 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
373 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
374 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
375 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
380 gint flag
= 0; // GDK_HINT_POS;
381 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
382 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
384 geom
.min_width
= minWidth
;
385 geom
.min_height
= minHeight
;
386 geom
.max_width
= maxWidth
;
387 geom
.max_height
= maxHeight
;
388 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
391 (GdkWindowHints
) flag
);
393 // I revert back to wxGTK's original behaviour. m_mainWidget holds
394 // the menubar, the toolbar and the client area, which is represented
396 // This hurts in the eye, but I don't want to call SetSize()
397 // because I don't want to call any non-native functions here.
399 #if wxUSE_MENUS_NATIVE
403 int yy
= m_miniEdge
+ m_miniTitle
;
404 int ww
= m_width
- 2*m_miniEdge
;
405 int hh
= m_menuBarHeight
;
406 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
407 m_frameMenuBar
->m_x
= xx
;
408 m_frameMenuBar
->m_y
= yy
;
409 m_frameMenuBar
->m_width
= ww
;
410 m_frameMenuBar
->m_height
= hh
;
411 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
412 m_frameMenuBar
->m_widget
,
414 client_area_y_offset
+= hh
;
416 #endif // wxUSE_MENUS_NATIVE
419 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
420 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
423 int yy
= m_miniEdge
+ m_miniTitle
;
424 #if wxUSE_MENUS_NATIVE
427 if (!m_menuBarDetached
)
428 yy
+= m_menuBarHeight
;
430 yy
+= wxPLACE_HOLDER
;
432 #endif // wxUSE_MENUS_NATIVE
434 m_frameToolBar
->m_x
= xx
;
435 m_frameToolBar
->m_y
= yy
;
437 // don't change the toolbar's reported height/width
439 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
441 ww
= m_toolBarDetached
? wxPLACE_HOLDER
442 : m_frameToolBar
->m_width
;
443 hh
= m_height
- 2*m_miniEdge
;
445 client_area_x_offset
+= ww
;
449 ww
= m_width
- 2*m_miniEdge
;
450 hh
= m_toolBarDetached
? wxPLACE_HOLDER
451 : m_frameToolBar
->m_height
;
453 client_area_y_offset
+= hh
;
456 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
457 m_frameToolBar
->m_widget
,
460 #endif // wxUSE_TOOLBAR
462 int client_x
= client_area_x_offset
+ m_miniEdge
;
463 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
464 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
465 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
466 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
468 client_x
, client_y
, client_w
, client_h
);
472 // If there is no m_mainWidget between m_widget and m_wxwindow there
473 // is no need to set the size or position of m_wxwindow.
477 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
479 int xx
= 0 + m_miniEdge
;
480 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
481 int ww
= m_width
- 2*m_miniEdge
;
482 int hh
= wxSTATUS_HEIGHT
;
483 m_frameStatusBar
->m_x
= xx
;
484 m_frameStatusBar
->m_y
= yy
;
485 m_frameStatusBar
->m_width
= ww
;
486 m_frameStatusBar
->m_height
= hh
;
487 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
488 m_frameStatusBar
->m_widget
,
490 gtk_widget_draw( m_frameStatusBar
->m_widget
, NULL
);
492 #endif // wxUSE_STATUSBAR
496 // send size event to frame
497 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
498 event
.SetEventObject( this );
499 HandleWindowEvent( event
);
502 // send size event to status bar
503 if (m_frameStatusBar
)
505 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
506 event2
.SetEventObject( m_frameStatusBar
);
507 m_frameStatusBar
->HandleWindowEvent( event2
);
509 #endif // wxUSE_STATUSBAR
514 void wxFrame::OnInternalIdle()
516 wxFrameBase::OnInternalIdle();
518 #if wxUSE_MENUS_NATIVE
519 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
520 #endif // wxUSE_MENUS_NATIVE
522 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
525 if (m_frameStatusBar
)
527 m_frameStatusBar
->OnInternalIdle();
529 // There may be controls in the status bar that
530 // need to be updated
531 for ( wxWindowList::compatibility_iterator node
= m_frameStatusBar
->GetChildren().GetFirst();
533 node
= node
->GetNext() )
535 wxWindow
*child
= node
->GetData();
536 child
->OnInternalIdle();
542 // ----------------------------------------------------------------------------
543 // menu/tool/status bar stuff
544 // ----------------------------------------------------------------------------
546 #if wxUSE_MENUS_NATIVE
548 void wxFrame::DetachMenuBar()
550 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
551 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
553 if ( m_frameMenuBar
)
555 m_frameMenuBar
->UnsetInvokingWindow( this );
557 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
559 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
560 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
562 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
563 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
566 gtk_widget_ref( m_frameMenuBar
->m_widget
);
568 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
571 wxFrameBase::DetachMenuBar();
574 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
576 wxFrameBase::AttachMenuBar(menuBar
);
580 m_frameMenuBar
->SetInvokingWindow( this );
582 m_frameMenuBar
->SetParent(this);
583 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
584 m_frameMenuBar
->m_widget
,
587 m_frameMenuBar
->m_width
,
588 m_frameMenuBar
->m_height
);
590 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
592 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached",
593 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
595 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached",
596 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
599 gtk_widget_show( m_frameMenuBar
->m_widget
);
606 GtkUpdateSize(); // resize window in OnInternalIdle
610 void wxFrame::UpdateMenuBarSize()
617 // this is called after Remove with a NULL m_frameMenuBar
618 if ( m_frameMenuBar
)
619 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request
)
620 (m_frameMenuBar
->m_widget
, &req
);
622 m_menuBarHeight
= req
.height
;
624 // resize window in OnInternalIdle
629 #endif // wxUSE_MENUS_NATIVE
633 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
635 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
637 m_insertInClientArea
= false;
639 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
641 m_insertInClientArea
= true;
645 return m_frameToolBar
;
648 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
650 bool hadTbar
= m_frameToolBar
!= NULL
;
652 wxFrameBase::SetToolBar(toolbar
);
654 if ( m_frameToolBar
)
656 // insert into toolbar area if not already there
657 if ((m_frameToolBar
->m_widget
->parent
) &&
658 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
660 GetChildren().DeleteObject( m_frameToolBar
);
662 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
666 else // toolbar unset
668 // still need to update size if it had been there before
676 #endif // wxUSE_TOOLBAR
680 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
683 const wxString
& name
)
685 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
687 // because it will change when toolbar is added
690 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
693 void wxFrame::SetStatusBar(wxStatusBar
*statbar
)
695 bool hadStatBar
= m_frameStatusBar
!= NULL
;
697 wxFrameBase::SetStatusBar(statbar
);
699 if (hadStatBar
&& !m_frameStatusBar
)
703 void wxFrame::PositionStatusBar()
705 if ( !m_frameStatusBar
)
710 #endif // wxUSE_STATUSBAR