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