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