1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsAppShellWindowEnumerator.h"
7
8 #include "nsIContentViewer.h"
9 #include "nsIDocShell.h"
10 #include "mozilla/dom/Document.h"
11 #include "nsIInterfaceRequestor.h"
12 #include "nsIInterfaceRequestorUtils.h"
13 #include "nsIAppWindow.h"
14 #include "mozilla/dom/Element.h"
15
16 #include "nsWindowMediator.h"
17
18 using mozilla::dom::Document;
19 using mozilla::dom::Element;
20
21 //
22 // static helper functions
23 //
24
25 static void GetAttribute(nsIAppWindow* inWindow, const nsAString& inAttribute,
26 nsAString& outValue);
27 static void GetWindowType(nsIAppWindow* inWindow, nsString& outType);
28
GetElementFromDocShell(nsIDocShell * aShell)29 static Element* GetElementFromDocShell(nsIDocShell* aShell) {
30 nsCOMPtr<nsIContentViewer> cv;
31 aShell->GetContentViewer(getter_AddRefs(cv));
32 if (cv) {
33 RefPtr<Document> doc = cv->GetDocument();
34 if (doc) {
35 return doc->GetDocumentElement();
36 }
37 }
38
39 return nullptr;
40 }
41
42 // generic "retrieve the value of a XUL attribute" function
GetAttribute(nsIAppWindow * inWindow,const nsAString & inAttribute,nsAString & outValue)43 void GetAttribute(nsIAppWindow* inWindow, const nsAString& inAttribute,
44 nsAString& outValue) {
45 nsCOMPtr<nsIDocShell> shell;
46 if (inWindow && NS_SUCCEEDED(inWindow->GetDocShell(getter_AddRefs(shell)))) {
47 RefPtr<Element> webshellElement = GetElementFromDocShell(shell);
48 if (webshellElement) {
49 webshellElement->GetAttribute(inAttribute, outValue);
50 }
51 }
52 }
53
54 // retrieve the window type, stored as the value of a particular
55 // attribute in its XUL window tag
GetWindowType(nsIAppWindow * aWindow,nsString & outType)56 void GetWindowType(nsIAppWindow* aWindow, nsString& outType) {
57 GetAttribute(aWindow, u"windowtype"_ns, outType);
58 }
59
60 //
61 // nsWindowInfo
62 //
63
nsWindowInfo(nsIAppWindow * inWindow,int32_t inTimeStamp)64 nsWindowInfo::nsWindowInfo(nsIAppWindow* inWindow, int32_t inTimeStamp)
65 : mWindow(inWindow),
66 mTimeStamp(inTimeStamp),
67 mZLevel(nsIAppWindow::normalZ) {
68 ReferenceSelf(true, true);
69 }
70
~nsWindowInfo()71 nsWindowInfo::~nsWindowInfo() {}
72
73 // return true if the window described by this WindowInfo has a type
74 // equal to the given type
TypeEquals(const nsAString & aType)75 bool nsWindowInfo::TypeEquals(const nsAString& aType) {
76 nsAutoString rtnString;
77 GetWindowType(mWindow, rtnString);
78 return rtnString == aType;
79 }
80
81 // insert the struct into their two linked lists, in position after the
82 // given (independent) method arguments
InsertAfter(nsWindowInfo * inOlder,nsWindowInfo * inHigher)83 void nsWindowInfo::InsertAfter(nsWindowInfo* inOlder, nsWindowInfo* inHigher) {
84 if (inOlder) {
85 mOlder = inOlder;
86 mYounger = inOlder->mYounger;
87 mOlder->mYounger = this;
88 if (mOlder->mOlder == mOlder) mOlder->mOlder = this;
89 mYounger->mOlder = this;
90 if (mYounger->mYounger == mYounger) mYounger->mYounger = this;
91 }
92 if (inHigher) {
93 mHigher = inHigher;
94 mLower = inHigher->mLower;
95 mHigher->mLower = this;
96 if (mHigher->mHigher == mHigher) mHigher->mHigher = this;
97 mLower->mHigher = this;
98 if (mLower->mLower == mLower) mLower->mLower = this;
99 }
100 }
101
102 // remove the struct from its linked lists
Unlink(bool inAge,bool inZ)103 void nsWindowInfo::Unlink(bool inAge, bool inZ) {
104 if (inAge) {
105 mOlder->mYounger = mYounger;
106 mYounger->mOlder = mOlder;
107 }
108 if (inZ) {
109 mLower->mHigher = mHigher;
110 mHigher->mLower = mLower;
111 }
112 ReferenceSelf(inAge, inZ);
113 }
114
115 // initialize the struct to be a valid linked list of one element
ReferenceSelf(bool inAge,bool inZ)116 void nsWindowInfo::ReferenceSelf(bool inAge, bool inZ) {
117 if (inAge) {
118 mYounger = this;
119 mOlder = this;
120 }
121 if (inZ) {
122 mLower = this;
123 mHigher = this;
124 }
125 }
126
127 //
128 // nsAppShellWindowEnumerator
129 //
130
nsAppShellWindowEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)131 nsAppShellWindowEnumerator::nsAppShellWindowEnumerator(
132 const char16_t* aTypeString, nsWindowMediator& aMediator)
133 : mWindowMediator(&aMediator),
134 mType(aTypeString),
135 mCurrentPosition(nullptr) {
136 mWindowMediator->AddEnumerator(this);
137 NS_ADDREF(mWindowMediator);
138 }
139
~nsAppShellWindowEnumerator()140 nsAppShellWindowEnumerator::~nsAppShellWindowEnumerator() {
141 mWindowMediator->RemoveEnumerator(this);
142 NS_RELEASE(mWindowMediator);
143 }
144
145 // after mCurrentPosition has been initialized to point to the beginning
146 // of the appropriate list, adjust it if necessary
AdjustInitialPosition()147 void nsAppShellWindowEnumerator::AdjustInitialPosition() {
148 if (!mType.IsEmpty() && mCurrentPosition &&
149 !mCurrentPosition->TypeEquals(mType))
150 mCurrentPosition = FindNext();
151 }
152
HasMoreElements(bool * retval)153 NS_IMETHODIMP nsAppShellWindowEnumerator::HasMoreElements(bool* retval) {
154 if (!retval) return NS_ERROR_INVALID_ARG;
155
156 *retval = mCurrentPosition ? true : false;
157 return NS_OK;
158 }
159
160 // if a window is being removed adjust the iterator's current position
WindowRemoved(nsWindowInfo * inInfo)161 void nsAppShellWindowEnumerator::WindowRemoved(nsWindowInfo* inInfo) {
162 if (mCurrentPosition == inInfo) mCurrentPosition = FindNext();
163 }
164
165 //
166 // nsASDOMWindowEnumerator
167 //
168
nsASDOMWindowEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)169 nsASDOMWindowEnumerator::nsASDOMWindowEnumerator(const char16_t* aTypeString,
170 nsWindowMediator& aMediator)
171 : nsAppShellWindowEnumerator(aTypeString, aMediator) {}
172
~nsASDOMWindowEnumerator()173 nsASDOMWindowEnumerator::~nsASDOMWindowEnumerator() {}
174
GetNext(nsISupports ** retval)175 NS_IMETHODIMP nsASDOMWindowEnumerator::GetNext(nsISupports** retval) {
176 if (!retval) return NS_ERROR_INVALID_ARG;
177
178 *retval = nullptr;
179 while (mCurrentPosition) {
180 nsCOMPtr<nsPIDOMWindowOuter> domWindow;
181 nsWindowMediator::GetDOMWindow(mCurrentPosition->mWindow, domWindow);
182 mCurrentPosition = FindNext();
183 if (domWindow) return CallQueryInterface(domWindow, retval);
184 }
185 return NS_ERROR_FAILURE;
186 }
187
188 //
189 // nsASAppWindowEnumerator
190 //
191
nsASAppWindowEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)192 nsASAppWindowEnumerator::nsASAppWindowEnumerator(const char16_t* aTypeString,
193 nsWindowMediator& aMediator)
194 : nsAppShellWindowEnumerator(aTypeString, aMediator) {}
195
~nsASAppWindowEnumerator()196 nsASAppWindowEnumerator::~nsASAppWindowEnumerator() {}
197
GetNext(nsISupports ** retval)198 NS_IMETHODIMP nsASAppWindowEnumerator::GetNext(nsISupports** retval) {
199 if (!retval) return NS_ERROR_INVALID_ARG;
200
201 *retval = nullptr;
202 if (mCurrentPosition) {
203 CallQueryInterface(mCurrentPosition->mWindow, retval);
204 mCurrentPosition = FindNext();
205 return NS_OK;
206 }
207 return NS_ERROR_FAILURE;
208 }
209
210 //
211 // nsASDOMWindowEarlyToLateEnumerator
212 //
213
nsASDOMWindowEarlyToLateEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)214 nsASDOMWindowEarlyToLateEnumerator::nsASDOMWindowEarlyToLateEnumerator(
215 const char16_t* aTypeString, nsWindowMediator& aMediator)
216 : nsASDOMWindowEnumerator(aTypeString, aMediator) {
217 mCurrentPosition = aMediator.mOldestWindow;
218 AdjustInitialPosition();
219 }
220
~nsASDOMWindowEarlyToLateEnumerator()221 nsASDOMWindowEarlyToLateEnumerator::~nsASDOMWindowEarlyToLateEnumerator() {}
222
FindNext()223 nsWindowInfo* nsASDOMWindowEarlyToLateEnumerator::FindNext() {
224 nsWindowInfo *info, *listEnd;
225 bool allWindows = mType.IsEmpty();
226
227 // see AppWindowEarlyToLateEnumerator::FindNext
228 if (!mCurrentPosition) return nullptr;
229
230 info = mCurrentPosition->mYounger;
231 listEnd = mWindowMediator->mOldestWindow;
232
233 while (info != listEnd) {
234 if (allWindows || info->TypeEquals(mType)) return info;
235 info = info->mYounger;
236 }
237
238 return nullptr;
239 }
240
241 //
242 // nsASAppWindowEarlyToLateEnumerator
243 //
244
nsASAppWindowEarlyToLateEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)245 nsASAppWindowEarlyToLateEnumerator::nsASAppWindowEarlyToLateEnumerator(
246 const char16_t* aTypeString, nsWindowMediator& aMediator)
247 : nsASAppWindowEnumerator(aTypeString, aMediator) {
248 mCurrentPosition = aMediator.mOldestWindow;
249 AdjustInitialPosition();
250 }
251
~nsASAppWindowEarlyToLateEnumerator()252 nsASAppWindowEarlyToLateEnumerator::~nsASAppWindowEarlyToLateEnumerator() {}
253
FindNext()254 nsWindowInfo* nsASAppWindowEarlyToLateEnumerator::FindNext() {
255 nsWindowInfo *info, *listEnd;
256 bool allWindows = mType.IsEmpty();
257
258 /* mCurrentPosition null is assumed to mean that the enumerator has run
259 its course and is now basically useless. It could also be interpreted
260 to mean that it was created at a time when there were no windows. In
261 that case it would probably be more appropriate to check to see whether
262 windows have subsequently been added. But it's not guaranteed that we'll
263 pick up newly added windows anyway (if they occurred previous to our
264 current position) so we just don't worry about that. */
265 if (!mCurrentPosition) return nullptr;
266
267 info = mCurrentPosition->mYounger;
268 listEnd = mWindowMediator->mOldestWindow;
269
270 while (info != listEnd) {
271 if (allWindows || info->TypeEquals(mType)) return info;
272 info = info->mYounger;
273 }
274
275 return nullptr;
276 }
277
278 //
279 // nsASAppWindowFrontToBackEnumerator
280 //
281
nsASAppWindowFrontToBackEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)282 nsASAppWindowFrontToBackEnumerator::nsASAppWindowFrontToBackEnumerator(
283 const char16_t* aTypeString, nsWindowMediator& aMediator)
284 : nsASAppWindowEnumerator(aTypeString, aMediator) {
285 mCurrentPosition = aMediator.mTopmostWindow;
286 AdjustInitialPosition();
287 }
288
~nsASAppWindowFrontToBackEnumerator()289 nsASAppWindowFrontToBackEnumerator::~nsASAppWindowFrontToBackEnumerator() {}
290
FindNext()291 nsWindowInfo* nsASAppWindowFrontToBackEnumerator::FindNext() {
292 nsWindowInfo *info, *listEnd;
293 bool allWindows = mType.IsEmpty();
294
295 // see AppWindowEarlyToLateEnumerator::FindNext
296 if (!mCurrentPosition) return nullptr;
297
298 info = mCurrentPosition->mLower;
299 listEnd = mWindowMediator->mTopmostWindow;
300
301 while (info != listEnd) {
302 if (allWindows || info->TypeEquals(mType)) return info;
303 info = info->mLower;
304 }
305
306 return nullptr;
307 }
308
309 //
310 // nsASAppWindowBackToFrontEnumerator
311 //
312
nsASAppWindowBackToFrontEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)313 nsASAppWindowBackToFrontEnumerator::nsASAppWindowBackToFrontEnumerator(
314 const char16_t* aTypeString, nsWindowMediator& aMediator)
315 : nsASAppWindowEnumerator(aTypeString, aMediator) {
316 mCurrentPosition =
317 aMediator.mTopmostWindow ? aMediator.mTopmostWindow->mHigher : nullptr;
318 AdjustInitialPosition();
319 }
320
~nsASAppWindowBackToFrontEnumerator()321 nsASAppWindowBackToFrontEnumerator::~nsASAppWindowBackToFrontEnumerator() {}
322
FindNext()323 nsWindowInfo* nsASAppWindowBackToFrontEnumerator::FindNext() {
324 nsWindowInfo *info, *listEnd;
325 bool allWindows = mType.IsEmpty();
326
327 // see AppWindowEarlyToLateEnumerator::FindNext
328 if (!mCurrentPosition) return nullptr;
329
330 info = mCurrentPosition->mHigher;
331 listEnd = mWindowMediator->mTopmostWindow;
332 if (listEnd) listEnd = listEnd->mHigher;
333
334 while (info != listEnd) {
335 if (allWindows || info->TypeEquals(mType)) return info;
336 info = info->mHigher;
337 }
338
339 return nullptr;
340 }
341