23 * questions. 24 */ 25 package java.awt; 26 27 import java.awt.event.FocusEvent; 28 import java.awt.event.KeyEvent; 29 import java.awt.event.WindowEvent; 30 import java.awt.peer.ComponentPeer; 31 import java.awt.peer.LightweightPeer; 32 import java.lang.ref.WeakReference; 33 import java.util.LinkedList; 34 import java.util.Iterator; 35 import java.util.ListIterator; 36 import java.util.Set; 37 38 import sun.util.logging.PlatformLogger; 39 40 import sun.awt.AppContext; 41 import sun.awt.SunToolkit; 42 import sun.awt.CausedFocusEvent; 43 44 /** 45 * The default KeyboardFocusManager for AWT applications. Focus traversal is 46 * done in response to a Component's focus traversal keys, and using a 47 * Container's FocusTraversalPolicy. 48 * <p> 49 * Please see 50 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html"> 51 * How to Use the Focus Subsystem</a>, 52 * a section in <em>The Java Tutorial</em>, and the 53 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a> 54 * for more information. 55 * 56 * @author David Mendenhall 57 * 58 * @see FocusTraversalPolicy 59 * @see Component#setFocusTraversalKeys 60 * @see Component#getFocusTraversalKeys 61 * @since 1.4 62 */ 63 public class DefaultKeyboardFocusManager extends KeyboardFocusManager { 64 private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.DefaultKeyboardFocusManager"); 65 66 // null weak references to not create too many objects 67 private static final WeakReference<Window> NULL_WINDOW_WR = 68 new WeakReference<Window>(null); 69 private static final WeakReference<Component> NULL_COMPONENT_WR = 70 new WeakReference<Component>(null); 71 private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR; 72 private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR; 73 private int inSendMessage; 74 private LinkedList enqueuedKeyEvents = new LinkedList(), 75 typeAheadMarkers = new LinkedList(); 76 private boolean consumeNextKeyTyped; 77 78 private static class TypeAheadMarker { 79 long after; 80 Component untilFocused; 81 82 TypeAheadMarker(long after, Component untilFocused) { 83 this.after = after; 84 this.untilFocused = untilFocused; 85 } 86 /** 87 * Returns string representation of the marker 88 */ 89 public String toString() { 90 return ">>> Marker after " + after + " on " + untilFocused; 91 } 92 } 93 94 private Window getOwningFrameDialog(Window window) { 95 while (window != null && !(window instanceof Frame || 242 edt.pumpEvents(SentEvent.ID, new Conditional() { 243 public boolean evaluate() { 244 return !se.dispatched && !targetAppContext.isDisposed(); 245 } 246 }); 247 } else { 248 synchronized (se) { 249 while (!se.dispatched && !targetAppContext.isDisposed()) { 250 try { 251 se.wait(1000); 252 } catch (InterruptedException ie) { 253 break; 254 } 255 } 256 } 257 } 258 } 259 return se.dispatched; 260 } 261 262 /** 263 * This method is called by the AWT event dispatcher requesting that the 264 * current KeyboardFocusManager dispatch the specified event on its behalf. 265 * DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents 266 * related to focus, and all KeyEvents. These events are dispatched based 267 * on the KeyboardFocusManager's notion of the focus owner and the focused 268 * and active Windows, sometimes overriding the source of the specified 269 * AWTEvent. If this method returns <code>false</code>, then the AWT event 270 * dispatcher will attempt to dispatch the event itself. 271 * 272 * @param e the AWTEvent to be dispatched 273 * @return <code>true</code> if this method dispatched the event; 274 * <code>false</code> otherwise 275 */ 276 public boolean dispatchEvent(AWTEvent e) { 277 if (focusLog.isLoggable(PlatformLogger.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) focusLog.fine("" + e); 278 switch (e.getID()) { 279 case WindowEvent.WINDOW_GAINED_FOCUS: { 280 WindowEvent we = (WindowEvent)e; 281 Window oldFocusedWindow = getGlobalFocusedWindow(); 282 Window newFocusedWindow = we.getWindow(); 283 if (newFocusedWindow == oldFocusedWindow) { 284 break; 285 } 286 287 if (!(newFocusedWindow.isFocusableWindow() 288 && newFocusedWindow.isVisible() 289 && newFocusedWindow.isDisplayable())) 290 { 291 // we can not accept focus on such window, so reject it. 292 restoreFocus(we); 293 break; 294 } 295 // If there exists a current focused window, then notify it 296 // that it has lost focus. 297 if (oldFocusedWindow != null) { 298 boolean isEventDispatched = 299 sendMessage(oldFocusedWindow, 619 } 620 621 if (currentActiveWindow != e.getSource()) { 622 // The event is lost in time. 623 // Allow listeners to precess the event but do not 624 // change any global states 625 break; 626 } 627 628 setGlobalActiveWindow(null); 629 if (getGlobalActiveWindow() != null) { 630 // Activation change was rejected. Unlikely, but possible. 631 break; 632 } 633 634 we.setSource(currentActiveWindow); 635 return typeAheadAssertions(currentActiveWindow, we); 636 } 637 638 case WindowEvent.WINDOW_LOST_FOCUS: { 639 WindowEvent we = (WindowEvent)e; 640 Window currentFocusedWindow = getGlobalFocusedWindow(); 641 Window losingFocusWindow = we.getWindow(); 642 Window activeWindow = getGlobalActiveWindow(); 643 Window oppositeWindow = we.getOppositeWindow(); 644 if (focusLog.isLoggable(PlatformLogger.FINE)) 645 focusLog.fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}", 646 activeWindow, currentFocusedWindow, 647 losingFocusWindow, oppositeWindow); 648 if (currentFocusedWindow == null) { 649 break; 650 } 651 652 // Special case -- if the native windowing system posts an 653 // event claiming that the active Window has lost focus to the 654 // focused Window, then discard the event. This is an artifact 655 // of the native windowing system not knowing which Window is 656 // really focused. 657 if (inSendMessage == 0 && losingFocusWindow == activeWindow && 658 oppositeWindow == currentFocusedWindow) | 23 * questions. 24 */ 25 package java.awt; 26 27 import java.awt.event.FocusEvent; 28 import java.awt.event.KeyEvent; 29 import java.awt.event.WindowEvent; 30 import java.awt.peer.ComponentPeer; 31 import java.awt.peer.LightweightPeer; 32 import java.lang.ref.WeakReference; 33 import java.util.LinkedList; 34 import java.util.Iterator; 35 import java.util.ListIterator; 36 import java.util.Set; 37 38 import sun.util.logging.PlatformLogger; 39 40 import sun.awt.AppContext; 41 import sun.awt.SunToolkit; 42 import sun.awt.CausedFocusEvent; 43 import sun.awt.TimedWindowEvent; 44 45 /** 46 * The default KeyboardFocusManager for AWT applications. Focus traversal is 47 * done in response to a Component's focus traversal keys, and using a 48 * Container's FocusTraversalPolicy. 49 * <p> 50 * Please see 51 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html"> 52 * How to Use the Focus Subsystem</a>, 53 * a section in <em>The Java Tutorial</em>, and the 54 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a> 55 * for more information. 56 * 57 * @author David Mendenhall 58 * 59 * @see FocusTraversalPolicy 60 * @see Component#setFocusTraversalKeys 61 * @see Component#getFocusTraversalKeys 62 * @since 1.4 63 */ 64 public class DefaultKeyboardFocusManager extends KeyboardFocusManager { 65 private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.DefaultKeyboardFocusManager"); 66 67 // null weak references to not create too many objects 68 private static final WeakReference<Window> NULL_WINDOW_WR = 69 new WeakReference<Window>(null); 70 private static final WeakReference<Component> NULL_COMPONENT_WR = 71 new WeakReference<Component>(null); 72 private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR; 73 private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR; 74 private int inSendMessage; 75 private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>(); 76 private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>(); 77 private boolean consumeNextKeyTyped; 78 79 private static class TypeAheadMarker { 80 long after; 81 Component untilFocused; 82 83 TypeAheadMarker(long after, Component untilFocused) { 84 this.after = after; 85 this.untilFocused = untilFocused; 86 } 87 /** 88 * Returns string representation of the marker 89 */ 90 public String toString() { 91 return ">>> Marker after " + after + " on " + untilFocused; 92 } 93 } 94 95 private Window getOwningFrameDialog(Window window) { 96 while (window != null && !(window instanceof Frame || 243 edt.pumpEvents(SentEvent.ID, new Conditional() { 244 public boolean evaluate() { 245 return !se.dispatched && !targetAppContext.isDisposed(); 246 } 247 }); 248 } else { 249 synchronized (se) { 250 while (!se.dispatched && !targetAppContext.isDisposed()) { 251 try { 252 se.wait(1000); 253 } catch (InterruptedException ie) { 254 break; 255 } 256 } 257 } 258 } 259 } 260 return se.dispatched; 261 } 262 263 /* 264 * Checks if the focus window event follows key events waiting in the type-ahead 265 * queue (if any). This may happen when a user types ahead in the window, the client 266 * listeners hang EDT for a while, and the user switches b/w toplevels. In that 267 * case the focus window events may be dispatched before the type-ahead events 268 * get handled. This may lead to wrong focus behavior and in order to avoid it, 269 * the focus window events are reposted to the end of the event queue. See 6981400. 270 */ 271 private boolean repostIfFollowsKeyEvents(WindowEvent e) { 272 if (!(e instanceof TimedWindowEvent)) { 273 return false; 274 } 275 TimedWindowEvent we = (TimedWindowEvent)e; 276 long time = we.getWhen(); 277 synchronized (this) { 278 for (KeyEvent ke: enqueuedKeyEvents) { 279 if (time >= ke.getWhen()) { 280 SunToolkit.postEvent(AppContext.getAppContext(), new SequencedEvent(e)); 281 return true; 282 } 283 } 284 } 285 return false; 286 } 287 288 /** 289 * This method is called by the AWT event dispatcher requesting that the 290 * current KeyboardFocusManager dispatch the specified event on its behalf. 291 * DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents 292 * related to focus, and all KeyEvents. These events are dispatched based 293 * on the KeyboardFocusManager's notion of the focus owner and the focused 294 * and active Windows, sometimes overriding the source of the specified 295 * AWTEvent. If this method returns <code>false</code>, then the AWT event 296 * dispatcher will attempt to dispatch the event itself. 297 * 298 * @param e the AWTEvent to be dispatched 299 * @return <code>true</code> if this method dispatched the event; 300 * <code>false</code> otherwise 301 */ 302 public boolean dispatchEvent(AWTEvent e) { 303 if (focusLog.isLoggable(PlatformLogger.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) focusLog.fine("" + e); 304 switch (e.getID()) { 305 case WindowEvent.WINDOW_GAINED_FOCUS: { 306 if (repostIfFollowsKeyEvents((WindowEvent)e)) { 307 break; 308 } 309 310 WindowEvent we = (WindowEvent)e; 311 Window oldFocusedWindow = getGlobalFocusedWindow(); 312 Window newFocusedWindow = we.getWindow(); 313 if (newFocusedWindow == oldFocusedWindow) { 314 break; 315 } 316 317 if (!(newFocusedWindow.isFocusableWindow() 318 && newFocusedWindow.isVisible() 319 && newFocusedWindow.isDisplayable())) 320 { 321 // we can not accept focus on such window, so reject it. 322 restoreFocus(we); 323 break; 324 } 325 // If there exists a current focused window, then notify it 326 // that it has lost focus. 327 if (oldFocusedWindow != null) { 328 boolean isEventDispatched = 329 sendMessage(oldFocusedWindow, 649 } 650 651 if (currentActiveWindow != e.getSource()) { 652 // The event is lost in time. 653 // Allow listeners to precess the event but do not 654 // change any global states 655 break; 656 } 657 658 setGlobalActiveWindow(null); 659 if (getGlobalActiveWindow() != null) { 660 // Activation change was rejected. Unlikely, but possible. 661 break; 662 } 663 664 we.setSource(currentActiveWindow); 665 return typeAheadAssertions(currentActiveWindow, we); 666 } 667 668 case WindowEvent.WINDOW_LOST_FOCUS: { 669 if (repostIfFollowsKeyEvents((WindowEvent)e)) { 670 break; 671 } 672 673 WindowEvent we = (WindowEvent)e; 674 Window currentFocusedWindow = getGlobalFocusedWindow(); 675 Window losingFocusWindow = we.getWindow(); 676 Window activeWindow = getGlobalActiveWindow(); 677 Window oppositeWindow = we.getOppositeWindow(); 678 if (focusLog.isLoggable(PlatformLogger.FINE)) 679 focusLog.fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}", 680 activeWindow, currentFocusedWindow, 681 losingFocusWindow, oppositeWindow); 682 if (currentFocusedWindow == null) { 683 break; 684 } 685 686 // Special case -- if the native windowing system posts an 687 // event claiming that the active Window has lost focus to the 688 // focused Window, then discard the event. This is an artifact 689 // of the native windowing system not knowing which Window is 690 // really focused. 691 if (inSendMessage == 0 && losingFocusWindow == activeWindow && 692 oppositeWindow == currentFocusedWindow) |