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