GtkOnSize parameters aren't useful
[wxWidgets.git] / src / gtk / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/frame.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 #include "wx/frame.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/app.h"
25 #include "wx/dcclient.h"
26 #include "wx/menu.h"
27 #include "wx/dialog.h"
28 #include "wx/control.h"
29 #include "wx/toolbar.h"
30 #include "wx/statusbr.h"
31 #endif // WX_PRECOMP
32
33 #include <glib.h>
34 #include "wx/gtk/private.h"
35
36 #include <gdk/gdkkeysyms.h>
37 #include <gdk/gdkx.h>
38
39 #include "wx/gtk/win_gtk.h"
40
41 // ----------------------------------------------------------------------------
42 // constants
43 // ----------------------------------------------------------------------------
44
45 const int wxSTATUS_HEIGHT = 25;
46 const int wxPLACE_HOLDER = 0;
47
48 // ----------------------------------------------------------------------------
49 // event tables
50 // ----------------------------------------------------------------------------
51
52 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxTopLevelWindow)
53
54 // ============================================================================
55 // implementation
56 // ============================================================================
57
58 // ----------------------------------------------------------------------------
59 // GTK callbacks
60 // ----------------------------------------------------------------------------
61
62 #if wxUSE_MENUS_NATIVE
63
64 //-----------------------------------------------------------------------------
65 // "child_attached" of menu bar
66 //-----------------------------------------------------------------------------
67
68 extern "C" {
69 static void gtk_menu_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
70 {
71 if (!win->m_hasVMT) return;
72
73 win->m_menuBarDetached = false;
74 win->GtkUpdateSize();
75 }
76 }
77
78 //-----------------------------------------------------------------------------
79 // "child_detached" of menu bar
80 //-----------------------------------------------------------------------------
81
82 extern "C" {
83 static void gtk_menu_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
84 {
85 if (g_isIdle)
86 wxapp_install_idle_handler();
87
88 if (!win->m_hasVMT) return;
89
90 // Raise the client area area
91 gdk_window_raise( win->m_wxwindow->window );
92
93 win->m_menuBarDetached = true;
94 win->GtkUpdateSize();
95 }
96 }
97
98 #endif // wxUSE_MENUS_NATIVE
99
100 #if wxUSE_TOOLBAR
101 //-----------------------------------------------------------------------------
102 // "child_attached" of tool bar
103 //-----------------------------------------------------------------------------
104
105 extern "C" {
106 static void gtk_toolbar_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
107 {
108 if (!win->m_hasVMT) return;
109
110 win->m_toolBarDetached = false;
111 win->GtkUpdateSize();
112 }
113 }
114
115 //-----------------------------------------------------------------------------
116 // "child_detached" of tool bar
117 //-----------------------------------------------------------------------------
118
119 extern "C" {
120 static void gtk_toolbar_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
121 {
122 if (g_isIdle)
123 wxapp_install_idle_handler();
124
125 if (!win->m_hasVMT) return;
126
127 // Raise the client area area
128 gdk_window_raise( win->m_wxwindow->window );
129
130 win->m_toolBarDetached = true;
131 win->GtkUpdateSize();
132 }
133 }
134 #endif // wxUSE_TOOLBAR
135
136
137 // ----------------------------------------------------------------------------
138 // wxFrame itself
139 // ----------------------------------------------------------------------------
140
141 //-----------------------------------------------------------------------------
142 // InsertChild for wxFrame
143 //-----------------------------------------------------------------------------
144
145 /* Callback for wxFrame. This very strange beast has to be used because
146 * C++ has no virtual methods in a constructor. We have to emulate a
147 * virtual function here as wxWidgets requires different ways to insert
148 * a child in container classes. */
149
150 static void wxInsertChildInFrame( wxFrame* parent, wxWindow* child )
151 {
152 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
153
154 if (!parent->m_insertInClientArea)
155 {
156 // These are outside the client area
157 wxFrame* frame = (wxFrame*) parent;
158 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
159 GTK_WIDGET(child->m_widget),
160 child->m_x,
161 child->m_y,
162 child->m_width,
163 child->m_height );
164
165 #if wxUSE_TOOLBAR_NATIVE
166 // We connect to these events for recalculating the client area
167 // space when the toolbar is floating
168 if (wxIS_KIND_OF(child,wxToolBar))
169 {
170 wxToolBar *toolBar = (wxToolBar*) child;
171 if (toolBar->GetWindowStyle() & wxTB_DOCKABLE)
172 {
173 g_signal_connect (toolBar->m_widget, "child_attached",
174 G_CALLBACK (gtk_toolbar_attached_callback),
175 parent);
176 g_signal_connect (toolBar->m_widget, "child_detached",
177 G_CALLBACK (gtk_toolbar_detached_callback),
178 parent);
179 }
180 }
181 #endif // wxUSE_TOOLBAR
182 }
183 else
184 {
185 // These are inside the client area
186 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
187 GTK_WIDGET(child->m_widget),
188 child->m_x,
189 child->m_y,
190 child->m_width,
191 child->m_height );
192 }
193 }
194
195 // ----------------------------------------------------------------------------
196 // wxFrame creation
197 // ----------------------------------------------------------------------------
198
199 void wxFrame::Init()
200 {
201 m_menuBarDetached = false;
202 m_toolBarDetached = false;
203 m_menuBarHeight = 2;
204 }
205
206 bool wxFrame::Create( wxWindow *parent,
207 wxWindowID id,
208 const wxString& title,
209 const wxPoint& pos,
210 const wxSize& sizeOrig,
211 long style,
212 const wxString &name )
213 {
214 bool rt = wxTopLevelWindow::Create(parent, id, title, pos, sizeOrig,
215 style, name);
216 m_insertCallback = (wxInsertChildFunction) wxInsertChildInFrame;
217
218 return rt;
219 }
220
221 wxFrame::~wxFrame()
222 {
223 m_isBeingDeleted = true;
224 DeleteAllBars();
225 }
226
227 // ----------------------------------------------------------------------------
228 // overridden wxWindow methods
229 // ----------------------------------------------------------------------------
230
231 void wxFrame::DoGetClientSize( int *width, int *height ) const
232 {
233 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
234
235 wxTopLevelWindow::DoGetClientSize( width, height );
236
237 if (height)
238 {
239 #if wxUSE_MENUS_NATIVE
240 // menu bar
241 if (m_frameMenuBar)
242 {
243 if (!m_menuBarDetached)
244 (*height) -= m_menuBarHeight;
245 else
246 (*height) -= wxPLACE_HOLDER;
247 }
248 #endif // wxUSE_MENUS_NATIVE
249
250 #if wxUSE_STATUSBAR
251 // status bar
252 if (m_frameStatusBar && m_frameStatusBar->IsShown())
253 (*height) -= wxSTATUS_HEIGHT;
254 #endif // wxUSE_STATUSBAR
255
256 #if wxUSE_TOOLBAR
257 // tool bar
258 if (m_frameToolBar && m_frameToolBar->IsShown())
259 {
260 if (m_toolBarDetached)
261 {
262 *height -= wxPLACE_HOLDER;
263 }
264 else
265 {
266 int x, y;
267 m_frameToolBar->GetSize( &x, &y );
268 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
269 {
270 *width -= x;
271 }
272 else
273 {
274 *height -= y;
275 }
276 }
277 }
278 #endif // wxUSE_TOOLBAR
279 }
280 }
281
282 void wxFrame::DoSetClientSize( int width, int height )
283 {
284 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
285
286 #if wxUSE_MENUS_NATIVE
287 // menu bar
288 if (m_frameMenuBar)
289 {
290 if (!m_menuBarDetached)
291 height += m_menuBarHeight;
292 else
293 height += wxPLACE_HOLDER;
294 }
295 #endif // wxUSE_MENUS_NATIVE
296
297 #if wxUSE_STATUSBAR
298 // status bar
299 if (m_frameStatusBar && m_frameStatusBar->IsShown()) height += wxSTATUS_HEIGHT;
300 #endif
301
302 #if wxUSE_TOOLBAR
303 // tool bar
304 if (m_frameToolBar && m_frameToolBar->IsShown())
305 {
306 if (m_toolBarDetached)
307 {
308 height += wxPLACE_HOLDER;
309 }
310 else
311 {
312 int x, y;
313 m_frameToolBar->GetSize( &x, &y );
314 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
315 {
316 width += x;
317 }
318 else
319 {
320 height += y;
321 }
322 }
323 }
324 #endif
325
326 wxTopLevelWindow::DoSetClientSize( width, height );
327 }
328
329 void wxFrame::GtkOnSize()
330 {
331 // avoid recursions
332 if (m_resizing) return;
333 m_resizing = true;
334
335 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
336 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
337
338 // space occupied by m_frameToolBar and m_frameMenuBar
339 int client_area_x_offset = 0,
340 client_area_y_offset = 0;
341
342 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
343 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
344 set in wxFrame::Create so it is used to check what kind of frame we
345 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
346 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
347 importantly) m_mainWidget */
348
349 int minWidth = GetMinWidth(),
350 minHeight = GetMinHeight(),
351 maxWidth = GetMaxWidth(),
352 maxHeight = GetMaxHeight();
353
354 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
355 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
356 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
357 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
358
359 if (m_mainWidget)
360 {
361 // set size hints
362 gint flag = 0; // GDK_HINT_POS;
363 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
364 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
365 GdkGeometry geom;
366 geom.min_width = minWidth;
367 geom.min_height = minHeight;
368 geom.max_width = maxWidth;
369 geom.max_height = maxHeight;
370 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
371 (GtkWidget*) NULL,
372 &geom,
373 (GdkWindowHints) flag );
374
375 // I revert back to wxGTK's original behaviour. m_mainWidget holds
376 // the menubar, the toolbar and the client area, which is represented
377 // by m_wxwindow.
378 // This hurts in the eye, but I don't want to call SetSize()
379 // because I don't want to call any non-native functions here.
380
381 #if wxUSE_MENUS_NATIVE
382 if (m_frameMenuBar)
383 {
384 int xx = m_miniEdge;
385 int yy = m_miniEdge + m_miniTitle;
386 int ww = m_width - 2*m_miniEdge;
387 int hh = m_menuBarHeight;
388 if (m_menuBarDetached) hh = wxPLACE_HOLDER;
389 m_frameMenuBar->m_x = xx;
390 m_frameMenuBar->m_y = yy;
391 m_frameMenuBar->m_width = ww;
392 m_frameMenuBar->m_height = hh;
393 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
394 m_frameMenuBar->m_widget,
395 xx, yy, ww, hh );
396 client_area_y_offset += hh;
397 }
398 #endif // wxUSE_MENUS_NATIVE
399
400 #if wxUSE_TOOLBAR
401 if ((m_frameToolBar) && m_frameToolBar->IsShown() &&
402 (m_frameToolBar->m_widget->parent == m_mainWidget))
403 {
404 int xx = m_miniEdge;
405 int yy = m_miniEdge + m_miniTitle;
406 #if wxUSE_MENUS_NATIVE
407 if (m_frameMenuBar)
408 {
409 if (!m_menuBarDetached)
410 yy += m_menuBarHeight;
411 else
412 yy += wxPLACE_HOLDER;
413 }
414 #endif // wxUSE_MENUS_NATIVE
415
416 m_frameToolBar->m_x = xx;
417 m_frameToolBar->m_y = yy;
418
419 // don't change the toolbar's reported height/width
420 int ww, hh;
421 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
422 {
423 ww = m_toolBarDetached ? wxPLACE_HOLDER
424 : m_frameToolBar->m_width;
425 hh = m_height - 2*m_miniEdge;
426
427 client_area_x_offset += ww;
428 }
429 else
430 {
431 ww = m_width - 2*m_miniEdge;
432 hh = m_toolBarDetached ? wxPLACE_HOLDER
433 : m_frameToolBar->m_height;
434
435 client_area_y_offset += hh;
436 }
437
438 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
439 m_frameToolBar->m_widget,
440 xx, yy, ww, hh );
441 }
442 #endif // wxUSE_TOOLBAR
443
444 int client_x = client_area_x_offset + m_miniEdge;
445 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
446 int client_w = m_width - client_area_x_offset - 2*m_miniEdge;
447 int client_h = m_height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
448 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
449 m_wxwindow,
450 client_x, client_y, client_w, client_h );
451 }
452 else
453 {
454 // If there is no m_mainWidget between m_widget and m_wxwindow there
455 // is no need to set the size or position of m_wxwindow.
456 }
457
458 #if wxUSE_STATUSBAR
459 if (m_frameStatusBar && m_frameStatusBar->IsShown())
460 {
461 int xx = 0 + m_miniEdge;
462 int yy = m_height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
463 int ww = m_width - 2*m_miniEdge;
464 int hh = wxSTATUS_HEIGHT;
465 m_frameStatusBar->m_x = xx;
466 m_frameStatusBar->m_y = yy;
467 m_frameStatusBar->m_width = ww;
468 m_frameStatusBar->m_height = hh;
469 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow),
470 m_frameStatusBar->m_widget,
471 xx, yy, ww, hh );
472 if (GTK_WIDGET_DRAWABLE (m_frameStatusBar->m_widget))
473 {
474 gtk_widget_queue_draw (m_frameStatusBar->m_widget);
475 // FIXME: Do we really want to force an immediate redraw?
476 gdk_window_process_updates (m_frameStatusBar->m_widget->window, TRUE);
477 }
478 }
479 #endif // wxUSE_STATUSBAR
480
481 m_sizeSet = true;
482
483 // send size event to frame
484 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
485 event.SetEventObject( this );
486 GetEventHandler()->ProcessEvent( event );
487
488 #if wxUSE_STATUSBAR
489 // send size event to status bar
490 if (m_frameStatusBar)
491 {
492 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
493 event2.SetEventObject( m_frameStatusBar );
494 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
495 }
496 #endif // wxUSE_STATUSBAR
497
498 m_resizing = false;
499 }
500
501 void wxFrame::OnInternalIdle()
502 {
503 wxFrameBase::OnInternalIdle();
504
505 #if wxUSE_MENUS_NATIVE
506 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
507 #endif // wxUSE_MENUS_NATIVE
508 #if wxUSE_TOOLBAR
509 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
510 #endif
511 #if wxUSE_STATUSBAR
512 if (m_frameStatusBar)
513 {
514 m_frameStatusBar->OnInternalIdle();
515
516 // There may be controls in the status bar that
517 // need to be updated
518 for ( wxWindowList::compatibility_iterator node = m_frameStatusBar->GetChildren().GetFirst();
519 node;
520 node = node->GetNext() )
521 {
522 wxWindow *child = node->GetData();
523 child->OnInternalIdle();
524 }
525 }
526 #endif
527 }
528
529 // ----------------------------------------------------------------------------
530 // menu/tool/status bar stuff
531 // ----------------------------------------------------------------------------
532
533 #if wxUSE_MENUS_NATIVE
534
535 void wxFrame::DetachMenuBar()
536 {
537 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
538 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
539
540 if ( m_frameMenuBar )
541 {
542 m_frameMenuBar->UnsetInvokingWindow( this );
543
544 if (m_frameMenuBar->GetWindowStyle() & wxMB_DOCKABLE)
545 {
546 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
547 (gpointer) gtk_menu_attached_callback,
548 this);
549
550 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
551 (gpointer) gtk_menu_detached_callback,
552 this);
553 }
554
555 gtk_widget_ref( m_frameMenuBar->m_widget );
556
557 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
558 }
559
560 wxFrameBase::DetachMenuBar();
561 }
562
563 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
564 {
565 wxFrameBase::AttachMenuBar(menuBar);
566
567 if (m_frameMenuBar)
568 {
569 m_frameMenuBar->SetInvokingWindow( this );
570
571 m_frameMenuBar->SetParent(this);
572 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
573 m_frameMenuBar->m_widget,
574 m_frameMenuBar->m_x,
575 m_frameMenuBar->m_y,
576 m_frameMenuBar->m_width,
577 m_frameMenuBar->m_height );
578
579 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
580 {
581 g_signal_connect (menuBar->m_widget, "child_attached",
582 G_CALLBACK (gtk_menu_attached_callback),
583 this);
584 g_signal_connect (menuBar->m_widget, "child_detached",
585 G_CALLBACK (gtk_menu_detached_callback),
586 this);
587 }
588
589 gtk_widget_show( m_frameMenuBar->m_widget );
590
591 UpdateMenuBarSize();
592 }
593 else
594 {
595 m_menuBarHeight = 2;
596 GtkUpdateSize(); // resize window in OnInternalIdle
597 }
598 }
599
600 void wxFrame::UpdateMenuBarSize()
601 {
602 GtkRequisition req;
603
604 req.width = 2;
605 req.height = 2;
606
607 // this is called after Remove with a NULL m_frameMenuBar
608 if ( m_frameMenuBar )
609 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_frameMenuBar->m_widget) )->size_request )
610 (m_frameMenuBar->m_widget, &req );
611
612 m_menuBarHeight = req.height;
613
614 // resize window in OnInternalIdle
615
616 GtkUpdateSize();
617 }
618
619 #endif // wxUSE_MENUS_NATIVE
620
621 #if wxUSE_TOOLBAR
622
623 wxToolBar* wxFrame::CreateToolBar( long style, wxWindowID id, const wxString& name )
624 {
625 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
626
627 m_insertInClientArea = false;
628
629 m_frameToolBar = wxFrameBase::CreateToolBar( style, id, name );
630
631 m_insertInClientArea = true;
632
633 GtkUpdateSize();
634
635 return m_frameToolBar;
636 }
637
638 void wxFrame::SetToolBar(wxToolBar *toolbar)
639 {
640 bool hadTbar = m_frameToolBar != NULL;
641
642 wxFrameBase::SetToolBar(toolbar);
643
644 if ( m_frameToolBar )
645 {
646 // insert into toolbar area if not already there
647 if ((m_frameToolBar->m_widget->parent) &&
648 (m_frameToolBar->m_widget->parent != m_mainWidget))
649 {
650 GetChildren().DeleteObject( m_frameToolBar );
651
652 gtk_widget_reparent( m_frameToolBar->m_widget, m_mainWidget );
653 GtkUpdateSize();
654 }
655 }
656 else // toolbar unset
657 {
658 // still need to update size if it had been there before
659 if ( hadTbar )
660 {
661 GtkUpdateSize();
662 }
663 }
664 }
665
666 #endif // wxUSE_TOOLBAR
667
668 #if wxUSE_STATUSBAR
669
670 wxStatusBar* wxFrame::CreateStatusBar(int number,
671 long style,
672 wxWindowID id,
673 const wxString& name)
674 {
675 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
676
677 // because it will change when toolbar is added
678 GtkUpdateSize();
679
680 return wxFrameBase::CreateStatusBar( number, style, id, name );
681 }
682
683 void wxFrame::SetStatusBar(wxStatusBar *statbar)
684 {
685 bool hadStatBar = m_frameStatusBar != NULL;
686
687 wxFrameBase::SetStatusBar(statbar);
688
689 if (hadStatBar && !m_frameStatusBar)
690 GtkUpdateSize();
691 }
692
693 void wxFrame::PositionStatusBar()
694 {
695 if ( !m_frameStatusBar )
696 return;
697
698 GtkUpdateSize();
699 }
700 #endif // wxUSE_STATUSBAR