1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
19 #pragma implementation "frame.h"
22 // For compilers that support precompilation, includes "wx.h".
23 #include "wx/wxprec.h"
28 #include "wx/dialog.h"
29 #include "wx/control.h"
33 #include "wx/toolbar.h"
36 #include "wx/statusbr.h"
38 #include "wx/dcclient.h"
41 #include "wx/gtk/private.h"
43 #include <gdk/gdkkeysyms.h>
46 #include "wx/gtk/win_gtk.h"
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 const int wxSTATUS_HEIGHT
= 25;
53 const int wxPLACE_HOLDER
= 0;
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 extern void wxapp_install_idle_handler();
61 extern int g_openDialogs
;
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
)
69 // ============================================================================
71 // ============================================================================
73 // ----------------------------------------------------------------------------
75 // ----------------------------------------------------------------------------
77 #if wxUSE_MENUS_NATIVE
79 //-----------------------------------------------------------------------------
80 // "child_attached" of menu bar
81 //-----------------------------------------------------------------------------
84 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
86 if (!win
->m_hasVMT
) return;
88 win
->m_menuBarDetached
= FALSE
;
93 //-----------------------------------------------------------------------------
94 // "child_detached" of menu bar
95 //-----------------------------------------------------------------------------
98 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
101 wxapp_install_idle_handler();
103 if (!win
->m_hasVMT
) return;
105 // Raise the client area area
106 gdk_window_raise( win
->m_wxwindow
->window
);
108 win
->m_menuBarDetached
= TRUE
;
109 win
->GtkUpdateSize();
113 #endif // wxUSE_MENUS_NATIVE
116 //-----------------------------------------------------------------------------
117 // "child_attached" of tool bar
118 //-----------------------------------------------------------------------------
121 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
123 if (!win
->m_hasVMT
) return;
125 win
->m_toolBarDetached
= FALSE
;
126 win
->GtkUpdateSize();
130 //-----------------------------------------------------------------------------
131 // "child_detached" of tool bar
132 //-----------------------------------------------------------------------------
135 static void gtk_toolbar_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
138 wxapp_install_idle_handler();
140 if (!win
->m_hasVMT
) return;
142 // Raise the client area area
143 gdk_window_raise( win
->m_wxwindow
->window
);
145 win
->m_toolBarDetached
= TRUE
;
146 win
->GtkUpdateSize();
149 #endif // wxUSE_TOOLBAR
152 // ----------------------------------------------------------------------------
154 // ----------------------------------------------------------------------------
156 //-----------------------------------------------------------------------------
157 // InsertChild for wxFrame
158 //-----------------------------------------------------------------------------
160 /* Callback for wxFrame. This very strange beast has to be used because
161 * C++ has no virtual methods in a constructor. We have to emulate a
162 * virtual function here as wxWidgets requires different ways to insert
163 * a child in container classes. */
165 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
167 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
169 if (!parent
->m_insertInClientArea
)
171 // These are outside the client area
172 wxFrame
* frame
= (wxFrame
*) parent
;
173 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
174 GTK_WIDGET(child
->m_widget
),
180 #if wxUSE_TOOLBAR_NATIVE
181 // We connect to these events for recalculating the client area
182 // space when the toolbar is floating
183 if (wxIS_KIND_OF(child
,wxToolBar
))
185 wxToolBar
*toolBar
= (wxToolBar
*) child
;
186 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
188 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached",
189 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent
);
191 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached",
192 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent
);
195 #endif // wxUSE_TOOLBAR
199 // These are inside the client area
200 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
201 GTK_WIDGET(child
->m_widget
),
208 // Resize on OnInternalIdle
209 parent
->GtkUpdateSize();
212 // ----------------------------------------------------------------------------
214 // ----------------------------------------------------------------------------
218 m_menuBarDetached
= FALSE
;
219 m_toolBarDetached
= FALSE
;
223 bool wxFrame::Create( wxWindow
*parent
,
225 const wxString
& title
,
227 const wxSize
& sizeOrig
,
229 const wxString
&name
)
231 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
233 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
240 m_isBeingDeleted
= TRUE
;
244 // ----------------------------------------------------------------------------
245 // overridden wxWindow methods
246 // ----------------------------------------------------------------------------
248 void wxFrame::DoGetClientSize( int *width
, int *height
) const
250 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
252 wxTopLevelWindow::DoGetClientSize( width
, height
);
256 #if wxUSE_MENUS_NATIVE
260 if (!m_menuBarDetached
)
261 (*height
) -= m_menuBarHeight
;
263 (*height
) -= wxPLACE_HOLDER
;
265 #endif // wxUSE_MENUS_NATIVE
269 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
270 (*height
) -= wxSTATUS_HEIGHT
;
271 #endif // wxUSE_STATUSBAR
275 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
277 if (m_toolBarDetached
)
279 *height
-= wxPLACE_HOLDER
;
284 m_frameToolBar
->GetSize( &x
, &y
);
285 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
295 #endif // wxUSE_TOOLBAR
299 void wxFrame::DoSetClientSize( int width
, int height
)
301 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
303 #if wxUSE_MENUS_NATIVE
307 if (!m_menuBarDetached
)
308 height
+= m_menuBarHeight
;
310 height
+= wxPLACE_HOLDER
;
312 #endif // wxUSE_MENUS_NATIVE
316 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
321 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
323 if (m_toolBarDetached
)
325 height
+= wxPLACE_HOLDER
;
330 m_frameToolBar
->GetSize( &x
, &y
);
331 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
343 wxTopLevelWindow::DoSetClientSize( width
, height
);
346 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
347 int width
, int height
)
349 // due to a bug in gtk, x,y are always 0
354 if (m_resizing
) return;
357 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
358 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
363 // space occupied by m_frameToolBar and m_frameMenuBar
364 int client_area_x_offset
= 0,
365 client_area_y_offset
= 0;
367 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
368 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
369 set in wxFrame::Create so it is used to check what kind of frame we
370 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
371 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
372 importantly) m_mainWidget */
374 int minWidth
= GetMinWidth(),
375 minHeight
= GetMinHeight(),
376 maxWidth
= GetMaxWidth(),
377 maxHeight
= GetMaxHeight();
379 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
380 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
381 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
382 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
387 gint flag
= 0; // GDK_HINT_POS;
388 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
389 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
391 geom
.min_width
= minWidth
;
392 geom
.min_height
= minHeight
;
393 geom
.max_width
= maxWidth
;
394 geom
.max_height
= maxHeight
;
395 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
398 (GdkWindowHints
) flag
);
400 // I revert back to wxGTK's original behaviour. m_mainWidget holds
401 // the menubar, the toolbar and the client area, which is represented
403 // This hurts in the eye, but I don't want to call SetSize()
404 // because I don't want to call any non-native functions here.
406 #if wxUSE_MENUS_NATIVE
410 int yy
= m_miniEdge
+ m_miniTitle
;
411 int ww
= m_width
- 2*m_miniEdge
;
412 int hh
= m_menuBarHeight
;
413 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
414 m_frameMenuBar
->m_x
= xx
;
415 m_frameMenuBar
->m_y
= yy
;
416 m_frameMenuBar
->m_width
= ww
;
417 m_frameMenuBar
->m_height
= hh
;
418 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
419 m_frameMenuBar
->m_widget
,
421 client_area_y_offset
+= hh
;
423 #endif // wxUSE_MENUS_NATIVE
426 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
427 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
430 int yy
= m_miniEdge
+ m_miniTitle
;
431 #if wxUSE_MENUS_NATIVE
434 if (!m_menuBarDetached
)
435 yy
+= m_menuBarHeight
;
437 yy
+= wxPLACE_HOLDER
;
439 #endif // wxUSE_MENUS_NATIVE
441 m_frameToolBar
->m_x
= xx
;
442 m_frameToolBar
->m_y
= yy
;
444 // don't change the toolbar's reported height/width
446 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
448 ww
= m_toolBarDetached
? wxPLACE_HOLDER
449 : m_frameToolBar
->m_width
;
450 hh
= m_height
- 2*m_miniEdge
;
452 client_area_x_offset
+= ww
;
456 ww
= m_width
- 2*m_miniEdge
;
457 hh
= m_toolBarDetached
? wxPLACE_HOLDER
458 : m_frameToolBar
->m_height
;
460 client_area_y_offset
+= hh
;
463 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
464 m_frameToolBar
->m_widget
,
467 #endif // wxUSE_TOOLBAR
469 int client_x
= client_area_x_offset
+ m_miniEdge
;
470 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
471 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
472 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
473 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
475 client_x
, client_y
, client_w
, client_h
);
479 // If there is no m_mainWidget between m_widget and m_wxwindow there
480 // is no need to set the size or position of m_wxwindow.
484 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
486 int xx
= 0 + m_miniEdge
;
487 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
488 int ww
= m_width
- 2*m_miniEdge
;
489 int hh
= wxSTATUS_HEIGHT
;
490 m_frameStatusBar
->m_x
= xx
;
491 m_frameStatusBar
->m_y
= yy
;
492 m_frameStatusBar
->m_width
= ww
;
493 m_frameStatusBar
->m_height
= hh
;
494 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
495 m_frameStatusBar
->m_widget
,
497 gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL
);
499 #endif // wxUSE_STATUSBAR
503 // send size event to frame
504 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
505 event
.SetEventObject( this );
506 GetEventHandler()->ProcessEvent( event
);
509 // send size event to status bar
510 if (m_frameStatusBar
)
512 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
513 event2
.SetEventObject( m_frameStatusBar
);
514 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
516 #endif // wxUSE_STATUSBAR
521 void wxFrame::OnInternalIdle()
523 wxFrameBase::OnInternalIdle();
525 #if wxUSE_MENUS_NATIVE
526 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
527 #endif // wxUSE_MENUS_NATIVE
529 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
532 if (m_frameStatusBar
)
534 m_frameStatusBar
->OnInternalIdle();
536 // There may be controls in the status bar that
537 // need to be updated
538 for ( wxWindowList::compatibility_iterator node
= m_frameStatusBar
->GetChildren().GetFirst();
540 node
= node
->GetNext() )
542 wxWindow
*child
= node
->GetData();
543 child
->OnInternalIdle();
549 // ----------------------------------------------------------------------------
550 // menu/tool/status bar stuff
551 // ----------------------------------------------------------------------------
553 #if wxUSE_MENUS_NATIVE
555 void wxFrame::DetachMenuBar()
557 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
558 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
560 if ( m_frameMenuBar
)
562 m_frameMenuBar
->UnsetInvokingWindow( this );
564 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
566 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
567 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
569 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
570 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
573 gtk_widget_ref( m_frameMenuBar
->m_widget
);
575 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
578 wxFrameBase::DetachMenuBar();
581 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
583 wxFrameBase::AttachMenuBar(menuBar
);
587 m_frameMenuBar
->SetInvokingWindow( this );
589 m_frameMenuBar
->SetParent(this);
590 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
591 m_frameMenuBar
->m_widget
,
594 m_frameMenuBar
->m_width
,
595 m_frameMenuBar
->m_height
);
597 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
599 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached",
600 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
602 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached",
603 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
606 gtk_widget_show( m_frameMenuBar
->m_widget
);
613 GtkUpdateSize(); // resize window in OnInternalIdle
617 void wxFrame::UpdateMenuBarSize()
624 // this is called after Remove with a NULL m_frameMenuBar
625 if ( m_frameMenuBar
)
626 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request
)
627 (m_frameMenuBar
->m_widget
, &req
);
629 m_menuBarHeight
= req
.height
;
631 // resize window in OnInternalIdle
636 #endif // wxUSE_MENUS_NATIVE
640 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
642 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
644 m_insertInClientArea
= FALSE
;
646 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
648 m_insertInClientArea
= TRUE
;
652 return m_frameToolBar
;
655 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
657 bool hadTbar
= m_frameToolBar
!= NULL
;
659 wxFrameBase::SetToolBar(toolbar
);
661 if ( m_frameToolBar
)
663 // insert into toolbar area if not already there
664 if ((m_frameToolBar
->m_widget
->parent
) &&
665 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
667 GetChildren().DeleteObject( m_frameToolBar
);
669 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
673 else // toolbar unset
675 // still need to update size if it had been there before
683 #endif // wxUSE_TOOLBAR
687 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
690 const wxString
& name
)
692 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
694 // because it will change when toolbar is added
697 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
700 void wxFrame::SetStatusBar(wxStatusBar
*statbar
)
702 bool hadStatBar
= m_frameStatusBar
!= NULL
;
704 wxFrameBase::SetStatusBar(statbar
);
706 if (hadStatBar
&& !m_frameStatusBar
)
710 void wxFrame::PositionStatusBar()
712 if ( !m_frameStatusBar
)
717 #endif // wxUSE_STATUSBAR