/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Mozilla browser. * * The Initial Developer of the Original Code is * Netscape Communications, Inc. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * David W. Hyatt (Original Author) * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" #include "nsWindowRoot.h" #include "nsIDOMWindow.h" #include "nsIDOMDocument.h" #include "nsIDocument.h" #include "nsIEventListenerManager.h" #include "nsIPresShell.h" #include "nsPresContext.h" #include "nsLayoutCID.h" #include "nsContentCID.h" #include "nsIEventStateManager.h" #include "nsIPrivateDOMEvent.h" #include "nsIDOMWindowInternal.h" #include "nsFocusController.h" #include "nsString.h" #include "nsDOMClassInfo.h" static NS_DEFINE_CID(kEventListenerManagerCID, NS_EVENTLISTENERMANAGER_CID); nsWindowRoot::nsWindowRoot(nsIDOMWindow* aWindow) { mWindow = aWindow; // Create and init our focus controller. nsFocusController::Create(getter_AddRefs(mFocusController)); nsCOMPtr focusListener(do_QueryInterface(mFocusController)); ++mRefCnt; AddEventListener(NS_LITERAL_STRING("focus"), focusListener, PR_TRUE); AddEventListener(NS_LITERAL_STRING("blur"), focusListener, PR_TRUE); --mRefCnt; } nsWindowRoot::~nsWindowRoot() { if (mListenerManager) { mListenerManager->Disconnect(); } } NS_INTERFACE_MAP_BEGIN(nsWindowRoot) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventReceiver) NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver) NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant) NS_INTERFACE_MAP_ENTRY(nsIChromeEventHandler) NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot) NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget) NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WindowRoot) // XXX right name? NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsWindowRoot) NS_IMPL_RELEASE(nsWindowRoot) NS_IMETHODIMP nsWindowRoot::AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture) { return AddGroupedEventListener(aType, aListener, aUseCapture, nsnull); } NS_IMETHODIMP nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture) { return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull); } NS_IMETHODIMP nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, PRBool *_retval) { // Obtain a presentation context nsCOMPtr domDoc; mWindow->GetDocument(getter_AddRefs(domDoc)); if (!domDoc) return NS_OK; nsCOMPtr doc(do_QueryInterface(domDoc)); PRInt32 count = doc->GetNumberOfShells(); if (count == 0) return NS_OK; nsIPresShell *shell = doc->GetShellAt(0); // Retrieve the context nsCOMPtr aPresContext = shell->GetPresContext(); return aPresContext->EventStateManager()-> DispatchNewEvent(NS_STATIC_CAST(nsIDOMEventReceiver*, this), aEvt, _retval); } NS_IMETHODIMP nsWindowRoot::AddGroupedEventListener(const nsAString & aType, nsIDOMEventListener *aListener, PRBool aUseCapture, nsIDOMEventGroup *aEvtGrp) { nsCOMPtr manager; if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager)))) { PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp); return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsWindowRoot::RemoveGroupedEventListener(const nsAString & aType, nsIDOMEventListener *aListener, PRBool aUseCapture, nsIDOMEventGroup *aEvtGrp) { if (mListenerManager) { PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; mListenerManager->RemoveEventListenerByType(aListener, aType, flags, aEvtGrp); return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsWindowRoot::CanTrigger(const nsAString & type, PRBool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsWindowRoot::IsRegisteredHere(const nsAString & type, PRBool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsWindowRoot::AddEventListener(const nsAString& aType, nsIDOMEventListener *aListener, PRBool aUseCapture, PRBool aWantsUntrusted) { nsCOMPtr manager; nsresult rv = GetListenerManager(getter_AddRefs(manager)); NS_ENSURE_SUCCESS(rv, rv); PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; if (aWantsUntrusted) { flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED; } return manager->AddEventListenerByType(aListener, aType, flags, nsnull); } NS_IMETHODIMP nsWindowRoot::AddEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID) { nsCOMPtr manager; GetListenerManager(getter_AddRefs(manager)); if (manager) { manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE); return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsWindowRoot::RemoveEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID) { nsCOMPtr manager; GetListenerManager(getter_AddRefs(manager)); if (manager) { manager->RemoveEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE); return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsWindowRoot::GetListenerManager(nsIEventListenerManager** aResult) { if (!mListenerManager) { nsresult rv; mListenerManager = do_CreateInstance(kEventListenerManagerCID, &rv); if (NS_FAILED(rv)) return rv; mListenerManager->SetListenerTarget( NS_STATIC_CAST(nsIDOMEventReceiver*, this)); } *aResult = mListenerManager; NS_ADDREF(*aResult); return NS_OK; } NS_IMETHODIMP nsWindowRoot::HandleEvent(nsIDOMEvent *aEvent) { PRBool defaultActionEnabled; return DispatchEvent(aEvent, &defaultActionEnabled); } NS_IMETHODIMP nsWindowRoot::GetSystemEventGroup(nsIDOMEventGroup **aGroup) { nsCOMPtr manager; if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager))) && manager) { return manager->GetSystemEventGroupLM(aGroup); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsWindowRoot::HandleChromeEvent(nsPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus) { // Make sure to tell the event that dispatch has started. NS_MARK_EVENT_DISPATCH_STARTED(aEvent); // Prevent the world from going // away until after we've finished handling the event. nsCOMPtr kungFuDeathGrip(mWindow); nsresult ret = NS_OK; nsIDOMEvent* domEvent = nsnull; // We're at the top, so there's no bubbling or capturing here. if (NS_EVENT_FLAG_INIT & aFlags) { aDOMEvent = &domEvent; aEvent->flags = aFlags; aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL); } //Local handling stage if (mListenerManager && !(aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) { aEvent->flags |= aFlags; mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, this, aFlags, aEventStatus); aEvent->flags &= ~aFlags; } if (NS_EVENT_FLAG_INIT & aFlags) { // We're leaving the DOM event loop so if we created a DOM event, // release here. if (nsnull != *aDOMEvent) { nsrefcnt rc; NS_RELEASE2(*aDOMEvent, rc); if (0 != rc) { // Okay, so someone in the DOM loop (a listener, JS object) // still has a ref to the DOM Event but the internal data // hasn't been malloc'd. Force a copy of the data here so the // DOM Event is still valid. nsIPrivateDOMEvent *privateEvent; if (NS_OK == (*aDOMEvent)->QueryInterface(NS_GET_IID(nsIPrivateDOMEvent), (void**)&privateEvent)) { privateEvent->DuplicatePrivateData(); NS_RELEASE(privateEvent); } } } aDOMEvent = nsnull; // Now that we're done with this event, remove the flag that says // we're in the process of dispatching this event. NS_MARK_EVENT_DISPATCH_DONE(aEvent); } return ret; } nsIDOMGCParticipant* nsWindowRoot::GetSCCIndex() { return this; } void nsWindowRoot::AppendReachableList(nsCOMArray& aArray) { } NS_IMETHODIMP nsWindowRoot::GetFocusController(nsIFocusController** aResult) { *aResult = mFocusController; NS_IF_ADDREF(*aResult); return NS_OK; } /////////////////////////////////////////////////////////////////////////////////// nsresult NS_NewWindowRoot(nsIDOMWindow* aWindow, nsIChromeEventHandler** aResult) { *aResult = new nsWindowRoot(aWindow); if (!*aResult) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aResult); return NS_OK; }