]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/frame.cpp
d9299edf62d1a23a6756e01c5bda4c717f8e0e2a
[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 {
749 gtk_grab_add( m_widget );
750 gtk_main();
751 gtk_grab_remove( m_widget );
752 }
753 else
754 {
755 gtk_main_quit();
756 }
757 }
758
759 void wxFrame::OnInternalIdle()
760 {
761 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
762 GtkOnSize( m_x, m_y, m_width, m_height );
763
764 DoMenuUpdates();
765
766 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
767 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
768 if (m_frameStatusBar) m_frameStatusBar->OnInternalIdle();
769 }
770
771 void wxFrame::OnCloseWindow( wxCloseEvent& WXUNUSED(event) )
772 {
773 Destroy();
774 }
775
776 void wxFrame::OnSize( wxSizeEvent &WXUNUSED(event) )
777 {
778 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
779
780 if (GetAutoLayout())
781 {
782 Layout();
783 }
784 else
785 {
786 /* do we have exactly one child? */
787 wxWindow *child = (wxWindow *)NULL;
788 for ( wxNode *node = GetChildren().First(); node; node = node->Next() )
789 {
790 wxWindow *win = (wxWindow *)node->Data();
791 if ( !wxIS_KIND_OF(win,wxFrame) && !wxIS_KIND_OF(win,wxDialog) )
792 {
793 if (child)
794 {
795 /* it's the second one: do nothing */
796 return;
797 }
798
799 child = win;
800 }
801 }
802
803 /* no children at all? */
804 if (child)
805 {
806 /* yes: set it's size to fill all the frame */
807 int client_x, client_y;
808 DoGetClientSize( &client_x, &client_y );
809 child->SetSize( 1, 1, client_x-2, client_y-2 );
810 }
811 }
812 }
813
814 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
815 {
816 menu->SetInvokingWindow( win );
817
818 #if (GTK_MINOR_VERSION > 0)
819 /* support for native hot keys */
820 gtk_accel_group_attach( menu->m_accel, GTK_OBJECT(win->m_widget));
821 #endif
822
823 wxNode *node = menu->GetItems().First();
824 while (node)
825 {
826 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
827 if (menuitem->IsSubMenu())
828 SetInvokingWindow( menuitem->GetSubMenu(), win );
829 node = node->Next();
830 }
831 }
832
833 void wxFrame::SetMenuBar( wxMenuBar *menuBar )
834 {
835 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
836 wxASSERT_MSG( (m_wxwindow != NULL), _T("invalid frame") );
837
838 m_frameMenuBar = menuBar;
839
840 if (m_frameMenuBar)
841 {
842 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
843 /* support for native key accelerators indicated by underscroes */
844 gtk_accel_group_attach( m_frameMenuBar->m_accel, GTK_OBJECT(m_widget));
845 #endif
846
847 wxNode *node = m_frameMenuBar->GetMenus().First();
848 while (node)
849 {
850 wxMenu *menu = (wxMenu*)node->Data();
851 SetInvokingWindow( menu, this );
852 node = node->Next();
853 }
854
855 if (m_frameMenuBar->GetParent() != this)
856 {
857 m_frameMenuBar->SetParent(this);
858 gtk_myfixed_put( GTK_MYFIXED(m_mainWidget),
859 m_frameMenuBar->m_widget,
860 m_frameMenuBar->m_x,
861 m_frameMenuBar->m_y,
862 m_frameMenuBar->m_width,
863 m_frameMenuBar->m_height );
864
865 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
866 {
867 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_attached",
868 GTK_SIGNAL_FUNC(gtk_menu_attached_callback), (gpointer)this );
869
870 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_detached",
871 GTK_SIGNAL_FUNC(gtk_menu_detached_callback), (gpointer)this );
872 }
873 }
874 }
875
876 /* resize window in OnInternalIdle */
877 m_sizeSet = FALSE;
878 }
879
880 wxMenuBar *wxFrame::GetMenuBar() const
881 {
882 return m_frameMenuBar;
883 }
884
885 void wxFrame::OnMenuHighlight(wxMenuEvent& event)
886 {
887 if (GetStatusBar())
888 {
889 // if no help string found, we will clear the status bar text
890 wxString helpString;
891
892 int menuId = event.GetMenuId();
893 if ( menuId != -1 )
894 {
895 wxMenuBar *menuBar = GetMenuBar();
896 if (menuBar)
897 {
898 helpString = menuBar->GetHelpString(menuId);
899 }
900 }
901
902 SetStatusText(helpString);
903 }
904 }
905
906 wxToolBar* wxFrame::CreateToolBar( long style, wxWindowID id, const wxString& name )
907 {
908 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
909
910 wxCHECK_MSG( m_frameToolBar == NULL, FALSE, _T("recreating toolbar in wxFrame") );
911
912 m_insertInClientArea = FALSE;
913
914 m_frameToolBar = OnCreateToolBar( style, id, name );
915
916 if (m_frameToolBar) GetChildren().DeleteObject( m_frameToolBar );
917
918 m_insertInClientArea = TRUE;
919
920 m_sizeSet = FALSE;
921
922 return m_frameToolBar;
923 }
924
925 wxToolBar* wxFrame::OnCreateToolBar( long style, wxWindowID id, const wxString& name )
926 {
927 return new wxToolBar( this, id, wxDefaultPosition, wxDefaultSize, style, name );
928 }
929
930 wxToolBar *wxFrame::GetToolBar() const
931 {
932 return m_frameToolBar;
933 }
934
935 wxStatusBar* wxFrame::CreateStatusBar( int number, long style, wxWindowID id, const wxString& name )
936 {
937 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
938
939 wxCHECK_MSG( m_frameStatusBar == NULL, FALSE, _T("recreating status bar in wxFrame") );
940
941 m_frameStatusBar = OnCreateStatusBar( number, style, id, name );
942
943 m_sizeSet = FALSE;
944
945 return m_frameStatusBar;
946 }
947
948 wxStatusBar *wxFrame::OnCreateStatusBar( int number, long style, wxWindowID id, const wxString& name )
949 {
950 wxStatusBar *statusBar = (wxStatusBar *) NULL;
951
952 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 20), style, name);
953
954 // Set the height according to the font and the border size
955 wxClientDC dc(statusBar);
956 dc.SetFont( statusBar->GetFont() );
957
958 long x, y;
959 dc.GetTextExtent( "X", &x, &y );
960
961 int height = (int)( (y * 1.1) + 2* statusBar->GetBorderY());
962
963 statusBar->SetSize( -1, -1, 100, height );
964
965 statusBar->SetFieldsCount( number );
966 return statusBar;
967 }
968
969 void wxFrame::Command( int id )
970 {
971 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
972 commandEvent.SetInt( id );
973 commandEvent.SetEventObject( this );
974
975 wxMenuBar *bar = GetMenuBar();
976 if (!bar) return;
977
978 wxMenuItem *item = bar->FindItemForId(id) ;
979 if (item && item->IsCheckable())
980 {
981 bar->Check(id,!bar->Checked(id)) ;
982 }
983
984 wxEvtHandler* evtHandler = GetEventHandler();
985
986 evtHandler->ProcessEvent(commandEvent);
987 }
988
989 void wxFrame::SetStatusText(const wxString& text, int number)
990 {
991 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
992
993 wxCHECK_RET( m_frameStatusBar != NULL, _T("no statusbar to set text for") );
994
995 m_frameStatusBar->SetStatusText(text, number);
996 }
997
998 void wxFrame::SetStatusWidths(int n, const int widths_field[] )
999 {
1000 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
1001
1002 wxCHECK_RET( m_frameStatusBar != NULL, _T("no statusbar to set widths for") );
1003
1004 m_frameStatusBar->SetStatusWidths(n, widths_field);
1005 }
1006
1007 wxStatusBar *wxFrame::GetStatusBar() const
1008 {
1009 return m_frameStatusBar;
1010 }
1011
1012 void wxFrame::SetTitle( const wxString &title )
1013 {
1014 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
1015
1016 m_title = title;
1017 if (m_title.IsNull()) m_title = _T("");
1018 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
1019 }
1020
1021 void wxFrame::SetIcon( const wxIcon &icon )
1022 {
1023 wxASSERT_MSG( (m_widget != NULL), _T("invalid frame") );
1024
1025 m_icon = icon;
1026 if (!icon.Ok()) return;
1027
1028 if (!m_widget->window) return;
1029
1030 wxMask *mask = icon.GetMask();
1031 GdkBitmap *bm = (GdkBitmap *) NULL;
1032 if (mask) bm = mask->GetBitmap();
1033
1034 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
1035 }
1036