mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-25 19:25:43 +00:00
94617f91cf
Backed out changeset 499f6dffd9cb (bug 1434399) Backed out changeset 018290612415 (bug 1434399) Backed out changeset f4c3179f8e59 (bug 1434399) Backed out changeset f3ce2826b857 (bug 1434399) Backed out changeset 6d2391af01dd (bug 1434399) Backed out changeset dc98ed8c609a (bug 1434399) Backed out changeset 8eaa395d6200 (bug 1434399) Backed out changeset 19b18f4a53be (bug 1434399) Backed out changeset 8ff378a6e96a (bug 1434399) Backed out changeset 60fe73be1a26 (bug 1434399) Backed out changeset faefb2751fdc (bug 1434399) Backed out changeset 55cdf8b3a959 (bug 1434399) Backed out changeset b578cc8efb92 (bug 1434399) Backed out changeset 54cc4cb2fca1 (bug 1434399) Backed out changeset f5343ef34d6c (bug 1434399) Backed out changeset 8fb30e066cbd (bug 1434399) Backed out changeset 21341b656b0f (bug 1434399) Backed out changeset fab1f8b087a2 (bug 1434399) Backed out changeset 55250a54852a (bug 1434399)
439 lines
14 KiB
C++
439 lines
14 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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 "mozilla/BasicEvents.h"
|
|
#include "mozilla/EventDispatcher.h"
|
|
#include "mozilla/EventListenerManager.h"
|
|
#include "mozilla/dom/WindowRootBinding.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsWindowRoot.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsLayoutCID.h"
|
|
#include "nsContentCID.h"
|
|
#include "nsString.h"
|
|
#include "nsGlobalWindow.h"
|
|
#include "nsFocusManager.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
#include "nsIControllers.h"
|
|
#include "nsIController.h"
|
|
#include "xpcpublic.h"
|
|
#include "nsCycleCollectionParticipant.h"
|
|
#include "mozilla/dom/TabParent.h"
|
|
#include "mozilla/dom/HTMLTextAreaElement.h"
|
|
|
|
#ifdef MOZ_XUL
|
|
#include "nsXULElement.h"
|
|
#endif
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
nsWindowRoot::nsWindowRoot(nsPIDOMWindowOuter* aWindow)
|
|
{
|
|
mWindow = aWindow;
|
|
|
|
// Keyboard indicators are not shown on Mac by default.
|
|
#if defined(XP_MACOSX)
|
|
mShowAccelerators = false;
|
|
mShowFocusRings = false;
|
|
#else
|
|
mShowAccelerators = true;
|
|
mShowFocusRings = true;
|
|
#endif
|
|
}
|
|
|
|
nsWindowRoot::~nsWindowRoot()
|
|
{
|
|
if (mListenerManager) {
|
|
mListenerManager->Disconnect();
|
|
}
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsWindowRoot,
|
|
mWindow,
|
|
mListenerManager,
|
|
mParent)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
|
|
NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
|
NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot)
|
|
|
|
NS_IMPL_DOMTARGET_DEFAULTS(nsWindowRoot)
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture)
|
|
{
|
|
if (RefPtr<EventListenerManager> elm = GetExistingListenerManager()) {
|
|
elm->RemoveEventListener(aType, aListener, aUseCapture);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsWindowRoot)
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, bool *aRetVal)
|
|
{
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsresult rv = EventDispatcher::DispatchDOMEvent(
|
|
static_cast<EventTarget*>(this), nullptr, aEvt, nullptr, &status);
|
|
*aRetVal = (status != nsEventStatus_eConsumeNoDefault);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowRoot::AddEventListener(const nsAString& aType,
|
|
nsIDOMEventListener *aListener,
|
|
bool aUseCapture, bool aWantsUntrusted,
|
|
uint8_t aOptionalArgc)
|
|
{
|
|
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
|
|
"Won't check if this is chrome, you want to set "
|
|
"aWantsUntrusted to false or make the aWantsUntrusted "
|
|
"explicit by making optional_argc non-zero.");
|
|
|
|
EventListenerManager* elm = GetOrCreateListenerManager();
|
|
NS_ENSURE_STATE(elm);
|
|
elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsWindowRoot::AddEventListener(const nsAString& aType,
|
|
EventListener* aListener,
|
|
const AddEventListenerOptionsOrBoolean& aOptions,
|
|
const Nullable<bool>& aWantsUntrusted,
|
|
ErrorResult& aRv)
|
|
{
|
|
bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value();
|
|
EventListenerManager* elm = GetOrCreateListenerManager();
|
|
if (!elm) {
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
|
return;
|
|
}
|
|
elm->AddEventListener(aType, aListener, aOptions, wantsUntrusted);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowRoot::AddSystemEventListener(const nsAString& aType,
|
|
nsIDOMEventListener *aListener,
|
|
bool aUseCapture,
|
|
bool aWantsUntrusted,
|
|
uint8_t aOptionalArgc)
|
|
{
|
|
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
|
|
"Won't check if this is chrome, you want to set "
|
|
"aWantsUntrusted to false or make the aWantsUntrusted "
|
|
"explicit by making optional_argc non-zero.");
|
|
|
|
return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
|
|
aWantsUntrusted);
|
|
}
|
|
|
|
EventListenerManager*
|
|
nsWindowRoot::GetOrCreateListenerManager()
|
|
{
|
|
if (!mListenerManager) {
|
|
mListenerManager =
|
|
new EventListenerManager(static_cast<EventTarget*>(this));
|
|
}
|
|
|
|
return mListenerManager;
|
|
}
|
|
|
|
EventListenerManager*
|
|
nsWindowRoot::GetExistingListenerManager() const
|
|
{
|
|
return mListenerManager;
|
|
}
|
|
|
|
nsIScriptContext*
|
|
nsWindowRoot::GetContextForEventHandlers(nsresult* aRv)
|
|
{
|
|
*aRv = NS_OK;
|
|
return nullptr;
|
|
}
|
|
|
|
nsresult
|
|
nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
|
{
|
|
aVisitor.mCanHandle = true;
|
|
aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
|
|
// To keep mWindow alive
|
|
aVisitor.mItemData = static_cast<nsISupports *>(mWindow);
|
|
aVisitor.SetParentTarget(mParent, false);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
nsPIDOMWindowOuter*
|
|
nsWindowRoot::GetOwnerGlobalForBindings()
|
|
{
|
|
return GetWindow();
|
|
}
|
|
|
|
nsIGlobalObject*
|
|
nsWindowRoot::GetOwnerGlobal() const
|
|
{
|
|
nsCOMPtr<nsIGlobalObject> global =
|
|
do_QueryInterface(mWindow->GetCurrentInnerWindow());
|
|
// We're still holding a ref to it, so returning the raw pointer is ok...
|
|
return global;
|
|
}
|
|
|
|
nsPIDOMWindowOuter*
|
|
nsWindowRoot::GetWindow()
|
|
{
|
|
return mWindow;
|
|
}
|
|
|
|
nsresult
|
|
nsWindowRoot::GetControllers(bool aForVisibleWindow,
|
|
nsIControllers** aResult)
|
|
{
|
|
*aResult = nullptr;
|
|
|
|
// XXX: we should fix this so there's a generic interface that
|
|
// describes controllers, so this code would have no special
|
|
// knowledge of what object might have controllers.
|
|
|
|
nsFocusManager::SearchRange searchRange =
|
|
aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants :
|
|
nsFocusManager::eIncludeAllDescendants;
|
|
nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
|
|
nsIContent* focusedContent =
|
|
nsFocusManager::GetFocusedDescendant(mWindow, searchRange,
|
|
getter_AddRefs(focusedWindow));
|
|
if (focusedContent) {
|
|
#ifdef MOZ_XUL
|
|
RefPtr<nsXULElement> xulElement = nsXULElement::FromContent(focusedContent);
|
|
if (xulElement) {
|
|
ErrorResult rv;
|
|
*aResult = xulElement->GetControllers(rv);
|
|
NS_IF_ADDREF(*aResult);
|
|
return rv.StealNSResult();
|
|
}
|
|
#endif
|
|
|
|
HTMLTextAreaElement* htmlTextArea =
|
|
HTMLTextAreaElement::FromContent(focusedContent);
|
|
if (htmlTextArea)
|
|
return htmlTextArea->GetControllers(aResult);
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> htmlInputElement =
|
|
do_QueryInterface(focusedContent);
|
|
if (htmlInputElement)
|
|
return htmlInputElement->GetControllers(aResult);
|
|
|
|
if (focusedContent->IsEditable() && focusedWindow)
|
|
return focusedWindow->GetControllers(aResult);
|
|
}
|
|
else {
|
|
return focusedWindow->GetControllers(aResult);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsWindowRoot::GetControllerForCommand(const char* aCommand,
|
|
bool aForVisibleWindow,
|
|
nsIController** _retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
*_retval = nullptr;
|
|
|
|
{
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
GetControllers(aForVisibleWindow, getter_AddRefs(controllers));
|
|
if (controllers) {
|
|
nsCOMPtr<nsIController> controller;
|
|
controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
|
|
if (controller) {
|
|
controller.forget(_retval);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
nsFocusManager::SearchRange searchRange =
|
|
aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants :
|
|
nsFocusManager::eIncludeAllDescendants;
|
|
nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
|
|
nsFocusManager::GetFocusedDescendant(mWindow, searchRange,
|
|
getter_AddRefs(focusedWindow));
|
|
while (focusedWindow) {
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
focusedWindow->GetControllers(getter_AddRefs(controllers));
|
|
if (controllers) {
|
|
nsCOMPtr<nsIController> controller;
|
|
controllers->GetControllerForCommand(aCommand,
|
|
getter_AddRefs(controller));
|
|
if (controller) {
|
|
controller.forget(_retval);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
// XXXndeakin P3 is this casting safe?
|
|
nsGlobalWindowOuter *win = nsGlobalWindowOuter::Cast(focusedWindow);
|
|
focusedWindow = win->GetPrivateParent();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsWindowRoot::GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers,
|
|
nsTHashtable<nsCharPtrHashKey>& aCommandsHandled,
|
|
nsTArray<nsCString>& aEnabledCommands,
|
|
nsTArray<nsCString>& aDisabledCommands)
|
|
{
|
|
uint32_t controllerCount;
|
|
aControllers->GetControllerCount(&controllerCount);
|
|
for (uint32_t c = 0; c < controllerCount; c++) {
|
|
nsCOMPtr<nsIController> controller;
|
|
aControllers->GetControllerAt(c, getter_AddRefs(controller));
|
|
|
|
nsCOMPtr<nsICommandController> commandController(do_QueryInterface(controller));
|
|
if (commandController) {
|
|
uint32_t commandsCount;
|
|
char** commands;
|
|
if (NS_SUCCEEDED(commandController->GetSupportedCommands(&commandsCount, &commands))) {
|
|
for (uint32_t e = 0; e < commandsCount; e++) {
|
|
// Use a hash to determine which commands have already been handled by
|
|
// earlier controllers, as the earlier controller's result should get
|
|
// priority.
|
|
if (aCommandsHandled.EnsureInserted(commands[e])) {
|
|
// We inserted a new entry into aCommandsHandled.
|
|
bool enabled = false;
|
|
controller->IsCommandEnabled(commands[e], &enabled);
|
|
|
|
const nsDependentCSubstring commandStr(commands[e], strlen(commands[e]));
|
|
if (enabled) {
|
|
aEnabledCommands.AppendElement(commandStr);
|
|
} else {
|
|
aDisabledCommands.AppendElement(commandStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(commandsCount, commands);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsWindowRoot::GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands,
|
|
nsTArray<nsCString>& aDisabledCommands)
|
|
{
|
|
nsTHashtable<nsCharPtrHashKey> commandsHandled;
|
|
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
GetControllers(false, getter_AddRefs(controllers));
|
|
if (controllers) {
|
|
GetEnabledDisabledCommandsForControllers(controllers, commandsHandled,
|
|
aEnabledCommands, aDisabledCommands);
|
|
}
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
|
|
nsFocusManager::GetFocusedDescendant(mWindow,
|
|
nsFocusManager::eIncludeAllDescendants,
|
|
getter_AddRefs(focusedWindow));
|
|
while (focusedWindow) {
|
|
focusedWindow->GetControllers(getter_AddRefs(controllers));
|
|
if (controllers) {
|
|
GetEnabledDisabledCommandsForControllers(controllers, commandsHandled,
|
|
aEnabledCommands, aDisabledCommands);
|
|
}
|
|
|
|
nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
|
|
focusedWindow = win->GetPrivateParent();
|
|
}
|
|
}
|
|
|
|
already_AddRefed<nsINode>
|
|
nsWindowRoot::GetPopupNode()
|
|
{
|
|
nsCOMPtr<nsINode> popupNode = do_QueryReferent(mPopupNode);
|
|
return popupNode.forget();
|
|
}
|
|
|
|
void
|
|
nsWindowRoot::SetPopupNode(nsINode* aNode)
|
|
{
|
|
mPopupNode = do_GetWeakReference(aNode);
|
|
}
|
|
|
|
nsIGlobalObject*
|
|
nsWindowRoot::GetParentObject()
|
|
{
|
|
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
|
}
|
|
|
|
JSObject*
|
|
nsWindowRoot::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
return mozilla::dom::WindowRootBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
void
|
|
nsWindowRoot::AddBrowser(mozilla::dom::TabParent* aBrowser)
|
|
{
|
|
nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(aBrowser));
|
|
mWeakBrowsers.PutEntry(weakBrowser);
|
|
}
|
|
|
|
void
|
|
nsWindowRoot::RemoveBrowser(mozilla::dom::TabParent* aBrowser)
|
|
{
|
|
nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(aBrowser));
|
|
mWeakBrowsers.RemoveEntry(weakBrowser);
|
|
}
|
|
|
|
void
|
|
nsWindowRoot::EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg)
|
|
{
|
|
// Collect strong references to all browsers in a separate array in
|
|
// case aEnumFunc alters mWeakBrowsers.
|
|
nsTArray<RefPtr<TabParent>> tabParents;
|
|
for (auto iter = mWeakBrowsers.ConstIter(); !iter.Done(); iter.Next()) {
|
|
nsCOMPtr<nsITabParent> tabParent(do_QueryReferent(iter.Get()->GetKey()));
|
|
if (TabParent* tab = TabParent::GetFrom(tabParent)) {
|
|
tabParents.AppendElement(tab);
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < tabParents.Length(); ++i) {
|
|
aEnumFunc(tabParents[i], aArg);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
already_AddRefed<EventTarget>
|
|
NS_NewWindowRoot(nsPIDOMWindowOuter* aWindow)
|
|
{
|
|
nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
|
|
return result.forget();
|
|
}
|