1 /*
   2  * Copyright (c) 2002, 2013, 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.FocusEvent;
  31 import java.awt.event.WindowEvent;
  32 
  33 import java.awt.peer.ComponentPeer;
  34 import java.awt.peer.WindowPeer;
  35 
  36 import java.io.UnsupportedEncodingException;
  37 
  38 import java.security.AccessController;
  39 import java.security.PrivilegedAction;
  40 
  41 import java.util.ArrayList;
  42 import java.util.HashSet;
  43 import java.util.Iterator;
  44 import java.util.Set;
  45 import java.util.Vector;
  46 
  47 import java.util.concurrent.atomic.AtomicBoolean;
  48 
  49 import sun.util.logging.PlatformLogger;
  50 
  51 import sun.awt.AWTAccessor;
  52 import sun.awt.DisplayChangedListener;
  53 import sun.awt.SunToolkit;
  54 import sun.awt.X11GraphicsDevice;
  55 import sun.awt.X11GraphicsEnvironment;
  56 import sun.awt.IconInfo;
  57 
  58 import sun.java2d.pipe.Region;
  59 
  60 class XWindowPeer extends XPanelPeer implements WindowPeer,
  61                                                 DisplayChangedListener {
  62 
  63     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XWindowPeer");
  64     private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XWindowPeer");
  65     private static final PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XWindowPeer");
  66     private static final PlatformLogger grabLog = PlatformLogger.getLogger("sun.awt.X11.grab.XWindowPeer");
  67     private static final PlatformLogger iconLog = PlatformLogger.getLogger("sun.awt.X11.icon.XWindowPeer");
  68 
  69     // should be synchronized on awtLock
  70     private static Set<XWindowPeer> windows = new HashSet<XWindowPeer>();
  71 
  72 
  73     private boolean cachedFocusableWindow;
  74     XWarningWindow warningWindow;
  75 
  76     private boolean alwaysOnTop;
  77     private boolean locationByPlatform;
  78 
  79     Dialog modalBlocker;
  80     boolean delayedModalBlocking = false;
  81     Dimension targetMinimumSize = null;
  82 
  83     private XWindowPeer ownerPeer;
  84 
  85     // used for modal blocking to keep existing z-order
  86     protected XWindowPeer prevTransientFor, nextTransientFor;
  87     // value of WM_TRANSIENT_FOR hint set on this window
  88     private XWindowPeer curRealTransientFor;
  89 
  90     private boolean grab = false; // Whether to do a grab during showing
  91 
  92     private boolean isMapped = false; // Is this window mapped or not
  93     private boolean mustControlStackPosition = false; // Am override-redirect not on top
  94     private XEventDispatcher rootPropertyEventDispatcher = null;
  95 
  96     private static final AtomicBoolean isStartupNotificationRemoved = new AtomicBoolean();
  97 
  98     /*
  99      * Focus related flags
 100      */
 101     private boolean isUnhiding = false;             // Is the window unhiding.
 102     private boolean isBeforeFirstMapNotify = false; // Is the window (being shown) between
 103                                                     //    setVisible(true) & handleMapNotify().
 104 
 105     /**
 106      * The type of the window.
 107      *
 108      * The type is supposed to be immutable while the peer object exists.
 109      * The value gets initialized in the preInit() method.
 110      */
 111     private Window.Type windowType = Window.Type.NORMAL;
 112 
 113     public final Window.Type getWindowType() {
 114         return windowType;
 115     }
 116 
 117     // It need to be accessed from XFramePeer.
 118     protected Vector <ToplevelStateListener> toplevelStateListeners = new Vector<ToplevelStateListener>();
 119     XWindowPeer(XCreateWindowParams params) {
 120         super(params.putIfNull(PARENT_WINDOW, Long.valueOf(0)));
 121     }
 122 
 123     XWindowPeer(Window target) {
 124         super(new XCreateWindowParams(new Object[] {
 125             TARGET, target,
 126             PARENT_WINDOW, Long.valueOf(0)}));
 127     }
 128 
 129     /*
 130      * This constant defines icon size recommended for using.
 131      * Apparently, we should use XGetIconSizes which should
 132      * return icon sizes would be most appreciated by the WM.
 133      * However, XGetIconSizes always returns 0 for some reason.
 134      * So the constant has been introduced.
 135      */
 136     private static final int PREFERRED_SIZE_FOR_ICON = 128;
 137 
 138     /*
 139      * Sometimes XChangeProperty(_NET_WM_ICON) doesn't work if
 140      * image buffer is too large. This constant holds maximum
 141      * length of buffer which can be used with _NET_WM_ICON hint.
 142      * It holds int's value.
 143      */
 144     private static final int MAXIMUM_BUFFER_LENGTH_NET_WM_ICON = (2<<15) - 1;
 145 
 146     void preInit(XCreateWindowParams params) {
 147         target = (Component)params.get(TARGET);
 148         windowType = ((Window)target).getType();
 149         params.put(REPARENTED,
 150                    Boolean.valueOf(isOverrideRedirect() || isSimpleWindow()));
 151         super.preInit(params);
 152         params.putIfNull(BIT_GRAVITY, Integer.valueOf(XConstants.NorthWestGravity));
 153 
 154         long eventMask = 0;
 155         if (params.containsKey(EVENT_MASK)) {
 156             eventMask = ((Long)params.get(EVENT_MASK));
 157         }
 158         eventMask |= XConstants.VisibilityChangeMask;
 159         params.put(EVENT_MASK, eventMask);
 160 
 161         XA_NET_WM_STATE = XAtom.get("_NET_WM_STATE");
 162 
 163 
 164         params.put(OVERRIDE_REDIRECT, Boolean.valueOf(isOverrideRedirect()));
 165 
 166         SunToolkit.awtLock();
 167         try {
 168             windows.add(this);
 169         } finally {
 170             SunToolkit.awtUnlock();
 171         }
 172 
 173         cachedFocusableWindow = isFocusableWindow();
 174 
 175         Font f = target.getFont();
 176         if (f == null) {
 177             f = XWindow.getDefaultFont();
 178             target.setFont(f);
 179             // we should not call setFont because it will call a repaint
 180             // which the peer may not be ready to do yet.
 181         }
 182         Color c = target.getBackground();
 183         if (c == null) {
 184             Color background = SystemColor.window;
 185             target.setBackground(background);
 186             // we should not call setBackGround because it will call a repaint
 187             // which the peer may not be ready to do yet.
 188         }
 189         c = target.getForeground();
 190         if (c == null) {
 191             target.setForeground(SystemColor.windowText);
 192             // we should not call setForeGround because it will call a repaint
 193             // which the peer may not be ready to do yet.
 194         }
 195 
 196         alwaysOnTop = ((Window)target).isAlwaysOnTop() && ((Window)target).isAlwaysOnTopSupported();
 197 
 198         GraphicsConfiguration gc = getGraphicsConfiguration();
 199         ((X11GraphicsDevice)gc.getDevice()).addDisplayChangedListener(this);
 200     }
 201 
 202     protected String getWMName() {
 203         String name = target.getName();
 204         if (name == null || name.trim().equals("")) {
 205             name = " ";
 206         }
 207         return name;
 208     }
 209 
 210     private static native String getLocalHostname();
 211     private static native int getJvmPID();
 212 
 213     void postInit(XCreateWindowParams params) {
 214         super.postInit(params);
 215 
 216         // Init WM_PROTOCOLS atom
 217         initWMProtocols();
 218 
 219         // Set _NET_WM_PID and WM_CLIENT_MACHINE using this JVM
 220         XAtom.get("WM_CLIENT_MACHINE").setProperty(getWindow(), getLocalHostname());
 221         XAtom.get("_NET_WM_PID").setCard32Property(getWindow(), getJvmPID());
 222 
 223         // Set WM_TRANSIENT_FOR and group_leader
 224         Window t_window = (Window)target;
 225         Window owner = t_window.getOwner();
 226         if (owner != null) {
 227             ownerPeer = (XWindowPeer)owner.getPeer();
 228             if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
 229                 focusLog.finer("Owner is " + owner);
 230                 focusLog.finer("Owner peer is " + ownerPeer);
 231                 focusLog.finer("Owner X window " + Long.toHexString(ownerPeer.getWindow()));
 232                 focusLog.finer("Owner content X window " + Long.toHexString(ownerPeer.getContentWindow()));
 233             }
 234             // as owner window may be an embedded window, we must get a toplevel window
 235             // to set as TRANSIENT_FOR hint
 236             long ownerWindow = ownerPeer.getWindow();
 237             if (ownerWindow != 0) {
 238                 XToolkit.awtLock();
 239                 try {
 240                     // Set WM_TRANSIENT_FOR
 241                     if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
 242                         focusLog.fine("Setting transient on " + Long.toHexString(getWindow())
 243                                       + " for " + Long.toHexString(ownerWindow));
 244                     }
 245                     setToplevelTransientFor(this, ownerPeer, false, true);
 246 
 247                     // Set group leader
 248                     XWMHints hints = getWMHints();
 249                     hints.set_flags(hints.get_flags() | (int)XUtilConstants.WindowGroupHint);
 250                     hints.set_window_group(ownerWindow);
 251                     XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData);
 252                 }
 253                 finally {
 254                     XToolkit.awtUnlock();
 255                 }
 256             }
 257         }
 258 
 259         if (owner != null || isSimpleWindow()) {
 260             XNETProtocol protocol = XWM.getWM().getNETProtocol();
 261             if (protocol != null && protocol.active()) {
 262                 XToolkit.awtLock();
 263                 try {
 264                     XAtomList net_wm_state = getNETWMState();
 265                     net_wm_state.add(protocol.XA_NET_WM_STATE_SKIP_TASKBAR);
 266                     setNETWMState(net_wm_state);
 267                 } finally {
 268                     XToolkit.awtUnlock();
 269                 }
 270 
 271             }
 272         }
 273 
 274          // Init warning window(for applets)
 275         if (((Window)target).getWarningString() != null) {
 276             // accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip
 277             // and TrayIcon balloon windows without a warning window.
 278             if (!AWTAccessor.getWindowAccessor().isTrayIconWindow((Window)target)) {
 279                 warningWindow = new XWarningWindow((Window)target, getWindow(), this);
 280             }
 281         }
 282 
 283         setSaveUnder(true);
 284 
 285         updateIconImages();
 286 
 287         updateShape();
 288         updateOpacity();
 289         // no need in updateOpaque() as it is no-op
 290     }
 291 
 292     public void updateIconImages() {
 293         Window target = (Window)this.target;
 294         java.util.List<Image> iconImages = ((Window)target).getIconImages();
 295         XWindowPeer ownerPeer = getOwnerPeer();
 296         winAttr.icons = new ArrayList<IconInfo>();
 297         if (iconImages.size() != 0) {
 298             //read icon images from target
 299             winAttr.iconsInherited = false;
 300             for (Iterator<Image> i = iconImages.iterator(); i.hasNext(); ) {
 301                 Image image = i.next();
 302                 if (image == null) {
 303                     if (log.isLoggable(PlatformLogger.Level.FINEST)) {
 304                         log.finest("XWindowPeer.updateIconImages: Skipping the image passed into Java because it's null.");
 305                     }
 306                     continue;
 307                 }
 308                 IconInfo iconInfo;
 309                 try {
 310                     iconInfo = new IconInfo(image);
 311                 } catch (Exception e){
 312                     if (log.isLoggable(PlatformLogger.Level.FINEST)) {
 313                         log.finest("XWindowPeer.updateIconImages: Perhaps the image passed into Java is broken. Skipping this icon.");
 314                     }
 315                     continue;
 316                 }
 317                 if (iconInfo.isValid()) {
 318                     winAttr.icons.add(iconInfo);
 319                 }
 320             }
 321         }
 322 
 323         // Fix for CR#6425089
 324         winAttr.icons = normalizeIconImages(winAttr.icons);
 325 
 326         if (winAttr.icons.size() == 0) {
 327             //target.icons is empty or all icon images are broken
 328             if (ownerPeer != null) {
 329                 //icon is inherited from parent
 330                 winAttr.iconsInherited = true;
 331                 winAttr.icons = ownerPeer.getIconInfo();
 332             } else {
 333                 //default icon is used
 334                 winAttr.iconsInherited = false;
 335                 winAttr.icons = getDefaultIconInfo();
 336             }
 337         }
 338         recursivelySetIcon(winAttr.icons);
 339     }
 340 
 341     /*
 342      * Sometimes XChangeProperty(_NET_WM_ICON) doesn't work if
 343      * image buffer is too large. This function help us accommodate
 344      * initial list of the icon images to certainly-acceptable.
 345      * It does scale some of these icons to appropriate size
 346      * if it's necessary.
 347      */
 348     static java.util.List<IconInfo> normalizeIconImages(java.util.List<IconInfo> icons) {
 349         java.util.List<IconInfo> result = new ArrayList<IconInfo>();
 350         int totalLength = 0;
 351         boolean haveLargeIcon = false;
 352 
 353         for (IconInfo icon : icons) {
 354             int width = icon.getWidth();
 355             int height = icon.getHeight();
 356             int length = icon.getRawLength();
 357 
 358             if (width > PREFERRED_SIZE_FOR_ICON || height > PREFERRED_SIZE_FOR_ICON) {
 359                 if (haveLargeIcon) {
 360                     continue;
 361                 }
 362                 int scaledWidth = width;
 363                 int scaledHeight = height;
 364                 while (scaledWidth > PREFERRED_SIZE_FOR_ICON ||
 365                        scaledHeight > PREFERRED_SIZE_FOR_ICON) {
 366                     scaledWidth = scaledWidth / 2;
 367                     scaledHeight = scaledHeight / 2;
 368                 }
 369 
 370                 icon.setScaledSize(scaledWidth, scaledHeight);
 371                 length = icon.getRawLength();
 372             }
 373 
 374             if (totalLength + length <= MAXIMUM_BUFFER_LENGTH_NET_WM_ICON) {
 375                 totalLength += length;
 376                 result.add(icon);
 377                 if (width > PREFERRED_SIZE_FOR_ICON || height > PREFERRED_SIZE_FOR_ICON) {
 378                     haveLargeIcon = true;
 379                 }
 380             }
 381         }
 382 
 383         if (iconLog.isLoggable(PlatformLogger.Level.FINEST)) {
 384             iconLog.finest(">>> Length_ of buffer of icons data: " + totalLength +
 385                            ", maximum length: " + MAXIMUM_BUFFER_LENGTH_NET_WM_ICON);
 386         }
 387 
 388         return result;
 389     }
 390 
 391     /*
 392      * Dumps each icon from the list
 393      */
 394     static void dumpIcons(java.util.List<IconInfo> icons) {
 395         if (iconLog.isLoggable(PlatformLogger.Level.FINEST)) {
 396             iconLog.finest(">>> Sizes of icon images:");
 397             for (Iterator<IconInfo> i = icons.iterator(); i.hasNext(); ) {
 398                 iconLog.finest("    {0}", i.next());
 399             }
 400         }
 401     }
 402 
 403     public void recursivelySetIcon(java.util.List<IconInfo> icons) {
 404         dumpIcons(winAttr.icons);
 405         setIconHints(icons);
 406         Window target = (Window)this.target;
 407         Window[] children = target.getOwnedWindows();
 408         int cnt = children.length;
 409         for (int i = 0; i < cnt; i++) {
 410             ComponentPeer childPeer = children[i].getPeer();
 411             if (childPeer != null && childPeer instanceof XWindowPeer) {
 412                 if (((XWindowPeer)childPeer).winAttr.iconsInherited) {
 413                     ((XWindowPeer)childPeer).winAttr.icons = icons;
 414                     ((XWindowPeer)childPeer).recursivelySetIcon(icons);
 415                 }
 416             }
 417         }
 418     }
 419 
 420     java.util.List<IconInfo> getIconInfo() {
 421         return winAttr.icons;
 422     }
 423     void setIconHints(java.util.List<IconInfo> icons) {
 424         //This does nothing for XWindowPeer,
 425         //It's overriden in XDecoratedPeer
 426     }
 427 
 428     private static ArrayList<IconInfo> defaultIconInfo;
 429     protected synchronized static java.util.List<IconInfo> getDefaultIconInfo() {
 430         if (defaultIconInfo == null) {
 431             defaultIconInfo = new ArrayList<IconInfo>();
 432             if (XlibWrapper.dataModel == 32) {
 433                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon16_png.java_icon16_png));
 434                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon24_png.java_icon24_png));
 435                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon32_png.java_icon32_png));
 436                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon48_png.java_icon48_png));
 437             } else {
 438                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon16_png.java_icon16_png));
 439                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon24_png.java_icon24_png));
 440                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon32_png.java_icon32_png));
 441                 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon48_png.java_icon48_png));
 442             }
 443         }
 444         return defaultIconInfo;
 445     }
 446 
 447     private void updateShape() {
 448         // Shape shape = ((Window)target).getShape();
 449         Shape shape = AWTAccessor.getWindowAccessor().getShape((Window)target);
 450         if (shape != null) {
 451             applyShape(Region.getInstance(shape, null));
 452         }
 453     }
 454 
 455     private void updateOpacity() {
 456         // float opacity = ((Window)target).getOpacity();
 457         float opacity = AWTAccessor.getWindowAccessor().getOpacity((Window)target);
 458         if (opacity < 1.0f) {
 459             setOpacity(opacity);
 460         }
 461     }
 462 
 463     public void updateMinimumSize() {
 464         //This function only saves minimumSize value in XWindowPeer
 465         //Setting WMSizeHints is implemented in XDecoratedPeer
 466         targetMinimumSize = (((Component)target).isMinimumSizeSet()) ?
 467             ((Component)target).getMinimumSize() : null;
 468     }
 469 
 470     public Dimension getTargetMinimumSize() {
 471         return (targetMinimumSize == null) ? null : new Dimension(targetMinimumSize);
 472     }
 473 
 474     public XWindowPeer getOwnerPeer() {
 475         return ownerPeer;
 476     }
 477 
 478     //Fix for 6318144: PIT:Setting Min Size bigger than current size enlarges
 479     //the window but fails to revalidate, Sol-CDE
 480     //This bug is regression for
 481     //5025858: Resizing a decorated frame triggers componentResized event twice.
 482     //Since events are not posted from Component.setBounds we need to send them here.
 483     //Note that this function is overriden in XDecoratedPeer so event
 484     //posting is not changing for decorated peers
 485     public void setBounds(int x, int y, int width, int height, int op) {
 486         XToolkit.awtLock();
 487         try {
 488             Rectangle oldBounds = getBounds();
 489 
 490             super.setBounds(x, y, width, height, op);
 491 
 492             Rectangle bounds = getBounds();
 493 
 494             XSizeHints hints = getHints();
 495             setSizeHints(hints.get_flags() | XUtilConstants.PPosition | XUtilConstants.PSize,
 496                              bounds.x, bounds.y, bounds.width, bounds.height);
 497             XWM.setMotifDecor(this, false, 0, 0);
 498 
 499             boolean isResized = !bounds.getSize().equals(oldBounds.getSize());
 500             boolean isMoved = !bounds.getLocation().equals(oldBounds.getLocation());
 501             if (isMoved || isResized) {
 502                 repositionSecurityWarning();
 503             }
 504             if (isResized) {
 505                 postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_RESIZED));
 506             }
 507             if (isMoved) {
 508                 postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_MOVED));
 509             }
 510         } finally {
 511             XToolkit.awtUnlock();
 512         }
 513     }
 514 
 515     void updateFocusability() {
 516         updateFocusableWindowState();
 517         XToolkit.awtLock();
 518         try {
 519             XWMHints hints = getWMHints();
 520             hints.set_flags(hints.get_flags() | (int)XUtilConstants.InputHint);
 521             hints.set_input(false/*isNativelyNonFocusableWindow() ? (0):(1)*/);
 522             XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData);
 523         }
 524         finally {
 525             XToolkit.awtUnlock();
 526         }
 527     }
 528 
 529     public Insets getInsets() {
 530         return new Insets(0, 0, 0, 0);
 531     }
 532 
 533     // NOTE: This method may be called by privileged threads.
 534     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 535     public void handleIconify() {
 536         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED));
 537     }
 538 
 539     // NOTE: This method may be called by privileged threads.
 540     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 541     public void handleDeiconify() {
 542         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED));
 543     }
 544 
 545     // NOTE: This method may be called by privileged threads.
 546     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 547     public void handleStateChange(int oldState, int newState) {
 548         postEvent(new WindowEvent((Window)target,
 549                                   WindowEvent.WINDOW_STATE_CHANGED,
 550                                   oldState, newState));
 551     }
 552 
 553     /**
 554      * DEPRECATED:  Replaced by getInsets().
 555      */
 556     public Insets insets() {
 557         return getInsets();
 558     }
 559 
 560     boolean isAutoRequestFocus() {
 561         if (XToolkit.isToolkitThread()) {
 562             return AWTAccessor.getWindowAccessor().isAutoRequestFocus((Window)target);
 563         } else {
 564             return ((Window)target).isAutoRequestFocus();
 565         }
 566     }
 567 
 568     /*
 569      * Retrives real native focused window and converts it into Java peer.
 570      */
 571     static XWindowPeer getNativeFocusedWindowPeer() {
 572         XBaseWindow baseWindow = XToolkit.windowToXWindow(xGetInputFocus());
 573         return (baseWindow instanceof XWindowPeer) ? (XWindowPeer)baseWindow :
 574                (baseWindow instanceof XFocusProxyWindow) ?
 575                ((XFocusProxyWindow)baseWindow).getOwner() : null;
 576     }
 577 
 578     /*
 579      * Retrives real native focused window and converts it into Java window.
 580      */
 581     static Window getNativeFocusedWindow() {
 582         XWindowPeer peer = getNativeFocusedWindowPeer();
 583         return peer != null ? (Window)peer.target : null;
 584     }
 585 
 586     boolean isFocusableWindow() {
 587         if (XToolkit.isToolkitThread() || SunToolkit.isAWTLockHeldByCurrentThread())
 588         {
 589             return cachedFocusableWindow;
 590         } else {
 591             return ((Window)target).isFocusableWindow();
 592         }
 593     }
 594 
 595     /* WARNING: don't call client code in this method! */
 596     boolean isFocusedWindowModalBlocker() {
 597         return false;
 598     }
 599 
 600     long getFocusTargetWindow() {
 601         return getContentWindow();
 602     }
 603 
 604     /**
 605      * Returns whether or not this window peer has native X window
 606      * configured as non-focusable window. It might happen if:
 607      * - Java window is non-focusable
 608      * - Java window is simple Window(not Frame or Dialog)
 609      */
 610     boolean isNativelyNonFocusableWindow() {
 611         if (XToolkit.isToolkitThread() || SunToolkit.isAWTLockHeldByCurrentThread())
 612         {
 613             return isSimpleWindow() || !cachedFocusableWindow;
 614         } else {
 615             return isSimpleWindow() || !(((Window)target).isFocusableWindow());
 616         }
 617     }
 618 
 619     public void handleWindowFocusIn_Dispatch() {
 620         if (EventQueue.isDispatchThread()) {
 621             XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow((Window) target);
 622             WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS);
 623             SunToolkit.setSystemGenerated(we);
 624             target.dispatchEvent(we);
 625         }
 626     }
 627 
 628     public void handleWindowFocusInSync(long serial) {
 629         WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS);
 630         XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow((Window) target);
 631         sendEvent(we);
 632     }
 633     // NOTE: This method may be called by privileged threads.
 634     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 635     public void handleWindowFocusIn(long serial) {
 636         WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS);
 637         /* wrap in Sequenced, then post*/
 638         XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow((Window) target);
 639         postEvent(wrapInSequenced((AWTEvent) we));
 640     }
 641 
 642     // NOTE: This method may be called by privileged threads.
 643     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 644     public void handleWindowFocusOut(Window oppositeWindow, long serial) {
 645         WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_LOST_FOCUS, oppositeWindow);
 646         XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null);
 647         XKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
 648         /* wrap in Sequenced, then post*/
 649         postEvent(wrapInSequenced((AWTEvent) we));
 650     }
 651     public void handleWindowFocusOutSync(Window oppositeWindow, long serial) {
 652         WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_LOST_FOCUS, oppositeWindow);
 653         XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null);
 654         XKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null);
 655         sendEvent(we);
 656     }
 657 
 658 /* --- DisplayChangedListener Stuff --- */
 659 
 660     /* Xinerama
 661      * called to check if we've been moved onto a different screen
 662      * Based on checkNewXineramaScreen() in awt_GraphicsEnv.c
 663      */
 664     public void checkIfOnNewScreen(Rectangle newBounds) {
 665         if (!XToolkit.localEnv.runningXinerama()) {
 666             return;
 667         }
 668 
 669         if (log.isLoggable(PlatformLogger.Level.FINEST)) {
 670             log.finest("XWindowPeer: Check if we've been moved to a new screen since we're running in Xinerama mode");
 671         }
 672 
 673         int area = newBounds.width * newBounds.height;
 674         int intAmt, vertAmt, horizAmt;
 675         int largestAmt = 0;
 676         int curScreenNum = ((X11GraphicsDevice)getGraphicsConfiguration().getDevice()).getScreen();
 677         int newScreenNum = 0;
 678         GraphicsDevice gds[] = XToolkit.localEnv.getScreenDevices();
 679         GraphicsConfiguration newGC = null;
 680         Rectangle screenBounds;
 681 
 682         for (int i = 0; i < gds.length; i++) {
 683             screenBounds = gds[i].getDefaultConfiguration().getBounds();
 684             if (newBounds.intersects(screenBounds)) {
 685                 horizAmt = Math.min(newBounds.x + newBounds.width,
 686                                     screenBounds.x + screenBounds.width) -
 687                            Math.max(newBounds.x, screenBounds.x);
 688                 vertAmt = Math.min(newBounds.y + newBounds.height,
 689                                    screenBounds.y + screenBounds.height)-
 690                           Math.max(newBounds.y, screenBounds.y);
 691                 intAmt = horizAmt * vertAmt;
 692                 if (intAmt == area) {
 693                     // Completely on this screen - done!
 694                     newScreenNum = i;
 695                     newGC = gds[i].getDefaultConfiguration();
 696                     break;
 697                 }
 698                 if (intAmt > largestAmt) {
 699                     largestAmt = intAmt;
 700                     newScreenNum = i;
 701                     newGC = gds[i].getDefaultConfiguration();
 702                 }
 703             }
 704         }
 705         if (newScreenNum != curScreenNum) {
 706             if (log.isLoggable(PlatformLogger.Level.FINEST)) {
 707                 log.finest("XWindowPeer: Moved to a new screen");
 708             }
 709             executeDisplayChangedOnEDT(newGC);
 710         }
 711     }
 712 
 713     /**
 714      * Helper method that executes the displayChanged(screen) method on
 715      * the event dispatch thread.  This method is used in the Xinerama case
 716      * and after display mode change events.
 717      */
 718     private void executeDisplayChangedOnEDT(final GraphicsConfiguration gc) {
 719         Runnable dc = new Runnable() {
 720             public void run() {
 721                 AWTAccessor.getComponentAccessor().
 722                     setGraphicsConfiguration((Component)target, gc);
 723             }
 724         };
 725         SunToolkit.executeOnEventHandlerThread((Component)target, dc);
 726     }
 727 
 728     /**
 729      * From the DisplayChangedListener interface; called from
 730      * X11GraphicsDevice when the display mode has been changed.
 731      */
 732     public void displayChanged() {
 733         executeDisplayChangedOnEDT(getGraphicsConfiguration());
 734     }
 735 
 736     /**
 737      * From the DisplayChangedListener interface; top-levels do not need
 738      * to react to this event.
 739      */
 740     public void paletteChanged() {
 741     }
 742 
 743     private Point queryXLocation()
 744     {
 745         return XlibUtil.translateCoordinates(
 746             getContentWindow(),
 747             XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()),
 748             new Point(0, 0));
 749     }
 750 
 751     protected Point getNewLocation(XConfigureEvent xe, int leftInset, int topInset) {
 752         // Bounds of the window
 753         Rectangle targetBounds = AWTAccessor.getComponentAccessor().getBounds((Component)target);
 754 
 755         int runningWM = XWM.getWMID();
 756         Point newLocation = targetBounds.getLocation();
 757         if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) {
 758             // Location, Client size + insets
 759             newLocation = new Point(xe.get_x() - leftInset, xe.get_y() - topInset);
 760         } else {
 761             // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when
 762             // a window is resized but the client can not tell if the window was
 763             // moved or not. The client should consider the position as unkown
 764             // and use TranslateCoordinates to find the actual position.
 765             //
 766             // TODO this should be the default for every case.
 767             switch (runningWM) {
 768                 case XWM.CDE_WM:
 769                 case XWM.MOTIF_WM:
 770                 case XWM.METACITY_WM:
 771                 case XWM.MUTTER_WM:
 772                 case XWM.SAWFISH_WM:
 773                 {
 774                     Point xlocation = queryXLocation();
 775                     if (log.isLoggable(PlatformLogger.Level.FINE)) {
 776                         log.fine("New X location: {0}", xlocation);
 777                     }
 778                     if (xlocation != null) {
 779                         newLocation = xlocation;
 780                     }
 781                     break;
 782                 }
 783                 default:
 784                     break;
 785             }
 786         }
 787         return newLocation;
 788     }
 789 
 790     /*
 791      * Overridden to check if we need to update our GraphicsDevice/Config
 792      * Added for 4934052.
 793      */
 794     @Override
 795     public void handleConfigureNotifyEvent(XEvent xev) {
 796         XConfigureEvent xe = xev.get_xconfigure();
 797         /*
 798          * Correct window location which could be wrong in some cases.
 799          * See getNewLocation() for the details.
 800          */
 801         Point newLocation = getNewLocation(xe, 0, 0);
 802         xe.set_x(newLocation.x);
 803         xe.set_y(newLocation.y);
 804         checkIfOnNewScreen(new Rectangle(xe.get_x(),
 805                                          xe.get_y(),
 806                                          xe.get_width(),
 807                                          xe.get_height()));
 808 
 809         // Don't call super until we've handled a screen change.  Otherwise
 810         // there could be a race condition in which a ComponentListener could
 811         // see the old screen.
 812         super.handleConfigureNotifyEvent(xev);
 813         repositionSecurityWarning();
 814     }
 815 
 816     final void requestXFocus(long time) {
 817         requestXFocus(time, true);
 818     }
 819 
 820     final void requestXFocus() {
 821         requestXFocus(0, false);
 822     }
 823 
 824     /**
 825      * Requests focus to this top-level. Descendants should override to provide
 826      * implementations based on a class of top-level.
 827      */
 828     protected void requestXFocus(long time, boolean timeProvided) {
 829         // Since in XAWT focus is synthetic and all basic Windows are
 830         // override_redirect all we can do is check whether our parent
 831         // is active. If it is - we can freely synthesize focus transfer.
 832         // Luckily, this logic is already implemented in requestWindowFocus.
 833         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
 834             focusLog.fine("Requesting window focus");
 835         }
 836         requestWindowFocus(time, timeProvided);
 837     }
 838 
 839     public final boolean focusAllowedFor() {
 840         if (isNativelyNonFocusableWindow()) {
 841             return false;
 842         }
 843 /*
 844         Window target = (Window)this.target;
 845         if (!target.isVisible() ||
 846             !target.isEnabled() ||
 847             !target.isFocusable())
 848         {
 849             return false;
 850         }
 851 */
 852         if (isModalBlocked()) {
 853             return false;
 854         }
 855         return true;
 856     }
 857 
 858     public void handleFocusEvent(XEvent xev) {
 859         XFocusChangeEvent xfe = xev.get_xfocus();
 860         FocusEvent fe;
 861         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
 862             focusLog.fine("{0}", xfe);
 863         }
 864         if (isEventDisabled(xev)) {
 865             return;
 866         }
 867         if (xev.get_type() == XConstants.FocusIn)
 868         {
 869             // If this window is non-focusable don't post any java focus event
 870             if (focusAllowedFor()) {
 871                 if (xfe.get_mode() == XConstants.NotifyNormal // Normal notify
 872                     || xfe.get_mode() == XConstants.NotifyWhileGrabbed) // Alt-Tab notify
 873                 {
 874                     handleWindowFocusIn(xfe.get_serial());
 875                 }
 876             }
 877         }
 878         else
 879         {
 880             if (xfe.get_mode() == XConstants.NotifyNormal // Normal notify
 881                 || xfe.get_mode() == XConstants.NotifyWhileGrabbed) // Alt-Tab notify
 882             {
 883                 // If this window is non-focusable don't post any java focus event
 884                 if (!isNativelyNonFocusableWindow()) {
 885                     XWindowPeer oppositeXWindow = getNativeFocusedWindowPeer();
 886                     Object oppositeTarget = (oppositeXWindow!=null)? oppositeXWindow.getTarget() : null;
 887                     Window oppositeWindow = null;
 888                     if (oppositeTarget instanceof Window) {
 889                         oppositeWindow = (Window) oppositeTarget;
 890                     }
 891                     // Check if opposite window is non-focusable. In that case we don't want to
 892                     // post any event.
 893                     if (oppositeXWindow != null && oppositeXWindow.isNativelyNonFocusableWindow()) {
 894                         return;
 895                     }
 896                     if (this == oppositeXWindow) {
 897                         oppositeWindow = null;
 898                     } else if (oppositeXWindow instanceof XDecoratedPeer) {
 899                         if (((XDecoratedPeer) oppositeXWindow).actualFocusedWindow != null) {
 900                             oppositeXWindow = ((XDecoratedPeer) oppositeXWindow).actualFocusedWindow;
 901                             oppositeTarget = oppositeXWindow.getTarget();
 902                             if (oppositeTarget instanceof Window
 903                                 && oppositeXWindow.isVisible()
 904                                 && oppositeXWindow.isNativelyNonFocusableWindow())
 905                             {
 906                                 oppositeWindow = ((Window) oppositeTarget);
 907                             }
 908                         }
 909                     }
 910                     handleWindowFocusOut(oppositeWindow, xfe.get_serial());
 911                 }
 912             }
 913         }
 914     }
 915 
 916     void setSaveUnder(boolean state) {}
 917 
 918     public void toFront() {
 919         if (isOverrideRedirect() && mustControlStackPosition) {
 920             mustControlStackPosition = false;
 921             removeRootPropertyEventDispatcher();
 922         }
 923         if (isVisible()) {
 924             super.toFront();
 925             if (isFocusableWindow() && isAutoRequestFocus() &&
 926                 !isModalBlocked() && !isWithdrawn())
 927             {
 928                 requestInitialFocus();
 929             }
 930         } else {
 931             setVisible(true);
 932         }
 933     }
 934 
 935     public void toBack() {
 936         XToolkit.awtLock();
 937         try {
 938             if(!isOverrideRedirect()) {
 939                 XlibWrapper.XLowerWindow(XToolkit.getDisplay(), getWindow());
 940             }else{
 941                 lowerOverrideRedirect();
 942             }
 943         }
 944         finally {
 945             XToolkit.awtUnlock();
 946         }
 947     }
 948     private void lowerOverrideRedirect() {
 949         //
 950         // make new hash of toplevels of all windows from 'windows' hash.
 951         // FIXME: do not call them "toplevel" as it is misleading.
 952         //
 953         HashSet toplevels = new HashSet();
 954         long topl = 0, mytopl = 0;
 955 
 956         for (XWindowPeer xp : windows) {
 957             topl = getToplevelWindow( xp.getWindow() );
 958             if( xp.equals( this ) ) {
 959                 mytopl = topl;
 960             }
 961             if( topl > 0 )
 962                 toplevels.add( Long.valueOf( topl ) );
 963         }
 964 
 965         //
 966         // find in the root's tree:
 967         // (1) my toplevel, (2) lowest java toplevel, (3) desktop
 968         // We must enforce (3), (1), (2) order, upward;
 969         // note that nautilus on the next restacking will do (1),(3),(2).
 970         //
 971         long laux,     wDesktop = -1, wBottom = -1;
 972         int  iMy = -1, iDesktop = -1, iBottom = -1;
 973         int i = 0;
 974         XQueryTree xqt = new XQueryTree(XToolkit.getDefaultRootWindow());
 975         try {
 976             if( xqt.execute() > 0 ) {
 977                 int nchildren = xqt.get_nchildren();
 978                 long children = xqt.get_children();
 979                 for(i = 0; i < nchildren; i++) {
 980                     laux = Native.getWindow(children, i);
 981                     if( laux == mytopl ) {
 982                         iMy = i;
 983                     }else if( isDesktopWindow( laux ) ) {
 984                         // we need topmost desktop of them all.
 985                         iDesktop = i;
 986                         wDesktop = laux;
 987                     }else if(iBottom < 0 &&
 988                              toplevels.contains( Long.valueOf(laux) ) &&
 989                              laux != mytopl) {
 990                         iBottom = i;
 991                         wBottom = laux;
 992                     }
 993                 }
 994             }
 995 
 996             if( (iMy < iBottom || iBottom < 0 )&& iDesktop < iMy)
 997                 return; // no action necessary
 998 
 999             long to_restack = Native.allocateLongArray(2);
1000             Native.putLong(to_restack, 0, wBottom);
1001             Native.putLong(to_restack, 1,  mytopl);
1002             XlibWrapper.XRestackWindows(XToolkit.getDisplay(), to_restack, 2);
1003             XlibWrapper.unsafe.freeMemory(to_restack);
1004 
1005 
1006             if( !mustControlStackPosition ) {
1007                 mustControlStackPosition = true;
1008                 // add root window property listener:
1009                 // somebody (eg nautilus desktop) may obscure us
1010                 addRootPropertyEventDispatcher();
1011             }
1012         } finally {
1013             xqt.dispose();
1014         }
1015     }
1016     /**
1017         Get XID of closest to root window in a given window hierarchy.
1018         FIXME: do not call it "toplevel" as it is misleading.
1019         On error return 0.
1020     */
1021     private long getToplevelWindow( long w ) {
1022         long wi = w, ret, root;
1023         do {
1024             ret = wi;
1025             XQueryTree qt = new XQueryTree(wi);
1026             try {
1027                 if (qt.execute() == 0) {
1028                     return 0;
1029                 }
1030                 root = qt.get_root();
1031                 wi = qt.get_parent();
1032             } finally {
1033                 qt.dispose();
1034             }
1035 
1036         } while (wi != root);
1037 
1038         return ret;
1039     }
1040 
1041     private static boolean isDesktopWindow( long wi ) {
1042         return XWM.getWM().isDesktopWindow( wi );
1043     }
1044 
1045     private void updateAlwaysOnTop() {
1046         if (log.isLoggable(PlatformLogger.Level.FINE)) {
1047             log.fine("Promoting always-on-top state {0}", Boolean.valueOf(alwaysOnTop));
1048         }
1049         XWM.getWM().setLayer(this,
1050                              alwaysOnTop ?
1051                              XLayerProtocol.LAYER_ALWAYS_ON_TOP :
1052                              XLayerProtocol.LAYER_NORMAL);
1053     }
1054 
1055     public void updateAlwaysOnTopState() {
1056         this.alwaysOnTop = ((Window) this.target).isAlwaysOnTop();
1057         updateAlwaysOnTop();
1058     }
1059 
1060     boolean isLocationByPlatform() {
1061         return locationByPlatform;
1062     }
1063 
1064     private void promoteDefaultPosition() {
1065         this.locationByPlatform = ((Window)target).isLocationByPlatform();
1066         if (locationByPlatform) {
1067             XToolkit.awtLock();
1068             try {
1069                 Rectangle bounds = getBounds();
1070                 XSizeHints hints = getHints();
1071                 setSizeHints(hints.get_flags() & ~(XUtilConstants.USPosition | XUtilConstants.PPosition),
1072                              bounds.x, bounds.y, bounds.width, bounds.height);
1073             } finally {
1074                 XToolkit.awtUnlock();
1075             }
1076         }
1077     }
1078 
1079     public void setVisible(boolean vis) {
1080         if (!isVisible() && vis) {
1081             isBeforeFirstMapNotify = true;
1082             winAttr.initialFocus = isAutoRequestFocus();
1083             if (!winAttr.initialFocus) {
1084                 /*
1085                  * It's easier and safer to temporary suppress WM_TAKE_FOCUS
1086                  * protocol itself than to ignore WM_TAKE_FOCUS client message.
1087                  * Because we will have to make the difference between
1088                  * the message come after showing and the message come after
1089                  * activation. Also, on Metacity, for some reason, we have _two_
1090                  * WM_TAKE_FOCUS client messages when showing a frame/dialog.
1091                  */
1092                 suppressWmTakeFocus(true);
1093             }
1094         }
1095         updateFocusability();
1096         promoteDefaultPosition();
1097         if (!vis && warningWindow != null) {
1098             warningWindow.setSecurityWarningVisible(false, false);
1099         }
1100         super.setVisible(vis);
1101         if (!vis && !isWithdrawn()) {
1102             // ICCCM, 4.1.4. Changing Window State:
1103             // "Iconic -> Withdrawn - The client should unmap the window and follow it
1104             // with a synthetic UnmapNotify event as described later in this section."
1105             // The same is true for Normal -> Withdrawn
1106             XToolkit.awtLock();
1107             try {
1108                 XUnmapEvent unmap = new XUnmapEvent();
1109                 unmap.set_window(window);
1110                 unmap.set_event(XToolkit.getDefaultRootWindow());
1111                 unmap.set_type((int)XConstants.UnmapNotify);
1112                 unmap.set_from_configure(false);
1113                 XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
1114                         false, XConstants.SubstructureNotifyMask | XConstants.SubstructureRedirectMask,
1115                         unmap.pData);
1116                 unmap.dispose();
1117             }
1118             finally {
1119                 XToolkit.awtUnlock();
1120             }
1121         }
1122         // method called somewhere in parent does not generate configure-notify
1123         // event for override-redirect.
1124         // Ergo, no reshape and bugs like 5085647 in case setBounds was
1125         // called before setVisible.
1126         if (isOverrideRedirect() && vis) {
1127             updateChildrenSizes();
1128         }
1129         repositionSecurityWarning();
1130     }
1131 
1132     protected void suppressWmTakeFocus(boolean doSuppress) {
1133     }
1134 
1135     final boolean isSimpleWindow() {
1136         return !(target instanceof Frame || target instanceof Dialog);
1137     }
1138     boolean hasWarningWindow() {
1139         return ((Window)target).getWarningString() != null;
1140     }
1141 
1142     // The height of menu bar window
1143     int getMenuBarHeight() {
1144         return 0;
1145     }
1146 
1147     // Called when shell changes its size and requires children windows
1148     // to update their sizes appropriately
1149     void updateChildrenSizes() {
1150     }
1151 
1152     public void repositionSecurityWarning() {
1153         // NOTE: On KWin if the window/border snapping option is enabled,
1154         // the Java window may be swinging while it's being moved.
1155         // This doesn't make the application unusable though looks quite ugly.
1156         // Probobly we need to find some hint to assign to our Security
1157         // Warning window in order to exclude it from the snapping option.
1158         // We are not currently aware of existance of such a property.
1159         if (warningWindow != null) {
1160             // We can't use the coordinates stored in the XBaseWindow since
1161             // they are zeros for decorated frames.
1162             AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
1163             int x = compAccessor.getX(target);
1164             int y = compAccessor.getY(target);
1165             int width = compAccessor.getWidth(target);
1166             int height = compAccessor.getHeight(target);
1167             warningWindow.reposition(x, y, width, height);
1168         }
1169     }
1170 
1171     @Override
1172     protected void setMouseAbove(boolean above) {
1173         super.setMouseAbove(above);
1174         updateSecurityWarningVisibility();
1175     }
1176 
1177     @Override
1178     public void setFullScreenExclusiveModeState(boolean state) {
1179         super.setFullScreenExclusiveModeState(state);
1180         updateSecurityWarningVisibility();
1181     }
1182 
1183     public void updateSecurityWarningVisibility() {
1184         if (warningWindow == null) {
1185             return;
1186         }
1187 
1188         if (!isVisible()) {
1189             return; // The warning window should already be hidden.
1190         }
1191 
1192         boolean show = false;
1193 
1194         if (!isFullScreenExclusiveMode()) {
1195             int state = getWMState();
1196 
1197             // getWMState() always returns 0 (Withdrawn) for simple windows. Hence
1198             // we ignore the state for such windows.
1199             if (isVisible() && (state == XUtilConstants.NormalState || isSimpleWindow())) {
1200                 if (XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() ==
1201                         getTarget())
1202                 {
1203                     show = true;
1204                 }
1205 
1206                 if (isMouseAbove() || warningWindow.isMouseAbove())
1207                 {
1208                     show = true;
1209                 }
1210             }
1211         }
1212 
1213         warningWindow.setSecurityWarningVisible(show, true);
1214     }
1215 
1216     boolean isOverrideRedirect() {
1217         return XWM.getWMID() == XWM.OPENLOOK_WM ||
1218             Window.Type.POPUP.equals(getWindowType());
1219     }
1220 
1221     final boolean isOLWMDecorBug() {
1222         return XWM.getWMID() == XWM.OPENLOOK_WM &&
1223             winAttr.nativeDecor == false;
1224     }
1225 
1226     public void dispose() {
1227         if (isGrabbed()) {
1228             if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
1229                 grabLog.fine("Generating UngrabEvent on {0} because of the window disposal", this);
1230             }
1231             postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource()));
1232         }
1233 
1234         SunToolkit.awtLock();
1235 
1236         try {
1237             windows.remove(this);
1238         } finally {
1239             SunToolkit.awtUnlock();
1240         }
1241 
1242         if (warningWindow != null) {
1243             warningWindow.destroy();
1244         }
1245 
1246         removeRootPropertyEventDispatcher();
1247         mustControlStackPosition = false;
1248         super.dispose();
1249 
1250         /*
1251          * Fix for 6457980.
1252          * When disposing an owned Window we should implicitly
1253          * return focus to its decorated owner because it won't
1254          * receive WM_TAKE_FOCUS.
1255          */
1256         if (isSimpleWindow()) {
1257             if (target == XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow()) {
1258                 Window owner = getDecoratedOwner((Window)target);
1259                 ((XWindowPeer)AWTAccessor.getComponentAccessor().getPeer(owner)).requestWindowFocus();
1260             }
1261         }
1262     }
1263 
1264     boolean isResizable() {
1265         return winAttr.isResizable;
1266     }
1267 
1268     public void handleVisibilityEvent(XEvent xev) {
1269         super.handleVisibilityEvent(xev);
1270         XVisibilityEvent ve = xev.get_xvisibility();
1271         winAttr.visibilityState = ve.get_state();
1272 //         if (ve.get_state() == XlibWrapper.VisibilityUnobscured) {
1273 //             // raiseInputMethodWindow
1274 //         }
1275         repositionSecurityWarning();
1276     }
1277 
1278     void handleRootPropertyNotify(XEvent xev) {
1279         XPropertyEvent ev = xev.get_xproperty();
1280         if( mustControlStackPosition &&
1281             ev.get_atom() == XAtom.get("_NET_CLIENT_LIST_STACKING").getAtom()){
1282             // Restore stack order unhadled/spoiled by WM or some app (nautilus).
1283             // As of now, don't use any generic machinery: just
1284             // do toBack() again.
1285             if(isOverrideRedirect()) {
1286                 toBack();
1287             }
1288         }
1289     }
1290 
1291     private void removeStartupNotification() {
1292         if (isStartupNotificationRemoved.getAndSet(true)) {
1293             return;
1294         }
1295 
1296         final String desktopStartupId = AccessController.doPrivileged(new PrivilegedAction<String>() {
1297             public String run() {
1298                 return XToolkit.getEnv("DESKTOP_STARTUP_ID");
1299             }
1300         });
1301         if (desktopStartupId == null) {
1302             return;
1303         }
1304 
1305         final StringBuilder messageBuilder = new StringBuilder("remove: ID=");
1306         messageBuilder.append('"');
1307         for (int i = 0; i < desktopStartupId.length(); i++) {
1308             if (desktopStartupId.charAt(i) == '"' || desktopStartupId.charAt(i) == '\\') {
1309                 messageBuilder.append('\\');
1310             }
1311             messageBuilder.append(desktopStartupId.charAt(i));
1312         }
1313         messageBuilder.append('"');
1314         messageBuilder.append('\0');
1315         final byte[] message;
1316         try {
1317             message = messageBuilder.toString().getBytes("UTF-8");
1318         } catch (UnsupportedEncodingException cannotHappen) {
1319             return;
1320         }
1321 
1322         XClientMessageEvent req = null;
1323 
1324         XToolkit.awtLock();
1325         try {
1326             final XAtom netStartupInfoBeginAtom = XAtom.get("_NET_STARTUP_INFO_BEGIN");
1327             final XAtom netStartupInfoAtom = XAtom.get("_NET_STARTUP_INFO");
1328 
1329             req = new XClientMessageEvent();
1330             req.set_type(XConstants.ClientMessage);
1331             req.set_window(getWindow());
1332             req.set_message_type(netStartupInfoBeginAtom.getAtom());
1333             req.set_format(8);
1334 
1335             for (int pos = 0; pos < message.length; pos += 20) {
1336                 final int msglen = Math.min(message.length - pos, 20);
1337                 int i = 0;
1338                 for (; i < msglen; i++) {
1339                     XlibWrapper.unsafe.putByte(req.get_data() + i, message[pos + i]);
1340                 }
1341                 for (; i < 20; i++) {
1342                     XlibWrapper.unsafe.putByte(req.get_data() + i, (byte)0);
1343                 }
1344                 XlibWrapper.XSendEvent(XToolkit.getDisplay(),
1345                     XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()),
1346                     false,
1347                     XConstants.PropertyChangeMask,
1348                     req.pData);
1349                 req.set_message_type(netStartupInfoAtom.getAtom());
1350             }
1351         } finally {
1352             XToolkit.awtUnlock();
1353             if (req != null) {
1354                 req.dispose();
1355             }
1356         }
1357     }
1358 
1359     public void handleMapNotifyEvent(XEvent xev) {
1360         removeStartupNotification();
1361 
1362         // See 6480534.
1363         isUnhiding |= isWMStateNetHidden();
1364 
1365         super.handleMapNotifyEvent(xev);
1366         if (!winAttr.initialFocus) {
1367             suppressWmTakeFocus(false); // restore the protocol.
1368             /*
1369              * For some reason, on Metacity, a frame/dialog being shown
1370              * without WM_TAKE_FOCUS protocol doesn't get moved to the front.
1371              * So, we do it evidently.
1372              */
1373             XToolkit.awtLock();
1374             try {
1375                 XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow());
1376             } finally {
1377                 XToolkit.awtUnlock();
1378             }
1379         }
1380         if (shouldFocusOnMapNotify()) {
1381             focusLog.fine("Automatically request focus on window");
1382             requestInitialFocus();
1383         }
1384         isUnhiding = false;
1385         isBeforeFirstMapNotify = false;
1386         updateAlwaysOnTop();
1387 
1388         synchronized (getStateLock()) {
1389             if (!isMapped) {
1390                 isMapped = true;
1391             }
1392         }
1393     }
1394 
1395     public void handleUnmapNotifyEvent(XEvent xev) {
1396         super.handleUnmapNotifyEvent(xev);
1397 
1398         // On Metacity UnmapNotify comes before PropertyNotify (for _NET_WM_STATE_HIDDEN).
1399         // So we also check for the property later in MapNotify. See 6480534.
1400         isUnhiding |= isWMStateNetHidden();
1401 
1402         synchronized (getStateLock()) {
1403             if (isMapped) {
1404                 isMapped = false;
1405             }
1406         }
1407     }
1408 
1409     private boolean shouldFocusOnMapNotify() {
1410         boolean res = false;
1411 
1412         if (isBeforeFirstMapNotify) {
1413             res = (winAttr.initialFocus ||          // Window.autoRequestFocus
1414                    isFocusedWindowModalBlocker());
1415         } else {
1416             res = isUnhiding;                       // Unhiding
1417         }
1418         res = res &&
1419             isFocusableWindow() &&                  // General focusability
1420             !isModalBlocked();                      // Modality
1421 
1422         return res;
1423     }
1424 
1425     protected boolean isWMStateNetHidden() {
1426         XNETProtocol protocol = XWM.getWM().getNETProtocol();
1427         return (protocol != null && protocol.isWMStateNetHidden(this));
1428     }
1429 
1430     protected void requestInitialFocus() {
1431         requestXFocus();
1432     }
1433 
1434     public void addToplevelStateListener(ToplevelStateListener l){
1435         toplevelStateListeners.add(l);
1436     }
1437 
1438     public void removeToplevelStateListener(ToplevelStateListener l){
1439         toplevelStateListeners.remove(l);
1440     }
1441 
1442     /**
1443      * Override this methods to get notifications when top-level window state changes. The state is
1444      * meant in terms of ICCCM: WithdrawnState, IconicState, NormalState
1445      */
1446     @Override
1447     protected void stateChanged(long time, int oldState, int newState) {
1448         // Fix for 6401700, 6412803
1449         // If this window is modal blocked, it is put into the transient_for
1450         // chain using prevTransientFor and nextTransientFor hints. However,
1451         // the real WM_TRANSIENT_FOR hint shouldn't be set for windows in
1452         // different WM states (except for owner-window relationship), so
1453         // if the window changes its state, its real WM_TRANSIENT_FOR hint
1454         // should be updated accordingly.
1455         updateTransientFor();
1456 
1457         for (ToplevelStateListener topLevelListenerTmp : toplevelStateListeners) {
1458             topLevelListenerTmp.stateChangedICCCM(oldState, newState);
1459         }
1460 
1461         updateSecurityWarningVisibility();
1462     }
1463 
1464     boolean isWithdrawn() {
1465         return getWMState() == XUtilConstants.WithdrawnState;
1466     }
1467 
1468     boolean hasDecorations(int decor) {
1469         if (!winAttr.nativeDecor) {
1470             return false;
1471         }
1472         else {
1473             int myDecor = winAttr.decorations;
1474             boolean hasBits = ((myDecor & decor) == decor);
1475             if ((myDecor & XWindowAttributesData.AWT_DECOR_ALL) != 0)
1476                 return !hasBits;
1477             else
1478                 return hasBits;
1479         }
1480     }
1481 
1482     void setReparented(boolean newValue) {
1483         super.setReparented(newValue);
1484         XToolkit.awtLock();
1485         try {
1486             if (isReparented() && delayedModalBlocking) {
1487                 addToTransientFors((XDialogPeer) AWTAccessor.getComponentAccessor().getPeer(modalBlocker));
1488                 delayedModalBlocking = false;
1489             }
1490         } finally {
1491             XToolkit.awtUnlock();
1492         }
1493     }
1494 
1495     /*
1496      * Returns a Vector of all Java top-level windows,
1497      * sorted by their current Z-order
1498      */
1499     static Vector<XWindowPeer> collectJavaToplevels() {
1500         Vector<XWindowPeer> javaToplevels = new Vector<XWindowPeer>();
1501         Vector<Long> v = new Vector<Long>();
1502         X11GraphicsEnvironment ge =
1503             (X11GraphicsEnvironment)GraphicsEnvironment.getLocalGraphicsEnvironment();
1504         GraphicsDevice[] gds = ge.getScreenDevices();
1505         if (!ge.runningXinerama() && (gds.length > 1)) {
1506             for (GraphicsDevice gd : gds) {
1507                 int screen = ((X11GraphicsDevice)gd).getScreen();
1508                 long rootWindow = XlibWrapper.RootWindow(XToolkit.getDisplay(), screen);
1509                 v.add(rootWindow);
1510             }
1511         } else {
1512             v.add(XToolkit.getDefaultRootWindow());
1513         }
1514         final int windowsCount = windows.size();
1515         while ((v.size() > 0) && (javaToplevels.size() < windowsCount)) {
1516             long win = v.remove(0);
1517             XQueryTree qt = new XQueryTree(win);
1518             try {
1519                 if (qt.execute() != 0) {
1520                     int nchildren = qt.get_nchildren();
1521                     long children = qt.get_children();
1522                     // XQueryTree returns window children ordered by z-order
1523                     for (int i = 0; i < nchildren; i++) {
1524                         long child = Native.getWindow(children, i);
1525                         XBaseWindow childWindow = XToolkit.windowToXWindow(child);
1526                         // filter out Java non-toplevels
1527                         if ((childWindow != null) && !(childWindow instanceof XWindowPeer)) {
1528                             continue;
1529                         } else {
1530                             v.add(child);
1531                         }
1532                         if (childWindow instanceof XWindowPeer) {
1533                             XWindowPeer np = (XWindowPeer)childWindow;
1534                             javaToplevels.add(np);
1535                             // XQueryTree returns windows sorted by their z-order. However,
1536                             // if WM has not handled transient for hint for a child window,
1537                             // it may appear in javaToplevels before its owner. Move such
1538                             // children after their owners.
1539                             int k = 0;
1540                             XWindowPeer toCheck = javaToplevels.get(k);
1541                             while (toCheck != np) {
1542                                 XWindowPeer toCheckOwnerPeer = toCheck.getOwnerPeer();
1543                                 if (toCheckOwnerPeer == np) {
1544                                     javaToplevels.remove(k);
1545                                     javaToplevels.add(toCheck);
1546                                 } else {
1547                                     k++;
1548                                 }
1549                                 toCheck = javaToplevels.get(k);
1550                             }
1551                         }
1552                     }
1553                 }
1554             } finally {
1555                 qt.dispose();
1556             }
1557         }
1558         return javaToplevels;
1559     }
1560 
1561     public void setModalBlocked(Dialog d, boolean blocked) {
1562         setModalBlocked(d, blocked, null);
1563     }
1564     public void setModalBlocked(Dialog d, boolean blocked,
1565                                 Vector<XWindowPeer> javaToplevels)
1566     {
1567         XToolkit.awtLock();
1568         try {
1569             // State lock should always be after awtLock
1570             synchronized(getStateLock()) {
1571                 XDialogPeer blockerPeer = (XDialogPeer) AWTAccessor.getComponentAccessor().getPeer(d);
1572                 if (blocked) {
1573                     if (log.isLoggable(PlatformLogger.Level.FINE)) {
1574                         log.fine("{0} is blocked by {1}", this, blockerPeer);
1575                     }
1576                     modalBlocker = d;
1577 
1578                     if (isReparented() || XWM.isNonReparentingWM()) {
1579                         addToTransientFors(blockerPeer, javaToplevels);
1580                     } else {
1581                         delayedModalBlocking = true;
1582                     }
1583                 } else {
1584                     if (d != modalBlocker) {
1585                         throw new IllegalStateException("Trying to unblock window blocked by another dialog");
1586                     }
1587                     modalBlocker = null;
1588 
1589                     if (isReparented() || XWM.isNonReparentingWM()) {
1590                         removeFromTransientFors();
1591                     } else {
1592                         delayedModalBlocking = false;
1593                     }
1594                 }
1595 
1596                 updateTransientFor();
1597             }
1598         } finally {
1599             XToolkit.awtUnlock();
1600         }
1601     }
1602 
1603     /*
1604      * Sets the TRANSIENT_FOR hint to the given top-level window. This
1605      *  method is used when a window is modal blocked/unblocked or
1606      *  changed its state from/to NormalState to/from other states.
1607      * If window or transientForWindow are embedded frames, the containing
1608      *  top-level windows are used.
1609      *
1610      * @param window specifies the top-level window that the hint
1611      *  is to be set to
1612      * @param transientForWindow the top-level window
1613      * @param updateChain specifies if next/prevTransientFor fields are
1614      *  to be updated
1615      * @param allStates if set to <code>true</code> then TRANSIENT_FOR hint
1616      *  is set regardless of the state of window and transientForWindow,
1617      *  otherwise it is set only if both are in the same state
1618      */
1619     static void setToplevelTransientFor(XWindowPeer window, XWindowPeer transientForWindow,
1620                                                 boolean updateChain, boolean allStates)
1621     {
1622         if ((window == null) || (transientForWindow == null)) {
1623             return;
1624         }
1625         if (updateChain) {
1626             window.prevTransientFor = transientForWindow;
1627             transientForWindow.nextTransientFor = window;
1628         }
1629         if (window.curRealTransientFor == transientForWindow) {
1630             return;
1631         }
1632         if (!allStates && (window.getWMState() != transientForWindow.getWMState())) {
1633             return;
1634         }
1635         if (window.getScreenNumber() != transientForWindow.getScreenNumber()) {
1636             return;
1637         }
1638         long bpw = window.getWindow();
1639         while (!XlibUtil.isToplevelWindow(bpw) && !XlibUtil.isXAWTToplevelWindow(bpw)) {
1640             bpw = XlibUtil.getParentWindow(bpw);
1641         }
1642         long tpw = transientForWindow.getWindow();
1643         while (!XlibUtil.isToplevelWindow(tpw) && !XlibUtil.isXAWTToplevelWindow(tpw)) {
1644             tpw = XlibUtil.getParentWindow(tpw);
1645         }
1646         XlibWrapper.XSetTransientFor(XToolkit.getDisplay(), bpw, tpw);
1647         window.curRealTransientFor = transientForWindow;
1648     }
1649 
1650     /*
1651      * This method does nothing if this window is not blocked by any modal dialog.
1652      * For modal blocked windows this method looks up for the nearest
1653      *  prevTransiendFor window that is in the same state (Normal/Iconified/Withdrawn)
1654      *  as this one and makes this window transient for it. The same operation is
1655      *  performed for nextTransientFor window.
1656      * Values of prevTransientFor and nextTransientFor fields are not changed.
1657      */
1658     void updateTransientFor() {
1659         int state = getWMState();
1660         XWindowPeer p = prevTransientFor;
1661         while ((p != null) && ((p.getWMState() != state) || (p.getScreenNumber() != getScreenNumber()))) {
1662             p = p.prevTransientFor;
1663         }
1664         if (p != null) {
1665             setToplevelTransientFor(this, p, false, false);
1666         } else {
1667             restoreTransientFor(this);
1668         }
1669         XWindowPeer n = nextTransientFor;
1670         while ((n != null) && ((n.getWMState() != state) || (n.getScreenNumber() != getScreenNumber()))) {
1671             n = n.nextTransientFor;
1672         }
1673         if (n != null) {
1674             setToplevelTransientFor(n, this, false, false);
1675         }
1676     }
1677 
1678     /*
1679      * Removes the TRANSIENT_FOR hint from the given top-level window.
1680      * If window or transientForWindow are embedded frames, the containing
1681      *  top-level windows are used.
1682      *
1683      * @param window specifies the top-level window that the hint
1684      *  is to be removed from
1685      */
1686     private static void removeTransientForHint(XWindowPeer window) {
1687         XAtom XA_WM_TRANSIENT_FOR = XAtom.get(XAtom.XA_WM_TRANSIENT_FOR);
1688         long bpw = window.getWindow();
1689         while (!XlibUtil.isToplevelWindow(bpw) && !XlibUtil.isXAWTToplevelWindow(bpw)) {
1690             bpw = XlibUtil.getParentWindow(bpw);
1691         }
1692         XlibWrapper.XDeleteProperty(XToolkit.getDisplay(), bpw, XA_WM_TRANSIENT_FOR.getAtom());
1693         window.curRealTransientFor = null;
1694     }
1695 
1696     /*
1697      * When a modal dialog is shown, all its blocked windows are lined up into
1698      *  a chain in such a way that each window is a transient_for window for
1699      *  the next one. That allows us to keep the modal dialog above all its
1700      *  blocked windows (even if there are some another modal dialogs between
1701      *  them).
1702      * This method adds this top-level window to the chain of the given modal
1703      *  dialog. To keep the current relative z-order, we should use the
1704      *  XQueryTree to find the place to insert this window to. As each window
1705      *  can be blocked by only one modal dialog (such checks are performed in
1706      *  shared code), both this and blockerPeer are on the top of their chains
1707      *  (chains may be empty).
1708      * If this window is a modal dialog and has its own chain, these chains are
1709      *  merged according to the current z-order (XQueryTree is used again).
1710      *  Below are some simple examples (z-order is from left to right, -- is
1711      *  modal blocking).
1712      *
1713      * Example 0:
1714      *     T (current chain of this, no windows are blocked by this)
1715      *  W1---B (current chain of blockerPeer, W2 is blocked by blockerPeer)
1716      *  Result is:
1717      *  W1-T-B (merged chain, all the windows are blocked by blockerPeer)
1718      *
1719      * Example 1:
1720      *  W1-T (current chain of this, W1 is blocked by this)
1721      *       W2-B (current chain of blockerPeer, W2 is blocked by blockerPeer)
1722      *  Result is:
1723      *  W1-T-W2-B (merged chain, all the windows are blocked by blockerPeer)
1724      *
1725      * Example 2:
1726      *  W1----T (current chain of this, W1 is blocked by this)
1727      *     W2---B (current chain of blockerPeer, W2 is blocked by blockerPeer)
1728      *  Result is:
1729      *  W1-W2-T-B (merged chain, all the windows are blocked by blockerPeer)
1730      *
1731      * This method should be called under the AWT lock.
1732      *
1733      * @see #removeFromTransientFors
1734      * @see #setModalBlocked
1735      */
1736     private void addToTransientFors(XDialogPeer blockerPeer) {
1737         addToTransientFors(blockerPeer, null);
1738     }
1739 
1740     private void addToTransientFors(XDialogPeer blockerPeer, Vector<XWindowPeer> javaToplevels)
1741     {
1742         // blockerPeer chain iterator
1743         XWindowPeer blockerChain = blockerPeer;
1744         while (blockerChain.prevTransientFor != null) {
1745             blockerChain = blockerChain.prevTransientFor;
1746         }
1747         // this window chain iterator
1748         // each window can be blocked no more than once, so this window
1749         //   is on top of its chain
1750         XWindowPeer thisChain = this;
1751         while (thisChain.prevTransientFor != null) {
1752             thisChain = thisChain.prevTransientFor;
1753         }
1754         // if there are no windows blocked by modalBlocker, simply add this window
1755         //  and its chain to blocker's chain
1756         if (blockerChain == blockerPeer) {
1757             setToplevelTransientFor(blockerPeer, this, true, false);
1758         } else {
1759             // Collect all the Java top-levels, if required
1760             if (javaToplevels == null) {
1761                 javaToplevels = collectJavaToplevels();
1762             }
1763             // merged chain tail
1764             XWindowPeer mergedChain = null;
1765             for (XWindowPeer w : javaToplevels) {
1766                 XWindowPeer prevMergedChain = mergedChain;
1767                 if (w == thisChain) {
1768                     if (thisChain == this) {
1769                         if (prevMergedChain != null) {
1770                             setToplevelTransientFor(this, prevMergedChain, true, false);
1771                         }
1772                         setToplevelTransientFor(blockerChain, this, true, false);
1773                         break;
1774                     } else {
1775                         mergedChain = thisChain;
1776                         thisChain = thisChain.nextTransientFor;
1777                     }
1778                 } else if (w == blockerChain) {
1779                     mergedChain = blockerChain;
1780                     blockerChain = blockerChain.nextTransientFor;
1781                 } else {
1782                     continue;
1783                 }
1784                 if (prevMergedChain == null) {
1785                     mergedChain.prevTransientFor = null;
1786                 } else {
1787                     setToplevelTransientFor(mergedChain, prevMergedChain, true, false);
1788                     mergedChain.updateTransientFor();
1789                 }
1790                 if (blockerChain == blockerPeer) {
1791                     setToplevelTransientFor(thisChain, mergedChain, true, false);
1792                     setToplevelTransientFor(blockerChain, this, true, false);
1793                     break;
1794                 }
1795             }
1796         }
1797 
1798         XToolkit.XSync();
1799     }
1800 
1801     static void restoreTransientFor(XWindowPeer window) {
1802         XWindowPeer ownerPeer = window.getOwnerPeer();
1803         if (ownerPeer != null) {
1804             setToplevelTransientFor(window, ownerPeer, false, true);
1805         } else {
1806             removeTransientForHint(window);
1807         }
1808     }
1809 
1810     /*
1811      * When a window is modally unblocked, it should be removed from its blocker
1812      *  chain, see {@link #addToTransientFor addToTransientFors} method for the
1813      *  chain definition.
1814      * The problem is that we cannot simply restore window's original
1815      *  TRANSIENT_FOR hint (if any) and link prevTransientFor and
1816      *  nextTransientFor together as the whole chain could be created as a merge
1817      *  of two other chains in addToTransientFors. In that case, if this window is
1818      *  a modal dialog, it would lost all its own chain, if we simply exclude it
1819      *  from the chain.
1820      * The correct behaviour of this method should be to split the chain, this
1821      *  window is currently in, into two chains. First chain is this window own
1822      *  chain (i. e. all the windows blocked by this one, directly or indirectly),
1823      *  if any, and the rest windows from the current chain.
1824      *
1825      * Example:
1826      *  Original state:
1827      *   W1-B1 (window W1 is blocked by B1)
1828      *   W2-B2 (window W2 is blocked by B2)
1829      *  B3 is shown and blocks B1 and B2:
1830      *   W1-W2-B1-B2-B3 (a single chain after B1.addToTransientFors() and B2.addToTransientFors())
1831      *  If we then unblock B1, the state should be:
1832      *   W1-B1 (window W1 is blocked by B1)
1833      *   W2-B2-B3 (window W2 is blocked by B2 and B2 is blocked by B3)
1834      *
1835      * This method should be called under the AWT lock.
1836      *
1837      * @see #addToTransientFors
1838      * @see #setModalBlocked
1839      */
1840     private void removeFromTransientFors() {
1841         // the head of the chain of this window
1842         XWindowPeer thisChain = this;
1843         // the head of the current chain
1844         // nextTransientFor is always not null as this window is in the chain
1845         XWindowPeer otherChain = nextTransientFor;
1846         // the set of blockers in this chain: if this dialog blocks some other
1847         // modal dialogs, their blocked windows should stay in this dialog's chain
1848         Set<XWindowPeer> thisChainBlockers = new HashSet<XWindowPeer>();
1849         thisChainBlockers.add(this);
1850         // current chain iterator in the order from next to prev
1851         XWindowPeer chainToSplit = prevTransientFor;
1852         while (chainToSplit != null) {
1853             XWindowPeer blocker = (XWindowPeer) AWTAccessor.getComponentAccessor().getPeer(chainToSplit.modalBlocker);
1854             if (thisChainBlockers.contains(blocker)) {
1855                 // add to this dialog's chain
1856                 setToplevelTransientFor(thisChain, chainToSplit, true, false);
1857                 thisChain = chainToSplit;
1858                 thisChainBlockers.add(chainToSplit);
1859             } else {
1860                 // leave in the current chain
1861                 setToplevelTransientFor(otherChain, chainToSplit, true, false);
1862                 otherChain = chainToSplit;
1863             }
1864             chainToSplit = chainToSplit.prevTransientFor;
1865         }
1866         restoreTransientFor(thisChain);
1867         thisChain.prevTransientFor = null;
1868         restoreTransientFor(otherChain);
1869         otherChain.prevTransientFor = null;
1870         nextTransientFor = null;
1871 
1872         XToolkit.XSync();
1873     }
1874 
1875     boolean isModalBlocked() {
1876         return modalBlocker != null;
1877     }
1878 
1879     static Window getDecoratedOwner(Window window) {
1880         while ((null != window) && !(window instanceof Frame || window instanceof Dialog)) {
1881             window = (Window) AWTAccessor.getComponentAccessor().getParent(window);
1882         }
1883         return window;
1884     }
1885 
1886     public boolean requestWindowFocus(XWindowPeer actualFocusedWindow) {
1887         setActualFocusedWindow(actualFocusedWindow);
1888         return requestWindowFocus();
1889     }
1890 
1891     public boolean requestWindowFocus() {
1892         return requestWindowFocus(0, false);
1893     }
1894 
1895     public boolean requestWindowFocus(long time, boolean timeProvided) {
1896         focusLog.fine("Request for window focus");
1897         // If this is Frame or Dialog we can't assure focus request success - but we still can try
1898         // If this is Window and its owner Frame is active we can be sure request succedded.
1899         Window ownerWindow  = XWindowPeer.getDecoratedOwner((Window)target);
1900         Window focusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow();
1901         Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
1902 
1903         if (isWMStateNetHidden()) {
1904             focusLog.fine("The window is unmapped, so rejecting the request");
1905             return false;
1906         }
1907         if (activeWindow == ownerWindow) {
1908             focusLog.fine("Parent window is active - generating focus for this window");
1909             handleWindowFocusInSync(-1);
1910             return true;
1911         }
1912         focusLog.fine("Parent window is not active");
1913 
1914         XDecoratedPeer wpeer = (XDecoratedPeer)AWTAccessor.getComponentAccessor().getPeer(ownerWindow);
1915         if (wpeer != null && wpeer.requestWindowFocus(this, time, timeProvided)) {
1916             focusLog.fine("Parent window accepted focus request - generating focus for this window");
1917             return true;
1918         }
1919         focusLog.fine("Denied - parent window is not active and didn't accept focus request");
1920         return false;
1921     }
1922 
1923     // This method is to be overriden in XDecoratedPeer.
1924     void setActualFocusedWindow(XWindowPeer actualFocusedWindow) {
1925     }
1926 
1927     /**
1928      * Applies the current window type.
1929      */
1930     private void applyWindowType() {
1931         XNETProtocol protocol = XWM.getWM().getNETProtocol();
1932         if (protocol == null) {
1933             return;
1934         }
1935 
1936         XAtom typeAtom = null;
1937 
1938         switch (getWindowType())
1939         {
1940             case NORMAL:
1941                 typeAtom = (ownerPeer == null) ?
1942                                protocol.XA_NET_WM_WINDOW_TYPE_NORMAL :
1943                                protocol.XA_NET_WM_WINDOW_TYPE_DIALOG;
1944                 break;
1945             case UTILITY:
1946                 typeAtom = protocol.XA_NET_WM_WINDOW_TYPE_UTILITY;
1947                 break;
1948             case POPUP:
1949                 typeAtom = protocol.XA_NET_WM_WINDOW_TYPE_POPUP_MENU;
1950                 break;
1951         }
1952 
1953         if (typeAtom != null) {
1954             XAtomList wtype = new XAtomList();
1955             wtype.add(typeAtom);
1956             protocol.XA_NET_WM_WINDOW_TYPE.
1957                 setAtomListProperty(getWindow(), wtype);
1958         } else {
1959             protocol.XA_NET_WM_WINDOW_TYPE.
1960                 DeleteProperty(getWindow());
1961         }
1962     }
1963 
1964     @Override
1965     public void xSetVisible(boolean visible) {
1966         if (log.isLoggable(PlatformLogger.Level.FINE)) {
1967             log.fine("Setting visible on " + this + " to " + visible);
1968         }
1969         XToolkit.awtLock();
1970         try {
1971             this.visible = visible;
1972             if (visible) {
1973                 applyWindowType();
1974                 XlibWrapper.XMapRaised(XToolkit.getDisplay(), getWindow());
1975             } else {
1976                 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow());
1977             }
1978             XlibWrapper.XFlush(XToolkit.getDisplay());
1979         }
1980         finally {
1981             XToolkit.awtUnlock();
1982         }
1983     }
1984 
1985     // should be synchronized on awtLock
1986     private int dropTargetCount = 0;
1987 
1988     public void addDropTarget() {
1989         XToolkit.awtLock();
1990         try {
1991             if (dropTargetCount == 0) {
1992                 long window = getWindow();
1993                 if (window != 0) {
1994                     XDropTargetRegistry.getRegistry().registerDropSite(window);
1995                 }
1996             }
1997             dropTargetCount++;
1998         } finally {
1999             XToolkit.awtUnlock();
2000         }
2001     }
2002 
2003     public void removeDropTarget() {
2004         XToolkit.awtLock();
2005         try {
2006             dropTargetCount--;
2007             if (dropTargetCount == 0) {
2008                 long window = getWindow();
2009                 if (window != 0) {
2010                     XDropTargetRegistry.getRegistry().unregisterDropSite(window);
2011                 }
2012             }
2013         } finally {
2014             XToolkit.awtUnlock();
2015         }
2016     }
2017     void addRootPropertyEventDispatcher() {
2018         if( rootPropertyEventDispatcher == null ) {
2019             rootPropertyEventDispatcher = new XEventDispatcher() {
2020                 public void dispatchEvent(XEvent ev) {
2021                     if( ev.get_type() == XConstants.PropertyNotify ) {
2022                         handleRootPropertyNotify( ev );
2023                     }
2024                 }
2025             };
2026             XlibWrapper.XSelectInput( XToolkit.getDisplay(),
2027                                       XToolkit.getDefaultRootWindow(),
2028                                       XConstants.PropertyChangeMask);
2029             XToolkit.addEventDispatcher(XToolkit.getDefaultRootWindow(),
2030                                                 rootPropertyEventDispatcher);
2031         }
2032     }
2033     void removeRootPropertyEventDispatcher() {
2034         if( rootPropertyEventDispatcher != null ) {
2035             XToolkit.removeEventDispatcher(XToolkit.getDefaultRootWindow(),
2036                                                 rootPropertyEventDispatcher);
2037             rootPropertyEventDispatcher = null;
2038         }
2039     }
2040     public void updateFocusableWindowState() {
2041         cachedFocusableWindow = isFocusableWindow();
2042     }
2043 
2044     XAtom XA_NET_WM_STATE;
2045     XAtomList net_wm_state;
2046     public XAtomList getNETWMState() {
2047         if (net_wm_state == null) {
2048             net_wm_state = XA_NET_WM_STATE.getAtomListPropertyList(this);
2049         }
2050         return net_wm_state;
2051     }
2052 
2053     public void setNETWMState(XAtomList state) {
2054         net_wm_state = state;
2055         if (state != null) {
2056             XA_NET_WM_STATE.setAtomListProperty(this, state);
2057         }
2058     }
2059 
2060     public PropMwmHints getMWMHints() {
2061         if (mwm_hints == null) {
2062             mwm_hints = new PropMwmHints();
2063             if (!XWM.XA_MWM_HINTS.getAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS)) {
2064                 mwm_hints.zero();
2065             }
2066         }
2067         return mwm_hints;
2068     }
2069 
2070     public void setMWMHints(PropMwmHints hints) {
2071         mwm_hints = hints;
2072         if (hints != null) {
2073             XWM.XA_MWM_HINTS.setAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS);
2074         }
2075     }
2076 
2077     protected void updateDropTarget() {
2078         XToolkit.awtLock();
2079         try {
2080             if (dropTargetCount > 0) {
2081                 long window = getWindow();
2082                 if (window != 0) {
2083                     XDropTargetRegistry.getRegistry().unregisterDropSite(window);
2084                     XDropTargetRegistry.getRegistry().registerDropSite(window);
2085                 }
2086             }
2087         } finally {
2088             XToolkit.awtUnlock();
2089         }
2090     }
2091 
2092     public void setGrab(boolean grab) {
2093         this.grab = grab;
2094         if (grab) {
2095             pressTarget = this;
2096             grabInput();
2097         } else {
2098             ungrabInput();
2099         }
2100     }
2101 
2102     public boolean isGrabbed() {
2103         return grab && XAwtState.getGrabWindow() == this;
2104     }
2105 
2106     public void handleXCrossingEvent(XEvent xev) {
2107         XCrossingEvent xce = xev.get_xcrossing();
2108         if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
2109             grabLog.fine("{0}, when grabbed {1}, contains {2}",
2110                          xce, isGrabbed(), containsGlobal(xce.get_x_root(), xce.get_y_root()));
2111         }
2112         if (isGrabbed()) {
2113             // When window is grabbed, all events are dispatched to
2114             // it.  Retarget them to the corresponding windows (notice
2115             // that XBaseWindow.dispatchEvent does the opposite
2116             // translation)
2117             // Note that we need to retarget XCrossingEvents to content window
2118             // since it generates MOUSE_ENTERED/MOUSE_EXITED for frame and dialog.
2119             // (fix for 6390326)
2120             XBaseWindow target = XToolkit.windowToXWindow(xce.get_window());
2121             if (grabLog.isLoggable(PlatformLogger.Level.FINER)) {
2122                 grabLog.finer("  -  Grab event target {0}", target);
2123             }
2124             if (target != null && target != this) {
2125                 target.dispatchEvent(xev);
2126                 return;
2127             }
2128         }
2129         super.handleXCrossingEvent(xev);
2130     }
2131 
2132     public void handleMotionNotify(XEvent xev) {
2133         XMotionEvent xme = xev.get_xmotion();
2134         if (grabLog.isLoggable(PlatformLogger.Level.FINER)) {
2135             grabLog.finer("{0}, when grabbed {1}, contains {2}",
2136                           xme, isGrabbed(), containsGlobal(xme.get_x_root(), xme.get_y_root()));
2137         }
2138         if (isGrabbed()) {
2139             boolean dragging = false;
2140             final int buttonsNumber = XToolkit.getNumberOfButtonsForMask();
2141 
2142             for (int i = 0; i < buttonsNumber; i++){
2143                 // here is the bug in WM: extra buttons doesn't have state!=0 as they should.
2144                 if ((i != 4) && (i != 5)){
2145                     dragging = dragging || ((xme.get_state() & XlibUtil.getButtonMask(i + 1)) != 0);
2146                 }
2147             }
2148             // When window is grabbed, all events are dispatched to
2149             // it.  Retarget them to the corresponding windows (notice
2150             // that XBaseWindow.dispatchEvent does the opposite
2151             // translation)
2152             XBaseWindow target = XToolkit.windowToXWindow(xme.get_window());
2153             if (dragging && pressTarget != target) {
2154                 // for some reasons if we grab input MotionNotify for drag is reported with target
2155                 // to underlying window, not to window on which we have initiated drag
2156                 // so we need to retarget them.  Here I use simplified logic which retarget all
2157                 // such events to source of mouse press (or the grabber).  It helps with fix for 6390326.
2158                 // So, I do not want to implement complicated logic for better retargeting.
2159                 target = pressTarget.isVisible() ? pressTarget : this;
2160                 xme.set_window(target.getWindow());
2161                 Point localCoord = target.toLocal(xme.get_x_root(), xme.get_y_root());
2162                 xme.set_x(localCoord.x);
2163                 xme.set_y(localCoord.y);
2164             }
2165             if (grabLog.isLoggable(PlatformLogger.Level.FINER)) {
2166                 grabLog.finer("  -  Grab event target {0}", target);
2167             }
2168             if (target != null) {
2169                 if (target != getContentXWindow() && target != this) {
2170                     target.dispatchEvent(xev);
2171                     return;
2172                 }
2173             }
2174 
2175             // note that we need to pass dragging events to the grabber (6390326)
2176             // see comment above for more inforamtion.
2177             if (!containsGlobal(xme.get_x_root(), xme.get_y_root()) && !dragging) {
2178                 // Outside of Java
2179                 return;
2180             }
2181         }
2182         super.handleMotionNotify(xev);
2183     }
2184 
2185     // we use it to retarget mouse drag and mouse release during grab.
2186     private XBaseWindow pressTarget = this;
2187 
2188     public void handleButtonPressRelease(XEvent xev) {
2189         XButtonEvent xbe = xev.get_xbutton();
2190 
2191         /*
2192          * Ignore the buttons above 20 due to the bit limit for
2193          * InputEvent.BUTTON_DOWN_MASK.
2194          * One more bit is reserved for FIRST_HIGH_BIT.
2195          */
2196         if (xbe.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) {
2197             return;
2198         }
2199         if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
2200             grabLog.fine("{0}, when grabbed {1}, contains {2} ({3}, {4}, {5}x{6})",
2201                          xbe, isGrabbed(), containsGlobal(xbe.get_x_root(), xbe.get_y_root()), getAbsoluteX(), getAbsoluteY(), getWidth(), getHeight());
2202         }
2203         if (isGrabbed()) {
2204             // When window is grabbed, all events are dispatched to
2205             // it.  Retarget them to the corresponding windows (notice
2206             // that XBaseWindow.dispatchEvent does the opposite
2207             // translation)
2208             XBaseWindow target = XToolkit.windowToXWindow(xbe.get_window());
2209             try {
2210                 if (grabLog.isLoggable(PlatformLogger.Level.FINER)) {
2211                     grabLog.finer("  -  Grab event target {0} (press target {1})", target, pressTarget);
2212                 }
2213                 if (xbe.get_type() == XConstants.ButtonPress
2214                     && xbe.get_button() == XConstants.buttons[0])
2215                 {
2216                     // need to keep it to retarget mouse release
2217                     pressTarget = target;
2218                 } else if (xbe.get_type() == XConstants.ButtonRelease
2219                            && xbe.get_button() == XConstants.buttons[0]
2220                            && pressTarget != target)
2221                 {
2222                     // during grab we do receive mouse release on different component (not on the source
2223                     // of mouse press).  So we need to retarget it.
2224                     // see 6390326 for more information.
2225                     target = pressTarget.isVisible() ? pressTarget : this;
2226                     xbe.set_window(target.getWindow());
2227                     Point localCoord = target.toLocal(xbe.get_x_root(), xbe.get_y_root());
2228                     xbe.set_x(localCoord.x);
2229                     xbe.set_y(localCoord.y);
2230                     pressTarget = this;
2231                 }
2232                 if (target != null && target != getContentXWindow() && target != this) {
2233                     target.dispatchEvent(xev);
2234                     return;
2235                 }
2236             } finally {
2237                 if (target != null) {
2238                     // Target is either us or our content window -
2239                     // check that event is inside.  'Us' in case of
2240                     // shell will mean that this will also filter out press on title
2241                     if ((target == this || target == getContentXWindow()) && !containsGlobal(xbe.get_x_root(), xbe.get_y_root())) {
2242                         // Outside this toplevel hierarchy
2243                         // According to the specification of UngrabEvent, post it
2244                         // when press occurs outside of the window and not on its owned windows
2245                         if (xbe.get_type() == XConstants.ButtonPress) {
2246                             if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
2247                                 grabLog.fine("Generating UngrabEvent on {0} because not inside of shell", this);
2248                             }
2249                             postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource()));
2250                             return;
2251                         }
2252                     }
2253                     // First, get the toplevel
2254                     XWindowPeer toplevel = target.getToplevelXWindow();
2255                     if (toplevel != null) {
2256                         Window w = (Window)toplevel.target;
2257                         while (w != null && toplevel != this && !(toplevel instanceof XDialogPeer)) {
2258                             w = (Window) AWTAccessor.getComponentAccessor().getParent(w);
2259                             if (w != null) {
2260                                 toplevel = (XWindowPeer) AWTAccessor.getComponentAccessor().getPeer(w);
2261                             }
2262                         }
2263                         if (w == null || (w != this.target && w instanceof Dialog)) {
2264                             // toplevel == null - outside of
2265                             // hierarchy, toplevel is Dialog - should
2266                             // send ungrab (but shouldn't for Window)
2267                             if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
2268                                 grabLog.fine("Generating UngrabEvent on {0} because hierarchy ended", this);
2269                             }
2270                             postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource()));
2271                         }
2272                     } else {
2273                         // toplevel is null - outside of hierarchy
2274                         if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
2275                             grabLog.fine("Generating UngrabEvent on {0} because toplevel is null", this);
2276                         }
2277                         postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource()));
2278                         return;
2279                     }
2280                 } else {
2281                     // target doesn't map to XAWT window - outside of hierarchy
2282                     if (grabLog.isLoggable(PlatformLogger.Level.FINE)) {
2283                         grabLog.fine("Generating UngrabEvent on because target is null {0}", this);
2284                     }
2285                     postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource()));
2286                     return;
2287                 }
2288             }
2289         }
2290         super.handleButtonPressRelease(xev);
2291     }
2292 
2293     public void print(Graphics g) {
2294         // We assume we print the whole frame,
2295         // so we expect no clip was set previously
2296         Shape shape = AWTAccessor.getWindowAccessor().getShape((Window)target);
2297         if (shape != null) {
2298             g.setClip(shape);
2299         }
2300         super.print(g);
2301     }
2302 
2303     @Override
2304     public void setOpacity(float opacity) {
2305         final long maxOpacity = 0xffffffffl;
2306         long iOpacity = (long)(opacity * maxOpacity);
2307         if (iOpacity < 0) {
2308             iOpacity = 0;
2309         }
2310         if (iOpacity > maxOpacity) {
2311             iOpacity = maxOpacity;
2312         }
2313 
2314         XAtom netWmWindowOpacityAtom = XAtom.get("_NET_WM_WINDOW_OPACITY");
2315 
2316         if (iOpacity == maxOpacity) {
2317             netWmWindowOpacityAtom.DeleteProperty(getWindow());
2318         } else {
2319             netWmWindowOpacityAtom.setCard32Property(getWindow(), iOpacity);
2320         }
2321     }
2322 
2323     @Override
2324     public void setOpaque(boolean isOpaque) {
2325         // no-op
2326     }
2327 
2328     @Override
2329     public void updateWindow() {
2330         // no-op
2331     }
2332 }