/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __nsNativeMenuDocListener_h__ #define __nsNativeMenuDocListener_h__ #include "mozilla/Attributes.h" #include "mozilla/GuardObjects.h" #include "mozilla/RefPtr.h" #include "nsAutoPtr.h" #include "nsDataHashtable.h" #include "nsStubMutationObserver.h" #include "nsTArray.h" class nsIAtom; class nsIContent; class nsIDocument; class nsNativeMenuChangeObserver; /* * This class keeps a mapping of content nodes to observers and forwards DOM * mutations to these. There is exactly one of these for every menubar. */ class nsNativeMenuDocListener final : nsStubMutationObserver { public: NS_DECL_ISUPPORTS nsNativeMenuDocListener(nsIContent* aRootNode); // Register an observer to receive mutation events for the specified // content node. The caller must keep the observer alive until // UnregisterForContentChanges is called. void RegisterForContentChanges(nsIContent* aContent, nsNativeMenuChangeObserver* aObserver); // Unregister the registered observer for the specified content node void UnregisterForContentChanges(nsIContent* aContent); // Start listening to the document and forwarding DOM mutations to // registered observers. void Start(); // Stop listening to the document. No DOM mutations will be forwarded // to registered observers. void Stop(); /* * This class is intended to be used inside GObject signal handlers. * It allows us to queue updates until we have finished delivering * events to Goanna, and then we can batch updates to our view of the * menu. This allows us to do menu updates without altering the structure * seen by the OS. */ class MOZ_STACK_CLASS BlockUpdatesScope { public: BlockUpdatesScope(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; nsNativeMenuDocListener::AddUpdateBlocker(); } ~BlockUpdatesScope() { nsNativeMenuDocListener::RemoveUpdateBlocker(); } private: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; private: friend class DispatchHelper; struct MutationRecord { enum RecordType { eAttributeChanged, eContentInserted, eContentRemoved } mType; nsCOMPtr mTarget; nsCOMPtr mChild; nsCOMPtr mPrevSibling; nsCOMPtr mAttribute; }; ~nsNativeMenuDocListener(); NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED void DoAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute); void DoContentInserted(nsIContent* aContainer, nsIContent* aChild, nsIContent* aPrevSibling); void DoContentRemoved(nsIContent* aContainer, nsIContent* aChild); void DoBeginUpdates(nsIContent* aTarget); void DoEndUpdates(nsIContent* aTarget); void FlushPendingMutations(); static void ScheduleFlush(nsNativeMenuDocListener* aListener); static void CancelFlush(nsNativeMenuDocListener* aListener); static void AddUpdateBlocker() { ++sUpdateBlockersCount; } static void RemoveUpdateBlocker(); nsCOMPtr mRootNode; nsIDocument* mDocument; nsIContent* mLastSource; nsNativeMenuChangeObserver* mLastTarget; nsTArray > mPendingMutations; nsDataHashtable, nsNativeMenuChangeObserver* > mContentToObserverTable; static uint32_t sUpdateBlockersCount; }; typedef nsTArray > nsNativeMenuDocListenerTArray; /* * Implemented by classes that want to listen to mutation events from content * nodes. */ class nsNativeMenuChangeObserver { public: virtual void OnAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute) {} virtual void OnContentInserted(nsIContent* aContainer, nsIContent* aChild, nsIContent* aPrevSibling) {} virtual void OnContentRemoved(nsIContent* aContainer, nsIContent* aChild) {} // Signals the start of a sequence of more than 1 event for the specified // node. This only happens when events are flushed as all BlockUpdatesScope // instances go out of scope virtual void OnBeginUpdates(nsIContent* aContent) {}; // Signals the end of a sequence of events virtual void OnEndUpdates() {}; }; #endif /* __nsNativeMenuDocListener_h__ */