├── 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 | }
--------------------------------------------------------------------------------