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"
27 #include "wx/dialog.h"
28 #include "wx/control.h"
32 #include "wx/toolbar.h"
35 #include "wx/statusbr.h"
37 #include "wx/dcclient.h"
40 #include "wx/gtk/private.h"
42 #include <gdk/gdkkeysyms.h>
45 #include "wx/gtk/win_gtk.h"
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 const int wxSTATUS_HEIGHT
= 25;
52 const int wxPLACE_HOLDER
= 0;
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 extern void wxapp_install_idle_handler();
60 extern int g_openDialogs
;
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 //-----------------------------------------------------------------------------
82 static void gtk_menu_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
84 if (!win
->m_hasVMT
) return;
86 win
->m_menuBarDetached
= FALSE
;
90 //-----------------------------------------------------------------------------
91 // "child_detached" of menu bar
92 //-----------------------------------------------------------------------------
94 static void gtk_menu_detached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
97 wxapp_install_idle_handler();
99 if (!win
->m_hasVMT
) return;
101 // Raise the client area area
102 gdk_window_raise( win
->m_wxwindow
->window
);
104 win
->m_menuBarDetached
= TRUE
;
105 win
->GtkUpdateSize();
108 #endif // wxUSE_MENUS_NATIVE
111 //-----------------------------------------------------------------------------
112 // "child_attached" of tool bar
113 //-----------------------------------------------------------------------------
115 static void gtk_toolbar_attached_callback( GtkWidget
*WXUNUSED(widget
), GtkWidget
*WXUNUSED(child
), wxFrame
*win
)
117 if (!win
->m_hasVMT
) return;
119 win
->m_toolBarDetached
= FALSE
;
120 win
->GtkUpdateSize();
123 //-----------------------------------------------------------------------------
124 // "child_detached" of tool bar
125 //-----------------------------------------------------------------------------
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();
140 #endif // wxUSE_TOOLBAR
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
147 //-----------------------------------------------------------------------------
148 // InsertChild for wxFrame
149 //-----------------------------------------------------------------------------
151 /* Callback for wxFrame. This very strange beast has to be used because
152 * C++ has no virtual methods in a constructor. We have to emulate a
153 * virtual function here as wxWidgets requires different ways to insert
154 * a child in container classes. */
156 static void wxInsertChildInFrame( wxFrame
* parent
, wxWindow
* child
)
158 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
160 if (!parent
->m_insertInClientArea
)
162 // These are outside the client area
163 wxFrame
* frame
= (wxFrame
*) parent
;
164 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
165 GTK_WIDGET(child
->m_widget
),
171 #if wxUSE_TOOLBAR_NATIVE
172 // We connect to these events for recalculating the client area
173 // space when the toolbar is floating
174 if (wxIS_KIND_OF(child
,wxToolBar
))
176 wxToolBar
*toolBar
= (wxToolBar
*) child
;
177 if (toolBar
->GetWindowStyle() & wxTB_DOCKABLE
)
179 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_attached",
180 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback
), (gpointer
)parent
);
182 gtk_signal_connect( GTK_OBJECT(toolBar
->m_widget
), "child_detached",
183 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback
), (gpointer
)parent
);
186 #endif // wxUSE_TOOLBAR
190 // These are inside the client area
191 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
192 GTK_WIDGET(child
->m_widget
),
199 // Resize on OnInternalIdle
200 parent
->GtkUpdateSize();
203 // ----------------------------------------------------------------------------
205 // ----------------------------------------------------------------------------
209 m_menuBarDetached
= FALSE
;
210 m_toolBarDetached
= FALSE
;
214 bool wxFrame::Create( wxWindow
*parent
,
216 const wxString
& title
,
218 const wxSize
& sizeOrig
,
220 const wxString
&name
)
222 bool rt
= wxTopLevelWindow::Create(parent
, id
, title
, pos
, sizeOrig
,
224 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInFrame
;
231 m_isBeingDeleted
= TRUE
;
235 // ----------------------------------------------------------------------------
236 // overridden wxWindow methods
237 // ----------------------------------------------------------------------------
239 void wxFrame::DoGetClientSize( int *width
, int *height
) const
241 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
243 wxTopLevelWindow::DoGetClientSize( width
, height
);
247 #if wxUSE_MENUS_NATIVE
251 if (!m_menuBarDetached
)
252 (*height
) -= m_menuBarHeight
;
254 (*height
) -= wxPLACE_HOLDER
;
256 #endif // wxUSE_MENUS_NATIVE
260 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
261 (*height
) -= wxSTATUS_HEIGHT
;
262 #endif // wxUSE_STATUSBAR
266 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
268 if (m_toolBarDetached
)
270 *height
-= wxPLACE_HOLDER
;
275 m_frameToolBar
->GetSize( &x
, &y
);
276 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
286 #endif // wxUSE_TOOLBAR
290 void wxFrame::DoSetClientSize( int width
, int height
)
292 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
294 #if wxUSE_MENUS_NATIVE
298 if (!m_menuBarDetached
)
299 height
+= m_menuBarHeight
;
301 height
+= wxPLACE_HOLDER
;
303 #endif // wxUSE_MENUS_NATIVE
307 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown()) height
+= wxSTATUS_HEIGHT
;
312 if (m_frameToolBar
&& m_frameToolBar
->IsShown())
314 if (m_toolBarDetached
)
316 height
+= wxPLACE_HOLDER
;
321 m_frameToolBar
->GetSize( &x
, &y
);
322 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
334 wxTopLevelWindow::DoSetClientSize( width
, height
);
337 void wxFrame::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
338 int width
, int height
)
340 // due to a bug in gtk, x,y are always 0
345 if (m_resizing
) return;
348 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
349 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
354 // space occupied by m_frameToolBar and m_frameMenuBar
355 int client_area_x_offset
= 0,
356 client_area_y_offset
= 0;
358 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
359 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
360 set in wxFrame::Create so it is used to check what kind of frame we
361 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
362 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
363 importantly) m_mainWidget */
365 int minWidth
= GetMinWidth(),
366 minHeight
= GetMinHeight(),
367 maxWidth
= GetMaxWidth(),
368 maxHeight
= GetMaxHeight();
370 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
371 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
372 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
373 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
378 gint flag
= 0; // GDK_HINT_POS;
379 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
380 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
382 geom
.min_width
= minWidth
;
383 geom
.min_height
= minHeight
;
384 geom
.max_width
= maxWidth
;
385 geom
.max_height
= maxHeight
;
386 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
389 (GdkWindowHints
) flag
);
391 // I revert back to wxGTK's original behaviour. m_mainWidget holds
392 // the menubar, the toolbar and the client area, which is represented
394 // This hurts in the eye, but I don't want to call SetSize()
395 // because I don't want to call any non-native functions here.
397 #if wxUSE_MENUS_NATIVE
401 int yy
= m_miniEdge
+ m_miniTitle
;
402 int ww
= m_width
- 2*m_miniEdge
;
403 int hh
= m_menuBarHeight
;
404 if (m_menuBarDetached
) hh
= wxPLACE_HOLDER
;
405 m_frameMenuBar
->m_x
= xx
;
406 m_frameMenuBar
->m_y
= yy
;
407 m_frameMenuBar
->m_width
= ww
;
408 m_frameMenuBar
->m_height
= hh
;
409 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
410 m_frameMenuBar
->m_widget
,
412 client_area_y_offset
+= hh
;
414 #endif // wxUSE_MENUS_NATIVE
417 if ((m_frameToolBar
) && m_frameToolBar
->IsShown() &&
418 (m_frameToolBar
->m_widget
->parent
== m_mainWidget
))
421 int yy
= m_miniEdge
+ m_miniTitle
;
422 #if wxUSE_MENUS_NATIVE
425 if (!m_menuBarDetached
)
426 yy
+= m_menuBarHeight
;
428 yy
+= wxPLACE_HOLDER
;
430 #endif // wxUSE_MENUS_NATIVE
432 m_frameToolBar
->m_x
= xx
;
433 m_frameToolBar
->m_y
= yy
;
435 // don't change the toolbar's reported height/width
437 if ( m_frameToolBar
->GetWindowStyle() & wxTB_VERTICAL
)
439 ww
= m_toolBarDetached
? wxPLACE_HOLDER
440 : m_frameToolBar
->m_width
;
441 hh
= m_height
- 2*m_miniEdge
;
443 client_area_x_offset
+= ww
;
447 ww
= m_width
- 2*m_miniEdge
;
448 hh
= m_toolBarDetached
? wxPLACE_HOLDER
449 : m_frameToolBar
->m_height
;
451 client_area_y_offset
+= hh
;
454 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
455 m_frameToolBar
->m_widget
,
458 #endif // wxUSE_TOOLBAR
460 int client_x
= client_area_x_offset
+ m_miniEdge
;
461 int client_y
= client_area_y_offset
+ m_miniEdge
+ m_miniTitle
;
462 int client_w
= m_width
- client_area_x_offset
- 2*m_miniEdge
;
463 int client_h
= m_height
- client_area_y_offset
- 2*m_miniEdge
- m_miniTitle
;
464 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
466 client_x
, client_y
, client_w
, client_h
);
470 // If there is no m_mainWidget between m_widget and m_wxwindow there
471 // is no need to set the size or position of m_wxwindow.
475 if (m_frameStatusBar
&& m_frameStatusBar
->IsShown())
477 int xx
= 0 + m_miniEdge
;
478 int yy
= m_height
- wxSTATUS_HEIGHT
- m_miniEdge
- client_area_y_offset
;
479 int ww
= m_width
- 2*m_miniEdge
;
480 int hh
= wxSTATUS_HEIGHT
;
481 m_frameStatusBar
->m_x
= xx
;
482 m_frameStatusBar
->m_y
= yy
;
483 m_frameStatusBar
->m_width
= ww
;
484 m_frameStatusBar
->m_height
= hh
;
485 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow
),
486 m_frameStatusBar
->m_widget
,
488 gtk_widget_draw( m_frameStatusBar
->m_widget
, (GdkRectangle
*) NULL
);
490 #endif // wxUSE_STATUSBAR
494 // send size event to frame
495 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
496 event
.SetEventObject( this );
497 GetEventHandler()->ProcessEvent( event
);
500 // send size event to status bar
501 if (m_frameStatusBar
)
503 wxSizeEvent
event2( wxSize(m_frameStatusBar
->m_width
,m_frameStatusBar
->m_height
), m_frameStatusBar
->GetId() );
504 event2
.SetEventObject( m_frameStatusBar
);
505 m_frameStatusBar
->GetEventHandler()->ProcessEvent( event2
);
507 #endif // wxUSE_STATUSBAR
512 void wxFrame::OnInternalIdle()
514 wxFrameBase::OnInternalIdle();
516 #if wxUSE_MENUS_NATIVE
517 if (m_frameMenuBar
) m_frameMenuBar
->OnInternalIdle();
518 #endif // wxUSE_MENUS_NATIVE
520 if (m_frameToolBar
) m_frameToolBar
->OnInternalIdle();
523 if (m_frameStatusBar
)
525 m_frameStatusBar
->OnInternalIdle();
527 // There may be controls in the status bar that
528 // need to be updated
529 for ( wxWindowList::compatibility_iterator node
= m_frameStatusBar
->GetChildren().GetFirst();
531 node
= node
->GetNext() )
533 wxWindow
*child
= node
->GetData();
534 child
->OnInternalIdle();
540 // ----------------------------------------------------------------------------
541 // menu/tool/status bar stuff
542 // ----------------------------------------------------------------------------
544 #if wxUSE_MENUS_NATIVE
546 void wxFrame::DetachMenuBar()
548 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
549 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
551 if ( m_frameMenuBar
)
553 m_frameMenuBar
->UnsetInvokingWindow( this );
555 if (m_frameMenuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
557 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
558 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
560 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar
->m_widget
),
561 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
564 gtk_widget_ref( m_frameMenuBar
->m_widget
);
566 gtk_container_remove( GTK_CONTAINER(m_mainWidget
), m_frameMenuBar
->m_widget
);
569 wxFrameBase::DetachMenuBar();
572 void wxFrame::AttachMenuBar( wxMenuBar
*menuBar
)
574 wxFrameBase::AttachMenuBar(menuBar
);
578 m_frameMenuBar
->SetInvokingWindow( this );
580 m_frameMenuBar
->SetParent(this);
581 gtk_pizza_put( GTK_PIZZA(m_mainWidget
),
582 m_frameMenuBar
->m_widget
,
585 m_frameMenuBar
->m_width
,
586 m_frameMenuBar
->m_height
);
588 if (menuBar
->GetWindowStyle() & wxMB_DOCKABLE
)
590 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_attached",
591 GTK_SIGNAL_FUNC(gtk_menu_attached_callback
), (gpointer
)this );
593 gtk_signal_connect( GTK_OBJECT(menuBar
->m_widget
), "child_detached",
594 GTK_SIGNAL_FUNC(gtk_menu_detached_callback
), (gpointer
)this );
597 gtk_widget_show( m_frameMenuBar
->m_widget
);
604 GtkUpdateSize(); // resize window in OnInternalIdle
608 void wxFrame::UpdateMenuBarSize()
615 // this is called after Remove with a NULL m_frameMenuBar
616 if ( m_frameMenuBar
)
617 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar
->m_widget
) )->size_request
)
618 (m_frameMenuBar
->m_widget
, &req
);
620 m_menuBarHeight
= req
.height
;
622 // resize window in OnInternalIdle
627 #endif // wxUSE_MENUS_NATIVE
631 wxToolBar
* wxFrame::CreateToolBar( long style
, wxWindowID id
, const wxString
& name
)
633 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
635 m_insertInClientArea
= FALSE
;
637 m_frameToolBar
= wxFrameBase::CreateToolBar( style
, id
, name
);
639 m_insertInClientArea
= TRUE
;
643 return m_frameToolBar
;
646 void wxFrame::SetToolBar(wxToolBar
*toolbar
)
648 bool hadTbar
= m_frameToolBar
!= NULL
;
650 wxFrameBase::SetToolBar(toolbar
);
652 if ( m_frameToolBar
)
654 // insert into toolbar area if not already there
655 if ((m_frameToolBar
->m_widget
->parent
) &&
656 (m_frameToolBar
->m_widget
->parent
!= m_mainWidget
))
658 GetChildren().DeleteObject( m_frameToolBar
);
660 gtk_widget_reparent( m_frameToolBar
->m_widget
, m_mainWidget
);
664 else // toolbar unset
666 // still need to update size if it had been there before
674 #endif // wxUSE_TOOLBAR
678 wxStatusBar
* wxFrame::CreateStatusBar(int number
,
681 const wxString
& name
)
683 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
685 // because it will change when toolbar is added
688 return wxFrameBase::CreateStatusBar( number
, style
, id
, name
);
691 void wxFrame::SetStatusBar(wxStatusBar
*statbar
)
693 bool hadStatBar
= m_frameStatusBar
!= NULL
;
695 wxFrameBase::SetStatusBar(statbar
);
697 if (hadStatBar
&& !m_frameStatusBar
)
701 void wxFrame::PositionStatusBar()
703 if ( !m_frameStatusBar
)
708 #endif // wxUSE_STATUSBAR