1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/carbon/frame.cpp
3 // Purpose:     wxFrame
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:     1998-01-01
7 // Copyright:   (c) Stefan Csomor
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #include "wx/wxprec.h"
12 
13 #include "wx/frame.h"
14 
15 #ifndef WX_PRECOMP
16     #include "wx/app.h"
17     #include "wx/dcclient.h"
18     #include "wx/menu.h"
19     #include "wx/dialog.h"
20     #include "wx/settings.h"
21     #include "wx/toolbar.h"
22     #include "wx/statusbr.h"
23     #include "wx/menuitem.h"
24 #endif // WX_PRECOMP
25 
26 #include "wx/osx/private.h"
27 
BEGIN_EVENT_TABLE(wxFrame,wxFrameBase)28 BEGIN_EVENT_TABLE(wxFrame, wxFrameBase)
29   EVT_ACTIVATE(wxFrame::OnActivate)
30   EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged)
31 END_EVENT_TABLE()
32 
33 #define WX_MAC_STATUSBAR_HEIGHT 18
34 
35 // ----------------------------------------------------------------------------
36 // creation/destruction
37 // ----------------------------------------------------------------------------
38 
39 void wxFrame::Init()
40 {
41     m_winLastFocused = NULL;
42 }
43 
Create(wxWindow * parent,wxWindowID id,const wxString & title,const wxPoint & pos,const wxSize & size,long style,const wxString & name)44 bool wxFrame::Create(wxWindow *parent,
45            wxWindowID id,
46            const wxString& title,
47            const wxPoint& pos,
48            const wxSize& size,
49            long style,
50            const wxString& name)
51 {
52     if ( !wxTopLevelWindow::Create(parent, id, title, pos, size, style, name) )
53         return false;
54 
55     return true;
56 }
57 
~wxFrame()58 wxFrame::~wxFrame()
59 {
60     SendDestroyEvent();
61 
62     DeleteAllBars();
63 }
64 
65 // get the origin of the client area in the client coordinates
GetClientAreaOrigin() const66 wxPoint wxFrame::GetClientAreaOrigin() const
67 {
68     wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin();
69 
70 #if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__)
71     wxToolBar *toolbar = GetToolBar();
72     if ( toolbar && toolbar->IsShown() )
73     {
74         int w, h;
75         toolbar->GetSize(&w, &h);
76 
77         if ( toolbar->HasFlag(wxTB_LEFT) )
78         {
79             pt.x += w;
80         }
81         else if ( toolbar->HasFlag(wxTB_TOP) )
82         {
83 #if !wxOSX_USE_NATIVE_TOOLBAR
84             pt.y += h;
85 #endif
86         }
87     }
88 #endif
89 
90     return pt;
91 }
92 
Enable(bool enable)93 bool wxFrame::Enable(bool enable)
94 {
95     if ( !wxWindow::Enable(enable) )
96         return false;
97 
98 #if wxUSE_MENUS
99     // we should always enable/disable the menubar, even if we are not current, otherwise
100     // we might miss some state change later (happened eg in the docview sample after PrintPreview)
101     if ( m_frameMenuBar /*&& m_frameMenuBar == wxMenuBar::MacGetInstalledMenuBar()*/)
102     {
103         int iMaxMenu = m_frameMenuBar->GetMenuCount();
104         for ( int i = 0 ; i < iMaxMenu ; ++ i )
105         {
106             m_frameMenuBar->EnableTop( i , enable ) ;
107         }
108     }
109 #endif
110     return true;
111 }
112 
113 #if wxUSE_STATUSBAR
OnCreateStatusBar(int number,long style,wxWindowID id,const wxString & name)114 wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id,
115     const wxString& name)
116 {
117     wxStatusBar *statusBar;
118 
119     statusBar = new wxStatusBar(this, id, style, name);
120     statusBar->SetSize(100, WX_MAC_STATUSBAR_HEIGHT);
121     statusBar->SetFieldsCount(number);
122 
123     return statusBar;
124 }
125 
PositionStatusBar()126 void wxFrame::PositionStatusBar()
127 {
128     if (m_frameStatusBar && m_frameStatusBar->IsShown() )
129     {
130         int w, h;
131         GetClientSize(&w, &h);
132 
133         // Since we wish the status bar to be directly under the client area,
134         // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
135         m_frameStatusBar->SetSize(0, h, w, WX_MAC_STATUSBAR_HEIGHT);
136     }
137 }
138 #endif // wxUSE_STATUSBAR
139 
140 // Responds to colour changes, and passes event on to children.
OnSysColourChanged(wxSysColourChangedEvent & event)141 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
142 {
143     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
144     Refresh();
145 
146 #if wxUSE_STATUSBAR
147     if ( m_frameStatusBar )
148     {
149         wxSysColourChangedEvent event2;
150 
151         event2.SetEventObject( m_frameStatusBar );
152         m_frameStatusBar->GetEventHandler()->ProcessEvent(event2);
153     }
154 #endif // wxUSE_STATUSBAR
155 
156     // Propagate the event to the non-top-level children
157     wxWindow::OnSysColourChanged(event);
158 }
159 
160 // Default activation behaviour - set the focus for the first child
161 // subwindow found.
OnActivate(wxActivateEvent & event)162 void wxFrame::OnActivate(wxActivateEvent& event)
163 {
164     if ( !event.GetActive() )
165     {
166        // remember the last focused child if it is our child
167         m_winLastFocused = FindFocus();
168 
169         // so we NULL it out if it's a child from some other frame
170         wxWindow *win = m_winLastFocused;
171         while ( win )
172         {
173             if ( win->IsTopLevel() )
174             {
175                 if ( win != this )
176                     m_winLastFocused = NULL;
177 
178                 break;
179             }
180 
181             win = win->GetParent();
182         }
183 
184         event.Skip();
185     }
186     else
187     {
188         // restore focus to the child which was last focused
189         wxWindow *parent = m_winLastFocused
190             ? m_winLastFocused->GetParent()
191             : NULL;
192 
193         if (parent == NULL)
194             parent = this;
195 
196         wxSetFocusToChild(parent, &m_winLastFocused);
197 
198 #if wxUSE_MENUS
199         if (m_frameMenuBar != NULL)
200         {
201             m_frameMenuBar->MacInstallMenuBar();
202         }
203         else
204         {
205             wxFrame *tlf = wxDynamicCast( wxTheApp->GetTopWindow(), wxFrame );
206             if (tlf != NULL)
207             {
208                 // Trying top-level frame membar
209                 if (tlf->GetMenuBar())
210                     tlf->GetMenuBar()->MacInstallMenuBar();
211             }
212         }
213 #endif
214     }
215 }
216 
217 #if wxUSE_MENUS
DetachMenuBar()218 void wxFrame::DetachMenuBar()
219 {
220     wxFrameBase::DetachMenuBar();
221 }
222 
AttachMenuBar(wxMenuBar * menuBar)223 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
224 {
225 #if wxOSX_USE_CARBON
226     wxFrame* tlf = wxDynamicCast( wxNonOwnedWindow::GetFromWXWindow( (WXWindow) FrontNonFloatingWindow() ) , wxFrame );
227 #elif wxOSX_USE_COCOA
228     wxFrame* tlf = wxDynamicCast( wxNonOwnedWindow::GetFromWXWindow( wxOSXGetMainWindow() ) , wxFrame );
229 #else
230     wxFrame* tlf = wxDynamicCast( wxTheApp->GetTopWindow(), wxFrame );
231 #endif
232     bool makeCurrent = false;
233 
234     // if this is already the current menubar or we are the frontmost window
235     if ( (tlf == this) || (m_frameMenuBar == wxMenuBar::MacGetInstalledMenuBar()) )
236         makeCurrent = true;
237     // or there is an app-level menubar like MDI
238     else if ( tlf && (tlf->GetMenuBar() == NULL) && (((wxFrame*)wxTheApp->GetTopWindow()) == this) )
239         makeCurrent = true;
240 
241     wxFrameBase::AttachMenuBar( menuBar );
242 
243     if (m_frameMenuBar)
244     {
245         if (makeCurrent)
246             m_frameMenuBar->MacInstallMenuBar();
247     }
248 }
249 #endif
250 
DoGetClientSize(int * x,int * y) const251 void wxFrame::DoGetClientSize(int *x, int *y) const
252 {
253     wxTopLevelWindow::DoGetClientSize( x , y );
254 
255 #if wxUSE_STATUSBAR
256     if ( GetStatusBar() && GetStatusBar()->IsShown() && y )
257         *y -= WX_MAC_STATUSBAR_HEIGHT;
258 #endif
259 
260 #if wxUSE_TOOLBAR
261     wxToolBar *toolbar = GetToolBar();
262     if ( toolbar && toolbar->IsShown() )
263     {
264         int w, h;
265         toolbar->GetSize(&w, &h);
266 
267         if ( toolbar->IsVertical() )
268         {
269             if ( x )
270                 *x -= w;
271         }
272         else if ( toolbar->HasFlag( wxTB_BOTTOM ) )
273         {
274             if ( y )
275                 *y -= h;
276         }
277         else
278         {
279 #if !wxOSX_USE_NATIVE_TOOLBAR
280             if ( y )
281                 *y -= h;
282 #endif
283         }
284     }
285 #endif
286 }
287 
MacIsChildOfClientArea(const wxWindow * child) const288 bool wxFrame::MacIsChildOfClientArea( const wxWindow* child ) const
289 {
290 #if wxUSE_STATUSBAR
291     if ( child == GetStatusBar() )
292         return false ;
293 #endif
294 
295 #if wxUSE_TOOLBAR
296     if ( child == GetToolBar() )
297         return false ;
298 #endif
299 
300     return wxFrameBase::MacIsChildOfClientArea( child ) ;
301 }
302 
DoSetClientSize(int clientwidth,int clientheight)303 void wxFrame::DoSetClientSize(int clientwidth, int clientheight)
304 {
305     int currentclientwidth , currentclientheight ;
306     int currentwidth , currentheight ;
307 
308     GetClientSize( &currentclientwidth , &currentclientheight ) ;
309     if ( clientwidth == -1 )
310         clientwidth = currentclientwidth ;
311     if ( clientheight == -1 )
312         clientheight = currentclientheight ;
313     GetSize( &currentwidth , &currentheight ) ;
314 
315     // find the current client size
316 
317     // Find the difference between the entire window (title bar and all) and
318     // the client area; add this to the new client size to move the window
319     DoSetSize( -1 , -1 , currentwidth + clientwidth - currentclientwidth ,
320         currentheight + clientheight - currentclientheight , wxSIZE_USE_EXISTING ) ;
321 }
322 
323 #if wxUSE_TOOLBAR
SetToolBar(wxToolBar * toolbar)324 void wxFrame::SetToolBar(wxToolBar *toolbar)
325 {
326     if ( m_frameToolBar == toolbar )
327         return ;
328 
329 #ifndef __WXOSX_IPHONE__
330 #if wxOSX_USE_NATIVE_TOOLBAR
331     if ( m_frameToolBar )
332         m_frameToolBar->MacInstallNativeToolbar( false ) ;
333 #endif
334 #endif
335     m_frameToolBar = toolbar ;
336 
337 #ifndef __WXOSX_IPHONE__
338 #if wxOSX_USE_NATIVE_TOOLBAR
339     if ( toolbar )
340         toolbar->MacInstallNativeToolbar( true ) ;
341 #endif
342 #endif
343 }
344 
CreateToolBar(long style,wxWindowID id,const wxString & name)345 wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& name)
346 {
347     if ( wxFrameBase::CreateToolBar(style, id, name) )
348         PositionToolBar();
349 
350     return m_frameToolBar;
351 }
352 
PositionToolBar()353 void wxFrame::PositionToolBar()
354 {
355     int cw, ch;
356 
357     wxTopLevelWindow::DoGetClientSize( &cw , &ch );
358 
359     int statusX = 0 ;
360     int statusY = 0 ;
361 
362 #if wxUSE_STATUSBAR
363     if (GetStatusBar() && GetStatusBar()->IsShown())
364     {
365         GetStatusBar()->GetSize(&statusX, &statusY);
366         ch -= statusY;
367     }
368 #endif
369 
370 #ifdef __WXOSX_IPHONE__
371     // TODO integrate this in a better way, on iphone the status bar is not a child of the content view
372     // but the toolbar is
373     ch -= 20;
374 #endif
375 
376     if (GetToolBar())
377     {
378         int tx, ty, tw, th;
379 
380         tx = ty = 0 ;
381         GetToolBar()->GetSize(&tw, &th);
382         if (GetToolBar()->HasFlag(wxTB_LEFT))
383         {
384             // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
385             // means, pretend we don't have toolbar/status bar, so we
386             // have the original client size.
387             GetToolBar()->SetSize(tx , ty , tw, ch , wxSIZE_NO_ADJUSTMENTS );
388         }
389         else if (GetToolBar()->HasFlag(wxTB_RIGHT))
390         {
391             // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
392             // means, pretend we don't have toolbar/status bar, so we
393             // have the original client size.
394             tx = cw - tw;
395             GetToolBar()->SetSize(tx , ty , tw, ch , wxSIZE_NO_ADJUSTMENTS );
396         }
397         else if (GetToolBar()->HasFlag(wxTB_BOTTOM))
398         {
399             tx = 0;
400             ty = ch - th;
401             GetToolBar()->SetSize(tx, ty, cw, th, wxSIZE_NO_ADJUSTMENTS );
402         }
403         else
404         {
405 #if !wxOSX_USE_NATIVE_TOOLBAR
406             // Use the 'real' position
407             GetToolBar()->SetSize(tx , ty , cw , th, wxSIZE_NO_ADJUSTMENTS );
408 #endif
409         }
410     }
411 }
412 #endif // wxUSE_TOOLBAR
413 
PositionBars()414 void wxFrame::PositionBars()
415 {
416 #if wxUSE_STATUSBAR
417     PositionStatusBar();
418 #endif
419 #if wxUSE_TOOLBAR
420     PositionToolBar();
421 #endif
422 }
423 
424 
425