1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/mdi.mm
3 // Purpose: wxMDIParentFrame, wxMDIChildFrame, wxMDIClientWindow
4 // Author: David Elliott
7 // Copyright: (c) 2003 David Elliott
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
17 #include "wx/cocoa/objc/objc_uniquifying.h"
23 // #include "wx/cocoa/autorelease.h"
24 #include "wx/cocoa/mbarman.h"
26 #import <AppKit/NSWindow.h>
27 #import <Foundation/NSNotification.h>
28 // #import <AppKit/NSApplication.h>
29 // #import <AppKit/NSView.h>
31 #include "wx/listimpl.cpp"
32 WX_DEFINE_LIST(wxCocoaMDIChildFrameList);
34 WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap);
36 // ============================================================================
37 // wxMDIParentFrameObserver
38 // ============================================================================
39 @interface wxMDIParentFrameObserver : NSObject
41 wxMDIParentFrame *m_mdiParent;
45 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent;
46 - (void)windowDidBecomeMain: (NSNotification *)notification;
47 @end // interface wxMDIParentFrameObserver : NSObject
48 WX_DECLARE_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
50 @implementation wxMDIParentFrameObserver : NSObject
53 wxFAIL_MSG(wxT("[wxMDIParentFrameObserver -init] should never be called!"));
58 - (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent
61 m_mdiParent = mdiParent;
65 - (void)windowDidBecomeMain: (NSNotification *)notification
67 wxASSERT(m_mdiParent);
68 m_mdiParent->WindowDidBecomeMain(notification);
71 @end // implementation wxMDIParentFrameObserver : NSObject
72 WX_IMPLEMENT_GET_OBJC_CLASS(wxMDIParentFrameObserver,NSObject)
74 // ========================================================================
76 // ========================================================================
77 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
78 BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame)
81 void wxMDIParentFrame::Init()
83 m_clientWindow = NULL;
84 m_currentChild = NULL;
85 m_observer = [[WX_GET_OBJC_CLASS(wxMDIParentFrameObserver) alloc]
86 initWithWxMDIParentFrame:this];
87 [[NSNotificationCenter defaultCenter] addObserver:m_observer
88 selector:@selector(windowDidBecomeMain:)
89 name:NSWindowDidBecomeMainNotification object:nil];
92 bool wxMDIParentFrame::Create(wxWindow *parent,
93 wxWindowID winid, const wxString& title,
94 const wxPoint& pos, const wxSize& size,
95 long style, const wxString& name)
97 if ( !wxFrame::Create(parent,winid,title,pos,size,style,name) )
100 m_clientWindow = OnCreateClient();
102 return m_clientWindow != NULL;
105 wxMDIParentFrame::~wxMDIParentFrame()
107 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
108 m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
110 wxMDIChildFrame *child = node->GetData();
113 wxASSERT_MSG(!m_mdiChildren.Find(child),
114 wxT("MDI child didn't remove itself using RemoveMDIChild()"));
116 [m_observer release];
119 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
121 m_mdiChildren.Append(child);
124 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
126 m_mdiChildren.DeleteObject(child);
127 if(child==m_currentChild)
128 SetActiveChild(NULL);
131 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
133 m_currentChild = child;
134 wxMenuBarManager::GetInstance()->UpdateMenuBar();
137 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
139 if(m_currentChild && (win==this))
140 return m_currentChild->GetAppMenuBar(win);
141 return wxFrame::GetAppMenuBar(win);
144 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
146 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
147 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
149 sm_cocoaDeactivateWindow = NULL;
152 else if(sm_cocoaDeactivateWindow == this)
154 sm_cocoaDeactivateWindow = NULL;
161 NSWindow *nswin = m_currentChild->GetNSWindow();
162 if(![nswin isMainWindow])
163 [nswin makeMainWindow];
165 wxFrame::CocoaDelegate_windowDidBecomeKey();
169 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
171 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
173 wxFrame::CocoaDelegate_windowDidResignKey();
175 sm_cocoaDeactivateWindow = this;
178 // We should not become the main window as we aren't a document window
179 // MDI "Children" should be the main window
180 bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
182 canBecome = m_mdiChildren.IsEmpty(); return true;
185 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
187 // If we aren't the key window, we don't care
188 if(![m_cocoaNSWindow isKeyWindow])
190 wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
191 // If we are key and becoming main, that's great
194 // If one of our children is becoming main, also great
195 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
196 m_mdiChildren.GetFirst(); node; node = node->GetNext())
198 wxMDIChildFrame *child = node->GetData();
202 // Some other window is becoming main, but we are key
203 // Make the new main window the key window
204 [[notification object] makeKeyWindow];
207 wxIntMDIChildFrameHashMap hashmap;
208 for(wxCocoaMDIChildFrameList::compatibility_iterator node =
209 m_mdiChildren.GetFirst(); node; node = node->GetNext())
211 wxMDIChildFrame *child = node->GetData();
212 hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
216 NSInteger windowCount = 0;
217 NSCountWindows(&windowCount);
218 wxASSERT(windowCount>0);
219 NSInteger *windowList = new NSInteger[windowCount];
220 NSWindowList(windowCount, windowList);
221 wxIntMDIChildFrameHashMap::iterator iter = hashmap.end();
222 for(int i=0; i<windowCount && iter == hashmap.end(); i++)
223 iter=hashmap.find(windowList[i]);
224 if(iter != hashmap.end())
225 m_currentChild = iter->second;
230 // ========================================================================
232 // ========================================================================
233 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
234 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
237 void wxMDIChildFrame::Init()
242 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
243 wxWindowID winid, const wxString& title,
244 const wxPoint& pos, const wxSize& size,
245 long style, const wxString& name)
247 bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
250 m_mdiParent = parent;
251 parent->AddMDIChild(this);
256 wxMDIChildFrame::~wxMDIChildFrame()
258 // Just in case Destroy() wasn't called
259 m_mdiParent->RemoveMDIChild(this);
262 void wxMDIChildFrame::Activate()
266 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
268 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
269 if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
271 sm_cocoaDeactivateWindow = NULL;
272 if(m_mdiParent->GetActiveChild() != this)
273 sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
275 m_mdiParent->SetActiveChild(this);
276 wxFrame::CocoaDelegate_windowDidBecomeKey();
279 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
281 m_mdiParent->SetActiveChild(this);
282 wxFrame::CocoaDelegate_windowDidBecomeMain();
285 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
287 wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
288 sm_cocoaDeactivateWindow = this;
291 bool wxMDIChildFrame::Destroy()
293 // It's good to do this here before we are really closed
294 m_mdiParent->RemoveMDIChild(this);
295 return wxFrame::Destroy();
298 // ========================================================================
300 // ========================================================================
301 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
303 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
305 return Create(parent, wxID_ANY, wxPoint(0, 0), wxSize(0, 0), style);