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