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 package sun.awt.X11;
  26 
  27 import java.awt.*;
  28 
  29 import java.awt.event.ComponentEvent;
  30 import java.awt.event.InvocationEvent;
  31 import java.awt.event.WindowEvent;
  32 
  33 import java.util.logging.Level;
  34 import java.util.logging.Logger;
  35 
  36 import sun.awt.AWTAccessor;
  37 import sun.awt.ComponentAccessor;
  38 import sun.awt.SunToolkit;
  39 
  40 abstract class XDecoratedPeer extends XWindowPeer {
  41     private static final Logger log = Logger.getLogger("sun.awt.X11.XDecoratedPeer");
  42     private static final Logger insLog = Logger.getLogger("sun.awt.X11.insets.XDecoratedPeer");
  43     private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XDecoratedPeer");
  44     private static final Logger iconLog = Logger.getLogger("sun.awt.X11.icon.XDecoratedPeer");
  45 
  46     XIconWindow iconWindow;
  47 
  48     /**
  49      * The dimensions of the window.
  50      *
  51      * The entity encapsulates information about the bounds and the insets of
  52      * the window. The value is initialized in the preInit() method with the
  53      * bounds of the window as known on the shared level. Further updates
  54      * should be performed with the reportReshape() method only.
  55      */
  56     protected WindowDimensions dimensions;
  57 
  58     XContentWindow content;
  59     XFocusProxyWindow focusProxy;
  60 
  61     XDecoratedPeer(Window target) {
  62         super(target);
  63     }
  64 
  65     XDecoratedPeer(XCreateWindowParams params) {
  66         super(params);
  67     }
  68 
  69     public long getShell() {
  70         return window;
  71     }
  72 
  73     public long getContentWindow() {
  74         return (content == null) ? window : content.getWindow();
  75     }
  76 
  77     void preInit(XCreateWindowParams params) {
  78         super.preInit(params);
  79         winAttr.initialFocus = true;
  80 
  81         Rectangle bounds = (Rectangle)params.get(BOUNDS);
  82         dimensions = new WindowDimensions(bounds, getNativeInsets(), false);
  83         params.put(BOUNDS, dimensions.getClientRect());
  84         insLog.log(Level.FINE, "Initial dimensions {0}", new Object[] { dimensions });
  85 
  86         // Deny default processing of these events on the shell - proxy will take care of
  87         // them instead
  88         Long eventMask = (Long)params.get(EVENT_MASK);
  89         params.add(EVENT_MASK, Long.valueOf(eventMask.longValue() & ~(XConstants.FocusChangeMask | XConstants.KeyPressMask | XConstants.KeyReleaseMask)));
  90     }
  91 
  92     void postInit(XCreateWindowParams params) {
  93         super.postInit(params);
  94         // The lines that follow need to be in a postInit, so they
  95         // happen after the X window is created.
  96         initResizability();
  97         updateSizeHints(dimensions);
  98 
  99         content = XContentWindow.createContent(this);
 100 
 101         if (warningWindow != null) {
 102             warningWindow.toFront();
 103         }
 104         focusProxy = createFocusProxy();
 105     }
 106 
 107     void setIconHints(java.util.List<XIconInfo> icons) {
 108         if (!XWM.getWM().setNetWMIcon(this, icons)) {
 109             if (icons.size() > 0) {
 110                 if (iconWindow == null) {
 111                     iconWindow = new XIconWindow(this);
 112                 }
 113                 iconWindow.setIconImages(icons);
 114             }
 115         }
 116     }
 117 
 118     public void updateMinimumSize() {
 119         super.updateMinimumSize();
 120         updateMinSizeHints(getNativeInsets());
 121     }
 122 
 123     private void updateMinSizeHints(Insets insets) {
 124         if (isResizable()) {
 125             Dimension minimumSize = getTargetMinimumSize();
 126             if (minimumSize != null) {
 127                 int minWidth = minimumSize.width - insets.left - insets.right;
 128                 int minHeight = minimumSize.height - insets.top - insets.bottom;
 129                 if (minWidth < 0) minWidth = 0;
 130                 if (minHeight < 0) minHeight = 0;
 131                 setSizeHints(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.USPosition)),
 132                              getX(), getY(), minWidth, minHeight);
 133                 if (isVisible()) {
 134                     Rectangle bounds = getShellBounds();
 135                     int nw = (bounds.width < minWidth) ? minWidth : bounds.width;
 136                     int nh = (bounds.height < minHeight) ? minHeight : bounds.height;
 137                     if (nw != bounds.width || nh != bounds.height) {
 138                         setShellSize(new Rectangle(0, 0, nw, nh));
 139                     }
 140                 }
 141             } else {
 142                 boolean isMinSizeSet = isMinSizeSet();
 143                 XWM.removeSizeHints(this, XUtilConstants.PMinSize);
 144                 /* Some WMs need remap to redecorate the window */
 145                 if (isMinSizeSet && isShowing() && XWM.needRemap(this)) {
 146                     /*
 147                      * Do the re/mapping at the Xlib level.  Since we essentially
 148                      * work around a WM bug we don't want this hack to be exposed
 149                      * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
 150                      */
 151                     xSetVisible(false);
 152                     XToolkit.XSync();
 153                     xSetVisible(true);
 154                 }
 155             }
 156         }
 157     }
 158 
 159     XFocusProxyWindow createFocusProxy() {
 160         return new XFocusProxyWindow(this);
 161     }
 162 
 163     protected XAtomList getWMProtocols() {
 164         XAtomList protocols = super.getWMProtocols();
 165         protocols.add(wm_delete_window);
 166         protocols.add(wm_take_focus);
 167         return protocols;
 168     }
 169 
 170     public Graphics getGraphics() {
 171         return getGraphics(content.surfaceData,
 172                            ComponentAccessor.getForeground(target),
 173                            ComponentAccessor.getBackground(target),
 174                            ComponentAccessor.getFont_NoClientCode(target));
 175     }
 176 
 177     public void setTitle(String title) {
 178         if (log.isLoggable(Level.FINE)) log.fine("Title is " + title);
 179         winAttr.title = title;
 180         updateWMName();
 181     }
 182 
 183     protected String getWMName() {
 184         if (winAttr.title == null || winAttr.title.trim().equals("")) {
 185             return " ";
 186         } else {
 187             return winAttr.title;
 188         }
 189     }
 190 
 191     void updateWMName() {
 192         super.updateWMName();
 193         String name = getWMName();
 194         XToolkit.awtLock();
 195         try {
 196             if (name == null || name.trim().equals("")) {
 197                 name = "Java";
 198             }
 199             XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME);
 200             iconNameAtom.setProperty(getWindow(), name);
 201             XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME");
 202             netIconNameAtom.setPropertyUTF8(getWindow(), name);
 203         } finally {
 204             XToolkit.awtUnlock();
 205         }
 206     }
 207 
 208     // NOTE: This method may be called by privileged threads.
 209     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 210     public void handleIconify() {
 211         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED));
 212     }
 213 
 214     // NOTE: This method may be called by privileged threads.
 215     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 216     public void handleDeiconify() {
 217         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED));
 218     }
 219 
 220     public void handleFocusEvent(XEvent xev) {
 221         super.handleFocusEvent(xev);
 222         XFocusChangeEvent xfe = xev.get_xfocus();
 223 
 224         // If we somehow received focus events forward it instead to proxy
 225         // FIXME: Shouldn't we instead check for inferrior?
 226         focusLog.finer("Received focus event on shell: " + xfe);
 227 //         focusProxy.xRequestFocus();
 228    }
 229 
 230 /***************************************************************************************
 231  *                             I N S E T S   C O D E
 232  **************************************************************************************/
 233 
 234 
 235     /**
 236     * Current native insets of the window on the desktop.
 237     * When it's noticed the insets might have been changed (like when we
 238     * receive a ReparentNotify), the value must be reset to null by the
 239     * setNativeInsets(null) call.
 240     *
 241     * Synchronization: the awtLock is used. This should have been the state
 242     * lock instead, but the retrieveNativeInsets() uses the awtLock, and the
 243     * later must be always taken before the state lock.
 244     *
 245     * The field MUST NOT be used directly. Use get/setNativeInsets() instead.
 246     */
 247     private Insets nativeInsets = null;
 248 
 249     /**
 250     * Gets the current native insets.
 251     * This method may only return null if the fallBackToDefault is false.
 252     */
 253     private Insets getNativeInsets(boolean retrieve, boolean fallBackToDefault) {
 254         if (isTargetUndecorated() || isEmbedded() || !XWM.isRunning())
 255         {
 256             return (Insets)ZERO_INSETS.clone();
 257         }
 258         if (getWindow() == XConstants.None) {
 259             return getDefaultInsets();
 260         }
 261         XToolkit.awtLock();
 262         try {
 263             if (nativeInsets == null && retrieve) {
 264                 retrieveNativeInsets();
 265             }
 266             return nativeInsets == null ?
 267                 (fallBackToDefault ? getDefaultInsets() : null) :
 268                 (Insets)nativeInsets.clone();
 269         } finally {
 270             XToolkit.awtUnlock();
 271         }
 272     }
 273 
 274     /**
 275     * Gets the current native insets.
 276     */
 277     public Insets getNativeInsets() {
 278         return getNativeInsets(true, true);
 279     }
 280 
 281     @Override
 282     public Insets getInsets() {
 283         Insets insets = getNativeInsets();
 284         insets.top += getMenuBarHeight();
 285         if (insLog.isLoggable(Level.FINEST)) {
 286             insLog.log(Level.FINEST, "Get insets returns {0}",
 287                     new Object[] {insets});
 288         }
 289         return insets;
 290     }
 291 
 292     /**
 293      * Returns the insets that the window probably will get.
 294      */
 295     private Insets getDefaultInsets() {
 296         Insets insets = XWM.getWM().getDefaultInsets();
 297         return (Insets)(insets == null ? DEFAULT_INSETS : insets).clone();
 298     }
 299 
 300     /**
 301      * Get rid of insane insets.
 302      * The operation is performed in place - the given object gets modified.
 303      */
 304     private static Insets sanitize(Insets insets) {
 305         //XXX: Perhaps using the marginal values instead of the default would
 306         //     make more sense?
 307         if (insets.top > 64 || insets.top < 0) {
 308             insets.top = DEFAULT_INSETS.top;
 309         }
 310         if (insets.left > 32 || insets.left < 0) {
 311             insets.left = DEFAULT_INSETS.left;
 312         }
 313         if (insets.right > 32 || insets.right < 0) {
 314             insets.right = DEFAULT_INSETS.right;
 315         }
 316         if (insets.bottom > 32 || insets.bottom < 0) {
 317             insets.bottom = DEFAULT_INSETS.bottom;
 318         }
 319         return insets;
 320     }
 321 
 322     private void setNativeInsets(Insets insets) {
 323         XToolkit.awtLock();
 324         try {
 325             nativeInsets = insets == null ? null :
 326                 sanitize((Insets)insets.clone());
 327         } finally {
 328             XToolkit.awtUnlock();
 329         }
 330     }
 331 
 332     public static final Insets DEFAULT_INSETS = new Insets(25, 5, 5, 5);
 333     public static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0);
 334 
 335     /**
 336      * Retrieve the current insets of the window.
 337      *
 338      * This method must only be called by the getNativeInsets() method. DO NOT
 339      * call this method directly. If the insets need to be updated, nullify
 340      * them using the setNativeInsets(null) method.
 341      */
 342     private void retrieveNativeInsets() {
 343         long window = getWindow();
 344 
 345         if (XWM.requestWMExtents(window)) {
 346             XWM.waitForExtentsUpdateEvent();
 347         }
 348 
 349         // Some WMs may provide the extents via a property, but do not require
 350         // a request to update them. Hence try getting them unconditionally.
 351         // We could use the XEvent returned by the waitForExtentsUpdateEvent()
 352         // above, though that doesn't seem to make much sense.
 353         Insets insets = XWM.getInsetsFromExtents(window);
 354         if (insets != null) {
 355             setNativeInsets(insets);
 356             return;
 357         }
 358 
 359         // The window manager is unable to report any extents, so we need to
 360         // calculate them ourselves.
 361         Rectangle winRect = XlibUtil.getWindowGeometry(
 362                 window, XlibWrapper.larg1);
 363         if (winRect == null) {
 364             // Some error occured
 365             return;
 366         }
 367         // The root window must be got immediately after the previous
 368         // getWindowGeometry() call.
 369         long root = Native.getWindow(XlibWrapper.larg1); 
 370 
 371         long parent = getNativeParent();
 372         if (parent == XConstants.None || parent == root) {
 373             // Non-reparenting WM. Assume the insets are zero.
 374             setNativeInsets(ZERO_INSETS);
 375             return;
 376         }
 377 
 378         Rectangle parentRect = XlibUtil.getWindowGeometry(parent);
 379         if (parentRect == null) {
 380             // Some error again
 381             return;
 382         }
 383 
 384         long grand_parent = XlibUtil.getParentWindow(parent);
 385         if (grand_parent == XConstants.None || grand_parent == root ||
 386                 (winRect.x != 0 || winRect.y != 0 ||
 387                  winRect.width != parentRect.width ||
 388                  winRect.height != parentRect.height))
 389         {
 390             // Single-reparenting WM
 391             // Either there's no a valid grand-parent, or the direct parent
 392             // has greater bounds than the window itself.
 393             setNativeInsets(calculateInsets(winRect, parentRect));
 394         } else {
 395             // Double-reparenting WM
 396             // There's a valid grand-parent. The bounds of the direct
 397             // parent are equal to the bounds of the window itself.
 398             Rectangle grandParentRect = XlibUtil.getWindowGeometry(
 399                     grand_parent);
 400             if (grandParentRect == null) {
 401                 // One more error condition. This time we fall back to the
 402                 // single-reparenting case, though this will produce
 403                 // ZERO_INSETS actually...
 404                 setNativeInsets(calculateInsets(winRect, parentRect));
 405             } else {
 406                 setNativeInsets(calculateInsets(parentRect, grandParentRect));
 407             }
 408         }
 409     }
 410 
 411     /**
 412      * Calculates the insets for the given interior and exterior rectangles.
 413      * Only positive insets are allowed. If the interior rectangle is bigger
 414      * than the exterior one, the negative inset values will be ignored,
 415      * and zero value used instead.
 416      */
 417     private static Insets calculateInsets(Rectangle interior, Rectangle exterior) {
 418         return new Insets(
 419                 Math.max(interior.y, 0),
 420                 Math.max(interior.x, 0),
 421                 Math.max(exterior.height - interior.height - interior.y, 0),
 422                 Math.max(exterior.width - interior.width - interior.x, 0));
 423     }
 424 
 425     /**
 426      * Applies the new insets.
 427      */
 428     private void setInsets(Insets insets) {
 429         setNativeInsets(insets);
 430 
 431         WindowDimensions dims = new WindowDimensions(dimensions);
 432         dims.setInsets(insets);
 433         reportOrAdjust(dims, false);
 434     }
 435 
 436     @Override
 437     public void handlePropertyNotify(XEvent xev) {
 438         super.handlePropertyNotify(xev);
 439 
 440         XPropertyEvent ev = xev.get_xproperty();
 441         if (XWM.isExtentsPropertyAtom(ev.get_atom())) {
 442             Insets insets = XWM.getInsetsFromProp(getWindow(),
 443                     XAtom.get(ev.get_atom()));
 444             if (insLog.isLoggable(Level.FINE)) {
 445                 insLog.fine("" + insets);
 446             }
 447             if (insets != null) {
 448                 setInsets(insets);
 449             }
 450         }
 451     }
 452 
 453     // The serial of the last received ReparentNotify event
 454     private long reparentNotifySerial = 0;
 455 
 456     // The number of processed ConfigureNotify events with the same serial
 457     // as reparentNotifySerial.
 458     private int numOfConfigureNotifyJustAfterReparentNotify = 0;
 459 
 460     @Override
 461     public void handleReparentNotifyEvent(XEvent xev) {
 462         super.handleReparentNotifyEvent(xev);
 463 
 464         XReparentEvent  xe = xev.get_xreparent();
 465         if (insLog.isLoggable(Level.FINE)) {
 466             insLog.fine(xe.toString());
 467         }
 468 
 469         if (xe.get_window() != getWindow()) {
 470             return;
 471         }
 472 
 473         if (!isParented()) {
 474             if (isVisible()) {
 475                 // Either the WM or the embedder exited
 476                 XWM.getWM().unshadeKludge(this);
 477                 if (!isEmbedded()) {
 478                     XWM.reset();
 479                 }
 480                 setInsets(null);
 481             } //else: The window just got hidden
 482         } else {
 483             // We just got parented: prepare stuff to recalculate the insets,
 484             // and to readjust the bounds if needed
 485             reparentNotifySerial = xe.get_serial();
 486             numOfConfigureNotifyJustAfterReparentNotify = 0;
 487 
 488             setNativeInsets(null);
 489             needToAdjustBounds();
 490         }
 491     }
 492 
 493     protected boolean isInitialReshape() {
 494         return false;
 495     }
 496 
 497     public void handleMoved(Point loc) {
 498         ComponentAccessor.setX((Component)target, loc.x);
 499         ComponentAccessor.setY((Component)target, loc.y);
 500         postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED));
 501     }
 502 
 503 
 504     public void revalidate() {
 505         XToolkit.executeOnEventHandlerThread(target, new Runnable() {
 506                 public void run() {
 507                     target.invalidate();
 508                     target.validate();
 509                 }
 510             });
 511     }
 512 
 513     boolean gravityBug() {
 514         return XWM.configureGravityBuggy();
 515     }
 516 
 517     // The height of area used to display current active input method
 518     int getInputMethodHeight() {
 519         return 0;
 520     }
 521 
 522     void updateSizeHints(WindowDimensions dims) {
 523         Rectangle rec = dims.getClientRect();
 524         checkShellRect(rec);
 525         updateSizeHints(rec.x, rec.y, rec.width, rec.height);
 526     }
 527 
 528     void updateSizeHints() {
 529         updateSizeHints(dimensions);
 530     }
 531 
 532     // Coordinates are that of the target
 533     // Called only on Toolkit thread
 534     private void reshape(WindowDimensions newDimensions, int op)
 535     {
 536         if (insLog.isLoggable(Level.FINE)) {
 537             insLog.fine("Reshaping " + this + " to " + newDimensions +
 538                     "; op " + operationToString(op));
 539         }
 540         XToolkit.awtLock();
 541         try {
 542             if (!isVisible()) {
 543                 Rectangle client = newDimensions.getClientRect();
 544                 checkShellRect(client);
 545                 setShellBounds(client);
 546 
 547                 reportReshape(newDimensions);
 548             } else {
 549                 requestReshape(newDimensions, op);
 550             }
 551         } finally {
 552             XToolkit.awtUnlock();
 553         }
 554     }
 555 
 556     /**
 557      * Sets window dimensions and propagates the changes to the target sending
 558      * corresponding events if needed.
 559      * 
 560      * MUST be invoked under the AWTLock.
 561      */
 562     private void reportReshape(WindowDimensions newDims) {
 563         if (insLog.isLoggable(Level.FINE)) {
 564             insLog.fine("" + newDims);
 565         }
 566 
 567         final Insets insets = newDims.getInsets();
 568         if (!insets.equals(dimensions.getInsets())) {
 569             // Recalculate the minimum size of the client area
 570             updateMinSizeHints(insets);
 571         }
 572 
 573         // If the client area size changes, we need to revalidate the target.
 574         // This may happen in the XContentWindow.setContentBounds(). If this
 575         // does not happen there, we need to dispatch the operation here.
 576         final boolean needRevalidate =
 577             !dimensions.getClientSize().equals(newDims.getClientSize());
 578 
 579         checkIfOnNewScreen(newDims.getBounds());
 580 
 581         Point oldLocation = getLocation();
 582         dimensions = newDims;
 583         if (!getLocation().equals(oldLocation)) {
 584             handleMoved(getLocation());
 585         }
 586 
 587         if (!reconfigureContentWindow(dimensions) && needRevalidate) {
 588             revalidate();
 589         }
 590 
 591         updateChildrenSizes();
 592         repositionSecurityWarning();
 593     }
 594 
 595     private void reportOrAdjust(WindowDimensions newDims,
 596             boolean handlingConfigureNotify)
 597     {
 598         if (dimensions.equals(newDims) && !areBoundsAdjusting()) {
 599             // If nothing has changed and we're already adjusted, return
 600             if (insLog.isLoggable(Level.FINE)) {
 601                 insLog.fine("Ignored: nothing changed: " + newDims);
 602             }
 603             return;
 604         }
 605         if (adjustBounds(newDims, handlingConfigureNotify)) {
 606             // We expect another ConfigureNotify
 607             return;
 608         }
 609 
 610         reportReshape(newDims);
 611     }
 612 
 613     /**
 614      * Requests the system to reshape the window.
 615      * 
 616      * MUST be invoked under the AWTLock.
 617      */
 618     private void requestReshape(WindowDimensions newDimensions, int op) {
 619         if (insLog.isLoggable(Level.FINE)) {
 620             insLog.fine("Request reshape: " + newDimensions + "; op: " +
 621                     operationToString(op));
 622         }
 623 
 624         Rectangle shellRect = newDimensions.getClientRect();
 625 
 626         if (gravityBug()) {
 627             Insets in = newDimensions.getInsets();
 628             shellRect.translate(in.left, in.top);
 629         }
 630 
 631         if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) {
 632             shellRect.setLocation(0, 0);
 633         }
 634 
 635         checkShellRectSize(shellRect);
 636         if (!isEmbedded()) {
 637             checkShellRectPos(shellRect);
 638         }
 639 
 640         op = op & ~NO_EMBEDDED_CHECK;
 641 
 642         if (op == SET_LOCATION) {
 643             setShellPosition(shellRect);
 644         } else if (isResizable()) {
 645             if (op == SET_BOUNDS) {
 646                 setShellBounds(shellRect);
 647             } else {
 648                 setShellSize(shellRect);
 649             }
 650         } else {
 651             XWM.setShellNotResizable(this, newDimensions, shellRect, true);
 652             if (op == SET_BOUNDS) {
 653                 setShellPosition(shellRect);
 654             }
 655         }
 656     }
 657 
 658     // This method gets overriden in XFramePeer & XDialogPeer.
 659     abstract boolean isTargetUndecorated();
 660 
 661     /**
 662      * @see java.awt.peer.ComponentPeer#setBounds
 663      */
 664     public void setBounds(int x, int y, int width, int height, int operation) {
 665         WindowDimensions dims = new WindowDimensions(dimensions);
 666         switch (operation & (~NO_EMBEDDED_CHECK)) {
 667           case SET_LOCATION:
 668               // Set location always sets bounds location. However, until the window is mapped we
 669               // should use client coordinates
 670               dims.setLocation(x, y);
 671               break;
 672           case SET_SIZE:
 673               // Set size sets bounds size. However, until the window is mapped we
 674               // should use client coordinates
 675               dims.setSize(width, height);
 676               break;
 677           case SET_CLIENT_SIZE: {
 678               // Sets client rect size. Width and height contain insets.
 679               // Also update the insets to the latest known value to decrease
 680               // (or even eliminate) the bounds adjustment after showing
 681               // the window.
 682               Insets in = getNativeInsets();
 683               width -= in.left+in.right;
 684               height -= in.top+in.bottom;
 685               dims.setClientSize(width, height);
 686               dims.setInsets(in);
 687               break;
 688           }
 689           case SET_BOUNDS:
 690           default:
 691               dims.setLocation(x, y);
 692               dims.setSize(width, height);
 693               break;
 694         }
 695         reshape(dims, operation);
 696         validateSurface();
 697     }
 698 
 699     /**
 700      * Sets the content window bounds.
 701      *
 702      * @return whether a COMPONENT_RESIZED has been sent
 703      */
 704     boolean reconfigureContentWindow(WindowDimensions dims) {
 705         if (content == null) {
 706             insLog.fine("WARNING: Content window is null");
 707             return false;
 708         }
 709         return content.setContentBounds(dims);
 710     }
 711 
 712     /**
 713      * Indicates if the adjustBounds() needs to be invoked.
 714      * Synchronization: state lock.
 715      */
 716     private boolean areBoundsAdjusted = false;
 717 
 718     /**
 719      * Forces the system to re-adjust the bounds of the window after it has
 720      * been finally adopted by the windowing system.
 721      */
 722     private void needToAdjustBounds() {
 723         synchronized (getStateLock()) {
 724             areBoundsAdjusted = false;
 725         }
 726     }
 727 
 728     /**
 729      * Indicates if the window bounds has not yet been finally configured by
 730      * the X server/window manager.
 731      */
 732     public boolean areBoundsAdjusting() {
 733         synchronized (getStateLock()) {
 734             return !areBoundsAdjusted;
 735         }
 736     }
 737 
 738     // XXX: Perhaps the following two might be replaced with Window.isSizeSet,
 739     //      isLocationSet? Just like we have Window.isPacked...
 740     /**
 741      * Indicates if the size hints of the window specify a position requested
 742      * by the user's code.
 743      */
 744     private boolean isUserSpecifiedPositionSet() {
 745         return (getHints().get_flags() &
 746                 (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0;
 747     }
 748 
 749     /**
 750      * Indicates if the size hints of the window specify a position requested
 751      * by the user's code.
 752      */
 753     private boolean isUserSpecifiedSizeSet() {
 754         return (getHints().get_flags() &
 755                 (XUtilConstants.USSize | XUtilConstants.PSize)) != 0;
 756     }
 757 
 758     /**
 759      * Adjust the bounds of the window.
 760      *
 761      * @return true if an adjustment has taken place. false if the new bounds
 762      *         are OK.
 763      */
 764     private boolean adjustBounds(WindowDimensions newDims,
 765             boolean handlingConfigureNotify)
 766     {
 767         synchronized (getStateLock()) {
 768             if (areBoundsAdjusted) {
 769                 return false;
 770             }
 771             // We have to adjust bounds upon showing once.
 772             // We also may adjust them several times before showing - e.g.
 773             // when we receive the PropertyNotify event with the extents.
 774             if (handlingConfigureNotify && isVisible()) {
 775                 insLog.log(Level.FINE, "Final adjustment");
 776                 areBoundsAdjusted = true;
 777             }
 778         }
 779 
 780         if (isMaximized()) {
 781             return false;
 782         }
 783 
 784         int operation = 0;
 785         boolean isPacked = AWTAccessor.getWindowAccessor().
 786             isPacked((Window)target);
 787 
 788         if (!newDims.getClientSize().equals(dimensions.getClientSize())
 789                 && isPacked)
 790         {
 791             // The client area size calculated via pack() needs to be preserved
 792             operation = SET_SIZE;
 793         } else
 794         if (!newDims.getSize().equals(dimensions.getSize())
 795                 && isUserSpecifiedSizeSet())
 796         {
 797             // The size set via setSize()/setBounds() needs to be preserved
 798             operation = SET_SIZE;
 799         }
 800 
 801         if (isUserSpecifiedPositionSet() &&
 802                 !newDims.getLocation().equals(dimensions.getLocation()))
 803         {
 804             // The user also requested a specific position
 805             if (operation == 0) {
 806                 operation = SET_LOCATION;
 807             } else {
 808                 operation = SET_BOUNDS;
 809             }
 810         }
 811 
 812         if (operation == 0) {
 813             insLog.fine("No adjustment needed");
 814             return false;
 815         }
 816 
 817         WindowDimensions dims = new WindowDimensions(
 818                 dimensions.getLocation(),
 819                 isPacked ? dimensions.getClientSize() : dimensions.getSize(),
 820                 newDims.getInsets(),
 821                 isPacked);
 822         
 823         if (insLog.isLoggable(Level.FINE)) {
 824             insLog.fine("Request: " + dims + "; operation=" +
 825                     operationToString(operation));
 826         }
 827         requestReshape(dims, operation);
 828         return true;
 829     }
 830 
 831     @Override
 832     public void handleConfigureNotifyEvent(XEvent xev) {
 833         // Note: we don't call super because the XWindowPeer immediately calls
 834         //       the checkIfOnNewScreen() assuming the bounds are correct. This
 835         //       is not always correct for decorated peers.
 836 
 837         XConfigureEvent xe = xev.get_xconfigure();
 838 
 839         // Due to the SubstructureNotifyMask we should process only those
 840         // events that belong to us.
 841         if (xe.get_window() != getWindow()) {
 842             return;
 843         }
 844         
 845         if (insLog.isLoggable(Level.FINE)) {
 846             insLog.fine("" + xe);
 847             insLog.fine("XWM.isRunning: " + XWM.isRunning());
 848         }
 849 
 850         // If there's a WM we have to ignore some events
 851         if (XWM.isRunning()) {
 852             // Ignore any events until after we become visible
 853             if (!isVisible()) {
 854                 insLog.fine("Ignored: Not visible yet");
 855                 needToAdjustBounds();
 856                 return;
 857             }
 858 
 859             // We have not yet been parented by the WM
 860             if (mayBeReparented() && !isTargetUndecorated()) {
 861                 insLog.fine("Ignored: Not parented yet");
 862                 needToAdjustBounds();
 863                 return;
 864             }
 865 
 866             // Just after reparenting we can receive a synthetic and/or real
 867             // event(s).  Since sometimes we need to adjust the bounds of the
 868             // frame, we need to process only one of the events. Justification:
 869             //    1. Both events carry the same information: one from the X
 870             //    server, the other from the WM.
 871             //    2. The adjustment operation is performed only once upon
 872             //    processing the first ConfigureNotify event that is not
 873             //    ignored.
 874             //    3. If the first event causes the adjustment to happen, the
 875             //    second event will be considered as a normal, not ignored
 876             //    event that may generate Java events and set incorrect
 877             //    (not-yet-adjusted) bounds to the frame.
 878             // So generally, if the adjustment is needed, the first
 879             // ConfigureNotify that we should really process is the one caused
 880             // by the adjustment operation. So we process only the first
 881             // ConfigureNotify event having the same serial that the preceeding
 882             // ReparentNotify.
 883             //
 884             // There's one exception however: we do not ignore the events for
 885             // maximized frames. The real ConfigureNotify that we would like to
 886             // act upon usually is the third one (it carries the correct
 887             // maximized bounds). However, it has the same serial (which is
 888             // obvious), and what's worse - we can't reliably determine if the
 889             // window manager/X server send us exactly two events before that,
 890             // or maybe one of them might be not sent at all - and in this case
 891             // we would need to process the second event, not the third. So we
 892             // just process everything for a maximized frame. This does produce
 893             // absolutely meaningless bounds dancing (with events sent to the
 894             // user space), but at least this is backward-compatible and quite
 895             // reliable. Should we find a way to detect and process only the
 896             // very last of ConfigureNotify events sent with the same serial,
 897             // we would like to use this approach instead of the current
 898             // processing of the very first event only.
 899             if (xe.get_serial() == reparentNotifySerial && !isMaximized())
 900             {
 901                 if (++numOfConfigureNotifyJustAfterReparentNotify > 1) {
 902                     insLog.fine("Ignored: serial matches the ReparentNotify");
 903                     return;
 904                 }
 905             }
 906         }
 907 
 908         // At this point we can calculate some reliable insets
 909         Insets insets = getNativeInsets();
 910 
 911         // Note that in some cases this kind of event may be caused by the
 912         // changed insets (like if the theme changes, or something).  However
 913         // it's difficult if at all possible to identify this situation, and
 914         // not confuse it with a regular reconfiguration w/o introducing some
 915         // serious performance degradation. So we only support changing the
 916         // insets:
 917         //    a. when a reparenting WM exits/gets replaced.
 918         //    b. when the window gets hidden/shown.
 919         //    c. if the WM is smart enough to send the PropertyNotify
 920         //       events with the updated extents.
 921 
 922         // x, y, width, height hold the coordinates of the whole frame
 923         // including the decorations.
 924         int x;
 925         int y;
 926 
 927         if (xe.get_send_event() || !isParented()) {
 928             // If the event is synthetic or we're not parented, the coordinates
 929             // are relative to the root window.
 930             x = xe.get_x() - insets.left;
 931             y = xe.get_y() - insets.top;
 932         } else {
 933             // The event is real and we're parented - the coordinates are
 934             // relative to the parent
 935             Point loc = null;
 936             if (XWM.isNoSyntheticConfigureNotifyOnLeftTopResize()) {
 937                 // there's a bug in the WM, so ask the X server
 938                 loc = queryXLocation();
 939             }
 940             if (loc == null) {
 941                 // consider the current location unchanged
 942                 // TODO: this may not be true... perhaps querying X in all cases is worthwhile?
 943                 //       after all: we already do this for Metacity which is quite common,
 944                 //       so we should not worry much about the performance.
 945                 loc = getLocation();
 946             }
 947 
 948             x = loc.x;
 949             y = loc.y;
 950         }
 951 
 952         int width = xe.get_width() + insets.left + insets.right;
 953         int height = xe.get_height() + insets.top + insets.bottom;
 954 
 955         // Now apply the new bounds
 956         WindowDimensions d = new WindowDimensions(
 957                     new Rectangle(x, y, width, height), insets, false);
 958         reportOrAdjust(d, true);
 959     }
 960 
 961     private void checkShellRectSize(Rectangle shellRect) {
 962         if (shellRect.width < 0) {
 963             shellRect.width = 1;
 964         }
 965         if (shellRect.height < 0) {
 966             shellRect.height = 1;
 967         }
 968     }
 969 
 970     private void checkShellRectPos(Rectangle shellRect) {
 971         int wm = XWM.getWMID();
 972         if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) {
 973             if (shellRect.x == 0 && shellRect.y == 0) {
 974                 shellRect.x = shellRect.y = 1;
 975             }
 976         }
 977     }
 978 
 979     private void checkShellRect(Rectangle shellRect) {
 980         checkShellRectSize(shellRect);
 981         checkShellRectPos(shellRect);
 982     }
 983 
 984     public void setShellBounds(Rectangle rec) {
 985         if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell bounds on " +
 986                                                        this + " to " + rec);
 987         XToolkit.awtLock();
 988         try {
 989             updateSizeHints(rec.x, rec.y, rec.width, rec.height);
 990             XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height);
 991             XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y);
 992         }
 993         finally {
 994             XToolkit.awtUnlock();
 995         }
 996     }
 997     public void setShellSize(Rectangle rec) {
 998         if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell size on " +
 999                                                        this + " to " + rec);
