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