1 /*
   2  * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 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 import java.util.Collections;
  33 import java.util.HashMap;
  34 import java.util.Map;
  35 
  36 import sun.awt.IconInfo;
  37 import sun.util.logging.PlatformLogger;
  38 
  39 import sun.awt.AWTAccessor;
  40 import sun.awt.SunToolkit;
  41 
  42 abstract class XDecoratedPeer extends XWindowPeer {
  43     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XDecoratedPeer");
  44     private static final PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XDecoratedPeer");
  45     private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XDecoratedPeer");
  46     private static final PlatformLogger iconLog = PlatformLogger.getLogger("sun.awt.X11.icon.XDecoratedPeer");
  47 
  48     // Set to true when we get the first ConfigureNotify after being
  49     // reparented - indicates that WM has adopted the top-level.
  50     boolean configure_seen;
  51     boolean insets_corrected;
  52 
  53     XIconWindow iconWindow;
  54     volatile WindowDimensions dimensions;
  55     XContentWindow content;
  56     volatile Insets currentInsets;
  57     XFocusProxyWindow focusProxy;
  58     static final Map<Class<?>,Insets> lastKnownInsets =
  59                                    Collections.synchronizedMap(new HashMap<>());
  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         currentInsets = new Insets(0,0,0,0);
  82         if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
  83             currentInsets = lastKnownInsets.get(getClass());
  84         }
  85         applyGuessedInsets();
  86 
  87         Rectangle bounds = (Rectangle)params.get(BOUNDS);
  88         dimensions = new WindowDimensions(bounds, getRealInsets(), false);
  89         params.put(BOUNDS, dimensions.getClientRect());
  90         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
  91             insLog.fine("Initial dimensions {0}", dimensions);
  92         }
  93 
  94         // Deny default processing of these events on the shell - proxy will take care of
  95         // them instead
  96         Long eventMask = (Long)params.get(EVENT_MASK);
  97         params.add(EVENT_MASK, Long.valueOf(eventMask.longValue() & ~(XConstants.FocusChangeMask | XConstants.KeyPressMask | XConstants.KeyReleaseMask)));
  98     }
  99 
 100     void postInit(XCreateWindowParams params) {
 101         // The size hints must be set BEFORE mapping the window (see 6895647)
 102         updateSizeHints(dimensions);
 103 
 104         // The super method maps the window if it's visible on the shared level
 105         super.postInit(params);
 106 
 107         // The lines that follow need to be in a postInit, so they
 108         // happen after the X window is created.
 109         setResizable(winAttr.initialResizability);
 110         XWM.requestWMExtents(getWindow());
 111 
 112         content = XContentWindow.createContent(this);
 113 
 114         if (warningWindow != null) {
 115             warningWindow.toFront();
 116         }
 117         focusProxy = createFocusProxy();
 118     }
 119 
 120     void setIconHints(java.util.List<IconInfo> icons) {
 121         if (!XWM.getWM().setNetWMIcon(this, icons)) {
 122             if (icons.size() > 0) {
 123                 if (iconWindow == null) {
 124                     iconWindow = new XIconWindow(this);
 125                 }
 126                 iconWindow.setIconImages(icons);
 127             }
 128         }
 129     }
 130 
 131     public void updateMinimumSize() {
 132         super.updateMinimumSize();
 133         XToolkit.awtLock();
 134         try {
 135             updateMinSizeHints();
 136         } finally {
 137             XToolkit.awtUnlock();
 138         }
 139     }
 140 
 141     private void updateMinSizeHints() {
 142         if (isResizable()) {
 143             Dimension minimumSize = getTargetMinimumSize();
 144             if (minimumSize != null) {
 145                 Insets insets = getRealInsets();
 146                 int minWidth = minimumSize.width - insets.left - insets.right;
 147                 int minHeight = minimumSize.height - insets.top - insets.bottom;
 148                 if (minWidth < 0) minWidth = 0;
 149                 if (minHeight < 0) minHeight = 0;
 150                 setSizeHints(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.USPosition)),
 151                              getX(), getY(), minWidth, minHeight);
 152                 if (isVisible()) {
 153                     Rectangle bounds = getShellBounds();
 154                     int nw = (bounds.width < minWidth) ? minWidth : bounds.width;
 155                     int nh = (bounds.height < minHeight) ? minHeight : bounds.height;
 156                     if (nw != bounds.width || nh != bounds.height) {
 157                         setShellSize(new Rectangle(0, 0, nw, nh));
 158                     }
 159                 }
 160             } else {
 161                 boolean isMinSizeSet = isMinSizeSet();
 162                 XWM.removeSizeHints(this, XUtilConstants.PMinSize);
 163                 /* Some WMs need remap to redecorate the window */
 164                 if (isMinSizeSet && isShowing() && XWM.needRemap(this)) {
 165                     /*
 166                      * Do the re/mapping at the Xlib level.  Since we essentially
 167                      * work around a WM bug we don't want this hack to be exposed
 168                      * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
 169                      */
 170                     xSetVisible(false);
 171                     XToolkit.XSync();
 172                     xSetVisible(true);
 173                 }
 174             }
 175         }
 176     }
 177 
 178     XFocusProxyWindow createFocusProxy() {
 179         return new XFocusProxyWindow(this);
 180     }
 181 
 182     protected XAtomList getWMProtocols() {
 183         XAtomList protocols = super.getWMProtocols();
 184         protocols.add(wm_delete_window);
 185         protocols.add(wm_take_focus);
 186         return protocols;
 187     }
 188 
 189     public Graphics getGraphics() {
 190         AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
 191         return getGraphics(content.surfaceData,
 192                            compAccessor.getForeground(target),
 193                            compAccessor.getBackground(target),
 194                            compAccessor.getFont(target));
 195     }
 196 
 197     public void setTitle(String title) {
 198         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 199             log.fine("Title is " + title);
 200         }
 201         XToolkit.awtLock();
 202         try {
 203             winAttr.title = title;
 204             updateWMName();
 205         } finally {
 206             XToolkit.awtUnlock();
 207         }
 208     }
 209 
 210     protected String getWMName() {
 211         if (winAttr.title == null || winAttr.title.trim().equals("")) {
 212             return " ";
 213         } else {
 214             return winAttr.title;
 215         }
 216     }
 217 
 218     void updateWMName() {
 219         XToolkit.awtLock();
 220         try {
 221             super.updateWMName();
 222             String name = getWMName();
 223             if (name == null || name.trim().equals("")) {
 224                 name = "Java";
 225             }
 226             XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME);
 227             iconNameAtom.setProperty(getWindow(), name);
 228             XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME");
 229             netIconNameAtom.setPropertyUTF8(getWindow(), name);
 230         } finally {
 231             XToolkit.awtUnlock();
 232         }
 233     }
 234 
 235     // NOTE: This method may be called by privileged threads.
 236     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 237     public void handleIconify() {
 238         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED));
 239     }
 240 
 241     // NOTE: This method may be called by privileged threads.
 242     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 243     public void handleDeiconify() {
 244         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED));
 245     }
 246 
 247     public void handleFocusEvent(XEvent xev) {
 248         super.handleFocusEvent(xev);
 249         XFocusChangeEvent xfe = xev.get_xfocus();
 250 
 251         // If we somehow received focus events forward it instead to proxy
 252         // FIXME: Shouldn't we instead check for inferrior?
 253         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
 254             focusLog.finer("Received focus event on shell: " + xfe);
 255         }
 256 //         focusProxy.xRequestFocus();
 257    }
 258 
 259 /***************************************************************************************
 260  *                             I N S E T S   C O D E
 261  **************************************************************************************/
 262 
 263     protected boolean isInitialReshape() {
 264         return false;
 265     }
 266 
 267     private static Insets difference(Insets i1, Insets i2) {
 268         return new Insets(i1.top-i2.top, i1.left - i2.left, i1.bottom-i2.bottom, i1.right-i2.right);
 269     }
 270 
 271     private static boolean isNull(Insets i) {
 272         return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0);
 273     }
 274 
 275     private static Insets copy(Insets i) {
 276         return new Insets(i.top, i.left, i.bottom, i.right);
 277     }
 278 
 279     private Insets copyAndScaleDown(Insets i) {
 280         return new Insets(scaleDown(i.top), scaleDown(i.left),
 281                           scaleDown(i.bottom), scaleDown(i.right));
 282     }
 283 
 284 
 285     // insets which we get from WM (e.g from _NET_FRAME_EXTENTS)
 286     private Insets wm_set_insets;
 287 
 288     private Insets getWMSetInsets(XAtom changedAtom) {
 289         if (isEmbedded()) {
 290             return null;
 291         }
 292 
 293         if (wm_set_insets != null) {
 294             return wm_set_insets;
 295         }
 296 
 297         if (changedAtom == null) {
 298             wm_set_insets = XWM.getInsetsFromExtents(getWindow());
 299         } else {
 300             wm_set_insets = XWM.getInsetsFromProp(getWindow(), changedAtom);
 301         }
 302 
 303         if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
 304             insLog.finer("FRAME_EXTENTS: {0}", wm_set_insets);
 305         }
 306 
 307         if (wm_set_insets != null) {
 308             wm_set_insets = copyAndScaleDown(wm_set_insets);
 309         }
 310         return wm_set_insets;
 311     }
 312 
 313     private void resetWMSetInsets() {
 314         if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
 315             currentInsets = new Insets(0, 0, 0, 0);
 316             wm_set_insets = null;
 317         } else {
 318             insets_corrected = false;
 319         }
 320     }
 321 
 322     public void handlePropertyNotify(XEvent xev) {
 323         super.handlePropertyNotify(xev);
 324 
 325         XPropertyEvent ev = xev.get_xproperty();
 326         if( !insets_corrected && isReparented() &&
 327                                          XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
 328             int state = XWM.getWM().getState(this);
 329             if ((state & Frame.MAXIMIZED_BOTH) ==  Frame.MAXIMIZED_BOTH) {
 330                 // Stop ignoring ConfigureNotify because no extents will be sent
 331                 // by WM for initially maximized decorated window.
 332                 // Re-request window bounds to ensure actual dimensions and
 333                 // notify the target with the initial size.
 334                 insets_corrected = true;
 335                 XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
 336                                                              getWindow(), 0, 0);
 337             }
 338         }
 339         if (ev.get_atom() == XWM.XA_KDE_NET_WM_FRAME_STRUT.getAtom()
 340             || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom())
 341         {
 342             if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
 343                 getWMSetInsets(XAtom.get(ev.get_atom()));
 344             } else {
 345                 if (!isReparented()) {
 346                     return;
 347                 }
 348                 wm_set_insets = null;
 349                 Insets in = getWMSetInsets(XAtom.get(ev.get_atom()));
 350                 if (isNull(in)) {
 351                     return;
 352                 }
 353                 if (!isEmbedded() && !isTargetUndecorated()) {
 354                     lastKnownInsets.put(getClass(), in);
 355                 }
 356                 if (!in.equals(dimensions.getInsets())) {
 357                     if (insets_corrected || isMaximized()) {
 358                         currentInsets = in;
 359                         insets_corrected = true;
 360                         // insets were changed by WM. To handle this situation
 361                         // re-request window bounds because the current
 362                         // dimensions may be not actual as well.
 363                         XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
 364                                                              getWindow(), 0, 0);
 365                     } else {
 366                         // recalculate dimensions when window is just created
 367                         // and the initially guessed insets were wrong
 368                         handleCorrectInsets(in);
 369                     }
 370                 } else if (!insets_corrected || !dimensions.isClientSizeSet()) {
 371                     insets_corrected = true;
 372                     // initial insets were guessed correctly. Re-request
 373                     // frame bounds because they may be changed by WM if the
 374                     // initial window position overlapped desktop's toolbars.
 375                     // This should initiate the final ConfigureNotify upon which
 376                     // the target will be notified with the final size.
 377                     XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
 378                                                              getWindow(), 0, 0);
 379                 }
 380             }
 381         }
 382     }
 383 
 384     long reparent_serial = 0;
 385 
 386     public void handleReparentNotifyEvent(XEvent xev) {
 387         XReparentEvent  xe = xev.get_xreparent();
 388         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 389             insLog.fine(xe.toString());
 390         }
 391         reparent_serial = xe.get_serial();
 392         long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber());
 393 
 394         if (isEmbedded()) {
 395             setReparented(true);
 396             insets_corrected = true;
 397             return;
 398         }
 399         if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) {
 400             setReparented(true);
 401             insets_corrected = true;
 402             reshape(dimensions, SET_SIZE, false);
 403         } else if (xe.get_parent() == root) {
 404             configure_seen = false;
 405             insets_corrected = false;
 406 
 407             /*
 408              * We can be repareted to root for two reasons:
 409              *   . setVisible(false)
 410              *   . WM exited
 411              */
 412             if (isVisible()) { /* WM exited */
 413                 /* Work around 4775545 */
 414                 XWM.getWM().unshadeKludge(this);
 415                 insLog.fine("- WM exited");
 416             } else {
 417                 insLog.fine(" - reparent due to hide");
 418             }
 419         } else { /* reparented to WM frame, figure out our insets */
 420             setReparented(true);
 421             insets_corrected = false;
 422             if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
 423                 return;
 424             }
 425 
 426             // Check if we have insets provided by the WM
 427             Insets correctWM = getWMSetInsets(null);
 428             if (correctWM != null) {
 429                 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
 430                     insLog.finer("wm-provided insets {0}", correctWM);
 431                 }
 432                 // If these insets are equal to our current insets - no actions are necessary
 433                 Insets dimInsets = dimensions.getInsets();
 434                 if (correctWM.equals(dimInsets)) {
 435                     insLog.finer("Insets are the same as estimated - no additional reshapes necessary");
 436                     no_reparent_artifacts = true;
 437                     insets_corrected = true;
 438                     applyGuessedInsets();
 439                     return;
 440                 }
 441             } else {
 442                 correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent());
 443                 if (correctWM != null) {
 444                     correctWM = copyAndScaleDown(correctWM);
 445                 }
 446 
 447                 if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
 448                     if (correctWM != null) {
 449                         insLog.finer("correctWM {0}", correctWM);
 450                     } else {
 451                         insLog.finer("correctWM insets are not available, waiting for configureNotify");
 452                     }
 453                 }
 454             }
 455 
 456             if (correctWM != null) {
 457                 handleCorrectInsets(correctWM);
 458             }
 459         }
 460     }
 461 
 462     private void handleCorrectInsets(Insets correctWM) {
 463         /*
 464          * Ok, now see if we need adjust window size because
 465          * initial insets were wrong (most likely they were).
 466          */
 467         Insets correction = difference(correctWM, currentInsets);
 468         if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
 469             insLog.finest("Corrention {0}", correction);
 470         }
 471         if (!isNull(correction)) {
 472             currentInsets = copy(correctWM);
 473             applyGuessedInsets();
 474 
 475             //Fix for 6318109: PIT: Min Size is not honored properly when a
 476             //smaller size is specified in setSize(), XToolkit
 477             //update minimum size hints
 478             updateMinSizeHints();
 479         }
 480         if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
 481             insLog.finer("Dimensions before reparent: " + dimensions);
 482         }
 483         WindowDimensions newDimensions = new WindowDimensions(dimensions);
 484         newDimensions.setInsets(getRealInsets());
 485         dimensions = newDimensions;
 486         insets_corrected = true;
 487 
 488         if (isMaximized()) {
 489             return;
 490         }
 491 
 492         /*
 493          * If this window has been sized by a pack() we need
 494          * to keep the interior geometry intact.  Since pack()
 495          * computed width and height with wrong insets, we
 496          * must adjust the target dimensions appropriately.
 497          */
 498         if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) {
 499             reshape(dimensions, SET_BOUNDS, false);
 500         } else {
 501             reshape(dimensions, SET_SIZE, false);
 502         }
 503     }
 504 
 505     void handleMoved(WindowDimensions dims) {
 506         Point loc = dims.getLocation();
 507         AWTAccessor.getComponentAccessor().setLocation(target, loc.x, loc.y);
 508         postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED));
 509     }
 510 
 511 
 512     private Insets guessInsets() {
 513         if (isEmbedded() || isTargetUndecorated()) {
 514             return new Insets(0, 0, 0, 0);
 515         } else {
 516             if (!isNull(currentInsets)) {
 517                 /* insets were set on wdata by System Properties */
 518                 return copy(currentInsets);
 519             } else {
 520                 Insets res = getWMSetInsets(null);
 521                 if (res == null) {
 522                     res = XWM.getWM().guessInsets(this);
 523                     if (res != null) {
 524                         res = copyAndScaleDown(res);
 525                     }
 526                 }
 527                 return res;
 528             }
 529         }
 530     }
 531 
 532     private void applyGuessedInsets() {
 533         Insets guessed = guessInsets();
 534         currentInsets = copy(guessed);
 535     }
 536 
 537     private Insets getRealInsets() {
 538         if (isNull(currentInsets)) {
 539             applyGuessedInsets();
 540         }
 541         return currentInsets;
 542     }
 543 
 544     public Insets getInsets() {
 545         Insets in = copy(getRealInsets());
 546         in.top += getMenuBarHeight();
 547         if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
 548             insLog.finest("Get insets returns {0}", in);
 549         }
 550         return in;
 551     }
 552 
 553     boolean gravityBug() {
 554         return XWM.configureGravityBuggy();
 555     }
 556 
 557     // The height of area used to display current active input method
 558     int getInputMethodHeight() {
 559         return 0;
 560     }
 561 
 562     void updateSizeHints(WindowDimensions dims) {
 563         Rectangle rec = dims.getClientRect();
 564         checkShellRect(rec);
 565         updateSizeHints(rec.x, rec.y, rec.width, rec.height);
 566     }
 567 
 568     void updateSizeHints() {
 569         updateSizeHints(dimensions);
 570     }
 571 
 572     // Coordinates are that of the target
 573     // Called only on Toolkit thread
 574     private void reshape(WindowDimensions newDimensions, int op,
 575                         boolean userReshape)
 576     {
 577         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 578             insLog.fine("Reshaping " + this + " to " + newDimensions + " op " + op + " user reshape " + userReshape);
 579         }
 580         if (userReshape) {
 581             // We handle only userReshape == true cases. It means that
 582             // if the window manager or any other part of the windowing
 583             // system sets inappropriate size for this window, we can
 584             // do nothing but accept it.
 585             Rectangle newBounds = newDimensions.getBounds();
 586             Insets insets = newDimensions.getInsets();
 587             // Inherit isClientSizeSet from newDimensions
 588             if (newDimensions.isClientSizeSet()) {
 589                 newBounds = new Rectangle(newBounds.x, newBounds.y,
 590                                           newBounds.width - insets.left - insets.right,
 591                                           newBounds.height - insets.top - insets.bottom);
 592             }
 593             newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet());
 594         }
 595         if (!isReparented() || !isVisible()) {
 596             if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 597                 insLog.fine("- not reparented({0}) or not visible({1}), default reshape",
 598                        Boolean.valueOf(isReparented()), Boolean.valueOf(visible));
 599             }
 600 
 601             // Fix for 6323293.
 602             // This actually is needed to preserve compatibility with previous releases -
 603             // some of licensees are expecting componentMoved event on invisible one while
 604             // its location changes.
 605             Point oldLocation = getLocation();
 606 
 607             Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX(target),
 608                                           AWTAccessor.getComponentAccessor().getY(target));
 609 
 610             if (!newLocation.equals(oldLocation)) {
 611                 handleMoved(newDimensions);
 612             }
 613 
 614             dimensions = new WindowDimensions(newDimensions);
 615             updateSizeHints(dimensions);
 616             Rectangle client = dimensions.getClientRect();
 617             checkShellRect(client);
 618             setShellBounds(client);
 619             if (content != null &&
 620                 !content.getSize().equals(newDimensions.getSize()))
 621             {
 622                 reconfigureContentWindow(newDimensions);
 623             }
 624             return;
 625         }
 626 
 627         updateChildrenSizes();
 628         applyGuessedInsets();
 629 
 630         Rectangle shellRect = newDimensions.getClientRect();
 631 
 632         if (gravityBug()) {
 633             Insets in = newDimensions.getInsets();
 634             shellRect.translate(in.left, in.top);
 635         }
 636 
 637         if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) {
 638             shellRect.setLocation(0, 0);
 639         }
 640 
 641         checkShellRectSize(shellRect);
 642         if (!isEmbedded()) {
 643             checkShellRectPos(shellRect);
 644         }
 645 
 646         op = op & ~NO_EMBEDDED_CHECK;
 647 
 648         if (op == SET_LOCATION) {
 649             setShellPosition(shellRect);
 650         } else if (isResizable()) {
 651             if (op == SET_BOUNDS) {
 652                 setShellBounds(shellRect);
 653             } else {
 654                 setShellSize(shellRect);
 655             }
 656         } else {
 657             XWM.setShellNotResizable(this, newDimensions, shellRect, true);
 658             if (op == SET_BOUNDS) {
 659                 setShellPosition(shellRect);
 660             }
 661         }
 662 
 663         reconfigureContentWindow(newDimensions);
 664     }
 665 
 666     /**
 667      * @param x, y, width, heith - dimensions of the window with insets
 668      */
 669     private void reshape(int x, int y, int width, int height, int operation,
 670                          boolean userReshape)
 671     {
 672         WindowDimensions dims = new WindowDimensions(dimensions);
 673         switch (operation & (~NO_EMBEDDED_CHECK)) {
 674           case SET_LOCATION:
 675               // Set location always sets bounds location. However, until the window is mapped we
 676               // should use client coordinates
 677               dims.setLocation(x, y);
 678               break;
 679           case SET_SIZE:
 680               // Set size sets bounds size. However, until the window is mapped we
 681               // should use client coordinates
 682               dims.setSize(width, height);
 683               break;
 684           case SET_CLIENT_SIZE: {
 685               // Sets client rect size. Width and height contain insets.
 686               Insets in = currentInsets;
 687               width -= in.left+in.right;
 688               height -= in.top+in.bottom;
 689               dims.setClientSize(width, height);
 690               break;
 691           }
 692           case SET_BOUNDS:
 693           default:
 694               dims.setLocation(x, y);
 695               dims.setSize(width, height);
 696               break;
 697         }
 698         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 699             insLog.fine("For the operation {0} new dimensions are {1}",
 700                         operationToString(operation), dims);
 701         }
 702 
 703         reshape(dims, operation, userReshape);
 704     }
 705 
 706     // This method gets overriden in XFramePeer & XDialogPeer.
 707     abstract boolean isTargetUndecorated();
 708 
 709     /**
 710      * @see java.awt.peer.ComponentPeer#setBounds
 711      */
 712     public void setBounds(int x, int y, int width, int height, int op) {
 713         // TODO: Rewrite with WindowDimensions
 714         XToolkit.awtLock();
 715         try {
 716             reshape(x, y, width, height, op, true);
 717         } finally {
 718             XToolkit.awtUnlock();
 719         }
 720         validateSurface();
 721     }
 722 
 723     // Coordinates are that of the shell
 724     void reconfigureContentWindow(WindowDimensions dims) {
 725         if (content == null) {
 726             insLog.fine("WARNING: Content window is null");
 727             return;
 728         }
 729         content.setContentBounds(dims);
 730     }
 731 
 732     boolean no_reparent_artifacts = false;
 733     public void handleConfigureNotifyEvent(XEvent xev) {
 734         if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM && !insets_corrected) {
 735             return;
 736         }
 737         assert (SunToolkit.isAWTLockHeldByCurrentThread());
 738         XConfigureEvent xe = xev.get_xconfigure();
 739         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 740             insLog.fine("Configure notify {0}", xe);
 741         }
 742 
 743         // XXX: should really only consider synthetic events, but
 744         if (isReparented()) {
 745             configure_seen = true;
 746         }
 747 
 748         if (!isMaximized()
 749             && (xe.get_serial() == reparent_serial || xe.get_window() != getShell())
 750             && !no_reparent_artifacts)
 751         {
 752             insLog.fine("- reparent artifact, skipping");
 753             return;
 754         }
 755         no_reparent_artifacts = false;
 756 
 757         /**
 758          * When there is a WM we receive some CN before being visible and after.
 759          * We should skip all CN which are before being visible, because we assume
 760          * the gravity is in action while it is not yet.
 761          *
 762          * When there is no WM we receive CN only _before_ being visible.
 763          * We should process these CNs.
 764          */
 765         if (!isVisible() && XWM.getWMID() != XWM.NO_WM) {
 766             insLog.fine(" - not visible, skipping");
 767             return;
 768         }
 769 
 770         /*
 771          * Some window managers configure before we are reparented and
 772          * the send event flag is set! ugh... (Enlighetenment for one,
 773          * possibly MWM as well).  If we haven't been reparented yet
 774          * this is just the WM shuffling us into position.  Ignore
 775          * it!!!! or we wind up in a bogus location.
 776          */
 777         int runningWM = XWM.getWMID();
 778         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 779             insLog.fine("reparented={0}, visible={1}, WM={2}, decorations={3}",
 780                         isReparented(), isVisible(), runningWM, getDecorations());
 781         }
 782         if (!isReparented() && isVisible() && runningWM != XWM.NO_WM
 783                 &&  !XWM.isNonReparentingWM()
 784                 && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) {
 785             insLog.fine("- visible but not reparented, skipping");
 786             return;
 787         }
 788         //Last chance to correct insets
 789         if (!insets_corrected && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) {
 790             long parent = XlibUtil.getParentWindow(window);
 791             Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(this, window, parent) : null;
 792             if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
 793                 if (correctWM != null) {
 794                     insLog.finer("Configure notify - insets : " + correctWM);
 795                 } else {
 796                     insLog.finer("Configure notify - insets are still not available");
 797                 }
 798             }
 799             if (correctWM != null) {
 800                 handleCorrectInsets(copyAndScaleDown(correctWM));
 801             } else {
 802                 //Only one attempt to correct insets is made (to lower risk)
 803                 //if insets are still not available we simply set the flag
 804                 insets_corrected = true;
 805             }
 806         }
 807 
 808         updateChildrenSizes();
 809 
 810         Point newLocation = getNewLocation(xe, currentInsets.left, currentInsets.top);
 811         WindowDimensions newDimensions =
 812                 new WindowDimensions(newLocation,
 813                                      new Dimension(scaleDown(xe.get_width()),
 814                                                    scaleDown(xe.get_height())),
 815                                      copy(currentInsets), true);
 816 
 817         if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
 818             insLog.finer("Insets are {0}, new dimensions {1}",
 819                      currentInsets, newDimensions);
 820         }
 821 
 822         checkIfOnNewScreen(newDimensions.getBounds());
 823 
 824         Point oldLocation = getLocation();
 825         dimensions = newDimensions;
 826         if (!newLocation.equals(oldLocation)) {
 827             handleMoved(newDimensions);
 828         }
 829         reconfigureContentWindow(newDimensions);
 830         updateChildrenSizes();
 831 
 832         repositionSecurityWarning();
 833     }
 834 
 835     private void checkShellRectSize(Rectangle shellRect) {
 836         shellRect.width = Math.max(MIN_SIZE, shellRect.width);
 837         shellRect.height = Math.max(MIN_SIZE, shellRect.height);
 838     }
 839 
 840     private void checkShellRectPos(Rectangle shellRect) {
 841         int wm = XWM.getWMID();
 842         if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) {
 843             if (shellRect.x == 0 && shellRect.y == 0) {
 844                 shellRect.x = shellRect.y = 1;
 845             }
 846         }
 847     }
 848 
 849     private void checkShellRect(Rectangle shellRect) {
 850         checkShellRectSize(shellRect);
 851         checkShellRectPos(shellRect);
 852     }
 853 
 854     private void setShellBounds(Rectangle rec) {
 855         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 856             insLog.fine("Setting shell bounds on " + this + " to " + rec);
 857         }
 858         updateSizeHints(rec.x, rec.y, rec.width, rec.height);
 859         XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(),
 860                                       scaleUp(rec.x), scaleUp(rec.y),
 861                                       scaleUp(rec.width), scaleUp(rec.height));
 862     }
 863 
 864     private void setShellSize(Rectangle rec) {
 865         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 866             insLog.fine("Setting shell size on " + this + " to " + rec);
 867         }
 868         updateSizeHints(rec.x, rec.y, rec.width, rec.height);
 869         XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(),
 870                                   scaleUp(rec.width), scaleUp(rec.height));
 871     }
 872 
 873     private void setShellPosition(Rectangle rec) {
 874         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 875             insLog.fine("Setting shell position on " + this + " to " + rec);
 876         }
 877         updateSizeHints(rec.x, rec.y, rec.width, rec.height);
 878         XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(),
 879                                 scaleUp(rec.x), scaleUp(rec.y));
 880     }
 881 
 882     public void setResizable(boolean resizable) {
 883         XToolkit.awtLock();
 884         try {
 885             int fs = winAttr.functions;
 886             if (!isResizable() && resizable) {
 887                 resetWMSetInsets();
 888                 if (!isEmbedded()) {
 889                     setReparented(false);
 890                 }
 891                 winAttr.isResizable = resizable;
 892                 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
 893                     fs &= ~(MWMConstants.MWM_FUNC_RESIZE
 894                           | MWMConstants.MWM_FUNC_MAXIMIZE);
 895                 } else {
 896                     fs |= (MWMConstants.MWM_FUNC_RESIZE
 897                          | MWMConstants.MWM_FUNC_MAXIMIZE);
 898                 }
 899                 winAttr.functions = fs;
 900                 XWM.setShellResizable(this);
 901             } else if (isResizable() && !resizable) {
 902                 resetWMSetInsets();
 903                 if (!isEmbedded()) {
 904                     setReparented(false);
 905                 }
 906                 winAttr.isResizable = resizable;
 907                 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
 908                     fs |= (MWMConstants.MWM_FUNC_RESIZE
 909                          | MWMConstants.MWM_FUNC_MAXIMIZE);
 910                 } else {
 911                     fs &= ~(MWMConstants.MWM_FUNC_RESIZE
 912                           | MWMConstants.MWM_FUNC_MAXIMIZE);
 913                 }
 914                 winAttr.functions = fs;
 915                 XWM.setShellNotResizable(this, dimensions,
 916                         XWM.getWMID() == XWM.UNITY_COMPIZ_WM && configure_seen ?
 917                         dimensions.getScreenBounds() :
 918                         dimensions.getBounds(), false);
 919             }
 920         } finally {
 921             XToolkit.awtUnlock();
 922         }
 923     }
 924 
 925     Rectangle getShellBounds() {
 926         return dimensions.getClientRect();
 927     }
 928 
 929     public Rectangle getBounds() {
 930         return dimensions.getBounds();
 931     }
 932 
 933     public Dimension getSize() {
 934         return dimensions.getSize();
 935     }
 936 
 937     public int getX() {
 938         return dimensions.getLocation().x;
 939     }
 940 
 941     public int getY() {
 942         return dimensions.getLocation().y;
 943     }
 944 
 945     public Point getLocation() {
 946         return dimensions.getLocation();
 947     }
 948 
 949     public int getAbsoluteX() {
 950         // NOTE: returning this peer's location which is shell location
 951         return dimensions.getScreenBounds().x;
 952     }
 953 
 954     public int getAbsoluteY() {
 955         // NOTE: returning this peer's location which is shell location
 956         return dimensions.getScreenBounds().y;
 957     }
 958 
 959     public int getWidth() {
 960         return getSize().width;
 961     }
 962 
 963     public int getHeight() {
 964         return getSize().height;
 965     }
 966 
 967     public final WindowDimensions getDimensions() {
 968         return dimensions;
 969     }
 970 
 971     public Point getLocationOnScreen() {
 972         XToolkit.awtLock();
 973         try {
 974             if (configure_seen) {
 975                 return toGlobal(0,0);
 976             }
 977         } finally {
 978             XToolkit.awtUnlock();
 979         }
 980         Point location = target.getLocation();
 981         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
 982             insLog.fine("getLocationOnScreen {0} not reparented: {1} ",
 983                         this, location);
 984         }
 985         return location;
 986     }
 987 
 988 
 989 /***************************************************************************************
 990  *              END            OF             I N S E T S   C O D E
 991  **************************************************************************************/
 992 
 993     protected boolean isEventDisabled(XEvent e) {
 994         switch (e.get_type()) {
 995             // Do not generate MOVED/RESIZED events since we generate them by ourselves
 996           case XConstants.ConfigureNotify:
 997               return true;
 998           case XConstants.EnterNotify:
 999           case XConstants.LeaveNotify:
1000               // Disable crossing event on outer borders of Frame so
1001               // we receive only one set of cross notifications(first set is from content window)
1002               return true;
1003           default:
1004               return super.isEventDisabled(e);
1005         }
1006     }
1007 
1008     int getDecorations() {
1009         return winAttr.decorations;
1010     }
1011 
1012     int getFunctions() {
1013         return winAttr.functions;
1014     }
1015 
1016     public void setVisible(boolean vis) {
1017         if (log.isLoggable(PlatformLogger.Level.FINER)) {
1018             log.finer("Setting {0} to visible {1}", this, Boolean.valueOf(vis));
1019         }
1020         if (vis && !isVisible()) {
1021             XWM.setShellDecor(this);
1022             super.setVisible(vis);
1023             if (winAttr.isResizable) {
1024                 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
1025                 //We need to update frame's minimum size, not to reset it
1026                 XWM.removeSizeHints(this, XUtilConstants.PMaxSize);
1027                 updateMinimumSize();
1028             }
1029         } else {
1030             super.setVisible(vis);
1031         }
1032     }
1033 
1034     protected void suppressWmTakeFocus(boolean doSuppress) {
1035         XAtomList protocols = getWMProtocols();
1036         if (doSuppress) {
1037             protocols.remove(wm_take_focus);
1038         } else {
1039             protocols.add(wm_take_focus);
1040         }
1041         wm_protocols.setAtomListProperty(this, protocols);
1042     }
1043 
1044     public void dispose() {
1045         if (content != null) {
1046             content.destroy();
1047         }
1048         focusProxy.destroy();
1049 
1050         if (iconWindow != null) {
1051             iconWindow.destroy();
1052         }
1053 
1054         super.dispose();
1055     }
1056 
1057     public void handleClientMessage(XEvent xev) {
1058         super.handleClientMessage(xev);
1059         XClientMessageEvent cl = xev.get_xclient();
1060         if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) {
1061             if (cl.get_data(0) == wm_delete_window.getAtom()) {
1062                 handleQuit();
1063             } else if (cl.get_data(0) == wm_take_focus.getAtom()) {
1064                 handleWmTakeFocus(cl);
1065             }
1066         }
1067     }
1068 
1069     private void handleWmTakeFocus(XClientMessageEvent cl) {
1070         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1071             focusLog.fine("WM_TAKE_FOCUS on {0}", this);
1072         }
1073 
1074         if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
1075             // JDK-8159460
1076             Window focusedWindow = XKeyboardFocusManagerPeer.getInstance()
1077                     .getCurrentFocusedWindow();
1078             Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
1079             if (activeWindow != target) {
1080                 requestWindowFocus(cl.get_data(1), true);
1081             } else {
1082                 WindowEvent we = new WindowEvent(focusedWindow,
1083                         WindowEvent.WINDOW_GAINED_FOCUS);
1084                 sendEvent(we);
1085             }
1086         } else {
1087             requestWindowFocus(cl.get_data(1), true);
1088         }
1089     }
1090 
1091     /**
1092      * Requests focus to this decorated top-level by requesting X input focus
1093      * to the shell window.
1094      */
1095     protected void requestXFocus(long time, boolean timeProvided) {
1096         // We have proxied focus mechanism - instead of shell the focus is held
1097         // by "proxy" - invisible mapped window. When we want to set X input focus to
1098         // toplevel set it on proxy instead.
1099         if (focusProxy == null) {
1100             if (focusLog.isLoggable(PlatformLogger.Level.WARNING)) {
1101                 focusLog.warning("Focus proxy is null for " + this);
1102             }
1103         } else {
1104             if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1105                 focusLog.fine("Requesting focus to proxy: " + focusProxy);
1106             }
1107             if (timeProvided) {
1108                 focusProxy.xRequestFocus(time);
1109             } else {
1110                 focusProxy.xRequestFocus();
1111             }
1112         }
1113     }
1114 
1115     XFocusProxyWindow getFocusProxy() {
1116         return focusProxy;
1117     }
1118 
1119     private void handleQuit() {
1120         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING));
1121     }
1122 
1123     final void dumpMe() {
1124         System.err.println(">>> Peer: " + x + ", " + y + ", " + width + ", " + height);
1125     }
1126 
1127     final void dumpTarget() {
1128         AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
1129         int getWidth = compAccessor.getWidth(target);
1130         int getHeight = compAccessor.getHeight(target);
1131         int getTargetX = compAccessor.getX(target);
1132         int getTargetY = compAccessor.getY(target);
1133         System.err.println(">>> Target: " + getTargetX + ", " + getTargetY + ", " + getWidth + ", " + getHeight);
1134     }
1135 
1136     final void dumpShell() {
1137         dumpWindow("Shell", getShell());
1138     }
1139     final void dumpContent() {
1140         dumpWindow("Content", getContentWindow());
1141     }
1142     final void dumpParent() {
1143         long parent = XlibUtil.getParentWindow(getShell());
1144         if (parent != 0)
1145         {
1146             dumpWindow("Parent", parent);
1147         }
1148         else
1149         {
1150             System.err.println(">>> NO PARENT");
1151         }
1152     }
1153 
1154     final void dumpWindow(String id, long window) {
1155         XWindowAttributes pattr = new XWindowAttributes();
1156         try {
1157             XToolkit.awtLock();
1158             try {
1159                 int status =
1160                     XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
1161                                                      window, pattr.pData);
1162             }
1163             finally {
1164                 XToolkit.awtUnlock();
1165             }
1166             System.err.println(">>>> " + id + ": " + pattr.get_x()
1167                                + ", " + pattr.get_y() + ", " + pattr.get_width()
1168                                + ", " + pattr.get_height());
1169         } finally {
1170             pattr.dispose();
1171         }
1172     }
1173 
1174     final void dumpAll() {
1175         dumpTarget();
1176         dumpMe();
1177         dumpParent();
1178         dumpShell();
1179         dumpContent();
1180     }
1181 
1182     boolean isMaximized() {
1183         return false;
1184     }
1185 
1186     @Override
1187     boolean isOverrideRedirect() {
1188         return Window.Type.POPUP.equals(getWindowType());
1189     }
1190 
1191     public boolean requestWindowFocus(long time, boolean timeProvided) {
1192         focusLog.fine("Request for decorated window focus");
1193         // If this is Frame or Dialog we can't assure focus request success - but we still can try
1194         // If this is Window and its owner Frame is active we can be sure request succedded.
1195         Window focusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow();
1196         Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
1197 
1198         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
1199             focusLog.finer("Current window is: active={0}, focused={1}",
1200                        Boolean.valueOf(target == activeWindow),
1201                        Boolean.valueOf(target == focusedWindow));
1202         }
1203 
1204         XWindowPeer toFocus = this;
1205         while (toFocus.nextTransientFor != null) {
1206             toFocus = toFocus.nextTransientFor;
1207         }
1208         if (toFocus == null || !toFocus.focusAllowedFor()) {
1209             // This might change when WM will have property to determine focus policy.
1210             // Right now, because policy is unknown we can't be sure we succedded
1211             return false;
1212         }
1213         if (this == toFocus) {
1214             if (isWMStateNetHidden()) {
1215                 focusLog.fine("The window is unmapped, so rejecting the request");
1216                 return false;
1217             }
1218             if (target == activeWindow && target != focusedWindow) {
1219                 // Happens when an owned window is currently focused
1220                 focusLog.fine("Focus is on child window - transferring it back to the owner");
1221                 handleWindowFocusInSync(-1);
1222                 return true;
1223             }
1224             Window realNativeFocusedWindow = XWindowPeer.getNativeFocusedWindow();
1225             if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
1226                 focusLog.finest("Real native focused window: " + realNativeFocusedWindow +
1227                             "\nKFM's focused window: " + focusedWindow);
1228             }
1229 
1230             // A workaround for Metacity. See 6522725, 6613426, 7147075.
1231             if (target == realNativeFocusedWindow && XWM.getWMID() == XWM.METACITY_WM) {
1232                 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1233                     focusLog.fine("The window is already natively focused.");
1234                 }
1235                 return true;
1236             }
1237         }
1238         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1239             focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus));
1240         }
1241 
1242         if (timeProvided) {
1243             toFocus.requestXFocus(time);
1244         } else {
1245             toFocus.requestXFocus();
1246         }
1247         return (this == toFocus);
1248     }
1249 
1250     XWindowPeer actualFocusedWindow = null;
1251     void setActualFocusedWindow(XWindowPeer actualFocusedWindow) {
1252         synchronized(getStateLock()) {
1253             this.actualFocusedWindow = actualFocusedWindow;
1254         }
1255     }
1256 
1257     boolean requestWindowFocus(XWindowPeer actualFocusedWindow,
1258                                long time, boolean timeProvided)
1259     {
1260         setActualFocusedWindow(actualFocusedWindow);
1261         return requestWindowFocus(time, timeProvided);
1262     }
1263     public void handleWindowFocusIn(long serial) {
1264         if (null == actualFocusedWindow) {
1265             super.handleWindowFocusIn(serial);
1266         } else {
1267             /*
1268              * Fix for 6314575.
1269              * If this is a result of clicking on one of the Frame's component
1270              * then 'actualFocusedWindow' shouldn't be focused. A decision of focusing
1271              * it or not should be made after the appropriate Java mouse event (if any)
1272              * is handled by the component where 'actualFocusedWindow' value may be reset.
1273              *
1274              * The fix is based on the empiric fact consisting in that the component
1275              * receives native mouse event nearly at the same time the Frame receives
1276              * WM_TAKE_FOCUS (when FocusIn is generated via XSetInputFocus call) but
1277              * definetely before the Frame gets FocusIn event (when this method is called).
1278              */
1279             postEvent(new InvocationEvent(target, new Runnable() {
1280                 public void run() {
1281                     XWindowPeer fw = null;
1282                     synchronized (getStateLock()) {
1283                         fw = actualFocusedWindow;
1284                         actualFocusedWindow = null;
1285                         if (null == fw || !fw.isVisible() || !fw.isFocusableWindow()) {
1286                             fw = XDecoratedPeer.this;
1287                         }
1288                     }
1289                     fw.handleWindowFocusIn_Dispatch();
1290                 }
1291             }));
1292         }
1293     }
1294 
1295     public void handleWindowFocusOut(Window oppositeWindow, long serial) {
1296         Window actualFocusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow();
1297 
1298         // If the actual focused window is not this decorated window then retain it.
1299         if (actualFocusedWindow != null && actualFocusedWindow != target) {
1300             Window owner = XWindowPeer.getDecoratedOwner(actualFocusedWindow);
1301 
1302             if (owner != null && owner == target) {
1303                 setActualFocusedWindow(AWTAccessor.getComponentAccessor().getPeer(actualFocusedWindow));
1304             }
1305         }
1306         super.handleWindowFocusOut(oppositeWindow, serial);
1307     }
1308 }