1000         XToolkit.awtLock();
1001         try {
1002             updateSizeHints(rec.x, rec.y, rec.width, rec.height);
1003             XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height);
1004         }
1005         finally {
1006             XToolkit.awtUnlock();
1007         }
1008     }
1009     public void setShellPosition(Rectangle rec) {
1010         if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell position on " +
1011                                                        this + " to " + rec);
1012         XToolkit.awtLock();
1013         try {
1014             updateSizeHints(rec.x, rec.y, rec.width, rec.height);
1015             XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y);
1016         }
1017         finally {
1018             XToolkit.awtUnlock();
1019         }
1020     }
1021 
1022     void initResizability() {
1023         setResizable(winAttr.initialResizability);
1024     }
1025     public void setResizable(boolean resizable) {
1026         int fs = winAttr.functions;
1027         if (!isResizable() && resizable) {
1028             setNativeInsets(null);
1029             winAttr.isResizable = resizable;
1030             if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
1031                 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
1032             } else {
1033                 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
1034             }
1035             winAttr.functions = fs;
1036             XWM.setShellResizable(this);
1037         } else if (isResizable() && !resizable) {
1038             setNativeInsets(null);
1039             winAttr.isResizable = resizable;
1040             if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
1041                 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
1042             } else {
1043                 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
1044             }
1045             winAttr.functions = fs;
1046             XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false);
1047         }
1048     }
1049 
1050     Rectangle getShellBounds() {
1051         return dimensions.getClientRect();
1052     }
1053 
1054     public Rectangle getBounds() {
1055         return dimensions.getBounds();
1056     }
1057 
1058     public Dimension getSize() {
1059         return dimensions.getSize();
1060     }
1061 
1062     public int getX() {
1063         return dimensions.getLocation().x;
1064     }
1065 
1066     public int getY() {
1067         return dimensions.getLocation().y;
1068     }
1069 
1070     public Point getLocation() {
1071         return dimensions.getLocation();
1072     }
1073 
1074     public int getAbsoluteX() {
1075         // NOTE: returning this peer's location which is shell location
1076         return dimensions.getScreenBounds().x;
1077     }
1078 
1079     public int getAbsoluteY() {
1080         // NOTE: returning this peer's location which is shell location
1081         return dimensions.getScreenBounds().y;
1082     }
1083 
1084     public int getWidth() {
1085         return getSize().width;
1086     }
1087 
1088     public int getHeight() {
1089         return getSize().height;
1090     }
1091 
1092     final public WindowDimensions getDimensions() {
1093         return dimensions;
1094     }
1095 
1096     public Point getLocationOnScreen() {
1097         XToolkit.awtLock();
1098         try {
1099             if (!areBoundsAdjusting()) {
1100                 return toGlobal(0,0);
1101             } else {
1102                 Point location = target.getLocation();
1103                 if (insLog.isLoggable(Level.FINE)) {
1104                     insLog.log(Level.FINE, "getLocationOnScreen {0} not reparented: {1} ",
1105                                new Object[] {this, location});
1106                 }
1107                 return location;
1108             }
1109         } finally {
1110             XToolkit.awtUnlock();
1111         }
1112     }
1113 
1114 
1115 /***************************************************************************************
1116  *              END            OF             I N S E T S   C O D E
1117  **************************************************************************************/
1118 
1119     protected boolean isEventDisabled(XEvent e) {
1120         switch (e.get_type()) {
1121             // Do not generate MOVED/RESIZED events since we generate them by ourselves
1122           case XConstants.ConfigureNotify:
1123               return true;
1124           case XConstants.EnterNotify:
1125           case XConstants.LeaveNotify:
1126               // Disable crossing event on outer borders of Frame so
1127               // we receive only one set of cross notifications(first set is from content window)
1128               return true;
1129           default:
1130               return super.isEventDisabled(e);
1131         }
1132     }
1133 
1134     int getDecorations() {
1135         return winAttr.decorations;
1136     }
1137 
1138     int getFunctions() {
1139         return winAttr.functions;
1140     }
1141 
1142     public void setVisible(boolean vis) {
1143         log.log(Level.FINER, "Setting {0} to visible {1}", new Object[] {this, Boolean.valueOf(vis)});
1144         if (vis && !isVisible()) {
1145             XWM.setShellDecor(this);
1146             super.setVisible(vis);
1147             if (winAttr.isResizable) {
1148                 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
1149                 //We need to update frame's minimum size, not to reset it
1150                 XWM.removeSizeHints(this, XUtilConstants.PMaxSize);
1151                 updateMinimumSize();
1152             }
1153         } else {
1154             super.setVisible(vis);
1155         }
1156     }
1157 
1158     protected void suppressWmTakeFocus(boolean doSuppress) {
1159         XAtomList protocols = getWMProtocols();
1160         if (doSuppress) {
1161             protocols.remove(wm_take_focus);
1162         } else {
1163             protocols.add(wm_take_focus);
1164         }
1165         wm_protocols.setAtomListProperty(this, protocols);
1166     }
1167 
1168     public void dispose() {
1169         if (content != null) {
1170             content.destroy();
1171         }
1172         focusProxy.destroy();
1173 
1174         if (iconWindow != null) {
1175             iconWindow.destroy();
1176         }
1177 
1178         super.dispose();
1179     }
1180 
1181     public void handleClientMessage(XEvent xev) {
1182         super.handleClientMessage(xev);
1183         XClientMessageEvent cl = xev.get_xclient();
1184         if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) {
1185             if (cl.get_data(0) == wm_delete_window.getAtom()) {
1186                 handleQuit();
1187             } else if (cl.get_data(0) == wm_take_focus.getAtom()) {
1188                 handleWmTakeFocus(cl);
1189             }
1190         }
1191     }
1192 
1193     private void handleWmTakeFocus(XClientMessageEvent cl) {
1194         focusLog.log(Level.FINE, "WM_TAKE_FOCUS on {0}", new Object[]{this});
1195         requestWindowFocus(cl.get_data(1), true);
1196     }
1197 
1198     /**
1199      * Requests focus to this decorated top-level by requesting X input focus
1200      * to the shell window.
1201      */
1202     protected void requestXFocus(long time, boolean timeProvided) {
1203         // We have proxied focus mechanism - instead of shell the focus is held
1204         // by "proxy" - invisible mapped window. When we want to set X input focus to
1205         // toplevel set it on proxy instead.
1206         if (focusProxy == null) {
1207             if (focusLog.isLoggable(Level.FINE)) focusLog.warning("Focus proxy is null for " + this);
1208         } else {
1209             if (focusLog.isLoggable(Level.FINE)) focusLog.fine("Requesting focus to proxy: " + focusProxy);
1210             if (timeProvided) {
1211                 focusProxy.xRequestFocus(time);
1212             } else {
1213                 focusProxy.xRequestFocus();
1214             }
1215         }
1216     }
1217 
1218     XFocusProxyWindow getFocusProxy() {
1219         return focusProxy;
1220     }
1221 
1222     public void handleQuit() {
1223         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING));
1224     }
1225 
1226     final void dumpMe() {
1227         System.err.println(">>> Peer: " + x + ", " + y + ", " + width + ", " + height);
1228     }
1229 
1230     final void dumpTarget() {
1231         int getWidth = ComponentAccessor.getWidth((Component)target);
1232         int getHeight = ComponentAccessor.getHeight((Component)target);
1233         int getTargetX = ComponentAccessor.getX((Component)target);
1234         int getTargetY = ComponentAccessor.getY((Component)target);
1235         System.err.println(">>> Target: " + getTargetX + ", " + getTargetY + ", " + getWidth + ", " + getHeight);
1236     }
1237 
1238     final void dumpShell() {
1239         dumpWindow("Shell", getShell());
1240     }
1241     final void dumpContent() {
1242         dumpWindow("Content", getContentWindow());
1243     }
1244     final void dumpParent() {
1245         long parent = XlibUtil.getParentWindow(getShell());
1246         if (parent != XConstants.None)
1247         {
1248             dumpWindow("Parent", parent);
1249         }
1250         else
1251         {
1252             System.err.println(">>> NO PARENT");
1253         }
1254     }
1255 
1256     final void dumpWindow(String id, long window) {
1257         XWindowAttributes pattr = new XWindowAttributes();
1258         try {
1259             XToolkit.awtLock();
1260             try {
1261                 int status =
1262                     XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
1263                                                      window, pattr.pData);
1264             }
1265             finally {
1266                 XToolkit.awtUnlock();
1267             }
1268             System.err.println(">>>> " + id + ": " + pattr.get_x()
1269                                + ", " + pattr.get_y() + ", " + pattr.get_width()
1270                                + ", " + pattr.get_height());
1271         } finally {
1272             pattr.dispose();
1273         }
1274     }
1275 
1276     final void dumpAll() {
1277         dumpTarget();
1278         dumpMe();
1279         dumpParent();
1280         dumpShell();
1281         dumpContent();
1282     }
1283 
1284     boolean isMaximized() {
1285         return false;
1286     }
1287 
1288     boolean isOverrideRedirect() {
1289         return ((XToolkit)Toolkit.getDefaultToolkit()).isOverrideRedirect((Window)target);
1290     }
1291 
1292     public boolean requestWindowFocus(long time, boolean timeProvided) {
1293         focusLog.fine("Request for decorated window focus");
1294         // If this is Frame or Dialog we can't assure focus request success - but we still can try
1295         // If this is Window and its owner Frame is active we can be sure request succedded.
1296         Window focusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
1297         Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
1298 
1299         focusLog.log(Level.FINER, "Current window is: active={0}, focused={1}",
1300                      new Object[]{ Boolean.valueOf(target == activeWindow),
1301                                    Boolean.valueOf(target == focusedWindow)});
1302 
1303         XWindowPeer toFocus = this;
1304         while (toFocus.nextTransientFor != null) {
1305             toFocus = toFocus.nextTransientFor;
1306         }
1307         if (toFocus == null || !toFocus.focusAllowedFor()) {
1308             // This might change when WM will have property to determine focus policy.
1309             // Right now, because policy is unknown we can't be sure we succedded
1310             return false;
1311         }
1312         if (this == toFocus) {
1313             if (isWMStateNetHidden()) {
1314                 focusLog.fine("The window is unmapped, so rejecting the request");
1315                 return false;
1316             }
1317             if (target == activeWindow && target != focusedWindow) {
1318                 // Happens when an owned window is currently focused
1319                 focusLog.fine("Focus is on child window - transfering it back to the owner");
1320                 handleWindowFocusInSync(-1);
1321                 return true;
1322             }
1323             Window realNativeFocusedWindow = XWindowPeer.getNativeFocusedWindow();
1324             focusLog.finest("Real native focused window: " + realNativeFocusedWindow +
1325                             "\nKFM's focused window: " + focusedWindow);
1326 
1327             // See 6522725, 6613426.
1328             if (target == realNativeFocusedWindow) {
1329                 focusLog.fine("The window is already natively focused.");
1330                 return true;
1331             }
1332         }
1333         focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus));
1334 
1335         if (timeProvided) {
1336             toFocus.requestXFocus(time);
1337         } else {
1338             toFocus.requestXFocus();
1339         }
1340         return (this == toFocus);
1341     }
1342 
1343     XWindowPeer actualFocusedWindow = null;
1344     void setActualFocusedWindow(XWindowPeer actualFocusedWindow) {
1345         synchronized(getStateLock()) {
1346             this.actualFocusedWindow = actualFocusedWindow;
1347         }
1348     }
1349 
1350     boolean requestWindowFocus(XWindowPeer actualFocusedWindow,
1351                                long time, boolean timeProvided)
1352     {
1353         setActualFocusedWindow(actualFocusedWindow);
1354         return requestWindowFocus(time, timeProvided);
1355     }
1356     public void handleWindowFocusIn(long serial) {
1357         if (null == actualFocusedWindow) {
1358             super.handleWindowFocusIn(serial);
1359         } else {
1360             /*
1361              * Fix for 6314575.
1362              * If this is a result of clicking on one of the Frame's component
1363              * then 'actualFocusedWindow' shouldn't be focused. A decision of focusing
1364              * it or not should be made after the appropriate Java mouse event (if any)
1365              * is handled by the component where 'actualFocusedWindow' value may be reset.
1366              *
1367              * The fix is based on the empiric fact consisting in that the component
1368              * receives native mouse event nearly at the same time the Frame receives
1369              * WM_TAKE_FOCUS (when FocusIn is generated via XSetInputFocus call) but
1370              * definetely before the Frame gets FocusIn event (when this method is called).
1371              */
1372             postEvent(new InvocationEvent(target, new Runnable() {
1373                 public void run() {
1374                     XWindowPeer fw = null;
1375                     synchronized (getStateLock()) {
1376                         fw = actualFocusedWindow;
1377                         actualFocusedWindow = null;
1378                         if (null == fw || !fw.isVisible() || !fw.isFocusableWindow()) {
1379                             fw = XDecoratedPeer.this;
1380                         }
1381                     }
1382                     fw.handleWindowFocusIn_Dispatch();
1383                 }
1384             }));
1385         }
1386     }
1387 
1388     public void handleWindowFocusOut(Window oppositeWindow, long serial) {
1389         Window actualFocusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow();
1390 
1391         // If the actual focused window is not this decorated window then retain it.
1392         if (actualFocusedWindow != null && actualFocusedWindow != target) {
1393             Window owner = XWindowPeer.getDecoratedOwner(actualFocusedWindow);
1394 
1395             if (owner != null && owner == target) {
1396                 setActualFocusedWindow((XWindowPeer) ComponentAccessor.getPeer(actualFocusedWindow));
1397             }
1398         }
1399         super.handleWindowFocusOut(oppositeWindow, serial);
1400     }
1401 
1402     private Point queryXLocation()
1403     {
1404         return XlibUtil.translateCoordinates(
1405             getContentWindow(),
1406             XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()),
1407             new Point(0, 0));
1408     }
1409 }