diff --git a/src/java.desktop/share/classes/java/awt/Container.java b/src/java.desktop/share/classes/java/awt/Container.java index 1a6163eb4..88f3b8d04 100644 --- a/src/java.desktop/share/classes/java/awt/Container.java +++ b/src/java.desktop/share/classes/java/awt/Container.java @@ -678,6 +678,10 @@ public class Container extends Component { } } + public ComponentPeer getPeer(){ + return peer; + } + /** * Detects whether or not remove from current parent and adding to new parent requires call of * removeNotify on the component. Since removeNotify destroys native window this might (not) diff --git a/src/java.desktop/share/classes/javax/swing/JTextArea.java b/src/java.desktop/share/classes/javax/swing/JTextArea.java index d64fa0272..ccf7dceca 100644 --- a/src/java.desktop/share/classes/javax/swing/JTextArea.java +++ b/src/java.desktop/share/classes/javax/swing/JTextArea.java @@ -547,7 +547,10 @@ public class JTextArea extends JTextComponent { } return rowHeight; } - + + public FontMetrics getFontMetrics() { + return getFontMetrics(getFont()); + } /** * Returns the number of columns in the TextArea. * diff --git a/src/java.desktop/share/classes/javax/swing/JTextField.java b/src/java.desktop/share/classes/javax/swing/JTextField.java index b8e3ffe06..3bfe3cae1 100644 --- a/src/java.desktop/share/classes/javax/swing/JTextField.java +++ b/src/java.desktop/share/classes/javax/swing/JTextField.java @@ -409,7 +409,11 @@ public class JTextField extends JTextComponent implements SwingConstants { } return columnWidth; } - + + public FontMetrics getFontMetrics() { + return getFontMetrics(getFont()); + } + /** * Returns the preferred size Dimensions needed for this * TextField. If a non-zero number of columns has been diff --git a/src/java.desktop/share/classes/sun/awt/im/InputContext.java b/src/java.desktop/share/classes/sun/awt/im/InputContext.java index ad9d71be7..3d437ae8a 100644 --- a/src/java.desktop/share/classes/sun/awt/im/InputContext.java +++ b/src/java.desktop/share/classes/sun/awt/im/InputContext.java @@ -28,6 +28,7 @@ package sun.awt.im; import java.awt.AWTEvent; import java.awt.AWTKeyStroke; import java.awt.Component; +import java.awt.Cursor; import java.awt.EventQueue; import java.awt.Frame; import java.awt.Rectangle; @@ -39,6 +40,7 @@ import java.awt.event.FocusEvent; import java.awt.event.InputEvent; import java.awt.event.InputMethodEvent; import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.im.InputMethodRequests; @@ -54,6 +56,7 @@ import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import sun.util.logging.PlatformLogger; import sun.awt.SunToolkit; +import sun.awt.X11InputMethod; /** * This InputContext class contains parts of the implementation of @@ -249,13 +252,26 @@ public class InputContext extends java.awt.im.InputContext focusLost((Component) event.getSource(), ((FocusEvent) event).isTemporary()); break; + case MouseEvent.MOUSE_RELEASED: + if(checkTextCursor((Component)event.getSource())) { + // focusGained((Component) event.getSource()); + transCaretPositionToXIM((Component)event.getSource()); + break; + } + case KeyEvent.KEY_PRESSED: - if (checkInputMethodSelectionKey((KeyEvent)event)) { + if (event instanceof KeyEvent && checkInputMethodSelectionKey((KeyEvent)event)) { // pop up the input method selection menu InputMethodManager.getInstance().notifyChangeRequestByHotKey((Component)event.getSource()); break; } + case KeyEvent.KEY_RELEASED: + if (event instanceof KeyEvent && checkDirectionKey((KeyEvent)event)) { + transCaretPositionToXIM((Component) event.getSource()); + break; + } + // fall through default: @@ -359,7 +375,65 @@ public class InputContext extends java.awt.im.InputContext } } } - + /** + * fix fcitx position + */ + private void transCaretPositionToXIM(Component source) { + synchronized (source.getTreeLock()) { + synchronized (this) { + if ("sun.awt.im.CompositionArea".equals(source.getClass().getName())) { + // no special handling for this one + } else if (getComponentWindow(source) instanceof InputMethodWindow) { + // no special handling for this one either + } else { + if (!source.isDisplayable()) { + // Component is being disposed + return; + } + currentClientComponent = source; + } + awtFocussedComponent = source; + if (inputMethod != null && inputMethod instanceof X11InputMethod) { + ((X11InputMethod)inputMethod).setXICTextCursorPosition(source); + } + InputMethodContext inputContext = ((InputMethodContext)this); + if (!inputContext.isCompositionAreaVisible()) { + InputMethodRequests req = source.getInputMethodRequests(); + if (req != null && inputContext.useBelowTheSpotInput()) { + inputContext.setCompositionAreaUndecorated(true); + } else { + inputContext.setCompositionAreaUndecorated(false); + } + } + // restores the composition area if it was set to invisible + // when focus got lost + if (compositionAreaHidden == true) { + ((InputMethodContext)this).setCompositionAreaVisible(true); + compositionAreaHidden = false; + } + + } + } + } + /** + * fix fcitx position + */ + private boolean checkDirectionKey(KeyEvent event) { + // if (event.getKeyCode() >= 37 && event.getKeyCode() <=40) { + // return true; + // } else { + // return false; + // } + return true; + } + /** + * fix fcitx position + */ + private boolean checkTextCursor(Component source) { + if(source.getCursor().getType()==Cursor.TEXT_CURSOR) + return true; + return false; + } /** * Activates the current input method of this input context, and grabs * the composition area for use by this input context. diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java b/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java index 07c1334b8..01d5910de 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java @@ -28,15 +28,27 @@ package sun.awt.X11; import java.awt.AWTException; import java.awt.Component; import java.awt.Container; +import java.awt.geom.Point2D; +import java.awt.FontMetrics; +import java.awt.Point; import java.awt.Rectangle; import java.awt.im.spi.InputMethodContext; import java.awt.peer.ComponentPeer; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.text.JTextComponent; + import sun.awt.AWTAccessor; import sun.awt.X11InputMethod; import sun.util.logging.PlatformLogger; + /** * Input Method Adapter for XIM (without Motif) * @@ -83,8 +95,20 @@ public class XInputMethod extends X11InputMethod { return 0; return releaseXICNative(pData); } - + + private static volatile long xicFocus = 0; + + public void setXICTextCursorOffXY(ComponentPeer peer) { + + if (peer == null) { + return; + } + xicFocus = ((XComponentPeer)peer).getContentWindow(); + int[] result = getOffXYRelateToFrame(peer ,true); + setXICFocusNative(((XComponentPeer)peer).getContentWindow(),true,true,result); + // setXICTextCursorOffXYNative(((XComponentPeer)peer).getContentWindow(),result); + } protected void setXICFocus(ComponentPeer peer, boolean value, boolean active) { @@ -92,9 +116,11 @@ public class XInputMethod extends X11InputMethod { return; } xicFocus = ((XComponentPeer)peer).getContentWindow(); + int[] result = getOffXYRelateToFrame(peer ,value); setXICFocusNative(((XComponentPeer)peer).getContentWindow(), value, - active); + active, + result); } public static long getXICFocus() { @@ -156,6 +182,71 @@ public class XInputMethod extends X11InputMethod { return peer.getContentWindow(); } + protected int[] getOffXYRelateToFrame(ComponentPeer peer, boolean value) { + int[] result = null; + if(value && this.awtFocussedComponent!=null && this.awtFocussedComponent instanceof JTextComponent){ + try { + Method method_getFontMetrics = null; + Method method_getEditor = null; + FontMetrics font_metrics = null; + Object editor = null; + int font_height = 0; + int caret_x = 0; + int caret_y = 0; + if(this.awtFocussedComponent instanceof JTextArea || this.awtFocussedComponent instanceof JTextField){ + method_getFontMetrics = this.awtFocussedComponent.getClass().getMethod("getFontMetrics"); + font_metrics = (FontMetrics)method_getFontMetrics.invoke(this.awtFocussedComponent); + font_height = font_metrics.getHeight(); + JTextComponent jc = (JTextComponent)this.awtFocussedComponent; + if( jc.getCaret().getMagicCaretPosition() != null) { + caret_x = jc.getCaret().getMagicCaretPosition().x; + caret_y = jc.getCaret().getMagicCaretPosition().y; + } + }else { + method_getEditor = this.awtFocussedComponent.getClass().getMethod("getEditor"); + + editor = method_getEditor.invoke(this.awtFocussedComponent); + + method_getFontMetrics = editor.getClass().getMethod("getFontMetrics",int.class); + font_metrics = (FontMetrics)method_getFontMetrics.invoke(editor, 0); + font_height = font_metrics.getHeight(); + Method getCaretLocations = editor.getClass().getMethod("getCaretLocations", boolean.class); + Object[] locations = (Object[])getCaretLocations.invoke(editor, false); + Field point = locations[0].getClass().getField("myPoint"); + Point2D pd = (Point2D)point.get(locations[0]); + caret_x = (int)pd.getX(); + caret_y = (int)pd.getY(); + } + + + Method method_getLocationOnScreen = this.awtFocussedComponent.getClass().getMethod("getLocationOnScreen"); + + Point point = (Point)method_getLocationOnScreen.invoke(this.awtFocussedComponent); + + Method method_getNativeContainer = Component.class.getDeclaredMethod("getNativeContainer"); + method_getNativeContainer.setAccessible(true); + Container c = (Container)method_getNativeContainer.invoke(awtFocussedComponent); + if(c!=null) + result = new int[]{point.x - c.getPeer().getLocationOnScreen().x + caret_x, point.y - c.getPeer().getLocationOnScreen().y + font_height + caret_y}; + + return result; + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (SecurityException e) { + e.printStackTrace(); + } catch(NoSuchFieldException e) { + e.printStackTrace(); + } + } + return result; + } + /* * Native methods */ @@ -164,6 +255,6 @@ public class XInputMethod extends X11InputMethod { private native boolean recreateXICNative(long window, long px11data, int ctxid); private native int releaseXICNative(long px11data); private native void setXICFocusNative(long window, - boolean value, boolean active); + boolean value, boolean active, int[] offxy); private native void adjustStatusWindow(long window); } diff --git a/src/java.desktop/unix/classes/sun/awt/X11InputMethod.java b/src/java.desktop/unix/classes/sun/awt/X11InputMethod.java index d9c45ed97..834164ad8 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11InputMethod.java +++ b/src/java.desktop/unix/classes/sun/awt/X11InputMethod.java @@ -33,6 +33,7 @@ import java.awt.AWTException; import java.awt.event.InputMethodEvent; import java.awt.font.TextAttribute; import java.awt.font.TextHitInfo; +import java.awt.Component; import java.awt.peer.ComponentPeer; import java.text.AttributedString; import java.util.Map; @@ -56,6 +57,10 @@ public abstract class X11InputMethod extends X11InputMethodBase { public X11InputMethod() throws AWTException { super(); } + /** + * fix fcitx position + */ + public abstract void setXICTextCursorOffXY(ComponentPeer peer); /** * Reset the composition state to the current composition state. @@ -380,6 +385,30 @@ public abstract class X11InputMethod extends X11InputMethodBase { } } + /** + * fix fcitx position + */ + public synchronized void setXICTextCursorPosition(Component component){ + if (component == null) { + return; + } + if (isActive) { + // deactivate/activate are being suppressed during a focus change - + // this may happen when an input method window is made visible + // boolean ac = haveActiveClient(); already set true in awt_InputMethod.c + setXICTextCursorOffXY(getPeer(awtFocussedComponent)); + + } + awtFocussedComponent = component; + // ComponentPeer lastXICFocussedComponentPeer = null; + // if (lastXICFocussedComponent != null) { + // lastXICFocussedComponentPeer = getPeer(lastXICFocussedComponent); + // } + ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent); + if(awtFocussedComponent !=null ) + setXICTextCursorOffXY(awtFocussedComponentPeer); + } + protected abstract boolean recreateXIC(int ctxid); protected abstract int releaseXIC(); private static native boolean recreateX11InputMethod(); diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c b/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c index 847c44b52..c619d3773 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c @@ -436,13 +436,17 @@ setXICFocus(XIC ic, unsigned short req) * Sets the focus window to the given XIC. */ static void -setXICWindowFocus(XIC ic, Window w) +setXICWindowFocus(XIC ic, Window w, int arr[2]) { if (ic == NULL) { (void)fprintf(stderr, "Couldn't find X Input Context\n"); return; } - (void) XSetICValues(ic, XNFocusWindow, w, NULL); + XPoint spot; + spot.x = arr[0]; + spot.y = arr[1]; + XVaNestedList xy = (XVaNestedList)XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); + (void) XSetICValues(ic, XNFocusWindow, w, XNPreeditAttributes, xy, NULL); } /* @@ -1468,7 +1472,8 @@ Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, jobject this, jlong w, jboolean req, - jboolean active) + jboolean active, + jintArray arr) { X11InputMethodData *pX11IMData; AWT_LOCK(); @@ -1489,7 +1494,17 @@ Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, * On Solaris2.6, setXICWindowFocus() has to be invoked * before setting focus. */ - setXICWindowFocus(pX11IMData->current_ic, w); + int positions[2] = {100,50}; + if (arr) + { + int length = (*env)->GetArrayLength(env,arr); + int *addArr = (*env)->GetIntArrayElements(env, arr, NULL); + for (int i= 0; i < length; ++i) { + positions[i] = *(addArr + i); + } + (*env)->ReleaseIntArrayElements(env, arr, addArr, 0); + } + setXICWindowFocus(pX11IMData->current_ic, w, positions); setXICFocus(pX11IMData->current_ic, req); currentX11InputMethodInstance = pX11IMData->x11inputmethod; currentFocusWindow = w;