1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "nsIController.h"
10 #include "nsIControllers.h"
11 #include "nsIObserver.h"
13 #include "nsServiceManagerUtils.h"
15 #include "nsContentUtils.h"
16 #include "nsPIDOMWindow.h"
17 #include "nsPIWindowRoot.h"
19 #include "nsCOMArray.h"
21 #include "nsCommandManager.h"
23 nsCommandManager::nsCommandManager(mozIDOMWindowProxy
* aWindow
)
25 MOZ_DIAGNOSTIC_ASSERT(mWindow
);
28 nsCommandManager::~nsCommandManager() = default;
30 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager
)
32 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager
)
33 tmp
->mObserversTable
.Clear();
34 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
35 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager
)
37 for (const auto& entry
: tmp
->mObserversTable
) {
38 nsCommandManager::ObserverList
* observers
= entry
.GetWeak();
39 int32_t numItems
= observers
->Length();
40 for (int32_t i
= 0; i
< numItems
; ++i
) {
41 cb
.NoteXPCOMChild(observers
->ElementAt(i
));
44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
46 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager
)
47 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager
)
49 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager
)
50 NS_INTERFACE_MAP_ENTRY(nsICommandManager
)
51 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
52 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsICommandManager
)
55 void nsCommandManager::CommandStatusChanged(const char* aCommandName
) {
56 ObserverList
* commandObservers
;
57 mObserversTable
.Get(aCommandName
, &commandObservers
);
59 if (commandObservers
) {
60 // XXX Should we worry about observers removing themselves from Observe()?
61 int32_t i
, numItems
= commandObservers
->Length();
62 for (i
= 0; i
< numItems
; ++i
) {
63 nsCOMPtr
<nsIObserver
> observer
= commandObservers
->ElementAt(i
);
64 // should we get the command state to pass here? This might be expensive.
65 observer
->Observe(NS_ISUPPORTS_CAST(nsICommandManager
*, this),
66 aCommandName
, u
"command_status_changed");
76 nsCommandManager::AddCommandObserver(nsIObserver
* aCommandObserver
,
77 const char* aCommandToObserve
) {
78 NS_ENSURE_ARG(aCommandObserver
);
80 // XXX todo: handle special cases of aCommandToObserve being null, or empty
82 // for each command in the table, we make a list of observers for that command
83 auto* const commandObservers
=
84 mObserversTable
.GetOrInsertNew(aCommandToObserve
);
86 // need to check that this command observer hasn't already been registered
87 int32_t existingIndex
= commandObservers
->IndexOf(aCommandObserver
);
88 if (existingIndex
== -1) {
89 commandObservers
->AppendElement(aCommandObserver
);
91 NS_WARNING("Registering command observer twice on the same command");
98 nsCommandManager::RemoveCommandObserver(nsIObserver
* aCommandObserver
,
99 const char* aCommandObserved
) {
100 NS_ENSURE_ARG(aCommandObserver
);
102 // XXX todo: handle special cases of aCommandToObserve being null, or empty
104 ObserverList
* commandObservers
;
105 if (!mObserversTable
.Get(aCommandObserved
, &commandObservers
)) {
106 return NS_ERROR_UNEXPECTED
;
109 commandObservers
->RemoveElement(aCommandObserver
);
115 nsCommandManager::IsCommandSupported(const char* aCommandName
,
116 mozIDOMWindowProxy
* aTargetWindow
,
118 NS_ENSURE_ARG_POINTER(aResult
);
120 nsCOMPtr
<nsIController
> controller
;
121 GetControllerForCommand(aCommandName
, aTargetWindow
,
122 getter_AddRefs(controller
));
123 *aResult
= (controller
.get() != nullptr);
128 nsCommandManager::IsCommandEnabled(const char* aCommandName
,
129 mozIDOMWindowProxy
* aTargetWindow
,
131 NS_ENSURE_ARG_POINTER(aResult
);
136 *aResult
= IsCommandEnabled(nsDependentCString(aCommandName
), aTargetWindow
);
140 bool nsCommandManager::IsCommandEnabled(const nsCString
& aCommandName
,
141 mozIDOMWindowProxy
* aTargetWindow
) {
142 nsCOMPtr
<nsIController
> controller
;
143 GetControllerForCommand(aCommandName
.get(), aTargetWindow
,
144 getter_AddRefs(controller
));
149 bool enabled
= false;
150 controller
->IsCommandEnabled(aCommandName
.get(), &enabled
);
155 nsCommandManager::GetCommandState(const char* aCommandName
,
156 mozIDOMWindowProxy
* aTargetWindow
,
157 nsICommandParams
* aCommandParams
) {
158 nsCOMPtr
<nsIController
> controller
;
160 nsresult rv
= GetControllerForCommand(aCommandName
, aTargetWindow
,
161 getter_AddRefs(controller
));
163 return NS_ERROR_FAILURE
;
166 nsCOMPtr
<nsICommandController
> commandController
=
167 do_QueryInterface(controller
);
168 if (commandController
) {
169 rv
= commandController
->GetCommandStateWithParams(aCommandName
,
172 rv
= NS_ERROR_NOT_IMPLEMENTED
;
178 nsCommandManager::DoCommand(const char* aCommandName
,
179 nsICommandParams
* aCommandParams
,
180 mozIDOMWindowProxy
* aTargetWindow
) {
181 nsCOMPtr
<nsIController
> controller
;
182 nsresult rv
= GetControllerForCommand(aCommandName
, aTargetWindow
,
183 getter_AddRefs(controller
));
185 return NS_ERROR_FAILURE
;
188 nsCOMPtr
<nsICommandController
> commandController
=
189 do_QueryInterface(controller
);
190 if (commandController
&& aCommandParams
) {
191 rv
= commandController
->DoCommandWithParams(aCommandName
, aCommandParams
);
193 rv
= controller
->DoCommand(aCommandName
);
198 nsresult
nsCommandManager::GetControllerForCommand(
199 const char* aCommand
, mozIDOMWindowProxy
* aTargetWindow
,
200 nsIController
** aResult
) {
201 nsresult rv
= NS_ERROR_FAILURE
;
204 // check if we're in content or chrome
205 // if we're not chrome we must have a target window or we bail
206 if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
207 if (!aTargetWindow
) {
211 // if a target window is specified, it must be the window we expect
212 if (aTargetWindow
!= mWindow
) {
213 return NS_ERROR_FAILURE
;
217 if (auto* targetWindow
= nsPIDOMWindowOuter::From(aTargetWindow
)) {
218 // get the controller for this particular window
219 nsCOMPtr
<nsIControllers
> controllers
;
220 rv
= targetWindow
->GetControllers(getter_AddRefs(controllers
));
225 return NS_ERROR_FAILURE
;
228 // dispatch the command
229 return controllers
->GetControllerForCommand(aCommand
, aResult
);
232 auto* window
= nsPIDOMWindowOuter::From(mWindow
);
233 NS_ENSURE_TRUE(window
, NS_ERROR_FAILURE
);
234 nsCOMPtr
<nsPIWindowRoot
> root
= window
->GetTopWindowRoot();
235 NS_ENSURE_TRUE(root
, NS_ERROR_FAILURE
);
237 // no target window; send command to focus controller
238 return root
->GetControllerForCommand(aCommand
, false /* for any window */,