1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
19 #pragma implementation "frame.h"
24 #include "wx/dialog.h"
25 #include "wx/control.h"
29 #include "wx/toolbar.h"
32 #include "wx/statusbr.h"
34 #include "wx/dcclient.h"
39 #include <gdk/gdkkeysyms.h>
42 #include "wx/gtk/win_gtk.h"
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 const int wxMENU_HEIGHT
= 27;
49 const int wxSTATUS_HEIGHT
= 25;
50 const int wxPLACE_HOLDER
= 0;
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 extern void wxapp_install_idle_handler();
58 extern int g_openDialogs
;
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 //-----------------------------------------------------------------------------
80 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
82 if (!win
->m_hasVMT
) return;
84 win
->m_menuBarDetached
= FALSE
;
88 //-----------------------------------------------------------------------------
89 // "child_detached" of menu bar
90 //-----------------------------------------------------------------------------
92 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
94 if (!win
->m_hasVMT
) return;
96 win
->m_menuBarDetached
= TRUE
;
100 #endif // wxUSE_MENUS_NATIVE
103 //-----------------------------------------------------------------------------
104 // "child_attached" of tool bar
105 //-----------------------------------------------------------------------------
107 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
109 if (!win
->m_hasVMT
) return;
111 win
->m_toolBarDetached
= FALSE
;
113 win
->GtkUpdateSize();
116 //-----------------------------------------------------------------------------
117 // "child_detached" of tool bar
118 //-----------------------------------------------------------------------------
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 win
->m_toolBarDetached
= TRUE
;
128 win
->GtkUpdateSize();
130 #endif // wxUSE_TOOLBAR
133 // ----------------------------------------------------------------------------
135 // ----------------------------------------------------------------------------
137 //-----------------------------------------------------------------------------
138 // InsertChild for wxFrame
139 //-----------------------------------------------------------------------------
141 /* Callback for wxFrame. This very strange beast has to be used because
142 * C++ has no virtual methods in a constructor. We have to emulate a
143 * virtual function here as wxWindows requires different ways to insert
144 * a child in container classes. */
146 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
148 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
150 if (!parent
->m_insertInClientArea
)
152 /* these are outside the client area */
153 wxFrame
* frame
= (wxFrame
*) parent
;
154 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
155 GTK_WIDGET(child
->m_widget
),
161 #if wxUSE_TOOLBAR_NATIVE
162 /* we connect to these events for recalculating the client area
163 space when the toolbar is floating */
164 if (wxIS_KIND_OF(child
,wxToolBar
))
166 wxToolBar
*toolBar
= (wxToolBar
*) child
;
167 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
169 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached",
170 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent
);
172 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached",
173 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent
);
176 #endif // wxUSE_TOOLBAR
180 /* these are inside the client area */
181 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
182 GTK_WIDGET(child
->m_widget
),
189 /* resize on OnInternalIdle */
190 parent
->GtkUpdateSize();
193 // ----------------------------------------------------------------------------
195 // ----------------------------------------------------------------------------
199 m_menuBarDetached
= FALSE
;
200 m_toolBarDetached
= FALSE
;
203 bool wxFrame::Create( wxWindow
*parent
,
205 const wxString
& title
,
207 const wxSize
& sizeOrig
,
209 const wxString
&name
)
211 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
213 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
219 m_isBeingDeleted
= TRUE
;
223 // ----------------------------------------------------------------------------
224 // overridden wxWindow methods
225 // ----------------------------------------------------------------------------
227 void wxFrame::DoGetClientSize( int *width
, int *height
) const
229 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
231 wxTopLevelWindow::DoGetClientSize( width
, height
);
235 #if wxUSE_MENUS_NATIVE
239 if (!m_menuBarDetached
)
240 (*height
) -= wxMENU_HEIGHT
;
242 (*height
) -= wxPLACE_HOLDER
;
244 #endif // wxUSE_MENUS_NATIVE
248 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
249 (*height
) -= wxSTATUS_HEIGHT
;
250 #endif // wxUSE_STATUSBAR
254 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
256 if (m_toolBarDetached
)
258 *height
-= wxPLACE_HOLDER
;
263 m_frameToolBar
->GetSize( &x
, &y
);
264 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
274 #endif // wxUSE_TOOLBAR
278 void wxFrame::DoSetClientSize( int width
, int height
)
280 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
282 #if wxUSE_MENUS_NATIVE
286 if (!m_menuBarDetached
)
287 height
+= wxMENU_HEIGHT
;
289 height
+= wxPLACE_HOLDER
;
291 #endif // wxUSE_MENUS_NATIVE
295 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
300 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
302 if (m_toolBarDetached
)
304 height
+= wxPLACE_HOLDER
;
309 m_frameToolBar
->GetSize( &x
, &y
);
310 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
322 wxTopLevelWindow::DoSetClientSize( width
, height
);
325 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
326 int width
, int height
)
328 // due to a bug in gtk, x,y are always 0
332 /* avoid recursions */
333 if (m_resizing
) return;
336 /* this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
337 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
342 /* space occupied by m_frameToolBar and m_frameMenuBar */
343 int client_area_x_offset
= 0,
344 client_area_y_offset
= 0;
346 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
347 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
348 set in wxFrame::Create so it is used to check what kind of frame we
349 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
350 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
351 importantly) m_mainWidget */
353 int minWidth
= GetMinWidth(),
354 minHeight
= GetMinHeight(),
355 maxWidth
= GetMaxWidth(),
356 maxHeight
= GetMaxHeight();
358 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
359 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
360 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
361 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
366 gint flag
= 0; // GDK_HINT_POS;
367 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
368 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
370 geom
.min_width
= minWidth
;
371 geom
.min_height
= minHeight
;
372 geom
.max_width
= maxWidth
;
373 geom
.max_height
= maxHeight
;
374 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
377 (GdkWindowHints
) flag
);
379 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
380 * menubar, the toolbar and the client area, which is represented by
382 * this hurts in the eye, but I don't want to call SetSize()
383 * because I don't want to call any non-native functions here. */
385 #if wxUSE_MENUS_NATIVE
389 int yy
= m_miniEdge
+ m_miniTitle
;
390 int ww
= m_width
- 2*m_miniEdge
;
391 int hh
= wxMENU_HEIGHT
;
392 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
393 m_frameMenuBar
->m_x
= xx
;
394 m_frameMenuBar
->m_y
= yy
;
395 m_frameMenuBar
->m_width
= ww
;
396 m_frameMenuBar
->m_height
= hh
;
397 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
398 m_frameMenuBar
->m_widget
,
400 client_area_y_offset
+= hh
;
402 #endif // wxUSE_MENUS_NATIVE
405 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
406 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
409 int yy
= m_miniEdge
+ m_miniTitle
;
410 #if wxUSE_MENUS_NATIVE
413 if (!m_menuBarDetached
)
416 yy
+= wxPLACE_HOLDER
;
418 #endif // wxUSE_MENUS_NATIVE
420 m_frameToolBar
->m_x
= xx
;
421 m_frameToolBar
->m_y
= yy
;
423 /* don't change the toolbar's reported height/width */
425 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
427 ww
= m_toolBarDetached
? wxPLACE_HOLDER
428 : m_frameToolBar
->m_width
;
429 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
;
452 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
454 client_x
, client_y
, client_w
, client_h
);
458 /* if there is no m_mainWidget between m_widget and m_wxwindow there
459 is no need to set the size or position of m_wxwindow. */
463 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
465 int xx
= 0 + m_miniEdge
;
466 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
467 int ww
= m_width
- 2*m_miniEdge
;
468 int hh
= wxSTATUS_HEIGHT
;
469 m_frameStatusBar
->m_x
= xx
;
470 m_frameStatusBar
->m_y
= yy
;
471 m_frameStatusBar
->m_width
= ww
;
472 m_frameStatusBar
->m_height
= hh
;
473 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
474 m_frameStatusBar
->m_widget
,
476 gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL
);
478 #endif // wxUSE_STATUSBAR
482 // send size event to frame
483 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
484 event
.SetEventObject( this );
485 GetEventHandler()->ProcessEvent( event
);
488 // send size event to status bar
489 if (m_frameStatusBar
)
491 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
492 event2
.SetEventObject( m_frameStatusBar
);
493 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
495 #endif // wxUSE_STATUSBAR
500 void wxFrame::OnInternalIdle()
502 wxTopLevelWindow::OnInternalIdle();
504 #if wxUSE_MENUS_NATIVE
505 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
506 #endif // wxUSE_MENUS_NATIVE
508 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
511 if (m_frameStatusBar
) m_frameStatusBar
->OnInternalIdle();
515 // ----------------------------------------------------------------------------
516 // menu/tool/status bar stuff
517 // ----------------------------------------------------------------------------
519 #if wxUSE_MENUS_NATIVE
521 void wxFrame::DetachMenuBar()
523 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
524 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
526 if ( m_frameMenuBar
)
528 m_frameMenuBar
->UnsetInvokingWindow( this );
530 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
532 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
533 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
535 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
536 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
539 gtk_widget_ref( m_frameMenuBar
->m_widget
);
541 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
544 wxFrameBase::DetachMenuBar();
547 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
549 wxFrameBase::AttachMenuBar(menuBar
);
553 m_frameMenuBar
->SetInvokingWindow( this );
555 m_frameMenuBar
->SetParent(this);
556 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
557 m_frameMenuBar
->m_widget
,
560 m_frameMenuBar
->m_width
,
561 m_frameMenuBar
->m_height
);
563 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
565 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached",
566 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
568 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached",
569 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
572 m_frameMenuBar
->Show( TRUE
);
575 // resize window in OnInternalIdle
579 #endif // wxUSE_MENUS_NATIVE
583 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
585 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
587 m_insertInClientArea
= FALSE
;
589 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
591 m_insertInClientArea
= TRUE
;
595 return m_frameToolBar
;
598 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
600 wxFrameBase::SetToolBar(toolbar
);
604 // insert into toolbar area if not already there
605 if ((m_frameToolBar
->m_widget
->parent
) &&
606 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
608 GetChildren().DeleteObject( m_frameToolBar
);
610 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
616 #endif // wxUSE_TOOLBAR
620 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
623 const wxString
& name
)
625 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
627 // because it will change when toolbar is added
630 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
633 void wxFrame::PositionStatusBar()
635 if ( !m_frameStatusBar
)
640 #endif // wxUSE_STATUSBAR