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.

To download the current JDK release, click here.
Other
5.0 tigerFixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
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 ======================================================================
15-04-2003