widget/cocoa/nsMenuGroupOwnerX.mm

changeset 0
6474c204b198
     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 +}

mercurial