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