jdk Sdiff src/share/classes/java/awt (original) (raw)
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 *
49 * Please see 50 * 51 * How to Use the Focus Subsystem, 52 * a section in The Java Tutorial, and the 53 * Focus Specification 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 NULL_WINDOW_WR = 68 new WeakReference(null); 69 private static final WeakReference NULL_COMPONENT_WR = 70 new WeakReference(null); 71 private WeakReference realOppositeWindowWR = NULL_WINDOW_WR; 72 private WeakReference 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 false
, then the AWT event
270 * dispatcher will attempt to dispatch the event itself.
271 *
272 * @param e the AWTEvent to be dispatched
273 * @return true
if this method dispatched the event;
274 * false
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)
798 * @see MenuShortcut
799 /
800 public boolean postProcessKeyEvent(KeyEvent e) {
801 if (!e.isConsumed()) {
802 Component target = e.getComponent();
803 Container p = (Container)
804 (target instanceof Container ? target : target.getParent());
805 if (p != null) {
806 p.postProcessKeyEvent(e);
807 }
808 }
809 return true;
810 }
811
812 private void pumpApprovedKeyEvents() {
813 KeyEvent ke;
814 do {
815 ke = null;
816 synchronized (this) {
817 if (enqueuedKeyEvents.size() != 0) {
818 ke = (KeyEvent)enqueuedKeyEvents.getFirst();
819 if (typeAheadMarkers.size() != 0) {
820 TypeAheadMarker marker = (TypeAheadMarker)
821 typeAheadMarkers.getFirst();
822 // Fixed 5064013: may appears that the events have the same time
823 // if (ke.getWhen() >= marker.after) {
824 // The fix is rolled out.
825
826 if (ke.getWhen() > marker.after) {
827 ke = null;
828 }
829 }
830 if (ke != null) {
831 focusLog.finer("Pumping approved event {0}", ke);
832 enqueuedKeyEvents.removeFirst();
833 }
834 }
835 }
836 if (ke != null) {
837 preDispatchKeyEvent(ke);
838 }
839 } while (ke != null);
840 }
841
842 /*
843 * Dumps the list of type-ahead queue markers to stderr
844 /
845 void dumpMarkers() {
846 if (focusLog.isLoggable(PlatformLogger.FINEST)) {
847 focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());
848 synchronized (this) {
849 if (typeAheadMarkers.size() != 0) {
850 Iterator iter = typeAheadMarkers.iterator();
851 while (iter.hasNext()) {
852 TypeAheadMarker marker = (TypeAheadMarker)iter.next();
853 focusLog.finest(" {0}", marker);
854 }
855 }
856 }
857 }
858 }
859
860 private boolean typeAheadAssertions(Component target, AWTEvent e) {
861
862 // Clear any pending events here as well as in the FOCUS_GAINED
863 // handler. We need this call here in case a marker was removed in
864 // response to a call to dequeueKeyEvents.
865 pumpApprovedKeyEvents();
866
867 switch (e.getID()) {
868 case KeyEvent.KEY_TYPED:
869 case KeyEvent.KEY_PRESSED:
870 case KeyEvent.KEY_RELEASED: {
871 KeyEvent ke = (KeyEvent)e;
872 synchronized (this) {
873 if (e.isPosted && typeAheadMarkers.size() != 0) {
874 TypeAheadMarker marker = (TypeAheadMarker)
875 typeAheadMarkers.getFirst();
876 // Fixed 5064013: may appears that the events have the same time
877 // if (ke.getWhen() >= marker.after) {
878 // The fix is rolled out.
879
880 if (ke.getWhen() > marker.after) {
881 focusLog.finer("Storing event {0} because of marker {1}", ke, marker);
882 enqueuedKeyEvents.addLast(ke);
883 return true;
884 }
885 }
886 }
887
888 // KeyEvent was posted before focus change request
889 return preDispatchKeyEvent(ke);
890 }
891
892 case FocusEvent.FOCUS_GAINED:
893 focusLog.finest("Markers before FOCUS_GAINED on {0}", target);
894 dumpMarkers();
895 // Search the marker list for the first marker tied to
896 // the Component which just gained focus. Then remove
897 // that marker, any markers which immediately follow
898 // and are tied to the same component, and all markers
899 // that preceed it. This handles the case where
900 // multiple focus requests were made for the same
901 // Component in a row and when we lost some of the
902 // earlier requests. Since FOCUS_GAINED events will
903 // not be generated for these additional requests, we
904 // need to clear those markers too.
905 synchronized (this) {
906 boolean found = false;
907 if (hasMarker(target)) {
908 for (Iterator iter = typeAheadMarkers.iterator();
909 iter.hasNext(); )
910 {
911 if (((TypeAheadMarker)iter.next()).untilFocused ==
912 target)
913 {
914 found = true;
915 } else if (found) {
916 break;
917 }
918 iter.remove();
919 }
920 } else {
921 // Exception condition - event without marker
922 focusLog.finer("Event without marker {0}", e);
923 }
924 }
925 focusLog.finest("Markers after FOCUS_GAINED");
926 dumpMarkers();
927
928 redispatchEvent(target, e);
929
930 // Now, dispatch any pending KeyEvents which have been
931 // released because of the FOCUS_GAINED event so that we don't
932 // have to wait for another event to be posted to the queue.
933 pumpApprovedKeyEvents();
934 return true;
935
936 default:
937 redispatchEvent(target, e);
938 return true;
939 }
940 }
941
942 /*
943 * Returns true if there are some marker associated with component comp
944 * in a markers' queue
945 * @since 1.5
946 /
947 private boolean hasMarker(Component comp) {
948 for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
949 if (((TypeAheadMarker)iter.next()).untilFocused == comp) {
950 return true;
951 }
952 }
953 return false;
954 }
955
956 /*
957 * Clears markers queue
958 * @since 1.5
959 /
960 void clearMarkers() {
961 synchronized(this) {
962 typeAheadMarkers.clear();
963 }
964 }
965
966 private boolean preDispatchKeyEvent(KeyEvent ke) {
967 if (((AWTEvent) ke).isPosted) {
968 Component focusOwner = getFocusOwner();
969 ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow()));
970 }
971 if (ke.getSource() == null) {
972 return true;
973 }
974
975 // Explicitly set the current event and most recent timestamp here in
976 // addition to the call in Component.dispatchEventImpl. Because
977 // KeyEvents can be delivered in response to a FOCUS_GAINED event, the
978 // current timestamp may be incorrect. We need to set it here so that
979 // KeyEventDispatchers will use the correct time.
980 EventQueue.setCurrentEventAndMostRecentTime(ke);
981
982 /*
983 * Fix for 4495473.
984 * This fix allows to correctly dispatch events when native
985 * event proxying mechanism is active.
986 * If it is active we should redispatch key events after
987 * we detected its correct target.
988 /
989 if (KeyboardFocusManager.isProxyActive(ke)) {
990 Component source = (Component)ke.getSource();
991 Container target = source.getNativeContainer();
992 if (target != null) {
993 ComponentPeer peer = target.getPeer();
994 if (peer != null) {
995 peer.handleEvent(ke);
996 /*
997 * Fix for 4478780 - consume event after it was dispatched by peer.
998 */
999 ke.consume();
1147 *
1148 * @param after timestamp of current event, or the current, system time if
1149 * the current event has no timestamp, or the AWT cannot determine
1150 * which event is currently being handled
1151 * @param untilFocused Component which will receive a FOCUS_GAINED event
1152 * before any pending KeyEvents
1153 * @see #dequeueKeyEvents
1154 * @see #discardKeyEvents
1155 */
1156 protected synchronized void enqueueKeyEvents(long after,
1157 Component untilFocused) {
1158 if (untilFocused == null) {
1159 return;
1160 }
1161
1162 focusLog.finer("Enqueue at {0} for {1}",
1163 after, untilFocused);
1164
1165 int insertionIndex = 0,
1166 i = typeAheadMarkers.size();
1167 ListIterator iter = typeAheadMarkers.listIterator(i);
1168
1169 for (; i > 0; i--) {
1170 TypeAheadMarker marker = (TypeAheadMarker)iter.previous();
1171 if (marker.after <= after) {
1172 insertionIndex = i;
1173 break;
1174 }
1175 }
1176
1177 typeAheadMarkers.add(insertionIndex,
1178 new TypeAheadMarker(after, untilFocused));
1179 }
1180
1181 /**
1182 * Releases for normal dispatching to the current focus owner all
1183 * KeyEvents which were enqueued because of a call to
1184 * enqueueKeyEvents
with the same timestamp and Component.
1185 * If the given timestamp is less than zero, the outstanding enqueue
1186 * request for the given Component with the oldest timestamp (if
1187 * any) should be cancelled.
1188 *
1189 * @param after the timestamp specified in the call to
1190 * enqueueKeyEvents
, or any value < 0
1191 * @param untilFocused the Component specified in the call to
1192 * enqueueKeyEvents
1193 * @see #enqueueKeyEvents
1194 * @see #discardKeyEvents
1195 /
1196 protected synchronized void dequeueKeyEvents(long after,
1197 Component untilFocused) {
1198 if (untilFocused == null) {
1199 return;
1200 }
1201
1202 focusLog.finer("Dequeue at {0} for {1}",
1203 after, untilFocused);
1204
1205 TypeAheadMarker marker;
1206 ListIterator iter = typeAheadMarkers.listIterator
1207 ((after >= 0) ? typeAheadMarkers.size() : 0);
1208
1209 if (after < 0) {
1210 while (iter.hasNext()) {
1211 marker = (TypeAheadMarker)iter.next();
1212 if (marker.untilFocused == untilFocused)
1213 {
1214 iter.remove();
1215 return;
1216 }
1217 }
1218 } else {
1219 while (iter.hasPrevious()) {
1220 marker = (TypeAheadMarker)iter.previous();
1221 if (marker.untilFocused == untilFocused &&
1222 marker.after == after)
1223 {
1224 iter.remove();
1225 return;
1226 }
1227 }
1228 }
1229 }
1230
1231 /**
1232 * Discards all KeyEvents which were enqueued because of one or more calls
1233 * to enqueueKeyEvents
with the specified Component, or one of
1234 * its descendants.
1235 *
1236 * @param comp the Component specified in one or more calls to
1237 * enqueueKeyEvents
, or a parent of such a Component
1238 * @see #enqueueKeyEvents
1239 * @see #dequeueKeyEvents
1240 /
1241 protected synchronized void discardKeyEvents(Component comp) {
1242 if (comp == null) {
1243 return;
1244 }
1245
1246 long start = -1;
1247
1248 for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
1249 TypeAheadMarker marker = (TypeAheadMarker)iter.next();
1250 Component toTest = marker.untilFocused;
1251 boolean match = (toTest == comp);
1252 while (!match && toTest != null && !(toTest instanceof Window)) {
1253 toTest = toTest.getParent();
1254 match = (toTest == comp);
1255 }
1256 if (match) {
1257 if (start < 0) {
1258 start = marker.after;
1259 }
1260 iter.remove();
1261 } else if (start >= 0) {
1262 purgeStampedEvents(start, marker.after);
1263 start = -1;
1264 }
1265 }
1266
1267 purgeStampedEvents(start, -1);
1268 }
1269
1270 // Notes:
1271 // * must be called inside a synchronized block
1272 // * if 'start' is < 0, then this function does nothing
1273 // * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
1274 // queue will be removed
1275 private void purgeStampedEvents(long start, long end) {
1276 if (start < 0) {
1277 return;
1278 }
1279
1280 for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
1281 KeyEvent ke = (KeyEvent)iter.next();
1282 long time = ke.getWhen();
1283
1284 if (start < time && (end < 0 || time <= end)) {
1285 iter.remove();
1286 }
1287
1288 if (end >= 0 && time > end) {
1289 break;
1290 }
1291 }
1292 }
1293
1294 /
1295 * Focuses the Component before aComponent, typically based on a
1296 * FocusTraversalPolicy.
1297 *
1298 * @param aComponent the Component that is the basis for the focus
1299 * traversal operation
1300 * @see FocusTraversalPolicy
1301 * @see Component#transferFocusBackward
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 *
50 * Please see 51 * 52 * How to Use the Focus Subsystem, 53 * a section in The Java Tutorial, and the 54 * Focus Specification 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 NULL_WINDOW_WR = 69 new WeakReference(null); 70 private static final WeakReference NULL_COMPONENT_WR = 71 new WeakReference(null); 72 private WeakReference realOppositeWindowWR = NULL_WINDOW_WR; 73 private WeakReference realOppositeComponentWR = NULL_COMPONENT_WR; 74 private int inSendMessage; 75 private LinkedList enqueuedKeyEvents = new LinkedList(); 76 private LinkedList typeAheadMarkers = new LinkedList(); 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 false
, then the AWT event
296 * dispatcher will attempt to dispatch the event itself.
297 *
298 * @param e the AWTEvent to be dispatched
299 * @return true
if this method dispatched the event;
300 * false
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)
832 * @see MenuShortcut 833 */ 834 public boolean postProcessKeyEvent(KeyEvent e) { 835 if (!e.isConsumed()) { 836 Component target = e.getComponent(); 837 Container p = (Container) 838 (target instanceof Container ? target : target.getParent()); 839 if (p != null) { 840 p.postProcessKeyEvent(e); 841 } 842 } 843 return true; 844 } 845 846 private void pumpApprovedKeyEvents() { 847 KeyEvent ke; 848 do { 849 ke = null; 850 synchronized (this) { 851 if (enqueuedKeyEvents.size() != 0) { 852 ke = enqueuedKeyEvents.getFirst(); 853 if (typeAheadMarkers.size() != 0) { 854 TypeAheadMarker marker = typeAheadMarkers.getFirst();
855 // Fixed 5064013: may appears that the events have the same time 856 // if (ke.getWhen() >= marker.after) { 857 // The fix is rolled out. 858 859 if (ke.getWhen() > marker.after) { 860 ke = null; 861 } 862 } 863 if (ke != null) { 864 focusLog.finer("Pumping approved event {0}", ke); 865 enqueuedKeyEvents.removeFirst(); 866 } 867 } 868 } 869 if (ke != null) { 870 preDispatchKeyEvent(ke); 871 } 872 } while (ke != null); 873 } 874 875 /** 876 * Dumps the list of type-ahead queue markers to stderr 877 */ 878 void dumpMarkers() { 879 if (focusLog.isLoggable(PlatformLogger.FINEST)) { 880 focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis()); 881 synchronized (this) { 882 if (typeAheadMarkers.size() != 0) { 883 Iterator iter = typeAheadMarkers.iterator(); 884 while (iter.hasNext()) { 885 TypeAheadMarker marker = iter.next(); 886 focusLog.finest(" {0}", marker); 887 } 888 } 889 } 890 } 891 } 892 893 private boolean typeAheadAssertions(Component target, AWTEvent e) { 894 895 // Clear any pending events here as well as in the FOCUS_GAINED 896 // handler. We need this call here in case a marker was removed in 897 // response to a call to dequeueKeyEvents. 898 pumpApprovedKeyEvents(); 899 900 switch (e.getID()) { 901 case KeyEvent.KEY_TYPED: 902 case KeyEvent.KEY_PRESSED: 903 case KeyEvent.KEY_RELEASED: { 904 KeyEvent ke = (KeyEvent)e; 905 synchronized (this) { 906 if (e.isPosted && typeAheadMarkers.size() != 0) { 907 TypeAheadMarker marker = typeAheadMarkers.getFirst();
908 // Fixed 5064013: may appears that the events have the same time 909 // if (ke.getWhen() >= marker.after) { 910 // The fix is rolled out. 911 912 if (ke.getWhen() > marker.after) { 913 focusLog.finer("Storing event {0} because of marker {1}", ke, marker); 914 enqueuedKeyEvents.addLast(ke); 915 return true; 916 } 917 } 918 } 919 920 // KeyEvent was posted before focus change request 921 return preDispatchKeyEvent(ke); 922 } 923 924 case FocusEvent.FOCUS_GAINED: 925 focusLog.finest("Markers before FOCUS_GAINED on {0}", target); 926 dumpMarkers(); 927 // Search the marker list for the first marker tied to 928 // the Component which just gained focus. Then remove 929 // that marker, any markers which immediately follow 930 // and are tied to the same component, and all markers 931 // that preceed it. This handles the case where 932 // multiple focus requests were made for the same 933 // Component in a row and when we lost some of the 934 // earlier requests. Since FOCUS_GAINED events will 935 // not be generated for these additional requests, we 936 // need to clear those markers too. 937 synchronized (this) { 938 boolean found = false; 939 if (hasMarker(target)) { 940 for (Iterator iter = typeAheadMarkers.iterator(); 941 iter.hasNext(); ) 942 { 943 if (iter.next().untilFocused == target) {
944 found = true;
945 } else if (found) {
946 break;
947 }
948 iter.remove();
949 }
950 } else {
951 // Exception condition - event without marker
952 focusLog.finer("Event without marker {0}", e);
953 }
954 }
955 focusLog.finest("Markers after FOCUS_GAINED");
956 dumpMarkers();
957
958 redispatchEvent(target, e);
959
960 // Now, dispatch any pending KeyEvents which have been
961 // released because of the FOCUS_GAINED event so that we don't
962 // have to wait for another event to be posted to the queue.
963 pumpApprovedKeyEvents();
964 return true;
965
966 default:
967 redispatchEvent(target, e);
968 return true;
969 }
970 }
971
972 /**
973 * Returns true if there are some marker associated with component comp
974 * in a markers' queue
975 * @since 1.5
976 /
977 private boolean hasMarker(Component comp) {
978 for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
979 if (iter.next().untilFocused == comp) {
980 return true;
981 }
982 }
983 return false;
984 }
985
986 /*
987 * Clears markers queue
988 * @since 1.5
989 */
990 void clearMarkers() {
991 synchronized(this) {
992 typeAheadMarkers.clear();
993 }
994 }
995
996 private boolean preDispatchKeyEvent(KeyEvent ke) {
997 if (((AWTEvent) ke).isPosted) {
998 Component focusOwner = getFocusOwner();
999 ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow()));
1000 }
1001 if (ke.getSource() == null) {
1002 return true;
1003 }
1004
1005 // Explicitly set the key event timestamp here (not in Component.dispatchEventImpl):
1006 // - A key event is anyway passed to this method which starts its actual dispatching.
1007 // - If a key event is put to the type ahead queue, its time stamp should not be registered
1008 // until its dispatching actually starts (by this method).
1009 EventQueue.setCurrentEventAndMostRecentTime(ke); 1010 1011 /** 1012 * Fix for 4495473. 1013 * This fix allows to correctly dispatch events when native 1014 * event proxying mechanism is active. 1015 * If it is active we should redispatch key events after 1016 * we detected its correct target. 1017 / 1018 if (KeyboardFocusManager.isProxyActive(ke)) { 1019 Component source = (Component)ke.getSource(); 1020 Container target = source.getNativeContainer(); 1021 if (target != null) { 1022 ComponentPeer peer = target.getPeer(); 1023 if (peer != null) { 1024 peer.handleEvent(ke); 1025 /* 1026 * Fix for 4478780 - consume event after it was dispatched by peer. 1027 */ 1028 ke.consume();
1176 *
1177 * @param after timestamp of current event, or the current, system time if
1178 * the current event has no timestamp, or the AWT cannot determine
1179 * which event is currently being handled
1180 * @param untilFocused Component which will receive a FOCUS_GAINED event
1181 * before any pending KeyEvents
1182 * @see #dequeueKeyEvents
1183 * @see #discardKeyEvents
1184 */
1185 protected synchronized void enqueueKeyEvents(long after,
1186 Component untilFocused) {
1187 if (untilFocused == null) {
1188 return;
1189 }
1190
1191 focusLog.finer("Enqueue at {0} for {1}",
1192 after, untilFocused);
1193
1194 int insertionIndex = 0,
1195 i = typeAheadMarkers.size();
1196 ListIterator iter = typeAheadMarkers.listIterator(i);
1197
1198 for (; i > 0; i--) {
1199 TypeAheadMarker marker = iter.previous();
1200 if (marker.after <= after) {
1201 insertionIndex = i;
1202 break;
1203 }
1204 }
1205
1206 typeAheadMarkers.add(insertionIndex,
1207 new TypeAheadMarker(after, untilFocused));
1208 }
1209
1210 /**
1211 * Releases for normal dispatching to the current focus owner all
1212 * KeyEvents which were enqueued because of a call to
1213 * enqueueKeyEvents
with the same timestamp and Component.
1214 * If the given timestamp is less than zero, the outstanding enqueue
1215 * request for the given Component with the oldest timestamp (if
1216 * any) should be cancelled.
1217 *
1218 * @param after the timestamp specified in the call to
1219 * enqueueKeyEvents
, or any value < 0
1220 * @param untilFocused the Component specified in the call to
1221 * enqueueKeyEvents
1222 * @see #enqueueKeyEvents
1223 * @see #discardKeyEvents
1224 /
1225 protected synchronized void dequeueKeyEvents(long after,
1226 Component untilFocused) {
1227 if (untilFocused == null) {
1228 return;
1229 }
1230
1231 focusLog.finer("Dequeue at {0} for {1}",
1232 after, untilFocused);
1233
1234 TypeAheadMarker marker;
1235 ListIterator iter = typeAheadMarkers.listIterator
1236 ((after >= 0) ? typeAheadMarkers.size() : 0);
1237
1238 if (after < 0) {
1239 while (iter.hasNext()) {
1240 marker = iter.next();
1241 if (marker.untilFocused == untilFocused)
1242 {
1243 iter.remove();
1244 return;
1245 }
1246 }
1247 } else {
1248 while (iter.hasPrevious()) {
1249 marker = iter.previous();
1250 if (marker.untilFocused == untilFocused &&
1251 marker.after == after)
1252 {
1253 iter.remove();
1254 return;
1255 }
1256 }
1257 }
1258 }
1259
1260 /**
1261 * Discards all KeyEvents which were enqueued because of one or more calls
1262 * to enqueueKeyEvents
with the specified Component, or one of
1263 * its descendants.
1264 *
1265 * @param comp the Component specified in one or more calls to
1266 * enqueueKeyEvents
, or a parent of such a Component
1267 * @see #enqueueKeyEvents
1268 * @see #dequeueKeyEvents
1269 /
1270 protected synchronized void discardKeyEvents(Component comp) {
1271 if (comp == null) {
1272 return;
1273 }
1274
1275 long start = -1;
1276
1277 for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
1278 TypeAheadMarker marker = iter.next();
1279 Component toTest = marker.untilFocused;
1280 boolean match = (toTest == comp);
1281 while (!match && toTest != null && !(toTest instanceof Window)) {
1282 toTest = toTest.getParent();
1283 match = (toTest == comp);
1284 }
1285 if (match) {
1286 if (start < 0) {
1287 start = marker.after;
1288 }
1289 iter.remove();
1290 } else if (start >= 0) {
1291 purgeStampedEvents(start, marker.after);
1292 start = -1;
1293 }
1294 }
1295
1296 purgeStampedEvents(start, -1);
1297 }
1298
1299 // Notes:
1300 // * must be called inside a synchronized block
1301 // * if 'start' is < 0, then this function does nothing
1302 // * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
1303 // queue will be removed
1304 private void purgeStampedEvents(long start, long end) {
1305 if (start < 0) {
1306 return;
1307 }
1308
1309 for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
1310 KeyEvent ke = iter.next();
1311 long time = ke.getWhen();
1312
1313 if (start < time && (end < 0 || time <= end)) {
1314 iter.remove();
1315 }
1316
1317 if (end >= 0 && time > end) {
1318 break;
1319 }
1320 }
1321 }
1322
1323 /
1324 * Focuses the Component before aComponent, typically based on a
1325 * FocusTraversalPolicy.
1326 *
1327 * @param aComponent the Component that is the basis for the focus
1328 * traversal operation
1329 * @see FocusTraversalPolicy
1330 * @see Component#transferFocusBackward