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