summaryrefslogtreecommitdiffstats
path: root/embedding/components/commandhandler
diff options
context:
space:
mode:
Diffstat (limited to 'embedding/components/commandhandler')
-rw-r--r--embedding/components/commandhandler/moz.build26
-rw-r--r--embedding/components/commandhandler/nsBaseCommandController.cpp184
-rw-r--r--embedding/components/commandhandler/nsBaseCommandController.h49
-rw-r--r--embedding/components/commandhandler/nsCommandGroup.cpp296
-rw-r--r--embedding/components/commandhandler/nsCommandGroup.h44
-rw-r--r--embedding/components/commandhandler/nsCommandManager.cpp262
-rw-r--r--embedding/components/commandhandler/nsCommandManager.h50
-rw-r--r--embedding/components/commandhandler/nsCommandParams.cpp264
-rw-r--r--embedding/components/commandhandler/nsCommandParams.h131
-rw-r--r--embedding/components/commandhandler/nsControllerCommandTable.cpp209
-rw-r--r--embedding/components/commandhandler/nsControllerCommandTable.h36
-rw-r--r--embedding/components/commandhandler/nsICommandManager.idl118
-rw-r--r--embedding/components/commandhandler/nsICommandParams.idl85
-rw-r--r--embedding/components/commandhandler/nsIControllerCommand.idl51
-rw-r--r--embedding/components/commandhandler/nsIControllerCommandTable.idl100
-rw-r--r--embedding/components/commandhandler/nsIControllerContext.idl35
-rw-r--r--embedding/components/commandhandler/nsPICommandUpdater.idl39
17 files changed, 1979 insertions, 0 deletions
diff --git a/embedding/components/commandhandler/moz.build b/embedding/components/commandhandler/moz.build
new file mode 100644
index 000000000..d44d57f20
--- /dev/null
+++ b/embedding/components/commandhandler/moz.build
@@ -0,0 +1,26 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPIDL_SOURCES += [
+ 'nsICommandManager.idl',
+ 'nsICommandParams.idl',
+ 'nsIControllerCommand.idl',
+ 'nsIControllerCommandTable.idl',
+ 'nsIControllerContext.idl',
+ 'nsPICommandUpdater.idl',
+]
+
+XPIDL_MODULE = 'commandhandler'
+
+UNIFIED_SOURCES += [
+ 'nsBaseCommandController.cpp',
+ 'nsCommandGroup.cpp',
+ 'nsCommandManager.cpp',
+ 'nsCommandParams.cpp',
+ 'nsControllerCommandTable.cpp',
+]
+
+FINAL_LIBRARY = 'xul'
diff --git a/embedding/components/commandhandler/nsBaseCommandController.cpp b/embedding/components/commandhandler/nsBaseCommandController.cpp
new file mode 100644
index 000000000..2bd87b6f5
--- /dev/null
+++ b/embedding/components/commandhandler/nsBaseCommandController.cpp
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nsString.h"
+#include "nsIComponentManager.h"
+#include "nsBaseCommandController.h"
+
+#include "nsString.h"
+#include "nsWeakPtr.h"
+
+NS_IMPL_ADDREF(nsBaseCommandController)
+NS_IMPL_RELEASE(nsBaseCommandController)
+
+NS_INTERFACE_MAP_BEGIN(nsBaseCommandController)
+ NS_INTERFACE_MAP_ENTRY(nsIController)
+ NS_INTERFACE_MAP_ENTRY(nsICommandController)
+ NS_INTERFACE_MAP_ENTRY(nsIControllerContext)
+ NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIControllerContext)
+NS_INTERFACE_MAP_END
+
+nsBaseCommandController::nsBaseCommandController()
+ : mCommandContextRawPtr(nullptr)
+{
+}
+
+nsBaseCommandController::~nsBaseCommandController()
+{
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::Init(nsIControllerCommandTable* aCommandTable)
+{
+ nsresult rv = NS_OK;
+
+ if (aCommandTable) {
+ mCommandTable = aCommandTable;
+ } else {
+ mCommandTable =
+ do_CreateInstance(NS_CONTROLLERCOMMANDTABLE_CONTRACTID, &rv);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::SetCommandContext(nsISupports* aCommandContext)
+{
+ mCommandContextWeakPtr = nullptr;
+ mCommandContextRawPtr = nullptr;
+
+ if (aCommandContext) {
+ nsCOMPtr<nsISupportsWeakReference> weak = do_QueryInterface(aCommandContext);
+ if (weak) {
+ nsresult rv =
+ weak->GetWeakReference(getter_AddRefs(mCommandContextWeakPtr));
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ mCommandContextRawPtr = aCommandContext;
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::GetInterface(const nsIID& aIID, void** aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ if (NS_SUCCEEDED(QueryInterface(aIID, aResult))) {
+ return NS_OK;
+ }
+
+ if (aIID.Equals(NS_GET_IID(nsIControllerCommandTable))) {
+ if (mCommandTable) {
+ return mCommandTable->QueryInterface(aIID, aResult);
+ }
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ return NS_NOINTERFACE;
+}
+
+/* =======================================================================
+ * nsIController
+ * ======================================================================= */
+
+NS_IMETHODIMP
+nsBaseCommandController::IsCommandEnabled(const char* aCommand, bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aCommand);
+ NS_ENSURE_ARG_POINTER(aResult);
+ NS_ENSURE_STATE(mCommandTable);
+
+ nsISupports* context = mCommandContextRawPtr;
+ nsCOMPtr<nsISupports> weak;
+ if (!context) {
+ weak = do_QueryReferent(mCommandContextWeakPtr);
+ context = weak;
+ }
+ return mCommandTable->IsCommandEnabled(aCommand, context, aResult);
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::SupportsCommand(const char* aCommand, bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aCommand);
+ NS_ENSURE_ARG_POINTER(aResult);
+ NS_ENSURE_STATE(mCommandTable);
+
+ nsISupports* context = mCommandContextRawPtr;
+ nsCOMPtr<nsISupports> weak;
+ if (!context) {
+ weak = do_QueryReferent(mCommandContextWeakPtr);
+ context = weak;
+ }
+ return mCommandTable->SupportsCommand(aCommand, context, aResult);
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::DoCommand(const char* aCommand)
+{
+ NS_ENSURE_ARG_POINTER(aCommand);
+ NS_ENSURE_STATE(mCommandTable);
+
+ nsISupports* context = mCommandContextRawPtr;
+ nsCOMPtr<nsISupports> weak;
+ if (!context) {
+ weak = do_QueryReferent(mCommandContextWeakPtr);
+ context = weak;
+ }
+ return mCommandTable->DoCommand(aCommand, context);
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::DoCommandWithParams(const char* aCommand,
+ nsICommandParams* aParams)
+{
+ NS_ENSURE_ARG_POINTER(aCommand);
+ NS_ENSURE_STATE(mCommandTable);
+
+ nsISupports* context = mCommandContextRawPtr;
+ nsCOMPtr<nsISupports> weak;
+ if (!context) {
+ weak = do_QueryReferent(mCommandContextWeakPtr);
+ context = weak;
+ }
+ return mCommandTable->DoCommandParams(aCommand, aParams, context);
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::GetCommandStateWithParams(const char* aCommand,
+ nsICommandParams* aParams)
+{
+ NS_ENSURE_ARG_POINTER(aCommand);
+ NS_ENSURE_STATE(mCommandTable);
+
+ nsISupports* context = mCommandContextRawPtr;
+ nsCOMPtr<nsISupports> weak;
+ if (!context) {
+ weak = do_QueryReferent(mCommandContextWeakPtr);
+ context = weak;
+ }
+ return mCommandTable->GetCommandState(aCommand, aParams, context);
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::OnEvent(const char* aEventName)
+{
+ NS_ENSURE_ARG_POINTER(aEventName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBaseCommandController::GetSupportedCommands(uint32_t* aCount,
+ char*** aCommands)
+{
+ NS_ENSURE_STATE(mCommandTable);
+ return mCommandTable->GetSupportedCommands(aCount, aCommands);
+}
diff --git a/embedding/components/commandhandler/nsBaseCommandController.h b/embedding/components/commandhandler/nsBaseCommandController.h
new file mode 100644
index 000000000..83976faac
--- /dev/null
+++ b/embedding/components/commandhandler/nsBaseCommandController.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 nsBaseCommandController_h__
+#define nsBaseCommandController_h__
+
+#define NS_BASECOMMANDCONTROLLER_CID \
+ { 0xbf88b48c, 0xfd8e, 0x40b4, { 0xba, 0x36, 0xc7, 0xc3, 0xad, 0x6d, 0x8a, 0xc9 } }
+#define NS_BASECOMMANDCONTROLLER_CONTRACTID \
+ "@mozilla.org/embedcomp/base-command-controller;1"
+
+#include "nsIController.h"
+#include "nsIControllerContext.h"
+#include "nsIControllerCommandTable.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIWeakReferenceUtils.h"
+
+// The base editor controller is used for both text widgets, and all other text
+// and html editing
+class nsBaseCommandController
+ : public nsIController
+ , public nsIControllerContext
+ , public nsIInterfaceRequestor
+ , public nsICommandController
+{
+public:
+ nsBaseCommandController();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICONTROLLER
+ NS_DECL_NSICOMMANDCONTROLLER
+ NS_DECL_NSICONTROLLERCONTEXT
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+protected:
+ virtual ~nsBaseCommandController();
+
+private:
+ nsWeakPtr mCommandContextWeakPtr;
+ nsISupports* mCommandContextRawPtr;
+
+ // Our reference to the command manager
+ nsCOMPtr<nsIControllerCommandTable> mCommandTable;
+};
+
+#endif /* nsBaseCommandController_h_ */
diff --git a/embedding/components/commandhandler/nsCommandGroup.cpp b/embedding/components/commandhandler/nsCommandGroup.cpp
new file mode 100644
index 000000000..696b93f67
--- /dev/null
+++ b/embedding/components/commandhandler/nsCommandGroup.cpp
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nsString.h"
+#include "nsReadableUtils.h"
+#include "nsTArray.h"
+#include "nsISimpleEnumerator.h"
+#include "nsXPCOM.h"
+#include "nsSupportsPrimitives.h"
+#include "nsIComponentManager.h"
+#include "nsCommandGroup.h"
+#include "nsIControllerCommand.h"
+#include "nsCRT.h"
+
+class nsGroupsEnumerator : public nsISimpleEnumerator
+{
+public:
+ explicit nsGroupsEnumerator(
+ nsControllerCommandGroup::GroupsHashtable& aInHashTable);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISIMPLEENUMERATOR
+
+protected:
+ virtual ~nsGroupsEnumerator();
+
+ nsresult Initialize();
+
+protected:
+ nsControllerCommandGroup::GroupsHashtable& mHashTable;
+ int32_t mIndex;
+ const char** mGroupNames; // array of pointers to char16_t* in the hash table
+ bool mInitted;
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS(nsGroupsEnumerator, nsISimpleEnumerator)
+
+nsGroupsEnumerator::nsGroupsEnumerator(
+ nsControllerCommandGroup::GroupsHashtable& aInHashTable)
+ : mHashTable(aInHashTable)
+ , mIndex(-1)
+ , mGroupNames(nullptr)
+ , mInitted(false)
+{
+}
+
+nsGroupsEnumerator::~nsGroupsEnumerator()
+{
+ delete[] mGroupNames;
+}
+
+NS_IMETHODIMP
+nsGroupsEnumerator::HasMoreElements(bool* aResult)
+{
+ nsresult rv = NS_OK;
+
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ if (!mInitted) {
+ rv = Initialize();
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ *aResult = (mIndex < static_cast<int32_t>(mHashTable.Count()) - 1);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGroupsEnumerator::GetNext(nsISupports** aResult)
+{
+ nsresult rv = NS_OK;
+
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ if (!mInitted) {
+ rv = Initialize();
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ mIndex++;
+ if (mIndex >= static_cast<int32_t>(mHashTable.Count())) {
+ return NS_ERROR_FAILURE;
+ }
+
+ const char* thisGroupName = mGroupNames[mIndex];
+
+ nsCOMPtr<nsISupportsCString> supportsString =
+ do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ supportsString->SetData(nsDependentCString(thisGroupName));
+ return CallQueryInterface(supportsString, aResult);
+}
+
+nsresult
+nsGroupsEnumerator::Initialize()
+{
+ if (mInitted) {
+ return NS_OK;
+ }
+
+ mGroupNames = new const char*[mHashTable.Count()];
+ if (!mGroupNames) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ mIndex = 0;
+ for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) {
+ mGroupNames[mIndex] = iter.Key().Data();
+ mIndex++;
+ }
+
+ mIndex = -1;
+ mInitted = true;
+ return NS_OK;
+}
+
+class nsNamedGroupEnumerator : public nsISimpleEnumerator
+{
+public:
+ explicit nsNamedGroupEnumerator(nsTArray<nsCString>* aInArray);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISIMPLEENUMERATOR
+
+protected:
+ virtual ~nsNamedGroupEnumerator();
+
+ nsTArray<nsCString>* mGroupArray;
+ int32_t mIndex;
+};
+
+nsNamedGroupEnumerator::nsNamedGroupEnumerator(nsTArray<nsCString>* aInArray)
+ : mGroupArray(aInArray)
+ , mIndex(-1)
+{
+}
+
+nsNamedGroupEnumerator::~nsNamedGroupEnumerator()
+{
+}
+
+NS_IMPL_ISUPPORTS(nsNamedGroupEnumerator, nsISimpleEnumerator)
+
+NS_IMETHODIMP
+nsNamedGroupEnumerator::HasMoreElements(bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ int32_t arrayLen = mGroupArray ? mGroupArray->Length() : 0;
+ *aResult = (mIndex < arrayLen - 1);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNamedGroupEnumerator::GetNext(nsISupports** aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ if (!mGroupArray) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mIndex++;
+ if (mIndex >= int32_t(mGroupArray->Length())) {
+ return NS_ERROR_FAILURE;
+ }
+
+ const nsCString& thisGroupName = mGroupArray->ElementAt(mIndex);
+
+ nsresult rv;
+ nsCOMPtr<nsISupportsCString> supportsString =
+ do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ supportsString->SetData(thisGroupName);
+ return CallQueryInterface(supportsString, aResult);
+}
+
+NS_IMPL_ISUPPORTS(nsControllerCommandGroup, nsIControllerCommandGroup)
+
+nsControllerCommandGroup::nsControllerCommandGroup()
+{
+}
+
+nsControllerCommandGroup::~nsControllerCommandGroup()
+{
+ ClearGroupsHash();
+}
+
+void
+nsControllerCommandGroup::ClearGroupsHash()
+{
+ mGroupsHash.Clear();
+}
+
+NS_IMETHODIMP
+nsControllerCommandGroup::AddCommandToGroup(const char* aCommand,
+ const char* aGroup)
+{
+ nsDependentCString groupKey(aGroup);
+ nsTArray<nsCString>* commandList = mGroupsHash.Get(groupKey);
+ if (!commandList) {
+ // make this list
+ commandList = new AutoTArray<nsCString, 8>;
+ mGroupsHash.Put(groupKey, commandList);
+ }
+
+#ifdef DEBUG
+ nsCString* appended =
+#endif
+ commandList->AppendElement(aCommand);
+ NS_ASSERTION(appended, "Append failed");
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandGroup::RemoveCommandFromGroup(const char* aCommand,
+ const char* aGroup)
+{
+ nsDependentCString groupKey(aGroup);
+ nsTArray<nsCString>* commandList = mGroupsHash.Get(groupKey);
+ if (!commandList) {
+ return NS_OK; // no group
+ }
+
+ uint32_t numEntries = commandList->Length();
+ for (uint32_t i = 0; i < numEntries; i++) {
+ nsCString commandString = commandList->ElementAt(i);
+ if (nsDependentCString(aCommand) != commandString) {
+ commandList->RemoveElementAt(i);
+ break;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandGroup::IsCommandInGroup(const char* aCommand,
+ const char* aGroup, bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+ *aResult = false;
+
+ nsDependentCString groupKey(aGroup);
+ nsTArray<nsCString>* commandList = mGroupsHash.Get(groupKey);
+ if (!commandList) {
+ return NS_OK; // no group
+ }
+
+ uint32_t numEntries = commandList->Length();
+ for (uint32_t i = 0; i < numEntries; i++) {
+ nsCString commandString = commandList->ElementAt(i);
+ if (nsDependentCString(aCommand) != commandString) {
+ *aResult = true;
+ break;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandGroup::GetGroupsEnumerator(nsISimpleEnumerator** aResult)
+{
+ RefPtr<nsGroupsEnumerator> groupsEnum = new nsGroupsEnumerator(mGroupsHash);
+
+ groupsEnum.forget(aResult);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandGroup::GetEnumeratorForGroup(const char* aGroup,
+ nsISimpleEnumerator** aResult)
+{
+ nsDependentCString groupKey(aGroup);
+ nsTArray<nsCString>* commandList = mGroupsHash.Get(groupKey); // may be null
+
+ RefPtr<nsNamedGroupEnumerator> theGroupEnum =
+ new nsNamedGroupEnumerator(commandList);
+
+ theGroupEnum.forget(aResult);
+ return NS_OK;
+}
diff --git a/embedding/components/commandhandler/nsCommandGroup.h b/embedding/components/commandhandler/nsCommandGroup.h
new file mode 100644
index 000000000..b06d725b3
--- /dev/null
+++ b/embedding/components/commandhandler/nsCommandGroup.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 nsCommandGroup_h__
+#define nsCommandGroup_h__
+
+#include "nsIController.h"
+#include "nsClassHashtable.h"
+#include "nsHashKeys.h"
+
+// {ecd55a01-2780-11d5-a73c-ca641a6813bc}
+#define NS_CONTROLLER_COMMAND_GROUP_CID \
+ { 0xecd55a01, 0x2780, 0x11d5, { 0xa7, 0x3c, 0xca, 0x64, 0x1a, 0x68, 0x13, 0xbc } }
+
+#define NS_CONTROLLER_COMMAND_GROUP_CONTRACTID \
+ "@mozilla.org/embedcomp/controller-command-group;1"
+
+class nsControllerCommandGroup : public nsIControllerCommandGroup
+{
+public:
+ nsControllerCommandGroup();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICONTROLLERCOMMANDGROUP
+
+public:
+ typedef nsClassHashtable<nsCStringHashKey, nsTArray<nsCString>>
+ GroupsHashtable;
+
+protected:
+ virtual ~nsControllerCommandGroup();
+
+ void ClearGroupsHash();
+
+protected:
+ // Hash keyed on command group. This could be made more space-efficient,
+ // maybe with atoms.
+ GroupsHashtable mGroupsHash;
+};
+
+#endif // nsCommandGroup_h__
diff --git a/embedding/components/commandhandler/nsCommandManager.cpp b/embedding/components/commandhandler/nsCommandManager.cpp
new file mode 100644
index 000000000..c11a901b2
--- /dev/null
+++ b/embedding/components/commandhandler/nsCommandManager.cpp
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nsString.h"
+
+#include "nsIController.h"
+#include "nsIControllers.h"
+#include "nsIObserver.h"
+
+#include "nsIComponentManager.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsIScriptSecurityManager.h"
+
+#include "nsContentUtils.h"
+#include "nsIDOMWindow.h"
+#include "nsPIDOMWindow.h"
+#include "nsPIWindowRoot.h"
+#include "nsIFocusManager.h"
+
+#include "nsCOMArray.h"
+
+#include "nsCommandManager.h"
+
+nsCommandManager::nsCommandManager()
+ : mWindow(nullptr)
+{
+}
+
+nsCommandManager::~nsCommandManager()
+{
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
+ tmp->mObserversTable.Clear();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager)
+ for (auto iter = tmp->mObserversTable.Iter(); !iter.Done(); iter.Next()) {
+ nsCommandManager::ObserverList* observers = iter.UserData();
+ int32_t numItems = observers->Length();
+ for (int32_t i = 0; i < numItems; ++i) {
+ cb.NoteXPCOMChild(observers->ElementAt(i));
+ }
+ }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager)
+ NS_INTERFACE_MAP_ENTRY(nsICommandManager)
+ NS_INTERFACE_MAP_ENTRY(nsPICommandUpdater)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP
+nsCommandManager::Init(mozIDOMWindowProxy* aWindow)
+{
+ NS_ENSURE_ARG_POINTER(aWindow);
+
+ mWindow = aWindow; // weak ptr
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandManager::CommandStatusChanged(const char* aCommandName)
+{
+ ObserverList* commandObservers;
+ mObserversTable.Get(aCommandName, &commandObservers);
+
+ if (commandObservers) {
+ // XXX Should we worry about observers removing themselves from Observe()?
+ int32_t i, numItems = commandObservers->Length();
+ for (i = 0; i < numItems; ++i) {
+ nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i);
+ // should we get the command state to pass here? This might be expensive.
+ observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this),
+ aCommandName,
+ u"command_status_changed");
+ }
+ }
+
+ return NS_OK;
+}
+
+#if 0
+#pragma mark -
+#endif
+
+NS_IMETHODIMP
+nsCommandManager::AddCommandObserver(nsIObserver* aCommandObserver,
+ const char* aCommandToObserve)
+{
+ NS_ENSURE_ARG(aCommandObserver);
+
+ // XXX todo: handle special cases of aCommandToObserve being null, or empty
+
+ // for each command in the table, we make a list of observers for that command
+ ObserverList* commandObservers;
+ if (!mObserversTable.Get(aCommandToObserve, &commandObservers)) {
+ commandObservers = new ObserverList;
+ mObserversTable.Put(aCommandToObserve, commandObservers);
+ }
+
+ // need to check that this command observer hasn't already been registered
+ int32_t existingIndex = commandObservers->IndexOf(aCommandObserver);
+ if (existingIndex == -1) {
+ commandObservers->AppendElement(aCommandObserver);
+ } else {
+ NS_WARNING("Registering command observer twice on the same command");
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandManager::RemoveCommandObserver(nsIObserver* aCommandObserver,
+ const char* aCommandObserved)
+{
+ NS_ENSURE_ARG(aCommandObserver);
+
+ // XXX todo: handle special cases of aCommandToObserve being null, or empty
+
+ ObserverList* commandObservers;
+ if (!mObserversTable.Get(aCommandObserved, &commandObservers)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ commandObservers->RemoveElement(aCommandObserver);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandManager::IsCommandSupported(const char* aCommandName,
+ mozIDOMWindowProxy* aTargetWindow,
+ bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ nsCOMPtr<nsIController> controller;
+ GetControllerForCommand(aCommandName, aTargetWindow,
+ getter_AddRefs(controller));
+ *aResult = (controller.get() != nullptr);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandManager::IsCommandEnabled(const char* aCommandName,
+ mozIDOMWindowProxy* aTargetWindow,
+ bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ bool commandEnabled = false;
+
+ nsCOMPtr<nsIController> controller;
+ GetControllerForCommand(aCommandName, aTargetWindow,
+ getter_AddRefs(controller));
+ if (controller) {
+ controller->IsCommandEnabled(aCommandName, &commandEnabled);
+ }
+ *aResult = commandEnabled;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandManager::GetCommandState(const char* aCommandName,
+ mozIDOMWindowProxy* aTargetWindow,
+ nsICommandParams* aCommandParams)
+{
+ nsCOMPtr<nsIController> controller;
+ nsAutoString tValue;
+ nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
+ getter_AddRefs(controller));
+ if (!controller) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsICommandController> commandController =
+ do_QueryInterface(controller);
+ if (commandController) {
+ rv = commandController->GetCommandStateWithParams(aCommandName,
+ aCommandParams);
+ } else {
+ rv = NS_ERROR_NOT_IMPLEMENTED;
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsCommandManager::DoCommand(const char* aCommandName,
+ nsICommandParams* aCommandParams,
+ mozIDOMWindowProxy* aTargetWindow)
+{
+ nsCOMPtr<nsIController> controller;
+ nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
+ getter_AddRefs(controller));
+ if (!controller) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsICommandController> commandController =
+ do_QueryInterface(controller);
+ if (commandController && aCommandParams) {
+ rv = commandController->DoCommandWithParams(aCommandName, aCommandParams);
+ } else {
+ rv = controller->DoCommand(aCommandName);
+ }
+ return rv;
+}
+
+nsresult
+nsCommandManager::GetControllerForCommand(const char* aCommand,
+ mozIDOMWindowProxy* aTargetWindow,
+ nsIController** aResult)
+{
+ nsresult rv = NS_ERROR_FAILURE;
+ *aResult = nullptr;
+
+ // check if we're in content or chrome
+ // if we're not chrome we must have a target window or we bail
+ if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
+ if (!aTargetWindow) {
+ return rv;
+ }
+
+ // if a target window is specified, it must be the window we expect
+ if (aTargetWindow != mWindow) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ if (auto* targetWindow = nsPIDOMWindowOuter::From(aTargetWindow)) {
+ // get the controller for this particular window
+ nsCOMPtr<nsIControllers> controllers;
+ rv = targetWindow->GetControllers(getter_AddRefs(controllers));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (!controllers) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // dispatch the command
+ return controllers->GetControllerForCommand(aCommand, aResult);
+ }
+
+ auto* window = nsPIDOMWindowOuter::From(mWindow);
+ NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+ nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
+ NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
+
+ // no target window; send command to focus controller
+ return root->GetControllerForCommand(aCommand, aResult);
+}
diff --git a/embedding/components/commandhandler/nsCommandManager.h b/embedding/components/commandhandler/nsCommandManager.h
new file mode 100644
index 000000000..1d26c40ba
--- /dev/null
+++ b/embedding/components/commandhandler/nsCommandManager.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 nsCommandManager_h__
+#define nsCommandManager_h__
+
+#include "nsString.h"
+#include "nsClassHashtable.h"
+#include "nsWeakReference.h"
+
+#include "nsICommandManager.h"
+#include "nsPICommandUpdater.h"
+#include "nsCycleCollectionParticipant.h"
+
+class nsIController;
+template<class E> class nsCOMArray;
+
+class nsCommandManager
+ : public nsICommandManager
+ , public nsPICommandUpdater
+ , public nsSupportsWeakReference
+{
+public:
+ typedef nsTArray<nsCOMPtr<nsIObserver> > ObserverList;
+
+ nsCommandManager();
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCommandManager, nsICommandManager)
+
+ NS_DECL_NSICOMMANDMANAGER
+ NS_DECL_NSPICOMMANDUPDATER
+
+protected:
+ virtual ~nsCommandManager();
+
+ nsresult GetControllerForCommand(const char* aCommand,
+ mozIDOMWindowProxy* aDirectedToThisWindow,
+ nsIController** aResult);
+
+protected:
+ nsClassHashtable<nsCharPtrHashKey, ObserverList> mObserversTable;
+
+ mozIDOMWindowProxy* mWindow; // weak ptr. The window should always outlive us
+};
+
+#endif // nsCommandManager_h__
diff --git a/embedding/components/commandhandler/nsCommandParams.cpp b/embedding/components/commandhandler/nsCommandParams.cpp
new file mode 100644
index 000000000..86647d4dd
--- /dev/null
+++ b/embedding/components/commandhandler/nsCommandParams.cpp
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "xpcom-config.h"
+#include <new>
+#include "nscore.h"
+#include "nsCRT.h"
+
+#include "nsCommandParams.h"
+#include "mozilla/HashFunctions.h"
+
+using namespace mozilla;
+
+const PLDHashTableOps nsCommandParams::sHashOps =
+{
+ HashKey,
+ HashMatchEntry,
+ HashMoveEntry,
+ HashClearEntry
+};
+
+NS_IMPL_ISUPPORTS(nsCommandParams, nsICommandParams)
+
+nsCommandParams::nsCommandParams()
+ : mValuesHash(&sHashOps, sizeof(HashEntry), 2)
+{
+}
+
+nsCommandParams::~nsCommandParams()
+{
+}
+
+NS_IMETHODIMP
+nsCommandParams::GetValueType(const char* aName, int16_t* aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aRetVal);
+
+ HashEntry* foundEntry = GetNamedEntry(aName);
+ if (foundEntry) {
+ *aRetVal = foundEntry->mEntryType;
+ return NS_OK;
+ }
+ *aRetVal = eNoType;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsCommandParams::GetBooleanValue(const char* aName, bool* aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aRetVal);
+
+ HashEntry* foundEntry = GetNamedEntry(aName);
+ if (foundEntry && foundEntry->mEntryType == eBooleanType) {
+ *aRetVal = foundEntry->mData.mBoolean;
+ return NS_OK;
+ }
+ *aRetVal = false;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsCommandParams::GetLongValue(const char* aName, int32_t* aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aRetVal);
+
+ HashEntry* foundEntry = GetNamedEntry(aName);
+ if (foundEntry && foundEntry->mEntryType == eLongType) {
+ *aRetVal = foundEntry->mData.mLong;
+ return NS_OK;
+ }
+ *aRetVal = false;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsCommandParams::GetDoubleValue(const char* aName, double* aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aRetVal);
+
+ HashEntry* foundEntry = GetNamedEntry(aName);
+ if (foundEntry && foundEntry->mEntryType == eDoubleType) {
+ *aRetVal = foundEntry->mData.mDouble;
+ return NS_OK;
+ }
+ *aRetVal = 0.0;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsCommandParams::GetStringValue(const char* aName, nsAString& aRetVal)
+{
+ HashEntry* foundEntry = GetNamedEntry(aName);
+ if (foundEntry && foundEntry->mEntryType == eWStringType) {
+ NS_ASSERTION(foundEntry->mData.mString, "Null string");
+ aRetVal.Assign(*foundEntry->mData.mString);
+ return NS_OK;
+ }
+ aRetVal.Truncate();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsCommandParams::GetCStringValue(const char* aName, char** aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aRetVal);
+
+ HashEntry* foundEntry = GetNamedEntry(aName);
+ if (foundEntry && foundEntry->mEntryType == eStringType) {
+ NS_ASSERTION(foundEntry->mData.mCString, "Null string");
+ *aRetVal = ToNewCString(*foundEntry->mData.mCString);
+ return NS_OK;
+ }
+ *aRetVal = nullptr;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsCommandParams::GetISupportsValue(const char* aName, nsISupports** aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aRetVal);
+
+ HashEntry* foundEntry = GetNamedEntry(aName);
+ if (foundEntry && foundEntry->mEntryType == eISupportsType) {
+ NS_IF_ADDREF(*aRetVal = foundEntry->mISupports.get());
+ return NS_OK;
+ }
+ *aRetVal = nullptr;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsCommandParams::SetBooleanValue(const char* aName, bool aValue)
+{
+ HashEntry* foundEntry = GetOrMakeEntry(aName, eBooleanType);
+ if (!foundEntry) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ foundEntry->mData.mBoolean = aValue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandParams::SetLongValue(const char* aName, int32_t aValue)
+{
+ HashEntry* foundEntry = GetOrMakeEntry(aName, eLongType);
+ if (!foundEntry) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ foundEntry->mData.mLong = aValue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandParams::SetDoubleValue(const char* aName, double aValue)
+{
+ HashEntry* foundEntry = GetOrMakeEntry(aName, eDoubleType);
+ if (!foundEntry) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ foundEntry->mData.mDouble = aValue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandParams::SetStringValue(const char* aName, const nsAString& aValue)
+{
+ HashEntry* foundEntry = GetOrMakeEntry(aName, eWStringType);
+ if (!foundEntry) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ foundEntry->mData.mString = new nsString(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandParams::SetCStringValue(const char* aName, const char* aValue)
+{
+ HashEntry* foundEntry = GetOrMakeEntry(aName, eStringType);
+ if (!foundEntry) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ foundEntry->mData.mCString = new nsCString(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandParams::SetISupportsValue(const char* aName, nsISupports* aValue)
+{
+ HashEntry* foundEntry = GetOrMakeEntry(aName, eISupportsType);
+ if (!foundEntry) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ foundEntry->mISupports = aValue; // addrefs
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCommandParams::RemoveValue(const char* aName)
+{
+ mValuesHash.Remove((void*)aName);
+ return NS_OK;
+}
+
+nsCommandParams::HashEntry*
+nsCommandParams::GetNamedEntry(const char* aName)
+{
+ return static_cast<HashEntry*>(mValuesHash.Search((void*)aName));
+}
+
+nsCommandParams::HashEntry*
+nsCommandParams::GetOrMakeEntry(const char* aName, uint8_t aEntryType)
+{
+ auto foundEntry = static_cast<HashEntry*>(mValuesHash.Search((void*)aName));
+ if (foundEntry) { // reuse existing entry
+ foundEntry->Reset(aEntryType);
+ return foundEntry;
+ }
+
+ foundEntry = static_cast<HashEntry*>(mValuesHash.Add((void*)aName, fallible));
+ if (!foundEntry) {
+ return nullptr;
+ }
+
+ // Use placement new. Our ctor does not clobber keyHash, which is important.
+ new (foundEntry) HashEntry(aEntryType, aName);
+ return foundEntry;
+}
+
+PLDHashNumber
+nsCommandParams::HashKey(const void* aKey)
+{
+ return HashString((const char*)aKey);
+}
+
+bool
+nsCommandParams::HashMatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey)
+{
+ const char* keyString = (const char*)aKey;
+ const HashEntry* thisEntry = static_cast<const HashEntry*>(aEntry);
+ return thisEntry->mEntryName.Equals(keyString);
+}
+
+void
+nsCommandParams::HashMoveEntry(PLDHashTable* aTable,
+ const PLDHashEntryHdr* aFrom,
+ PLDHashEntryHdr* aTo)
+{
+ const HashEntry* fromEntry = static_cast<const HashEntry*>(aFrom);
+ HashEntry* toEntry = static_cast<HashEntry*>(aTo);
+
+ new (toEntry) HashEntry(*fromEntry);
+
+ fromEntry->~HashEntry();
+}
+
+void
+nsCommandParams::HashClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
+{
+ HashEntry* thisEntry = static_cast<HashEntry*>(aEntry);
+ thisEntry->~HashEntry();
+}
diff --git a/embedding/components/commandhandler/nsCommandParams.h b/embedding/components/commandhandler/nsCommandParams.h
new file mode 100644
index 000000000..52df28d79
--- /dev/null
+++ b/embedding/components/commandhandler/nsCommandParams.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 nsCommandParams_h__
+#define nsCommandParams_h__
+
+#include "nsString.h"
+#include "nsICommandParams.h"
+#include "nsCOMPtr.h"
+#include "PLDHashTable.h"
+
+class nsCommandParams : public nsICommandParams
+{
+public:
+ nsCommandParams();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICOMMANDPARAMS
+
+protected:
+ virtual ~nsCommandParams();
+
+ struct HashEntry : public PLDHashEntryHdr
+ {
+ nsCString mEntryName;
+
+ uint8_t mEntryType;
+ union
+ {
+ bool mBoolean;
+ int32_t mLong;
+ double mDouble;
+ nsString* mString;
+ nsCString* mCString;
+ } mData;
+
+ nsCOMPtr<nsISupports> mISupports;
+
+ HashEntry(uint8_t aType, const char* aEntryName)
+ : mEntryName(aEntryName)
+ , mEntryType(aType)
+ {
+ Reset(mEntryType);
+ }
+
+ HashEntry(const HashEntry& aRHS)
+ : mEntryType(aRHS.mEntryType)
+ {
+ Reset(mEntryType);
+ switch (mEntryType) {
+ case eBooleanType:
+ mData.mBoolean = aRHS.mData.mBoolean;
+ break;
+ case eLongType:
+ mData.mLong = aRHS.mData.mLong;
+ break;
+ case eDoubleType:
+ mData.mDouble = aRHS.mData.mDouble;
+ break;
+ case eWStringType:
+ NS_ASSERTION(aRHS.mData.mString, "Source entry has no string");
+ mData.mString = new nsString(*aRHS.mData.mString);
+ break;
+ case eStringType:
+ NS_ASSERTION(aRHS.mData.mCString, "Source entry has no string");
+ mData.mCString = new nsCString(*aRHS.mData.mCString);
+ break;
+ case eISupportsType:
+ mISupports = aRHS.mISupports.get();
+ break;
+ default:
+ NS_ERROR("Unknown type");
+ }
+ }
+
+ ~HashEntry() { Reset(eNoType); }
+
+ void Reset(uint8_t aNewType)
+ {
+ switch (mEntryType) {
+ case eNoType:
+ break;
+ case eBooleanType:
+ mData.mBoolean = false;
+ break;
+ case eLongType:
+ mData.mLong = 0;
+ break;
+ case eDoubleType:
+ mData.mDouble = 0.0;
+ break;
+ case eWStringType:
+ delete mData.mString;
+ mData.mString = nullptr;
+ break;
+ case eISupportsType:
+ mISupports = nullptr;
+ break;
+ case eStringType:
+ delete mData.mCString;
+ mData.mCString = nullptr;
+ break;
+ default:
+ NS_ERROR("Unknown type");
+ }
+ mEntryType = aNewType;
+ }
+ };
+
+ HashEntry* GetNamedEntry(const char* aName);
+ HashEntry* GetOrMakeEntry(const char* aName, uint8_t aEntryType);
+
+protected:
+ static PLDHashNumber HashKey(const void* aKey);
+
+ static bool HashMatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey);
+
+ static void HashMoveEntry(PLDHashTable* aTable, const PLDHashEntryHdr* aFrom,
+ PLDHashEntryHdr* aTo);
+
+ static void HashClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry);
+
+ PLDHashTable mValuesHash;
+
+ static const PLDHashTableOps sHashOps;
+};
+
+#endif // nsCommandParams_h__
diff --git a/embedding/components/commandhandler/nsControllerCommandTable.cpp b/embedding/components/commandhandler/nsControllerCommandTable.cpp
new file mode 100644
index 000000000..91075bba4
--- /dev/null
+++ b/embedding/components/commandhandler/nsControllerCommandTable.cpp
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nsString.h"
+#include "nsIControllerCommand.h"
+#include "nsControllerCommandTable.h"
+
+nsresult NS_NewControllerCommandTable(nsIControllerCommandTable** aResult);
+
+// this value is used to size the hash table. Just a sensible upper bound
+#define NUM_COMMANDS_LENGTH 32
+
+nsControllerCommandTable::nsControllerCommandTable()
+ : mCommandsTable(NUM_COMMANDS_LENGTH)
+ , mMutable(true)
+{
+}
+
+nsControllerCommandTable::~nsControllerCommandTable()
+{
+}
+
+NS_IMPL_ISUPPORTS(nsControllerCommandTable, nsIControllerCommandTable,
+ nsISupportsWeakReference)
+
+NS_IMETHODIMP
+nsControllerCommandTable::MakeImmutable(void)
+{
+ mMutable = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::RegisterCommand(const char* aCommandName,
+ nsIControllerCommand* aCommand)
+{
+ NS_ENSURE_TRUE(mMutable, NS_ERROR_FAILURE);
+
+ mCommandsTable.Put(nsDependentCString(aCommandName), aCommand);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::UnregisterCommand(const char* aCommandName,
+ nsIControllerCommand* aCommand)
+{
+ NS_ENSURE_TRUE(mMutable, NS_ERROR_FAILURE);
+
+ nsDependentCString commandKey(aCommandName);
+ if (!mCommandsTable.Get(commandKey, nullptr)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mCommandsTable.Remove(commandKey);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::FindCommandHandler(const char* aCommandName,
+ nsIControllerCommand** aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ *aResult = nullptr;
+
+ nsCOMPtr<nsIControllerCommand> foundCommand;
+ mCommandsTable.Get(nsDependentCString(aCommandName),
+ getter_AddRefs(foundCommand));
+ if (!foundCommand) {
+ return NS_ERROR_FAILURE;
+ }
+
+ foundCommand.forget(aResult);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::IsCommandEnabled(const char* aCommandName,
+ nsISupports* aCommandRefCon,
+ bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ *aResult = false;
+
+ nsCOMPtr<nsIControllerCommand> commandHandler;
+ FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
+ if (!commandHandler) {
+ NS_WARNING("Controller command table asked about a command that it does "
+ "not handle");
+ return NS_OK;
+ }
+
+ return commandHandler->IsCommandEnabled(aCommandName, aCommandRefCon,
+ aResult);
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::UpdateCommandState(const char* aCommandName,
+ nsISupports* aCommandRefCon)
+{
+ nsCOMPtr<nsIControllerCommand> commandHandler;
+ FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
+ if (!commandHandler) {
+ NS_WARNING("Controller command table asked to update the state of a "
+ "command that it does not handle");
+ return NS_OK;
+ }
+
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::SupportsCommand(const char* aCommandName,
+ nsISupports* aCommandRefCon,
+ bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ // XXX: need to check the readonly and disabled states
+
+ *aResult = false;
+
+ nsCOMPtr<nsIControllerCommand> commandHandler;
+ FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
+
+ *aResult = (commandHandler.get() != nullptr);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::DoCommand(const char* aCommandName,
+ nsISupports* aCommandRefCon)
+{
+ nsCOMPtr<nsIControllerCommand> commandHandler;
+ FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
+ if (!commandHandler) {
+ NS_WARNING("Controller command table asked to do a command that it does "
+ "not handle");
+ return NS_OK;
+ }
+
+ return commandHandler->DoCommand(aCommandName, aCommandRefCon);
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::DoCommandParams(const char* aCommandName,
+ nsICommandParams* aParams,
+ nsISupports* aCommandRefCon)
+{
+ nsCOMPtr<nsIControllerCommand> commandHandler;
+ FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
+ if (!commandHandler) {
+ NS_WARNING("Controller command table asked to do a command that it does "
+ "not handle");
+ return NS_OK;
+ }
+ return commandHandler->DoCommandParams(aCommandName, aParams, aCommandRefCon);
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::GetCommandState(const char* aCommandName,
+ nsICommandParams* aParams,
+ nsISupports* aCommandRefCon)
+{
+ nsCOMPtr<nsIControllerCommand> commandHandler;
+ FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
+ if (!commandHandler) {
+ NS_WARNING("Controller command table asked to do a command that it does "
+ "not handle");
+ return NS_OK;
+ }
+ return commandHandler->GetCommandStateParams(aCommandName, aParams,
+ aCommandRefCon);
+}
+
+NS_IMETHODIMP
+nsControllerCommandTable::GetSupportedCommands(uint32_t* aCount,
+ char*** aCommands)
+{
+ char** commands =
+ static_cast<char**>(moz_xmalloc(sizeof(char*) * mCommandsTable.Count()));
+ *aCount = mCommandsTable.Count();
+ *aCommands = commands;
+
+ for (auto iter = mCommandsTable.Iter(); !iter.Done(); iter.Next()) {
+ *commands = ToNewCString(iter.Key());
+ commands++;
+ }
+ return NS_OK;
+}
+
+nsresult
+NS_NewControllerCommandTable(nsIControllerCommandTable** aResult)
+{
+ NS_PRECONDITION(aResult != nullptr, "null ptr");
+ if (!aResult) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ nsControllerCommandTable* newCommandTable = new nsControllerCommandTable();
+ NS_ADDREF(newCommandTable);
+ *aResult = newCommandTable;
+ return NS_OK;
+}
diff --git a/embedding/components/commandhandler/nsControllerCommandTable.h b/embedding/components/commandhandler/nsControllerCommandTable.h
new file mode 100644
index 000000000..353850bc0
--- /dev/null
+++ b/embedding/components/commandhandler/nsControllerCommandTable.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 nsControllerCommandTable_h_
+#define nsControllerCommandTable_h_
+
+#include "nsIControllerCommandTable.h"
+#include "nsWeakReference.h"
+#include "nsInterfaceHashtable.h"
+
+class nsIControllerCommand;
+
+class nsControllerCommandTable final
+ : public nsIControllerCommandTable
+ , public nsSupportsWeakReference
+{
+public:
+ nsControllerCommandTable();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICONTROLLERCOMMANDTABLE
+
+protected:
+ virtual ~nsControllerCommandTable();
+
+ // Hash table of nsIControllerCommands, keyed by command name.
+ nsInterfaceHashtable<nsCStringHashKey, nsIControllerCommand> mCommandsTable;
+
+ // Are we mutable?
+ bool mMutable;
+};
+
+#endif // nsControllerCommandTable_h_
diff --git a/embedding/components/commandhandler/nsICommandManager.idl b/embedding/components/commandhandler/nsICommandManager.idl
new file mode 100644
index 000000000..958108740
--- /dev/null
+++ b/embedding/components/commandhandler/nsICommandManager.idl
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+#include "nsIObserver.idl"
+#include "nsICommandParams.idl"
+
+interface mozIDOMWindowProxy;
+
+/*
+ * nsICommandManager is an interface used to executing user-level commands,
+ * and getting the state of available commands.
+ *
+ * Commands are identified by strings, which are documented elsewhere.
+ * In addition, the list of required and optional parameters for
+ * each command, that are passed in via the nsICommandParams, are
+ * also documented elsewhere. (Where? Need a good location for this).
+ */
+
+
+[scriptable, uuid(bb5a1730-d83b-4fa2-831b-35b9d5842e84)]
+interface nsICommandManager : nsISupports
+{
+ /*
+ * Register an observer on the specified command. The observer's Observe
+ * method will get called when the state (enabled/disbaled, or toggled etc)
+ * of the command changes.
+ *
+ * You can register the same observer on multiple commmands by calling this
+ * multiple times.
+ */
+ void addCommandObserver(in nsIObserver aCommandObserver,
+ in string aCommandToObserve);
+
+ /*
+ * Stop an observer from observering the specified command. If the observer
+ * was also registered on ther commands, they will continue to be observed.
+ *
+ * Passing an empty string in 'aCommandObserved' will remove the observer
+ * from all commands.
+ */
+ void removeCommandObserver(in nsIObserver aCommandObserver,
+ in string aCommandObserved);
+
+ /*
+ * Ask the command manager if the specified command is supported.
+ * If aTargetWindow is null, the focused window is used.
+ *
+ */
+ boolean isCommandSupported(in string aCommandName,
+ in mozIDOMWindowProxy aTargetWindow);
+
+ /*
+ * Ask the command manager if the specified command is currently.
+ * enabled.
+ * If aTargetWindow is null, the focused window is used.
+ */
+ boolean isCommandEnabled(in string aCommandName,
+ in mozIDOMWindowProxy aTargetWindow);
+
+ /*
+ * Get the state of the specified commands.
+ *
+ * On input: aCommandParams filled in with values that the caller cares
+ * about, most of which are command-specific (see the command documentation
+ * for details). One boolean value, "enabled", applies to all commands,
+ * and, in return will be set to indicate whether the command is enabled
+ * (equivalent to calling isCommandEnabled).
+ *
+ * aCommandName is the name of the command that needs the state
+ * aTargetWindow is the source of command controller
+ * (null means use focus controller)
+ * On output: aCommandParams: values set by the caller filled in with
+ * state from the command.
+ */
+ void getCommandState(in string aCommandName,
+ in mozIDOMWindowProxy aTargetWindow,
+ /* inout */ in nsICommandParams aCommandParams);
+
+ /*
+ * Execute the specified command.
+ * The command will be executed in aTargetWindow if it is specified.
+ * If aTargetWindow is null, it will go to the focused window.
+ *
+ * param: aCommandParams, a list of name-value pairs of command parameters,
+ * may be null for parameter-less commands.
+ *
+ */
+ void doCommand(in string aCommandName,
+ in nsICommandParams aCommandParams,
+ in mozIDOMWindowProxy aTargetWindow);
+
+};
+
+
+/*
+
+Arguments to observers "Observe" method are as follows:
+
+ void Observe( in nsISupports aSubject, // The nsICommandManager calling this Observer
+ in string aTopic, // Name of the command
+ in wstring aDummy ); // unused
+
+*/
+
+// {64edb481-0c04-11d5-a73c-e964b968b0bc}
+%{C++
+#define NS_COMMAND_MANAGER_CID \
+{ 0x64edb481, 0x0c04, 0x11d5, { 0xa7, 0x3c, 0xe9, 0x64, 0xb9, 0x68, 0xb0, 0xbc } }
+
+#define NS_COMMAND_MANAGER_CONTRACTID \
+ "@mozilla.org/embedcomp/command-manager;1"
+%}
+
+
+
diff --git a/embedding/components/commandhandler/nsICommandParams.idl b/embedding/components/commandhandler/nsICommandParams.idl
new file mode 100644
index 000000000..fcd3ff973
--- /dev/null
+++ b/embedding/components/commandhandler/nsICommandParams.idl
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+/*
+ * nsICommandParams is used to pass parameters to commands executed
+ * via nsICommandManager, and to get command state.
+ *
+ */
+
+[scriptable, uuid(b1fdf3c4-74e3-4f7d-a14d-2b76bcf53482)]
+interface nsICommandParams : nsISupports
+{
+ /*
+ * List of primitive types for parameter values.
+ */
+ const short eNoType = 0; /* Only used for sanity checking */
+ const short eBooleanType = 1;
+ const short eLongType = 2;
+ const short eDoubleType = 3;
+ const short eWStringType = 4;
+ const short eISupportsType = 5;
+ const short eStringType = 6;
+
+ /*
+ * getValueType
+ *
+ * Get the type of a specified parameter
+ */
+ short getValueType(in string name);
+
+ /*
+ * get_Value
+ *
+ * Get the value of a specified parameter. Will return
+ * an error if the parameter does not exist, or if the value
+ * is of the wrong type (no coercion is performed for you).
+ *
+ * nsISupports values can contain any XPCOM interface,
+ * as documented for the command. It is permissible
+ * for it to contain nsICommandParams, but not *this*
+ * one (i.e. self-containing is not allowed).
+ */
+ boolean getBooleanValue(in string name);
+ long getLongValue(in string name);
+ double getDoubleValue(in string name);
+ AString getStringValue(in string name);
+ string getCStringValue(in string name);
+ nsISupports getISupportsValue(in string name);
+
+ /*
+ * set_Value
+ *
+ * Set the value of a specified parameter (thus creating
+ * an entry for it).
+ *
+ * nsISupports values can contain any XPCOM interface,
+ * as documented for the command. It is permissible
+ * for it to contain nsICommandParams, but not *this*
+ * one (i.e. self-containing is not allowed).
+ */
+ void setBooleanValue(in string name, in boolean value);
+ void setLongValue(in string name, in long value);
+ void setDoubleValue(in string name, in double value);
+ void setStringValue(in string name, in AString value);
+ void setCStringValue(in string name, in string value);
+ void setISupportsValue(in string name, in nsISupports value);
+
+ /*
+ * removeValue
+ *
+ * Remove the specified parameter from the list.
+ */
+ void removeValue(in string name);
+};
+
+// {f7fa4581-238e-11d5-a73c-ab64fb68f2bc}
+%{C++
+#define NS_COMMAND_PARAMS_CID { 0xf7fa4581, 0x238e, 0x11d5, { 0xa7, 0x3c, 0xab, 0x64, 0xfb, 0x68, 0xf2, 0xbc } }
+#define NS_COMMAND_PARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1"
+%}
+
diff --git a/embedding/components/commandhandler/nsIControllerCommand.idl b/embedding/components/commandhandler/nsIControllerCommand.idl
new file mode 100644
index 000000000..a1ea583a4
--- /dev/null
+++ b/embedding/components/commandhandler/nsIControllerCommand.idl
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+
+#include "nsISupports.idl"
+#include "nsICommandParams.idl"
+
+/**
+ * nsIControllerCommand
+ *
+ * A generic command interface. You can register an nsIControllerCommand
+ * with the nsIControllerCommandTable.
+ */
+
+[scriptable, uuid(0eae9a46-1dd2-11b2-aca0-9176f05fe9db)]
+interface nsIControllerCommand : nsISupports
+{
+
+ /**
+ * Returns true if the command is currently enabled. An nsIControllerCommand
+ * can implement more than one commands; say, a group of related commands
+ * (e.g. delete left/delete right). Because of this, the command name is
+ * passed to each method.
+ *
+ * @param aCommandName the name of the command for which we want the enabled
+ * state.
+ * @param aCommandContext a cookie held by the nsIControllerCommandTable,
+ * allowing the command to get some context information.
+ * The contents of this cookie are implementation-defined.
+ */
+ boolean isCommandEnabled(in string aCommandName, in nsISupports aCommandContext);
+
+ void getCommandStateParams(in string aCommandName, in nsICommandParams aParams, in nsISupports aCommandContext);
+
+ /**
+ * Execute the name command.
+ *
+ * @param aCommandName the name of the command to execute.
+ *
+ * @param aCommandContext a cookie held by the nsIControllerCommandTable,
+ * allowing the command to get some context information.
+ * The contents of this cookie are implementation-defined.
+ */
+ void doCommand(in string aCommandName, in nsISupports aCommandContext);
+
+ void doCommandParams(in string aCommandName, in nsICommandParams aParams, in nsISupports aCommandContext);
+
+};
+
diff --git a/embedding/components/commandhandler/nsIControllerCommandTable.idl b/embedding/components/commandhandler/nsIControllerCommandTable.idl
new file mode 100644
index 000000000..fb2c86fae
--- /dev/null
+++ b/embedding/components/commandhandler/nsIControllerCommandTable.idl
@@ -0,0 +1,100 @@
+/* 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/. */
+
+#include "nsISupports.idl"
+#include "nsIControllerCommand.idl"
+#include "nsICommandParams.idl"
+
+/**
+ * nsIControllerCommandTable
+ *
+ * An interface via which a controller can maintain a series of commands,
+ * and efficiently dispatch commands to their respective handlers.
+ *
+ * Controllers that use an nsIControllerCommandTable should support
+ * nsIInterfaceRequestor, and be able to return an interface to their
+ * controller command table via getInterface().
+ *
+ */
+
+[scriptable, uuid(c847f90e-b8f3-49db-a4df-8867831f2800)]
+interface nsIControllerCommandTable : nsISupports
+{
+ /**
+ * Make this command table immutable, so that commands cannot
+ * be registered or unregistered. Some command tables are made
+ * mutable after command registration so that they can be
+ * used as singletons.
+ */
+ void makeImmutable();
+
+ /**
+ * Register and unregister commands with the command table.
+ *
+ * @param aCommandName the name of the command under which to register or
+ * unregister the given command handler.
+ *
+ * @param aCommand the handler for this command.
+ */
+ void registerCommand(in string aCommandName, in nsIControllerCommand aCommand);
+ void unregisterCommand(in string aCommandName, in nsIControllerCommand aCommand);
+
+ /**
+ * Find the command handler which has been registered to handle the named command.
+ *
+ * @param aCommandName the name of the command to find the handler for.
+ */
+ nsIControllerCommand findCommandHandler(in string aCommandName);
+
+ /**
+ * Get whether the named command is enabled.
+ *
+ * @param aCommandName the name of the command to test
+ * @param aCommandRefCon the command context data
+ */
+ boolean isCommandEnabled(in string aCommandName, in nsISupports aCommandRefCon);
+
+ /**
+ * Tell the command to update its state (if it is a state updating command)
+ *
+ * @param aCommandName the name of the command to update
+ * @param aCommandRefCon the command context data
+ */
+ void updateCommandState(in string aCommandName, in nsISupports aCommandRefCon);
+
+ /**
+ * Get whether the named command is supported.
+ *
+ * @param aCommandName the name of the command to test
+ * @param aCommandRefCon the command context data
+ */
+ boolean supportsCommand(in string aCommandName, in nsISupports aCommandRefCon);
+
+ /**
+ * Execute the named command.
+ *
+ * @param aCommandName the name of the command to execute
+ * @param aCommandRefCon the command context data
+ */
+ void doCommand(in string aCommandName, in nsISupports aCommandRefCon);
+
+ void doCommandParams(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon);
+
+ void getCommandState(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon);
+
+ void getSupportedCommands(out unsigned long count,
+ [array, size_is(count), retval] out string commands);
+};
+
+
+
+%{C++
+// {670ee5da-6ad5-11d7-9950-000393636592}
+#define NS_CONTROLLERCOMMANDTABLE_CID \
+ {0x670ee5da, 0x6ad5, 0x11d7, \
+ { 0x99, 0x50, 0x00, 0x03, 0x93, 0x63, 0x65, 0x92 }}
+
+#define NS_CONTROLLERCOMMANDTABLE_CONTRACTID \
+ "@mozilla.org/embedcomp/controller-command-table;1"
+%}
diff --git a/embedding/components/commandhandler/nsIControllerContext.idl b/embedding/components/commandhandler/nsIControllerContext.idl
new file mode 100644
index 000000000..7c7ed67fd
--- /dev/null
+++ b/embedding/components/commandhandler/nsIControllerContext.idl
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+#include "nsIControllerCommandTable.idl"
+
+[scriptable, uuid(47B82B60-A36F-4167-8072-6F421151ED50)]
+interface nsIControllerContext : nsISupports
+{
+
+ /**
+ * Init the controller, optionally passing a controller
+ * command table.
+ *
+ * @param aCommandTable a command table, used internally
+ * by this controller. May be null, in
+ * which case the controller will create
+ * a new, empty table.
+ */
+ void init(in nsIControllerCommandTable aCommandTable);
+
+ /**
+ * Set a context on this controller, which is passed
+ * to commands to give them some context when they execute.
+ *
+ * @param aCommandContext the context passed to commands.
+ * Note that this is *not* addreffed by the
+ * controller, and so needs to outlive it,
+ * or be nulled out.
+ */
+ void setCommandContext(in nsISupports aCommandContext);
+
+};
diff --git a/embedding/components/commandhandler/nsPICommandUpdater.idl b/embedding/components/commandhandler/nsPICommandUpdater.idl
new file mode 100644
index 000000000..3712dbdff
--- /dev/null
+++ b/embedding/components/commandhandler/nsPICommandUpdater.idl
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+interface mozIDOMWindowProxy;
+
+/*
+ The nsPICommandUpdater interface is used by modules that implement
+ commands, to tell the command manager that commands need updating.
+ This is a private interface; embedders should not use it.
+
+ Command-implementing modules should get one of these by a QI
+ from an nsICommandManager.
+*/
+
+[scriptable, uuid(35e474ae-8016-4c34-9644-edc11f8b0ce1)]
+interface nsPICommandUpdater : nsISupports
+{
+
+ /*
+ * Init the command updater, passing an nsIDOMWindow which
+ * is the window that the command updater lives on.
+ *
+ */
+ void init(in mozIDOMWindowProxy aWindow);
+
+ /*
+ * Notify the command manager that the status of a command
+ * changed. It may have changed from enabled to disabled,
+ * or vice versa, or become toggled etc.
+ */
+ void commandStatusChanged(in string aCommandName);
+
+};
+
+