1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/mdi.mm
3 // Purpose: wxMDIParentFrame, wxMDIChildFrame, wxMDIClientWindow
4 // Author: David Elliott
8 // Copyright: (c) 2003 David Elliott
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
18 #include "wx/cocoa/objc/objc_uniquifying.h"
24 // #include "wx/cocoa/autorelease.h"
25 #include "wx/cocoa/mbarman.h"
27 #import <AppKit/NSWindow.h>
28 #import <Foundation/NSNotification.h>
29 // #import <AppKit/NSApplication.h>
30 // #import <AppKit/NSView.h>
32 #include "wx/listimpl.cpp"
33 WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
35 WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap);
37 // ============================================================================
38 // wxMDIParentFrameObserver
39 // ============================================================================
40 @interface wxMDIParentFrameObserver : NSObject
42 wxMDIParentFrame *m_mdiParent;
46 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent;
47 - (void)windowDidBecomeMain: (NSNotification *)notification;
48 @end // interface wxMDIParentFrameObserver : NSObject
49 WX_DECLARE_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
51 @implementation wxMDIParentFrameObserver : NSObject
54 wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
59 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent
62 m_mdiParent = mdiParent;
66 - (void)windowDidBecomeMain: (NSNotification *)notification
68 wxASSERT(m_mdiParent);
69 m_mdiParent->WindowDidBecomeMain(notification);
72 @end // implementation wxMDIParentFrameObserver : NSObject
73 WX_IMPLEMENT_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
75 // ========================================================================
77 // ========================================================================
78 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
79 BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
82 void wxMDIParentFrame::Init()
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];
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)
98 if ( !wxFrame::Create(parent,winid,title,pos,size,style,name) )
101 m_clientWindow = OnCreateClient();
103 return m_clientWindow != NULL;
106 wxMDIParentFrame::~wxMDIParentFrame()
108 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
109 m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
111 wxMDIChildFrame *child = node->GetData();
114 wxASSERT_MSG(!m_mdiChildren.Find(child),
115 wxT("MDI child didn't remove itself using RemoveMDIChild()"));
117 [m_observer release];
120 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
122 m_mdiChildren.Append(child);
125 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
127 m_mdiChildren.DeleteObject(child);
128 if(child==m_currentChild)
129 SetActiveChild(NULL);
132 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
134 return m_currentChild;
137 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
139 m_currentChild = child;
140 wxMenuBarManager::GetInstance()->UpdateMenuBar();
143 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
145 return m_clientWindow;
148 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
150 return new wxMDIClientWindow( this );
153 void wxMDIParentFrame::ActivateNext()
157 void wxMDIParentFrame::ActivatePrevious()
161 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
163 if(m_currentChild && (win==this))
164 return m_currentChild->GetAppMenuBar(win);
165 return wxFrame::GetAppMenuBar(win);
168 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
170 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
171 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
173 sm_cocoaDeactivateWindow = NULL;
176 else if(sm_cocoaDeactivateWindow == this)
178 sm_cocoaDeactivateWindow = NULL;
185 NSWindow *nswin = m_currentChild->GetNSWindow();
186 if(![nswin isMainWindow])
187 [nswin makeMainWindow];
189 wxFrame::CocoaDelegate_windowDidBecomeKey();
193 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
195 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
197 wxFrame::CocoaDelegate_windowDidResignKey();
199 sm_cocoaDeactivateWindow = this;
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)
206 canBecome = m_mdiChildren.IsEmpty(); return true;
209 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
211 // If we aren't the key window, we don't care
212 if(![m_cocoaNSWindow isKeyWindow])
214 wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
215 // If we are key and becoming main, that's great
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())
222 wxMDIChildFrame *child = node->GetData();
226 // Some other window is becoming main, but we are key
227 // Make the new main window the key window
228 [[notification object] makeKeyWindow];
231 wxIntMDIChildFrameHashMap hashmap;
232 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
233 m_mdiChildren.GetFirst(); node; node = node->GetNext())
235 wxMDIChildFrame *child = node->GetData();
236 hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
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;
254 // ========================================================================
256 // ========================================================================
257 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
258 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
261 void wxMDIChildFrame::Init()
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)
271 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
274 m_mdiParent = parent;
275 parent->AddMDIChild(this);
280 wxMDIChildFrame::~wxMDIChildFrame()
282 // Just in case Destroy() wasn't called
283 m_mdiParent->RemoveMDIChild(this);
286 void wxMDIChildFrame::Activate()
290 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
292 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
293 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
295 sm_cocoaDeactivateWindow = NULL;
296 if(m_mdiParent->GetActiveChild() != this)
297 sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
299 m_mdiParent->SetActiveChild(this);
300 wxFrame::CocoaDelegate_windowDidBecomeKey();
303 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
305 m_mdiParent->SetActiveChild(this);
306 wxFrame::CocoaDelegate_windowDidBecomeMain();
309 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
311 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
312 sm_cocoaDeactivateWindow = this;
315 bool wxMDIChildFrame::Destroy()
317 // It's good to do this here before we are really closed
318 m_mdiParent->RemoveMDIChild(this);
319 return wxFrame::Destroy();
322 // ========================================================================
324 // ========================================================================
325 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
327 wxMDIClientWindow::wxMDIClientWindow()
331 wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
332 :wxWindow(parent, wxID_ANY)
336 wxMDIClientWindow::~wxMDIClientWindow()
340 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)