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