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