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