src/share/classes/java/awt/DefaultKeyboardFocusManager.java

Print this page




  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)