mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			340 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- 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;
 | 
						|
}
 |