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