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