Mypal/widget/gtk/nsNativeMenuDocListener.h

147 lines
4.8 KiB
C++

/* 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<nsIContent> mTarget;
nsCOMPtr<nsIContent> mChild;
nsCOMPtr<nsIContent> mPrevSibling;
nsCOMPtr<nsIAtom> 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<nsIContent> mRootNode;
nsIDocument* mDocument;
nsIContent* mLastSource;
nsNativeMenuChangeObserver* mLastTarget;
nsTArray<nsAutoPtr<MutationRecord> > mPendingMutations;
nsDataHashtable<nsPtrHashKey<nsIContent>, nsNativeMenuChangeObserver* > mContentToObserverTable;
static uint32_t sUpdateBlockersCount;
};
typedef nsTArray<RefPtr<nsNativeMenuDocListener> > 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__ */