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