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