6505819: Provide traverseIn method for sun.awt.EmbeddedFrame
Reviewed-by: dcherepanov, art
--- a/jdk/src/share/classes/java/awt/KeyboardFocusManager.java Fri Sep 03 11:08:41 2010 +0400
+++ b/jdk/src/share/classes/java/awt/KeyboardFocusManager.java Mon Sep 27 16:11:58 2010 +0400
@@ -142,6 +142,9 @@
public void removeLastFocusRequest(Component heavyweight) {
KeyboardFocusManager.removeLastFocusRequest(heavyweight);
}
+ public void setMostRecentFocusOwner(Window window, Component component) {
+ KeyboardFocusManager.setMostRecentFocusOwner(window, component);
+ }
}
);
}
--- a/jdk/src/share/classes/sun/awt/AWTAccessor.java Fri Sep 03 11:08:41 2010 +0400
+++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java Mon Sep 27 16:11:58 2010 +0400
@@ -344,6 +344,11 @@
* Removes the last focus request for the heavyweight from the queue.
*/
void removeLastFocusRequest(Component heavyweight);
+
+ /*
+ * Sets the most recent focus owner in the window.
+ */
+ void setMostRecentFocusOwner(Window window, Component component);
}
/*
--- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Fri Sep 03 11:08:41 2010 +0400
+++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Mon Sep 27 16:11:58 2010 +0400
@@ -70,7 +70,10 @@
// JDK 1.1 compatibility
private static final long serialVersionUID = 2967042741780317130L;
- // Use these in traverseOut method to determine directions
+ /*
+ * The constants define focus traversal directions.
+ * Use them in {@code traverseIn}, {@code traverseOut} methods.
+ */
protected static final boolean FORWARD = true;
protected static final boolean BACKWARD = false;
@@ -284,6 +287,41 @@
}
/**
+ * This method is called by the embedder when we should receive focus as element
+ * of the traversal chain. The method requests focus on:
+ * 1. the first Component of this EmbeddedFrame if user moves focus forward
+ * in the focus traversal cycle.
+ * 2. the last Component of this EmbeddedFrame if user moves focus backward
+ * in the focus traversal cycle.
+ *
+ * The direction parameter specifies which of the two mentioned cases is
+ * happening. Use FORWARD and BACKWARD constants defined in the EmbeddedFrame class
+ * to avoid confusing boolean values.
+ *
+ * A concrete implementation of this method is defined in the platform-dependent
+ * subclasses.
+ *
+ * @param direction FORWARD or BACKWARD
+ * @return true, if the EmbeddedFrame wants to get focus, false otherwise.
+ */
+ public boolean traverseIn(boolean direction) {
+ Component comp = null;
+
+ if (direction == FORWARD) {
+ comp = getFocusTraversalPolicy().getFirstComponent(this);
+ } else {
+ comp = getFocusTraversalPolicy().getLastComponent(this);
+ }
+ if (comp != null) {
+ // comp.requestFocus(); - Leads to a hung.
+
+ AWTAccessor.getKeyboardFocusManagerAccessor().setMostRecentFocusOwner(this, comp);
+ synthesizeWindowActivation(true);
+ }
+ return (null != comp);
+ }
+
+ /**
* This method is called from dispatchKeyEvent in the following two cases:
* 1. The focus is on the first Component of this EmbeddedFrame and we are
* about to transfer the focus backward.
--- a/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFrame.java Fri Sep 03 11:08:41 2010 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFrame.java Mon Sep 27 16:11:58 2010 +0400
@@ -28,9 +28,12 @@
import sun.awt.EmbeddedFrame;
import java.awt.*;
import java.awt.AWTKeyStroke;
+import java.util.logging.Logger;
public class XEmbeddedFrame extends EmbeddedFrame {
+ private static final Logger log = Logger.getLogger(XEmbeddedFrame.class.getName());
+
long handle;
public XEmbeddedFrame() {
}
@@ -70,6 +73,21 @@
this(handle, supportsXEmbed, false);
}
+ /*
+ * The method shouldn't be called in case of active XEmbed.
+ */
+ public boolean traverseIn(boolean direction) {
+ XEmbeddedFramePeer peer = (XEmbeddedFramePeer)getPeer();
+ if (peer != null) {
+ if (peer.supportsXEmbed() && peer.isXEmbedActive()) {
+ log.fine("The method shouldn't be called when XEmbed is active!");
+ } else {
+ return super.traverseIn(direction);
+ }
+ }
+ return false;
+ }
+
protected boolean traverseOut(boolean direction) {
XEmbeddedFramePeer xefp = (XEmbeddedFramePeer) getPeer();
if (direction == FORWARD) {
@@ -81,6 +99,20 @@
return true;
}
+ /*
+ * The method shouldn't be called in case of active XEmbed.
+ */
+ public void synthesizeWindowActivation(boolean doActivate) {
+ XEmbeddedFramePeer peer = (XEmbeddedFramePeer)getPeer();
+ if (peer != null) {
+ if (peer.supportsXEmbed() && peer.isXEmbedActive()) {
+ log.fine("The method shouldn't be called when XEmbed is active!");
+ } else {
+ peer.synthesizeFocusInOut(doActivate);
+ }
+ }
+ }
+
public void registerAccelerator(AWTKeyStroke stroke) {
XEmbeddedFramePeer xefp = (XEmbeddedFramePeer) getPeer();
if (xefp != null) {
--- a/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java Fri Sep 03 11:08:41 2010 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java Mon Sep 27 16:11:58 2010 +0400
@@ -35,6 +35,8 @@
import sun.awt.EmbeddedFrame;
import sun.awt.SunToolkit;
+import static sun.awt.X11.XConstants.*;
+
public class XEmbeddedFramePeer extends XFramePeer {
private static final PlatformLogger xembedLog = PlatformLogger.getLogger("sun.awt.X11.xembed.XEmbeddedFramePeer");
@@ -305,4 +307,20 @@
EmbeddedFrame frame = (EmbeddedFrame)target;
frame.notifyModalBlocked(blocker, blocked);
}
+
+ public void synthesizeFocusInOut(boolean doFocus) {
+ XFocusChangeEvent xev = new XFocusChangeEvent();
+
+ XToolkit.awtLock();
+ try {
+ xev.set_type(doFocus ? FocusIn : FocusOut);
+ xev.set_window(getFocusProxy().getWindow());
+ xev.set_mode(NotifyNormal);
+ XlibWrapper.XSendEvent(XToolkit.getDisplay(), getFocusProxy().getWindow(), false,
+ NoEventMask, xev.pData);
+ } finally {
+ XToolkit.awtUnlock();
+ xev.dispose();
+ }
+ }
}
--- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java Fri Sep 03 11:08:41 2010 +0400
+++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java Mon Sep 27 16:11:58 2010 +0400
@@ -191,9 +191,20 @@
public void activateEmbeddingTopLevel() {
}
- public void synthesizeWindowActivation(boolean doActivate) {
- ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(doActivate);
+ public void synthesizeWindowActivation(final boolean doActivate) {
+ if (!doActivate || EventQueue.isDispatchThread()) {
+ ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(doActivate);
+ } else {
+ // To avoid focus concurrence b/w IE and EmbeddedFrame
+ // activation is postponed by means of posting it to EDT.
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(true);
+ }
+ });
+ }
}
+
public void registerAccelerator(AWTKeyStroke stroke) {}
public void unregisterAccelerator(AWTKeyStroke stroke) {}