├── LICENSE ├── .gitignore ├── src └── main │ ├── resources │ ├── META-INF │ │ └── MANIFEST.MF │ ├── swt.key.mapping.properties │ └── patch.key.mapping.properties │ └── java │ ├── net │ └── x11 │ │ └── patch │ │ ├── LinuxJavaPatchAgent.java │ │ ├── XKeysymTransformer.java │ │ └── SWTEventTableTransformer.java │ └── KeyEventDemo.java ├── pom.xml ├── README.md └── archive ├── EventTable.java └── XWindow.java /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *bin* 3 | *gen* 4 | *.settings* 5 | .classpath 6 | .project 7 | /target 8 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Premain-Class: net.x11.patch.LinuxJavaPatchAgent 2 | Boot-Class-Path: javassist-3.12.1.GA.jar 3 | -------------------------------------------------------------------------------- /src/main/resources/swt.key.mapping.properties: -------------------------------------------------------------------------------- 1 | 1081=113 2 | 1094=119 3 | 1091=101 4 | 1082=114 5 | 1077=116 6 | 1085=121 7 | 1075=117 8 | 1096=105 9 | 1097=111 10 | 1079=112 11 | 12 | 1092=97 13 | 1099=115 14 | 1074=100 15 | 1072=102 16 | 1087=103 17 | 1088=104 18 | 1086=106 19 | 1083=107 20 | 1076=108 21 | 22 | 1103=122 23 | 1095=120 24 | 1089=99 25 | 1084=118 26 | 1080=98 27 | 1090=110 28 | 1100=109 -------------------------------------------------------------------------------- /src/main/resources/patch.key.mapping.properties: -------------------------------------------------------------------------------- 1 | 6ca=Q 2 | 6c3=W 3 | 6d5=E 4 | 6cb=R 5 | 6c5=T 6 | 6ce=Y 7 | 6c7=U 8 | 6db=I 9 | 6dd=O 10 | 6da=P 11 | 6c6=A 12 | 6d9=S 13 | 6d7=D 14 | 6c1=F 15 | 6d0=G 16 | 6d2=H 17 | 6cf=J 18 | 6cc=K 19 | 6c4=L 20 | 6d1=Z 21 | 6de=X 22 | 6d3=C 23 | 6cd=V 24 | 6c9=B 25 | 6d4=N 26 | 6d8=M 27 | 6c8=OPEN_BRACKET 28 | 6df=CLOSE_BRACKET 29 | 6d6=SEMICOLON 30 | 6dc=QUOTE 31 | 6c2=COMMA 32 | 6c0=PERIOD 33 | 6a3=BACK_QUOTE 34 | -------------------------------------------------------------------------------- /src/main/java/net/x11/patch/LinuxJavaPatchAgent.java: -------------------------------------------------------------------------------- 1 | package net.x11.patch; 2 | 3 | import java.io.*; 4 | import java.lang.instrument.Instrumentation; 5 | import java.util.Properties; 6 | 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: mzheludkov 11 | * -javaagent:target/LinuxJavaFixes-1.0.0-SNAPSHOT.jar 12 | */ 13 | public class LinuxJavaPatchAgent { 14 | 15 | public static void premain(String agentArgument, Instrumentation instrumentation) { 16 | if(agentArgument==null || !agentArgument.startsWith(SWTEventTableTransformer.SWT)) { 17 | instrumentation.addTransformer(new XKeysymTransformer(agentArgument)); 18 | } else if(agentArgument.startsWith(SWTEventTableTransformer.SWT)){ 19 | instrumentation.addTransformer(new SWTEventTableTransformer(agentArgument)); 20 | } 21 | } 22 | 23 | public static Properties getProperties(String defaultProperties, String propertiesFile) throws IOException { 24 | Properties props = null; 25 | if(propertiesFile !=null && !propertiesFile.equals("")) { 26 | File mapping = new File(propertiesFile); 27 | if(mapping.exists()) { 28 | props = new Properties(); 29 | System.out.println("LinuxJavaPatchAgent.loaded properties from "+mapping); 30 | props.load(new FileInputStream(mapping)); 31 | 32 | } 33 | } 34 | if(props==null) { 35 | props = new Properties(); 36 | System.out.println("LinuxJavaPatchAgent.loaded properties from classpath! "+defaultProperties); 37 | props.load(LinuxJavaPatchAgent.class.getClassLoader().getResourceAsStream(defaultProperties)); 38 | } 39 | return props; 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | ru.mate.java.patch 8 | LinuxJavaFixes 9 | jar 10 | 1.0.0-SNAPSHOT 11 | 12 | 13 | javassist 14 | javassist 15 | 3.12.1.GA 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 24 | 1.6 25 | 1.6 26 | UTF-8 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-jar-plugin 32 | 33 | 34 | src/main/resources/META-INF/MANIFEST.MF 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-dependency-plugin 41 | 42 | 43 | copy-dependencies 44 | package 45 | 46 | copy-dependencies 47 | 48 | 49 | runtime 50 | 51 | ${project.build.directory} 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #LinuxJavaFixes 2 | 3 | Simple javaagent to fix problems in linux with non latin hotkeys in gui java applications. 4 | 5 | Aimed to walkaround bug with java gui apps: "Hotkeys not functional in non-latin keyboard layout in 13.10 - 16.04" https://bugs.launchpad.net/unity/+bug/1226962 6 | 7 | ## Swing java apps (IntelliJ Idea, Oracle SQL Developer etc.) 8 | 9 | Copy to any directory 2 files: 10 | 11 | **LinuxJavaFixes-1.0.0-SNAPSHOT.jar** 12 | 13 | **javassist-3.12.1.GA.jar** 14 | 15 | add 16 | 17 | `-javaagent:[path to directory with jar files]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar` 18 | 19 | to java run string 20 | 21 | #### Examples: 22 | 23 | ##### SoapUI 24 | 25 | Add line to **soapui.sh**. 26 | 27 | `JAVA_OPTS="$JAVA_OPTS java -javaagent:[path to directory with jar files]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar` 28 | 29 | ##### Oracle SQL Developer 30 | 31 | Add line to **sqldeveloper/ide/bin/jdk.conf**. 32 | 33 | `AddVMOption -javaagent:[path to directory with jar files]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar` 34 | 35 | ##### IntelliJ Idea 36 | 37 | Add line to **idea64.vmoptions* or *idea.vmoptions** 38 | 39 | `-javaagent:[path to directory with jar files]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar` 40 | 41 | ## Eclipse 42 | 43 | Copy to any directory 2 files: 44 | 45 | **LinuxJavaFixes-1.0.0-SNAPSHOT.jar** 46 | 47 | **javassist-3.12.1.GA.jar** 48 | 49 | Add following line to **eclipse.ini**. 50 | 51 | `-javaagent:[path to directory with jar files]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar=swt` 52 | 53 | ## Advanced part 54 | 55 | ### Modify kaybindings for swing apps in case non russian layout 56 | 57 | If you want another mapping you can create it by yourself: 58 | 59 | - run any app with java vm option `-javaagent:[path]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar=print` 60 | - after that utily begin print to console entered symbol codes using format 61 | 62 | `XKeysymPatchAgent.keysym=[hex code]` 63 | 64 | - then create file using format `[hex code]=[latin code of the same button]` 65 | 66 | #### Example: 67 | 68 | ``` 69 | 6ca=Q 70 | 71 | 6c3=W 72 | ``` 73 | etc. 74 | 75 | - replace hex codes wuth yours 76 | - use following option to run app with custom mapping: 77 | 78 | `-javaagent:[path to directory with jar files]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar=[your mapping file]` 79 | 80 | ### Modify keybindings for swt in case non russian layout 81 | 82 | - add following line to eclipse.ini 83 | 84 | `-javaagent:[path]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar=swt:print` 85 | 86 | - then grab codes and create properties file with mapping 87 | 88 | `[your locale key]=[latin key]` 89 | 90 | - then run eclipse wuth following config 91 | 92 | `-javaagent:[path]/LinuxJavaFixes-1.0.0-SNAPSHOT.jar=swt:[path to your mapping file]` 93 | -------------------------------------------------------------------------------- /src/main/java/net/x11/patch/XKeysymTransformer.java: -------------------------------------------------------------------------------- 1 | package net.x11.patch; 2 | 3 | import javassist.ClassPool; 4 | import javassist.CtClass; 5 | import javassist.CtMethod; 6 | 7 | import java.lang.instrument.ClassFileTransformer; 8 | import java.lang.instrument.IllegalClassFormatException; 9 | import java.security.ProtectionDomain; 10 | import java.util.Properties; 11 | 12 | /** 13 | * Created by mikl on 08.02.14. 14 | */ 15 | public class XKeysymTransformer implements ClassFileTransformer { 16 | public static final String XNET_PROTOCOL = "sun/awt/X11/XKeysym"; 17 | public static final String PATCH_KEY_MAPPING_PROPERTIES = "patch.key.mapping.properties"; 18 | public static final String PRINT = "print"; 19 | private String agentArgument; 20 | 21 | public XKeysymTransformer(String agentArgument) { 22 | this.agentArgument = agentArgument; 23 | } 24 | 25 | @Override 26 | public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 27 | try { 28 | return className!=null && className.equals(XNET_PROTOCOL) ? doClass(className, classBeingRedefined, classfileBuffer) : classfileBuffer; 29 | } catch (Throwable err) { 30 | err.printStackTrace(); 31 | return classfileBuffer; 32 | } 33 | } 34 | 35 | private byte[] doClass(String name, Class clazz, byte[] b) { 36 | CtClass cl = null; 37 | ClassPool pool = ClassPool.getDefault(); 38 | try { 39 | cl = pool.makeClass(new java.io.ByteArrayInputStream(b)); 40 | if(agentArgument!=null && agentArgument.equals(PRINT)) { 41 | CtMethod method = cl.getDeclaredMethod("getJavaKeycode"); 42 | method.insertBefore("System.out.println(\"LinuxJavaPatchAgent.keysym=\"+Long.toHexString($1));"); 43 | } else { 44 | Properties props = LinuxJavaPatchAgent.getProperties(PATCH_KEY_MAPPING_PROPERTIES, agentArgument); 45 | for(Object key: props.keySet()) { 46 | String value = props.getProperty((String) key); 47 | cl.getClassInitializer().insertAfter("keysym2JavaKeycodeHash.put( Long.valueOf(0x"+key+"l), new sun.awt.X11.XKeysym$Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_"+value+", java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));"); 48 | } 49 | } 50 | b = cl.toBytecode(); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | System.out.println("LinuxJavaPatchAgent.Could not instrument " + name + ", exception : " + e.getMessage()); 54 | } finally { 55 | if (cl != null) { 56 | cl.detach(); 57 | } 58 | } 59 | return b; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/net/x11/patch/SWTEventTableTransformer.java: -------------------------------------------------------------------------------- 1 | package net.x11.patch; 2 | 3 | import javassist.*; 4 | 5 | import java.lang.instrument.ClassFileTransformer; 6 | import java.lang.instrument.IllegalClassFormatException; 7 | import java.net.URL; 8 | import java.net.URLClassLoader; 9 | import java.security.ProtectionDomain; 10 | import java.util.Properties; 11 | 12 | /** 13 | * Created by mikl on 08.02.14. 14 | */ 15 | public class SWTEventTableTransformer implements ClassFileTransformer { 16 | public static final String EVENT_TABLE_CLASS = "org/eclipse/swt/widgets/EventTable"; 17 | public static final String PATCH_KEY_MAPPING_PROPERTIES = "swt.key.mapping.properties"; 18 | public static final String PRINT = "print"; 19 | public static final String SWT = "swt"; 20 | private String agentArgument; 21 | 22 | public SWTEventTableTransformer(String agentArgument) { 23 | this.agentArgument = agentArgument==null||agentArgument.equalsIgnoreCase(SWT) ? null : agentArgument.substring(4); 24 | } 25 | 26 | @Override 27 | public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 28 | try { 29 | return className.equals(EVENT_TABLE_CLASS) ? doClass(loader, className, classBeingRedefined, classfileBuffer) : classfileBuffer; 30 | } catch (Throwable err) { 31 | err.printStackTrace(); 32 | return classfileBuffer; 33 | } 34 | } 35 | 36 | private byte[] doClass(ClassLoader classLoader, String name, Class clazz, byte[] b) throws ClassNotFoundException, NotFoundException { 37 | CtClass cl = null; 38 | ClassPool pool = ClassPool.getDefault(); 39 | pool.appendClassPath(new LoaderClassPath(classLoader)); 40 | try { 41 | cl = pool.makeClass(new java.io.ByteArrayInputStream(b)); 42 | CtMethod method = cl.getDeclaredMethod("sendEvent"); 43 | if(agentArgument!=null && agentArgument.equals(PRINT)) { 44 | method.insertBefore("if($1.type==1) {System.out.println(\"keyCode=\"+$1.keyCode);};" ); 45 | } else { 46 | Properties props = LinuxJavaPatchAgent.getProperties(PATCH_KEY_MAPPING_PROPERTIES, agentArgument); 47 | for(Object key: props.keySet()) { 48 | String value = props.getProperty((String) key); 49 | method.insertBefore("if(($1.type==1) && $1.keyCode==" + key + " && ((event.stateMask & org.eclipse.swt.SWT.MOD1) !=0 || (event.stateMask & org.eclipse.swt.SWT.MOD2) !=0 )) { $1.keyCode=" + value + ";}"); 50 | } 51 | } 52 | b = cl.toBytecode(); 53 | } catch (Exception e) { 54 | e.printStackTrace(System.out); 55 | System.out.println("LinuxJavaPatchAgent.Could not instrument " + name + ", exception : " + e.getMessage()); 56 | } finally { 57 | if (cl != null) { 58 | cl.detach(); 59 | } 60 | } 61 | return b; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /archive/EventTable.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2000, 2011 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | package org.eclipse.swt.widgets; 12 | 13 | 14 | import org.eclipse.swt.*; 15 | import org.eclipse.swt.internal.SWTEventListener; 16 | 17 | /** 18 | * Instances of this class implement a simple 19 | * look up mechanism that maps an event type 20 | * to a listener. Multiple listeners for the 21 | * same event type are supported. 22 | */ 23 | 24 | class EventTable { 25 | int [] types; 26 | Listener [] listeners; 27 | int level; 28 | static final int GROW_SIZE = 4; 29 | 30 | public Listener [] getListeners (int eventType) { 31 | if (types == null) return new Listener [0]; 32 | int count = 0; 33 | for (int i=0; i= 0) { 52 | if (types [index] != 0) break; 53 | --index; 54 | } 55 | index++; 56 | if (index == length) { 57 | int [] newTypes = new int [length + GROW_SIZE]; 58 | System.arraycopy (types, 0, newTypes, 0, length); 59 | types = newTypes; 60 | Listener [] newListeners = new Listener [length + GROW_SIZE]; 61 | System.arraycopy (listeners, 0, newListeners, 0, length); 62 | listeners = newListeners; 63 | } 64 | types [index] = eventType; 65 | listeners [index] = listener; 66 | } 67 | 68 | public boolean hooks (int eventType) { 69 | if (types == null) return false; 70 | for (int i=0; i= 0 ? 1 : -1; 90 | try { 91 | for (int i=0; i= 0 ? 1 : -1; 104 | if (compact && level == 0) { 105 | int index = 0; 106 | for (int i=0; i 0) level = -level; 138 | } 139 | types [index] = 0; 140 | listeners [index] = null; 141 | } 142 | 143 | public void unhook (int eventType, Listener listener) { 144 | if (types == null) return; 145 | for (int i=0; i 0) { 158 | modString += " (" + tmpString + ")"; 159 | } else { 160 | modString += " (no extended modifiers)"; 161 | } 162 | 163 | String actionString = "action key? "; 164 | if (e.isActionKey()) { 165 | actionString += "YES"; 166 | } else { 167 | actionString += "NO"; 168 | } 169 | 170 | String locationString = "key location: "; 171 | int location = e.getKeyLocation(); 172 | if (location == KeyEvent.KEY_LOCATION_STANDARD) { 173 | locationString += "standard"; 174 | } else if (location == KeyEvent.KEY_LOCATION_LEFT) { 175 | locationString += "left"; 176 | } else if (location == KeyEvent.KEY_LOCATION_RIGHT) { 177 | locationString += "right"; 178 | } else if (location == KeyEvent.KEY_LOCATION_NUMPAD) { 179 | locationString += "numpad"; 180 | } else { // (location == KeyEvent.KEY_LOCATION_UNKNOWN) 181 | locationString += "unknown"; 182 | } 183 | 184 | System.out.println(keyStatus + newline 185 | + " " + keyString + newline 186 | + " " + modString + newline 187 | + " " + actionString + newline 188 | + " " + locationString + newline); 189 | 190 | displayArea.append(keyStatus + newline 191 | + " " + keyString + newline 192 | + " " + modString + newline 193 | + " " + actionString + newline 194 | + " " + locationString + newline); 195 | displayArea.setCaretPosition(displayArea.getDocument().getLength()); 196 | } 197 | } -------------------------------------------------------------------------------- /archive/XWindow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | 26 | package sun.awt.X11; 27 | 28 | import java.awt.*; 29 | import java.awt.event.*; 30 | import java.awt.peer.ComponentPeer; 31 | import java.awt.image.ColorModel; 32 | 33 | import java.lang.ref.WeakReference; 34 | 35 | import java.lang.reflect.Method; 36 | 37 | //import sun.util.logging.PlatformLogger; 38 | 39 | import sun.awt.*; 40 | 41 | import sun.awt.image.PixelConverter; 42 | 43 | import sun.java2d.SunGraphics2D; 44 | import sun.java2d.SurfaceData; 45 | 46 | public class XWindow extends XBaseWindow implements X11ComponentPeer { 47 | // private static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XWindow"); 48 | // private static PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XWindow"); 49 | // private static PlatformLogger eventLog = PlatformLogger.getLogger("sun.awt.X11.event.XWindow"); 50 | // private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XWindow"); 51 | // private static PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XWindow"); 52 | /* If a motion comes in while a multi-click is pending, 53 | * allow a smudge factor so that moving the mouse by a small 54 | * amount does not wipe out the multi-click state variables. 55 | */ 56 | private final static int AWT_MULTICLICK_SMUDGE = 4; 57 | // ButtonXXX events stuff 58 | static int rbutton = 0; 59 | static int lastX = 0, lastY = 0; 60 | static long lastTime = 0; 61 | static long lastButton = 0; 62 | static WeakReference lastWindowRef = null; 63 | static int clickCount = 0; 64 | 65 | // used to check if we need to re-create surfaceData. 66 | int oldWidth = -1; 67 | int oldHeight = -1; 68 | 69 | protected PropMwmHints mwm_hints; 70 | protected static XAtom wm_protocols; 71 | protected static XAtom wm_delete_window; 72 | protected static XAtom wm_take_focus; 73 | 74 | private boolean stateChanged; // Indicates whether the value on savedState is valid 75 | private int savedState; // Holds last known state of the top-level window 76 | 77 | XWindowAttributesData winAttr; 78 | 79 | protected X11GraphicsConfig graphicsConfig; 80 | protected AwtGraphicsConfigData graphicsConfigData; 81 | 82 | private boolean reparented; 83 | 84 | XWindow parent; 85 | 86 | Component target; 87 | 88 | private static int JAWT_LOCK_ERROR=0x00000001; 89 | private static int JAWT_LOCK_CLIP_CHANGED=0x00000002; 90 | private static int JAWT_LOCK_BOUNDS_CHANGED=0x00000004; 91 | private static int JAWT_LOCK_SURFACE_CHANGED=0x00000008; 92 | private int drawState = JAWT_LOCK_CLIP_CHANGED | 93 | JAWT_LOCK_BOUNDS_CHANGED | 94 | JAWT_LOCK_SURFACE_CHANGED; 95 | 96 | public static final String TARGET = "target", 97 | REPARENTED = "reparented"; // whether it is reparented by default 98 | 99 | SurfaceData surfaceData; 100 | 101 | XRepaintArea paintArea; 102 | 103 | // fallback default font object 104 | private static Font defaultFont; 105 | 106 | static synchronized Font getDefaultFont() { 107 | if (null == defaultFont) { 108 | defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); 109 | } 110 | return defaultFont; 111 | } 112 | 113 | /* A bitmask keeps the button's numbers as Button1Mask, Button2Mask, Button3Mask 114 | * which are allowed to 115 | * generate the CLICK event after the RELEASE has happened. 116 | * There are conditions that must be true for that sending CLICK event: 117 | * 1) button was initially PRESSED 118 | * 2) no movement or drag has happened until RELEASE 119 | */ 120 | private int mouseButtonClickAllowed = 0; 121 | 122 | native int getNativeColor(Color clr, GraphicsConfiguration gc); 123 | native void getWMInsets(long window, long left, long top, long right, long bottom, long border); 124 | native long getTopWindow(long window, long rootWin); 125 | native void getWindowBounds(long window, long x, long y, long width, long height); 126 | private native static void initIDs(); 127 | 128 | static { 129 | initIDs(); 130 | } 131 | 132 | XWindow(XCreateWindowParams params) { 133 | super(params); 134 | } 135 | 136 | XWindow() { 137 | } 138 | 139 | XWindow(long parentWindow, Rectangle bounds) { 140 | super(new XCreateWindowParams(new Object[] { 141 | BOUNDS, bounds, 142 | PARENT_WINDOW, Long.valueOf(parentWindow)})); 143 | } 144 | 145 | XWindow(Component target, long parentWindow, Rectangle bounds) { 146 | super(new XCreateWindowParams(new Object[] { 147 | BOUNDS, bounds, 148 | PARENT_WINDOW, Long.valueOf(parentWindow), 149 | TARGET, target})); 150 | } 151 | 152 | XWindow(Component target, long parentWindow) { 153 | this(target, parentWindow, new Rectangle(target.getBounds())); 154 | } 155 | 156 | XWindow(Component target) { 157 | this(target, (target.getParent() == null) ? 0 : getParentWindowID(target), new Rectangle(target.getBounds())); 158 | } 159 | 160 | XWindow(Object target) { 161 | this(null, 0, null); 162 | } 163 | 164 | /* This create is used by the XEmbeddedFramePeer since it has to create the window 165 | as a child of the netscape window. This netscape window is passed in as wid */ 166 | XWindow(long parentWindow) { 167 | super(new XCreateWindowParams(new Object[] { 168 | PARENT_WINDOW, Long.valueOf(parentWindow), 169 | REPARENTED, Boolean.TRUE, 170 | EMBEDDED, Boolean.TRUE})); 171 | } 172 | 173 | protected void initGraphicsConfiguration() { 174 | graphicsConfig = (X11GraphicsConfig) target.getGraphicsConfiguration(); 175 | graphicsConfigData = new AwtGraphicsConfigData(graphicsConfig.getAData()); 176 | } 177 | 178 | void preInit(XCreateWindowParams params) { 179 | super.preInit(params); 180 | reparented = Boolean.TRUE.equals(params.get(REPARENTED)); 181 | 182 | target = (Component)params.get(TARGET); 183 | 184 | initGraphicsConfiguration(); 185 | 186 | AwtGraphicsConfigData gData = getGraphicsConfigurationData(); 187 | X11GraphicsConfig config = (X11GraphicsConfig) getGraphicsConfiguration(); 188 | XVisualInfo visInfo = gData.get_awt_visInfo(); 189 | params.putIfNull(EVENT_MASK, XConstants.KeyPressMask | XConstants.KeyReleaseMask 190 | | XConstants.FocusChangeMask | XConstants.ButtonPressMask | XConstants.ButtonReleaseMask 191 | | XConstants.EnterWindowMask | XConstants.LeaveWindowMask | XConstants.PointerMotionMask 192 | | XConstants.ButtonMotionMask | XConstants.ExposureMask | XConstants.StructureNotifyMask); 193 | 194 | if (target != null) { 195 | params.putIfNull(BOUNDS, new Rectangle(target.getBounds())); 196 | } else { 197 | params.putIfNull(BOUNDS, new Rectangle(0, 0, MIN_SIZE, MIN_SIZE)); 198 | } 199 | params.putIfNull(BORDER_PIXEL, Long.valueOf(0)); 200 | getColorModel(); // fix 4948833: this call forces the color map to be initialized 201 | params.putIfNull(COLORMAP, gData.get_awt_cmap()); 202 | params.putIfNull(DEPTH, gData.get_awt_depth()); 203 | params.putIfNull(VISUAL_CLASS, Integer.valueOf((int)XConstants.InputOutput)); 204 | params.putIfNull(VISUAL, visInfo.get_visual()); 205 | params.putIfNull(VALUE_MASK, XConstants.CWBorderPixel | XConstants.CWEventMask | XConstants.CWColormap); 206 | Long parentWindow = (Long)params.get(PARENT_WINDOW); 207 | if (parentWindow == null || parentWindow.longValue() == 0) { 208 | XToolkit.awtLock(); 209 | try { 210 | int screen = visInfo.get_screen(); 211 | if (screen != -1) { 212 | params.add(PARENT_WINDOW, XlibWrapper.RootWindow(XToolkit.getDisplay(), screen)); 213 | } else { 214 | params.add(PARENT_WINDOW, XToolkit.getDefaultRootWindow()); 215 | } 216 | } finally { 217 | XToolkit.awtUnlock(); 218 | } 219 | } 220 | 221 | paintArea = new XRepaintArea(); 222 | if (target != null) { 223 | this.parent = getParentXWindowObject(target.getParent()); 224 | } 225 | 226 | params.putIfNull(BACKING_STORE, XToolkit.getBackingStoreType()); 227 | 228 | XToolkit.awtLock(); 229 | try { 230 | if (wm_protocols == null) { 231 | wm_protocols = XAtom.get("WM_PROTOCOLS"); 232 | wm_delete_window = XAtom.get("WM_DELETE_WINDOW"); 233 | wm_take_focus = XAtom.get("WM_TAKE_FOCUS"); 234 | } 235 | } 236 | finally { 237 | XToolkit.awtUnlock(); 238 | } 239 | winAttr = new XWindowAttributesData(); 240 | savedState = XUtilConstants.WithdrawnState; 241 | } 242 | 243 | void postInit(XCreateWindowParams params) { 244 | super.postInit(params); 245 | 246 | setWMClass(getWMClass()); 247 | 248 | surfaceData = graphicsConfig.createSurfaceData(this); 249 | Color c; 250 | if (target != null && (c = target.getBackground()) != null) { 251 | // We need a version of setBackground that does not call repaint !! 252 | // and one that does not get overridden. The problem is that in postInit 253 | // we call setBackground and we dont have all the stuff initialized to 254 | // do a full paint for most peers. So we cannot call setBackground in postInit. 255 | // instead we need to call xSetBackground. 256 | xSetBackground(c); 257 | } 258 | } 259 | 260 | public GraphicsConfiguration getGraphicsConfiguration() { 261 | if (graphicsConfig == null) { 262 | initGraphicsConfiguration(); 263 | } 264 | return graphicsConfig; 265 | } 266 | 267 | public AwtGraphicsConfigData getGraphicsConfigurationData() { 268 | if (graphicsConfigData == null) { 269 | initGraphicsConfiguration(); 270 | } 271 | return graphicsConfigData; 272 | } 273 | 274 | protected String[] getWMClass() { 275 | return new String[] {XToolkit.getCorrectXIDString(getClass().getName()), XToolkit.getAWTAppClassName()}; 276 | } 277 | 278 | void setReparented(boolean newValue) { 279 | reparented = newValue; 280 | } 281 | 282 | boolean isReparented() { 283 | return reparented; 284 | } 285 | 286 | static long getParentWindowID(Component target) { 287 | 288 | ComponentPeer peer = target.getParent().getPeer(); 289 | Component temp = target.getParent(); 290 | while (!(peer instanceof XWindow)) 291 | { 292 | temp = temp.getParent(); 293 | peer = temp.getPeer(); 294 | } 295 | 296 | if (peer != null && peer instanceof XWindow) 297 | return ((XWindow)peer).getContentWindow(); 298 | else return 0; 299 | } 300 | 301 | 302 | static XWindow getParentXWindowObject(Component target) { 303 | if (target == null) return null; 304 | Component temp = target.getParent(); 305 | if (temp == null) return null; 306 | ComponentPeer peer = temp.getPeer(); 307 | if (peer == null) return null; 308 | while ((peer != null) && !(peer instanceof XWindow)) 309 | { 310 | temp = temp.getParent(); 311 | peer = temp.getPeer(); 312 | } 313 | if (peer != null && peer instanceof XWindow) 314 | return (XWindow) peer; 315 | else return null; 316 | } 317 | 318 | 319 | boolean isParentOf(XWindow win) { 320 | if (!(target instanceof Container) || win == null || win.getTarget() == null) { 321 | return false; 322 | } 323 | Container parent = AWTAccessor.getComponentAccessor().getParent(win.target); 324 | while (parent != null && parent != target) { 325 | parent = AWTAccessor.getComponentAccessor().getParent(parent); 326 | } 327 | return (parent == target); 328 | } 329 | 330 | public Object getTarget() { 331 | return target; 332 | } 333 | public Component getEventSource() { 334 | return target; 335 | } 336 | 337 | public ColorModel getColorModel(int transparency) { 338 | return graphicsConfig.getColorModel (transparency); 339 | } 340 | 341 | public ColorModel getColorModel() { 342 | if (graphicsConfig != null) { 343 | return graphicsConfig.getColorModel (); 344 | } 345 | else { 346 | return XToolkit.getStaticColorModel(); 347 | } 348 | } 349 | 350 | Graphics getGraphics(SurfaceData surfData, Color afore, Color aback, Font afont) { 351 | if (surfData == null) return null; 352 | 353 | Component target = (Component) this.target; 354 | 355 | /* Fix for bug 4746122. Color and Font shouldn't be null */ 356 | Color bgColor = aback; 357 | if (bgColor == null) { 358 | bgColor = SystemColor.window; 359 | } 360 | Color fgColor = afore; 361 | if (fgColor == null) { 362 | fgColor = SystemColor.windowText; 363 | } 364 | Font font = afont; 365 | if (font == null) { 366 | font = XWindow.getDefaultFont(); 367 | } 368 | return new SunGraphics2D(surfData, fgColor, bgColor, font); 369 | } 370 | 371 | public Graphics getGraphics() { 372 | return getGraphics(surfaceData, 373 | target.getForeground(), 374 | target.getBackground(), 375 | target.getFont()); 376 | } 377 | 378 | public FontMetrics getFontMetrics(Font font) { 379 | return Toolkit.getDefaultToolkit().getFontMetrics(font); 380 | } 381 | 382 | public Rectangle getTargetBounds() { 383 | return target.getBounds(); 384 | } 385 | 386 | /** 387 | * Returns true if the event has been handled and should not be 388 | * posted to Java. 389 | */ 390 | boolean prePostEvent(AWTEvent e) { 391 | return false; 392 | } 393 | 394 | static Method m_sendMessage; 395 | static void sendEvent(final AWTEvent e) { 396 | // The uses of this method imply that the incoming event is system-generated 397 | SunToolkit.setSystemGenerated(e); 398 | PeerEvent pe = new PeerEvent(Toolkit.getDefaultToolkit(), new Runnable() { 399 | public void run() { 400 | AWTAccessor.getAWTEventAccessor().setPosted(e); 401 | ((Component)e.getSource()).dispatchEvent(e); 402 | } 403 | }, PeerEvent.ULTIMATE_PRIORITY_EVENT); 404 | //if (focusLog.isLoggable(PlatformLogger.FINER) && (e instanceof FocusEvent)) focusLog.finer("Sending " + e); 405 | System.out.println("Sending " + e); 406 | XToolkit.postEvent(XToolkit.targetToAppContext(e.getSource()), pe); 407 | } 408 | 409 | 410 | /* 411 | * Post an event to the event queue. 412 | */ 413 | // NOTE: This method may be called by privileged threads. 414 | // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 415 | void postEvent(AWTEvent event) { 416 | XToolkit.postEvent(XToolkit.targetToAppContext(event.getSource()), event); 417 | } 418 | 419 | static void postEventStatic(AWTEvent event) { 420 | XToolkit.postEvent(XToolkit.targetToAppContext(event.getSource()), event); 421 | } 422 | 423 | public void postEventToEventQueue(final AWTEvent event) { 424 | //fix for 6239938 : Choice drop-down does not disappear when it loses focus, on XToolkit 425 | if (!prePostEvent(event)) { 426 | //event hasn't been handled and must be posted to EventQueue 427 | postEvent(event); 428 | } 429 | } 430 | 431 | // overriden in XCanvasPeer 432 | protected boolean doEraseBackground() { 433 | return true; 434 | } 435 | 436 | // We need a version of setBackground that does not call repaint !! 437 | // and one that does not get overridden. The problem is that in postInit 438 | // we call setBackground and we dont have all the stuff initialized to 439 | // do a full paint for most peers. So we cannot call setBackground in postInit. 440 | final public void xSetBackground(Color c) { 441 | XToolkit.awtLock(); 442 | try { 443 | winBackground(c); 444 | // fix for 6558510: handle sun.awt.noerasebackground flag, 445 | // see doEraseBackground() and preInit() methods in XCanvasPeer 446 | if (!doEraseBackground()) { 447 | return; 448 | } 449 | // 6304250: XAWT: Items in choice show a blue border on OpenGL + Solaris10 when background color is set 450 | // Note: When OGL is enabled, surfaceData.pixelFor() will not 451 | // return a pixel value appropriate for passing to 452 | // XSetWindowBackground(). Therefore, we will use the ColorModel 453 | // for this component in order to calculate a pixel value from 454 | // the given RGB value. 455 | ColorModel cm = getColorModel(); 456 | int pixel = PixelConverter.instance.rgbToPixel(c.getRGB(), cm); 457 | XlibWrapper.XSetWindowBackground(XToolkit.getDisplay(), getContentWindow(), pixel); 458 | } 459 | finally { 460 | XToolkit.awtUnlock(); 461 | } 462 | } 463 | 464 | public void setBackground(Color c) { 465 | xSetBackground(c); 466 | } 467 | 468 | Color backgroundColor; 469 | void winBackground(Color c) { 470 | backgroundColor = c; 471 | } 472 | 473 | public Color getWinBackground() { 474 | Color c = null; 475 | 476 | if (backgroundColor != null) { 477 | c = backgroundColor; 478 | } else if (parent != null) { 479 | c = parent.getWinBackground(); 480 | } 481 | 482 | if (c instanceof SystemColor) { 483 | c = new Color(c.getRGB()); 484 | } 485 | 486 | return c; 487 | } 488 | 489 | public boolean isEmbedded() { 490 | return embedded; 491 | } 492 | 493 | public void repaint(int x,int y, int width, int height) { 494 | if (!isVisible()) { 495 | return; 496 | } 497 | Graphics g = getGraphics(); 498 | if (g != null) { 499 | try { 500 | g.setClip(x,y,width,height); 501 | paint(g); 502 | } finally { 503 | g.dispose(); 504 | } 505 | } 506 | } 507 | 508 | public void repaint() { 509 | if (!isVisible()) { 510 | return; 511 | } 512 | Graphics g = getGraphics(); 513 | if (g != null) { 514 | try { 515 | paint(g); 516 | } finally { 517 | g.dispose(); 518 | } 519 | } 520 | } 521 | 522 | void paint(Graphics g) { 523 | } 524 | 525 | //used by Peers to avoid flickering withing paint() 526 | protected void flush(){ 527 | XToolkit.awtLock(); 528 | try { 529 | XlibWrapper.XFlush(XToolkit.getDisplay()); 530 | } finally { 531 | XToolkit.awtUnlock(); 532 | } 533 | } 534 | 535 | public void popup(int x, int y, int width, int height) { 536 | // TBD: grab the pointer 537 | xSetBounds(x, y, width, height); 538 | } 539 | 540 | public void handleExposeEvent(XEvent xev) { 541 | super.handleExposeEvent(xev); 542 | XExposeEvent xe = xev.get_xexpose(); 543 | if (isEventDisabled(xev)) { 544 | return; 545 | } 546 | int x = xe.get_x(); 547 | int y = xe.get_y(); 548 | int w = xe.get_width(); 549 | int h = xe.get_height(); 550 | 551 | Component target = (Component)getEventSource(); 552 | AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 553 | 554 | if (!compAccessor.getIgnoreRepaint(target) 555 | && compAccessor.getWidth(target) != 0 556 | && compAccessor.getHeight(target) != 0) 557 | { 558 | handleExposeEvent(target, x, y, w, h); 559 | } 560 | } 561 | 562 | public void handleExposeEvent(Component target, int x, int y, int w, int h) { 563 | PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher(). 564 | createPaintEvent(target, x, y, w, h); 565 | if (event != null) { 566 | postEventToEventQueue(event); 567 | } 568 | } 569 | 570 | static int getModifiers(int state, int button, int keyCode) { 571 | return getModifiers(state, button, keyCode, 0, false); 572 | } 573 | 574 | static int getModifiers(int state, int button, int keyCode, int type, boolean wheel_mouse) { 575 | int modifiers = 0; 576 | 577 | if (((state & XConstants.ShiftMask) != 0) ^ (keyCode == KeyEvent.VK_SHIFT)) { 578 | modifiers |= InputEvent.SHIFT_DOWN_MASK; 579 | } 580 | if (((state & XConstants.ControlMask) != 0) ^ (keyCode == KeyEvent.VK_CONTROL)) { 581 | modifiers |= InputEvent.CTRL_DOWN_MASK; 582 | } 583 | if (((state & XToolkit.metaMask) != 0) ^ (keyCode == KeyEvent.VK_META)) { 584 | modifiers |= InputEvent.META_DOWN_MASK; 585 | } 586 | if (((state & XToolkit.altMask) != 0) ^ (keyCode == KeyEvent.VK_ALT)) { 587 | modifiers |= InputEvent.ALT_DOWN_MASK; 588 | } 589 | if (((state & XToolkit.modeSwitchMask) != 0) ^ (keyCode == KeyEvent.VK_ALT_GRAPH)) { 590 | modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK; 591 | } 592 | //InputEvent.BUTTON_DOWN_MASK array is starting from BUTTON1_DOWN_MASK on index == 0. 593 | // button currently reflects a real button number and starts from 1. (except NOBUTTON which is zero ) 594 | 595 | /* this is an attempt to refactor button IDs in : MouseEvent, InputEvent, XlibWrapper and XWindow.*/ 596 | 597 | //reflects a button number similar to MouseEvent.BUTTON1, 2, 3 etc. 598 | for (int i = 0; i < XConstants.buttonsMask.length; i ++){ 599 | //modifier should be added if : 600 | // 1) current button is now still in PRESSED state (means that user just pressed mouse but not released yet) or 601 | // 2) if Xsystem reports that "state" represents that button was just released. This only happens on RELEASE with 1,2,3 buttons. 602 | // ONLY one of these conditions should be TRUE to add that modifier. 603 | if (((state & XConstants.buttonsMask[i]) != 0) != (button == XConstants.buttons[i])){ 604 | //exclude wheel buttons from adding their numbers as modifiers 605 | if (!wheel_mouse) { 606 | modifiers |= InputEvent.getMaskForButton(i+1); 607 | } 608 | } 609 | } 610 | return modifiers; 611 | } 612 | 613 | static int getXModifiers(AWTKeyStroke stroke) { 614 | int mods = stroke.getModifiers(); 615 | int res = 0; 616 | if ((mods & (InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK)) != 0) { 617 | res |= XConstants.ShiftMask; 618 | } 619 | if ((mods & (InputEvent.CTRL_DOWN_MASK | InputEvent.CTRL_MASK)) != 0) { 620 | res |= XConstants.ControlMask; 621 | } 622 | if ((mods & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_MASK)) != 0) { 623 | res |= XToolkit.altMask; 624 | } 625 | if ((mods & (InputEvent.META_DOWN_MASK | InputEvent.META_MASK)) != 0) { 626 | res |= XToolkit.metaMask; 627 | } 628 | if ((mods & (InputEvent.ALT_GRAPH_DOWN_MASK | InputEvent.ALT_GRAPH_MASK)) != 0) { 629 | res |= XToolkit.modeSwitchMask; 630 | } 631 | return res; 632 | } 633 | 634 | /** 635 | * Returns true if this event is disabled and shouldn't be passed to Java. 636 | * Default implementation returns false for all events. 637 | */ 638 | static int getRightButtonNumber() { 639 | if (rbutton == 0) { // not initialized yet 640 | XToolkit.awtLock(); 641 | try { 642 | rbutton = XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), XlibWrapper.ibuffer, 3); 643 | } 644 | finally { 645 | XToolkit.awtUnlock(); 646 | } 647 | } 648 | return rbutton; 649 | } 650 | 651 | static int getMouseMovementSmudge() { 652 | //TODO: It's possible to read corresponding settings 653 | return AWT_MULTICLICK_SMUDGE; 654 | } 655 | 656 | public void handleButtonPressRelease(XEvent xev) { 657 | super.handleButtonPressRelease(xev); 658 | XButtonEvent xbe = xev.get_xbutton(); 659 | if (isEventDisabled(xev)) { 660 | return; 661 | } 662 | //if (eventLog.isLoggable(PlatformLogger.FINE)) eventLog.fine(xbe.toString()); 663 | long when; 664 | int modifiers; 665 | boolean popupTrigger = false; 666 | int button=0; 667 | boolean wheel_mouse = false; 668 | int lbutton = xbe.get_button(); 669 | /* 670 | * Ignore the buttons above 20 due to the bit limit for 671 | * InputEvent.BUTTON_DOWN_MASK. 672 | * One more bit is reserved for FIRST_HIGH_BIT. 673 | */ 674 | if (lbutton > SunToolkit.MAX_BUTTONS_SUPPORTED) { 675 | return; 676 | } 677 | int type = xev.get_type(); 678 | when = xbe.get_time(); 679 | long jWhen = XToolkit.nowMillisUTC_offset(when); 680 | 681 | int x = xbe.get_x(); 682 | int y = xbe.get_y(); 683 | if (xev.get_xany().get_window() != window) { 684 | Point localXY = toLocal(xbe.get_x_root(), xbe.get_y_root()); 685 | x = localXY.x; 686 | y = localXY.y; 687 | } 688 | 689 | if (type == XConstants.ButtonPress) { 690 | //Allow this mouse button to generate CLICK event on next ButtonRelease 691 | mouseButtonClickAllowed |= XConstants.buttonsMask[lbutton]; 692 | XWindow lastWindow = (lastWindowRef != null) ? ((XWindow)lastWindowRef.get()):(null); 693 | /* 694 | multiclick checking 695 | */ 696 | // if (eventLog.isLoggable(PlatformLogger.FINEST)) eventLog.finest("lastWindow = " + lastWindow + ", lastButton " 697 | // + lastButton + ", lastTime " + lastTime + ", multiClickTime " 698 | // + XToolkit.getMultiClickTime()); 699 | if (lastWindow == this && lastButton == lbutton && (when - lastTime) < XToolkit.getMultiClickTime()) { 700 | clickCount++; 701 | } else { 702 | clickCount = 1; 703 | lastWindowRef = new WeakReference(this); 704 | lastButton = lbutton; 705 | lastX = x; 706 | lastY = y; 707 | } 708 | lastTime = when; 709 | 710 | 711 | /* 712 | Check for popup trigger !! 713 | */ 714 | if (lbutton == getRightButtonNumber() || lbutton > 2) { 715 | popupTrigger = true; 716 | } else { 717 | popupTrigger = false; 718 | } 719 | } 720 | 721 | button = XConstants.buttons[lbutton - 1]; 722 | // 4 and 5 buttons are usually considered assigned to a first wheel 723 | if (lbutton == XConstants.buttons[3] || 724 | lbutton == XConstants.buttons[4]) { 725 | wheel_mouse = true; 726 | } 727 | 728 | // mapping extra buttons to numbers starting from 4. 729 | if ((button > XConstants.buttons[4]) && (!Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled())){ 730 | return; 731 | } 732 | 733 | if (button > XConstants.buttons[4]){ 734 | button -= 2; 735 | } 736 | modifiers = getModifiers(xbe.get_state(),button,0, type, wheel_mouse); 737 | 738 | if (!wheel_mouse) { 739 | MouseEvent me = new MouseEvent((Component)getEventSource(), 740 | type == XConstants.ButtonPress ? MouseEvent.MOUSE_PRESSED : MouseEvent.MOUSE_RELEASED, 741 | jWhen,modifiers, x, y, 742 | xbe.get_x_root(), 743 | xbe.get_y_root(), 744 | clickCount,popupTrigger,button); 745 | 746 | postEventToEventQueue(me); 747 | 748 | if ((type == XConstants.ButtonRelease) && 749 | ((mouseButtonClickAllowed & XConstants.buttonsMask[lbutton]) != 0) ) // No up-button in the drag-state 750 | { 751 | postEventToEventQueue(me = new MouseEvent((Component)getEventSource(), 752 | MouseEvent.MOUSE_CLICKED, 753 | jWhen, 754 | modifiers, 755 | x, y, 756 | xbe.get_x_root(), 757 | xbe.get_y_root(), 758 | clickCount, 759 | false, button)); 760 | } 761 | 762 | } 763 | else { 764 | if (xev.get_type() == XConstants.ButtonPress) { 765 | MouseWheelEvent mwe = new MouseWheelEvent((Component)getEventSource(),MouseEvent.MOUSE_WHEEL, jWhen, 766 | modifiers, 767 | x, y, 768 | xbe.get_x_root(), 769 | xbe.get_y_root(), 770 | 1,false,MouseWheelEvent.WHEEL_UNIT_SCROLL, 771 | 3,button==4 ? -1 : 1); 772 | postEventToEventQueue(mwe); 773 | } 774 | } 775 | 776 | /* Update the state variable AFTER the CLICKED event post. */ 777 | if (type == XConstants.ButtonRelease) { 778 | /* Exclude this mouse button from allowed list.*/ 779 | mouseButtonClickAllowed &= ~XConstants.buttonsMask[lbutton]; 780 | } 781 | } 782 | 783 | public void handleMotionNotify(XEvent xev) { 784 | super.handleMotionNotify(xev); 785 | XMotionEvent xme = xev.get_xmotion(); 786 | if (isEventDisabled(xev)) { 787 | return; 788 | } 789 | 790 | int mouseKeyState = 0; //(xme.get_state() & (XConstants.buttonsMask[0] | XConstants.buttonsMask[1] | XConstants.buttonsMask[2])); 791 | 792 | //this doesn't work for extra buttons because Xsystem is sending state==0 for every extra button event. 793 | // we can't correct it in MouseEvent class as we done it with modifiers, because exact type (DRAG|MOVE) 794 | // should be passed from XWindow. 795 | final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons(); 796 | 797 | for (int i = 0; i < buttonsNumber; i++){ 798 | // TODO : here is the bug in WM: extra buttons doesn't have state!=0 as they should. 799 | if ((i != 4) && (i != 5)) { 800 | mouseKeyState = mouseKeyState | (xme.get_state() & XConstants.buttonsMask[i]); 801 | } 802 | } 803 | 804 | boolean isDragging = (mouseKeyState != 0); 805 | int mouseEventType = 0; 806 | 807 | if (isDragging) { 808 | mouseEventType = MouseEvent.MOUSE_DRAGGED; 809 | } else { 810 | mouseEventType = MouseEvent.MOUSE_MOVED; 811 | } 812 | 813 | /* 814 | Fix for 6176814 . Add multiclick checking. 815 | */ 816 | int x = xme.get_x(); 817 | int y = xme.get_y(); 818 | XWindow lastWindow = (lastWindowRef != null) ? ((XWindow)lastWindowRef.get()):(null); 819 | 820 | if (!(lastWindow == this && 821 | (xme.get_time() - lastTime) < XToolkit.getMultiClickTime() && 822 | (Math.abs(lastX - x) < AWT_MULTICLICK_SMUDGE && 823 | Math.abs(lastY - y) < AWT_MULTICLICK_SMUDGE))) { 824 | clickCount = 0; 825 | lastWindowRef = null; 826 | mouseButtonClickAllowed = 0; 827 | lastTime = 0; 828 | lastX = 0; 829 | lastY = 0; 830 | } 831 | 832 | long jWhen = XToolkit.nowMillisUTC_offset(xme.get_time()); 833 | int modifiers = getModifiers(xme.get_state(), 0, 0); 834 | boolean popupTrigger = false; 835 | 836 | Component source = (Component)getEventSource(); 837 | 838 | if (xme.get_window() != window) { 839 | Point localXY = toLocal(xme.get_x_root(), xme.get_y_root()); 840 | x = localXY.x; 841 | y = localXY.y; 842 | } 843 | /* Fix for 5039416. 844 | * According to canvas.c we shouldn't post any MouseEvent if mouse is dragging and clickCount!=0. 845 | */ 846 | if ((isDragging && clickCount == 0) || !isDragging) { 847 | MouseEvent mme = new MouseEvent(source, mouseEventType, jWhen, 848 | modifiers, x, y, xme.get_x_root(), xme.get_y_root(), 849 | clickCount, popupTrigger, MouseEvent.NOBUTTON); 850 | postEventToEventQueue(mme); 851 | } 852 | } 853 | 854 | 855 | // REMIND: need to implement looking for disabled events 856 | public native boolean x11inputMethodLookupString(long event, long [] keysymArray); 857 | native boolean haveCurrentX11InputMethodInstance(); 858 | 859 | private boolean mouseAboveMe; 860 | 861 | public boolean isMouseAbove() { 862 | synchronized (getStateLock()) { 863 | return mouseAboveMe; 864 | } 865 | } 866 | protected void setMouseAbove(boolean above) { 867 | synchronized (getStateLock()) { 868 | mouseAboveMe = above; 869 | } 870 | } 871 | 872 | protected void enterNotify(long window) { 873 | if (window == getWindow()) { 874 | setMouseAbove(true); 875 | } 876 | } 877 | protected void leaveNotify(long window) { 878 | if (window == getWindow()) { 879 | setMouseAbove(false); 880 | } 881 | } 882 | 883 | public void handleXCrossingEvent(XEvent xev) { 884 | super.handleXCrossingEvent(xev); 885 | XCrossingEvent xce = xev.get_xcrossing(); 886 | 887 | // if (eventLog.isLoggable(PlatformLogger.FINEST)) eventLog.finest(xce.toString()); 888 | 889 | if (xce.get_type() == XConstants.EnterNotify) { 890 | enterNotify(xce.get_window()); 891 | } else { // LeaveNotify: 892 | leaveNotify(xce.get_window()); 893 | } 894 | 895 | // Skip event If it was caused by a grab 896 | // This is needed because on displays with focus-follows-mouse on MousePress X system generates 897 | // two XCrossing events with mode != NormalNotify. First of them notifies that the mouse has left 898 | // current component. Second one notifies that it has entered into the same component. 899 | // This looks like the window under the mouse has actually changed and Java handle these events 900 | // accordingly. This leads to impossibility to make a double click on Component (6404708) 901 | XWindowPeer toplevel = getToplevelXWindow(); 902 | if (toplevel != null && !toplevel.isModalBlocked()){ 903 | if (xce.get_mode() != XConstants.NotifyNormal) { 904 | // 6404708 : need update cursor in accordance with skipping Leave/EnterNotify event 905 | // whereas it doesn't need to handled further. 906 | if (xce.get_type() == XConstants.EnterNotify) { 907 | XAwtState.setComponentMouseEntered(getEventSource()); 908 | XGlobalCursorManager.nativeUpdateCursor(getEventSource()); 909 | } else { // LeaveNotify: 910 | XAwtState.setComponentMouseEntered(null); 911 | } 912 | return; 913 | } 914 | } 915 | // X sends XCrossing to all hierarchy so if the edge of child equals to 916 | // ancestor and mouse enters child, the ancestor will get an event too. 917 | // From java point the event is bogus as ancestor is obscured, so if 918 | // the child can get java event itself, we skip it on ancestor. 919 | long childWnd = xce.get_subwindow(); 920 | if (childWnd != XConstants.None) { 921 | XBaseWindow child = XToolkit.windowToXWindow(childWnd); 922 | if (child != null && child instanceof XWindow && 923 | !child.isEventDisabled(xev)) 924 | { 925 | return; 926 | } 927 | } 928 | 929 | // Remember old component with mouse to have the opportunity to send it MOUSE_EXITED. 930 | final Component compWithMouse = XAwtState.getComponentMouseEntered(); 931 | if (toplevel != null) { 932 | if(!toplevel.isModalBlocked()){ 933 | if (xce.get_type() == XConstants.EnterNotify) { 934 | // Change XAwtState's component mouse entered to the up-to-date one before requesting 935 | // to update the cursor since XAwtState.getComponentMouseEntered() is used when the 936 | // cursor is updated (in XGlobalCursorManager.findHeavyweightUnderCursor()). 937 | XAwtState.setComponentMouseEntered(getEventSource()); 938 | XGlobalCursorManager.nativeUpdateCursor(getEventSource()); 939 | } else { // LeaveNotify: 940 | XAwtState.setComponentMouseEntered(null); 941 | } 942 | } else { 943 | ((XComponentPeer) AWTAccessor.getComponentAccessor().getPeer(target)) 944 | .pSetCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 945 | } 946 | } 947 | 948 | if (isEventDisabled(xev)) { 949 | return; 950 | } 951 | 952 | long jWhen = XToolkit.nowMillisUTC_offset(xce.get_time()); 953 | int modifiers = getModifiers(xce.get_state(),0,0); 954 | int clickCount = 0; 955 | boolean popupTrigger = false; 956 | int x = xce.get_x(); 957 | int y = xce.get_y(); 958 | if (xce.get_window() != window) { 959 | Point localXY = toLocal(xce.get_x_root(), xce.get_y_root()); 960 | x = localXY.x; 961 | y = localXY.y; 962 | } 963 | 964 | // This code tracks boundary crossing and ensures MOUSE_ENTER/EXIT 965 | // are posted in alternate pairs 966 | if (compWithMouse != null) { 967 | MouseEvent me = new MouseEvent(compWithMouse, 968 | MouseEvent.MOUSE_EXITED, jWhen, modifiers, xce.get_x(), 969 | xce.get_y(), xce.get_x_root(), xce.get_y_root(), clickCount, popupTrigger, 970 | MouseEvent.NOBUTTON); 971 | postEventToEventQueue(me); 972 | // eventLog.finest("Clearing last window ref"); 973 | lastWindowRef = null; 974 | } 975 | if (xce.get_type() == XConstants.EnterNotify) { 976 | MouseEvent me = new MouseEvent(getEventSource(), MouseEvent.MOUSE_ENTERED, 977 | jWhen, modifiers, xce.get_x(), xce.get_y(), xce.get_x_root(), xce.get_y_root(), clickCount, 978 | popupTrigger, MouseEvent.NOBUTTON); 979 | postEventToEventQueue(me); 980 | } 981 | } 982 | 983 | public void doLayout(int x, int y, int width, int height) {} 984 | 985 | public void handleConfigureNotifyEvent(XEvent xev) { 986 | Rectangle oldBounds = getBounds(); 987 | 988 | super.handleConfigureNotifyEvent(xev); 989 | // insLog.finer("Configure, {0}, event disabled: {1}",xev.get_xconfigure(), isEventDisabled(xev)); 990 | if (isEventDisabled(xev)) { 991 | return; 992 | } 993 | 994 | // if ( Check if it's a resize, a move, or a stacking order change ) 995 | // { 996 | Rectangle bounds = getBounds(); 997 | if (!bounds.getSize().equals(oldBounds.getSize())) { 998 | postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_RESIZED)); 999 | } 1000 | if (!bounds.getLocation().equals(oldBounds.getLocation())) { 1001 | postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_MOVED)); 1002 | } 1003 | // } 1004 | } 1005 | 1006 | public void handleMapNotifyEvent(XEvent xev) { 1007 | super.handleMapNotifyEvent(xev); 1008 | // log.fine("Mapped {0}", this); 1009 | if (isEventDisabled(xev)) { 1010 | return; 1011 | } 1012 | ComponentEvent ce; 1013 | 1014 | ce = new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_SHOWN); 1015 | postEventToEventQueue(ce); 1016 | } 1017 | 1018 | public void handleUnmapNotifyEvent(XEvent xev) { 1019 | super.handleUnmapNotifyEvent(xev); 1020 | if (isEventDisabled(xev)) { 1021 | return; 1022 | } 1023 | ComponentEvent ce; 1024 | 1025 | ce = new ComponentEvent(target, ComponentEvent.COMPONENT_HIDDEN); 1026 | postEventToEventQueue(ce); 1027 | } 1028 | 1029 | private void dumpKeysymArray(XKeyEvent ev) { 1030 | System.out.println(" "+Long.toHexString(XlibWrapper.XKeycodeToKeysym(XToolkit.getDisplay(), ev.get_keycode(), 0))+ 1031 | "\n "+Long.toHexString(XlibWrapper.XKeycodeToKeysym(XToolkit.getDisplay(), ev.get_keycode(), 1))+ 1032 | "\n "+Long.toHexString(XlibWrapper.XKeycodeToKeysym(XToolkit.getDisplay(), ev.get_keycode(), 2))+ 1033 | "\n "+Long.toHexString(XlibWrapper.XKeycodeToKeysym(XToolkit.getDisplay(), ev.get_keycode(), 3))); 1034 | } 1035 | /** 1036 | Return unicode character or 0 if no correspondent character found. 1037 | Parameter is a keysym basically from keysymdef.h 1038 | XXX: how about vendor keys? Is there some with Unicode value and not in the list? 1039 | */ 1040 | int keysymToUnicode( long keysym, int state ) { 1041 | return XKeysym.convertKeysym( keysym, state ); 1042 | } 1043 | int keyEventType2Id( int xEventType ) { 1044 | return xEventType == XConstants.KeyPress ? java.awt.event.KeyEvent.KEY_PRESSED : 1045 | xEventType == XConstants.KeyRelease ? java.awt.event.KeyEvent.KEY_RELEASED : 0; 1046 | } 1047 | static private long xkeycodeToKeysym(XKeyEvent ev) { 1048 | return XKeysym.getKeysym( ev ); 1049 | } 1050 | private long xkeycodeToPrimaryKeysym(XKeyEvent ev) { 1051 | return XKeysym.xkeycode2primary_keysym( ev ); 1052 | } 1053 | static private int primaryUnicode2JavaKeycode(int uni) { 1054 | return (uni > 0? sun.awt.ExtendedKeyCodes.getExtendedKeyCodeForChar(uni) : 0); 1055 | //return (uni > 0? uni + 0x01000000 : 0); 1056 | } 1057 | void logIncomingKeyEvent(XKeyEvent ev) { 1058 | System.out.println("--XWindow.java:handleKeyEvent:" + ev); 1059 | dumpKeysymArray(ev); 1060 | System.out.println("XXXXXXXXXXXXXX javakeycode will be most probably:0x" + Integer.toHexString(XKeysym.getJavaKeycodeOnly(ev))); 1061 | } 1062 | public void handleKeyPress(XEvent xev) { 1063 | super.handleKeyPress(xev); 1064 | XKeyEvent ev = xev.get_xkey(); 1065 | // if (eventLog.isLoggable(PlatformLogger.FIN)) 1066 | System.out.println(ev.toString()); 1067 | if (isEventDisabled(xev)) { 1068 | return; 1069 | } 1070 | handleKeyPress(ev); 1071 | } 1072 | // called directly from this package, unlike handleKeyRelease. 1073 | // un-final it if you need to override it in a subclass. 1074 | final void handleKeyPress(XKeyEvent ev) { 1075 | long keysym[] = new long[2]; 1076 | int unicodeKey = 0; 1077 | keysym[0] = XConstants.NoSymbol; 1078 | 1079 | // if (keyEventLog.isLoggable(PlatformLogger.FINE)) { 1080 | logIncomingKeyEvent( ev ); 1081 | // } 1082 | if ( //TODO check if there's an active input method instance 1083 | // without calling a native method. Is it necessary though? 1084 | haveCurrentX11InputMethodInstance()) { 1085 | if (x11inputMethodLookupString(ev.pData, keysym)) { 1086 | // if (keyEventLog.isLoggable(PlatformLogger.FINE)) { 1087 | System.out.println("--XWindow.java XIM did process event; return; dec keysym processed:"+(keysym[0])+ 1088 | "; hex keysym processed:"+Long.toHexString(keysym[0]) 1089 | ); 1090 | // } 1091 | return; 1092 | }else { 1093 | unicodeKey = keysymToUnicode( keysym[0], ev.get_state() ); 1094 | // if (keyEventLog.isLoggable(PlatformLogger.FINE)) { 1095 | System.out.println("--XWindow.java XIM did NOT process event, hex keysym:"+Long.toHexString(keysym[0])+"\n"+ 1096 | " unicode key:"+Integer.toHexString((int)unicodeKey)); 1097 | // } 1098 | } 1099 | }else { 1100 | // No input method instance found. For example, there's a Java Input Method. 1101 | // Produce do-it-yourself keysym and perhaps unicode character. 1102 | keysym[0] = xkeycodeToKeysym(ev); 1103 | unicodeKey = keysymToUnicode( keysym[0], ev.get_state() ); 1104 | // if (keyEventLog.isLoggable(PlatformLogger.FINE)) { 1105 | System.out.println("--XWindow.java XIM is absent; hex keysym:"+Long.toHexString(keysym[0])+"\n"+ 1106 | " unicode key:"+Integer.toHexString((int)unicodeKey)); 1107 | // } 1108 | } 1109 | // Keysym should be converted to Unicode, if possible and necessary, 1110 | // and Java KeyEvent keycode should be calculated. 1111 | // For press we should post pressed & typed Java events. 1112 | // 1113 | // Press event might be not processed to this time because 1114 | // (1) either XIM could not handle it or 1115 | // (2) it was Latin 1:1 mapping. 1116 | // 1117 | XKeysym.Keysym2JavaKeycode jkc = XKeysym.getJavaKeycode(ev); 1118 | if( jkc == null ) { 1119 | jkc = new XKeysym.Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_UNDEFINED, java.awt.event.KeyEvent.KEY_LOCATION_UNKNOWN); 1120 | } 1121 | 1122 | // Take the first keysym from a keysym array associated with the XKeyevent 1123 | // and convert it to Unicode. Then, even if a Java keycode for the keystroke 1124 | // is undefined, we still have a guess of what has been engraved on a keytop. 1125 | int unicodeFromPrimaryKeysym = keysymToUnicode( xkeycodeToPrimaryKeysym(ev) ,0); 1126 | 1127 | // if (keyEventLog.isLoggable(PlatformLogger.FINE)) { 1128 | // System.out.println(">>>Fire Event:"+ 1129 | // (ev.get_type() == XConstants.KeyPress ? "KEY_PRESSED; " : "KEY_RELEASED; ")+ 1130 | // "jkeycode:decimal="+jkc.getJavaKeycode()+ 1131 | // ", hex=0x"+Integer.toHexString(jkc.getJavaKeycode())+"; "+ 1132 | // " legacy jkeycode: decimal="+XKeysym.getLegacyJavaKeycodeOnly(ev)+ 1133 | // ", hex=0x"+Integer.toHexString(XKeysym.getLegacyJavaKeycodeOnly(ev))+"; " 1134 | // ); 1135 | // } 1136 | 1137 | int jkeyToReturn = XKeysym.getLegacyJavaKeycodeOnly(ev); // someway backward compatible 1138 | int jkeyExtended = jkc.getJavaKeycode() == java.awt.event.KeyEvent.VK_UNDEFINED ? 1139 | primaryUnicode2JavaKeycode( unicodeFromPrimaryKeysym ) : 1140 | jkc.getJavaKeycode(); 1141 | System.out.println("!!!!!!!!!!!!!"); 1142 | System.out.println("unicodeKey="+unicodeKey+" jkeyToReturn="+jkeyToReturn+" ev.get_state()="+ev.get_state()+" ev.getPData()="+ev.getPData()+" (long)(ev.get_keycode())="+(long)(ev.get_keycode())+" unicodeFromPrimaryKeysym="+unicodeFromPrimaryKeysym+" jkeyExtended="+jkeyExtended ); 1143 | 1144 | postKeyEvent(java.awt.event.KeyEvent.KEY_PRESSED, 1145 | ev.get_time(), 1146 | jkeyToReturn, 1147 | (unicodeKey == 0 ? java.awt.event.KeyEvent.CHAR_UNDEFINED : unicodeKey), 1148 | jkc.getKeyLocation(), 1149 | ev.get_state(), ev.getPData(), XKeyEvent.getSize(), (long) (ev.get_keycode()), 1150 | unicodeFromPrimaryKeysym, 1151 | jkeyExtended); 1152 | 1153 | 1154 | if( unicodeKey > 0 ) { 1155 | System.out.println("fire _TYPED on "+unicodeKey); 1156 | postKeyEvent( java.awt.event.KeyEvent.KEY_TYPED, 1157 | ev.get_time(), 1158 | java.awt.event.KeyEvent.VK_UNDEFINED, 1159 | unicodeKey, 1160 | java.awt.event.KeyEvent.KEY_LOCATION_UNKNOWN, 1161 | ev.get_state(),ev.getPData(), XKeyEvent.getSize(), (long)0, 1162 | unicodeFromPrimaryKeysym, 1163 | java.awt.event.KeyEvent.VK_UNDEFINED); 1164 | 1165 | } 1166 | 1167 | 1168 | } 1169 | 1170 | public void handleKeyRelease(XEvent xev) { 1171 | super.handleKeyRelease(xev); 1172 | XKeyEvent ev = xev.get_xkey(); 1173 | // if (eventLog.isLoggable(PlatformLogger.FINE)) 1174 | System.out.println(ev.toString()); 1175 | if (isEventDisabled(xev)) { 1176 | return; 1177 | } 1178 | handleKeyRelease(ev); 1179 | } 1180 | // un-private it if you need to call it from elsewhere 1181 | private void handleKeyRelease(XKeyEvent ev) { 1182 | long keysym[] = new long[2]; 1183 | int unicodeKey = 0; 1184 | keysym[0] = XConstants.NoSymbol; 1185 | 1186 | // if (keyEventLog.isLoggable(PlatformLogger.FINE)) { 1187 | logIncomingKeyEvent( ev ); 1188 | // } 1189 | // Keysym should be converted to Unicode, if possible and necessary, 1190 | // and Java KeyEvent keycode should be calculated. 1191 | // For release we should post released event. 1192 | // 1193 | XKeysym.Keysym2JavaKeycode jkc = XKeysym.getJavaKeycode(ev); 1194 | if( jkc == null ) { 1195 | jkc = new XKeysym.Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_UNDEFINED, java.awt.event.KeyEvent.KEY_LOCATION_UNKNOWN); 1196 | } 1197 | // if (keyEventLog.isLoggable(PlatformLogger.FINE)) { 1198 | System.out.println(">>>Fire Event:"+ 1199 | (ev.get_type() == XConstants.KeyPress ? "KEY_PRESSED; " : "KEY_RELEASED; ")+ 1200 | "jkeycode:decimal="+jkc.getJavaKeycode()+ 1201 | ", hex=0x"+Integer.toHexString(jkc.getJavaKeycode())+"; "+ 1202 | " legacy jkeycode: decimal="+XKeysym.getLegacyJavaKeycodeOnly(ev)+ 1203 | ", hex=0x"+Integer.toHexString(XKeysym.getLegacyJavaKeycodeOnly(ev))+"; " 1204 | ); 1205 | // } 1206 | // We obtain keysym from IM and derive unicodeKey from it for KeyPress only. 1207 | // We used to cache that value and retrieve it on KeyRelease, 1208 | // but in case for example of a dead key+vowel pair, a vowel after a deadkey 1209 | // might never be cached before. 1210 | // Also, switching between keyboard layouts, we might cache a wrong letter. 1211 | // That's why we use the same procedure as if there was no IM instance: do-it-yourself unicode. 1212 | unicodeKey = keysymToUnicode( xkeycodeToKeysym(ev), ev.get_state() ); 1213 | 1214 | // Take a first keysym from a keysym array associated with the XKeyevent 1215 | // and convert it to Unicode. Then, even if Java keycode for the keystroke 1216 | // is undefined, we still will have a guess of what was engraved on a keytop. 1217 | int unicodeFromPrimaryKeysym = keysymToUnicode( xkeycodeToPrimaryKeysym(ev) ,0); 1218 | 1219 | int jkeyToReturn = XKeysym.getLegacyJavaKeycodeOnly(ev); // someway backward compatible 1220 | int jkeyExtended = jkc.getJavaKeycode() == java.awt.event.KeyEvent.VK_UNDEFINED ? 1221 | primaryUnicode2JavaKeycode( unicodeFromPrimaryKeysym ) : 1222 | jkc.getJavaKeycode(); 1223 | postKeyEvent( java.awt.event.KeyEvent.KEY_RELEASED, 1224 | ev.get_time(), 1225 | jkeyToReturn, 1226 | (unicodeKey == 0 ? java.awt.event.KeyEvent.CHAR_UNDEFINED : unicodeKey), 1227 | jkc.getKeyLocation(), 1228 | ev.get_state(),ev.getPData(), XKeyEvent.getSize(), (long)(ev.get_keycode()), 1229 | unicodeFromPrimaryKeysym, 1230 | jkeyExtended); 1231 | 1232 | 1233 | } 1234 | 1235 | /* 1236 | * XmNiconic and Map/UnmapNotify (that XmNiconic relies on) are 1237 | * unreliable, since mapping changes can happen for a virtual desktop 1238 | * switch or MacOS style shading that became quite popular under X as 1239 | * well. Yes, it probably should not be this way, as it violates 1240 | * ICCCM, but reality is that quite a lot of window managers abuse 1241 | * mapping state. 1242 | */ 1243 | int getWMState() { 1244 | if (stateChanged) { 1245 | stateChanged = false; 1246 | WindowPropertyGetter getter = 1247 | new WindowPropertyGetter(window, XWM.XA_WM_STATE, 0, 1, false, 1248 | XWM.XA_WM_STATE); 1249 | try { 1250 | int status = getter.execute(); 1251 | if (status != XConstants.Success || getter.getData() == 0) { 1252 | return savedState = XUtilConstants.WithdrawnState; 1253 | } 1254 | 1255 | if (getter.getActualType() != XWM.XA_WM_STATE.getAtom() && getter.getActualFormat() != 32) { 1256 | return savedState = XUtilConstants.WithdrawnState; 1257 | } 1258 | savedState = (int)Native.getCard32(getter.getData()); 1259 | } finally { 1260 | getter.dispose(); 1261 | } 1262 | } 1263 | return savedState; 1264 | } 1265 | 1266 | /** 1267 | * Override this methods to get notifications when top-level window state changes. The state is 1268 | * meant in terms of ICCCM: WithdrawnState, IconicState, NormalState 1269 | */ 1270 | protected void stateChanged(long time, int oldState, int newState) { 1271 | } 1272 | 1273 | @Override 1274 | public void handlePropertyNotify(XEvent xev) { 1275 | super.handlePropertyNotify(xev); 1276 | XPropertyEvent ev = xev.get_xproperty(); 1277 | if (ev.get_atom() == XWM.XA_WM_STATE.getAtom()) { 1278 | // State has changed, invalidate saved value 1279 | stateChanged = true; 1280 | stateChanged(ev.get_time(), savedState, getWMState()); 1281 | } 1282 | } 1283 | 1284 | public void reshape(Rectangle bounds) { 1285 | reshape(bounds.x, bounds.y, bounds.width, bounds.height); 1286 | } 1287 | 1288 | public void reshape(int x, int y, int width, int height) { 1289 | if (width <= 0) { 1290 | width = 1; 1291 | } 1292 | if (height <= 0) { 1293 | height = 1; 1294 | } 1295 | this.x = x; 1296 | this.y = y; 1297 | this.width = width; 1298 | this.height = height; 1299 | xSetBounds(x, y, width, height); 1300 | // Fixed 6322593, 6304251, 6315137: 1301 | // XWindow's SurfaceData should be invalidated and recreated as part 1302 | // of the process of resizing the window 1303 | // see the evaluation of the bug 6304251 for more information 1304 | validateSurface(); 1305 | layout(); 1306 | } 1307 | 1308 | public void layout() {} 1309 | 1310 | boolean isShowing() { 1311 | return visible; 1312 | } 1313 | 1314 | boolean isResizable() { 1315 | return true; 1316 | } 1317 | 1318 | boolean isLocationByPlatform() { 1319 | return false; 1320 | } 1321 | 1322 | void updateSizeHints() { 1323 | updateSizeHints(x, y, width, height); 1324 | } 1325 | 1326 | void updateSizeHints(int x, int y, int width, int height) { 1327 | long flags = XUtilConstants.PSize | (isLocationByPlatform() ? 0 : (XUtilConstants.PPosition | XUtilConstants.USPosition)); 1328 | if (!isResizable()) { 1329 | // log.finer("Window {0} is not resizable", this); 1330 | flags |= XUtilConstants.PMinSize | XUtilConstants.PMaxSize; 1331 | } else { 1332 | // log.finer("Window {0} is resizable", this); 1333 | } 1334 | setSizeHints(flags, x, y, width, height); 1335 | } 1336 | 1337 | void updateSizeHints(int x, int y) { 1338 | long flags = isLocationByPlatform() ? 0 : (XUtilConstants.PPosition | XUtilConstants.USPosition); 1339 | if (!isResizable()) { 1340 | // log.finer("Window {0} is not resizable", this); 1341 | flags |= XUtilConstants.PMinSize | XUtilConstants.PMaxSize | XUtilConstants.PSize; 1342 | } else { 1343 | // log.finer("Window {0} is resizable", this); 1344 | } 1345 | setSizeHints(flags, x, y, width, height); 1346 | } 1347 | 1348 | void validateSurface() { 1349 | if ((width != oldWidth) || (height != oldHeight)) { 1350 | doValidateSurface(); 1351 | 1352 | oldWidth = width; 1353 | oldHeight = height; 1354 | } 1355 | } 1356 | 1357 | final void doValidateSurface() { 1358 | SurfaceData oldData = surfaceData; 1359 | if (oldData != null) { 1360 | surfaceData = graphicsConfig.createSurfaceData(this); 1361 | oldData.invalidate(); 1362 | } 1363 | } 1364 | 1365 | public SurfaceData getSurfaceData() { 1366 | return surfaceData; 1367 | } 1368 | 1369 | public void dispose() { 1370 | SurfaceData oldData = surfaceData; 1371 | surfaceData = null; 1372 | if (oldData != null) { 1373 | oldData.invalidate(); 1374 | } 1375 | XToolkit.targetDisposedPeer(target, this); 1376 | destroy(); 1377 | } 1378 | 1379 | public Point getLocationOnScreen() { 1380 | synchronized (target.getTreeLock()) { 1381 | Component comp = target; 1382 | 1383 | while (comp != null && !(comp instanceof Window)) { 1384 | comp = AWTAccessor.getComponentAccessor().getParent(comp); 1385 | } 1386 | 1387 | // applets, embedded, etc - translate directly 1388 | // XXX: override in subclass? 1389 | if (comp == null || comp instanceof sun.awt.EmbeddedFrame) { 1390 | return toGlobal(0, 0); 1391 | } 1392 | 1393 | XToolkit.awtLock(); 1394 | try { 1395 | Object wpeer = XToolkit.targetToPeer(comp); 1396 | if (wpeer == null 1397 | || !(wpeer instanceof XDecoratedPeer) 1398 | || ((XDecoratedPeer)wpeer).configure_seen) 1399 | { 1400 | return toGlobal(0, 0); 1401 | } 1402 | 1403 | // wpeer is an XDecoratedPeer not yet fully adopted by WM 1404 | Point pt = toOtherWindow(getContentWindow(), 1405 | ((XDecoratedPeer)wpeer).getContentWindow(), 1406 | 0, 0); 1407 | 1408 | if (pt == null) { 1409 | pt = new Point(((XBaseWindow)wpeer).getAbsoluteX(), ((XBaseWindow)wpeer).getAbsoluteY()); 1410 | } 1411 | pt.x += comp.getX(); 1412 | pt.y += comp.getY(); 1413 | return pt; 1414 | } finally { 1415 | XToolkit.awtUnlock(); 1416 | } 1417 | } 1418 | } 1419 | 1420 | 1421 | static void setBData(KeyEvent e, byte[] data) { 1422 | AWTAccessor.getAWTEventAccessor().setBData(e, data); 1423 | } 1424 | 1425 | public void postKeyEvent(int id, long when, int keyCode, int keyChar, 1426 | int keyLocation, int state, long event, int eventSize, long rawCode, 1427 | int unicodeFromPrimaryKeysym, int extendedKeyCode) 1428 | 1429 | { 1430 | long jWhen = XToolkit.nowMillisUTC_offset(when); 1431 | int modifiers = getModifiers(state, 0, keyCode); 1432 | 1433 | KeyEvent ke = new KeyEvent((Component)getEventSource(), id, jWhen, 1434 | modifiers, keyCode, (char)keyChar, keyLocation); 1435 | if (event != 0) { 1436 | byte[] data = Native.toBytes(event, eventSize); 1437 | setBData(ke, data); 1438 | } 1439 | 1440 | AWTAccessor.KeyEventAccessor kea = AWTAccessor.getKeyEventAccessor(); 1441 | kea.setRawCode(ke, rawCode); 1442 | kea.setPrimaryLevelUnicode(ke, (long)unicodeFromPrimaryKeysym); 1443 | kea.setExtendedKeyCode(ke, (long)extendedKeyCode); 1444 | postEventToEventQueue(ke); 1445 | } 1446 | 1447 | static native int getAWTKeyCodeForKeySym(int keysym); 1448 | static native int getKeySymForAWTKeyCode(int keycode); 1449 | 1450 | /* These two methods are actually applicable to toplevel windows only. 1451 | * However, the functionality is required by both the XWindowPeer and 1452 | * XWarningWindow, both of which have the XWindow as a common ancestor. 1453 | * See XWM.setMotifDecor() for details. 1454 | */ 1455 | public PropMwmHints getMWMHints() { 1456 | if (mwm_hints == null) { 1457 | mwm_hints = new PropMwmHints(); 1458 | if (!XWM.XA_MWM_HINTS.getAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS)) { 1459 | mwm_hints.zero(); 1460 | } 1461 | } 1462 | return mwm_hints; 1463 | } 1464 | 1465 | public void setMWMHints(PropMwmHints hints) { 1466 | mwm_hints = hints; 1467 | if (hints != null) { 1468 | XWM.XA_MWM_HINTS.setAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS); 1469 | } 1470 | } 1471 | 1472 | protected final void initWMProtocols() { 1473 | wm_protocols.setAtomListProperty(this, getWMProtocols()); 1474 | } 1475 | 1476 | /** 1477 | * Returns list of protocols which should be installed on this window. 1478 | * Descendants can override this method to add class-specific protocols 1479 | */ 1480 | protected XAtomList getWMProtocols() { 1481 | // No protocols on simple window 1482 | return new XAtomList(); 1483 | } 1484 | 1485 | /** 1486 | * Indicates if the window is currently in the FSEM. 1487 | * Synchronization: state lock. 1488 | */ 1489 | private boolean fullScreenExclusiveModeState = false; 1490 | 1491 | // Implementation of the X11ComponentPeer 1492 | @Override 1493 | public void setFullScreenExclusiveModeState(boolean state) { 1494 | synchronized (getStateLock()) { 1495 | fullScreenExclusiveModeState = state; 1496 | } 1497 | } 1498 | 1499 | public final boolean isFullScreenExclusiveMode() { 1500 | synchronized (getStateLock()) { 1501 | return fullScreenExclusiveModeState; 1502 | } 1503 | } 1504 | 1505 | } --------------------------------------------------------------------------------