Define _CRT_NONSTDC_NO_WARNINGS for zlib compilation with MSVC.
[wxWidgets.git] / src / osx / carbon / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/mdi.cpp
3 // Purpose: MDI classes
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 #if wxUSE_MDI
14
15 #include "wx/mdi.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/log.h"
19 #include "wx/menu.h"
20 #include "wx/settings.h"
21 #include "wx/statusbr.h"
22 #endif
23
24 #include "wx/osx/private.h"
25 #include "wx/osx/uma.h"
26
27 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
28 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
29 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
30
31 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
32 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
33 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
34 END_EVENT_TABLE()
35
36 #define TRACE_MDI "mdi"
37
38 static const int IDM_WINDOWTILEHOR = 4001;
39 static const int IDM_WINDOWCASCADE = 4002;
40 static const int IDM_WINDOWICONS = 4003;
41 static const int IDM_WINDOWNEXT = 4004;
42 static const int IDM_WINDOWTILEVERT = 4005;
43
44 // others
45
46 void UMAHighlightAndActivateWindow( WindowRef inWindowRef , bool inActivate )
47 {
48 #if wxOSX_USE_CARBON // TODO REMOVE
49 if ( inWindowRef )
50 {
51 // bool isHighlighted = IsWindowHighlited( inWindowRef ) ;
52 // if ( inActivate != isHighlighted )
53 #ifndef __LP64__
54 GrafPtr port ;
55 GetPort( &port ) ;
56 SetPortWindowPort( inWindowRef ) ;
57 #endif
58 HiliteWindow( inWindowRef , inActivate ) ;
59 ControlRef control = NULL ;
60 ::GetRootControl( inWindowRef , &control ) ;
61 if ( control )
62 {
63 if ( inActivate )
64 ::ActivateControl( control ) ;
65 else
66 ::DeactivateControl( control ) ;
67 }
68 #ifndef __LP64__
69 SetPort( port ) ;
70 #endif
71 }
72 #elif defined(wxOSX_USE_COCOA)
73 wxUnusedVar(inActivate);
74 wxUnusedVar(inWindowRef);
75 // TODO: implement me!
76 #endif
77 }
78
79 // ----------------------------------------------------------------------------
80 // Parent frame
81 // ----------------------------------------------------------------------------
82
83 void wxMDIParentFrame::Init()
84 {
85 m_parentFrameActive = true;
86 m_shouldBeShown = false;
87 }
88
89 bool wxMDIParentFrame::Create(wxWindow *parent,
90 wxWindowID winid,
91 const wxString& title,
92 const wxPoint& pos,
93 const wxSize& size,
94 long style,
95 const wxString& name)
96 {
97 // this style can be used to prevent a window from having the standard MDI
98 // "Window" menu
99 if ( style & wxFRAME_NO_WINDOW_MENU )
100 {
101 m_windowMenu = NULL;
102 style -= wxFRAME_NO_WINDOW_MENU ;
103 }
104 else // normal case: we have the window menu, so construct it
105 {
106 m_windowMenu = new wxMenu;
107
108 m_windowMenu->Append(IDM_WINDOWCASCADE, wxT("&Cascade"));
109 m_windowMenu->Append(IDM_WINDOWTILEHOR, wxT("Tile &Horizontally"));
110 m_windowMenu->Append(IDM_WINDOWTILEVERT, wxT("Tile &Vertically"));
111 m_windowMenu->AppendSeparator();
112 m_windowMenu->Append(IDM_WINDOWICONS, wxT("&Arrange Icons"));
113 m_windowMenu->Append(IDM_WINDOWNEXT, wxT("&Next"));
114 }
115
116 if ( !wxFrame::Create( parent , winid , title , pos , size , style , name ) )
117 return false;
118
119 m_parentFrameActive = true;
120
121 m_clientWindow = OnCreateClient();
122 if ( !m_clientWindow || !m_clientWindow->CreateClient(this, style) )
123 return false;
124
125 return true;
126 }
127
128 wxMDIParentFrame::~wxMDIParentFrame()
129 {
130 DestroyChildren();
131
132 // already deleted by DestroyChildren()
133 m_clientWindow = NULL ;
134 }
135
136 void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
137 {
138 wxFrame::SetMenuBar( menu_bar ) ;
139 }
140
141 void wxMDIParentFrame::GetRectForTopLevelChildren(int *x, int *y, int *w, int *h)
142 {
143 if (x)
144 *x = 0;
145 if (y)
146 *y = 0;
147
148 wxDisplaySize(w, h);
149 }
150
151 void wxMDIParentFrame::AddChild(wxWindowBase *child)
152 {
153 // moved this to front, so that we don't run into unset m_parent problems later
154 wxFrame::AddChild(child);
155
156 if ( !m_currentChild )
157 {
158 m_currentChild = wxDynamicCast(child, wxMDIChildFrame);
159
160 if ( m_currentChild && IsShown() && !ShouldBeVisible() )
161 {
162 // we shouldn't remain visible any more
163 wxFrame::Show(false);
164 m_shouldBeShown = true;
165 }
166 }
167 }
168
169 void wxMDIParentFrame::RemoveChild(wxWindowBase *child)
170 {
171 if ( child == m_currentChild )
172 {
173 // the current child isn't active any more, try to find another one
174 m_currentChild = NULL;
175
176 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
177 node;
178 node = node->GetNext() )
179 {
180 wxMDIChildFrame *
181 childCur = wxDynamicCast(node->GetData(), wxMDIChildFrame);
182 if ( childCur != child )
183 {
184 m_currentChild = childCur;
185 break;
186 }
187 }
188 }
189
190 wxFrame::RemoveChild(child);
191
192 // if there are no more children left we need to show the frame if we
193 // hadn't shown it before because there were active children and it was
194 // useless (note that we have to do it after fully removing the child, i.e.
195 // after calling the base class RemoveChild() as otherwise we risk to touch
196 // pointer to the child being deleted)
197 if ( !m_currentChild && m_shouldBeShown && !IsShown() )
198 {
199 // we have to show it, but at least move it out of sight and make it of
200 // smallest possible size (unfortunately (0, 0) doesn't work so that it
201 // doesn't appear in expose
202 SetSize(-10000, -10000, 1, 1);
203 Show();
204 }
205 }
206
207 void wxMDIParentFrame::MacActivate(long timestamp, bool activating)
208 {
209 wxLogTrace(TRACE_MDI, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"), this, timestamp, activating ? wxT("ACTIV") : wxT("deact"));
210
211 if (activating)
212 {
213 if (s_macDeactivateWindow && s_macDeactivateWindow->GetParent() == this)
214 {
215 wxLogTrace(TRACE_MDI, wxT("child had been scheduled for deactivation, rehighlighting"));
216
217 UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->GetWXWindow(), true);
218
219 wxLogTrace(TRACE_MDI, wxT("finished highliting child"));
220
221 s_macDeactivateWindow = NULL;
222 }
223 else if (s_macDeactivateWindow == this)
224 {
225 wxLogTrace(TRACE_MDI, wxT("Avoided deactivation/activation of this=%p"), this);
226
227 s_macDeactivateWindow = NULL;
228 }
229 else // window to deactivate is NULL or is not us or one of our kids
230 {
231 // activate kid instead
232 if (m_currentChild)
233 m_currentChild->MacActivate(timestamp, activating);
234 else
235 wxFrame::MacActivate(timestamp, activating);
236 }
237 }
238 else
239 {
240 // We were scheduled for deactivation, and now we do it.
241 if (s_macDeactivateWindow == this)
242 {
243 s_macDeactivateWindow = NULL;
244 if (m_currentChild)
245 m_currentChild->MacActivate(timestamp, activating);
246 wxFrame::MacActivate(timestamp, activating);
247 }
248 else // schedule ourselves for deactivation
249 {
250 if (s_macDeactivateWindow)
251 {
252 wxLogTrace(TRACE_MDI, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow);
253 }
254 wxLogTrace(TRACE_MDI, wxT("Scheduling delayed MDI Parent deactivation"));
255
256 s_macDeactivateWindow = this;
257 }
258 }
259 }
260
261 void wxMDIParentFrame::OnActivate(wxActivateEvent& event)
262 {
263 event.Skip();
264 }
265
266 // Responds to colour changes, and passes event on to children.
267 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
268 {
269 // TODO
270
271 // Propagate the event to the non-top-level children
272 wxFrame::OnSysColourChanged(event);
273 }
274
275 bool wxMDIParentFrame::ShouldBeVisible() const
276 {
277 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
278 node;
279 node = node->GetNext() )
280 {
281 wxWindow *win = node->GetData();
282
283 if ( win->IsShown()
284 && !wxDynamicCast(win, wxMDIChildFrame)
285 #if wxUSE_STATUSBAR
286 && win != (wxWindow*) GetStatusBar()
287 #endif
288 && win != GetClientWindow() )
289 {
290 // if we have a non-MDI child, do remain visible so that it could
291 // be used
292 return true;
293 }
294 }
295
296 return false;
297 }
298
299 bool wxMDIParentFrame::Show( bool show )
300 {
301 m_shouldBeShown = false;
302
303 // don't really show the MDI frame unless it has any children other than
304 // MDI children as it is pretty useless in this case
305
306 if ( show )
307 {
308 if ( !ShouldBeVisible() && m_currentChild )
309 {
310 // don't make the window visible now but remember that we should
311 // have had done it
312 m_shouldBeShown = true;
313
314 return false;
315 }
316 }
317
318 return wxFrame::Show(show);
319 }
320
321 // ----------------------------------------------------------------------------
322 // Child frame
323 // ----------------------------------------------------------------------------
324
325 void wxMDIChildFrame::Init()
326 {
327 }
328
329 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
330 wxWindowID winid,
331 const wxString& title,
332 const wxPoint& pos,
333 const wxSize& size,
334 long style,
335 const wxString& name)
336 {
337 m_mdiParent = parent;
338
339 SetName(name);
340
341 if ( winid == wxID_ANY )
342 winid = (int)NewControlId();
343
344 wxNonOwnedWindow::Create( parent, winid, pos , size , MacRemoveBordersFromStyle(style) , name ) ;
345
346 SetTitle( title );
347
348 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
349
350 return true;
351 }
352
353 wxMDIChildFrame::~wxMDIChildFrame()
354 {
355 DestroyChildren();
356 }
357
358 void wxMDIChildFrame::MacActivate(long timestamp, bool activating)
359 {
360 wxLogTrace(TRACE_MDI, wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this, timestamp, activating ? wxT("ACTIV") : wxT("deact"));
361
362 wxMDIParentFrame *mdiparent = m_mdiParent;
363 wxASSERT(mdiparent);
364
365 if (activating)
366 {
367 if (s_macDeactivateWindow == m_parent)
368 {
369 wxLogTrace(TRACE_MDI, wxT("parent had been scheduled for deactivation, rehighlighting"));
370
371 UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->GetWXWindow(), true);
372
373 wxLogTrace(TRACE_MDI, wxT("finished highliting parent"));
374
375 s_macDeactivateWindow = NULL;
376 }
377 else if ((mdiparent->m_currentChild == this) || !s_macDeactivateWindow)
378 mdiparent->wxFrame::MacActivate(timestamp, activating);
379
380 if (mdiparent->m_currentChild && mdiparent->m_currentChild != this)
381 mdiparent->m_currentChild->wxFrame::MacActivate(timestamp, false);
382 mdiparent->m_currentChild = this;
383
384 if (s_macDeactivateWindow == this)
385 {
386 wxLogTrace(TRACE_MDI, wxT("Avoided deactivation/activation of this=%p"), this);
387
388 s_macDeactivateWindow = NULL;
389 }
390 else
391 wxFrame::MacActivate(timestamp, activating);
392 }
393 else
394 {
395 // We were scheduled for deactivation, and now we do it.
396 if (s_macDeactivateWindow == this)
397 {
398 s_macDeactivateWindow = NULL;
399 wxFrame::MacActivate(timestamp, activating);
400 if (mdiparent->m_currentChild == this)
401 mdiparent->wxFrame::MacActivate(timestamp, activating);
402 }
403 else // schedule ourselves for deactivation
404 {
405 if (s_macDeactivateWindow)
406 {
407 wxLogTrace(TRACE_MDI, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow);
408 }
409 wxLogTrace(TRACE_MDI, wxT("Scheduling delayed deactivation"));
410
411 s_macDeactivateWindow = this;
412 }
413 }
414 }
415
416 // MDI operations
417 void wxMDIChildFrame::Activate()
418 {
419 // The base class method calls Activate() so skip it to avoid infinite
420 // recursion and go directly to the real Raise() implementation.
421 wxFrame::Raise();
422 }
423
424 //-----------------------------------------------------------------------------
425 // wxMDIClientWindow
426 //-----------------------------------------------------------------------------
427
428 wxMDIClientWindow::~wxMDIClientWindow()
429 {
430 DestroyChildren();
431 }
432
433 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
434 {
435 if ( !wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style) )
436 return false;
437
438 return true;
439 }
440
441 void wxMDIClientWindow::DoGetClientSize(int *x, int *y) const
442 {
443 wxDisplaySize( x , y ) ;
444 }
445
446 #endif // wxUSE_MDI