Back to index

lightning-sunbird  0.9+nobinonly
nsWindowRoot.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   David W. Hyatt <hyatt@netscape.com> (Original Author)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsWindowRoot.h"
00042 #include "nsIDOMWindow.h"
00043 #include "nsIDOMDocument.h"
00044 #include "nsIDocument.h"
00045 #include "nsIEventListenerManager.h"
00046 #include "nsIPresShell.h"
00047 #include "nsPresContext.h"
00048 #include "nsLayoutCID.h"
00049 #include "nsContentCID.h"
00050 #include "nsIEventStateManager.h"
00051 #include "nsIPrivateDOMEvent.h"
00052 #include "nsIDOMWindowInternal.h"
00053 #include "nsFocusController.h"
00054 #include "nsString.h"
00055 #include "nsDOMClassInfo.h"
00056 
00057 static NS_DEFINE_CID(kEventListenerManagerCID,    NS_EVENTLISTENERMANAGER_CID);
00058 
00059 nsWindowRoot::nsWindowRoot(nsIDOMWindow* aWindow)
00060 {
00061   mWindow = aWindow;
00062 
00063   // Create and init our focus controller.
00064   nsFocusController::Create(getter_AddRefs(mFocusController));
00065 
00066   nsCOMPtr<nsIDOMFocusListener> focusListener(do_QueryInterface(mFocusController));
00067   ++mRefCnt;
00068   AddEventListener(NS_LITERAL_STRING("focus"), focusListener, PR_TRUE);
00069   AddEventListener(NS_LITERAL_STRING("blur"), focusListener, PR_TRUE);
00070   --mRefCnt;
00071 }
00072 
00073 nsWindowRoot::~nsWindowRoot()
00074 {
00075   if (mListenerManager) {
00076     mListenerManager->Disconnect();
00077   }
00078 }
00079 
00080 NS_INTERFACE_MAP_BEGIN(nsWindowRoot)
00081   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventReceiver)
00082   NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
00083   NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
00084   NS_INTERFACE_MAP_ENTRY(nsIChromeEventHandler)
00085   NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
00086   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
00087   NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
00088   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
00089   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WindowRoot) // XXX right name?
00090 NS_INTERFACE_MAP_END
00091 
00092 NS_IMPL_ADDREF(nsWindowRoot)
00093 NS_IMPL_RELEASE(nsWindowRoot)
00094 
00095 NS_IMETHODIMP
00096 nsWindowRoot::AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture)
00097 {
00098   return AddGroupedEventListener(aType, aListener, aUseCapture, nsnull);
00099 }
00100 
00101 NS_IMETHODIMP
00102 nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture)
00103 {
00104   return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
00105 }
00106 
00107 NS_IMETHODIMP
00108 nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, PRBool *_retval)
00109 {
00110   // Obtain a presentation context
00111   nsCOMPtr<nsIDOMDocument> domDoc;
00112   mWindow->GetDocument(getter_AddRefs(domDoc));
00113   if (!domDoc)
00114     return NS_OK;
00115   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
00116   
00117   PRInt32 count = doc->GetNumberOfShells();
00118   if (count == 0)
00119     return NS_OK;
00120 
00121   nsIPresShell *shell = doc->GetShellAt(0);
00122   
00123   // Retrieve the context
00124   nsCOMPtr<nsPresContext> aPresContext = shell->GetPresContext();
00125 
00126   return aPresContext->EventStateManager()->
00127     DispatchNewEvent(NS_STATIC_CAST(nsIDOMEventReceiver*, this),
00128                      aEvt, _retval);
00129 }
00130 
00131 NS_IMETHODIMP
00132 nsWindowRoot::AddGroupedEventListener(const nsAString & aType, nsIDOMEventListener *aListener, 
00133                                           PRBool aUseCapture, nsIDOMEventGroup *aEvtGrp)
00134 {
00135   nsCOMPtr<nsIEventListenerManager> manager;
00136 
00137   if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager)))) {
00138     PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
00139     manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
00140     return NS_OK;
00141   }
00142   return NS_ERROR_FAILURE;
00143 }
00144 
00145 NS_IMETHODIMP
00146 nsWindowRoot::RemoveGroupedEventListener(const nsAString & aType, nsIDOMEventListener *aListener, 
00147                                              PRBool aUseCapture, nsIDOMEventGroup *aEvtGrp)
00148 {
00149   if (mListenerManager) {
00150     PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
00151     mListenerManager->RemoveEventListenerByType(aListener, aType, flags, aEvtGrp);
00152     return NS_OK;
00153   }
00154   return NS_ERROR_FAILURE;
00155 }
00156 
00157 NS_IMETHODIMP
00158 nsWindowRoot::CanTrigger(const nsAString & type, PRBool *_retval)
00159 {
00160   return NS_ERROR_NOT_IMPLEMENTED;
00161 }
00162 
00163 NS_IMETHODIMP
00164 nsWindowRoot::IsRegisteredHere(const nsAString & type, PRBool *_retval)
00165 {
00166   return NS_ERROR_NOT_IMPLEMENTED;
00167 }
00168 
00169 NS_IMETHODIMP
00170 nsWindowRoot::AddEventListener(const nsAString& aType,
00171                                nsIDOMEventListener *aListener,
00172                                PRBool aUseCapture, PRBool aWantsUntrusted)
00173 {
00174   nsCOMPtr<nsIEventListenerManager> manager;
00175   nsresult rv = GetListenerManager(getter_AddRefs(manager));
00176   NS_ENSURE_SUCCESS(rv, rv);
00177 
00178   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
00179 
00180   if (aWantsUntrusted) {
00181     flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
00182   }
00183 
00184   return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
00185 }
00186 
00187 NS_IMETHODIMP
00188 nsWindowRoot::AddEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID)
00189 {
00190   nsCOMPtr<nsIEventListenerManager> manager;
00191   GetListenerManager(getter_AddRefs(manager));
00192   if (manager) {
00193     manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
00194     return NS_OK;
00195   }
00196   return NS_ERROR_FAILURE;
00197 }
00198   
00199 NS_IMETHODIMP
00200 nsWindowRoot::RemoveEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID)
00201 {
00202   nsCOMPtr<nsIEventListenerManager> manager;
00203   GetListenerManager(getter_AddRefs(manager));
00204   if (manager) {
00205     manager->RemoveEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
00206     return NS_OK;
00207   }
00208   return NS_ERROR_FAILURE;
00209 }
00210 
00211 NS_IMETHODIMP
00212 nsWindowRoot::GetListenerManager(nsIEventListenerManager** aResult)
00213 {
00214   if (!mListenerManager) {
00215     nsresult rv;
00216     mListenerManager = do_CreateInstance(kEventListenerManagerCID, &rv);
00217     if (NS_FAILED(rv)) return rv;
00218     mListenerManager->SetListenerTarget(
00219       NS_STATIC_CAST(nsIDOMEventReceiver*, this));
00220   }
00221 
00222   *aResult = mListenerManager;
00223   NS_ADDREF(*aResult);
00224   return NS_OK;
00225 }
00226 
00227 NS_IMETHODIMP
00228 nsWindowRoot::HandleEvent(nsIDOMEvent *aEvent)
00229 {
00230   PRBool defaultActionEnabled;
00231   return DispatchEvent(aEvent, &defaultActionEnabled);
00232 }
00233 
00234 NS_IMETHODIMP
00235 nsWindowRoot::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
00236 {
00237   nsCOMPtr<nsIEventListenerManager> manager;
00238   if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager))) && manager) {
00239     return manager->GetSystemEventGroupLM(aGroup);
00240   }
00241   return NS_ERROR_FAILURE;
00242 }
00243 
00244 NS_IMETHODIMP
00245 nsWindowRoot::HandleChromeEvent(nsPresContext* aPresContext, nsEvent* aEvent,
00246                                 nsIDOMEvent** aDOMEvent, PRUint32 aFlags, 
00247                                 nsEventStatus* aEventStatus)
00248 {
00249   // Make sure to tell the event that dispatch has started.
00250   NS_MARK_EVENT_DISPATCH_STARTED(aEvent);
00251 
00252   // Prevent the world from going
00253   // away until after we've finished handling the event.
00254   nsCOMPtr<nsIDOMWindow> kungFuDeathGrip(mWindow);
00255 
00256   nsresult ret = NS_OK;
00257   nsIDOMEvent* domEvent = nsnull;
00258 
00259   // We're at the top, so there's no bubbling or capturing here.
00260   if (NS_EVENT_FLAG_INIT & aFlags) {
00261     aDOMEvent = &domEvent;
00262     aEvent->flags = aFlags;
00263     aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL);
00264   }
00265 
00266   //Local handling stage
00267   if (mListenerManager && !(aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
00268     aEvent->flags |= aFlags;
00269     mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, this, aFlags, aEventStatus);
00270     aEvent->flags &= ~aFlags;
00271   }
00272 
00273   if (NS_EVENT_FLAG_INIT & aFlags) {
00274     // We're leaving the DOM event loop so if we created a DOM event,
00275     // release here.
00276     if (nsnull != *aDOMEvent) {
00277       nsrefcnt rc;
00278       NS_RELEASE2(*aDOMEvent, rc);
00279       if (0 != rc) {
00280         // Okay, so someone in the DOM loop (a listener, JS object)
00281         // still has a ref to the DOM Event but the internal data
00282         // hasn't been malloc'd.  Force a copy of the data here so the
00283         // DOM Event is still valid.
00284         nsIPrivateDOMEvent *privateEvent;
00285         if (NS_OK == (*aDOMEvent)->QueryInterface(NS_GET_IID(nsIPrivateDOMEvent), (void**)&privateEvent)) {
00286           privateEvent->DuplicatePrivateData();
00287           NS_RELEASE(privateEvent);
00288         }
00289       }
00290     }
00291     aDOMEvent = nsnull;
00292 
00293     // Now that we're done with this event, remove the flag that says
00294     // we're in the process of dispatching this event.
00295     NS_MARK_EVENT_DISPATCH_DONE(aEvent);
00296   }
00297 
00298   return ret;
00299 }
00300 
00301 nsIDOMGCParticipant*
00302 nsWindowRoot::GetSCCIndex()
00303 {
00304   return this;
00305 }
00306 
00307 void
00308 nsWindowRoot::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
00309 {
00310 }
00311 
00312 NS_IMETHODIMP
00313 nsWindowRoot::GetFocusController(nsIFocusController** aResult)
00314 {
00315   *aResult = mFocusController;
00316   NS_IF_ADDREF(*aResult);
00317   return NS_OK;
00318 }
00319 
00321 
00322 nsresult
00323 NS_NewWindowRoot(nsIDOMWindow* aWindow, nsIChromeEventHandler** aResult)
00324 {
00325   *aResult = new nsWindowRoot(aWindow);
00326   if (!*aResult)
00327     return NS_ERROR_OUT_OF_MEMORY;
00328   NS_ADDREF(*aResult);
00329   return NS_OK;
00330 }