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