michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsAppShellWindowEnumerator.h" michael@0: michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsIFactory.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIXULWindow.h" michael@0: michael@0: #include "nsWindowMediator.h" michael@0: michael@0: // michael@0: // static helper functions michael@0: // michael@0: michael@0: static nsCOMPtr GetDOMNodeFromDocShell(nsIDocShell *aShell); michael@0: static void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute, michael@0: nsAString &outValue); michael@0: static void GetWindowType(nsIXULWindow* inWindow, nsString &outType); michael@0: michael@0: nsCOMPtr GetDOMNodeFromDocShell(nsIDocShell *aShell) michael@0: { michael@0: nsCOMPtr node; michael@0: michael@0: nsCOMPtr cv; michael@0: aShell->GetContentViewer(getter_AddRefs(cv)); michael@0: if (cv) { michael@0: nsCOMPtr domdoc(do_QueryInterface(cv->GetDocument())); michael@0: if (domdoc) { michael@0: nsCOMPtr element; michael@0: domdoc->GetDocumentElement(getter_AddRefs(element)); michael@0: if (element) michael@0: node = element; michael@0: } michael@0: } michael@0: michael@0: return node; michael@0: } michael@0: michael@0: // generic "retrieve the value of a XUL attribute" function michael@0: void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute, michael@0: nsAString &outValue) michael@0: { michael@0: nsCOMPtr shell; michael@0: if (inWindow && NS_SUCCEEDED(inWindow->GetDocShell(getter_AddRefs(shell)))) { michael@0: nsCOMPtr node(GetDOMNodeFromDocShell(shell)); michael@0: if (node) { michael@0: nsCOMPtr webshellElement(do_QueryInterface(node)); michael@0: if (webshellElement) michael@0: webshellElement->GetAttribute(inAttribute, outValue); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // retrieve the window type, stored as the value of a particular michael@0: // attribute in its XUL window tag michael@0: void GetWindowType(nsIXULWindow* aWindow, nsString &outType) michael@0: { michael@0: GetAttribute(aWindow, NS_LITERAL_STRING("windowtype"), outType); michael@0: } michael@0: michael@0: // michael@0: // nsWindowInfo michael@0: // michael@0: michael@0: nsWindowInfo::nsWindowInfo(nsIXULWindow* inWindow, int32_t inTimeStamp) : michael@0: mWindow(inWindow),mTimeStamp(inTimeStamp),mZLevel(nsIXULWindow::normalZ) michael@0: { michael@0: ReferenceSelf(true, true); michael@0: } michael@0: michael@0: nsWindowInfo::~nsWindowInfo() michael@0: { michael@0: } michael@0: michael@0: // return true if the window described by this WindowInfo has a type michael@0: // equal to the given type michael@0: bool nsWindowInfo::TypeEquals(const nsAString &aType) michael@0: { michael@0: nsAutoString rtnString; michael@0: GetWindowType(mWindow, rtnString); michael@0: return rtnString == aType; michael@0: } michael@0: michael@0: // insert the struct into their two linked lists, in position after the michael@0: // given (independent) method arguments michael@0: void nsWindowInfo::InsertAfter(nsWindowInfo *inOlder , nsWindowInfo *inHigher) michael@0: { michael@0: if (inOlder) { michael@0: mOlder = inOlder; michael@0: mYounger = inOlder->mYounger; michael@0: mOlder->mYounger = this; michael@0: if (mOlder->mOlder == mOlder) michael@0: mOlder->mOlder = this; michael@0: mYounger->mOlder = this; michael@0: if (mYounger->mYounger == mYounger) michael@0: mYounger->mYounger = this; michael@0: } michael@0: if (inHigher) { michael@0: mHigher = inHigher; michael@0: mLower = inHigher->mLower; michael@0: mHigher->mLower = this; michael@0: if (mHigher->mHigher == mHigher) michael@0: mHigher->mHigher = this; michael@0: mLower->mHigher = this; michael@0: if (mLower->mLower == mLower) michael@0: mLower->mLower = this; michael@0: } michael@0: } michael@0: michael@0: // remove the struct from its linked lists michael@0: void nsWindowInfo::Unlink(bool inAge, bool inZ) michael@0: { michael@0: if (inAge) { michael@0: mOlder->mYounger = mYounger; michael@0: mYounger->mOlder = mOlder; michael@0: } michael@0: if (inZ) { michael@0: mLower->mHigher = mHigher; michael@0: mHigher->mLower = mLower; michael@0: } michael@0: ReferenceSelf(inAge, inZ); michael@0: } michael@0: michael@0: // initialize the struct to be a valid linked list of one element michael@0: void nsWindowInfo::ReferenceSelf(bool inAge, bool inZ) michael@0: { michael@0: if (inAge) { michael@0: mYounger = this; michael@0: mOlder = this; michael@0: } michael@0: if (inZ) { michael@0: mLower = this; michael@0: mHigher = this; michael@0: } michael@0: } michael@0: michael@0: // michael@0: // nsAppShellWindowEnumerator michael@0: // michael@0: michael@0: NS_IMPL_ISUPPORTS(nsAppShellWindowEnumerator, nsISimpleEnumerator) michael@0: michael@0: nsAppShellWindowEnumerator::nsAppShellWindowEnumerator( michael@0: const char16_t* aTypeString, michael@0: nsWindowMediator& aMediator) : michael@0: mWindowMediator(&aMediator), mType(aTypeString), mCurrentPosition(nullptr) michael@0: { michael@0: mWindowMediator->AddEnumerator(this); michael@0: NS_ADDREF(mWindowMediator); michael@0: } michael@0: michael@0: nsAppShellWindowEnumerator::~nsAppShellWindowEnumerator() michael@0: { michael@0: mWindowMediator->RemoveEnumerator(this); michael@0: NS_RELEASE(mWindowMediator); michael@0: } michael@0: michael@0: // after mCurrentPosition has been initialized to point to the beginning michael@0: // of the appropriate list, adjust it if necessary michael@0: void nsAppShellWindowEnumerator::AdjustInitialPosition() michael@0: { michael@0: if (!mType.IsEmpty() && mCurrentPosition && !mCurrentPosition->TypeEquals(mType)) michael@0: mCurrentPosition = FindNext(); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsAppShellWindowEnumerator::HasMoreElements(bool *retval) michael@0: { michael@0: if (!retval) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *retval = mCurrentPosition ? true : false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // if a window is being removed adjust the iterator's current position michael@0: void nsAppShellWindowEnumerator::WindowRemoved(nsWindowInfo *inInfo) michael@0: { michael@0: if (mCurrentPosition == inInfo) michael@0: mCurrentPosition = FindNext(); michael@0: } michael@0: michael@0: // michael@0: // nsASDOMWindowEnumerator michael@0: // michael@0: michael@0: nsASDOMWindowEnumerator::nsASDOMWindowEnumerator( michael@0: const char16_t* aTypeString, michael@0: nsWindowMediator& aMediator) : michael@0: nsAppShellWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: } michael@0: michael@0: nsASDOMWindowEnumerator::~nsASDOMWindowEnumerator() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP nsASDOMWindowEnumerator::GetNext(nsISupports **retval) michael@0: { michael@0: if (!retval) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *retval = nullptr; michael@0: while (mCurrentPosition) { michael@0: nsCOMPtr domWindow; michael@0: nsWindowMediator::GetDOMWindow(mCurrentPosition->mWindow, domWindow); michael@0: mCurrentPosition = FindNext(); michael@0: if (domWindow) michael@0: return CallQueryInterface(domWindow, retval); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // nsASXULWindowEnumerator michael@0: // michael@0: michael@0: nsASXULWindowEnumerator::nsASXULWindowEnumerator( michael@0: const char16_t* aTypeString, michael@0: nsWindowMediator& aMediator) : michael@0: nsAppShellWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: } michael@0: michael@0: nsASXULWindowEnumerator::~nsASXULWindowEnumerator() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP nsASXULWindowEnumerator::GetNext(nsISupports **retval) michael@0: { michael@0: if (!retval) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *retval = nullptr; michael@0: if (mCurrentPosition) { michael@0: CallQueryInterface(mCurrentPosition->mWindow, retval); michael@0: mCurrentPosition = FindNext(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // nsASDOMWindowEarlyToLateEnumerator michael@0: // michael@0: michael@0: nsASDOMWindowEarlyToLateEnumerator::nsASDOMWindowEarlyToLateEnumerator( michael@0: const char16_t *aTypeString, michael@0: nsWindowMediator &aMediator) : michael@0: nsASDOMWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: mCurrentPosition = aMediator.mOldestWindow; michael@0: AdjustInitialPosition(); michael@0: } michael@0: michael@0: nsASDOMWindowEarlyToLateEnumerator::~nsASDOMWindowEarlyToLateEnumerator() michael@0: { michael@0: } michael@0: michael@0: nsWindowInfo *nsASDOMWindowEarlyToLateEnumerator::FindNext() michael@0: { michael@0: nsWindowInfo *info, michael@0: *listEnd; michael@0: bool allWindows = mType.IsEmpty(); michael@0: michael@0: // see nsXULWindowEarlyToLateEnumerator::FindNext michael@0: if (!mCurrentPosition) michael@0: return nullptr; michael@0: michael@0: info = mCurrentPosition->mYounger; michael@0: listEnd = mWindowMediator->mOldestWindow; michael@0: michael@0: while (info != listEnd) { michael@0: if (allWindows || info->TypeEquals(mType)) michael@0: return info; michael@0: info = info->mYounger; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // michael@0: // nsASXULWindowEarlyToLateEnumerator michael@0: // michael@0: michael@0: nsASXULWindowEarlyToLateEnumerator::nsASXULWindowEarlyToLateEnumerator( michael@0: const char16_t *aTypeString, michael@0: nsWindowMediator &aMediator) : michael@0: nsASXULWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: mCurrentPosition = aMediator.mOldestWindow; michael@0: AdjustInitialPosition(); michael@0: } michael@0: michael@0: nsASXULWindowEarlyToLateEnumerator::~nsASXULWindowEarlyToLateEnumerator() michael@0: { michael@0: } michael@0: michael@0: nsWindowInfo *nsASXULWindowEarlyToLateEnumerator::FindNext() michael@0: { michael@0: nsWindowInfo *info, michael@0: *listEnd; michael@0: bool allWindows = mType.IsEmpty(); michael@0: michael@0: /* mCurrentPosition null is assumed to mean that the enumerator has run michael@0: its course and is now basically useless. It could also be interpreted michael@0: to mean that it was created at a time when there were no windows. In michael@0: that case it would probably be more appropriate to check to see whether michael@0: windows have subsequently been added. But it's not guaranteed that we'll michael@0: pick up newly added windows anyway (if they occurred previous to our michael@0: current position) so we just don't worry about that. */ michael@0: if (!mCurrentPosition) michael@0: return nullptr; michael@0: michael@0: info = mCurrentPosition->mYounger; michael@0: listEnd = mWindowMediator->mOldestWindow; michael@0: michael@0: while (info != listEnd) { michael@0: if (allWindows || info->TypeEquals(mType)) michael@0: return info; michael@0: info = info->mYounger; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // michael@0: // nsASDOMWindowFrontToBackEnumerator michael@0: // michael@0: michael@0: nsASDOMWindowFrontToBackEnumerator::nsASDOMWindowFrontToBackEnumerator( michael@0: const char16_t *aTypeString, michael@0: nsWindowMediator &aMediator) : michael@0: nsASDOMWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: mCurrentPosition = aMediator.mTopmostWindow; michael@0: AdjustInitialPosition(); michael@0: } michael@0: michael@0: nsASDOMWindowFrontToBackEnumerator::~nsASDOMWindowFrontToBackEnumerator() michael@0: { michael@0: } michael@0: michael@0: nsWindowInfo *nsASDOMWindowFrontToBackEnumerator::FindNext() michael@0: { michael@0: nsWindowInfo *info, michael@0: *listEnd; michael@0: bool allWindows = mType.IsEmpty(); michael@0: michael@0: // see nsXULWindowEarlyToLateEnumerator::FindNext michael@0: if (!mCurrentPosition) michael@0: return nullptr; michael@0: michael@0: info = mCurrentPosition->mLower; michael@0: listEnd = mWindowMediator->mTopmostWindow; michael@0: michael@0: while (info != listEnd) { michael@0: if (allWindows || info->TypeEquals(mType)) michael@0: return info; michael@0: info = info->mLower; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // michael@0: // nsASXULWindowFrontToBackEnumerator michael@0: // michael@0: michael@0: nsASXULWindowFrontToBackEnumerator::nsASXULWindowFrontToBackEnumerator( michael@0: const char16_t *aTypeString, michael@0: nsWindowMediator &aMediator) : michael@0: nsASXULWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: mCurrentPosition = aMediator.mTopmostWindow; michael@0: AdjustInitialPosition(); michael@0: } michael@0: michael@0: nsASXULWindowFrontToBackEnumerator::~nsASXULWindowFrontToBackEnumerator() michael@0: { michael@0: } michael@0: michael@0: nsWindowInfo *nsASXULWindowFrontToBackEnumerator::FindNext() michael@0: { michael@0: nsWindowInfo *info, michael@0: *listEnd; michael@0: bool allWindows = mType.IsEmpty(); michael@0: michael@0: // see nsXULWindowEarlyToLateEnumerator::FindNext michael@0: if (!mCurrentPosition) michael@0: return nullptr; michael@0: michael@0: info = mCurrentPosition->mLower; michael@0: listEnd = mWindowMediator->mTopmostWindow; michael@0: michael@0: while (info != listEnd) { michael@0: if (allWindows || info->TypeEquals(mType)) michael@0: return info; michael@0: info = info->mLower; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // michael@0: // nsASDOMWindowBackToFrontEnumerator michael@0: // michael@0: michael@0: nsASDOMWindowBackToFrontEnumerator::nsASDOMWindowBackToFrontEnumerator( michael@0: const char16_t *aTypeString, michael@0: nsWindowMediator &aMediator) : michael@0: nsASDOMWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: mCurrentPosition = aMediator.mTopmostWindow ? michael@0: aMediator.mTopmostWindow->mHigher : nullptr; michael@0: AdjustInitialPosition(); michael@0: } michael@0: michael@0: nsASDOMWindowBackToFrontEnumerator::~nsASDOMWindowBackToFrontEnumerator() michael@0: { michael@0: } michael@0: michael@0: nsWindowInfo *nsASDOMWindowBackToFrontEnumerator::FindNext() michael@0: { michael@0: nsWindowInfo *info, michael@0: *listEnd; michael@0: bool allWindows = mType.IsEmpty(); michael@0: michael@0: // see nsXULWindowEarlyToLateEnumerator::FindNext michael@0: if (!mCurrentPosition) michael@0: return nullptr; michael@0: michael@0: info = mCurrentPosition->mHigher; michael@0: listEnd = mWindowMediator->mTopmostWindow; michael@0: if (listEnd) michael@0: listEnd = listEnd->mHigher; michael@0: michael@0: while (info != listEnd) { michael@0: if (allWindows || info->TypeEquals(mType)) michael@0: return info; michael@0: info = info->mHigher; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // michael@0: // nsASXULWindowBackToFrontEnumerator michael@0: // michael@0: michael@0: nsASXULWindowBackToFrontEnumerator::nsASXULWindowBackToFrontEnumerator( michael@0: const char16_t *aTypeString, michael@0: nsWindowMediator &aMediator) : michael@0: nsASXULWindowEnumerator(aTypeString, aMediator) michael@0: { michael@0: mCurrentPosition = aMediator.mTopmostWindow ? michael@0: aMediator.mTopmostWindow->mHigher : nullptr; michael@0: AdjustInitialPosition(); michael@0: } michael@0: michael@0: nsASXULWindowBackToFrontEnumerator::~nsASXULWindowBackToFrontEnumerator() michael@0: { michael@0: } michael@0: michael@0: nsWindowInfo *nsASXULWindowBackToFrontEnumerator::FindNext() michael@0: { michael@0: nsWindowInfo *info, michael@0: *listEnd; michael@0: bool allWindows = mType.IsEmpty(); michael@0: michael@0: // see nsXULWindowEarlyToLateEnumerator::FindNext michael@0: if (!mCurrentPosition) michael@0: return nullptr; michael@0: michael@0: info = mCurrentPosition->mHigher; michael@0: listEnd = mWindowMediator->mTopmostWindow; michael@0: if (listEnd) michael@0: listEnd = listEnd->mHigher; michael@0: michael@0: while (info != listEnd) { michael@0: if (allWindows || info->TypeEquals(mType)) michael@0: return info; michael@0: info = info->mHigher; michael@0: } michael@0: michael@0: return nullptr; michael@0: }