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