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     bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
 
 104 wxMDIParentFrame::~wxMDIParentFrame()
 
 106     for(wxCocoaMDIChildFrameList::compatibility_iterator node =
 
 107             m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst())
 
 109         wxMDIChildFrame *child = node->GetData();
 
 112         wxASSERT_MSG(!m_mdiChildren.Find(child),
 
 113             wxT("MDI child didn't remove itself using RemoveMDIChild()"));
 
 115     [m_observer release];
 
 118 void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child)
 
 120     m_mdiChildren.Append(child);
 
 123 void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child)
 
 125     m_mdiChildren.DeleteObject(child);
 
 126     if(child==m_currentChild)
 
 127         SetActiveChild(NULL);
 
 130 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
 
 132     return m_currentChild;
 
 135 void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child)
 
 137     m_currentChild = child;
 
 138     wxMenuBarManager::GetInstance()->UpdateMenuBar();
 
 141 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
 
 143     return m_clientWindow;
 
 146 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
 
 148     m_clientWindow = new wxMDIClientWindow( this );
 
 149     return m_clientWindow;
 
 152 void wxMDIParentFrame::ActivateNext()
 
 156 void wxMDIParentFrame::ActivatePrevious()
 
 160 wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win)
 
 162     if(m_currentChild && (win==this))
 
 163         return m_currentChild->GetAppMenuBar(win);
 
 164     return wxFrame::GetAppMenuBar(win);
 
 167 void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void)
 
 169     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
 
 170     if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild)
 
 172         sm_cocoaDeactivateWindow = NULL;
 
 175     else if(sm_cocoaDeactivateWindow == this)
 
 177         sm_cocoaDeactivateWindow = NULL;
 
 184             NSWindow *nswin = m_currentChild->GetNSWindow();
 
 185             if(![nswin isMainWindow])
 
 186                 [nswin makeMainWindow];
 
 188         wxFrame::CocoaDelegate_windowDidBecomeKey();
 
 192 void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void)
 
 194     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey"),this);
 
 196         wxFrame::CocoaDelegate_windowDidResignKey();
 
 198         sm_cocoaDeactivateWindow = this;
 
 201 // We should not become the main window as we aren't a document window
 
 202 // MDI "Children" should be the main window
 
 203 bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome)
 
 205     canBecome = m_mdiChildren.IsEmpty(); return true;
 
 208 void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification)
 
 210     // If we aren't the key window, we don't care
 
 211     if(![m_cocoaNSWindow isKeyWindow])
 
 213     wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
 
 214     // If we are key and becoming main, that's great
 
 217     // If one of our children is becoming main, also great
 
 218     for(wxCocoaMDIChildFrameList::compatibility_iterator node =
 
 219             m_mdiChildren.GetFirst(); node; node = node->GetNext())
 
 221         wxMDIChildFrame *child = node->GetData();
 
 225     // Some other window is becoming main, but we are key
 
 226     // Make the new main window the key window
 
 227     [[notification object] makeKeyWindow];
 
 230         wxIntMDIChildFrameHashMap hashmap;
 
 231         for(wxCocoaMDIChildFrameList::compatibility_iterator node =
 
 232                 m_mdiChildren.GetFirst(); node; node = node->GetNext())
 
 234             wxMDIChildFrame *child = node->GetData();
 
 235             hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child));
 
 239             NSInteger windowCount = 0;
 
 240             NSCountWindows(&windowCount);
 
 241             wxASSERT(windowCount>0);
 
 242             NSInteger *windowList = new NSInteger[windowCount];
 
 243             NSWindowList(windowCount, windowList);
 
 244             wxIntMDIChildFrameHashMap::iterator iter = hashmap.end();
 
 245             for(int i=0; i<windowCount && iter == hashmap.end(); i++)
 
 246                 iter=hashmap.find(windowList[i]);
 
 247             if(iter != hashmap.end())
 
 248                 m_currentChild = iter->second;
 
 253 // ========================================================================
 
 255 // ========================================================================
 
 256 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
 
 257 BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame)
 
 260 void wxMDIChildFrame::Init()
 
 265 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
 
 266         wxWindowID winid, const wxString& title,
 
 267         const wxPoint& pos, const wxSize& size,
 
 268         long style, const wxString& name)
 
 270     bool success = wxFrame::Create(parent,winid,title,pos,size,style,name);
 
 273         m_mdiParent = parent;
 
 274         parent->AddMDIChild(this);
 
 279 wxMDIChildFrame::~wxMDIChildFrame()
 
 281     // Just in case Destroy() wasn't called
 
 282     m_mdiParent->RemoveMDIChild(this);
 
 285 void wxMDIChildFrame::Activate()
 
 289 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void)
 
 291     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey"),this);
 
 292     if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent)
 
 294         sm_cocoaDeactivateWindow = NULL;
 
 295         if(m_mdiParent->GetActiveChild() != this)
 
 296             sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild();
 
 298     m_mdiParent->SetActiveChild(this);
 
 299     wxFrame::CocoaDelegate_windowDidBecomeKey();
 
 302 void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void)
 
 304     m_mdiParent->SetActiveChild(this);
 
 305     wxFrame::CocoaDelegate_windowDidBecomeMain();
 
 308 void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void)
 
 310     wxLogTrace(wxTRACE_COCOA,wxT("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey"),this);
 
 311     sm_cocoaDeactivateWindow = this;
 
 314 bool wxMDIChildFrame::Destroy()
 
 316     // It's good to do this here before we are really closed
 
 317     m_mdiParent->RemoveMDIChild(this);
 
 318     return wxFrame::Destroy();
 
 321 // ========================================================================
 
 323 // ========================================================================
 
 324 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
 
 326 wxMDIClientWindow::wxMDIClientWindow()
 
 330 wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style)
 
 331                   :wxWindow(parent, wxID_ANY)
 
 335 wxMDIClientWindow::~wxMDIClientWindow()
 
 339 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style)