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: #ifdef MOZILLA_INTERNAL_API michael@0: #ifndef mozilla_EventDispatcher_h_ michael@0: #define mozilla_EventDispatcher_h_ michael@0: michael@0: #include "mozilla/EventForwards.h" michael@0: #include "nsCOMPtr.h" michael@0: michael@0: // Microsoft's API Name hackery sucks michael@0: #undef CreateEvent michael@0: michael@0: class nsIDOMEvent; michael@0: class nsIScriptGlobalObject; michael@0: class nsPresContext; michael@0: michael@0: template class nsCOMArray; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: class EventTarget; michael@0: } // namespace dom michael@0: michael@0: /** michael@0: * About event dispatching: michael@0: * When either EventDispatcher::Dispatch or michael@0: * EventDispatcher::DispatchDOMEvent is called an event target chain is michael@0: * created. EventDispatcher creates the chain by calling PreHandleEvent michael@0: * on each event target and the creation continues until either the mCanHandle michael@0: * member of the EventChainPreVisitor object is false or the mParentTarget michael@0: * does not point to a new target. The event target chain is created in the michael@0: * heap. michael@0: * michael@0: * If the event needs retargeting, mEventTargetAtParent must be set in michael@0: * PreHandleEvent. michael@0: * michael@0: * The capture, target and bubble phases of the event dispatch are handled michael@0: * by iterating through the event target chain. Iteration happens twice, michael@0: * first for the default event group and then for the system event group. michael@0: * While dispatching the event for the system event group PostHandleEvent michael@0: * is called right after calling event listener for the current event target. michael@0: */ michael@0: michael@0: class EventChainVisitor michael@0: { michael@0: public: michael@0: EventChainVisitor(nsPresContext* aPresContext, michael@0: WidgetEvent* aEvent, michael@0: nsIDOMEvent* aDOMEvent, michael@0: nsEventStatus aEventStatus = nsEventStatus_eIgnore) michael@0: : mPresContext(aPresContext) michael@0: , mEvent(aEvent) michael@0: , mDOMEvent(aDOMEvent) michael@0: , mEventStatus(aEventStatus) michael@0: , mItemFlags(0) michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * The prescontext, possibly nullptr. michael@0: */ michael@0: nsPresContext* const mPresContext; michael@0: michael@0: /** michael@0: * The WidgetEvent which is being dispatched. Never nullptr. michael@0: */ michael@0: WidgetEvent* const mEvent; michael@0: michael@0: /** michael@0: * The DOM Event assiciated with the mEvent. Possibly nullptr if a DOM Event michael@0: * is not (yet) created. michael@0: */ michael@0: nsIDOMEvent* mDOMEvent; michael@0: michael@0: /** michael@0: * The status of the event. michael@0: * @see nsEventStatus.h michael@0: */ michael@0: nsEventStatus mEventStatus; michael@0: michael@0: /** michael@0: * Bits for items in the event target chain. michael@0: * Set in PreHandleEvent() and used in PostHandleEvent(). michael@0: * michael@0: * @note These bits are different for each item in the event target chain. michael@0: * It is up to the Pre/PostHandleEvent implementation to decide how to michael@0: * use these bits. michael@0: * michael@0: * @note Using uint16_t because that is used also in EventTargetChainItem. michael@0: */ michael@0: uint16_t mItemFlags; michael@0: michael@0: /** michael@0: * Data for items in the event target chain. michael@0: * Set in PreHandleEvent() and used in PostHandleEvent(). michael@0: * michael@0: * @note This data is different for each item in the event target chain. michael@0: * It is up to the Pre/PostHandleEvent implementation to decide how to michael@0: * use this. michael@0: */ michael@0: nsCOMPtr mItemData; michael@0: }; michael@0: michael@0: class EventChainPreVisitor : public EventChainVisitor michael@0: { michael@0: public: michael@0: EventChainPreVisitor(nsPresContext* aPresContext, michael@0: WidgetEvent* aEvent, michael@0: nsIDOMEvent* aDOMEvent, michael@0: nsEventStatus aEventStatus, michael@0: bool aIsInAnon) michael@0: : EventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus) michael@0: , mCanHandle(true) michael@0: , mAutomaticChromeDispatch(true) michael@0: , mForceContentDispatch(false) michael@0: , mRelatedTargetIsInAnon(false) michael@0: , mOriginalTargetIsInAnon(aIsInAnon) michael@0: , mWantsWillHandleEvent(false) michael@0: , mMayHaveListenerManager(true) michael@0: , mParentTarget(nullptr) michael@0: , mEventTargetAtParent(nullptr) michael@0: { michael@0: } michael@0: michael@0: void Reset() michael@0: { michael@0: mItemFlags = 0; michael@0: mItemData = nullptr; michael@0: mCanHandle = true; michael@0: mAutomaticChromeDispatch = true; michael@0: mForceContentDispatch = false; michael@0: mWantsWillHandleEvent = false; michael@0: mMayHaveListenerManager = true; michael@0: mParentTarget = nullptr; michael@0: mEventTargetAtParent = nullptr; michael@0: } michael@0: michael@0: /** michael@0: * Member that must be set in PreHandleEvent by event targets. If set to false, michael@0: * indicates that this event target will not be handling the event and michael@0: * construction of the event target chain is complete. The target that sets michael@0: * mCanHandle to false is NOT included in the event target chain. michael@0: */ michael@0: bool mCanHandle; michael@0: michael@0: /** michael@0: * If mCanHandle is false and mAutomaticChromeDispatch is also false michael@0: * event will not be dispatched to the chrome event handler. michael@0: */ michael@0: bool mAutomaticChromeDispatch; michael@0: michael@0: /** michael@0: * If mForceContentDispatch is set to true, michael@0: * content dispatching is not disabled for this event target. michael@0: * FIXME! This is here for backward compatibility. Bug 329119 michael@0: */ michael@0: bool mForceContentDispatch; michael@0: michael@0: /** michael@0: * true if it is known that related target is or is a descendant of an michael@0: * element which is anonymous for events. michael@0: */ michael@0: bool mRelatedTargetIsInAnon; michael@0: michael@0: /** michael@0: * true if the original target of the event is inside anonymous content. michael@0: * This is set before calling PreHandleEvent on event targets. michael@0: */ michael@0: bool mOriginalTargetIsInAnon; michael@0: michael@0: /** michael@0: * Whether or not nsIDOMEventTarget::WillHandleEvent will be michael@0: * called. Default is false; michael@0: */ michael@0: bool mWantsWillHandleEvent; michael@0: michael@0: /** michael@0: * If it is known that the current target doesn't have a listener manager michael@0: * when PreHandleEvent is called, set this to false. michael@0: */ michael@0: bool mMayHaveListenerManager; michael@0: michael@0: /** michael@0: * Parent item in the event target chain. michael@0: */ michael@0: dom::EventTarget* mParentTarget; michael@0: michael@0: /** michael@0: * If the event needs to be retargeted, this is the event target, michael@0: * which should be used when the event is handled at mParentTarget. michael@0: */ michael@0: dom::EventTarget* mEventTargetAtParent; michael@0: }; michael@0: michael@0: class EventChainPostVisitor : public mozilla::EventChainVisitor michael@0: { michael@0: public: michael@0: EventChainPostVisitor(EventChainVisitor& aOther) michael@0: : EventChainVisitor(aOther.mPresContext, aOther.mEvent, michael@0: aOther.mDOMEvent, aOther.mEventStatus) michael@0: { michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * If an EventDispatchingCallback object is passed to Dispatch, michael@0: * its HandleEvent method is called after handling the default event group, michael@0: * before handling the system event group. michael@0: * This is used in nsPresShell. michael@0: */ michael@0: class MOZ_STACK_CLASS EventDispatchingCallback michael@0: { michael@0: public: michael@0: virtual void HandleEvent(EventChainPostVisitor& aVisitor) = 0; michael@0: }; michael@0: michael@0: /** michael@0: * The generic class for event dispatching. michael@0: * Must not be used outside Gecko! michael@0: */ michael@0: class EventDispatcher michael@0: { michael@0: public: michael@0: /** michael@0: * aTarget should QI to EventTarget. michael@0: * If the target of aEvent is set before calling this method, the target of michael@0: * aEvent is used as the target (unless there is event michael@0: * retargeting) and the originalTarget of the DOM Event. michael@0: * aTarget is always used as the starting point for constructing the event michael@0: * target chain, no matter what the value of aEvent->target is. michael@0: * In other words, aEvent->target is only a property of the event and it has michael@0: * nothing to do with the construction of the event target chain. michael@0: * Neither aTarget nor aEvent is allowed to be nullptr. michael@0: * michael@0: * If aTargets is non-null, event target chain will be created, but michael@0: * event won't be handled. In this case aEvent->message should be michael@0: * NS_EVENT_NULL. michael@0: * @note Use this method when dispatching a WidgetEvent. michael@0: */ michael@0: static nsresult Dispatch(nsISupports* aTarget, michael@0: nsPresContext* aPresContext, michael@0: WidgetEvent* aEvent, michael@0: nsIDOMEvent* aDOMEvent = nullptr, michael@0: nsEventStatus* aEventStatus = nullptr, michael@0: EventDispatchingCallback* aCallback = nullptr, michael@0: nsCOMArray* aTargets = nullptr); michael@0: michael@0: /** michael@0: * Dispatches an event. michael@0: * If aDOMEvent is not nullptr, it is used for dispatching michael@0: * (aEvent can then be nullptr) and (if aDOMEvent is not |trusted| already), michael@0: * the |trusted| flag is set based on the UniversalXPConnect capability. michael@0: * Otherwise this works like EventDispatcher::Dispatch. michael@0: * @note Use this method when dispatching nsIDOMEvent. michael@0: */ michael@0: static nsresult DispatchDOMEvent(nsISupports* aTarget, michael@0: WidgetEvent* aEvent, michael@0: nsIDOMEvent* aDOMEvent, michael@0: nsPresContext* aPresContext, michael@0: nsEventStatus* aEventStatus); michael@0: michael@0: /** michael@0: * Creates a DOM Event. michael@0: */ michael@0: static nsresult CreateEvent(dom::EventTarget* aOwner, michael@0: nsPresContext* aPresContext, michael@0: WidgetEvent* aEvent, michael@0: const nsAString& aEventType, michael@0: nsIDOMEvent** aDOMEvent); michael@0: michael@0: /** michael@0: * Called at shutting down. michael@0: */ michael@0: static void Shutdown(); michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_EventDispatcher_h_ michael@0: #endif