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"
37 #include "wx/gtk/private.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
)
95 wxapp_install_idle_handler();
97 if (!win
->m_hasVMT
) return;
99 // Raise the client area area
100 gdk_window_raise( win
->m_wxwindow
->window
);
102 win
->m_menuBarDetached
= TRUE
;
103 win
->GtkUpdateSize();
106 #endif // wxUSE_MENUS_NATIVE
109 //-----------------------------------------------------------------------------
110 // "child_attached" of tool bar
111 //-----------------------------------------------------------------------------
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();
121 //-----------------------------------------------------------------------------
122 // "child_detached" of tool bar
123 //-----------------------------------------------------------------------------
125 static void gtk_toolbar_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
128 wxapp_install_idle_handler();
130 if (!win
->m_hasVMT
) return;
132 // Raise the client area area
133 gdk_window_raise( win
->m_wxwindow
->window
);
135 win
->m_toolBarDetached
= TRUE
;
136 win
->GtkUpdateSize();
138 #endif // wxUSE_TOOLBAR
141 // ----------------------------------------------------------------------------
143 // ----------------------------------------------------------------------------
145 //-----------------------------------------------------------------------------
146 // InsertChild for wxFrame
147 //-----------------------------------------------------------------------------
149 /* Callback for wxFrame. This very strange beast has to be used because
150 * C++ has no virtual methods in a constructor. We have to emulate a
151 * virtual function here as wxWindows requires different ways to insert
152 * a child in container classes. */
154 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
156 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
158 if (!parent
->m_insertInClientArea
)
160 // These are outside the client area
161 wxFrame
* frame
= (wxFrame
*) parent
;
162 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
163 GTK_WIDGET(child
->m_widget
),
169 #if wxUSE_TOOLBAR_NATIVE
170 // We connect to these events for recalculating the client area
171 // space when the toolbar is floating
172 if (wxIS_KIND_OF(child
,wxToolBar
))
174 wxToolBar
*toolBar
= (wxToolBar
*) child
;
175 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
177 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached",
178 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent
);
180 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached",
181 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent
);
184 #endif // wxUSE_TOOLBAR
188 // These are inside the client area
189 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
190 GTK_WIDGET(child
->m_widget
),
197 // Resize on OnInternalIdle
198 parent
->GtkUpdateSize();
201 // ----------------------------------------------------------------------------
203 // ----------------------------------------------------------------------------
207 m_menuBarDetached
= FALSE
;
208 m_toolBarDetached
= FALSE
;
211 bool wxFrame::Create( wxWindow
*parent
,
213 const wxString
& title
,
215 const wxSize
& sizeOrig
,
217 const wxString
&name
)
219 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
221 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
227 m_isBeingDeleted
= TRUE
;
231 // ----------------------------------------------------------------------------
232 // overridden wxWindow methods
233 // ----------------------------------------------------------------------------
235 void wxFrame::DoGetClientSize( int *width
, int *height
) const
237 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
239 wxTopLevelWindow::DoGetClientSize( width
, height
);
243 #if wxUSE_MENUS_NATIVE
247 if (!m_menuBarDetached
)
248 (*height
) -= wxMENU_HEIGHT
;
250 (*height
) -= wxPLACE_HOLDER
;
252 #endif // wxUSE_MENUS_NATIVE
256 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
257 (*height
) -= wxSTATUS_HEIGHT
;
258 #endif // wxUSE_STATUSBAR
262 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
264 if (m_toolBarDetached
)
266 *height
-= wxPLACE_HOLDER
;
271 m_frameToolBar
->GetSize( &x
, &y
);
272 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
282 #endif // wxUSE_TOOLBAR
286 void wxFrame::DoSetClientSize( int width
, int height
)
288 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
290 #if wxUSE_MENUS_NATIVE
294 if (!m_menuBarDetached
)
295 height
+= wxMENU_HEIGHT
;
297 height
+= wxPLACE_HOLDER
;
299 #endif // wxUSE_MENUS_NATIVE
303 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
308 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
310 if (m_toolBarDetached
)
312 height
+= wxPLACE_HOLDER
;
317 m_frameToolBar
->GetSize( &x
, &y
);
318 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
330 wxTopLevelWindow::DoSetClientSize( width
, height
);
333 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
334 int width
, int height
)
336 // due to a bug in gtk, x,y are always 0
341 if (m_resizing
) return;
344 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
345 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
350 // space occupied by m_frameToolBar and m_frameMenuBar
351 int client_area_x_offset
= 0,
352 client_area_y_offset
= 0;
354 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
355 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
356 set in wxFrame::Create so it is used to check what kind of frame we
357 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
358 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
359 importantly) m_mainWidget */
361 int minWidth
= GetMinWidth(),
362 minHeight
= GetMinHeight(),
363 maxWidth
= GetMaxWidth(),
364 maxHeight
= GetMaxHeight();
366 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
367 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
368 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
369 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
374 gint flag
= 0; // GDK_HINT_POS;
375 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
376 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
378 geom
.min_width
= minWidth
;
379 geom
.min_height
= minHeight
;
380 geom
.max_width
= maxWidth
;
381 geom
.max_height
= maxHeight
;
382 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
385 (GdkWindowHints
) flag
);
387 // I revert back to wxGTK's original behaviour. m_mainWidget holds
388 // the menubar, the toolbar and the client area, which is represented
390 // This hurts in the eye, but I don't want to call SetSize()
391 // because I don't want to call any non-native functions here.
393 #if wxUSE_MENUS_NATIVE
397 int yy
= m_miniEdge
+ m_miniTitle
;
398 int ww
= m_width
- 2*m_miniEdge
;
399 int hh
= wxMENU_HEIGHT
;
400 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
401 m_frameMenuBar
->m_x
= xx
;
402 m_frameMenuBar
->m_y
= yy
;
403 m_frameMenuBar
->m_width
= ww
;
404 m_frameMenuBar
->m_height
= hh
;
405 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
406 m_frameMenuBar
->m_widget
,
408 client_area_y_offset
+= hh
;
410 #endif // wxUSE_MENUS_NATIVE
413 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
414 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
417 int yy
= m_miniEdge
+ m_miniTitle
;
418 #if wxUSE_MENUS_NATIVE
421 if (!m_menuBarDetached
)
424 yy
+= wxPLACE_HOLDER
;
426 #endif // wxUSE_MENUS_NATIVE
428 m_frameToolBar
->m_x
= xx
;
429 m_frameToolBar
->m_y
= yy
;
431 // don't change the toolbar's reported height/width
433 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
435 ww
= m_toolBarDetached
? wxPLACE_HOLDER
436 : m_frameToolBar
->m_width
;
437 hh
= m_height
- 2*m_miniEdge
;
439 client_area_x_offset
+= ww
;
443 ww
= m_width
- 2*m_miniEdge
;
444 hh
= m_toolBarDetached
? wxPLACE_HOLDER
445 : m_frameToolBar
->m_height
;
447 client_area_y_offset
+= hh
;
450 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
451 m_frameToolBar
->m_widget
,
454 #endif // wxUSE_TOOLBAR
456 int client_x
= client_area_x_offset
+ m_miniEdge
;
457 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
458 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
459 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
460 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
462 client_x
, client_y
, client_w
, client_h
);
466 // If there is no m_mainWidget between m_widget and m_wxwindow there
467 // is no need to set the size or position of m_wxwindow.
471 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
473 int xx
= 0 + m_miniEdge
;
474 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
475 int ww
= m_width
- 2*m_miniEdge
;
476 int hh
= wxSTATUS_HEIGHT
;
477 m_frameStatusBar
->m_x
= xx
;
478 m_frameStatusBar
->m_y
= yy
;
479 m_frameStatusBar
->m_width
= ww
;
480 m_frameStatusBar
->m_height
= hh
;
481 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
482 m_frameStatusBar
->m_widget
,
484 gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL
);
486 #endif // wxUSE_STATUSBAR
490 // send size event to frame
491 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
492 event
.SetEventObject( this );
493 GetEventHandler()->ProcessEvent( event
);
496 // send size event to status bar
497 if (m_frameStatusBar
)
499 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
500 event2
.SetEventObject( m_frameStatusBar
);
501 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
503 #endif // wxUSE_STATUSBAR
508 void wxFrame::OnInternalIdle()
510 wxTopLevelWindow::OnInternalIdle();
512 #if wxUSE_MENUS_NATIVE
513 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
514 #endif // wxUSE_MENUS_NATIVE
516 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
519 if (m_frameStatusBar
) m_frameStatusBar
->OnInternalIdle();
523 // ----------------------------------------------------------------------------
524 // menu/tool/status bar stuff
525 // ----------------------------------------------------------------------------
527 #if wxUSE_MENUS_NATIVE
529 void wxFrame::DetachMenuBar()
531 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
532 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
534 if ( m_frameMenuBar
)
536 m_frameMenuBar
->UnsetInvokingWindow( this );
538 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
540 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
541 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
543 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
544 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
547 gtk_widget_ref( m_frameMenuBar
->m_widget
);
549 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
552 wxFrameBase::DetachMenuBar();
555 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
557 wxFrameBase::AttachMenuBar(menuBar
);
561 m_frameMenuBar
->SetInvokingWindow( this );
563 m_frameMenuBar
->SetParent(this);
564 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
565 m_frameMenuBar
->m_widget
,
568 m_frameMenuBar
->m_width
,
569 m_frameMenuBar
->m_height
);
571 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
573 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached",
574 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
576 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached",
577 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
580 m_frameMenuBar
->Show( TRUE
);
583 // resize window in OnInternalIdle
587 #endif // wxUSE_MENUS_NATIVE
591 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
593 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
595 m_insertInClientArea
= FALSE
;
597 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
599 m_insertInClientArea
= TRUE
;
603 return m_frameToolBar
;
606 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
608 bool hadTbar
= m_frameToolBar
!= NULL
;
610 wxFrameBase::SetToolBar(toolbar
);
612 if ( m_frameToolBar
)
614 // insert into toolbar area if not already there
615 if ((m_frameToolBar
->m_widget
->parent
) &&
616 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
618 GetChildren().DeleteObject( m_frameToolBar
);
620 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
624 else // toolbar unset
626 // still need to update size if it had been there before
634 #endif // wxUSE_TOOLBAR
638 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
641 const wxString
& name
)
643 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
645 // because it will change when toolbar is added
648 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
651 void wxFrame::PositionStatusBar()
653 if ( !m_frameStatusBar
)
658 #endif // wxUSE_STATUSBAR