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();
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxTopLevelWindow
)
68 // ============================================================================
70 // ============================================================================
72 // ----------------------------------------------------------------------------
74 // ----------------------------------------------------------------------------
76 #if wxUSE_MENUS_NATIVE
78 //-----------------------------------------------------------------------------
79 // "child_attached" of menu bar
80 //-----------------------------------------------------------------------------
83 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
85 if (!win
->m_hasVMT
) return;
87 win
->m_menuBarDetached
= false;
92 //-----------------------------------------------------------------------------
93 // "child_detached" of menu bar
94 //-----------------------------------------------------------------------------
97 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
100 wxapp_install_idle_handler();
102 if (!win
->m_hasVMT
) return;
104 // Raise the client area area
105 gdk_window_raise( win
->m_wxwindow
->window
);
107 win
->m_menuBarDetached
= true;
108 win
->GtkUpdateSize();
112 #endif // wxUSE_MENUS_NATIVE
115 //-----------------------------------------------------------------------------
116 // "child_attached" of tool bar
117 //-----------------------------------------------------------------------------
120 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
122 if (!win
->m_hasVMT
) return;
124 win
->m_toolBarDetached
= false;
125 win
->GtkUpdateSize();
129 //-----------------------------------------------------------------------------
130 // "child_detached" of tool bar
131 //-----------------------------------------------------------------------------
134 static void gtk_toolbar_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
137 wxapp_install_idle_handler();
139 if (!win
->m_hasVMT
) return;
141 // Raise the client area area
142 gdk_window_raise( win
->m_wxwindow
->window
);
144 win
->m_toolBarDetached
= true;
145 win
->GtkUpdateSize();
148 #endif // wxUSE_TOOLBAR
151 // ----------------------------------------------------------------------------
153 // ----------------------------------------------------------------------------
155 //-----------------------------------------------------------------------------
156 // InsertChild for wxFrame
157 //-----------------------------------------------------------------------------
159 /* Callback for wxFrame. This very strange beast has to be used because
160 * C++ has no virtual methods in a constructor. We have to emulate a
161 * virtual function here as wxWidgets requires different ways to insert
162 * a child in container classes. */
164 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
166 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
168 if (!parent
->m_insertInClientArea
)
170 // These are outside the client area
171 wxFrame
* frame
= (wxFrame
*) parent
;
172 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
173 GTK_WIDGET(child
->m_widget
),
179 #if wxUSE_TOOLBAR_NATIVE
180 // We connect to these events for recalculating the client area
181 // space when the toolbar is floating
182 if (wxIS_KIND_OF(child
,wxToolBar
))
184 wxToolBar
*toolBar
= (wxToolBar
*) child
;
185 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
187 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached",
188 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent
);
190 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached",
191 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent
);
194 #endif // wxUSE_TOOLBAR
198 // These are inside the client area
199 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
200 GTK_WIDGET(child
->m_widget
),
207 // Resize on OnInternalIdle
208 parent
->GtkUpdateSize();
211 // ----------------------------------------------------------------------------
213 // ----------------------------------------------------------------------------
217 m_menuBarDetached
= false;
218 m_toolBarDetached
= false;
222 bool wxFrame::Create( wxWindow
*parent
,
224 const wxString
& title
,
226 const wxSize
& sizeOrig
,
228 const wxString
&name
)
230 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
232 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
239 m_isBeingDeleted
= true;
243 // ----------------------------------------------------------------------------
244 // overridden wxWindow methods
245 // ----------------------------------------------------------------------------
247 void wxFrame::DoGetClientSize( int *width
, int *height
) const
249 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
251 wxTopLevelWindow::DoGetClientSize( width
, height
);
255 #if wxUSE_MENUS_NATIVE
259 if (!m_menuBarDetached
)
260 (*height
) -= m_menuBarHeight
;
262 (*height
) -= wxPLACE_HOLDER
;
264 #endif // wxUSE_MENUS_NATIVE
268 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
269 (*height
) -= wxSTATUS_HEIGHT
;
270 #endif // wxUSE_STATUSBAR
274 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
276 if (m_toolBarDetached
)
278 *height
-= wxPLACE_HOLDER
;
283 m_frameToolBar
->GetSize( &x
, &y
);
284 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
294 #endif // wxUSE_TOOLBAR
298 void wxFrame::DoSetClientSize( int width
, int height
)
300 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
302 #if wxUSE_MENUS_NATIVE
306 if (!m_menuBarDetached
)
307 height
+= m_menuBarHeight
;
309 height
+= wxPLACE_HOLDER
;
311 #endif // wxUSE_MENUS_NATIVE
315 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
320 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
322 if (m_toolBarDetached
)
324 height
+= wxPLACE_HOLDER
;
329 m_frameToolBar
->GetSize( &x
, &y
);
330 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
342 wxTopLevelWindow::DoSetClientSize( width
, height
);
345 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
346 int width
, int height
)
348 // due to a bug in gtk, x,y are always 0
353 if (m_resizing
) return;
356 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
357 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
362 // space occupied by m_frameToolBar and m_frameMenuBar
363 int client_area_x_offset
= 0,
364 client_area_y_offset
= 0;
366 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
367 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
368 set in wxFrame::Create so it is used to check what kind of frame we
369 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
370 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
371 importantly) m_mainWidget */
373 int minWidth
= GetMinWidth(),
374 minHeight
= GetMinHeight(),
375 maxWidth
= GetMaxWidth(),
376 maxHeight
= GetMaxHeight();
378 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
379 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
380 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
381 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
386 gint flag
= 0; // GDK_HINT_POS;
387 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
388 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
390 geom
.min_width
= minWidth
;
391 geom
.min_height
= minHeight
;
392 geom
.max_width
= maxWidth
;
393 geom
.max_height
= maxHeight
;
394 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
397 (GdkWindowHints
) flag
);
399 // I revert back to wxGTK's original behaviour. m_mainWidget holds
400 // the menubar, the toolbar and the client area, which is represented
402 // This hurts in the eye, but I don't want to call SetSize()
403 // because I don't want to call any non-native functions here.
405 #if wxUSE_MENUS_NATIVE
409 int yy
= m_miniEdge
+ m_miniTitle
;
410 int ww
= m_width
- 2*m_miniEdge
;
411 int hh
= m_menuBarHeight
;
412 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
413 m_frameMenuBar
->m_x
= xx
;
414 m_frameMenuBar
->m_y
= yy
;
415 m_frameMenuBar
->m_width
= ww
;
416 m_frameMenuBar
->m_height
= hh
;
417 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
418 m_frameMenuBar
->m_widget
,
420 client_area_y_offset
+= hh
;
422 #endif // wxUSE_MENUS_NATIVE
425 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
426 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
429 int yy
= m_miniEdge
+ m_miniTitle
;
430 #if wxUSE_MENUS_NATIVE
433 if (!m_menuBarDetached
)
434 yy
+= m_menuBarHeight
;
436 yy
+= wxPLACE_HOLDER
;
438 #endif // wxUSE_MENUS_NATIVE
440 m_frameToolBar
->m_x
= xx
;
441 m_frameToolBar
->m_y
= yy
;
443 // don't change the toolbar's reported height/width
445 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
447 ww
= m_toolBarDetached
? wxPLACE_HOLDER
448 : m_frameToolBar
->m_width
;
449 hh
= m_height
- 2*m_miniEdge
;
451 client_area_x_offset
+= ww
;
455 ww
= m_width
- 2*m_miniEdge
;
456 hh
= m_toolBarDetached
? wxPLACE_HOLDER
457 : m_frameToolBar
->m_height
;
459 client_area_y_offset
+= hh
;
462 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
463 m_frameToolBar
->m_widget
,
466 #endif // wxUSE_TOOLBAR
468 int client_x
= client_area_x_offset
+ m_miniEdge
;
469 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
470 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
471 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
472 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
474 client_x
, client_y
, client_w
, client_h
);
478 // If there is no m_mainWidget between m_widget and m_wxwindow there
479 // is no need to set the size or position of m_wxwindow.
483 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
485 int xx
= 0 + m_miniEdge
;
486 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
487 int ww
= m_width
- 2*m_miniEdge
;
488 int hh
= wxSTATUS_HEIGHT
;
489 m_frameStatusBar
->m_x
= xx
;
490 m_frameStatusBar
->m_y
= yy
;
491 m_frameStatusBar
->m_width
= ww
;
492 m_frameStatusBar
->m_height
= hh
;
493 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
494 m_frameStatusBar
->m_widget
,
496 gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL
);
498 #endif // wxUSE_STATUSBAR
502 // send size event to frame
503 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
504 event
.SetEventObject( this );
505 GetEventHandler()->ProcessEvent( event
);
508 // send size event to status bar
509 if (m_frameStatusBar
)
511 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
512 event2
.SetEventObject( m_frameStatusBar
);
513 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
515 #endif // wxUSE_STATUSBAR
520 void wxFrame::OnInternalIdle()
522 wxFrameBase::OnInternalIdle();
524 #if wxUSE_MENUS_NATIVE
525 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
526 #endif // wxUSE_MENUS_NATIVE
528 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
531 if (m_frameStatusBar
)
533 m_frameStatusBar
->OnInternalIdle();
535 // There may be controls in the status bar that
536 // need to be updated
537 for ( wxWindowList::compatibility_iterator node
= m_frameStatusBar
->GetChildren().GetFirst();
539 node
= node
->GetNext() )
541 wxWindow
*child
= node
->GetData();
542 child
->OnInternalIdle();
548 // ----------------------------------------------------------------------------
549 // menu/tool/status bar stuff
550 // ----------------------------------------------------------------------------
552 #if wxUSE_MENUS_NATIVE
554 void wxFrame::DetachMenuBar()
556 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
557 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
559 if ( m_frameMenuBar
)
561 m_frameMenuBar
->UnsetInvokingWindow( this );
563 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
565 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
566 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
568 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
569 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
572 gtk_widget_ref( m_frameMenuBar
->m_widget
);
574 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
577 wxFrameBase::DetachMenuBar();
580 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
582 wxFrameBase::AttachMenuBar(menuBar
);
586 m_frameMenuBar
->SetInvokingWindow( this );
588 m_frameMenuBar
->SetParent(this);
589 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
590 m_frameMenuBar
->m_widget
,
593 m_frameMenuBar
->m_width
,
594 m_frameMenuBar
->m_height
);
596 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
598 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached",
599 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
601 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached",
602 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
605 gtk_widget_show( m_frameMenuBar
->m_widget
);
612 GtkUpdateSize(); // resize window in OnInternalIdle
616 void wxFrame::UpdateMenuBarSize()
623 // this is called after Remove with a NULL m_frameMenuBar
624 if ( m_frameMenuBar
)
625 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request
)
626 (m_frameMenuBar
->m_widget
, &req
);
628 m_menuBarHeight
= req
.height
;
630 // resize window in OnInternalIdle
635 #endif // wxUSE_MENUS_NATIVE
639 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
641 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
643 m_insertInClientArea
= false;
645 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
647 m_insertInClientArea
= true;
651 return m_frameToolBar
;
654 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
656 bool hadTbar
= m_frameToolBar
!= NULL
;
658 wxFrameBase::SetToolBar(toolbar
);
660 if ( m_frameToolBar
)
662 // insert into toolbar area if not already there
663 if ((m_frameToolBar
->m_widget
->parent
) &&
664 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
666 GetChildren().DeleteObject( m_frameToolBar
);
668 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
672 else // toolbar unset
674 // still need to update size if it had been there before
682 #endif // wxUSE_TOOLBAR
686 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
689 const wxString
& name
)
691 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
693 // because it will change when toolbar is added
696 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
699 void wxFrame::SetStatusBar(wxStatusBar
*statbar
)
701 bool hadStatBar
= m_frameStatusBar
!= NULL
;
703 wxFrameBase::SetStatusBar(statbar
);
705 if (hadStatBar
&& !m_frameStatusBar
)
709 void wxFrame::PositionStatusBar()
711 if ( !m_frameStatusBar
)
716 #endif // wxUSE_STATUSBAR