1 /////////////////////////////////////////////////////////////////////////////
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/autorelease.h"
19 #include "wx/cocoa/mbarman.h"
21 #import <AppKit/NSWindow.h>
22 #import <Foundation/NSNotification.h>
23 // #import <AppKit/NSApplication.h>
24 // #import <AppKit/NSView.h>
26 #include <wx/listimpl.cpp>
27 WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
29 WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap);
31 // ============================================================================
32 // wxMDIParentFrameObserver
33 // ============================================================================
34 @interface wxMDIParentFrameObserver : NSObject
36 wxMDIParentFrame *m_mdiParent;
40 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent;
41 - (void)windowDidBecomeMain: (NSNotification *)notification;
42 @end // interface wxMDIParentFrameObserver : NSObject
44 @implementation wxMDIParentFrameObserver : NSObject
47 wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
52 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent
55 m_mdiParent = mdiParent;
59 - (void)windowDidBecomeMain: (NSNotification *)notification
61 wxASSERT(m_mdiParent);
62 m_mdiParent->WindowDidBecomeMain(notification);
65 @end // implementation wxMDIParentFrameObserver : NSObject
67 // ========================================================================
69 // ========================================================================
70 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
71 BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
74 void wxMDIParentFrame::Init()
76 m_clientWindow = NULL;
77 m_currentChild = NULL;
78 m_observer = [[wxMDIParentFrameObserver alloc]
79 initWithWxMDIParentFrame:this];
80 [[NSNotificationCenter defaultCenter] addObserver:m_observer
81 selector:@selector(windowDidBecomeMain:)
82 name:NSWindowDidBecomeMainNotification object:nil];
85 bool wxMDIParentFrame::Create(wxWindow *parent,
86 wxWindowID winid, const wxString& title,
87 const wxPoint& pos, const wxSize& size,
88 long style, const wxString& name)
90 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
96 wxMDIParentFrame::~wxMDIParentFrame()
98 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
99 m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
101 wxMDIChildFrame *child = node->GetData();
104 wxASSERT_MSG(!m_mdiChildren.Find(child),
105 wxT("MDI child didn't remove itself using RemoveMDIChild()"));
107 [m_observer release];
110 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
112 m_mdiChildren.Append(child);
115 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
117 m_mdiChildren.DeleteObject(child);
118 if(child==m_currentChild)
119 SetActiveChild(NULL);
122 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
124 return m_currentChild;
127 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
129 m_currentChild = child;
130 wxMenuBarManager::GetInstance()->UpdateMenuBar();
133 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
135 return m_clientWindow;
138 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
140 m_clientWindow = new wxMDIClientWindow( this );
141 return m_clientWindow;
144 void wxMDIParentFrame::ActivateNext()
148 void wxMDIParentFrame::ActivatePrevious()
152 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
154 if(m_currentChild && (win==this))
155 return m_currentChild->GetAppMenuBar(win);
156 return wxFrame::GetAppMenuBar(win);
159 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
161 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
162 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
164 sm_cocoaDeactivateWindow = NULL;
167 else if(sm_cocoaDeactivateWindow == this)
169 sm_cocoaDeactivateWindow = NULL;
176 NSWindow *nswin = m_currentChild->GetNSWindow();
177 if(![nswin isMainWindow])
178 [nswin makeMainWindow];
180 wxFrame::CocoaDelegate_windowDidBecomeKey();
184 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
186 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
188 wxFrame::CocoaDelegate_windowDidResignKey();
190 sm_cocoaDeactivateWindow = this;
193 // We should not become the main window as we aren't a document window
194 // MDI "Children" should be the main window
195 bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
197 canBecome = m_mdiChildren.IsEmpty(); return true;
200 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
202 // If we aren't the key window, we don't care
203 if(![m_cocoaNSWindow isKeyWindow])
205 wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
206 // If we are key and becoming main, that's great
209 // If one of our children is becoming main, also great
210 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
211 m_mdiChildren.GetFirst(); node; node = node->GetNext())
213 wxMDIChildFrame *child = node->GetData();
217 // Some other window is becoming main, but we are key
218 // Make the new main window the key window
219 [[notification object] makeKeyWindow];
222 wxIntMDIChildFrameHashMap hashmap;
223 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
224 m_mdiChildren.GetFirst(); node; node = node->GetNext())
226 wxMDIChildFrame *child = node->GetData();
227 hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
232 NSCountWindows(&windowCount);
233 wxASSERT(windowCount>0);
234 int *windowList = new int[windowCount];
235 NSWindowList(windowCount, windowList);
236 wxIntMDIChildFrameHashMap::iterator iter = hashmap.end();
237 for(int i=0; i<windowCount && iter == hashmap.end(); i++)
238 iter=hashmap.find(windowList[i]);
239 if(iter != hashmap.end())
240 m_currentChild = iter->second;
245 // ========================================================================
247 // ========================================================================
248 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
249 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
252 void wxMDIChildFrame::Init()
257 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
258 wxWindowID winid, const wxString& title,
259 const wxPoint& pos, const wxSize& size,
260 long style, const wxString& name)
262 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
265 m_mdiParent = parent;
266 parent->AddMDIChild(this);
271 wxMDIChildFrame::~wxMDIChildFrame()
273 // Just in case Destroy() wasn't called
274 m_mdiParent->RemoveMDIChild(this);
277 void wxMDIChildFrame::Activate()
281 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
283 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
284 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
286 sm_cocoaDeactivateWindow = NULL;
287 if(m_mdiParent->GetActiveChild() != this)
288 sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
290 m_mdiParent->SetActiveChild(this);
291 wxFrame::CocoaDelegate_windowDidBecomeKey();
294 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
296 m_mdiParent->SetActiveChild(this);
297 wxFrame::CocoaDelegate_windowDidBecomeMain();
300 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
302 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
303 sm_cocoaDeactivateWindow = this;
306 bool wxMDIChildFrame::Destroy()
308 // It's good to do this here before we are really closed
309 m_mdiParent->RemoveMDIChild(this);
310 return wxFrame::Destroy();
313 // ========================================================================
315 // ========================================================================
316 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
318 wxMDIClientWindow::wxMDIClientWindow()
322 wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
323 : wxWindow(parent, -1)
327 wxMDIClientWindow::~wxMDIClientWindow()
331 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)