Changed SetToolBar() to behave a bit smarter. Untested.
[wxWidgets.git] / src / gtk1 / 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 #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"
18 #include "wx/menu.h"
19 #if wxUSE_TOOLBAR
20 #include "wx/toolbar.h"
21 #endif
22 #if wxUSE_STATUSBAR
23 #include "wx/statusbr.h"
24 #endif
25 #include "wx/dcclient.h"
26
27 #include "glib.h"
28 #include "gdk/gdk.h"
29 #include "gtk/gtk.h"
30 #include "wx/gtk/win_gtk.h"
31 #include "gdk/gdkkeysyms.h"
32 #include "gdk/gdkx.h"
33
34 //-----------------------------------------------------------------------------
35 // constants
36 //-----------------------------------------------------------------------------
37
38 const int wxMENU_HEIGHT = 27;
39 const int wxSTATUS_HEIGHT = 25;
40 const int wxPLACE_HOLDER = 0;
41
42 //-----------------------------------------------------------------------------
43 // idle system
44 //-----------------------------------------------------------------------------
45
46 extern void wxapp_install_idle_handler();
47 extern bool g_isIdle;
48
49 //-----------------------------------------------------------------------------
50 // data
51 //-----------------------------------------------------------------------------
52
53 extern wxList wxPendingDelete;
54
55 //-----------------------------------------------------------------------------
56 // debug
57 //-----------------------------------------------------------------------------
58
59 #ifdef __WXDEBUG__
60
61 extern void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window );
62
63 #endif
64
65 //-----------------------------------------------------------------------------
66 // "size_allocate"
67 //-----------------------------------------------------------------------------
68
69 static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxFrame *win )
70 {
71 if (g_isIdle)
72 wxapp_install_idle_handler();
73
74 if (!win->m_hasVMT) return;
75
76 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
77 {
78 win->m_width = alloc->width;
79 win->m_height = alloc->height;
80 win->UpdateSize();
81 }
82 }
83
84 //-----------------------------------------------------------------------------
85 // "delete_event"
86 //-----------------------------------------------------------------------------
87
88 static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxFrame *win )
89 {
90 if (g_isIdle)
91 wxapp_install_idle_handler();
92
93 win->Close();
94
95 return TRUE;
96 }
97
98 //-----------------------------------------------------------------------------
99 // "child_attached" of menu bar
100 //-----------------------------------------------------------------------------
101
102 static void gtk_menu_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
103 {
104 if (!win->m_hasVMT) return;
105
106 win->m_menuBarDetached = FALSE;
107 win->UpdateSize();
108 }
109
110 //-----------------------------------------------------------------------------
111 // "child_detached" of menu bar
112 //-----------------------------------------------------------------------------
113
114 static void gtk_menu_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
115 {
116 if (!win->m_hasVMT) return;
117
118 win->m_menuBarDetached = TRUE;
119 win->UpdateSize();
120 }
121
122 #if wxUSE_TOOLBAR
123 //-----------------------------------------------------------------------------
124 // "child_attached" of tool bar
125 //-----------------------------------------------------------------------------
126
127 static void gtk_toolbar_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
128 {
129 if (!win->m_hasVMT) return;
130
131 win->m_toolBarDetached = FALSE;
132
133 win->UpdateSize();
134 }
135
136 //-----------------------------------------------------------------------------
137 // "child_detached" of tool bar
138 //-----------------------------------------------------------------------------
139
140 static void gtk_toolbar_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
141 {
142 if (g_isIdle)
143 wxapp_install_idle_handler();
144
145 if (!win->m_hasVMT) return;
146
147 win->m_toolBarDetached = TRUE;
148 win->UpdateSize();
149 }
150 #endif // wxUSE_TOOLBAR
151
152 //-----------------------------------------------------------------------------
153 // "configure_event"
154 //-----------------------------------------------------------------------------
155
156 static gint
157 #if (GTK_MINOR_VERSON > 0)
158 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WXUNUSED(event), wxFrame *win )
159 #else
160 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *event, wxFrame *win )
161 #endif
162 {
163 if (g_isIdle)
164 wxapp_install_idle_handler();
165
166 if (!win->m_hasVMT) return FALSE;
167
168 #if (GTK_MINOR_VERSON > 0)
169 int x = 0;
170 int y = 0;
171 gdk_window_get_root_origin( win->m_widget->window, &x, &y );
172 win->m_x = x;
173 win->m_y = y;
174 #else
175 win->m_x = event->x;
176 win->m_y = event->y;
177 #endif
178
179 wxMoveEvent mevent( wxPoint(win->m_x,win->m_y), win->GetId() );
180 mevent.SetEventObject( win );
181 win->GetEventHandler()->ProcessEvent( mevent );
182
183 return FALSE;
184 }
185
186 //-----------------------------------------------------------------------------
187 // "realize" from m_widget
188 //-----------------------------------------------------------------------------
189
190 /* we cannot MWM hints and icons before the widget has been realized,
191 so we do this directly after realization */
192
193 static gint
194 gtk_frame_realized_callback( GtkWidget *WXUNUSED(widget), wxFrame *win )
195 {
196 if (g_isIdle)
197 wxapp_install_idle_handler();
198
199 /* all this is for Motif Window Manager "hints" and is supposed to be
200 recognized by other WM as well. not tested. */
201 long decor = (long) GDK_DECOR_BORDER;
202 long func = (long) GDK_FUNC_MOVE;
203
204 if ((win->GetWindowStyle() & wxCAPTION) != 0)
205 decor |= GDK_DECOR_TITLE;
206 if ((win->GetWindowStyle() & wxSYSTEM_MENU) != 0)
207 {
208 decor |= GDK_DECOR_MENU;
209 func |= GDK_FUNC_CLOSE;
210 }
211 if ((win->GetWindowStyle() & wxMINIMIZE_BOX) != 0)
212 {
213 func |= GDK_FUNC_MINIMIZE;
214 decor |= GDK_DECOR_MINIMIZE;
215 }
216 if ((win->GetWindowStyle() & wxMAXIMIZE_BOX) != 0)
217 {
218 func |= GDK_FUNC_MAXIMIZE;
219 decor |= GDK_DECOR_MAXIMIZE;
220 }
221 if ((win->GetWindowStyle() & wxRESIZE_BORDER) != 0)
222 {
223 func |= GDK_FUNC_RESIZE;
224 decor |= GDK_DECOR_RESIZEH;
225 }
226
227 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
228 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
229
230 /* GTK's shrinking/growing policy */
231 if ((win->GetWindowStyle() & wxRESIZE_BORDER) == 0)
232 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
233 else
234 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
235
236 /* reset the icon */
237 if (win->m_icon != wxNullIcon)
238 {
239 wxIcon icon( win->m_icon );
240 win->m_icon = wxNullIcon;
241 win->SetIcon( icon );
242 }
243
244 /* we set the focus to the child that accepts the focus. this
245 doesn't really have to be done in "realize" but why not? */
246 wxWindowList::Node *node = win->GetChildren().GetFirst();
247 while (node)
248 {
249 wxWindow *child = node->GetData();
250 if (child->AcceptsFocus())
251 {
252 child->SetFocus();
253 break;
254 }
255
256 node = node->GetNext();
257 }
258
259 return FALSE;
260 }
261
262 //-----------------------------------------------------------------------------
263 // InsertChild for wxFrame
264 //-----------------------------------------------------------------------------
265
266 /* Callback for wxFrame. This very strange beast has to be used because
267 * C++ has no virtual methods in a constructor. We have to emulate a
268 * virtual function here as wxWindows requires different ways to insert
269 * a child in container classes. */
270
271 static void wxInsertChildInFrame( wxFrame* parent, wxWindow* child )
272 {
273 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
274
275 if (!parent->m_insertInClientArea)
276 {
277 /* these are outside the client area */
278 wxFrame* frame = (wxFrame*) parent;
279 gtk_myfixed_put( GTK_MYFIXED(frame->m_mainWidget),
280 GTK_WIDGET(child->m_widget),
281 child->m_x,
282 child->m_y,
283 child->m_width,
284 child->m_height );
285
286 #if wxUSE_TOOLBAR
287 /* we connect to these events for recalculating the client area
288 space when the toolbar is floating */
289 if (wxIS_KIND_OF(child,wxToolBar))
290 {
291 wxToolBar *toolBar = (wxToolBar*) child;
292 if (toolBar->GetWindowStyle() & wxTB_DOCKABLE)
293 {
294 gtk_signal_connect( GTK_OBJECT(toolBar->m_widget), "child_attached",
295 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback), (gpointer)parent );
296
297 gtk_signal_connect( GTK_OBJECT(toolBar->m_widget), "child_detached",
298 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback), (gpointer)parent );
299 }
300 }
301 #endif // wxUSE_TOOLBAR
302 }
303 else
304 {
305 /* these are inside the client area */
306 gtk_myfixed_put( GTK_MYFIXED(parent->m_wxwindow),
307 GTK_WIDGET(child->m_widget),
308 child->m_x,
309 child->m_y,
310 child->m_width,
311 child->m_height );
312 }
313
314 /* resize on OnInternalIdle */
315 parent->UpdateSize();
316 }
317
318 //-----------------------------------------------------------------------------
319 // wxFrame
320 //-----------------------------------------------------------------------------
321
322 BEGIN_EVENT_TABLE(wxFrame, wxWindow)
323 EVT_SIZE(wxFrame::OnSize)
324 EVT_CLOSE(wxFrame::OnCloseWindow)
325 EVT_MENU_HIGHLIGHT_ALL(wxFrame::OnMenuHighlight)
326 END_EVENT_TABLE()
327
328 IMPLEMENT_DYNAMIC_CLASS(wxFrame,wxWindow)
329
330 void wxFrame::Init()
331 {
332 m_frameMenuBar = (wxMenuBar *) NULL;
333 #if wxUSE_STATUSBAR
334 m_frameStatusBar = (wxStatusBar *) NULL;
335 #endif // wxUSE_STATUSBAR
336 #if wxUSE_TOOLBAR
337 m_frameToolBar = (wxToolBar *) NULL;
338 #endif // wxUSE_TOOLBAR
339 m_sizeSet = FALSE;
340 m_miniEdge = 0;
341 m_miniTitle = 0;
342 m_mainWidget = (GtkWidget*) NULL;
343 m_menuBarDetached = FALSE;
344 m_toolBarDetached = FALSE;
345 m_insertInClientArea = TRUE;
346 }
347
348 wxFrame::wxFrame( wxWindow *parent, wxWindowID id, const wxString &title,
349 const wxPoint &pos, const wxSize &size,
350 long style, const wxString &name )
351 {
352 Init();
353
354 Create( parent, id, title, pos, size, style, name );
355 }
356
357 bool wxFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
358 const wxPoint &pos, const wxSize &size,
359 long style, const wxString &name )
360 {
361 wxTopLevelWindows.Append( this );
362
363 m_needParent = FALSE;
364
365 if (!PreCreation( parent, pos, size ) ||
366 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
367 {
368 wxFAIL_MSG( wxT("wxFrame creation failed") );
369 return FALSE;
370 }
371
372 m_title = title;
373
374 m_insertCallback = (wxInsertChildFunction) wxInsertChildInFrame;
375
376 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
377 if (style & wxSIMPLE_BORDER) win_type = GTK_WINDOW_POPUP;
378
379 m_widget = gtk_window_new( win_type );
380
381 if (!name.IsEmpty())
382 gtk_window_set_wmclass( GTK_WINDOW(m_widget), name.mb_str(), name.mb_str() );
383
384 #ifdef __WXDEBUG__
385 debug_focus_in( m_widget, wxT("wxFrame::m_widget"), name );
386 #endif
387
388 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
389 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
390
391 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
392 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
393
394 /* m_mainWidget holds the toolbar, the menubar and the client area */
395 m_mainWidget = gtk_myfixed_new();
396 gtk_widget_show( m_mainWidget );
397 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
398 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
399
400 #ifdef __WXDEBUG__
401 debug_focus_in( m_mainWidget, wxT("wxFrame::m_mainWidget"), name );
402 #endif
403
404 /* m_wxwindow only represents the client area without toolbar and menubar */
405 m_wxwindow = gtk_myfixed_new();
406 gtk_widget_show( m_wxwindow );
407 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
408
409 #ifdef __WXDEBUG__
410 debug_focus_in( m_wxwindow, wxT("wxFrame::m_wxwindow"), name );
411 #endif
412
413 /* we donm't allow the frame to get the focus as otherwise
414 the frame will grabit at arbitrary fcous changes. */
415 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
416
417 if (m_parent) m_parent->AddChild( this );
418
419 PostCreation();
420
421 /* we cannot set MWM hints and icons before the widget has
422 been realized, so we do this directly after realization */
423 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
424 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
425
426 /* the user resized the frame by dragging etc. */
427 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
428 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
429
430 /* the only way to get the window size is to connect to this event */
431 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
432 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
433
434 return TRUE;
435 }
436
437 wxFrame::~wxFrame()
438 {
439 m_isBeingDeleted = TRUE;
440
441 if (m_frameMenuBar) delete m_frameMenuBar;
442 m_frameMenuBar = (wxMenuBar *) NULL;
443
444 #if wxUSE_STATUSBAR
445 if (m_frameStatusBar) delete m_frameStatusBar;
446 m_frameStatusBar = (wxStatusBar *) NULL;
447 #endif // wxUSE_STATUSBAR
448
449 #if wxUSE_TOOLBAR
450 if (m_frameToolBar) delete m_frameToolBar;
451 m_frameToolBar = (wxToolBar *) NULL;
452 #endif // wxUSE_TOOLBAR
453
454 wxTopLevelWindows.DeleteObject( this );
455
456 if (wxTheApp->GetTopWindow() == this)
457 wxTheApp->SetTopWindow( (wxWindow*) NULL );
458
459 if (wxTopLevelWindows.Number() == 0)
460 wxTheApp->ExitMainLoop();
461 }
462
463 bool wxFrame::Show( bool show )
464 {
465 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
466
467 if (show && !m_sizeSet)
468 {
469 /* by calling GtkOnSize here, we don't have to call
470 either after showing the frame, which would entail
471 much ugly flicker or from within the size_allocate
472 handler, because GTK 1.1.X forbids that. */
473
474 GtkOnSize( m_x, m_y, m_width, m_height );
475 }
476
477 return wxWindow::Show( show );
478 }
479
480 bool wxFrame::Destroy()
481 {
482 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
483
484 if (!wxPendingDelete.Member(this)) wxPendingDelete.Append(this);
485
486 return TRUE;
487 }
488
489 void wxFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
490 {
491 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
492
493 /* this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
494 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
495
496 /* avoid recursions */
497 if (m_resizing) return;
498 m_resizing = TRUE;
499
500 int old_x = m_x;
501 int old_y = m_y;
502 int old_width = m_width;
503 int old_height = m_height;
504
505 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
506 {
507 if (x != -1) m_x = x;
508 if (y != -1) m_y = y;
509 if (width != -1) m_width = width;
510 if (height != -1) m_height = height;
511 }
512 else
513 {
514 m_x = x;
515 m_y = y;
516 m_width = width;
517 m_height = height;
518 }
519
520 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
521 {
522 if (width == -1) m_width = 80;
523 }
524
525 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
526 {
527 if (height == -1) m_height = 26;
528 }
529
530 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
531 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
532 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
533 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
534
535 if ((m_x != -1) || (m_y != -1))
536 {
537 if ((m_x != old_x) || (m_y != old_y))
538 {
539 gtk_widget_set_uposition( m_widget, m_x, m_y );
540 }
541 }
542
543 if ((m_width != old_width) || (m_height != old_height))
544 {
545 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
546 done either directly before the frame is shown or in idle time
547 so that different calls to SetSize() don't lead to flicker. */
548 m_sizeSet = FALSE;
549 }
550
551 m_resizing = FALSE;
552 }
553
554 void wxFrame::Centre( int direction )
555 {
556 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
557
558 int x = 0;
559 int y = 0;
560
561 if ((direction & wxHORIZONTAL) == wxHORIZONTAL) x = (gdk_screen_width () - m_width) / 2;
562 if ((direction & wxVERTICAL) == wxVERTICAL) y = (gdk_screen_height () - m_height) / 2;
563
564 Move( x, y );
565 }
566
567 void wxFrame::DoGetClientSize( int *width, int *height ) const
568 {
569 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
570
571 wxWindow::DoGetClientSize( width, height );
572 if (height)
573 {
574 /* menu bar */
575 if (m_frameMenuBar)
576 {
577 if (!m_menuBarDetached)
578 (*height) -= wxMENU_HEIGHT;
579 else
580 (*height) -= wxPLACE_HOLDER;
581 }
582
583 #if wxUSE_STATUSBAR
584 /* status bar */
585 if (m_frameStatusBar) (*height) -= wxSTATUS_HEIGHT;
586 #endif
587
588 #if wxUSE_TOOLBAR
589 /* tool bar */
590 if (m_frameToolBar)
591 {
592 if (!m_toolBarDetached)
593 {
594 int y = 0;
595 m_frameToolBar->GetSize( (int *) NULL, &y );
596 (*height) -= y;
597 }
598 else
599 (*height) -= wxPLACE_HOLDER;
600 }
601 #endif
602
603 /* mini edge */
604 (*height) -= m_miniEdge*2 + m_miniTitle;
605 }
606 if (width)
607 {
608 (*width) -= m_miniEdge*2;
609 }
610 }
611
612 void wxFrame::DoSetClientSize( int width, int height )
613 {
614 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
615
616 /* menu bar */
617 if (m_frameMenuBar)
618 {
619 if (!m_menuBarDetached)
620 height += wxMENU_HEIGHT;
621 else
622 height += wxPLACE_HOLDER;
623 }
624
625 #if wxUSE_STATUSBAR
626 /* status bar */
627 if (m_frameStatusBar) height += wxSTATUS_HEIGHT;
628 #endif
629
630 #if wxUSE_TOOLBAR
631 /* tool bar */
632 if (m_frameToolBar)
633 {
634 if (!m_toolBarDetached)
635 {
636 int y = 0;
637 m_frameToolBar->GetSize( (int *) NULL, &y );
638 height += y;
639 }
640 else
641 height += wxPLACE_HOLDER;
642 }
643 #endif
644
645 wxWindow::DoSetClientSize( width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle );
646 }
647
648 void wxFrame::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y), int width, int height )
649 {
650 // due to a bug in gtk, x,y are always 0
651 // m_x = x;
652 // m_y = y;
653
654 /* avoid recursions */
655 if (m_resizing) return;
656 m_resizing = TRUE;
657
658 /* this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
659 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
660
661 m_width = width;
662 m_height = height;
663
664 /* space occupied by m_frameToolBar and m_frameMenuBar */
665 int client_area_y_offset = 0;
666
667 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
668 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
669 set in wxFrame::Create so it is used to check what kind of frame we
670 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
671 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
672 importantly) m_mainWidget */
673
674 if (m_mainWidget)
675 {
676 /* check if size is in legal range */
677 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
678 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
679 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
680 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
681
682 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
683 * menubar, the toolbar and the client area, which is represented by
684 * m_wxwindow.
685 * this hurts in the eye, but I don't want to call SetSize()
686 * because I don't want to call any non-native functions here. */
687
688 if (m_frameMenuBar)
689 {
690 int xx = m_miniEdge;
691 int yy = m_miniEdge + m_miniTitle;
692 int ww = m_width - 2*m_miniEdge;
693 int hh = wxMENU_HEIGHT;
694 if (m_menuBarDetached) hh = wxPLACE_HOLDER;
695 m_frameMenuBar->m_x = xx;
696 m_frameMenuBar->m_y = yy;
697 m_frameMenuBar->m_width = ww;
698 m_frameMenuBar->m_height = hh;
699 gtk_myfixed_set_size( GTK_MYFIXED(m_mainWidget),
700 m_frameMenuBar->m_widget,
701 xx, yy, ww, hh );
702 client_area_y_offset += hh;
703 }
704
705 #if wxUSE_TOOLBAR
706 if (m_frameToolBar)
707 {
708 int xx = m_miniEdge;
709 int yy = m_miniEdge + m_miniTitle;
710 if (m_frameMenuBar)
711 {
712 if (!m_menuBarDetached)
713 yy += wxMENU_HEIGHT;
714 else
715 yy += wxPLACE_HOLDER;
716 }
717 int ww = m_width - 2*m_miniEdge;
718 int hh = m_frameToolBar->m_height;
719 if (m_toolBarDetached) hh = wxPLACE_HOLDER;
720 m_frameToolBar->m_x = xx;
721 m_frameToolBar->m_y = yy;
722 /* m_frameToolBar->m_height = hh; don't change the toolbar's height */
723 m_frameToolBar->m_width = ww;
724 gtk_myfixed_set_size( GTK_MYFIXED(m_mainWidget),
725 m_frameToolBar->m_widget,
726 xx, yy, ww, hh );
727 client_area_y_offset += hh;
728 }
729 #endif
730
731 int client_x = m_miniEdge;
732 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
733 int client_w = m_width - 2*m_miniEdge;
734 int client_h = m_height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
735 gtk_myfixed_set_size( GTK_MYFIXED(m_mainWidget),
736 m_wxwindow,
737 client_x, client_y, client_w, client_h );
738 }
739 else
740 {
741 /* if there is no m_mainWidget between m_widget and m_wxwindow there
742 is no need to set the size or position of m_wxwindow. */
743 }
744
745 #if wxUSE_STATUSBAR
746 if (m_frameStatusBar)
747 {
748 int xx = 0 + m_miniEdge;
749 int yy = m_height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
750 int ww = m_width - 2*m_miniEdge;
751 int hh = wxSTATUS_HEIGHT;
752 m_frameStatusBar->m_x = xx;
753 m_frameStatusBar->m_y = yy;
754 m_frameStatusBar->m_width = ww;
755 m_frameStatusBar->m_height = hh;
756 gtk_myfixed_set_size( GTK_MYFIXED(m_wxwindow),
757 m_frameStatusBar->m_widget,
758 xx, yy, ww, hh );
759 }
760 #endif
761
762 /* we actually set the size of a frame here and no-where else */
763 gtk_widget_set_usize( m_widget, m_width, m_height );
764
765 m_sizeSet = TRUE;
766
767 /* send size event to frame */
768 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
769 event.SetEventObject( this );
770 GetEventHandler()->ProcessEvent( event );
771
772 /* send size event to status bar */
773 if (m_frameStatusBar)
774 {
775 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
776 event2.SetEventObject( m_frameStatusBar );
777 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
778 }
779
780 m_resizing = FALSE;
781 }
782
783 void wxFrame::MakeModal( bool modal )
784 {
785 if (modal)
786 gtk_grab_add( m_widget );
787 else
788 gtk_grab_remove( m_widget );
789 }
790
791 void wxFrame::OnInternalIdle()
792 {
793 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
794 GtkOnSize( m_x, m_y, m_width, m_height );
795
796 DoMenuUpdates();
797
798 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
799 #if wxUSE_TOOLBAR
800 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
801 #endif
802 #if wxUSE_STATUSBAR
803 if (m_frameStatusBar) m_frameStatusBar->OnInternalIdle();
804 #endif
805
806 wxWindow::OnInternalIdle();
807 }
808
809 void wxFrame::OnCloseWindow( wxCloseEvent& WXUNUSED(event) )
810 {
811 Destroy();
812 }
813
814 void wxFrame::OnSize( wxSizeEvent &WXUNUSED(event) )
815 {
816 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
817
818 #if wxUSE_CONSTRAINTS
819 if (GetAutoLayout())
820 {
821 Layout();
822 }
823 else
824 #endif // wxUSE_CONSTRAINTS
825 {
826 /* do we have exactly one child? */
827 wxWindow *child = (wxWindow *)NULL;
828 for ( wxNode *node = GetChildren().First(); node; node = node->Next() )
829 {
830 wxWindow *win = (wxWindow *)node->Data();
831 if ( !wxIS_KIND_OF(win,wxFrame) && !wxIS_KIND_OF(win,wxDialog) )
832 {
833 if (child)
834 {
835 /* it's the second one: do nothing */
836 return;
837 }
838
839 child = win;
840 }
841 }
842
843 /* no children at all? */
844 if (child)
845 {
846 /* yes: set it's size to fill all the frame */
847 int client_x, client_y;
848 DoGetClientSize( &client_x, &client_y );
849 child->SetSize( 1, 1, client_x-2, client_y-2 );
850 }
851 }
852 }
853
854 void wxFrame::SetMenuBar( wxMenuBar *menuBar )
855 {
856 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
857 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
858
859 m_frameMenuBar = menuBar;
860
861 if (m_frameMenuBar)
862 {
863 m_frameMenuBar->SetInvokingWindow( this );
864
865 if (m_frameMenuBar->GetParent() != this)
866 {
867 m_frameMenuBar->SetParent(this);
868 gtk_myfixed_put( GTK_MYFIXED(m_mainWidget),
869 m_frameMenuBar->m_widget,
870 m_frameMenuBar->m_x,
871 m_frameMenuBar->m_y,
872 m_frameMenuBar->m_width,
873 m_frameMenuBar->m_height );
874
875 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
876 {
877 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_attached",
878 GTK_SIGNAL_FUNC(gtk_menu_attached_callback), (gpointer)this );
879
880 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_detached",
881 GTK_SIGNAL_FUNC(gtk_menu_detached_callback), (gpointer)this );
882 }
883
884 m_frameMenuBar->Show( TRUE );
885 }
886 }
887
888 /* resize window in OnInternalIdle */
889 m_sizeSet = FALSE;
890 }
891
892 wxMenuBar *wxFrame::GetMenuBar() const
893 {
894 return m_frameMenuBar;
895 }
896
897 void wxFrame::OnMenuHighlight(wxMenuEvent& event)
898 {
899 #if wxUSE_STATUSBAR
900 if (GetStatusBar())
901 {
902 // if no help string found, we will clear the status bar text
903 wxString helpString;
904
905 int menuId = event.GetMenuId();
906 if ( menuId != -1 )
907 {
908 wxMenuBar *menuBar = GetMenuBar();
909 if (menuBar)
910 {
911 helpString = menuBar->GetHelpString(menuId);
912 }
913 }
914
915 SetStatusText(helpString);
916 }
917 #endif // wxUSE_STATUSBAR
918 }
919
920 #if wxUSE_TOOLBAR
921 wxToolBar* wxFrame::CreateToolBar( long style, wxWindowID id, const wxString& name )
922 {
923 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
924
925 wxCHECK_MSG( m_frameToolBar == NULL, FALSE, wxT("recreating toolbar in wxFrame") );
926
927 m_insertInClientArea = FALSE;
928
929 m_frameToolBar = OnCreateToolBar( style, id, name );
930
931 if (m_frameToolBar) GetChildren().DeleteObject( m_frameToolBar );
932
933 m_insertInClientArea = TRUE;
934
935 m_sizeSet = FALSE;
936
937 return m_frameToolBar;
938 }
939
940 wxToolBar* wxFrame::OnCreateToolBar( long style, wxWindowID id, const wxString& name )
941 {
942 return new wxToolBar( this, id, wxDefaultPosition, wxDefaultSize, style, name );
943 }
944
945 void wxFrame::SetToolBar(wxToolBar *toolbar)
946 {
947 m_frameToolBar = toolbar;
948 if (m_frameToolBar)
949 {
950 /* insert into toolbar area if not already there */
951 if (m_frameToolBar->m_widget->parent != m_mainWidget)
952 {
953 gtk_widget_ref( m_frameToolBar->m_widget );
954 gtk_widget_unparent( m_frameToolBar->m_widget );
955
956 m_insertInClientArea = TRUE;
957 wxInsertChildInFrame( this, m_frameToolBar );
958 m_insertInClientArea = FALSE;
959
960 gtk_widget_unref( m_frameToolBar->m_widget );
961 }
962 }
963 }
964
965 wxToolBar *wxFrame::GetToolBar() const
966 {
967 return m_frameToolBar;
968 }
969 #endif // wxUSE_TOOLBAR
970
971 #if wxUSE_STATUSBAR
972 wxStatusBar* wxFrame::CreateStatusBar( int number, long style, wxWindowID id, const wxString& name )
973 {
974 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
975
976 wxCHECK_MSG( m_frameStatusBar == NULL, FALSE, wxT("recreating status bar in wxFrame") );
977
978 m_frameStatusBar = OnCreateStatusBar( number, style, id, name );
979
980 m_sizeSet = FALSE;
981
982 return m_frameStatusBar;
983 }
984
985 wxStatusBar *wxFrame::OnCreateStatusBar( int number, long style, wxWindowID id, const wxString& name )
986 {
987 wxStatusBar *statusBar = (wxStatusBar *) NULL;
988
989 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 20), style, name);
990
991 // Set the height according to the font and the border size
992 wxClientDC dc(statusBar);
993 dc.SetFont( statusBar->GetFont() );
994
995 long x, y;
996 dc.GetTextExtent( "X", &x, &y );
997
998 int height = (int)( (y * 1.1) + 2* statusBar->GetBorderY());
999
1000 statusBar->SetSize( -1, -1, 100, height );
1001
1002 statusBar->SetFieldsCount( number );
1003 return statusBar;
1004 }
1005
1006 wxStatusBar *wxFrame::GetStatusBar() const
1007 {
1008 return m_frameStatusBar;
1009 }
1010
1011 void wxFrame::SetStatusText(const wxString& text, int number)
1012 {
1013 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1014
1015 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
1016
1017 m_frameStatusBar->SetStatusText(text, number);
1018 }
1019
1020 void wxFrame::SetStatusWidths(int n, const int widths_field[] )
1021 {
1022 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1023
1024 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") );
1025
1026 m_frameStatusBar->SetStatusWidths(n, widths_field);
1027 }
1028 #endif // wxUSE_STATUSBAR
1029
1030 void wxFrame::Command( int id )
1031 {
1032 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
1033 commandEvent.SetInt( id );
1034 commandEvent.SetEventObject( this );
1035
1036 wxMenuBar *bar = GetMenuBar();
1037 if (!bar) return;
1038
1039 wxMenuItem *item = bar->FindItemForId(id) ;
1040 if (item && item->IsCheckable())
1041 {
1042 bar->Check(id,!bar->Checked(id)) ;
1043 }
1044
1045 wxEvtHandler* evtHandler = GetEventHandler();
1046
1047 evtHandler->ProcessEvent(commandEvent);
1048 }
1049
1050 void wxFrame::SetTitle( const wxString &title )
1051 {
1052 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1053
1054 m_title = title;
1055 if (m_title.IsNull()) m_title = wxT("");
1056 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
1057 }
1058
1059 void wxFrame::SetIcon( const wxIcon &icon )
1060 {
1061 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1062
1063 m_icon = icon;
1064 if (!icon.Ok()) return;
1065
1066 if (!m_widget->window) return;
1067
1068 wxMask *mask = icon.GetMask();
1069 GdkBitmap *bm = (GdkBitmap *) NULL;
1070 if (mask) bm = mask->GetBitmap();
1071
1072 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
1073 }
1074
1075 void wxFrame::Maximize(bool WXUNUSED(maximize))
1076 {
1077 }
1078
1079 void wxFrame::Restore()
1080 {
1081 }
1082
1083 void wxFrame::Iconize( bool iconize )
1084 {
1085 if (iconize)
1086 {
1087 XIconifyWindow( GDK_WINDOW_XDISPLAY( m_widget->window ),
1088 GDK_WINDOW_XWINDOW( m_widget->window ),
1089 DefaultScreen( GDK_DISPLAY() ) );
1090 }
1091 }
1092
1093 bool wxFrame::IsIconized() const
1094 {
1095 return FALSE;
1096 }