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