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