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 "nsIDocument.h"
11 #include "nsIDOMElement.h"
12 #include "nsIDOMWindow.h"
13 #include "nsIFactory.h"
14 #include "nsIInterfaceRequestor.h"
15 #include "nsIInterfaceRequestorUtils.h"
16 #include "nsIXULWindow.h"
17 #include "mozilla/dom/Element.h"
18
19 #include "nsWindowMediator.h"
20
21 using mozilla::dom::Element;
22
23 //
24 // static helper functions
25 //
26
27 static nsCOMPtr<nsIDOMNode> GetDOMNodeFromDocShell(nsIDocShell *aShell);
28 static void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute,
29 nsAString &outValue);
30 static void GetWindowType(nsIXULWindow *inWindow, nsString &outType);
31
GetDOMNodeFromDocShell(nsIDocShell * aShell)32 nsCOMPtr<nsIDOMNode> GetDOMNodeFromDocShell(nsIDocShell *aShell) {
33 nsCOMPtr<nsIDOMNode> node;
34
35 nsCOMPtr<nsIContentViewer> cv;
36 aShell->GetContentViewer(getter_AddRefs(cv));
37 if (cv) {
38 nsCOMPtr<nsIDocument> doc = cv->GetDocument();
39 if (doc) {
40 Element *element = doc->GetDocumentElement();
41 if (element) {
42 node = element->AsDOMNode();
43 }
44 }
45 }
46
47 return node;
48 }
49
50 // generic "retrieve the value of a XUL attribute" function
GetAttribute(nsIXULWindow * inWindow,const nsAString & inAttribute,nsAString & outValue)51 void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute,
52 nsAString &outValue) {
53 nsCOMPtr<nsIDocShell> shell;
54 if (inWindow && NS_SUCCEEDED(inWindow->GetDocShell(getter_AddRefs(shell)))) {
55 nsCOMPtr<nsIDOMNode> node(GetDOMNodeFromDocShell(shell));
56 if (node) {
57 nsCOMPtr<Element> webshellElement(do_QueryInterface(node));
58 if (webshellElement) webshellElement->GetAttribute(inAttribute, outValue);
59 }
60 }
61 }
62
63 // retrieve the window type, stored as the value of a particular
64 // attribute in its XUL window tag
GetWindowType(nsIXULWindow * aWindow,nsString & outType)65 void GetWindowType(nsIXULWindow *aWindow, nsString &outType) {
66 GetAttribute(aWindow, NS_LITERAL_STRING("windowtype"), outType);
67 }
68
69 //
70 // nsWindowInfo
71 //
72
nsWindowInfo(nsIXULWindow * inWindow,int32_t inTimeStamp)73 nsWindowInfo::nsWindowInfo(nsIXULWindow *inWindow, int32_t inTimeStamp)
74 : mWindow(inWindow),
75 mTimeStamp(inTimeStamp),
76 mZLevel(nsIXULWindow::normalZ) {
77 ReferenceSelf(true, true);
78 }
79
~nsWindowInfo()80 nsWindowInfo::~nsWindowInfo() {}
81
82 // return true if the window described by this WindowInfo has a type
83 // equal to the given type
TypeEquals(const nsAString & aType)84 bool nsWindowInfo::TypeEquals(const nsAString &aType) {
85 nsAutoString rtnString;
86 GetWindowType(mWindow, rtnString);
87 return rtnString == aType;
88 }
89
90 // insert the struct into their two linked lists, in position after the
91 // given (independent) method arguments
InsertAfter(nsWindowInfo * inOlder,nsWindowInfo * inHigher)92 void nsWindowInfo::InsertAfter(nsWindowInfo *inOlder, nsWindowInfo *inHigher) {
93 if (inOlder) {
94 mOlder = inOlder;
95 mYounger = inOlder->mYounger;
96 mOlder->mYounger = this;
97 if (mOlder->mOlder == mOlder) mOlder->mOlder = this;
98 mYounger->mOlder = this;
99 if (mYounger->mYounger == mYounger) mYounger->mYounger = this;
100 }
101 if (inHigher) {
102 mHigher = inHigher;
103 mLower = inHigher->mLower;
104 mHigher->mLower = this;
105 if (mHigher->mHigher == mHigher) mHigher->mHigher = this;
106 mLower->mHigher = this;
107 if (mLower->mLower == mLower) mLower->mLower = this;
108 }
109 }
110
111 // remove the struct from its linked lists
Unlink(bool inAge,bool inZ)112 void nsWindowInfo::Unlink(bool inAge, bool inZ) {
113 if (inAge) {
114 mOlder->mYounger = mYounger;
115 mYounger->mOlder = mOlder;
116 }
117 if (inZ) {
118 mLower->mHigher = mHigher;
119 mHigher->mLower = mLower;
120 }
121 ReferenceSelf(inAge, inZ);
122 }
123
124 // initialize the struct to be a valid linked list of one element
ReferenceSelf(bool inAge,bool inZ)125 void nsWindowInfo::ReferenceSelf(bool inAge, bool inZ) {
126 if (inAge) {
127 mYounger = this;
128 mOlder = this;
129 }
130 if (inZ) {
131 mLower = this;
132 mHigher = this;
133 }
134 }
135
136 //
137 // nsAppShellWindowEnumerator
138 //
139
NS_IMPL_ISUPPORTS(nsAppShellWindowEnumerator,nsISimpleEnumerator)140 NS_IMPL_ISUPPORTS(nsAppShellWindowEnumerator, nsISimpleEnumerator)
141
142 nsAppShellWindowEnumerator::nsAppShellWindowEnumerator(
143 const char16_t *aTypeString, nsWindowMediator &aMediator)
144 : mWindowMediator(&aMediator),
145 mType(aTypeString),
146 mCurrentPosition(nullptr) {
147 mWindowMediator->AddEnumerator(this);
148 NS_ADDREF(mWindowMediator);
149 }
150
~nsAppShellWindowEnumerator()151 nsAppShellWindowEnumerator::~nsAppShellWindowEnumerator() {
152 mWindowMediator->RemoveEnumerator(this);
153 NS_RELEASE(mWindowMediator);
154 }
155
156 // after mCurrentPosition has been initialized to point to the beginning
157 // of the appropriate list, adjust it if necessary
AdjustInitialPosition()158 void nsAppShellWindowEnumerator::AdjustInitialPosition() {
159 if (!mType.IsEmpty() && mCurrentPosition &&
160 !mCurrentPosition->TypeEquals(mType))
161 mCurrentPosition = FindNext();
162 }
163
HasMoreElements(bool * retval)164 NS_IMETHODIMP nsAppShellWindowEnumerator::HasMoreElements(bool *retval) {
165 if (!retval) return NS_ERROR_INVALID_ARG;
166
167 *retval = mCurrentPosition ? true : false;
168 return NS_OK;
169 }
170
171 // if a window is being removed adjust the iterator's current position
WindowRemoved(nsWindowInfo * inInfo)172 void nsAppShellWindowEnumerator::WindowRemoved(nsWindowInfo *inInfo) {
173 if (mCurrentPosition == inInfo) mCurrentPosition = FindNext();
174 }
175
176 //
177 // nsASDOMWindowEnumerator
178 //
179
nsASDOMWindowEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)180 nsASDOMWindowEnumerator::nsASDOMWindowEnumerator(const char16_t *aTypeString,
181 nsWindowMediator &aMediator)
182 : nsAppShellWindowEnumerator(aTypeString, aMediator) {}
183
~nsASDOMWindowEnumerator()184 nsASDOMWindowEnumerator::~nsASDOMWindowEnumerator() {}
185
GetNext(nsISupports ** retval)186 NS_IMETHODIMP nsASDOMWindowEnumerator::GetNext(nsISupports **retval) {
187 if (!retval) return NS_ERROR_INVALID_ARG;
188
189 *retval = nullptr;
190 while (mCurrentPosition) {
191 nsCOMPtr<nsPIDOMWindowOuter> domWindow;
192 nsWindowMediator::GetDOMWindow(mCurrentPosition->mWindow, domWindow);
193 mCurrentPosition = FindNext();
194 if (domWindow) return CallQueryInterface(domWindow, retval);
195 }
196 return NS_OK;
197 }
198
199 //
200 // nsASXULWindowEnumerator
201 //
202
nsASXULWindowEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)203 nsASXULWindowEnumerator::nsASXULWindowEnumerator(const char16_t *aTypeString,
204 nsWindowMediator &aMediator)
205 : nsAppShellWindowEnumerator(aTypeString, aMediator) {}
206
~nsASXULWindowEnumerator()207 nsASXULWindowEnumerator::~nsASXULWindowEnumerator() {}
208
GetNext(nsISupports ** retval)209 NS_IMETHODIMP nsASXULWindowEnumerator::GetNext(nsISupports **retval) {
210 if (!retval) return NS_ERROR_INVALID_ARG;
211
212 *retval = nullptr;
213 if (mCurrentPosition) {
214 CallQueryInterface(mCurrentPosition->mWindow, retval);
215 mCurrentPosition = FindNext();
216 }
217 return NS_OK;
218 }
219
220 //
221 // nsASDOMWindowEarlyToLateEnumerator
222 //
223
nsASDOMWindowEarlyToLateEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)224 nsASDOMWindowEarlyToLateEnumerator::nsASDOMWindowEarlyToLateEnumerator(
225 const char16_t *aTypeString, nsWindowMediator &aMediator)
226 : nsASDOMWindowEnumerator(aTypeString, aMediator) {
227 mCurrentPosition = aMediator.mOldestWindow;
228 AdjustInitialPosition();
229 }
230
~nsASDOMWindowEarlyToLateEnumerator()231 nsASDOMWindowEarlyToLateEnumerator::~nsASDOMWindowEarlyToLateEnumerator() {}
232
FindNext()233 nsWindowInfo *nsASDOMWindowEarlyToLateEnumerator::FindNext() {
234 nsWindowInfo *info, *listEnd;
235 bool allWindows = mType.IsEmpty();
236
237 // see nsXULWindowEarlyToLateEnumerator::FindNext
238 if (!mCurrentPosition) return nullptr;
239
240 info = mCurrentPosition->mYounger;
241 listEnd = mWindowMediator->mOldestWindow;
242
243 while (info != listEnd) {
244 if (allWindows || info->TypeEquals(mType)) return info;
245 info = info->mYounger;
246 }
247
248 return nullptr;
249 }
250
251 //
252 // nsASXULWindowEarlyToLateEnumerator
253 //
254
nsASXULWindowEarlyToLateEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)255 nsASXULWindowEarlyToLateEnumerator::nsASXULWindowEarlyToLateEnumerator(
256 const char16_t *aTypeString, nsWindowMediator &aMediator)
257 : nsASXULWindowEnumerator(aTypeString, aMediator) {
258 mCurrentPosition = aMediator.mOldestWindow;
259 AdjustInitialPosition();
260 }
261
~nsASXULWindowEarlyToLateEnumerator()262 nsASXULWindowEarlyToLateEnumerator::~nsASXULWindowEarlyToLateEnumerator() {}
263
FindNext()264 nsWindowInfo *nsASXULWindowEarlyToLateEnumerator::FindNext() {
265 nsWindowInfo *info, *listEnd;
266 bool allWindows = mType.IsEmpty();
267
268 /* mCurrentPosition null is assumed to mean that the enumerator has run
269 its course and is now basically useless. It could also be interpreted
270 to mean that it was created at a time when there were no windows. In
271 that case it would probably be more appropriate to check to see whether
272 windows have subsequently been added. But it's not guaranteed that we'll
273 pick up newly added windows anyway (if they occurred previous to our
274 current position) so we just don't worry about that. */
275 if (!mCurrentPosition) return nullptr;
276
277 info = mCurrentPosition->mYounger;
278 listEnd = mWindowMediator->mOldestWindow;
279
280 while (info != listEnd) {
281 if (allWindows || info->TypeEquals(mType)) return info;
282 info = info->mYounger;
283 }
284
285 return nullptr;
286 }
287
288 //
289 // nsASDOMWindowFrontToBackEnumerator
290 //
291
nsASDOMWindowFrontToBackEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)292 nsASDOMWindowFrontToBackEnumerator::nsASDOMWindowFrontToBackEnumerator(
293 const char16_t *aTypeString, nsWindowMediator &aMediator)
294 : nsASDOMWindowEnumerator(aTypeString, aMediator) {
295 mCurrentPosition = aMediator.mTopmostWindow;
296 AdjustInitialPosition();
297 }
298
~nsASDOMWindowFrontToBackEnumerator()299 nsASDOMWindowFrontToBackEnumerator::~nsASDOMWindowFrontToBackEnumerator() {}
300
FindNext()301 nsWindowInfo *nsASDOMWindowFrontToBackEnumerator::FindNext() {
302 nsWindowInfo *info, *listEnd;
303 bool allWindows = mType.IsEmpty();
304
305 // see nsXULWindowEarlyToLateEnumerator::FindNext
306 if (!mCurrentPosition) return nullptr;
307
308 info = mCurrentPosition->mLower;
309 listEnd = mWindowMediator->mTopmostWindow;
310
311 while (info != listEnd) {
312 if (allWindows || info->TypeEquals(mType)) return info;
313 info = info->mLower;
314 }
315
316 return nullptr;
317 }
318
319 //
320 // nsASXULWindowFrontToBackEnumerator
321 //
322
nsASXULWindowFrontToBackEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)323 nsASXULWindowFrontToBackEnumerator::nsASXULWindowFrontToBackEnumerator(
324 const char16_t *aTypeString, nsWindowMediator &aMediator)
325 : nsASXULWindowEnumerator(aTypeString, aMediator) {
326 mCurrentPosition = aMediator.mTopmostWindow;
327 AdjustInitialPosition();
328 }
329
~nsASXULWindowFrontToBackEnumerator()330 nsASXULWindowFrontToBackEnumerator::~nsASXULWindowFrontToBackEnumerator() {}
331
FindNext()332 nsWindowInfo *nsASXULWindowFrontToBackEnumerator::FindNext() {
333 nsWindowInfo *info, *listEnd;
334 bool allWindows = mType.IsEmpty();
335
336 // see nsXULWindowEarlyToLateEnumerator::FindNext
337 if (!mCurrentPosition) return nullptr;
338
339 info = mCurrentPosition->mLower;
340 listEnd = mWindowMediator->mTopmostWindow;
341
342 while (info != listEnd) {
343 if (allWindows || info->TypeEquals(mType)) return info;
344 info = info->mLower;
345 }
346
347 return nullptr;
348 }
349
350 //
351 // nsASDOMWindowBackToFrontEnumerator
352 //
353
nsASDOMWindowBackToFrontEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)354 nsASDOMWindowBackToFrontEnumerator::nsASDOMWindowBackToFrontEnumerator(
355 const char16_t *aTypeString, nsWindowMediator &aMediator)
356 : nsASDOMWindowEnumerator(aTypeString, aMediator) {
357 mCurrentPosition =
358 aMediator.mTopmostWindow ? aMediator.mTopmostWindow->mHigher : nullptr;
359 AdjustInitialPosition();
360 }
361
~nsASDOMWindowBackToFrontEnumerator()362 nsASDOMWindowBackToFrontEnumerator::~nsASDOMWindowBackToFrontEnumerator() {}
363
FindNext()364 nsWindowInfo *nsASDOMWindowBackToFrontEnumerator::FindNext() {
365 nsWindowInfo *info, *listEnd;
366 bool allWindows = mType.IsEmpty();
367
368 // see nsXULWindowEarlyToLateEnumerator::FindNext
369 if (!mCurrentPosition) return nullptr;
370
371 info = mCurrentPosition->mHigher;
372 listEnd = mWindowMediator->mTopmostWindow;
373 if (listEnd) listEnd = listEnd->mHigher;
374
375 while (info != listEnd) {
376 if (allWindows || info->TypeEquals(mType)) return info;
377 info = info->mHigher;
378 }
379
380 return nullptr;
381 }
382
383 //
384 // nsASXULWindowBackToFrontEnumerator
385 //
386
nsASXULWindowBackToFrontEnumerator(const char16_t * aTypeString,nsWindowMediator & aMediator)387 nsASXULWindowBackToFrontEnumerator::nsASXULWindowBackToFrontEnumerator(
388 const char16_t *aTypeString, nsWindowMediator &aMediator)
389 : nsASXULWindowEnumerator(aTypeString, aMediator) {
390 mCurrentPosition =
391 aMediator.mTopmostWindow ? aMediator.mTopmostWindow->mHigher : nullptr;
392 AdjustInitialPosition();
393 }
394
~nsASXULWindowBackToFrontEnumerator()395 nsASXULWindowBackToFrontEnumerator::~nsASXULWindowBackToFrontEnumerator() {}
396
FindNext()397 nsWindowInfo *nsASXULWindowBackToFrontEnumerator::FindNext() {
398 nsWindowInfo *info, *listEnd;
399 bool allWindows = mType.IsEmpty();
400
401 // see nsXULWindowEarlyToLateEnumerator::FindNext
402 if (!mCurrentPosition) return nullptr;
403
404 info = mCurrentPosition->mHigher;
405 listEnd = mWindowMediator->mTopmostWindow;
406 if (listEnd) listEnd = listEnd->mHigher;
407
408 while (info != listEnd) {
409 if (allWindows || info->TypeEquals(mType)) return info;
410 info = info->mHigher;
411 }
412
413 return nullptr;
414 }
415