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