don't assign the returned value in wxMDIParentFrame::OnCreateClient() to any member...
[wxWidgets.git] / src / cocoa / mdi.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/mdi.mm
3 // Purpose:     wxMDIParentFrame, wxMDIChildFrame, wxMDIClientWindow
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/09/08
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2003 David Elliott
9 // Licence:     wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_MDI
15
16 #include "wx/mdi.h"
17
18 #include "wx/cocoa/objc/objc_uniquifying.h"
19
20 #ifndef WX_PRECOMP
21     #include "wx/log.h"
22 #endif // WX_PRECOMP
23
24 // #include "wx/cocoa/autorelease.h"
25 #include "wx/cocoa/mbarman.h"
26
27 #import <AppKit/NSWindow.h>
28 #import <Foundation/NSNotification.h>
29 // #import <AppKit/NSApplication.h>
30 // #import <AppKit/NSView.h>
31
32 #include "wx/listimpl.cpp"
33 WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
34
35 WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap);
36
37 // ============================================================================
38 // wxMDIParentFrameObserver
39 // ============================================================================
40 @interface wxMDIParentFrameObserver : NSObject
41 {
42     wxMDIParentFrame *m_mdiParent;
43 }
44
45 - (id)init;
46 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent;
47 - (void)windowDidBecomeMain: (NSNotification *)notification;
48 @end // interface wxMDIParentFrameObserver : NSObject
49 WX_DECLARE_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
50
51 @implementation wxMDIParentFrameObserver : NSObject
52 - (id)init
53 {
54     wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
55     m_mdiParent = NULL;
56     return self;
57 }
58
59 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent
60 {
61     wxASSERT(mdiParent);
62     m_mdiParent = mdiParent;
63     return [super init];
64 }
65
66 - (void)windowDidBecomeMain: (NSNotification *)notification
67 {
68     wxASSERT(m_mdiParent);
69     m_mdiParent->WindowDidBecomeMain(notification);
70 }
71
72 @end // implementation wxMDIParentFrameObserver : NSObject
73 WX_IMPLEMENT_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
74
75 // ========================================================================
76 // wxMDIParentFrame
77 // ========================================================================
78 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
79 BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
80 END_EVENT_TABLE()
81
82 void wxMDIParentFrame::Init()
83 {
84     m_clientWindow = NULL;
85     m_currentChild = NULL;
86     m_observer = [[WX_GET_OBJC_CLASS(wxMDIParentFrameObserver) alloc]
87             initWithWxMDIParentFrame:this];
88     [[NSNotificationCenter defaultCenter] addObserver:m_observer
89             selector:@selector(windowDidBecomeMain:)
90             name:NSWindowDidBecomeMainNotification object:nil];
91 }
92
93 bool wxMDIParentFrame::Create(wxWindow *parent,
94         wxWindowID winid, const wxString& title,
95         const wxPoint& pos, const wxSize& size,
96         long style, const wxString& name)
97 {
98     if ( !wxFrame::Create(parent,winid,title,pos,size,style,name) )
99         return false;
100
101     m_clientWindow = OnCreateClient();
102
103     return m_clientWindow != NULL;
104 }
105
106 wxMDIParentFrame::~wxMDIParentFrame()
107 {
108     for(wxCocoaMDIChildFrameList::compatibility_iterator node =
109             m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
110     {
111         wxMDIChildFrame *child = node->GetData();
112         // Delete it NOW
113         delete child;
114         wxASSERT_MSG(!m_mdiChildren.Find(child),
115             wxT("MDI child didn't remove itself using RemoveMDIChild()"));
116     }
117     [m_observer release];
118 }
119
120 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
121 {
122     m_mdiChildren.Append(child);
123 }
124
125 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
126 {
127     m_mdiChildren.DeleteObject(child);
128     if(child==m_currentChild)
129         SetActiveChild(NULL);
130 }
131
132 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
133 {
134     return m_currentChild;
135 }
136
137 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
138 {
139     m_currentChild = child;
140     wxMenuBarManager::GetInstance()->UpdateMenuBar();
141 }
142
143 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
144 {
145     return m_clientWindow;
146 }
147
148 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
149 {
150     return new wxMDIClientWindow( this );
151 }
152
153 void wxMDIParentFrame::ActivateNext()
154 {
155 }
156
157 void wxMDIParentFrame::ActivatePrevious()
158 {
159 }
160
161 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
162 {
163     if(m_currentChild && (win==this))
164         return m_currentChild->GetAppMenuBar(win);
165     return wxFrame::GetAppMenuBar(win);
166 }
167
168 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
169 {
170     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
171     if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
172     {
173         sm_cocoaDeactivateWindow = NULL;
174     }
175     #if 0
176     else if(sm_cocoaDeactivateWindow == this)
177     {
178         sm_cocoaDeactivateWindow = NULL;
179     }
180     #endif
181     else
182     {
183         if(m_currentChild)
184         {
185             NSWindow *nswin = m_currentChild->GetNSWindow();
186             if(![nswin isMainWindow])
187                 [nswin makeMainWindow];
188         }
189         wxFrame::CocoaDelegate_windowDidBecomeKey();
190     }
191 }
192
193 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
194 {
195     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
196     if(m_closed)
197         wxFrame::CocoaDelegate_windowDidResignKey();
198     else
199         sm_cocoaDeactivateWindow = this;
200 }
201
202 // We should not become the main window as we aren't a document window
203 // MDI "Children" should be the main window
204 bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
205 {
206     canBecome = m_mdiChildren.IsEmpty(); return true;
207 }
208
209 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
210 {
211     // If we aren't the key window, we don't care
212     if(![m_cocoaNSWindow isKeyWindow])
213         return;
214     wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
215     // If we are key and becoming main, that's great
216     if(win==this)
217         return;
218     // If one of our children is becoming main, also great
219     for(wxCocoaMDIChildFrameList::compatibility_iterator node =
220             m_mdiChildren.GetFirst(); node; node = node->GetNext())
221     {
222         wxMDIChildFrame *child = node->GetData();
223         if(win==child)
224             return;
225     }
226     // Some other window is becoming main, but we are key
227     // Make the new main window the key window
228     [[notification object] makeKeyWindow];
229     if(!m_currentChild)
230     {
231         wxIntMDIChildFrameHashMap hashmap;
232         for(wxCocoaMDIChildFrameList::compatibility_iterator node =
233                 m_mdiChildren.GetFirst(); node; node = node->GetNext())
234         {
235             wxMDIChildFrame *child = node->GetData();
236             hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
237         }
238         if(!hashmap.empty())
239         {
240             NSInteger windowCount = 0;
241             NSCountWindows(&windowCount);
242             wxASSERT(windowCount>0);
243             NSInteger *windowList = new NSInteger[windowCount];
244             NSWindowList(windowCount, windowList);
245             wxIntMDIChildFrameHashMap::iterator iter = hashmap.end();
246             for(int i=0; i<windowCount && iter == hashmap.end(); i++)
247                 iter=hashmap.find(windowList[i]);
248             if(iter != hashmap.end())
249                 m_currentChild = iter->second;
250         }
251     }
252 }
253
254 // ========================================================================
255 // wxMDIChildFrame
256 // ========================================================================
257 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
258 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
259 END_EVENT_TABLE()
260
261 void wxMDIChildFrame::Init()
262 {
263     m_mdiParent = NULL;
264 }
265
266 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
267         wxWindowID winid, const wxString& title,
268         const wxPoint& pos, const wxSize& size,
269         long style, const wxString& name)
270 {
271     bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
272     if(success)
273     {
274         m_mdiParent = parent;
275         parent->AddMDIChild(this);
276     }
277     return success;
278 }
279
280 wxMDIChildFrame::~wxMDIChildFrame()
281 {
282     // Just in case Destroy() wasn't called
283     m_mdiParent->RemoveMDIChild(this);
284 }
285
286 void wxMDIChildFrame::Activate()
287 {
288 }
289
290 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
291 {
292     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
293     if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
294     {
295         sm_cocoaDeactivateWindow = NULL;
296         if(m_mdiParent->GetActiveChild() != this)
297             sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
298     }
299     m_mdiParent->SetActiveChild(this);
300     wxFrame::CocoaDelegate_windowDidBecomeKey();
301 }
302
303 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
304 {
305     m_mdiParent->SetActiveChild(this);
306     wxFrame::CocoaDelegate_windowDidBecomeMain();
307 }
308
309 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
310 {
311     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
312     sm_cocoaDeactivateWindow = this;
313 }
314
315 bool wxMDIChildFrame::Destroy()
316 {
317     // It's good to do this here before we are really closed
318     m_mdiParent->RemoveMDIChild(this);
319     return wxFrame::Destroy();
320 }
321
322 // ========================================================================
323 // wxMDIClientWindow
324 // ========================================================================
325 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
326
327 wxMDIClientWindow::wxMDIClientWindow()
328 {
329 }
330
331 wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
332                   :wxWindow(parent, wxID_ANY)
333 {
334 }
335
336 wxMDIClientWindow::~wxMDIClientWindow()
337 {
338 }
339
340 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)
341 {
342     return false;
343 }
344
345 #endif