JDK-4799136 : Type-ahead not queueing/working properly
Type:Bug
Component:client-libs
Sub-Component:java.awt
Affected Version:1.4.1
Priority:P4
Status:Resolved
Resolution:Fixed
OS:generic,windows_xp
CPU:generic
Submitted:2003-01-06
Updated:2010-08-11
Resolved:2003-05-25
The Version table provides details related to the release that this issue/RFE will be addressed.
Unresolved : Release in which this issue/RFE will be addressed. Resolved: Release in which this issue/RFE has been resolved. Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.
There is not way currently, to queue key events and have them sent to the following focusable component.
Comments
CONVERTED DATA
BugTraq+ Release Management Values
COMMIT TO FIX:
tiger
FIXED IN:
tiger
INTEGRATED IN:
tiger
tiger-b08
24-08-2004
WORK AROUND
None
24-08-2004
SUGGESTED FIX
--- DefaultKeyboardFocusManager.java
***************
*** 50,55 ****
--- 50,58 ----
this.after = after;
this.untilFocused = untilFocused;
}
+ public String toString() {
+ return ">>> Marker after " + after + " on " + untilFocused;
+ }
}
private Window getOwningFrameDialog(Window window) {
***************
*** 686,696 ****
private void pumpApprovedKeyEvents() {
KeyEvent ke;
- if (requestCount() == 0) {
- synchronized(this) {
- typeAheadMarkers.clear();
- }
- }
do {
ke = null;
synchronized (this) {
--- 689,694 ----
***************
*** 713,718 ****
--- 711,731 ----
}
} while (ke != null);
}
+
+ void dumpMarkers() {
+ System.err.println(">>> Markers dump, time: " + System.currentTimeMillis());
+ synchronized (this) {
+ if (typeAheadMarkers.size() != 0) {
+ Iterator iter = typeAheadMarkers.iterator();
+ while (iter.hasNext()) {
+ TypeAheadMarker marker = (TypeAheadMarker)iter.next();
+ System.err.println(marker);
+ }
+ }
+ }
+ System.err.println("");
+ }
+
private boolean typeAheadAssertions(Component target, AWTEvent e) {
// Clear any pending events here as well as in the FOCUS_GAINED
***************
*** 742,770 ****
}
case FocusEvent.FOCUS_GAINED:
! // Search the marker list for the first marker tied to the
! // Component which just gained focus. Then remove that marker
! // and any markers which immediately follow and are tied to
! // the same Component. This handles the case where multiple
! // focus requests were made for the same Component in a row.
! // Since FOCUS_GAINED events will not be generated for these
! // additional requests, we need to clear those markers too.
synchronized (this) {
boolean found = false;
! for (Iterator iter = typeAheadMarkers.iterator();
! iter.hasNext(); )
! {
! if (((TypeAheadMarker)iter.next()).untilFocused ==
! target)
! {
iter.remove();
! found = true;
! } else if (found) {
! break;
! }
! }
}
!
redispatchEvent(target, e);
// Now, dispatch any pending KeyEvents which have been
--- 755,789 ----
}
case FocusEvent.FOCUS_GAINED:
!
! // Search the marker list for the first marker tied to
! // the Component which just gained focus. Then remove
! // that marker, any markers which immediately follow
! // and are tied to the same component, and all markers
! // that preceed it. This handles the case where
! // multiple focus requests were made for the same
! // Component in a row and when we lost some of the
! // earlier requests. Since FOCUS_GAINED events will
! // not be generated for these additional requests, we
! // need to clear those markers too.
synchronized (this) {
boolean found = false;
! if (hasMarker(target)) {
! for (Iterator iter = typeAheadMarkers.iterator();
! iter.hasNext(); )
! {
! if (((TypeAheadMarker)iter.next()).untilFocused ==
! target)
! {
! found = true;
! } else if (found) {
! break;
! }
iter.remove();
! }
! }
}
!
redispatchEvent(target, e);
// Now, dispatch any pending KeyEvents which have been
***************
*** 778,783 ****
--- 797,827 ----
return true;
}
}
+
+ /**
+ * Returns true if there are some marker associated with component <code>comp</code>
+ * in a markers' queue
+ * @since 1.5
+ */
+ private boolean hasMarker(Component comp) {
+ for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
+ if (((TypeAheadMarker)iter.next()).untilFocused == comp) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Clears markers queue
+ * @since 1.5
+ */
+ void clearMarkers() {
+ synchronized(this) {
+ typeAheadMarkers.clear();
+ }
+ }
+
private boolean preDispatchKeyEvent(KeyEvent ke) {
Component focusOwner = getFocusOwner();
ke.setSource(((focusOwner != null) ? focusOwner
--- Dialog.java
***************
*** 520,585 ****
// Event dispatch thread of this app context will be sleeping until
// we wake it by any event from hideAndDisposeHandler().
showAppContext = AppContext.getAppContext();
! if (conditionalShow()) {
! // We have two mechanisms for blocking: 1. If we're on the
! // EventDispatchThread, start a new event pump. 2. If we're
! // on any other thread, call wait() on the treelock.
! // keep the KeyEvents from being dispatched
! // until the focus has been transfered
! long time = Toolkit.getEventQueue().getMostRecentEventTime();
! Component predictedFocusOwner = getMostRecentFocusOwner();
! KeyboardFocusManager.getCurrentKeyboardFocusManager().
! enqueueKeyEvents(time, predictedFocusOwner);
! Runnable pumpEventsForHierarchy = new Runnable() {
! public void run() {
! EventDispatchThread dispatchThread =
! (EventDispatchThread)Thread.currentThread();
! dispatchThread.pumpEventsForHierarchy(new Conditional() {
! public boolean evaluate() {
! return keepBlocking && windowClosingException == null;
! }
! }, Dialog.this);
! }
! };
!
! if (EventQueue.isDispatchThread()) {
! /*
! * dispose SequencedEvent we are dispatching on current
! * AppContext, to prevent us from hang.
*
* BugId 4531693 (###@###.###)
*/
! SequencedEvent currentSequencedEvent = KeyboardFocusManager.
! getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
! if (currentSequencedEvent != null) {
! currentSequencedEvent.dispose();
! }
! pumpEventsForHierarchy.run();
! } else {
! synchronized (getTreeLock()) {
! Toolkit.getEventQueue().
! postEvent(new PeerEvent(this,
! pumpEventsForHierarchy,
! PeerEvent.PRIORITY_EVENT));
! while (keepBlocking && windowClosingException == null) {
! try {
! getTreeLock().wait();
! } catch (InterruptedException e) {
! break;
}
}
}
}
KeyboardFocusManager.getCurrentKeyboardFocusManager().
dequeueKeyEvents(time, predictedFocusOwner);
- if (windowClosingException != null) {
- windowClosingException.fillInStackTrace();
- throw windowClosingException;
- }
}
}
}
--- 520,589 ----
// Event dispatch thread of this app context will be sleeping until
// we wake it by any event from hideAndDisposeHandler().
showAppContext = AppContext.getAppContext();
+
+ // keep the KeyEvents from being dispatched
+ // until the focus has been transfered
+ long time = Toolkit.getEventQueue().getMostRecentEventTime();
+ Component predictedFocusOwner = getMostRecentFocusOwner();
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().
+ enqueueKeyEvents(time, predictedFocusOwner);
! try {
! if (conditionalShow()) {
! // We have two mechanisms for blocking: 1. If we're on the
! // EventDispatchThread, start a new event pump. 2. If we're
! // on any other thread, call wait() on the treelock.
! Runnable pumpEventsForHierarchy = new Runnable() {
! public void run() {
! EventDispatchThread dispatchThread =
! (EventDispatchThread)Thread.currentThread();
! dispatchThread.pumpEventsForHierarchy(new Conditional() {
! public boolean evaluate() {
! return keepBlocking && windowClosingException == null;
! }
! }, Dialog.this);
! }
! };
! if (EventQueue.isDispatchThread()) {
! /*
! * dispose SequencedEvent we are dispatching on current
! * AppContext, to prevent us from hang.
*
* BugId 4531693 (###@###.###)
*/
! SequencedEvent currentSequencedEvent = KeyboardFocusManager.
! getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
! if (currentSequencedEvent != null) {
! currentSequencedEvent.dispose();
! }
! pumpEventsForHierarchy.run();
! } else {
! synchronized (getTreeLock()) {
! Toolkit.getEventQueue().
! postEvent(new PeerEvent(this,
! pumpEventsForHierarchy,
! PeerEvent.PRIORITY_EVENT));
! while (keepBlocking && windowClosingException == null) {
! try {
! getTreeLock().wait();
! } catch (InterruptedException e) {
! break;
! }
}
}
}
+ if (windowClosingException != null) {
+ windowClosingException.fillInStackTrace();
+ throw windowClosingException;
+ }
}
+ } finally {
+ // Restore normal key event dispatching
KeyboardFocusManager.getCurrentKeyboardFocusManager().
dequeueKeyEvents(time, predictedFocusOwner);
}
}
}
--- KeyboardFocusManager.java
***************
*** 1913,1918 ****
--- 1913,1930 ----
}
}
+ void dumpRequests() {
+ System.err.println(">>> Requests dump, time: " + System.currentTimeMillis());
+ synchronized (heavyweightRequests) {
+ Iterator iter = heavyweightRequests.iterator();
+ while (iter.hasNext()) {
+ HeavyweightFocusRequest req = (HeavyweightFocusRequest)iter.next();
+ System.err.println(">>> Req: " + req);
+ }
+ }
+ System.err.println("");
+ }
+
private static final class LightweightFocusRequest {
final Component component;
final boolean temporary;
***************
*** 2013,2022 ****
private static boolean clearingCurrentLightweightRequests;
private static Component newFocusOwner = null;
- int requestCount() {
- return heavyweightRequests.size();
- }
-
static final int SNFH_FAILURE = 0;
static final int SNFH_SUCCESS_HANDLED = 1;
static final int SNFH_SUCCESS_PROCEED = 2;
--- 2025,2030 ----
***************
*** 2624,2629 ****
--- 2632,2646 ----
return event;
}
+ /**
+ * Clears markers queue
+ * This method is not intended to be overridden by KFM's.
+ * Only DefaultKeyboardFocusManager can implement it.
+ * @since 1.5
+ */
+ void clearMarkers() {
+ }
+
static boolean removeFirstRequest() {
KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
***************
*** 2646,2651 ****
--- 2663,2673 ----
}
}
}
+ // Fix for 4799136 - clear type-ahead markers if requests queue is empty
+ // We do it here because this method is called only when problems happen
+ if (heavyweightRequests.size() == 0) {
+ manager.clearMarkers();
+ }
return (heavyweightRequests.size() > 0);
}
}
***************
*** 2654,2659 ****
--- 2676,2683 ----
dbg.assertion(heavyweight != null);
}
+ KeyboardFocusManager manager =
+ KeyboardFocusManager.getCurrentKeyboardFocusManager();
synchronized(heavyweightRequests) {
HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest)
((heavyweightRequests.size() > 0)
***************
*** 2660,2758 ****
? heavyweightRequests.getLast() : null);
if (hwFocusRequest != null &&
hwFocusRequest.heavyweight == heavyweight) {
! heavyweightRequests.removeLast();
}
! }
! }
! static void removeFocusRequest(Component component) {
! if (dbg.on) {
! dbg.assertion(component != null);
! }
!
!
24-08-2004
SUGGESTED FIX
Component heavyweight = (component.peer instanceof LightweightPeer)
! ? component.getNativeContainer() : component;
! if (heavyweight == null) {
! return;
! }
!
! synchronized (heavyweightRequests) {
! if ((currentLightweightRequests != null) &&
! (currentLightweightRequests.size() > 0)) {
! LightweightFocusRequest lwFocusRequest =
! (LightweightFocusRequest)currentLightweightRequests.getFirst();
! Component comp = lwFocusRequest.component;
! Component currentHeavyweight =
! (comp.peer instanceof LightweightPeer)
! ? comp.getNativeContainer() : comp;
!
! if (currentHeavyweight == component) {
! currentLightweightRequests = null;
! } else {
! for (Iterator iter = currentLightweightRequests.iterator();
! iter.hasNext(); ) {
! if (((LightweightFocusRequest)iter.next()).
! component == component)
! {
! iter.remove();
! }
! }
! if (currentLightweightRequests.size() == 0) {
! currentLightweightRequests = null;
! }
! }
}
- for (Iterator iter = heavyweightRequests.iterator();
- iter.hasNext(); )
- {
- HeavyweightFocusRequest hwFocusRequest =
- (HeavyweightFocusRequest)iter.next();
- if (hwFocusRequest.heavyweight == heavyweight) {
- if (heavyweight == component) {
- iter.remove();
- continue;
- }
- for (Iterator lwIter = hwFocusRequest.lightweightRequests.
- iterator();
- lwIter.hasNext(); )
- {
- if (((LightweightFocusRequest)lwIter.next()).
- component == component)
- {
- lwIter.remove();
- }
- }
- if (hwFocusRequest.lightweightRequests.size() == 0) {
- iter.remove();
- }
- }
- }
}
}
- private static void clearFocusRequestList() {
- KeyboardFocusManager manager =
- KeyboardFocusManager.getCurrentKeyboardFocusManager();
-
- synchronized (heavyweightRequests) {
- for (Iterator iter = heavyweightRequests.iterator();
- iter.hasNext(); )
- {
- HeavyweightFocusRequest hwFocusRequest =
- (HeavyweightFocusRequest)iter.next();
- if (hwFocusRequest.lightweightRequests == null) {
- continue;
- }
- for (Iterator lwIter = hwFocusRequest.lightweightRequests.
- iterator();
- lwIter.hasNext(); )
- {
- manager.dequeueKeyEvents
- (-1, ((LightweightFocusRequest)lwIter.next()).
- component);
- }
- }
- heavyweightRequests.clear();
- }
- }
private static boolean focusedWindowChanged(Component a, Component b) {
Window wa = getContainingWindow(a);
Window wb = getContainingWindow(b);
--- 2684,2698 ----
? heavyweightRequests.getLast() : null);
if (hwFocusRequest != null &&
hwFocusRequest.heavyweight == heavyweight) {
! Component comp = (Component) heavyweightRequests.removeLast();
}
! // Fix for 4799136 - clear type-ahead markers if requests queue is empty
! // We do it here because this method is called only when problems happen
! if (heavyweightRequests.size() == 0) {
! manager.clearMarkers();
}
}
}
private static boolean focusedWindowChanged(Component a, Component b) {
Window wa = getContainingWindow(a);
Window wb = getContainingWindow(b);
***************
*** 2761,2766 ****
--- 2701,2707 ----
}
return (wa != wb);
}
+
static Window getContainingWindow(Component comp) {
while (comp != null && !(comp instanceof Window)) {
comp = comp.getParent();
***************
*** 2768,2773 ****
--- 2709,2715 ----
return (Window)comp;
}
+
private static Component getHeavyweight(Component comp) {
if (comp == null || comp.getPeer() == null) {
return null;
Name: dmR10075 Date: 04/21/2003
Additional fix for special handling of FOCUS_LOST
***************
*** 2569,2575 ****
return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST,
temporary, lwFocusRequest.component);
! }
return retargetUnexpectedFocusEvent(fe);
} // end synchronized(heavyweightRequests)
--- 2580,2595 ----
return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST,
temporary, lwFocusRequest.component);
! } else if (focusedWindowChanged(opposite, currentFocusOwner)) {
! // If top-level changed there might be no focus request in a list
! // But we know the opposite, we now it is temporary - dispatch the event.
! if (!fe.isTemporary()) {
! // Create copy of the event with only difference in temporary parameter.
! fe = new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST,
! true, opposite);
! }
! return fe;
! }
return retargetUnexpectedFocusEvent(fe);
} // end synchronized(heavyweightRequests)
###@###.### 2003-04-21
======================================================================
21-04-2003
EVALUATION
This bug seems to be duplicate of the 4696733 - the partial fix for this bug is the same as in that bug. However, till final resolution and till we have normal fix I'll keep them both active.
###@###.### 2003-01-10
Name: dmR10075 Date: 04/07/2003
There is an error in Dialog.show() which might cause race between thread which calls
show() and EDT thread. Code in show() call conditionalShow() which shows window on the
screen then call enqueueKeyEvents which initiates type-ahead queueing but between these
two calls EDT could have processed initial focus for dialog and there will be no more
focus event to resolve type-ahead markers.
###@###.### 2003-04-07
======================================================================
Name: dmR10075 Date: 04/15/2003
We need to remove the fix for 4465508 but we should replace it with less agressive
synchronization because some synchronization is still required - sometimes focus events
arrive in the order we don't expect and we clear requests list therefore we should
clear type-ahead queue as well.
###@###.### 2003-04-15
======================================================================
Name: dmR10075 Date: 04/15/2003
I found that we constantly clear focus requests queue when we receive WINDOW_LOST_FOCUS
event during cross-toplevel focus transfer. This doesn't prevent us from dispatching
focus events but this also clears type-ahead queue so we need to reevaluate conditions
when we clear requests list. In this particular case I decided to detect whether or not
FOCUS_LOST arrives as the results of cross-toplevel transfer(it has opposite in another
top-level) and if it is so just dispatch.
###@###.### 2003-04-15
======================================================================