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