Hi Sven,
First off, some observations:
1) When a property of a Component changes, the corresponding setProperty
method of the Component object IS called. E.g. selecting Choice item
WILL result in a call to Choice.select(index) method.
(Test: Overload the setProperty method)
Makes perfect sense.
2) The above call is done from the event dispatch thread.
(Test: Print Toolkit.getSystemEventQueue().isDispatchThread() )
3) The call is from the peer handleEvent and NOT from the peer
dispatchEventImpl. The latter must also always call
super.dispatchEventImpl for the former to be called.
(Test: Construct your own event and send it to EventQueue.postEvent(ie)
fake events are passed on to listeners but do not change the state of
the Component or its peer.)
An example of where this is wrong is the current version of Checkbox.
You certainly mean Component dispatchEventImpl() and not peer
dispatchEventImpl(). And yes, ComponentPeer.handleEvent() is called from
Component.dispatchEventImpl(), so the subclass dispatchEventImpl() must
call super.
4) The Component-subclass's processEvent/processXXXEvent methods are
only called if the class has listeners (this much we seem to do right)
(Test: Overload processEvent)
Yep, this is what we do, but not in all cases correctly. The processXXX
methods are called if the component has the corresponding listener OR
has the event enabled vie enableEvents(). Internally we also should
check if a certain event type is enabled in the Toolkit and dispatch the
event to the toolkit in that case.
5) The initial setting-up of the native state (on creating the peer)
does not trigger any events. (Test: Add a listener). (the obvious
paint events, etc are exceptions of course)
Hmm ok.
So, how this works is that the peer keeps track of the native state,
and what happens is:
Case 1: The user clicks on something, changing the native state. A
callback to the peer occurs, and if the state has changed, the peer
updates its state and posts an event. This event is then executed
by the event dispatch thread, calling the peer handleEvent() method.
The peer handleEvent method checks if it's an event specific
to its peer type (or delegates it to super.handleEvent), and then, if
the owner's state needs updating, it calls its setProperty() method.
Case 2: The program calls Component.setProperty(). If the property
isn't changed, do nothing. Otherwise, set the property and call the peer
setProperty() method. This triggers a callback and posts an event, but
in this case the peer handleEvent() method does NOT call the owner's
setProperty() method a second time since the owner's state does not need
updating.
Case 3: Somebody sticks in a bogus event in the event queue. The peer
handleEvent() method does not call its owner's setProperty() method
because its state does not need updating.
We should add these observations to the Wiki somewhere (developer
guidelines or so).
So our behaviour here goes from broken, to almost-right to completely
wrong (although a bit functional). But we need to strive to do this
stuff the Right way. All this behaviour is testable, and by testable
I mean you can write a program that relys on it. Which means that this
is a compatibility problem.
I fully agree. I myself observed a couple of other problems inside AWT
that were related to event dispatching (see my focus and
Component/Container patches). There's still plenty to do here...
/Roman