Line data Source code
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/. */
6 :
7 : #include "nsString.h"
8 :
9 : #include "nsIController.h"
10 : #include "nsIControllers.h"
11 : #include "nsIObserver.h"
12 :
13 : #include "nsIComponentManager.h"
14 :
15 : #include "nsServiceManagerUtils.h"
16 : #include "nsIScriptSecurityManager.h"
17 :
18 : #include "nsContentUtils.h"
19 : #include "nsIDOMWindow.h"
20 : #include "nsPIDOMWindow.h"
21 : #include "nsPIWindowRoot.h"
22 : #include "nsIFocusManager.h"
23 :
24 : #include "nsCOMArray.h"
25 :
26 : #include "nsCommandManager.h"
27 :
28 0 : nsCommandManager::nsCommandManager()
29 0 : : mWindow(nullptr)
30 : {
31 0 : }
32 :
33 0 : nsCommandManager::~nsCommandManager()
34 : {
35 0 : }
36 :
37 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
38 :
39 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
40 0 : tmp->mObserversTable.Clear();
41 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
42 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager)
43 0 : for (auto iter = tmp->mObserversTable.Iter(); !iter.Done(); iter.Next()) {
44 0 : nsCommandManager::ObserverList* observers = iter.UserData();
45 0 : int32_t numItems = observers->Length();
46 0 : for (int32_t i = 0; i < numItems; ++i) {
47 0 : cb.NoteXPCOMChild(observers->ElementAt(i));
48 : }
49 : }
50 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
51 :
52 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)
53 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager)
54 :
55 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager)
56 0 : NS_INTERFACE_MAP_ENTRY(nsICommandManager)
57 0 : NS_INTERFACE_MAP_ENTRY(nsPICommandUpdater)
58 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
59 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager)
60 0 : NS_INTERFACE_MAP_END
61 :
62 : NS_IMETHODIMP
63 0 : nsCommandManager::Init(mozIDOMWindowProxy* aWindow)
64 : {
65 0 : NS_ENSURE_ARG_POINTER(aWindow);
66 :
67 0 : mWindow = aWindow; // weak ptr
68 0 : return NS_OK;
69 : }
70 :
71 : NS_IMETHODIMP
72 0 : nsCommandManager::CommandStatusChanged(const char* aCommandName)
73 : {
74 : ObserverList* commandObservers;
75 0 : mObserversTable.Get(aCommandName, &commandObservers);
76 :
77 0 : if (commandObservers) {
78 : // XXX Should we worry about observers removing themselves from Observe()?
79 0 : int32_t i, numItems = commandObservers->Length();
80 0 : for (i = 0; i < numItems; ++i) {
81 0 : nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i);
82 : // should we get the command state to pass here? This might be expensive.
83 0 : observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this),
84 : aCommandName,
85 0 : u"command_status_changed");
86 : }
87 : }
88 :
89 0 : return NS_OK;
90 : }
91 :
92 : #if 0
93 : #pragma mark -
94 : #endif
95 :
96 : NS_IMETHODIMP
97 0 : nsCommandManager::AddCommandObserver(nsIObserver* aCommandObserver,
98 : const char* aCommandToObserve)
99 : {
100 0 : NS_ENSURE_ARG(aCommandObserver);
101 :
102 : // XXX todo: handle special cases of aCommandToObserve being null, or empty
103 :
104 : // for each command in the table, we make a list of observers for that command
105 : ObserverList* commandObservers =
106 0 : mObserversTable.LookupForAdd(aCommandToObserve).OrInsert(
107 0 : [] () { return new ObserverList; });
108 :
109 : // need to check that this command observer hasn't already been registered
110 0 : int32_t existingIndex = commandObservers->IndexOf(aCommandObserver);
111 0 : if (existingIndex == -1) {
112 0 : commandObservers->AppendElement(aCommandObserver);
113 : } else {
114 0 : NS_WARNING("Registering command observer twice on the same command");
115 : }
116 :
117 0 : return NS_OK;
118 : }
119 :
120 : NS_IMETHODIMP
121 0 : nsCommandManager::RemoveCommandObserver(nsIObserver* aCommandObserver,
122 : const char* aCommandObserved)
123 : {
124 0 : NS_ENSURE_ARG(aCommandObserver);
125 :
126 : // XXX todo: handle special cases of aCommandToObserve being null, or empty
127 :
128 : ObserverList* commandObservers;
129 0 : if (!mObserversTable.Get(aCommandObserved, &commandObservers)) {
130 0 : return NS_ERROR_UNEXPECTED;
131 : }
132 :
133 0 : commandObservers->RemoveElement(aCommandObserver);
134 :
135 0 : return NS_OK;
136 : }
137 :
138 : NS_IMETHODIMP
139 0 : nsCommandManager::IsCommandSupported(const char* aCommandName,
140 : mozIDOMWindowProxy* aTargetWindow,
141 : bool* aResult)
142 : {
143 0 : NS_ENSURE_ARG_POINTER(aResult);
144 :
145 0 : nsCOMPtr<nsIController> controller;
146 0 : GetControllerForCommand(aCommandName, aTargetWindow,
147 0 : getter_AddRefs(controller));
148 0 : *aResult = (controller.get() != nullptr);
149 0 : return NS_OK;
150 : }
151 :
152 : NS_IMETHODIMP
153 0 : nsCommandManager::IsCommandEnabled(const char* aCommandName,
154 : mozIDOMWindowProxy* aTargetWindow,
155 : bool* aResult)
156 : {
157 0 : NS_ENSURE_ARG_POINTER(aResult);
158 :
159 0 : bool commandEnabled = false;
160 :
161 0 : nsCOMPtr<nsIController> controller;
162 0 : GetControllerForCommand(aCommandName, aTargetWindow,
163 0 : getter_AddRefs(controller));
164 0 : if (controller) {
165 0 : controller->IsCommandEnabled(aCommandName, &commandEnabled);
166 : }
167 0 : *aResult = commandEnabled;
168 0 : return NS_OK;
169 : }
170 :
171 : NS_IMETHODIMP
172 0 : nsCommandManager::GetCommandState(const char* aCommandName,
173 : mozIDOMWindowProxy* aTargetWindow,
174 : nsICommandParams* aCommandParams)
175 : {
176 0 : nsCOMPtr<nsIController> controller;
177 0 : nsAutoString tValue;
178 0 : nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
179 0 : getter_AddRefs(controller));
180 0 : if (!controller) {
181 0 : return NS_ERROR_FAILURE;
182 : }
183 :
184 : nsCOMPtr<nsICommandController> commandController =
185 0 : do_QueryInterface(controller);
186 0 : if (commandController) {
187 0 : rv = commandController->GetCommandStateWithParams(aCommandName,
188 0 : aCommandParams);
189 : } else {
190 0 : rv = NS_ERROR_NOT_IMPLEMENTED;
191 : }
192 0 : return rv;
193 : }
194 :
195 : NS_IMETHODIMP
196 0 : nsCommandManager::DoCommand(const char* aCommandName,
197 : nsICommandParams* aCommandParams,
198 : mozIDOMWindowProxy* aTargetWindow)
199 : {
200 0 : nsCOMPtr<nsIController> controller;
201 0 : nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
202 0 : getter_AddRefs(controller));
203 0 : if (!controller) {
204 0 : return NS_ERROR_FAILURE;
205 : }
206 :
207 : nsCOMPtr<nsICommandController> commandController =
208 0 : do_QueryInterface(controller);
209 0 : if (commandController && aCommandParams) {
210 0 : rv = commandController->DoCommandWithParams(aCommandName, aCommandParams);
211 : } else {
212 0 : rv = controller->DoCommand(aCommandName);
213 : }
214 0 : return rv;
215 : }
216 :
217 : nsresult
218 0 : nsCommandManager::GetControllerForCommand(const char* aCommand,
219 : mozIDOMWindowProxy* aTargetWindow,
220 : nsIController** aResult)
221 : {
222 0 : nsresult rv = NS_ERROR_FAILURE;
223 0 : *aResult = nullptr;
224 :
225 : // check if we're in content or chrome
226 : // if we're not chrome we must have a target window or we bail
227 0 : if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
228 0 : if (!aTargetWindow) {
229 0 : return rv;
230 : }
231 :
232 : // if a target window is specified, it must be the window we expect
233 0 : if (aTargetWindow != mWindow) {
234 0 : return NS_ERROR_FAILURE;
235 : }
236 : }
237 :
238 0 : if (auto* targetWindow = nsPIDOMWindowOuter::From(aTargetWindow)) {
239 : // get the controller for this particular window
240 0 : nsCOMPtr<nsIControllers> controllers;
241 0 : rv = targetWindow->GetControllers(getter_AddRefs(controllers));
242 0 : if (NS_FAILED(rv)) {
243 0 : return rv;
244 : }
245 0 : if (!controllers) {
246 0 : return NS_ERROR_FAILURE;
247 : }
248 :
249 : // dispatch the command
250 0 : return controllers->GetControllerForCommand(aCommand, aResult);
251 : }
252 :
253 0 : auto* window = nsPIDOMWindowOuter::From(mWindow);
254 0 : NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
255 0 : nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
256 0 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
257 :
258 : // no target window; send command to focus controller
259 0 : return root->GetControllerForCommand(aCommand, aResult);
260 : }
|