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