1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2001
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsAppShellWindowEnumerator.h"
39 :
40 : #include "nsIContentViewer.h"
41 : #include "nsIDocShell.h"
42 : #include "nsIDocument.h"
43 : #include "nsIDOMDocument.h"
44 : #include "nsIDOMElement.h"
45 : #include "nsIDOMWindow.h"
46 : #include "nsIFactory.h"
47 : #include "nsIInterfaceRequestor.h"
48 : #include "nsIInterfaceRequestorUtils.h"
49 : #include "nsIXULWindow.h"
50 :
51 : #include "nsWindowMediator.h"
52 :
53 : //
54 : // static helper functions
55 : //
56 :
57 : static nsresult GetDOMWindow(nsIXULWindow* inWindow,
58 : nsCOMPtr<nsIDOMWindow> &outDOMWindow);
59 : static nsCOMPtr<nsIDOMNode> GetDOMNodeFromDocShell(nsIDocShell *aShell);
60 : static void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute,
61 : nsAString &outValue);
62 : static void GetWindowType(nsIXULWindow* inWindow, nsString &outType);
63 :
64 : // fetch the nsIDOMWindow(Internal) from a XUL Window
65 0 : nsresult GetDOMWindow(nsIXULWindow *aWindow, nsCOMPtr<nsIDOMWindow> &aDOMWindow)
66 : {
67 0 : nsCOMPtr<nsIDocShell> docShell;
68 :
69 0 : aWindow->GetDocShell(getter_AddRefs(docShell));
70 0 : aDOMWindow = do_GetInterface(docShell);
71 0 : return aDOMWindow ? NS_OK : NS_ERROR_FAILURE;
72 : }
73 :
74 0 : nsCOMPtr<nsIDOMNode> GetDOMNodeFromDocShell(nsIDocShell *aShell)
75 : {
76 0 : nsCOMPtr<nsIDOMNode> node;
77 :
78 0 : nsCOMPtr<nsIContentViewer> cv;
79 0 : aShell->GetContentViewer(getter_AddRefs(cv));
80 0 : if (cv) {
81 0 : nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(cv->GetDocument()));
82 0 : if (domdoc) {
83 0 : nsCOMPtr<nsIDOMElement> element;
84 0 : domdoc->GetDocumentElement(getter_AddRefs(element));
85 0 : if (element)
86 0 : node = element;
87 : }
88 : }
89 :
90 : return node;
91 : }
92 :
93 : // generic "retrieve the value of a XUL attribute" function
94 0 : void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute,
95 : nsAString &outValue)
96 : {
97 0 : nsCOMPtr<nsIDocShell> shell;
98 0 : if (inWindow && NS_SUCCEEDED(inWindow->GetDocShell(getter_AddRefs(shell)))) {
99 0 : nsCOMPtr<nsIDOMNode> node(GetDOMNodeFromDocShell(shell));
100 0 : if (node) {
101 0 : nsCOMPtr<nsIDOMElement> webshellElement(do_QueryInterface(node));
102 0 : if (webshellElement)
103 0 : webshellElement->GetAttribute(inAttribute, outValue);
104 : }
105 : }
106 0 : }
107 :
108 : // retrieve the window type, stored as the value of a particular
109 : // attribute in its XUL window tag
110 0 : void GetWindowType(nsIXULWindow* aWindow, nsString &outType)
111 : {
112 0 : GetAttribute(aWindow, NS_LITERAL_STRING("windowtype"), outType);
113 0 : }
114 :
115 : //
116 : // nsWindowInfo
117 : //
118 :
119 0 : nsWindowInfo::nsWindowInfo(nsIXULWindow* inWindow, PRInt32 inTimeStamp) :
120 0 : mWindow(inWindow),mTimeStamp(inTimeStamp),mZLevel(nsIXULWindow::normalZ)
121 : {
122 0 : ReferenceSelf(true, true);
123 0 : }
124 :
125 0 : nsWindowInfo::~nsWindowInfo()
126 : {
127 0 : }
128 :
129 : // return true if the window described by this WindowInfo has a type
130 : // equal to the given type
131 0 : bool nsWindowInfo::TypeEquals(const nsAString &aType)
132 : {
133 0 : nsAutoString rtnString;
134 0 : GetWindowType(mWindow, rtnString);
135 0 : return rtnString == aType;
136 : }
137 :
138 : // insert the struct into their two linked lists, in position after the
139 : // given (independent) method arguments
140 0 : void nsWindowInfo::InsertAfter(nsWindowInfo *inOlder , nsWindowInfo *inHigher)
141 : {
142 0 : if (inOlder) {
143 0 : mOlder = inOlder;
144 0 : mYounger = inOlder->mYounger;
145 0 : mOlder->mYounger = this;
146 0 : if (mOlder->mOlder == mOlder)
147 0 : mOlder->mOlder = this;
148 0 : mYounger->mOlder = this;
149 0 : if (mYounger->mYounger == mYounger)
150 0 : mYounger->mYounger = this;
151 : }
152 0 : if (inHigher) {
153 0 : mHigher = inHigher;
154 0 : mLower = inHigher->mLower;
155 0 : mHigher->mLower = this;
156 0 : if (mHigher->mHigher == mHigher)
157 0 : mHigher->mHigher = this;
158 0 : mLower->mHigher = this;
159 0 : if (mLower->mLower == mLower)
160 0 : mLower->mLower = this;
161 : }
162 0 : }
163 :
164 : // remove the struct from its linked lists
165 0 : void nsWindowInfo::Unlink(bool inAge, bool inZ)
166 : {
167 0 : if (inAge) {
168 0 : mOlder->mYounger = mYounger;
169 0 : mYounger->mOlder = mOlder;
170 : }
171 0 : if (inZ) {
172 0 : mLower->mHigher = mHigher;
173 0 : mHigher->mLower = mLower;
174 : }
175 0 : ReferenceSelf(inAge, inZ);
176 0 : }
177 :
178 : // initialize the struct to be a valid linked list of one element
179 0 : void nsWindowInfo::ReferenceSelf(bool inAge, bool inZ)
180 : {
181 0 : if (inAge) {
182 0 : mYounger = this;
183 0 : mOlder = this;
184 : }
185 0 : if (inZ) {
186 0 : mLower = this;
187 0 : mHigher = this;
188 : }
189 0 : }
190 :
191 : //
192 : // nsAppShellWindowEnumerator
193 : //
194 :
195 7703 : NS_IMPL_ISUPPORTS1(nsAppShellWindowEnumerator, nsISimpleEnumerator)
196 :
197 837 : nsAppShellWindowEnumerator::nsAppShellWindowEnumerator(
198 : const PRUnichar* aTypeString,
199 : nsWindowMediator& aMediator) :
200 837 : mWindowMediator(&aMediator), mType(aTypeString), mCurrentPosition(nsnull)
201 : {
202 837 : mWindowMediator->AddEnumerator(this);
203 837 : NS_ADDREF(mWindowMediator);
204 837 : }
205 :
206 1674 : nsAppShellWindowEnumerator::~nsAppShellWindowEnumerator()
207 : {
208 837 : mWindowMediator->RemoveEnumerator(this);
209 837 : NS_RELEASE(mWindowMediator);
210 1674 : }
211 :
212 : // after mCurrentPosition has been initialized to point to the beginning
213 : // of the appropriate list, adjust it if necessary
214 837 : void nsAppShellWindowEnumerator::AdjustInitialPosition()
215 : {
216 837 : if (!mType.IsEmpty() && mCurrentPosition && !mCurrentPosition->TypeEquals(mType))
217 0 : mCurrentPosition = FindNext();
218 837 : }
219 :
220 520 : NS_IMETHODIMP nsAppShellWindowEnumerator::HasMoreElements(bool *retval)
221 : {
222 520 : if (!retval)
223 0 : return NS_ERROR_INVALID_ARG;
224 :
225 520 : *retval = mCurrentPosition ? true : false;
226 520 : return NS_OK;
227 : }
228 :
229 : // if a window is being removed adjust the iterator's current position
230 0 : void nsAppShellWindowEnumerator::WindowRemoved(nsWindowInfo *inInfo)
231 : {
232 0 : if (mCurrentPosition == inInfo)
233 0 : mCurrentPosition = FindNext();
234 0 : }
235 :
236 : //
237 : // nsASDOMWindowEnumerator
238 : //
239 :
240 837 : nsASDOMWindowEnumerator::nsASDOMWindowEnumerator(
241 : const PRUnichar* aTypeString,
242 : nsWindowMediator& aMediator) :
243 837 : nsAppShellWindowEnumerator(aTypeString, aMediator)
244 : {
245 837 : }
246 :
247 837 : nsASDOMWindowEnumerator::~nsASDOMWindowEnumerator()
248 : {
249 1674 : }
250 :
251 317 : NS_IMETHODIMP nsASDOMWindowEnumerator::GetNext(nsISupports **retval)
252 : {
253 317 : if (!retval)
254 0 : return NS_ERROR_INVALID_ARG;
255 :
256 317 : *retval = nsnull;
257 317 : if (mCurrentPosition) {
258 0 : nsCOMPtr<nsIDOMWindow> domWindow;
259 0 : GetDOMWindow(mCurrentPosition->mWindow, domWindow);
260 0 : CallQueryInterface(domWindow, retval);
261 0 : mCurrentPosition = FindNext();
262 : }
263 317 : return NS_OK;
264 : }
265 :
266 : //
267 : // nsASXULWindowEnumerator
268 : //
269 :
270 0 : nsASXULWindowEnumerator::nsASXULWindowEnumerator(
271 : const PRUnichar* aTypeString,
272 : nsWindowMediator& aMediator) :
273 0 : nsAppShellWindowEnumerator(aTypeString, aMediator)
274 : {
275 0 : }
276 :
277 0 : nsASXULWindowEnumerator::~nsASXULWindowEnumerator()
278 : {
279 0 : }
280 :
281 0 : NS_IMETHODIMP nsASXULWindowEnumerator::GetNext(nsISupports **retval)
282 : {
283 0 : if (!retval)
284 0 : return NS_ERROR_INVALID_ARG;
285 :
286 0 : *retval = nsnull;
287 0 : if (mCurrentPosition) {
288 0 : CallQueryInterface(mCurrentPosition->mWindow, retval);
289 0 : mCurrentPosition = FindNext();
290 : }
291 0 : return NS_OK;
292 : }
293 :
294 : //
295 : // nsASDOMWindowEarlyToLateEnumerator
296 : //
297 :
298 837 : nsASDOMWindowEarlyToLateEnumerator::nsASDOMWindowEarlyToLateEnumerator(
299 : const PRUnichar *aTypeString,
300 : nsWindowMediator &aMediator) :
301 837 : nsASDOMWindowEnumerator(aTypeString, aMediator)
302 : {
303 837 : mCurrentPosition = aMediator.mOldestWindow;
304 837 : AdjustInitialPosition();
305 837 : }
306 :
307 1674 : nsASDOMWindowEarlyToLateEnumerator::~nsASDOMWindowEarlyToLateEnumerator()
308 : {
309 3348 : }
310 :
311 0 : nsWindowInfo *nsASDOMWindowEarlyToLateEnumerator::FindNext()
312 : {
313 : nsWindowInfo *info,
314 : *listEnd;
315 0 : bool allWindows = mType.IsEmpty();
316 :
317 : // see nsXULWindowEarlyToLateEnumerator::FindNext
318 0 : if (!mCurrentPosition)
319 0 : return nsnull;
320 :
321 0 : info = mCurrentPosition->mYounger;
322 0 : listEnd = mWindowMediator->mOldestWindow;
323 :
324 0 : while (info != listEnd) {
325 0 : if (allWindows || info->TypeEquals(mType))
326 0 : return info;
327 0 : info = info->mYounger;
328 : }
329 :
330 0 : return nsnull;
331 : }
332 :
333 : //
334 : // nsASXULWindowEarlyToLateEnumerator
335 : //
336 :
337 0 : nsASXULWindowEarlyToLateEnumerator::nsASXULWindowEarlyToLateEnumerator(
338 : const PRUnichar *aTypeString,
339 : nsWindowMediator &aMediator) :
340 0 : nsASXULWindowEnumerator(aTypeString, aMediator)
341 : {
342 0 : mCurrentPosition = aMediator.mOldestWindow;
343 0 : AdjustInitialPosition();
344 0 : }
345 :
346 0 : nsASXULWindowEarlyToLateEnumerator::~nsASXULWindowEarlyToLateEnumerator()
347 : {
348 0 : }
349 :
350 0 : nsWindowInfo *nsASXULWindowEarlyToLateEnumerator::FindNext()
351 : {
352 : nsWindowInfo *info,
353 : *listEnd;
354 0 : bool allWindows = mType.IsEmpty();
355 :
356 : /* mCurrentPosition null is assumed to mean that the enumerator has run
357 : its course and is now basically useless. It could also be interpreted
358 : to mean that it was created at a time when there were no windows. In
359 : that case it would probably be more appropriate to check to see whether
360 : windows have subsequently been added. But it's not guaranteed that we'll
361 : pick up newly added windows anyway (if they occurred previous to our
362 : current position) so we just don't worry about that. */
363 0 : if (!mCurrentPosition)
364 0 : return nsnull;
365 :
366 0 : info = mCurrentPosition->mYounger;
367 0 : listEnd = mWindowMediator->mOldestWindow;
368 :
369 0 : while (info != listEnd) {
370 0 : if (allWindows || info->TypeEquals(mType))
371 0 : return info;
372 0 : info = info->mYounger;
373 : }
374 :
375 0 : return nsnull;
376 : }
377 :
378 : //
379 : // nsASDOMWindowFrontToBackEnumerator
380 : //
381 :
382 0 : nsASDOMWindowFrontToBackEnumerator::nsASDOMWindowFrontToBackEnumerator(
383 : const PRUnichar *aTypeString,
384 : nsWindowMediator &aMediator) :
385 0 : nsASDOMWindowEnumerator(aTypeString, aMediator)
386 : {
387 0 : mCurrentPosition = aMediator.mTopmostWindow;
388 0 : AdjustInitialPosition();
389 0 : }
390 :
391 0 : nsASDOMWindowFrontToBackEnumerator::~nsASDOMWindowFrontToBackEnumerator()
392 : {
393 0 : }
394 :
395 0 : nsWindowInfo *nsASDOMWindowFrontToBackEnumerator::FindNext()
396 : {
397 : nsWindowInfo *info,
398 : *listEnd;
399 0 : bool allWindows = mType.IsEmpty();
400 :
401 : // see nsXULWindowEarlyToLateEnumerator::FindNext
402 0 : if (!mCurrentPosition)
403 0 : return nsnull;
404 :
405 0 : info = mCurrentPosition->mLower;
406 0 : listEnd = mWindowMediator->mTopmostWindow;
407 :
408 0 : while (info != listEnd) {
409 0 : if (allWindows || info->TypeEquals(mType))
410 0 : return info;
411 0 : info = info->mLower;
412 : }
413 :
414 0 : return nsnull;
415 : }
416 :
417 : //
418 : // nsASXULWindowFrontToBackEnumerator
419 : //
420 :
421 0 : nsASXULWindowFrontToBackEnumerator::nsASXULWindowFrontToBackEnumerator(
422 : const PRUnichar *aTypeString,
423 : nsWindowMediator &aMediator) :
424 0 : nsASXULWindowEnumerator(aTypeString, aMediator)
425 : {
426 0 : mCurrentPosition = aMediator.mTopmostWindow;
427 0 : AdjustInitialPosition();
428 0 : }
429 :
430 0 : nsASXULWindowFrontToBackEnumerator::~nsASXULWindowFrontToBackEnumerator()
431 : {
432 0 : }
433 :
434 0 : nsWindowInfo *nsASXULWindowFrontToBackEnumerator::FindNext()
435 : {
436 : nsWindowInfo *info,
437 : *listEnd;
438 0 : bool allWindows = mType.IsEmpty();
439 :
440 : // see nsXULWindowEarlyToLateEnumerator::FindNext
441 0 : if (!mCurrentPosition)
442 0 : return nsnull;
443 :
444 0 : info = mCurrentPosition->mLower;
445 0 : listEnd = mWindowMediator->mTopmostWindow;
446 :
447 0 : while (info != listEnd) {
448 0 : if (allWindows || info->TypeEquals(mType))
449 0 : return info;
450 0 : info = info->mLower;
451 : }
452 :
453 0 : return nsnull;
454 : }
455 :
456 : //
457 : // nsASDOMWindowBackToFrontEnumerator
458 : //
459 :
460 0 : nsASDOMWindowBackToFrontEnumerator::nsASDOMWindowBackToFrontEnumerator(
461 : const PRUnichar *aTypeString,
462 : nsWindowMediator &aMediator) :
463 0 : nsASDOMWindowEnumerator(aTypeString, aMediator)
464 : {
465 : mCurrentPosition = aMediator.mTopmostWindow ?
466 0 : aMediator.mTopmostWindow->mHigher : nsnull;
467 0 : AdjustInitialPosition();
468 0 : }
469 :
470 0 : nsASDOMWindowBackToFrontEnumerator::~nsASDOMWindowBackToFrontEnumerator()
471 : {
472 0 : }
473 :
474 0 : nsWindowInfo *nsASDOMWindowBackToFrontEnumerator::FindNext()
475 : {
476 : nsWindowInfo *info,
477 : *listEnd;
478 0 : bool allWindows = mType.IsEmpty();
479 :
480 : // see nsXULWindowEarlyToLateEnumerator::FindNext
481 0 : if (!mCurrentPosition)
482 0 : return nsnull;
483 :
484 0 : info = mCurrentPosition->mHigher;
485 0 : listEnd = mWindowMediator->mTopmostWindow;
486 0 : if (listEnd)
487 0 : listEnd = listEnd->mHigher;
488 :
489 0 : while (info != listEnd) {
490 0 : if (allWindows || info->TypeEquals(mType))
491 0 : return info;
492 0 : info = info->mHigher;
493 : }
494 :
495 0 : return nsnull;
496 : }
497 :
498 : //
499 : // nsASXULWindowBackToFrontEnumerator
500 : //
501 :
502 0 : nsASXULWindowBackToFrontEnumerator::nsASXULWindowBackToFrontEnumerator(
503 : const PRUnichar *aTypeString,
504 : nsWindowMediator &aMediator) :
505 0 : nsASXULWindowEnumerator(aTypeString, aMediator)
506 : {
507 : mCurrentPosition = aMediator.mTopmostWindow ?
508 0 : aMediator.mTopmostWindow->mHigher : nsnull;
509 0 : AdjustInitialPosition();
510 0 : }
511 :
512 0 : nsASXULWindowBackToFrontEnumerator::~nsASXULWindowBackToFrontEnumerator()
513 : {
514 0 : }
515 :
516 0 : nsWindowInfo *nsASXULWindowBackToFrontEnumerator::FindNext()
517 : {
518 : nsWindowInfo *info,
519 : *listEnd;
520 0 : bool allWindows = mType.IsEmpty();
521 :
522 : // see nsXULWindowEarlyToLateEnumerator::FindNext
523 0 : if (!mCurrentPosition)
524 0 : return nsnull;
525 :
526 0 : info = mCurrentPosition->mHigher;
527 0 : listEnd = mWindowMediator->mTopmostWindow;
528 0 : if (listEnd)
529 0 : listEnd = listEnd->mHigher;
530 :
531 0 : while (info != listEnd) {
532 0 : if (allWindows || info->TypeEquals(mType))
533 0 : return info;
534 0 : info = info->mHigher;
535 : }
536 :
537 0 : return nsnull;
538 : }
|