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