summaryrefslogtreecommitdiffstats
path: root/xpfe/appshell/nsAppShellWindowEnumerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpfe/appshell/nsAppShellWindowEnumerator.cpp')
-rw-r--r--xpfe/appshell/nsAppShellWindowEnumerator.cpp340
1 files changed, 340 insertions, 0 deletions
diff --git a/xpfe/appshell/nsAppShellWindowEnumerator.cpp b/xpfe/appshell/nsAppShellWindowEnumerator.cpp
new file mode 100644
index 0000000000..3e7a4fa4b8
--- /dev/null
+++ b/xpfe/appshell/nsAppShellWindowEnumerator.cpp
@@ -0,0 +1,340 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsAppShellWindowEnumerator.h"
+
+#include "nsIContentViewer.h"
+#include "nsIDocShell.h"
+#include "mozilla/dom/Document.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIAppWindow.h"
+#include "mozilla/dom/Element.h"
+
+#include "nsWindowMediator.h"
+
+using mozilla::dom::Document;
+using mozilla::dom::Element;
+
+//
+// static helper functions
+//
+
+static void GetAttribute(nsIAppWindow* inWindow, const nsAString& inAttribute,
+ nsAString& outValue);
+static void GetWindowType(nsIAppWindow* inWindow, nsString& outType);
+
+static Element* GetElementFromDocShell(nsIDocShell* aShell) {
+ nsCOMPtr<nsIContentViewer> cv;
+ aShell->GetContentViewer(getter_AddRefs(cv));
+ if (cv) {
+ RefPtr<Document> doc = cv->GetDocument();
+ if (doc) {
+ return doc->GetDocumentElement();
+ }
+ }
+
+ return nullptr;
+}
+
+// generic "retrieve the value of a XUL attribute" function
+void GetAttribute(nsIAppWindow* inWindow, const nsAString& inAttribute,
+ nsAString& outValue) {
+ nsCOMPtr<nsIDocShell> shell;
+ if (inWindow && NS_SUCCEEDED(inWindow->GetDocShell(getter_AddRefs(shell)))) {
+ RefPtr<Element> webshellElement = GetElementFromDocShell(shell);
+ if (webshellElement) {
+ webshellElement->GetAttribute(inAttribute, outValue);
+ }
+ }
+}
+
+// retrieve the window type, stored as the value of a particular
+// attribute in its XUL window tag
+void GetWindowType(nsIAppWindow* aWindow, nsString& outType) {
+ GetAttribute(aWindow, u"windowtype"_ns, outType);
+}
+
+//
+// nsWindowInfo
+//
+
+nsWindowInfo::nsWindowInfo(nsIAppWindow* inWindow, int32_t inTimeStamp)
+ : mWindow(inWindow),
+ mTimeStamp(inTimeStamp),
+ mZLevel(nsIAppWindow::normalZ) {
+ ReferenceSelf(true, true);
+}
+
+nsWindowInfo::~nsWindowInfo() {}
+
+// return true if the window described by this WindowInfo has a type
+// equal to the given type
+bool nsWindowInfo::TypeEquals(const nsAString& aType) {
+ nsAutoString rtnString;
+ GetWindowType(mWindow, rtnString);
+ return rtnString == aType;
+}
+
+// insert the struct into their two linked lists, in position after the
+// given (independent) method arguments
+void nsWindowInfo::InsertAfter(nsWindowInfo* inOlder, nsWindowInfo* inHigher) {
+ if (inOlder) {
+ mOlder = inOlder;
+ mYounger = inOlder->mYounger;
+ mOlder->mYounger = this;
+ if (mOlder->mOlder == mOlder) mOlder->mOlder = this;
+ mYounger->mOlder = this;
+ if (mYounger->mYounger == mYounger) mYounger->mYounger = this;
+ }
+ if (inHigher) {
+ mHigher = inHigher;
+ mLower = inHigher->mLower;
+ mHigher->mLower = this;
+ if (mHigher->mHigher == mHigher) mHigher->mHigher = this;
+ mLower->mHigher = this;
+ if (mLower->mLower == mLower) mLower->mLower = this;
+ }
+}
+
+// remove the struct from its linked lists
+void nsWindowInfo::Unlink(bool inAge, bool inZ) {
+ if (inAge) {
+ mOlder->mYounger = mYounger;
+ mYounger->mOlder = mOlder;
+ }
+ if (inZ) {
+ mLower->mHigher = mHigher;
+ mHigher->mLower = mLower;
+ }
+ ReferenceSelf(inAge, inZ);
+}
+
+// initialize the struct to be a valid linked list of one element
+void nsWindowInfo::ReferenceSelf(bool inAge, bool inZ) {
+ if (inAge) {
+ mYounger = this;
+ mOlder = this;
+ }
+ if (inZ) {
+ mLower = this;
+ mHigher = this;
+ }
+}
+
+//
+// nsAppShellWindowEnumerator
+//
+
+nsAppShellWindowEnumerator::nsAppShellWindowEnumerator(
+ const char16_t* aTypeString, nsWindowMediator& aMediator)
+ : mWindowMediator(&aMediator),
+ mType(aTypeString),
+ mCurrentPosition(nullptr) {
+ mWindowMediator->AddEnumerator(this);
+ NS_ADDREF(mWindowMediator);
+}
+
+nsAppShellWindowEnumerator::~nsAppShellWindowEnumerator() {
+ mWindowMediator->RemoveEnumerator(this);
+ NS_RELEASE(mWindowMediator);
+}
+
+// after mCurrentPosition has been initialized to point to the beginning
+// of the appropriate list, adjust it if necessary
+void nsAppShellWindowEnumerator::AdjustInitialPosition() {
+ if (!mType.IsEmpty() && mCurrentPosition &&
+ !mCurrentPosition->TypeEquals(mType))
+ mCurrentPosition = FindNext();
+}
+
+NS_IMETHODIMP nsAppShellWindowEnumerator::HasMoreElements(bool* retval) {
+ if (!retval) return NS_ERROR_INVALID_ARG;
+
+ *retval = mCurrentPosition ? true : false;
+ return NS_OK;
+}
+
+// if a window is being removed adjust the iterator's current position
+void nsAppShellWindowEnumerator::WindowRemoved(nsWindowInfo* inInfo) {
+ if (mCurrentPosition == inInfo) mCurrentPosition = FindNext();
+}
+
+//
+// nsASDOMWindowEnumerator
+//
+
+nsASDOMWindowEnumerator::nsASDOMWindowEnumerator(const char16_t* aTypeString,
+ nsWindowMediator& aMediator)
+ : nsAppShellWindowEnumerator(aTypeString, aMediator) {}
+
+nsASDOMWindowEnumerator::~nsASDOMWindowEnumerator() {}
+
+NS_IMETHODIMP nsASDOMWindowEnumerator::GetNext(nsISupports** retval) {
+ if (!retval) return NS_ERROR_INVALID_ARG;
+
+ *retval = nullptr;
+ while (mCurrentPosition) {
+ nsCOMPtr<nsPIDOMWindowOuter> domWindow;
+ nsWindowMediator::GetDOMWindow(mCurrentPosition->mWindow, domWindow);
+ mCurrentPosition = FindNext();
+ if (domWindow) return CallQueryInterface(domWindow, retval);
+ }
+ return NS_ERROR_FAILURE;
+}
+
+//
+// nsASAppWindowEnumerator
+//
+
+nsASAppWindowEnumerator::nsASAppWindowEnumerator(const char16_t* aTypeString,
+ nsWindowMediator& aMediator)
+ : nsAppShellWindowEnumerator(aTypeString, aMediator) {}
+
+nsASAppWindowEnumerator::~nsASAppWindowEnumerator() {}
+
+NS_IMETHODIMP nsASAppWindowEnumerator::GetNext(nsISupports** retval) {
+ if (!retval) return NS_ERROR_INVALID_ARG;
+
+ *retval = nullptr;
+ if (mCurrentPosition) {
+ CallQueryInterface(mCurrentPosition->mWindow, retval);
+ mCurrentPosition = FindNext();
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+//
+// nsASDOMWindowEarlyToLateEnumerator
+//
+
+nsASDOMWindowEarlyToLateEnumerator::nsASDOMWindowEarlyToLateEnumerator(
+ const char16_t* aTypeString, nsWindowMediator& aMediator)
+ : nsASDOMWindowEnumerator(aTypeString, aMediator) {
+ mCurrentPosition = aMediator.mOldestWindow;
+ AdjustInitialPosition();
+}
+
+nsASDOMWindowEarlyToLateEnumerator::~nsASDOMWindowEarlyToLateEnumerator() {}
+
+nsWindowInfo* nsASDOMWindowEarlyToLateEnumerator::FindNext() {
+ nsWindowInfo *info, *listEnd;
+ bool allWindows = mType.IsEmpty();
+
+ // see AppWindowEarlyToLateEnumerator::FindNext
+ if (!mCurrentPosition) return nullptr;
+
+ info = mCurrentPosition->mYounger;
+ listEnd = mWindowMediator->mOldestWindow;
+
+ while (info != listEnd) {
+ if (allWindows || info->TypeEquals(mType)) return info;
+ info = info->mYounger;
+ }
+
+ return nullptr;
+}
+
+//
+// nsASAppWindowEarlyToLateEnumerator
+//
+
+nsASAppWindowEarlyToLateEnumerator::nsASAppWindowEarlyToLateEnumerator(
+ const char16_t* aTypeString, nsWindowMediator& aMediator)
+ : nsASAppWindowEnumerator(aTypeString, aMediator) {
+ mCurrentPosition = aMediator.mOldestWindow;
+ AdjustInitialPosition();
+}
+
+nsASAppWindowEarlyToLateEnumerator::~nsASAppWindowEarlyToLateEnumerator() {}
+
+nsWindowInfo* nsASAppWindowEarlyToLateEnumerator::FindNext() {
+ nsWindowInfo *info, *listEnd;
+ bool allWindows = mType.IsEmpty();
+
+ /* mCurrentPosition null is assumed to mean that the enumerator has run
+ its course and is now basically useless. It could also be interpreted
+ to mean that it was created at a time when there were no windows. In
+ that case it would probably be more appropriate to check to see whether
+ windows have subsequently been added. But it's not guaranteed that we'll
+ pick up newly added windows anyway (if they occurred previous to our
+ current position) so we just don't worry about that. */
+ if (!mCurrentPosition) return nullptr;
+
+ info = mCurrentPosition->mYounger;
+ listEnd = mWindowMediator->mOldestWindow;
+
+ while (info != listEnd) {
+ if (allWindows || info->TypeEquals(mType)) return info;
+ info = info->mYounger;
+ }
+
+ return nullptr;
+}
+
+//
+// nsASAppWindowFrontToBackEnumerator
+//
+
+nsASAppWindowFrontToBackEnumerator::nsASAppWindowFrontToBackEnumerator(
+ const char16_t* aTypeString, nsWindowMediator& aMediator)
+ : nsASAppWindowEnumerator(aTypeString, aMediator) {
+ mCurrentPosition = aMediator.mTopmostWindow;
+ AdjustInitialPosition();
+}
+
+nsASAppWindowFrontToBackEnumerator::~nsASAppWindowFrontToBackEnumerator() {}
+
+nsWindowInfo* nsASAppWindowFrontToBackEnumerator::FindNext() {
+ nsWindowInfo *info, *listEnd;
+ bool allWindows = mType.IsEmpty();
+
+ // see AppWindowEarlyToLateEnumerator::FindNext
+ if (!mCurrentPosition) return nullptr;
+
+ info = mCurrentPosition->mLower;
+ listEnd = mWindowMediator->mTopmostWindow;
+
+ while (info != listEnd) {
+ if (allWindows || info->TypeEquals(mType)) return info;
+ info = info->mLower;
+ }
+
+ return nullptr;
+}
+
+//
+// nsASAppWindowBackToFrontEnumerator
+//
+
+nsASAppWindowBackToFrontEnumerator::nsASAppWindowBackToFrontEnumerator(
+ const char16_t* aTypeString, nsWindowMediator& aMediator)
+ : nsASAppWindowEnumerator(aTypeString, aMediator) {
+ mCurrentPosition =
+ aMediator.mTopmostWindow ? aMediator.mTopmostWindow->mHigher : nullptr;
+ AdjustInitialPosition();
+}
+
+nsASAppWindowBackToFrontEnumerator::~nsASAppWindowBackToFrontEnumerator() {}
+
+nsWindowInfo* nsASAppWindowBackToFrontEnumerator::FindNext() {
+ nsWindowInfo *info, *listEnd;
+ bool allWindows = mType.IsEmpty();
+
+ // see AppWindowEarlyToLateEnumerator::FindNext
+ if (!mCurrentPosition) return nullptr;
+
+ info = mCurrentPosition->mHigher;
+ listEnd = mWindowMediator->mTopmostWindow;
+ if (listEnd) listEnd = listEnd->mHigher;
+
+ while (info != listEnd) {
+ if (allWindows || info->TypeEquals(mType)) return info;
+ info = info->mHigher;
+ }
+
+ return nullptr;
+}