]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/frame.cpp
Second try at doing Set/GetClient right
[wxWidgets.git] / src / gtk / frame.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: frame.cpp
3// Purpose:
4// Author: Robert Roebling
a81258be 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling
19717c50 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
11#pragma implementation "frame.h"
12#endif
13
14#include "wx/frame.h"
15#include "wx/dialog.h"
16#include "wx/control.h"
17#include "wx/app.h"
cf4219e7
RR
18#include "wx/menu.h"
19#include "wx/toolbar.h"
20#include "wx/statusbr.h"
362c6693 21#include "wx/dcclient.h"
c801d85f
KB
22#include "wx/gtk/win_gtk.h"
23
2f2aa628
RR
24//-----------------------------------------------------------------------------
25// constants
26//-----------------------------------------------------------------------------
27
dbf858b5 28const int wxMENU_HEIGHT = 30;
c67daf87 29const int wxSTATUS_HEIGHT = 25;
c801d85f 30
2f2aa628
RR
31//-----------------------------------------------------------------------------
32// data
33//-----------------------------------------------------------------------------
34
c801d85f
KB
35extern wxList wxTopLevelWindows;
36extern wxList wxPendingDelete;
37
38//-----------------------------------------------------------------------------
2f2aa628 39// "size_allocate"
c801d85f 40//-----------------------------------------------------------------------------
c801d85f 41
2f2aa628 42static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxFrame *win )
ed7a557b 43{
c801d85f
KB
44 if (!win->HasVMT()) return;
45
46/*
47 printf( "OnFrameResize from " );
48 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
49 printf( win->GetClassInfo()->GetClassName() );
50 printf( ".\n" );
51*/
ed7a557b 52
219f895a 53 win->GtkOnSize( alloc->x, alloc->y, alloc->width, alloc->height );
362c6693 54}
c801d85f
KB
55
56//-----------------------------------------------------------------------------
2f2aa628
RR
57// "delete_event"
58//-----------------------------------------------------------------------------
c801d85f 59
2f2aa628 60static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxFrame *win )
ed7a557b 61{
c801d85f
KB
62/*
63 printf( "OnDelete from " );
64 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
65 printf( win->GetClassInfo()->GetClassName() );
66 printf( ".\n" );
67*/
ed7a557b 68
c801d85f
KB
69 win->Close();
70
71 return TRUE;
362c6693 72}
c801d85f 73
47908e25 74//-----------------------------------------------------------------------------
2f2aa628
RR
75// "configure_event"
76//-----------------------------------------------------------------------------
47908e25 77
2f2aa628 78static gint gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *event, wxFrame *win )
47908e25
RR
79{
80 if (!win->HasVMT()) return FALSE;
81
82 win->m_x = event->x;
83 win->m_y = event->y;
84
85 return FALSE;
362c6693 86}
47908e25 87
2f2aa628
RR
88//-----------------------------------------------------------------------------
89// wxFrame
c801d85f
KB
90//-----------------------------------------------------------------------------
91
92BEGIN_EVENT_TABLE(wxFrame, wxWindow)
c801d85f 93 EVT_SIZE(wxFrame::OnSize)
716b7364 94 EVT_CLOSE(wxFrame::OnCloseWindow)
e2414cbe 95 EVT_IDLE(wxFrame::OnIdle)
c801d85f
KB
96END_EVENT_TABLE()
97
98IMPLEMENT_DYNAMIC_CLASS(wxFrame,wxWindow)
99
19717c50 100wxFrame::wxFrame()
c801d85f 101{
c67daf87
UR
102 m_frameMenuBar = (wxMenuBar *) NULL;
103 m_frameStatusBar = (wxStatusBar *) NULL;
104 m_frameToolBar = (wxToolBar *) NULL;
c801d85f
KB
105 m_sizeSet = FALSE;
106 wxTopLevelWindows.Insert( this );
362c6693 107}
c801d85f 108
ed7a557b 109wxFrame::wxFrame( wxWindow *parent, wxWindowID id, const wxString &title,
debe6624
JS
110 const wxPoint &pos, const wxSize &size,
111 long style, const wxString &name )
c801d85f 112{
c67daf87
UR
113 m_frameMenuBar = (wxMenuBar *) NULL;
114 m_frameStatusBar = (wxStatusBar *) NULL;
115 m_frameToolBar = (wxToolBar *) NULL;
c801d85f
KB
116 m_sizeSet = FALSE;
117 Create( parent, id, title, pos, size, style, name );
118 wxTopLevelWindows.Insert( this );
362c6693 119}
c801d85f 120
debe6624 121bool wxFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
c801d85f 122 const wxPoint &pos, const wxSize &size,
debe6624 123 long style, const wxString &name )
c801d85f
KB
124{
125 m_needParent = FALSE;
ed7a557b 126
c801d85f
KB
127 PreCreation( parent, id, pos, size, style, name );
128
c801d85f 129 m_title = title;
ed7a557b 130
32e9da8b
RR
131 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
132 if (style & wxSIMPLE_BORDER) win_type = GTK_WINDOW_POPUP;
133
134 m_widget = gtk_window_new( win_type );
ed7a557b 135 if ((size.x != -1) && (size.y != -1))
c801d85f 136 gtk_widget_set_usize( m_widget, m_width, m_height );
ed7a557b 137 if ((pos.x != -1) && (pos.y != -1))
c801d85f 138 gtk_widget_set_uposition( m_widget, m_x, m_y );
ed7a557b 139
c801d85f
KB
140 gtk_window_set_title( GTK_WINDOW(m_widget), title );
141 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ed7a557b 142
6ca41e57 143 gtk_widget_set( m_widget, "GtkWindow::allow_shrink", TRUE, NULL );
ed7a557b
VZ
144
145 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
c801d85f 146 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
ed7a557b 147
c801d85f
KB
148 m_wxwindow = gtk_myfixed_new();
149 gtk_widget_show( m_wxwindow );
150 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
ed7a557b 151
6ca41e57 152 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
ed7a557b 153
ed7a557b 154 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
c801d85f 155 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
ed7a557b 156
47908e25
RR
157 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
158 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
159
6ca41e57
RR
160 if (m_parent) m_parent->AddChild( this );
161
c801d85f 162 PostCreation();
ed7a557b 163
c801d85f 164 return TRUE;
362c6693 165}
c801d85f 166
19717c50 167wxFrame::~wxFrame()
c801d85f
KB
168{
169 if (m_frameMenuBar) delete m_frameMenuBar;
170 if (m_frameStatusBar) delete m_frameStatusBar;
ff7b1510 171 if (m_frameToolBar) delete m_frameToolBar;
ed7a557b 172
c801d85f
KB
173 wxTopLevelWindows.DeleteObject( this );
174 if (wxTopLevelWindows.Number() == 0) wxTheApp->ExitMainLoop();
362c6693 175}
ed7a557b 176
debe6624 177bool wxFrame::Show( bool show )
c801d85f 178{
e55ad60e
RR
179 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
180
c801d85f
KB
181 if (show)
182 {
183 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
184 m_sizeSet = FALSE;
185 ProcessEvent( event );
362c6693 186 }
c801d85f 187 return wxWindow::Show( show );
362c6693 188}
c801d85f 189
716b7364 190void wxFrame::OnCloseWindow( wxCloseEvent &event )
c801d85f 191{
e55ad60e 192 if (GetEventHandler()->OnClose() || event.GetForce()) this->Destroy();
362c6693 193}
c801d85f 194
19717c50 195bool wxFrame::Destroy()
c801d85f 196{
e55ad60e
RR
197 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
198
c801d85f
KB
199 if (!wxPendingDelete.Member(this))
200 wxPendingDelete.Append(this);
ed7a557b 201
c801d85f
KB
202 return TRUE;
203}
204
6ca41e57
RR
205wxPoint wxFrame::GetClientAreaOrigin() const
206{
207 wxPoint pt(0, 0);
208 if (m_frameMenuBar)
209 {
210 int h = 0;
211 m_frameMenuBar->GetSize( (int*)NULL, &h );
212 pt.y += h + 2;
213 }
214 if (m_frameToolBar)
215 {
216 int h = 0;
217 m_frameToolBar->GetSize( (int*)NULL, &h );
218 pt.y += h;
219 }
220 return pt;
221}
222
903f689b
RR
223void wxFrame::ImplementSetPosition(void)
224{
225 if ((m_x != -1) || (m_y != -1))
226 gtk_widget_set_uposition( m_widget, m_x, m_y );
227}
228
229void wxFrame::Centre( int direction )
230{
e55ad60e
RR
231 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
232
903f689b
RR
233 if (direction & wxHORIZONTAL == wxHORIZONTAL) m_x = (gdk_screen_width () - m_width) / 2;
234 if (direction & wxVERTICAL == wxVERTICAL) m_y = (gdk_screen_height () - m_height) / 2;
6ca41e57 235
903f689b
RR
236 ImplementSetPosition();
237}
238
c801d85f
KB
239void wxFrame::GetClientSize( int *width, int *height ) const
240{
e55ad60e
RR
241 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
242
c801d85f
KB
243 wxWindow::GetClientSize( width, height );
244 if (height)
245 {
246 if (m_frameMenuBar) (*height) -= wxMENU_HEIGHT;
247 if (m_frameStatusBar) (*height) -= wxSTATUS_HEIGHT;
46dc76ba
RR
248 if (m_frameToolBar)
249 {
250 int y = 0;
c67daf87 251 m_frameToolBar->GetSize( (int *) NULL, &y );
46dc76ba
RR
252 (*height) -= y;
253 }
362c6693
RR
254 }
255}
c801d85f 256
b593568e
RR
257void wxFrame::SetClientSize( int const width, int const height )
258{
e55ad60e
RR
259 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
260
b593568e
RR
261 int h = height;
262 if (m_frameMenuBar) h += wxMENU_HEIGHT;
263 if (m_frameStatusBar) h += wxSTATUS_HEIGHT;
264 if (m_frameToolBar)
265 {
266 int y = 0;
c67daf87 267 m_frameToolBar->GetSize( (int *) NULL, &y );
b593568e
RR
268 h += y;
269 }
270 wxWindow::SetClientSize( width, h );
362c6693 271}
b593568e 272
47908e25 273void wxFrame::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y), int width, int height )
c801d85f 274{
47908e25
RR
275 // due to a bug in gtk, x,y are always 0
276 // m_x = x;
277 // m_y = y;
219f895a 278
c801d85f
KB
279 if ((m_height == height) && (m_width == width) &&
280 (m_sizeSet)) return;
c801d85f
KB
281 if (!m_wxwindow) return;
282
283 m_width = width;
284 m_height = height;
2f2aa628
RR
285 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
286 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
287 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_minWidth;
288 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_minHeight;
ed7a557b 289
6ca41e57 290 gtk_widget_set_usize( m_widget, m_width, m_height );
ed7a557b 291
6ca41e57 292 // This emulates the new wxMSW behaviour
ed7a557b 293
c801d85f
KB
294 if (m_frameMenuBar)
295 {
6ca41e57
RR
296 m_frameMenuBar->m_x = 1;
297 m_frameMenuBar->m_y = 1;
298 m_frameMenuBar->m_width = m_width-2;
299 m_frameMenuBar->m_height = wxMENU_HEIGHT-2;
300 gtk_myfixed_move( GTK_MYFIXED(m_wxwindow), m_frameMenuBar->m_widget, 1, 1 );
301 gtk_widget_set_usize( m_frameMenuBar->m_widget, m_width-2, wxMENU_HEIGHT-2 );
362c6693 302 }
ed7a557b 303
46dc76ba
RR
304 if (m_frameToolBar)
305 {
7bce6aec
RR
306 int y = 0;
307 if (m_frameMenuBar) y = wxMENU_HEIGHT;
6ca41e57
RR
308 int h = m_frameToolBar->m_height;
309
310 m_frameToolBar->m_x = 2;
311 gtk_myfixed_move( GTK_MYFIXED(m_wxwindow), m_frameToolBar->m_widget, 2, y );
312 gtk_widget_set_usize( m_frameToolBar->m_widget, m_width-3, h );
362c6693 313 }
46dc76ba 314
c801d85f
KB
315 if (m_frameStatusBar)
316 {
6ca41e57
RR
317 // OK, this hurts in the eye, but I don't want to call SetSize()
318 // because I don't want to call any non-native functions here.
319 m_frameStatusBar->m_x = 0;
320 m_frameStatusBar->m_y = m_height-wxSTATUS_HEIGHT;
321 m_frameStatusBar->m_width = m_width;
322 m_frameStatusBar->m_height = wxSTATUS_HEIGHT;
323 gtk_myfixed_move( GTK_MYFIXED(m_wxwindow), m_frameStatusBar->m_widget, 0, m_height-wxSTATUS_HEIGHT );
324 gtk_widget_set_usize( m_frameStatusBar->m_widget, m_width, wxSTATUS_HEIGHT );
362c6693 325 }
c801d85f
KB
326
327 m_sizeSet = TRUE;
ed7a557b 328
c801d85f
KB
329 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
330 event.SetEventObject( this );
331 ProcessEvent( event );
362c6693 332}
c801d85f
KB
333
334void wxFrame::OnSize( wxSizeEvent &WXUNUSED(event) )
335{
e55ad60e
RR
336 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
337
ed7a557b
VZ
338 if ( GetAutoLayout() )
339 Layout();
340 else {
cf5f9c9c
GL
341 // no child: go out !
342 if (!GetChildren()->First())
343 return;
46dc76ba 344
ed7a557b 345 // do we have exactly one child?
c67daf87 346 wxWindow *child = (wxWindow *) NULL;
ed7a557b 347 for(wxNode *node = GetChildren()->First(); node; node = node->Next())
c801d85f 348 {
ed7a557b 349 wxWindow *win = (wxWindow *)node->Data();
e3e65dac 350 if (!IS_KIND_OF(win,wxFrame) && !IS_KIND_OF(win,wxDialog)
6ca41e57 351#if 0 // not in m_children anyway ?
ed7a557b 352 && (win != m_frameMenuBar) &&
46dc76ba 353 (win != m_frameToolBar) &&
ed7a557b
VZ
354 (win != m_frameStatusBar)
355#endif
356 )
357 {
358 if ( child ) // it's the second one: do nothing
359 return;
360
361 child = win;
362c6693
RR
362 }
363 }
c801d85f 364
ed7a557b 365 // yes: set it's size to fill all the frame
c801d85f 366 int client_x, client_y;
c801d85f 367 GetClientSize(&client_x, &client_y);
c801d85f
KB
368 child->SetSize( 1, 1, client_x-2, client_y);
369 }
362c6693 370}
c801d85f 371
716b7364 372static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
c801d85f
KB
373{
374 menu->SetInvokingWindow( win );
375 wxNode *node = menu->m_items.First();
376 while (node)
377 {
378 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
19717c50
VZ
379 if (menuitem->IsSubMenu())
380 SetInvokingWindow( menuitem->GetSubMenu(), win );
c801d85f 381 node = node->Next();
362c6693
RR
382 }
383}
c801d85f
KB
384
385void wxFrame::SetMenuBar( wxMenuBar *menuBar )
386{
e55ad60e
RR
387 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
388 wxASSERT_MSG( (m_wxwindow != NULL), "invalid frame" );
e55ad60e 389
c801d85f 390 m_frameMenuBar = menuBar;
716b7364
RR
391
392 if (m_frameMenuBar)
c801d85f 393 {
30dea054
RR
394 wxNode *node = m_frameMenuBar->m_menus.First();
395 while (node)
396 {
397 wxMenu *menu = (wxMenu*)node->Data();
398 SetInvokingWindow( menu, this );
399 node = node->Next();
362c6693 400 }
30dea054 401
716b7364
RR
402 if (m_frameMenuBar->m_parent != this)
403 {
716b7364 404 m_frameMenuBar->m_parent = this;
6ca41e57 405 gtk_myfixed_put( GTK_MYFIXED(m_wxwindow),
716b7364
RR
406 m_frameMenuBar->m_widget, m_frameMenuBar->m_x, m_frameMenuBar->m_y );
407 }
408 }
362c6693 409}
c801d85f 410
362c6693 411wxMenuBar *wxFrame::GetMenuBar(void) const
46dc76ba
RR
412{
413 return m_frameMenuBar;
362c6693 414}
46dc76ba 415
362c6693 416wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& name)
46dc76ba 417{
e55ad60e
RR
418 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
419
362c6693
RR
420 wxCHECK_MSG( m_frameToolBar == NULL, FALSE, "recreating toolbar in wxFrame" );
421
362c6693 422 m_frameToolBar = OnCreateToolBar( style, id, name );
6ca41e57
RR
423
424 GetChildren()->DeleteObject( m_frameToolBar );
46dc76ba
RR
425
426 return m_frameToolBar;
362c6693 427}
46dc76ba 428
362c6693 429wxToolBar* wxFrame::OnCreateToolBar( long style, wxWindowID id, const wxString& name )
46dc76ba 430{
362c6693
RR
431 return new wxToolBar( this, id, wxDefaultPosition, wxDefaultSize, style, name );
432}
433
434wxToolBar *wxFrame::GetToolBar(void) const
435{
436 return m_frameToolBar;
437}
46dc76ba 438
e3e65dac 439wxStatusBar* wxFrame::CreateStatusBar( int number, long style, wxWindowID id, const wxString& name )
c801d85f 440{
e55ad60e
RR
441 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
442
362c6693 443 wxCHECK_MSG( m_frameStatusBar == NULL, FALSE, "recreating status bar in wxFrame" );
c801d85f 444
362c6693 445 m_frameStatusBar = OnCreateStatusBar( number, style, id, name );
e3e65dac
RR
446
447 return m_frameStatusBar;
362c6693
RR
448}
449
450wxStatusBar *wxFrame::OnCreateStatusBar( int number, long style, wxWindowID id, const wxString& name )
451{
c67daf87 452 wxStatusBar *statusBar = (wxStatusBar *) NULL;
362c6693
RR
453
454 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 20), style, name);
455
456 // Set the height according to the font and the border size
457 wxClientDC dc(statusBar);
458 dc.SetFont( *statusBar->GetFont() );
459
460 long x, y;
461 dc.GetTextExtent( "X", &x, &y );
462
463 int height = (int)( (y * 1.1) + 2* statusBar->GetBorderY());
464
465 statusBar->SetSize( -1, -1, 100, height );
466
467 statusBar->SetFieldsCount( number );
468 return statusBar;
469}
c801d85f 470
362c6693 471void wxFrame::SetStatusText(const wxString& text, int number)
c801d85f 472{
e55ad60e
RR
473 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
474
362c6693 475 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set text for" );
c801d85f 476
362c6693
RR
477 m_frameStatusBar->SetStatusText(text, number);
478}
479
480void wxFrame::SetStatusWidths(int n, const int widths_field[] )
c801d85f 481{
e55ad60e
RR
482 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
483
362c6693
RR
484 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set widths for" );
485
486 m_frameStatusBar->SetStatusWidths(n, widths_field);
487}
c801d85f 488
362c6693 489wxStatusBar *wxFrame::GetStatusBar(void) const
c801d85f
KB
490{
491 return m_frameStatusBar;
362c6693 492}
c801d85f 493
c801d85f
KB
494void wxFrame::SetTitle( const wxString &title )
495{
e55ad60e
RR
496 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
497
c801d85f 498 m_title = title;
362c6693 499 if (m_title.IsNull()) m_title = "";
c801d85f 500 gtk_window_set_title( GTK_WINDOW(m_widget), title );
362c6693 501}
c801d85f 502
d355d3fe
RR
503void wxFrame::SetIcon( const wxIcon &icon )
504{
e55ad60e
RR
505 wxASSERT_MSG( (m_widget != NULL), "invalid frame" );
506
d355d3fe
RR
507 m_icon = icon;
508 if (!icon.Ok()) return;
509
510 wxMask *mask = icon.GetMask();
c67daf87 511 GdkBitmap *bm = (GdkBitmap *) NULL;
d355d3fe
RR
512 if (mask) bm = mask->GetBitmap();
513
c67daf87 514 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
d355d3fe 515}