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