2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2001 Dirk Mueller (mueller@kde.org)
7 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
27 #include "EventTargetNode.h"
32 #include "EventListener.h"
33 #include "EventNames.h"
35 #include "FrameView.h"
36 #include "HTMLNames.h"
37 #include "TextStream.h"
38 #include "KeyboardEvent.h"
39 #include "MouseEvent.h"
40 #include "MutationEvent.h"
41 #include "PlatformMouseEvent.h"
42 #include "PlatformWheelEvent.h"
43 #include "RegisteredEventListener.h"
45 #include "WheelEvent.h"
46 #include "kjs_proxy.h"
50 using namespace EventNames;
51 using namespace HTMLNames;
54 static int gEventDispatchForbidden = 0;
57 EventTargetNode::EventTargetNode(Document *doc)
63 EventTargetNode::~EventTargetNode()
65 if (m_regdListeners && !m_regdListeners->isEmpty() && !inDocument())
66 document()->unregisterDisconnectedNodeWithEventListeners(this);
67 delete m_regdListeners;
70 void EventTargetNode::insertedIntoDocument()
72 if (m_regdListeners && !m_regdListeners->isEmpty())
73 document()->unregisterDisconnectedNodeWithEventListeners(this);
75 Node::insertedIntoDocument();
78 void EventTargetNode::removedFromDocument()
80 if (m_regdListeners && !m_regdListeners->isEmpty())
81 document()->registerDisconnectedNodeWithEventListeners(this);
83 Node::removedFromDocument();
86 void EventTargetNode::addEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener, const bool useCapture)
88 if (!document()->attached())
91 Document::ListenerType type = static_cast<Document::ListenerType>(0);
92 if (eventType == DOMSubtreeModifiedEvent)
93 type = Document::DOMSUBTREEMODIFIED_LISTENER;
94 else if (eventType == DOMNodeInsertedEvent)
95 type = Document::DOMNODEINSERTED_LISTENER;
96 else if (eventType == DOMNodeRemovedEvent)
97 type = Document::DOMNODEREMOVED_LISTENER;
98 else if (eventType == DOMNodeRemovedFromDocumentEvent)
99 type = Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER;
100 else if (eventType == DOMNodeInsertedIntoDocumentEvent)
101 type = Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER;
102 else if (eventType == DOMAttrModifiedEvent)
103 type = Document::DOMATTRMODIFIED_LISTENER;
104 else if (eventType == DOMCharacterDataModifiedEvent)
105 type = Document::DOMCHARACTERDATAMODIFIED_LISTENER;
106 else if (eventType == overflowchangedEvent)
107 type = Document::OVERFLOWCHANGED_LISTENER;
110 document()->addListenerType(type);
112 if (!m_regdListeners)
113 m_regdListeners = new RegisteredEventListenerList;
115 // Remove existing identical listener set with identical arguments.
116 // The DOM2 spec says that "duplicate instances are discarded" in this case.
117 removeEventListener(eventType, listener.get(), useCapture);
119 // adding the first one
120 if (m_regdListeners->isEmpty() && !inDocument())
121 document()->registerDisconnectedNodeWithEventListeners(this);
123 m_regdListeners->append(new RegisteredEventListener(eventType, listener.get(), useCapture));
126 void EventTargetNode::removeEventListener(const AtomicString &eventType, EventListener *listener, bool useCapture)
128 if (!m_regdListeners) // nothing to remove
131 RegisteredEventListener rl(eventType, listener, useCapture);
133 RegisteredEventListenerList::Iterator end = m_regdListeners->end();
134 for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
135 if (*(*it).get() == rl) {
136 (*it)->setRemoved(true);
138 it = m_regdListeners->remove(it);
140 if (m_regdListeners->isEmpty() && !inDocument())
141 document()->unregisterDisconnectedNodeWithEventListeners(this);
146 void EventTargetNode::removeAllEventListeners()
148 delete m_regdListeners;
152 void EventTargetNode::handleLocalEvents(Event *evt, bool useCapture)
154 if (!m_regdListeners)
157 if (disabled() && evt->isMouseEvent())
160 RegisteredEventListenerList listenersCopy = *m_regdListeners;
161 RegisteredEventListenerList::Iterator end = listenersCopy.end();
163 for (RegisteredEventListenerList::Iterator it = listenersCopy.begin(); it != end; ++it)
164 if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed())
165 (*it)->listener()->handleEvent(evt, false);
168 bool EventTargetNode::dispatchGenericEvent(PassRefPtr<Event> e, ExceptionCode&, bool tempEvent)
170 RefPtr<Event> evt(e);
171 assert(!eventDispatchForbidden());
172 assert(evt->target());
173 assert(!evt->type().isNull()); // JavaScript code could create an event with an empty name
175 // work out what nodes to send event to
176 DeprecatedPtrList<Node> nodeChain;
178 for (n = this; n; n = n->parentNode()) {
180 nodeChain.prepend(n);
183 DeprecatedPtrListIterator<Node> it(nodeChain);
185 // Before we begin dispatching events, give the target node a chance to do some work prior
186 // to the DOM event handlers getting a crack.
187 void* data = preDispatchEventHandler(evt.get());
189 // trigger any capturing event handlers on our way down
190 evt->setEventPhase(Event::CAPTURING_PHASE);
193 // Handle window events for capture phase, except load events, this quirk is needed
194 // because Mozilla used to never propagate load events to the window object
195 if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped())
196 static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), true);
198 for (; it.current() && it.current() != this && !evt->propagationStopped(); ++it) {
199 evt->setCurrentTarget(it.current());
200 EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), true);
203 // dispatch to the actual target node
205 if (!evt->propagationStopped()) {
206 evt->setEventPhase(Event::AT_TARGET);
207 evt->setCurrentTarget(it.current());
209 // We do want capturing event listeners to be invoked here, even though
210 // that violates the specification since Mozilla does it.
211 EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), true);
213 EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), false);
217 // ok, now bubble up again (only non-capturing event handlers will be called)
218 // ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers)
219 // no. the DOM specs says:
220 // The chain of EventTargets from the event target to the top of the tree
221 // is determined before the initial dispatch of the event.
222 // If modifications occur to the tree during event processing,
223 // event flow will proceed based on the initial state of the tree.
225 // since the initial dispatch is before the capturing phase,
226 // there's no need to recalculate the node chain.
229 if (evt->bubbles()) {
230 evt->setEventPhase(Event::BUBBLING_PHASE);
231 for (; it.current() && !evt->propagationStopped() && !evt->getCancelBubble(); --it) {
232 evt->setCurrentTarget(it.current());
233 EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), false);
235 // Handle window events for bubbling phase, except load events, this quirk is needed
236 // because Mozilla used to never propagate load events at all
239 if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped() && !evt->getCancelBubble()) {
240 evt->setCurrentTarget(it.current());
241 static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), false);
245 evt->setCurrentTarget(0);
246 evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
247 // anything about the default event handler phase.
250 // Now call the post dispatch.
251 postDispatchEventHandler(evt.get(), data);
253 // now we call all default event handlers (this is not part of DOM - it is internal to khtml)
257 for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
258 EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
259 else if (!evt->defaultPrevented() && !evt->defaultHandled())
260 EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
262 // deref all nodes in chain
264 for (; it.current(); ++it)
265 it.current()->deref(); // this may delete us
267 Document::updateDocumentsRendering();
269 // If tempEvent is true, this means that the DOM implementation
270 // will not be storing a reference to the event, i.e. there is no
271 // way to retrieve it from javascript if a script does not already
272 // have a reference to it in a variable. So there is no need for
273 // the interpreter to keep the event in it's cache
274 Frame *frame = document()->frame();
275 if (tempEvent && frame && frame->scriptProxy())
276 frame->scriptProxy()->finishedWithEvent(evt.get());
278 return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent?
281 bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool tempEvent)
283 RefPtr<Event> evt(e);
284 assert(!eventDispatchForbidden());
285 if (!evt || evt->type().isEmpty()) {
286 ec = UNSPECIFIED_EVENT_TYPE_ERR;
289 evt->setTarget(this);
291 RefPtr<FrameView> view = document()->view();
293 return dispatchGenericEvent(evt.release(), ec, tempEvent);
296 bool EventTargetNode::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
298 assert(!eventDispatchForbidden());
300 // FIXME: Pull this whole if clause out of this function.
301 if (sendChildrenChanged) {
302 notifyNodeListsChildrenChanged();
305 notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing.
307 if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
309 ExceptionCode ec = 0;
310 return dispatchEvent(new MutationEvent(DOMSubtreeModifiedEvent,
311 true,false,0,String(),String(),String(),0),ec,true);
314 void EventTargetNode::dispatchWindowEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
316 assert(!eventDispatchForbidden());
317 ExceptionCode ec = 0;
318 RefPtr<Event> evt = new Event(eventType, canBubbleArg, cancelableArg);
319 RefPtr<Document> doc = document();
320 evt->setTarget(doc.get());
321 doc->handleWindowEvent(evt.get(), true);
322 doc->handleWindowEvent(evt.get(), false);
324 if (eventType == loadEvent) {
325 // For onload events, send a separate load event to the enclosing frame only.
326 // This is a DOM extension and is independent of bubbling/capturing rules of
328 Element* ownerElement = doc->ownerElement();
330 RefPtr<Event> ownerEvent = new Event(eventType, false, cancelableArg);
331 ownerEvent->setTarget(ownerElement);
332 ownerElement->dispatchGenericEvent(ownerEvent.release(), ec, true);
337 bool EventTargetNode::dispatchUIEvent(const AtomicString &eventType, int detail)
339 assert(!eventDispatchForbidden());
340 assert(eventType == DOMFocusInEvent || eventType == DOMFocusOutEvent || eventType == DOMActivateEvent);
342 bool cancelable = eventType == DOMActivateEvent;
344 ExceptionCode ec = 0;
345 UIEvent* evt = new UIEvent(eventType, true, cancelable, document()->defaultView(), detail);
346 return dispatchEvent(evt, ec, true);
349 bool EventTargetNode::dispatchKeyEvent(const PlatformKeyboardEvent& key)
351 assert(!eventDispatchForbidden());
352 ExceptionCode ec = 0;
353 RefPtr<KeyboardEvent> keyboardEvent = new KeyboardEvent(key, document()->defaultView());
354 bool r = dispatchEvent(keyboardEvent,ec,true);
356 // we want to return false if default is prevented (already taken care of)
357 // or if the element is default-handled by the DOM. Otherwise we let it just
358 // let it get handled by AppKit
359 if (keyboardEvent->defaultHandled())
365 bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& _mouse, const AtomicString& eventType,
366 int detail, Node* relatedTarget)
368 assert(!eventDispatchForbidden());
370 IntPoint contentsPos;
371 if (FrameView* view = document()->view())
372 contentsPos = view->windowToContents(_mouse.pos());
374 return dispatchMouseEvent(eventType, _mouse.button(), detail,
375 contentsPos.x(), contentsPos.y(), _mouse.globalX(), _mouse.globalY(),
376 _mouse.ctrlKey(), _mouse.altKey(), _mouse.shiftKey(), _mouse.metaKey(),
377 false, relatedTarget);
380 bool EventTargetNode::dispatchSimulatedMouseEvent(const AtomicString &eventType)
382 assert(!eventDispatchForbidden());
383 // Like Gecko, we just pass 0 for everything when we make a fake mouse event.
384 // Internet Explorer instead gives the current mouse position and state.
385 return dispatchMouseEvent(eventType, 0, 0, 0, 0, 0, 0, false, false, false, false, true);
388 bool EventTargetNode::dispatchMouseEvent(const AtomicString& eventType, int button, int detail,
389 int pageX, int pageY, int screenX, int screenY,
390 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
391 bool isSimulated, Node* relatedTargetArg)
393 assert(!eventDispatchForbidden());
394 if (disabled()) // Don't even send DOM events for disabled controls..
397 if (eventType.isEmpty())
398 return false; // Shouldn't happen.
400 // Dispatching the first event can easily result in this node being destroyed.
401 // Since we dispatch up to three events here, we need to make sure we're referenced
402 // so the pointer will be good for the two subsequent ones.
403 RefPtr<Node> protect(this);
405 bool cancelable = eventType != mousemoveEvent;
407 ExceptionCode ec = 0;
409 bool swallowEvent = false;
411 // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored.
412 EventTargetNode *relatedTarget = (relatedTargetArg && relatedTargetArg->isEventTargetNode()) ? static_cast<EventTargetNode*>(relatedTargetArg) : 0;
414 RefPtr<Event> me = new MouseEvent(eventType, true, cancelable, document()->defaultView(),
415 detail, screenX, screenY, pageX, pageY,
416 ctrlKey, altKey, shiftKey, metaKey, button,
417 relatedTarget, 0, isSimulated);
419 dispatchEvent(me, ec, true);
420 bool defaultHandled = me->defaultHandled();
421 bool defaultPrevented = me->defaultPrevented();
422 if (defaultHandled || defaultPrevented)
425 // Special case: If it's a double click event, we also send the dblclick event. This is not part
426 // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated
427 // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
428 if (eventType == clickEvent && detail == 2) {
429 me = new MouseEvent(dblclickEvent, true, cancelable, document()->defaultView(),
430 detail, screenX, screenY, pageX, pageY,
431 ctrlKey, altKey, shiftKey, metaKey, button,
432 relatedTarget, 0, isSimulated);
434 me->setDefaultHandled();
435 dispatchEvent(me, ec, true);
436 if (me->defaultHandled() || me->defaultPrevented())
440 // Also send a DOMActivate event, which causes things like form submissions to occur.
441 if (eventType == clickEvent && !defaultPrevented)
442 dispatchUIEvent(DOMActivateEvent, detail);
447 void EventTargetNode::dispatchWheelEvent(PlatformWheelEvent& e)
449 assert(!eventDispatchForbidden());
450 if (e.deltaX() == 0 && e.deltaY() == 0)
453 FrameView* view = document()->view();
457 IntPoint pos = view->windowToContents(e.pos());
459 RefPtr<WheelEvent> we = new WheelEvent(e.deltaX(), e.deltaY(),
460 document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(),
461 e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
462 ExceptionCode ec = 0;
463 if (!dispatchEvent(we, ec, true))
468 void EventTargetNode::dispatchFocusEvent()
470 dispatchHTMLEvent(focusEvent, false, false);
473 void EventTargetNode::dispatchBlurEvent()
475 dispatchHTMLEvent(blurEvent, false, false);
478 bool EventTargetNode::dispatchHTMLEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
480 assert(!eventDispatchForbidden());
481 ExceptionCode ec = 0;
482 return dispatchEvent(new Event(eventType, canBubbleArg, cancelableArg), ec, true);
485 void EventTargetNode::removeHTMLEventListener(const AtomicString &eventType)
487 if (!m_regdListeners) // nothing to remove
490 RegisteredEventListenerList::Iterator end = m_regdListeners->end();
491 for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
492 if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
493 it = m_regdListeners->remove(it);
495 if (m_regdListeners->isEmpty() && !inDocument())
496 document()->unregisterDisconnectedNodeWithEventListeners(this);
501 void EventTargetNode::setHTMLEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
503 // In case we are the only one holding a reference to it, we don't want removeHTMLEventListener to destroy it.
504 removeHTMLEventListener(eventType);
506 addEventListener(eventType, listener.get(), false);
509 EventListener *EventTargetNode::getHTMLEventListener(const AtomicString &eventType)
511 if (!m_regdListeners)
514 RegisteredEventListenerList::Iterator end = m_regdListeners->end();
515 for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
516 if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
517 return (*it)->listener();
521 bool EventTargetNode::disabled() const
526 void EventTargetNode::defaultEventHandler(Event* event)
528 if (event->type() == keypressEvent && event->isKeyboardEvent()) {
529 KeyboardEvent* keyEvent = static_cast<KeyboardEvent*>(event);
530 if (keyEvent->keyIdentifier() == "U+000009") {
531 Frame* frame = document()->frame();
532 if (frame && frame->view() && frame->view()->advanceFocus(keyEvent))
533 event->setDefaultHandled();
540 void EventTargetNode::dump(TextStream* stream, DeprecatedString ind) const
543 *stream << " #regdListeners=" << m_regdListeners->count(); // ### more detail
545 Node::dump(stream,ind);
548 void forbidEventDispatch()
550 ++gEventDispatchForbidden;
553 void allowEventDispatch()
555 if (gEventDispatchForbidden > 0)
556 --gEventDispatchForbidden;
559 bool eventDispatchForbidden()
561 return gEventDispatchForbidden > 0;
566 } // namespace WebCore