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 "mozilla/BasicEvents.h" michael@0: #include "mozilla/EventDispatcher.h" michael@0: #include "mozilla/EventListenerManager.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsWindowRoot.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsLayoutCID.h" michael@0: #include "nsContentCID.h" michael@0: #include "nsString.h" michael@0: #include "nsGlobalWindow.h" michael@0: #include "nsFocusManager.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIDOMHTMLInputElement.h" michael@0: #include "nsIDOMHTMLTextAreaElement.h" michael@0: #include "nsIControllers.h" michael@0: #include "nsIController.h" michael@0: michael@0: #include "nsCycleCollectionParticipant.h" michael@0: michael@0: #ifdef MOZ_XUL michael@0: #include "nsIDOMXULElement.h" michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: nsWindowRoot::nsWindowRoot(nsPIDOMWindow* aWindow) michael@0: { michael@0: mWindow = aWindow; michael@0: } michael@0: michael@0: nsWindowRoot::~nsWindowRoot() michael@0: { michael@0: if (mListenerManager) { michael@0: mListenerManager->Disconnect(); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(nsWindowRoot, michael@0: mWindow, michael@0: mListenerManager, michael@0: mPopupNode, michael@0: mParent) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot) michael@0: NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget) michael@0: NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) michael@0: NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot) michael@0: michael@0: NS_IMPL_DOMTARGET_DEFAULTS(nsWindowRoot) michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture) michael@0: { michael@0: if (nsRefPtr elm = GetExistingListenerManager()) { michael@0: elm->RemoveEventListener(aType, aListener, aUseCapture); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsWindowRoot) michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, bool *aRetVal) michael@0: { michael@0: nsEventStatus status = nsEventStatus_eIgnore; michael@0: nsresult rv = EventDispatcher::DispatchDOMEvent( michael@0: static_cast(this), nullptr, aEvt, nullptr, &status); michael@0: *aRetVal = (status != nsEventStatus_eConsumeNoDefault); michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindowRoot::DispatchDOMEvent(WidgetEvent* aEvent, michael@0: nsIDOMEvent* aDOMEvent, michael@0: nsPresContext* aPresContext, michael@0: nsEventStatus* aEventStatus) michael@0: { michael@0: return EventDispatcher::DispatchDOMEvent(static_cast(this), michael@0: aEvent, aDOMEvent, michael@0: aPresContext, aEventStatus); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowRoot::AddEventListener(const nsAString& aType, michael@0: nsIDOMEventListener *aListener, michael@0: bool aUseCapture, bool aWantsUntrusted, michael@0: uint8_t aOptionalArgc) michael@0: { michael@0: NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, michael@0: "Won't check if this is chrome, you want to set " michael@0: "aWantsUntrusted to false or make the aWantsUntrusted " michael@0: "explicit by making optional_argc non-zero."); michael@0: michael@0: EventListenerManager* elm = GetOrCreateListenerManager(); michael@0: NS_ENSURE_STATE(elm); michael@0: elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsWindowRoot::AddEventListener(const nsAString& aType, michael@0: EventListener* aListener, michael@0: bool aUseCapture, michael@0: const Nullable& aWantsUntrusted, michael@0: ErrorResult& aRv) michael@0: { michael@0: bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value(); michael@0: EventListenerManager* elm = GetOrCreateListenerManager(); michael@0: if (!elm) { michael@0: aRv.Throw(NS_ERROR_UNEXPECTED); michael@0: return; michael@0: } michael@0: elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindowRoot::AddSystemEventListener(const nsAString& aType, michael@0: nsIDOMEventListener *aListener, michael@0: bool aUseCapture, michael@0: bool aWantsUntrusted, michael@0: uint8_t aOptionalArgc) michael@0: { michael@0: NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, michael@0: "Won't check if this is chrome, you want to set " michael@0: "aWantsUntrusted to false or make the aWantsUntrusted " michael@0: "explicit by making optional_argc non-zero."); michael@0: michael@0: return NS_AddSystemEventListener(this, aType, aListener, aUseCapture, michael@0: aWantsUntrusted); michael@0: } michael@0: michael@0: EventListenerManager* michael@0: nsWindowRoot::GetOrCreateListenerManager() michael@0: { michael@0: if (!mListenerManager) { michael@0: mListenerManager = michael@0: new EventListenerManager(static_cast(this)); michael@0: } michael@0: michael@0: return mListenerManager; michael@0: } michael@0: michael@0: EventListenerManager* michael@0: nsWindowRoot::GetExistingListenerManager() const michael@0: { michael@0: return mListenerManager; michael@0: } michael@0: michael@0: nsIScriptContext* michael@0: nsWindowRoot::GetContextForEventHandlers(nsresult* aRv) michael@0: { michael@0: *aRv = NS_OK; michael@0: return nullptr; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindowRoot::PreHandleEvent(EventChainPreVisitor& aVisitor) michael@0: { michael@0: aVisitor.mCanHandle = true; michael@0: aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119 michael@0: // To keep mWindow alive michael@0: aVisitor.mItemData = static_cast(mWindow); michael@0: aVisitor.mParentTarget = mParent; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIDOMWindow* michael@0: nsWindowRoot::GetOwnerGlobal() michael@0: { michael@0: return GetWindow(); michael@0: } michael@0: michael@0: nsPIDOMWindow* michael@0: nsWindowRoot::GetWindow() michael@0: { michael@0: return mWindow; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindowRoot::GetControllers(nsIControllers** aResult) michael@0: { michael@0: *aResult = nullptr; michael@0: michael@0: // XXX: we should fix this so there's a generic interface that michael@0: // describes controllers, so this code would have no special michael@0: // knowledge of what object might have controllers. michael@0: michael@0: nsCOMPtr focusedWindow; michael@0: nsIContent* focusedContent = michael@0: nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow)); michael@0: if (focusedContent) { michael@0: #ifdef MOZ_XUL michael@0: nsCOMPtr xulElement(do_QueryInterface(focusedContent)); michael@0: if (xulElement) michael@0: return xulElement->GetControllers(aResult); michael@0: #endif michael@0: michael@0: nsCOMPtr htmlTextArea = michael@0: do_QueryInterface(focusedContent); michael@0: if (htmlTextArea) michael@0: return htmlTextArea->GetControllers(aResult); michael@0: michael@0: nsCOMPtr htmlInputElement = michael@0: do_QueryInterface(focusedContent); michael@0: if (htmlInputElement) michael@0: return htmlInputElement->GetControllers(aResult); michael@0: michael@0: if (focusedContent->IsEditable() && focusedWindow) michael@0: return focusedWindow->GetControllers(aResult); michael@0: } michael@0: else { michael@0: nsCOMPtr domWindow = do_QueryInterface(focusedWindow); michael@0: if (domWindow) michael@0: return domWindow->GetControllers(aResult); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindowRoot::GetControllerForCommand(const char * aCommand, michael@0: nsIController** _retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = nullptr; michael@0: michael@0: { michael@0: nsCOMPtr controllers; michael@0: GetControllers(getter_AddRefs(controllers)); michael@0: if (controllers) { michael@0: nsCOMPtr controller; michael@0: controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller)); michael@0: if (controller) { michael@0: controller.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr focusedWindow; michael@0: nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow)); michael@0: while (focusedWindow) { michael@0: nsCOMPtr controllers; michael@0: focusedWindow->GetControllers(getter_AddRefs(controllers)); michael@0: if (controllers) { michael@0: nsCOMPtr controller; michael@0: controllers->GetControllerForCommand(aCommand, michael@0: getter_AddRefs(controller)); michael@0: if (controller) { michael@0: controller.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // XXXndeakin P3 is this casting safe? michael@0: nsGlobalWindow *win = static_cast(focusedWindow.get()); michael@0: focusedWindow = win->GetPrivateParent(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIDOMNode* michael@0: nsWindowRoot::GetPopupNode() michael@0: { michael@0: return mPopupNode; michael@0: } michael@0: michael@0: void michael@0: nsWindowRoot::SetPopupNode(nsIDOMNode* aNode) michael@0: { michael@0: mPopupNode = aNode; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: already_AddRefed michael@0: NS_NewWindowRoot(nsPIDOMWindow* aWindow) michael@0: { michael@0: nsCOMPtr result = new nsWindowRoot(aWindow); michael@0: return result.forget(); michael@0: }