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"
21 // #include "wx/cocoa/autorelease.h"
22 #include "wx/cocoa/mbarman.h"
24 #import <AppKit/NSWindow.h>
25 #import <Foundation/NSNotification.h>
26 // #import <AppKit/NSApplication.h>
27 // #import <AppKit/NSView.h>
29 #include "wx/listimpl.cpp"
30 WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
32 WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap);
34 // ============================================================================
35 // wxMDIParentFrameObserver
36 // ============================================================================
37 @interface wxMDIParentFrameObserver : NSObject
39 wxMDIParentFrame *m_mdiParent;
43 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent;
44 - (void)windowDidBecomeMain: (NSNotification *)notification;
45 @end // interface wxMDIParentFrameObserver : NSObject
47 @implementation wxMDIParentFrameObserver : NSObject
50 wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
55 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent
58 m_mdiParent = mdiParent;
62 - (void)windowDidBecomeMain: (NSNotification *)notification
64 wxASSERT(m_mdiParent);
65 m_mdiParent->WindowDidBecomeMain(notification);
68 @end // implementation wxMDIParentFrameObserver : NSObject
70 // ========================================================================
72 // ========================================================================
73 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
74 BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
77 void wxMDIParentFrame::Init()
79 m_clientWindow = NULL;
80 m_currentChild = NULL;
81 m_observer = [[wxMDIParentFrameObserver alloc]
82 initWithWxMDIParentFrame:this];
83 [[NSNotificationCenter defaultCenter] addObserver:m_observer
84 selector:@selector(windowDidBecomeMain:)
85 name:NSWindowDidBecomeMainNotification object:nil];
88 bool wxMDIParentFrame::Create(wxWindow *parent,
89 wxWindowID winid, const wxString& title,
90 const wxPoint& pos, const wxSize& size,
91 long style, const wxString& name)
93 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
99 wxMDIParentFrame::~wxMDIParentFrame()
101 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
102 m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
104 wxMDIChildFrame *child = node->GetData();
107 wxASSERT_MSG(!m_mdiChildren.Find(child),
108 wxT("MDI child didn't remove itself using RemoveMDIChild()"));
110 [m_observer release];
113 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
115 m_mdiChildren.Append(child);
118 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
120 m_mdiChildren.DeleteObject(child);
121 if(child==m_currentChild)
122 SetActiveChild(NULL);
125 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
127 return m_currentChild;
130 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
132 m_currentChild = child;
133 wxMenuBarManager::GetInstance()->UpdateMenuBar();
136 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
138 return m_clientWindow;
141 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
143 m_clientWindow = new wxMDIClientWindow( this );
144 return m_clientWindow;
147 void wxMDIParentFrame::ActivateNext()
151 void wxMDIParentFrame::ActivatePrevious()
155 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
157 if(m_currentChild && (win==this))
158 return m_currentChild->GetAppMenuBar(win);
159 return wxFrame::GetAppMenuBar(win);
162 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
164 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
165 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
167 sm_cocoaDeactivateWindow = NULL;
170 else if(sm_cocoaDeactivateWindow == this)
172 sm_cocoaDeactivateWindow = NULL;
179 NSWindow *nswin = m_currentChild->GetNSWindow();
180 if(![nswin isMainWindow])
181 [nswin makeMainWindow];
183 wxFrame::CocoaDelegate_windowDidBecomeKey();
187 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
189 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
191 wxFrame::CocoaDelegate_windowDidResignKey();
193 sm_cocoaDeactivateWindow = this;
196 // We should not become the main window as we aren't a document window
197 // MDI "Children" should be the main window
198 bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
200 canBecome = m_mdiChildren.IsEmpty(); return true;
203 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
205 // If we aren't the key window, we don't care
206 if(![m_cocoaNSWindow isKeyWindow])
208 wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
209 // If we are key and becoming main, that's great
212 // If one of our children is becoming main, also great
213 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
214 m_mdiChildren.GetFirst(); node; node = node->GetNext())
216 wxMDIChildFrame *child = node->GetData();
220 // Some other window is becoming main, but we are key
221 // Make the new main window the key window
222 [[notification object] makeKeyWindow];
225 wxIntMDIChildFrameHashMap hashmap;
226 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
227 m_mdiChildren.GetFirst(); node; node = node->GetNext())
229 wxMDIChildFrame *child = node->GetData();
230 hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
235 NSCountWindows(&windowCount);
236 wxASSERT(windowCount>0);
237 int *windowList = new int[windowCount];
238 NSWindowList(windowCount, windowList);
239 wxIntMDIChildFrameHashMap::iterator iter = hashmap.end();
240 for(int i=0; i<windowCount && iter == hashmap.end(); i++)
241 iter=hashmap.find(windowList[i]);
242 if(iter != hashmap.end())
243 m_currentChild = iter->second;
248 // ========================================================================
250 // ========================================================================
251 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
252 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
255 void wxMDIChildFrame::Init()
260 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
261 wxWindowID winid, const wxString& title,
262 const wxPoint& pos, const wxSize& size,
263 long style, const wxString& name)
265 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
268 m_mdiParent = parent;
269 parent->AddMDIChild(this);
274 wxMDIChildFrame::~wxMDIChildFrame()
276 // Just in case Destroy() wasn't called
277 m_mdiParent->RemoveMDIChild(this);
280 void wxMDIChildFrame::Activate()
284 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
286 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
287 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
289 sm_cocoaDeactivateWindow = NULL;
290 if(m_mdiParent->GetActiveChild() != this)
291 sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
293 m_mdiParent->SetActiveChild(this);
294 wxFrame::CocoaDelegate_windowDidBecomeKey();
297 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
299 m_mdiParent->SetActiveChild(this);
300 wxFrame::CocoaDelegate_windowDidBecomeMain();
303 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
305 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
306 sm_cocoaDeactivateWindow = this;
309 bool wxMDIChildFrame::Destroy()
311 // It's good to do this here before we are really closed
312 m_mdiParent->RemoveMDIChild(this);
313 return wxFrame::Destroy();
316 // ========================================================================
318 // ========================================================================
319 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
321 wxMDIClientWindow::wxMDIClientWindow()
325 wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
326 : wxWindow(parent, -1)
330 wxMDIClientWindow::~wxMDIClientWindow()
334 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)