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"
22 // #include "wx/cocoa/autorelease.h"
23 #include "wx/cocoa/mbarman.h"
25 #import <AppKit/NSWindow.h>
26 #import <Foundation/NSNotification.h>
27 // #import <AppKit/NSApplication.h>
28 // #import <AppKit/NSView.h>
30 #include "wx/listimpl.cpp"
31 WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
33 WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap);
35 // ============================================================================
36 // wxMDIParentFrameObserver
37 // ============================================================================
38 @interface wxMDIParentFrameObserver : NSObject
40 wxMDIParentFrame *m_mdiParent;
44 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent;
45 - (void)windowDidBecomeMain: (NSNotification *)notification;
46 @end // interface wxMDIParentFrameObserver : NSObject
48 @implementation wxMDIParentFrameObserver : NSObject
51 wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
56 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent
59 m_mdiParent = mdiParent;
63 - (void)windowDidBecomeMain: (NSNotification *)notification
65 wxASSERT(m_mdiParent);
66 m_mdiParent->WindowDidBecomeMain(notification);
69 @end // implementation wxMDIParentFrameObserver : NSObject
71 // ========================================================================
73 // ========================================================================
74 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
75 BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
78 void wxMDIParentFrame::Init()
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];
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)
94 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
100 wxMDIParentFrame::~wxMDIParentFrame()
102 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
103 m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
105 wxMDIChildFrame *child = node->GetData();
108 wxASSERT_MSG(!m_mdiChildren.Find(child),
109 wxT("MDI child didn't remove itself using RemoveMDIChild()"));
111 [m_observer release];
114 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
116 m_mdiChildren.Append(child);
119 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
121 m_mdiChildren.DeleteObject(child);
122 if(child==m_currentChild)
123 SetActiveChild(NULL);
126 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
128 return m_currentChild;
131 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
133 m_currentChild = child;
134 wxMenuBarManager::GetInstance()->UpdateMenuBar();
137 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
139 return m_clientWindow;
142 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
144 m_clientWindow = new wxMDIClientWindow( this );
145 return m_clientWindow;
148 void wxMDIParentFrame::ActivateNext()
152 void wxMDIParentFrame::ActivatePrevious()
156 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
158 if(m_currentChild && (win==this))
159 return m_currentChild->GetAppMenuBar(win);
160 return wxFrame::GetAppMenuBar(win);
163 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
165 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
166 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
168 sm_cocoaDeactivateWindow = NULL;
171 else if(sm_cocoaDeactivateWindow == this)
173 sm_cocoaDeactivateWindow = NULL;
180 NSWindow *nswin = m_currentChild->GetNSWindow();
181 if(![nswin isMainWindow])
182 [nswin makeMainWindow];
184 wxFrame::CocoaDelegate_windowDidBecomeKey();
188 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
190 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
192 wxFrame::CocoaDelegate_windowDidResignKey();
194 sm_cocoaDeactivateWindow = this;
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)
201 canBecome = m_mdiChildren.IsEmpty(); return true;
204 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
206 // If we aren't the key window, we don't care
207 if(![m_cocoaNSWindow isKeyWindow])
209 wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
210 // If we are key and becoming main, that's great
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())
217 wxMDIChildFrame *child = node->GetData();
221 // Some other window is becoming main, but we are key
222 // Make the new main window the key window
223 [[notification object] makeKeyWindow];
226 wxIntMDIChildFrameHashMap hashmap;
227 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
228 m_mdiChildren.GetFirst(); node; node = node->GetNext())
230 wxMDIChildFrame *child = node->GetData();
231 hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
236 NSCountWindows(&windowCount);
237 wxASSERT(windowCount>0);
238 int *windowList = new int[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;
249 // ========================================================================
251 // ========================================================================
252 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
253 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
256 void wxMDIChildFrame::Init()
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)
266 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
269 m_mdiParent = parent;
270 parent->AddMDIChild(this);
275 wxMDIChildFrame::~wxMDIChildFrame()
277 // Just in case Destroy() wasn't called
278 m_mdiParent->RemoveMDIChild(this);
281 void wxMDIChildFrame::Activate()
285 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
287 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
288 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
290 sm_cocoaDeactivateWindow = NULL;
291 if(m_mdiParent->GetActiveChild() != this)
292 sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
294 m_mdiParent->SetActiveChild(this);
295 wxFrame::CocoaDelegate_windowDidBecomeKey();
298 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
300 m_mdiParent->SetActiveChild(this);
301 wxFrame::CocoaDelegate_windowDidBecomeMain();
304 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
306 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
307 sm_cocoaDeactivateWindow = this;
310 bool wxMDIChildFrame::Destroy()
312 // It's good to do this here before we are really closed
313 m_mdiParent->RemoveMDIChild(this);
314 return wxFrame::Destroy();
317 // ========================================================================
319 // ========================================================================
320 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
322 wxMDIClientWindow::wxMDIClientWindow()
326 wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
327 :wxWindow(parent, wxID_ANY)
331 wxMDIClientWindow::~wxMDIClientWindow()
335 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)