How Morphic processes events
Last updated at 1:57 pm UTC on 15 May 2018
EventSensor > HandMorph > Project current world (PasteUpMorph) > (MorphicEventDispatcher > Morph)
Page history:
Posted by Andreas Raab to the squeak-dev list on 2/12/2003
This page created by Brent Vukmer on 2/13/2003.
Reviewed by Daniel Vainsencher, with his clarifications [[between double brackets]]
Bob Arning added explaination on "front-most ... morphs" Examples added: TBD
This is an early description from 2003..2005: Needs to be rechecked for current versions of Squeak.
The Quick Overview
- The hand generates a MouseDownEvent from EventSensor's input.
- It sends the event using #handleListenEvent: to the registered listeners.
- It sends the event using #handleFocusEvent: to the current focus (if present) [#handleFocusEvent: typically simply invokes #handleEvent:, see below]
- Else if there is no focus, the hand sends the event using #dispatchEvent: to its owner (a world).
- The event is dispatched along the front-most, visible, unlocked chain of submorphs containing it, until it reaches a leaf.
- [On its way down, any morph can install a prospective handler if interested.]
- When the event traverses back up the chain, the event is sent to each morph in this chain using #handleEvent:
- #handleEvent: double dispatches the event into any of the system-level handlers.
- The system level handler (#handleMouseDown: etc) decides whether to invoke the user-level handler(s).
- Finally, the user-level handler (#mouseDown:) is invoked.
The front-most chain of morphs defined
Each morph has zero or more submorphs which are ordered front-to-back.
The chain would consist of (recursively) the frontmost submorph whose bounds contain the event point. So, it would look like:
1. The Project current world (the World).
2. The frontmost submorph of the World that intersects the event.
3. The frontmost submorph of #2 that intersects the event.
4. And so on until there are no submorphs that intersect the event.
The Details
- HandMorph obtains MorphicEvents by either converting primitive input (from Sensor) or some other means (like remote connections). [[ see RemoteHandMorph>>processEvents vs. HandMorph>>processEvents ]]
- The HandMorph then passes the event (depending on type) to any of the registered listeners (using #handleListenEvent:)
- Afterwards (again, depending on the type of the event,) the HandMorph send the event to its current focus (using #handleFocusEvent:).
- If there is no current event focus, theHandMorph passes the event to its world, for further dispatching (using #dispatchEvent:).
- [[Focus also applies to mouse events such as dragging, and focus is also affected when some morph is modal. ]]
- When an event is dispatched it uses (sometimes varying) strategies to figure out where it ends up. [[See #processEvent:with: and MorphicEventDispatcher.]] The general rule of thumb is: The front-most, visible, unlocked chain of morphs "containing" the event (as determined by #containsEvent:) is travelled all the way down to a leaf morph.
- As the hierarchy is traversed down, morphs may register themselves as "being interested" in the event by establishing a prospective handler. This handler can be used to figure out which morph (if more than one is interested) should ultimately handle the event in question. This prospective handler is essentially a way of passing an extra argument into the event processing loop without having to know the exact construction hierarchy of the children].
- On its way back up, each morph in the front-most chain of morphs is passed the event through #handleEvent:. BTW, this mechanism also ensures that even morphs where a child is outside of the parent can handle the event when it occured on some (out of bounds) child.
- [[Most of this is in order to a) not to have to establish the front-most chain of morphs explicitly, b) be efficeint and avoid exponential traversals of the morph chain, and c) allow for "delayed rejections" of some event. (IOW, if some system- or user-level handler wants to appear "transparent" -not being part of the front-most chain- it can do so.) The actual implementation uses both, the way down and the way up to determine which morphs are part of the front-most chain.]
- When #handleEvent: is invoked, it double-dispatches the event into a system-level handler (such as #handleMouseDown:).
- The system-level handler typically checks whether the event was already handled, and if not, it marks the event as handled and dispatches to the user-level event handler (such as #mouseDown:).
See also Morphic Event Handling.