1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/cocoa/nsMenuGroupOwnerX.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,244 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsMenuGroupOwnerX.h" 1.10 +#include "nsMenuBarX.h" 1.11 +#include "nsMenuX.h" 1.12 +#include "nsMenuItemX.h" 1.13 +#include "nsMenuUtilsX.h" 1.14 +#include "nsCocoaUtils.h" 1.15 +#include "nsCocoaWindow.h" 1.16 + 1.17 +#include "nsCOMPtr.h" 1.18 +#include "nsString.h" 1.19 +#include "nsObjCExceptions.h" 1.20 +#include "nsThreadUtils.h" 1.21 + 1.22 +#include "mozilla/dom/Element.h" 1.23 +#include "nsIWidget.h" 1.24 +#include "nsIDocument.h" 1.25 +#include "nsIDOMDocument.h" 1.26 +#include "nsIDOMElement.h" 1.27 + 1.28 +#include "nsINode.h" 1.29 + 1.30 +using namespace mozilla; 1.31 + 1.32 +NS_IMPL_ISUPPORTS(nsMenuGroupOwnerX, nsIMutationObserver) 1.33 + 1.34 + 1.35 +nsMenuGroupOwnerX::nsMenuGroupOwnerX() 1.36 +: mCurrentCommandID(eCommand_ID_Last), 1.37 + mDocument(nullptr) 1.38 +{ 1.39 +} 1.40 + 1.41 + 1.42 +nsMenuGroupOwnerX::~nsMenuGroupOwnerX() 1.43 +{ 1.44 + // make sure we unregister ourselves as a document observer 1.45 + if (mDocument) 1.46 + mDocument->RemoveMutationObserver(this); 1.47 +} 1.48 + 1.49 + 1.50 +nsresult nsMenuGroupOwnerX::Create(nsIContent* aContent) 1.51 +{ 1.52 + if (!aContent) 1.53 + return NS_ERROR_INVALID_ARG; 1.54 + 1.55 + mContent = aContent; 1.56 + 1.57 + nsIDocument* doc = aContent->OwnerDoc(); 1.58 + if (!doc) 1.59 + return NS_ERROR_FAILURE; 1.60 + doc->AddMutationObserver(this); 1.61 + mDocument = doc; 1.62 + 1.63 + return NS_OK; 1.64 +} 1.65 + 1.66 + 1.67 +// 1.68 +// nsIMutationObserver 1.69 +// 1.70 + 1.71 + 1.72 +void nsMenuGroupOwnerX::CharacterDataWillChange(nsIDocument* aDocument, 1.73 + nsIContent* aContent, 1.74 + CharacterDataChangeInfo* aInfo) 1.75 +{ 1.76 +} 1.77 + 1.78 + 1.79 +void nsMenuGroupOwnerX::CharacterDataChanged(nsIDocument* aDocument, 1.80 + nsIContent* aContent, 1.81 + CharacterDataChangeInfo* aInfo) 1.82 +{ 1.83 +} 1.84 + 1.85 + 1.86 +void nsMenuGroupOwnerX::ContentAppended(nsIDocument* aDocument, 1.87 + nsIContent* aContainer, 1.88 + nsIContent* aFirstNewContent, 1.89 + int32_t /* unused */) 1.90 +{ 1.91 + for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) { 1.92 + ContentInserted(aDocument, aContainer, cur, 0); 1.93 + } 1.94 +} 1.95 + 1.96 + 1.97 +void nsMenuGroupOwnerX::NodeWillBeDestroyed(const nsINode * aNode) 1.98 +{ 1.99 + // our menu bar node is being destroyed 1.100 + mDocument = nullptr; 1.101 +} 1.102 + 1.103 + 1.104 +void nsMenuGroupOwnerX::AttributeWillChange(nsIDocument* aDocument, 1.105 + dom::Element* aContent, 1.106 + int32_t aNameSpaceID, 1.107 + nsIAtom* aAttribute, 1.108 + int32_t aModType) 1.109 +{ 1.110 +} 1.111 + 1.112 + 1.113 +void nsMenuGroupOwnerX::AttributeChanged(nsIDocument* aDocument, 1.114 + dom::Element* aElement, 1.115 + int32_t aNameSpaceID, 1.116 + nsIAtom* aAttribute, 1.117 + int32_t aModType) 1.118 +{ 1.119 + nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); 1.120 + nsChangeObserver* obs = LookupContentChangeObserver(aElement); 1.121 + if (obs) 1.122 + obs->ObserveAttributeChanged(aDocument, aElement, aAttribute); 1.123 +} 1.124 + 1.125 + 1.126 +void nsMenuGroupOwnerX::ContentRemoved(nsIDocument * aDocument, 1.127 + nsIContent * aContainer, 1.128 + nsIContent * aChild, 1.129 + int32_t aIndexInContainer, 1.130 + nsIContent * aPreviousSibling) 1.131 +{ 1.132 + if (!aContainer) { 1.133 + return; 1.134 + } 1.135 + 1.136 + nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); 1.137 + nsChangeObserver* obs = LookupContentChangeObserver(aContainer); 1.138 + if (obs) 1.139 + obs->ObserveContentRemoved(aDocument, aChild, aIndexInContainer); 1.140 + else if (aContainer != mContent) { 1.141 + // We do a lookup on the parent container in case things were removed 1.142 + // under a "menupopup" item. That is basically a wrapper for the contents 1.143 + // of a "menu" node. 1.144 + nsCOMPtr<nsIContent> parent = aContainer->GetParent(); 1.145 + if (parent) { 1.146 + obs = LookupContentChangeObserver(parent); 1.147 + if (obs) 1.148 + obs->ObserveContentRemoved(aDocument, aChild, aIndexInContainer); 1.149 + } 1.150 + } 1.151 +} 1.152 + 1.153 + 1.154 +void nsMenuGroupOwnerX::ContentInserted(nsIDocument * aDocument, 1.155 + nsIContent * aContainer, 1.156 + nsIContent * aChild, 1.157 + int32_t /* unused */) 1.158 +{ 1.159 + if (!aContainer) { 1.160 + return; 1.161 + } 1.162 + 1.163 + nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); 1.164 + nsChangeObserver* obs = LookupContentChangeObserver(aContainer); 1.165 + if (obs) 1.166 + obs->ObserveContentInserted(aDocument, aContainer, aChild); 1.167 + else if (aContainer != mContent) { 1.168 + // We do a lookup on the parent container in case things were removed 1.169 + // under a "menupopup" item. That is basically a wrapper for the contents 1.170 + // of a "menu" node. 1.171 + nsCOMPtr<nsIContent> parent = aContainer->GetParent(); 1.172 + if (parent) { 1.173 + obs = LookupContentChangeObserver(parent); 1.174 + if (obs) 1.175 + obs->ObserveContentInserted(aDocument, aContainer, aChild); 1.176 + } 1.177 + } 1.178 +} 1.179 + 1.180 + 1.181 +void nsMenuGroupOwnerX::ParentChainChanged(nsIContent *aContent) 1.182 +{ 1.183 +} 1.184 + 1.185 + 1.186 +// For change management, we don't use a |nsSupportsHashtable| because 1.187 +// we know that the lifetime of all these items is bounded by the 1.188 +// lifetime of the menubar. No need to add any more strong refs to the 1.189 +// picture because the containment hierarchy already uses strong refs. 1.190 +void nsMenuGroupOwnerX::RegisterForContentChanges(nsIContent *aContent, 1.191 + nsChangeObserver *aMenuObject) 1.192 +{ 1.193 + mContentToObserverTable.Put(aContent, aMenuObject); 1.194 +} 1.195 + 1.196 + 1.197 +void nsMenuGroupOwnerX::UnregisterForContentChanges(nsIContent *aContent) 1.198 +{ 1.199 + mContentToObserverTable.Remove(aContent); 1.200 +} 1.201 + 1.202 + 1.203 +nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(nsIContent* aContent) 1.204 +{ 1.205 + nsChangeObserver * result; 1.206 + if (mContentToObserverTable.Get(aContent, &result)) 1.207 + return result; 1.208 + else 1.209 + return nullptr; 1.210 +} 1.211 + 1.212 + 1.213 +// Given a menu item, creates a unique 4-character command ID and 1.214 +// maps it to the item. Returns the id for use by the client. 1.215 +uint32_t nsMenuGroupOwnerX::RegisterForCommand(nsMenuItemX* inMenuItem) 1.216 +{ 1.217 + // no real need to check for uniqueness. We always start afresh with each 1.218 + // window at 1. Even if we did get close to the reserved Apple command id's, 1.219 + // those don't start until at least ' ', which is integer 538976288. If 1.220 + // we have that many menu items in one window, I think we have other 1.221 + // problems. 1.222 + 1.223 + // make id unique 1.224 + ++mCurrentCommandID; 1.225 + 1.226 + mCommandToMenuObjectTable.Put(mCurrentCommandID, inMenuItem); 1.227 + 1.228 + return mCurrentCommandID; 1.229 +} 1.230 + 1.231 + 1.232 +// Removes the mapping between the given 4-character command ID 1.233 +// and its associated menu item. 1.234 +void nsMenuGroupOwnerX::UnregisterCommand(uint32_t inCommandID) 1.235 +{ 1.236 + mCommandToMenuObjectTable.Remove(inCommandID); 1.237 +} 1.238 + 1.239 + 1.240 +nsMenuItemX* nsMenuGroupOwnerX::GetMenuItemForCommandID(uint32_t inCommandID) 1.241 +{ 1.242 + nsMenuItemX * result; 1.243 + if (mCommandToMenuObjectTable.Get(inCommandID, &result)) 1.244 + return result; 1.245 + else 1.246 + return nullptr; 1.247 +}