-
Bug
-
Resolution: Not an Issue
-
P2
-
None
-
1.1.6
-
x86, sparc
-
solaris_2.5.1, windows_nt
It is not possible to call
requestFocus()
on two different components in response to the same event without completely
screwing up AWT's notion of the focused component. Unfortunately, EWT needs
to be able to do this in a few different places (eg. in a editable Grid,
clicking on a cell first calls requestFocus() on the Grid, then on the
cell editor). This also currently effects lightweight windows due to some
focus management code which gets called when activating a window.
(EWT is a lightweight components graphics library)
More details:
Here's our understanding of the JDK 1.1.6 focus problems:
Apparently JavaSoft has decided to change focus event delivery for
lightweight components to be asynchronous (focus events are now queued
instead of dispatched synchronously).
- The focused component is redundantly stored in both the Window and the
LightweightDispatcher (one of these per heavy weight component).
- When a lightweight component requests the focus, this request is
propagated to the nearest LightweightDispatcher above the lightweight
component via Container.proxyRequestFocus().
- This results in a call to LightweightDispatcher.setFocusRequest() for
the requesting lightweight component.
- In setFocusRequest(), the Window's focus owner is retrieved via
Window.getFocusOwner(). (This just returns the Window's stored focus
owner.)
- If the window's focus owner matches the lightweight dispatcher's
focus owner, the lightweight dispatcher queues focus lost/gained events
for the old/new focus components and sets its focus owner to the new
focus component. The Window is not updated immediately - it will update
its focus owner when it receives the focus gained event for the new
focus component (this now happens asynchronously).
In most cases, this works out ok. However, since the lightweight
dispatcher's focus component is updated synchronously and the Window's
focus component is updated asynchronously, it is easy for these two
values to become out of sync. In this case, the Lightweight
dispatcher refuses to change the focus, as it seems that a
prerequestite for a focus change to take place is that the
LightweightDispatcher's focus component must be equal to the Window's
focus component. We get into this state when the focus is requested
on two different components while processing a single event.
This problem is easily reproduced with an editable Grid. On a mouse
press, two things happen:
- The Grid requests the focus to itself,
and then, when startCellEdit() is called
- The Grid requests the focus to move the the cell editor
Both of these focus changes occur in response to the same mouse
pressed event.
After the first call to request focus (on the Grid), AWT is in the
following state:
- LightweightDispatcher's focus == Grid
- Window's focus == the old focus owner - whatever used to have the focus
- FOCUS_LOST/FOCUS_GAINED events are posted at the front of the EventQueue
Now, when we call requestFocus() on the editor component, the
LightweightDispatcher checks to see whether its focus component
matches the Window's focus component. Since the event dispatcher has
not had a chance to deliver the focus change events to the Window (how
could it? we are doing all of this processing in the event dispatcher
thread in response to a single mouse event.), this test fails and the
focus is not updated. (Actually, in this case the
LightweightDispatcher quietly updates its own focus owner to the
requesting component, but no focus events are generated and the Window
never finds out about the change.)
I haven't been able to come up with any generic work around for this
problem. We may be able to work around the problem on a case by case
basis by eliminating cases where requestFocus() is called on two
different components in response to a single event. For example, we
can update the Grid such that it does not immediately call
requestFocus on its editor component, but instead defers this until it
receives a FOCUS_GAINED event. This approach only works if we know
which component is supposed to have the focus and we are sure that a
focus gained event is pending. We can probably apply the same work
around to other cases, but I think it is going to be very hard to get
everything right. Basically, this means looking at *every* call to
requestFocus() in both EWT code and client code and deciding whether
it may be called in a thread for which requestFocus() has already been
called on another component.
As far as a fix for JavaSoft... I don't think there is a trivial
solution. Basically they need to make sure that their
LightweightDispatcher and Window stay in sync, which means changing
the way their focus events are dispatched. See also 4131761.
---------------------------------------------------------------
Test case is attached. It can also be found in
~mrm/Oracle/bugs/jdk/4138263
marianne.mueller@Eng 1998-06-09
------------------------------------------------------------------------------
requestFocus()
on two different components in response to the same event without completely
screwing up AWT's notion of the focused component. Unfortunately, EWT needs
to be able to do this in a few different places (eg. in a editable Grid,
clicking on a cell first calls requestFocus() on the Grid, then on the
cell editor). This also currently effects lightweight windows due to some
focus management code which gets called when activating a window.
(EWT is a lightweight components graphics library)
More details:
Here's our understanding of the JDK 1.1.6 focus problems:
Apparently JavaSoft has decided to change focus event delivery for
lightweight components to be asynchronous (focus events are now queued
instead of dispatched synchronously).
- The focused component is redundantly stored in both the Window and the
LightweightDispatcher (one of these per heavy weight component).
- When a lightweight component requests the focus, this request is
propagated to the nearest LightweightDispatcher above the lightweight
component via Container.proxyRequestFocus().
- This results in a call to LightweightDispatcher.setFocusRequest() for
the requesting lightweight component.
- In setFocusRequest(), the Window's focus owner is retrieved via
Window.getFocusOwner(). (This just returns the Window's stored focus
owner.)
- If the window's focus owner matches the lightweight dispatcher's
focus owner, the lightweight dispatcher queues focus lost/gained events
for the old/new focus components and sets its focus owner to the new
focus component. The Window is not updated immediately - it will update
its focus owner when it receives the focus gained event for the new
focus component (this now happens asynchronously).
In most cases, this works out ok. However, since the lightweight
dispatcher's focus component is updated synchronously and the Window's
focus component is updated asynchronously, it is easy for these two
values to become out of sync. In this case, the Lightweight
dispatcher refuses to change the focus, as it seems that a
prerequestite for a focus change to take place is that the
LightweightDispatcher's focus component must be equal to the Window's
focus component. We get into this state when the focus is requested
on two different components while processing a single event.
This problem is easily reproduced with an editable Grid. On a mouse
press, two things happen:
- The Grid requests the focus to itself,
and then, when startCellEdit() is called
- The Grid requests the focus to move the the cell editor
Both of these focus changes occur in response to the same mouse
pressed event.
After the first call to request focus (on the Grid), AWT is in the
following state:
- LightweightDispatcher's focus == Grid
- Window's focus == the old focus owner - whatever used to have the focus
- FOCUS_LOST/FOCUS_GAINED events are posted at the front of the EventQueue
Now, when we call requestFocus() on the editor component, the
LightweightDispatcher checks to see whether its focus component
matches the Window's focus component. Since the event dispatcher has
not had a chance to deliver the focus change events to the Window (how
could it? we are doing all of this processing in the event dispatcher
thread in response to a single mouse event.), this test fails and the
focus is not updated. (Actually, in this case the
LightweightDispatcher quietly updates its own focus owner to the
requesting component, but no focus events are generated and the Window
never finds out about the change.)
I haven't been able to come up with any generic work around for this
problem. We may be able to work around the problem on a case by case
basis by eliminating cases where requestFocus() is called on two
different components in response to a single event. For example, we
can update the Grid such that it does not immediately call
requestFocus on its editor component, but instead defers this until it
receives a FOCUS_GAINED event. This approach only works if we know
which component is supposed to have the focus and we are sure that a
focus gained event is pending. We can probably apply the same work
around to other cases, but I think it is going to be very hard to get
everything right. Basically, this means looking at *every* call to
requestFocus() in both EWT code and client code and deciding whether
it may be called in a thread for which requestFocus() has already been
called on another component.
As far as a fix for JavaSoft... I don't think there is a trivial
solution. Basically they need to make sure that their
LightweightDispatcher and Window stay in sync, which means changing
the way their focus events are dispatched. See also 4131761.
---------------------------------------------------------------
Test case is attached. It can also be found in
~mrm/Oracle/bugs/jdk/4138263
marianne.mueller@Eng 1998-06-09
------------------------------------------------------------------------------
- relates to
-
JDK-4131761 What is the correct focusing behavior
-
- Closed
-