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