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