1 /*
   2  * Copyright (c) 2011, 2017, 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 
  26 package sun.lwawt.macosx;
  27 
  28 import java.awt.Color;
  29 import java.awt.Component;
  30 import java.awt.DefaultKeyboardFocusManager;
  31 import java.awt.Dialog;
  32 import java.awt.Dialog.ModalityType;
  33 import java.awt.Font;
  34 import java.awt.FontMetrics;
  35 import java.awt.Frame;
  36 import java.awt.GraphicsDevice;
  37 import java.awt.Insets;
  38 import java.awt.MenuBar;
  39 import java.awt.Point;
  40 import java.awt.Rectangle;
  41 import java.awt.Toolkit;
  42 import java.awt.Window;
  43 import java.awt.event.FocusEvent;
  44 import java.awt.event.WindowEvent;
  45 import java.beans.PropertyChangeEvent;
  46 import java.beans.PropertyChangeListener;
  47 import java.lang.reflect.InvocationTargetException;
  48 import java.util.ArrayList;
  49 import java.util.Arrays;
  50 import java.util.Comparator;
  51 import java.util.concurrent.atomic.AtomicBoolean;
  52 import java.util.concurrent.atomic.AtomicLong;
  53 import java.util.concurrent.atomic.AtomicReference;
  54 
  55 import javax.swing.JRootPane;
  56 import javax.swing.RootPaneContainer;
  57 import javax.swing.SwingUtilities;
  58 
  59 import com.apple.laf.ClientPropertyApplicator;
  60 import sun.awt.AWTAccessor;
  61 import sun.awt.AWTAccessor.ComponentAccessor;
  62 import sun.awt.AWTAccessor.WindowAccessor;
  63 import sun.java2d.SurfaceData;
  64 import sun.java2d.opengl.CGLSurfaceData;
  65 import sun.lwawt.LWToolkit;
  66 import sun.lwawt.LWWindowPeer;
  67 import sun.lwawt.PlatformWindow;
  68 import sun.util.logging.PlatformLogger;
  69 
  70 import com.apple.laf.ClientPropertyApplicator.Property;
  71 import com.sun.awt.AWTUtilities;
  72 import sun.lwawt.LWWindowPeer.PeerType;
  73 
  74 public class CPlatformWindow extends CFRetainedResource implements PlatformWindow {
  75     private native long nativeCreateNSWindow(long nsViewPtr,long ownerPtr, long styleBits, double x, double y, double w, double h);
  76     private static native void nativeSetNSWindowStyleBits(long nsWindowPtr, int mask, int data);
  77     private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr);
  78     private static native Insets nativeGetNSWindowInsets(long nsWindowPtr);
  79     private static native void nativeSetNSWindowBounds(long nsWindowPtr, double x, double y, double w, double h);
  80     private static native void nativeSetNSWindowLocationByPlatform(long nsWindowPtr);
  81     private static native void nativeSetNSWindowStandardFrame(long nsWindowPtr,
  82             double x, double y, double w, double h);
  83     private static native void nativeSetNSWindowMinMax(long nsWindowPtr, double minW, double minH, double maxW, double maxH);
  84     private static native void nativePushNSWindowToBack(long nsWindowPtr);
  85     private static native void nativePushNSWindowToFront(long nsWindowPtr);
  86     private static native void nativeSetNSWindowTitle(long nsWindowPtr, String title);
  87     private static native void nativeRevalidateNSWindowShadow(long nsWindowPtr);
  88     private static native void nativeSetNSWindowMinimizedIcon(long nsWindowPtr, long nsImage);
  89     private static native void nativeSetNSWindowRepresentedFilename(long nsWindowPtr, String representedFilename);
  90     private static native void nativeSetEnabled(long nsWindowPtr, boolean isEnabled);
  91     private static native void nativeSynthesizeMouseEnteredExitedEvents();
  92     private static native void nativeSynthesizeMouseEnteredExitedEvents(long nsWindowPtr, int eventType);
  93     private static native void nativeDispose(long nsWindowPtr);
  94     private static native void nativeEnterFullScreenMode(long nsWindowPtr);
  95     private static native void nativeExitFullScreenMode(long nsWindowPtr);
  96     static native CPlatformWindow nativeGetTopmostPlatformWindowUnderMouse();
  97 
  98     // Loger to report issues happened during execution but that do not affect functionality
  99     private static final PlatformLogger logger = PlatformLogger.getLogger("sun.lwawt.macosx.CPlatformWindow");
 100     private static final PlatformLogger focusLogger = PlatformLogger.getLogger("sun.lwawt.macosx.focus.CPlatformWindow");
 101 
 102     // for client properties
 103     public static final String WINDOW_BRUSH_METAL_LOOK = "apple.awt.brushMetalLook";
 104     public static final String WINDOW_DRAGGABLE_BACKGROUND = "apple.awt.draggableWindowBackground";
 105 
 106     public static final String WINDOW_ALPHA = "Window.alpha";
 107     public static final String WINDOW_SHADOW = "Window.shadow";
 108 
 109     public static final String WINDOW_STYLE = "Window.style";
 110     public static final String WINDOW_SHADOW_REVALIDATE_NOW = "apple.awt.windowShadow.revalidateNow";
 111 
 112     public static final String WINDOW_DOCUMENT_MODIFIED = "Window.documentModified";
 113     public static final String WINDOW_DOCUMENT_FILE = "Window.documentFile";
 114 
 115     public static final String WINDOW_CLOSEABLE = "Window.closeable";
 116     public static final String WINDOW_MINIMIZABLE = "Window.minimizable";
 117     public static final String WINDOW_ZOOMABLE = "Window.zoomable";
 118     public static final String WINDOW_HIDES_ON_DEACTIVATE="Window.hidesOnDeactivate";
 119 
 120     public static final String WINDOW_DOC_MODAL_SHEET = "apple.awt.documentModalSheet";
 121     public static final String WINDOW_FADE_DELEGATE = "apple.awt._windowFadeDelegate";
 122     public static final String WINDOW_FADE_IN = "apple.awt._windowFadeIn";
 123     public static final String WINDOW_FADE_OUT = "apple.awt._windowFadeOut";
 124     public static final String WINDOW_FULLSCREENABLE = "apple.awt.fullscreenable";
 125 
 126 
 127     // Yeah, I know. But it's easier to deal with ints from JNI
 128     static final int MODELESS = 0;
 129     static final int DOCUMENT_MODAL = 1;
 130     static final int APPLICATION_MODAL = 2;
 131     static final int TOOLKIT_MODAL = 3;
 132 
 133     // window style bits
 134     static final int _RESERVED_FOR_DATA = 1 << 0;
 135 
 136     // corresponds to native style mask bits
 137     static final int DECORATED = 1 << 1;
 138     static final int TEXTURED = 1 << 2;
 139     static final int UNIFIED = 1 << 3;
 140     static final int UTILITY = 1 << 4;
 141     static final int HUD = 1 << 5;
 142     static final int SHEET = 1 << 6;
 143 
 144     static final int CLOSEABLE = 1 << 7;
 145     static final int MINIMIZABLE = 1 << 8;
 146 
 147     static final int RESIZABLE = 1 << 9; // both a style bit and prop bit
 148     static final int NONACTIVATING = 1 << 24;
 149     static final int IS_DIALOG = 1 << 25;
 150     static final int IS_MODAL = 1 << 26;
 151     static final int IS_POPUP = 1 << 27;
 152 
 153     static final int _STYLE_PROP_BITMASK = DECORATED | TEXTURED | UNIFIED | UTILITY | HUD | SHEET | CLOSEABLE | MINIMIZABLE | RESIZABLE;
 154 
 155     // corresponds to method-based properties
 156     static final int HAS_SHADOW = 1 << 10;
 157     static final int ZOOMABLE = 1 << 11;
 158 
 159     static final int ALWAYS_ON_TOP = 1 << 15;
 160     static final int HIDES_ON_DEACTIVATE = 1 << 17;
 161     static final int DRAGGABLE_BACKGROUND = 1 << 19;
 162     static final int DOCUMENT_MODIFIED = 1 << 21;
 163     static final int FULLSCREENABLE = 1 << 23;
 164 
 165     static final int _METHOD_PROP_BITMASK = RESIZABLE | HAS_SHADOW | ZOOMABLE | ALWAYS_ON_TOP | HIDES_ON_DEACTIVATE | DRAGGABLE_BACKGROUND | DOCUMENT_MODIFIED | FULLSCREENABLE;
 166 
 167     // corresponds to callback-based properties
 168     static final int SHOULD_BECOME_KEY = 1 << 12;
 169     static final int SHOULD_BECOME_MAIN = 1 << 13;
 170     static final int MODAL_EXCLUDED = 1 << 16;
 171 
 172     static final int _CALLBACK_PROP_BITMASK = SHOULD_BECOME_KEY | SHOULD_BECOME_MAIN | MODAL_EXCLUDED;
 173 
 174     static int SET(final int bits, final int mask, final boolean value) {
 175         if (value) return (bits | mask);
 176         return bits & ~mask;
 177     }
 178 
 179     static boolean IS(final int bits, final int mask) {
 180         return (bits & mask) != 0;
 181     }
 182 
 183     @SuppressWarnings({"unchecked", "rawtypes"})
 184     static ClientPropertyApplicator<JRootPane, CPlatformWindow> CLIENT_PROPERTY_APPLICATOR = new ClientPropertyApplicator<JRootPane, CPlatformWindow>(new Property[] {
 185         new Property<CPlatformWindow>(WINDOW_DOCUMENT_MODIFIED) { public void applyProperty(final CPlatformWindow c, final Object value) {
 186             c.setStyleBits(DOCUMENT_MODIFIED, value == null ? false : Boolean.parseBoolean(value.toString()));
 187         }},
 188         new Property<CPlatformWindow>(WINDOW_BRUSH_METAL_LOOK) { public void applyProperty(final CPlatformWindow c, final Object value) {
 189             c.setStyleBits(TEXTURED, Boolean.parseBoolean(value.toString()));
 190         }},
 191         new Property<CPlatformWindow>(WINDOW_ALPHA) { public void applyProperty(final CPlatformWindow c, final Object value) {
 192             AWTUtilities.setWindowOpacity(c.target, value == null ? 1.0f : Float.parseFloat(value.toString()));
 193         }},
 194         new Property<CPlatformWindow>(WINDOW_SHADOW) { public void applyProperty(final CPlatformWindow c, final Object value) {
 195             c.setStyleBits(HAS_SHADOW, value == null ? true : Boolean.parseBoolean(value.toString()));
 196         }},
 197         new Property<CPlatformWindow>(WINDOW_MINIMIZABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
 198             c.setStyleBits(MINIMIZABLE, Boolean.parseBoolean(value.toString()));
 199         }},
 200         new Property<CPlatformWindow>(WINDOW_CLOSEABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
 201             c.setStyleBits(CLOSEABLE, Boolean.parseBoolean(value.toString()));
 202         }},
 203         new Property<CPlatformWindow>(WINDOW_ZOOMABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
 204             boolean zoomable = Boolean.parseBoolean(value.toString());
 205             if (c.target instanceof RootPaneContainer
 206                     && c.getPeer().getPeerType() == PeerType.FRAME) {
 207                 if (c.isInFullScreen && !zoomable) {
 208                     c.toggleFullScreen();
 209                 }
 210             }
 211             c.setStyleBits(ZOOMABLE, zoomable);
 212         }},
 213         new Property<CPlatformWindow>(WINDOW_FULLSCREENABLE) { public void applyProperty(final CPlatformWindow c, final Object value) {
 214             boolean fullscrenable = Boolean.parseBoolean(value.toString());
 215             if (c.target instanceof RootPaneContainer
 216                     && c.getPeer().getPeerType() == PeerType.FRAME) {
 217                 if (c.isInFullScreen && !fullscrenable) {
 218                     c.toggleFullScreen();
 219                 }
 220             }
 221             c.setStyleBits(FULLSCREENABLE, fullscrenable);
 222         }},
 223         new Property<CPlatformWindow>(WINDOW_SHADOW_REVALIDATE_NOW) { public void applyProperty(final CPlatformWindow c, final Object value) {
 224             c.execute(ptr -> nativeRevalidateNSWindowShadow(ptr));
 225         }},
 226         new Property<CPlatformWindow>(WINDOW_DOCUMENT_FILE) { public void applyProperty(final CPlatformWindow c, final Object value) {
 227             if (value == null || !(value instanceof java.io.File)) {
 228                 c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, null));
 229                 return;
 230             }
 231 
 232             final String filename = ((java.io.File)value).getAbsolutePath();
 233             c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, filename));
 234         }}
 235     }) {
 236         @SuppressWarnings("deprecation")
 237         public CPlatformWindow convertJComponentToTarget(final JRootPane p) {
 238             Component root = SwingUtilities.getRoot(p);
 239             final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
 240             if (root == null || acc.getPeer(root) == null) return null;
 241             return (CPlatformWindow)((LWWindowPeer)acc.getPeer(root)).getPlatformWindow();
 242         }
 243     };
 244     private final Comparator<Window> siblingsComparator = (w1, w2) -> {
 245         if (w1 == w2) {
 246             return 0;
 247         }
 248         ComponentAccessor componentAccessor = AWTAccessor.getComponentAccessor();
 249         Object p1 = componentAccessor.getPeer(w1);
 250         Object p2 = componentAccessor.getPeer(w2);
 251         if (p1 instanceof LWWindowPeer && p2 instanceof LWWindowPeer) {
 252             return Long.compare(
 253                     ((CPlatformWindow) (((LWWindowPeer) p1).getPlatformWindow())).lastBecomeMainTime,
 254                     ((CPlatformWindow) (((LWWindowPeer) p2).getPlatformWindow())).lastBecomeMainTime);
 255         }
 256         return 0;
 257     };
 258 
 259     // Bounds of the native widget but in the Java coordinate system.
 260     // In order to keep it up-to-date we will update them on
 261     // 1) setting native bounds via nativeSetBounds() call
 262     // 2) getting notification from the native level via deliverMoveResizeEvent()
 263     private Rectangle nativeBounds = new Rectangle(0, 0, 0, 0);
 264     private volatile boolean isFullScreenMode;
 265     private boolean isFullScreenAnimationOn;
 266 
 267     private volatile boolean isInFullScreen;
 268     private volatile boolean isIconifyAnimationActive;
 269     private volatile boolean isZoomed;
 270 
 271     private Window target;
 272     private LWWindowPeer peer;
 273     protected CPlatformView contentView;
 274     protected CPlatformWindow owner;
 275     protected boolean visible = false; // visibility status from native perspective
 276     private boolean undecorated; // initialized in getInitialStyleBits()
 277     private Rectangle normalBounds = null; // not-null only for undecorated maximized windows
 278     private CPlatformResponder responder;
 279     private long lastBecomeMainTime; // this is necessary to preserve right siblings order
 280 
 281     public CPlatformWindow() {
 282         super(0, true);
 283     }
 284 
 285     /*
 286      * Delegate initialization (create native window and all the
 287      * related resources).
 288      */
 289     @Override // PlatformWindow
 290     public void initialize(Window _target, LWWindowPeer _peer, PlatformWindow _owner) {
 291         initializeBase(_target, _peer, _owner, new CPlatformView());
 292 
 293         final int styleBits = getInitialStyleBits();
 294 
 295         responder = createPlatformResponder();
 296         contentView = createContentView();
 297         contentView.initialize(peer, responder);
 298 
 299         Rectangle bounds;
 300         if (!IS(DECORATED, styleBits)) {
 301             // For undecorated frames the move/resize event does not come if the frame is centered on the screen
 302             // so we need to set a stub location to force an initial move/resize. Real bounds would be set later.
 303             bounds = new Rectangle(0, 0, 1, 1);
 304         } else {
 305             bounds = _peer.constrainBounds(_target.getBounds());
 306         }
 307         AtomicLong ref = new AtomicLong();
 308         contentView.execute(viewPtr -> {
 309             boolean hasOwnerPtr = false;
 310 
 311             if (owner != null) {
 312                 hasOwnerPtr = 0L != owner.executeGet(ownerPtr -> {
 313                     ref.set(nativeCreateNSWindow(viewPtr, ownerPtr, styleBits,
 314                                                     bounds.x, bounds.y,
 315                                                     bounds.width, bounds.height));
 316                     return 1;
 317                 });
 318             }
 319 
 320             if (!hasOwnerPtr) {
 321                 ref.set(nativeCreateNSWindow(viewPtr, 0,
 322                                              styleBits, bounds.x, bounds.y,
 323                                              bounds.width, bounds.height));
 324             }
 325         });
 326         setPtr(ref.get());
 327 
 328         if (target instanceof javax.swing.RootPaneContainer) {
 329             final javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer)target).getRootPane();
 330             if (rootpane != null) rootpane.addPropertyChangeListener("ancestor", new PropertyChangeListener() {
 331                 public void propertyChange(final PropertyChangeEvent evt) {
 332                     CLIENT_PROPERTY_APPLICATOR.attachAndApplyClientProperties(rootpane);
 333                     rootpane.removePropertyChangeListener("ancestor", this);
 334                 }
 335             });
 336         }
 337 
 338         validateSurface();
 339     }
 340 
 341     protected void initializeBase(Window target, LWWindowPeer peer, PlatformWindow owner, CPlatformView view) {
 342         this.peer = peer;
 343         this.target = target;
 344         if (owner instanceof CPlatformWindow) {
 345             this.owner = (CPlatformWindow)owner;
 346         }
 347         this.contentView = view;
 348     }
 349 
 350     protected CPlatformResponder createPlatformResponder() {
 351         return new CPlatformResponder(peer, false);
 352     }
 353 
 354     protected CPlatformView createContentView() {
 355         return new CPlatformView();
 356     }
 357 
 358     protected int getInitialStyleBits() {
 359         // defaults style bits
 360         int styleBits = DECORATED | HAS_SHADOW | CLOSEABLE | MINIMIZABLE | ZOOMABLE | RESIZABLE;
 361 
 362         if (isNativelyFocusableWindow()) {
 363             styleBits = SET(styleBits, SHOULD_BECOME_KEY, true);
 364             styleBits = SET(styleBits, SHOULD_BECOME_MAIN, true);
 365         }
 366 
 367         final boolean isFrame = (target instanceof Frame);
 368         final boolean isDialog = (target instanceof Dialog);
 369         final boolean isPopup = (target.getType() == Window.Type.POPUP);
 370         if (isDialog) {
 371             styleBits = SET(styleBits, MINIMIZABLE, false);
 372         }
 373 
 374         // Either java.awt.Frame or java.awt.Dialog can be undecorated, however java.awt.Window always is undecorated.
 375         {
 376             this.undecorated = isFrame ? ((Frame)target).isUndecorated() : (isDialog ? ((Dialog)target).isUndecorated() : true);
 377             if (this.undecorated) styleBits = SET(styleBits, DECORATED, false);
 378         }
 379 
 380         // Either java.awt.Frame or java.awt.Dialog can be resizable, however java.awt.Window is never resizable
 381         {
 382             final boolean resizable = isFrame ? ((Frame)target).isResizable() : (isDialog ? ((Dialog)target).isResizable() : false);
 383             styleBits = SET(styleBits, RESIZABLE, resizable);
 384             if (!resizable) {
 385                 styleBits = SET(styleBits, ZOOMABLE, false);
 386             } else {
 387                 setCanFullscreen(true);
 388             }
 389         }
 390 
 391         if (target.isAlwaysOnTop()) {
 392             styleBits = SET(styleBits, ALWAYS_ON_TOP, true);
 393         }
 394 
 395         if (target.getModalExclusionType() == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) {
 396             styleBits = SET(styleBits, MODAL_EXCLUDED, true);
 397         }
 398 
 399         // If the target is a dialog, popup or tooltip we want it to ignore the brushed metal look.
 400         if (isPopup) {
 401             styleBits = SET(styleBits, TEXTURED, false);
 402             // Popups in applets don't activate applet's process
 403             styleBits = SET(styleBits, NONACTIVATING, true);
 404             styleBits = SET(styleBits, IS_POPUP, true);
 405         }
 406 
 407         if (Window.Type.UTILITY.equals(target.getType())) {
 408             styleBits = SET(styleBits, UTILITY, true);
 409         }
 410 
 411         if (target instanceof javax.swing.RootPaneContainer) {
 412             javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer)target).getRootPane();
 413             Object prop = null;
 414 
 415             prop = rootpane.getClientProperty(WINDOW_BRUSH_METAL_LOOK);
 416             if (prop != null) {
 417                 styleBits = SET(styleBits, TEXTURED, Boolean.parseBoolean(prop.toString()));
 418             }
 419 
 420             if (isDialog && ((Dialog)target).getModalityType() == ModalityType.DOCUMENT_MODAL) {
 421                 prop = rootpane.getClientProperty(WINDOW_DOC_MODAL_SHEET);
 422                 if (prop != null) {
 423                     styleBits = SET(styleBits, SHEET, Boolean.parseBoolean(prop.toString()));
 424                 }
 425             }
 426 
 427             prop = rootpane.getClientProperty(WINDOW_STYLE);
 428             if (prop != null) {
 429                 if ("small".equals(prop))  {
 430                     styleBits = SET(styleBits, UTILITY, true);
 431                     if (target.isAlwaysOnTop() && rootpane.getClientProperty(WINDOW_HIDES_ON_DEACTIVATE) == null) {
 432                         styleBits = SET(styleBits, HIDES_ON_DEACTIVATE, true);
 433                     }
 434                 }
 435                 if ("textured".equals(prop)) styleBits = SET(styleBits, TEXTURED, true);
 436                 if ("unified".equals(prop)) styleBits = SET(styleBits, UNIFIED, true);
 437                 if ("hud".equals(prop)) styleBits = SET(styleBits, HUD, true);
 438             }
 439 
 440             prop = rootpane.getClientProperty(WINDOW_HIDES_ON_DEACTIVATE);
 441             if (prop != null) {
 442                 styleBits = SET(styleBits, HIDES_ON_DEACTIVATE, Boolean.parseBoolean(prop.toString()));
 443             }
 444 
 445             prop = rootpane.getClientProperty(WINDOW_CLOSEABLE);
 446             if (prop != null) {
 447                 styleBits = SET(styleBits, CLOSEABLE, Boolean.parseBoolean(prop.toString()));
 448             }
 449 
 450             prop = rootpane.getClientProperty(WINDOW_MINIMIZABLE);
 451             if (prop != null) {
 452                 styleBits = SET(styleBits, MINIMIZABLE, Boolean.parseBoolean(prop.toString()));
 453             }
 454 
 455             prop = rootpane.getClientProperty(WINDOW_ZOOMABLE);
 456             if (prop != null) {
 457                 styleBits = SET(styleBits, ZOOMABLE, Boolean.parseBoolean(prop.toString()));
 458             }
 459 
 460             prop = rootpane.getClientProperty(WINDOW_FULLSCREENABLE);
 461             if (prop != null) {
 462                 styleBits = SET(styleBits, FULLSCREENABLE, Boolean.parseBoolean(prop.toString()));
 463             }
 464 
 465             prop = rootpane.getClientProperty(WINDOW_SHADOW);
 466             if (prop != null) {
 467                 styleBits = SET(styleBits, HAS_SHADOW, Boolean.parseBoolean(prop.toString()));
 468             }
 469 
 470             prop = rootpane.getClientProperty(WINDOW_DRAGGABLE_BACKGROUND);
 471             if (prop != null) {
 472                 styleBits = SET(styleBits, DRAGGABLE_BACKGROUND, Boolean.parseBoolean(prop.toString()));
 473             }
 474         }
 475 
 476         if (isDialog) {
 477             styleBits = SET(styleBits, IS_DIALOG, true);
 478             if (((Dialog) target).isModal()) {
 479                 styleBits = SET(styleBits, IS_MODAL, true);
 480             }
 481         }
 482 
 483         peer.setTextured(IS(TEXTURED, styleBits));
 484 
 485         return styleBits;
 486     }
 487 
 488     // this is the counter-point to -[CWindow _nativeSetStyleBit:]
 489     private void setStyleBits(final int mask, final boolean value) {
 490         execute(ptr -> nativeSetNSWindowStyleBits(ptr, mask, value ? mask : 0));
 491     }
 492 
 493     private native void _toggleFullScreenMode(final long model);
 494 
 495     public void toggleFullScreen() {
 496         execute(this::_toggleFullScreenMode);
 497     }
 498 
 499     @Override // PlatformWindow
 500     public void setMenuBar(MenuBar mb) {
 501         CMenuBar mbPeer = (CMenuBar)LWToolkit.targetToPeer(mb);
 502         execute(nsWindowPtr->{
 503             if (mbPeer != null) {
 504                 mbPeer.execute(ptr -> nativeSetNSWindowMenuBar(nsWindowPtr, ptr));
 505             } else {
 506                 nativeSetNSWindowMenuBar(nsWindowPtr, 0);
 507             }
 508         });
 509     }
 510 
 511     @Override // PlatformWindow
 512     public void dispose() {
 513         contentView.dispose();
 514         execute(CPlatformWindow::nativeDispose);
 515         CPlatformWindow.super.dispose();
 516     }
 517 
 518     @Override // PlatformWindow
 519     public FontMetrics getFontMetrics(Font f) {
 520         // TODO: not implemented
 521         (new RuntimeException("unimplemented")).printStackTrace();
 522         return null;
 523     }
 524 
 525     @Override // PlatformWindow
 526     public Insets getInsets() {
 527         AtomicReference<Insets> ref = new AtomicReference<>();
 528         execute(ptr -> {
 529             ref.set(nativeGetNSWindowInsets(ptr));
 530         });
 531         return ref.get() != null ? ref.get() : new Insets(0, 0, 0, 0);
 532     }
 533 
 534     @Override // PlatformWindow
 535     public Point getLocationOnScreen() {
 536         return new Point(nativeBounds.x, nativeBounds.y);
 537     }
 538 
 539     @Override
 540     public GraphicsDevice getGraphicsDevice() {
 541         return contentView.getGraphicsDevice();
 542     }
 543 
 544     @Override // PlatformWindow
 545     public SurfaceData getScreenSurface() {
 546         // TODO: not implemented
 547         return null;
 548     }
 549 
 550     @Override // PlatformWindow
 551     public SurfaceData replaceSurfaceData() {
 552         return contentView.replaceSurfaceData();
 553     }
 554 
 555     @Override // PlatformWindow
 556     public void setBounds(int x, int y, int w, int h) {
 557         execute(ptr -> nativeSetNSWindowBounds(ptr, x, y, w, h));
 558     }
 559 
 560     public void setMaximizedBounds(int x, int y, int w, int h) {
 561         execute(ptr -> nativeSetNSWindowStandardFrame(ptr, x, y, w, h));
 562     }
 563 
 564     private boolean isMaximized() {
 565         return undecorated ? this.normalBounds != null
 566                 : isZoomed;
 567     }
 568 
 569     private void maximize() {
 570         if (peer == null || isMaximized()) {
 571             return;
 572         }
 573         if (!undecorated) {
 574             execute(CWrapper.NSWindow::zoom);
 575         } else {
 576             deliverZoom(true);
 577 
 578             // We need an up to date size of the peer, so we flush the native events
 579             // to be sure that there are no setBounds requests in the queue.
 580             LWCToolkit.flushNativeSelectors();
 581             this.normalBounds = peer.getBounds();
 582             Rectangle maximizedBounds = peer.getMaximizedBounds();
 583             setBounds(maximizedBounds.x, maximizedBounds.y,
 584                     maximizedBounds.width, maximizedBounds.height);
 585         }
 586     }
 587 
 588     private void unmaximize() {
 589         if (!isMaximized()) {
 590             return;
 591         }
 592         if (!undecorated) {
 593             execute(CWrapper.NSWindow::zoom);
 594         } else {
 595             deliverZoom(false);
 596 
 597             Rectangle toBounds = this.normalBounds;
 598             this.normalBounds = null;
 599             setBounds(toBounds.x, toBounds.y, toBounds.width, toBounds.height);
 600         }
 601     }
 602 
 603     public boolean isVisible() {
 604         return this.visible;
 605     }
 606 
 607     @Override // PlatformWindow
 608     public void setVisible(boolean visible) {
 609         // Configure stuff
 610         updateIconImages();
 611         updateFocusabilityForAutoRequestFocus(false);
 612 
 613         boolean wasMaximized = isMaximized();
 614 
 615         if (visible && target.isLocationByPlatform()) {
 616             execute(CPlatformWindow::nativeSetNSWindowLocationByPlatform);
 617         }
 618 
 619         // Actually show or hide the window
 620         LWWindowPeer blocker = (peer == null)? null : peer.getBlocker();
 621         if (blocker == null || !visible) {
 622             // If it ain't blocked, or is being hidden, go regular way
 623             if (visible) {
 624                 contentView.execute(viewPtr -> {
 625                     execute(ptr -> CWrapper.NSWindow.makeFirstResponder(ptr,
 626                                                                         viewPtr));
 627                 });
 628 
 629                 boolean isPopup = (target.getType() == Window.Type.POPUP);
 630                 execute(ptr -> {
 631                     if (isPopup) {
 632                         // Popups in applets don't activate applet's process
 633                         CWrapper.NSWindow.orderFrontRegardless(ptr);
 634                     } else {
 635                         CWrapper.NSWindow.orderFront(ptr);
 636                     }
 637 
 638                     boolean isKeyWindow = CWrapper.NSWindow.isKeyWindow(ptr);
 639                     if (!isKeyWindow) {
 640                         CWrapper.NSWindow.makeKeyWindow(ptr);
 641                     }
 642                 });
 643             } else {
 644                 execute(ptr->{
 645                     // immediately hide the window
 646                     CWrapper.NSWindow.orderOut(ptr);
 647                     // process the close
 648                     CWrapper.NSWindow.close(ptr);
 649                 });
 650             }
 651         } else {
 652             // otherwise, put it in a proper z-order
 653             CPlatformWindow bw
 654                     = (CPlatformWindow) blocker.getPlatformWindow();
 655             bw.execute(blockerPtr -> {
 656                 execute(ptr -> {
 657                     CWrapper.NSWindow.orderWindow(ptr,
 658                                                   CWrapper.NSWindow.NSWindowBelow,
 659                                                   blockerPtr);
 660                 });
 661             });
 662         }
 663         this.visible = visible;
 664 
 665         // Manage the extended state when showing
 666         if (visible) {
 667             // Apply the extended state as expected in shared code
 668             if (target instanceof Frame) {
 669                 if (!wasMaximized && isMaximized()) {
 670                     // setVisible could have changed the native maximized state
 671                     deliverZoom(true);
 672                 } else {
 673                     int frameState = ((Frame)target).getExtendedState();
 674                     if ((frameState & Frame.ICONIFIED) != 0) {
 675                         // Treat all state bit masks with ICONIFIED bit as ICONIFIED state.
 676                         frameState = Frame.ICONIFIED;
 677                     }
 678                     switch (frameState) {
 679                         case Frame.ICONIFIED:
 680                             execute(CWrapper.NSWindow::miniaturize);
 681                             break;
 682                         case Frame.MAXIMIZED_BOTH:
 683                             maximize();
 684                             break;
 685                         default: // NORMAL
 686                             unmaximize(); // in case it was maximized, otherwise this is a no-op
 687                             break;
 688                     }
 689                 }
 690             }
 691         }
 692 
 693         nativeSynthesizeMouseEnteredExitedEvents();
 694 
 695         // Configure stuff #2
 696         updateFocusabilityForAutoRequestFocus(true);
 697 
 698         // Manage parent-child relationship when showing
 699         final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
 700 
 701         if (visible) {
 702             // Order myself above my parent
 703             if (owner != null && owner.isVisible()) {
 704                 owner.execute(ownerPtr -> {
 705                     execute(ptr -> {
 706                         CWrapper.NSWindow.orderWindow(ptr, CWrapper.NSWindow.NSWindowAbove, ownerPtr);
 707                     });
 708                 });
 709                 execute(CWrapper.NSWindow::orderFront);
 710                 applyWindowLevel(target);
 711             }
 712 
 713             // Order my own children above myself
 714             for (Window w : target.getOwnedWindows()) {
 715                 final Object p = acc.getPeer(w);
 716                 if (p instanceof LWWindowPeer) {
 717                     CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow();
 718                     if (pw != null && pw.isVisible()) {
 719                         pw.execute(childPtr -> {
 720                             execute(ptr -> {
 721                                 CWrapper.NSWindow.orderWindow(childPtr, CWrapper.NSWindow.NSWindowAbove, ptr);
 722                             });
 723                         });
 724                         pw.applyWindowLevel(w);
 725                     }
 726                 }
 727             }
 728         }
 729 
 730         // Deal with the blocker of the window being shown
 731         if (blocker != null && visible) {
 732             // Make sure the blocker is above its siblings
 733             ((CPlatformWindow)blocker.getPlatformWindow()).orderAboveSiblings();
 734         }
 735     }
 736 
 737     @Override // PlatformWindow
 738     public void setTitle(String title) {
 739         execute(ptr -> nativeSetNSWindowTitle(ptr, title));
 740     }
 741 
 742     // Should be called on every window key property change.
 743     @Override // PlatformWindow
 744     public void updateIconImages() {
 745         final CImage cImage = getImageForTarget();
 746         execute(ptr -> {
 747             if (cImage == null) {
 748                 nativeSetNSWindowMinimizedIcon(ptr, 0L);
 749             } else {
 750                 cImage.execute(imagePtr -> {
 751                     nativeSetNSWindowMinimizedIcon(ptr, imagePtr);
 752                 });
 753             }
 754         });
 755     }
 756 
 757     public SurfaceData getSurfaceData() {
 758         return contentView.getSurfaceData();
 759     }
 760 
 761     @Override  // PlatformWindow
 762     public void toBack() {
 763         execute(CPlatformWindow::nativePushNSWindowToBack);
 764     }
 765 
 766     @Override  // PlatformWindow
 767     public void toFront() {
 768         LWCToolkit lwcToolkit = (LWCToolkit) Toolkit.getDefaultToolkit();
 769         Window w = DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
 770         final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
 771         if( w != null && acc.getPeer(w) != null
 772                 && ((LWWindowPeer)acc.getPeer(w)).getPeerType() == LWWindowPeer.PeerType.EMBEDDED_FRAME
 773                 && !lwcToolkit.isApplicationActive()) {
 774             lwcToolkit.activateApplicationIgnoringOtherApps();
 775         }
 776         updateFocusabilityForAutoRequestFocus(false);
 777         execute(CPlatformWindow::nativePushNSWindowToFront);
 778         updateFocusabilityForAutoRequestFocus(true);
 779     }
 780 
 781     private void setCanFullscreen(final boolean canFullScreen) {
 782         if (target instanceof RootPaneContainer
 783                 && getPeer().getPeerType() == PeerType.FRAME) {
 784 
 785             if (isInFullScreen && !canFullScreen) {
 786                 toggleFullScreen();
 787             }
 788 
 789             final RootPaneContainer rpc = (RootPaneContainer) target;
 790             rpc.getRootPane().putClientProperty(
 791                     CPlatformWindow.WINDOW_FULLSCREENABLE, canFullScreen);
 792         }
 793     }
 794 
 795     @Override
 796     public void setResizable(final boolean resizable) {
 797         setCanFullscreen(resizable);
 798         setStyleBits(RESIZABLE, resizable);
 799         setStyleBits(ZOOMABLE, resizable);
 800     }
 801 
 802     @Override
 803     public void setSizeConstraints(int minW, int minH, int maxW, int maxH) {
 804         execute(ptr -> nativeSetNSWindowMinMax(ptr, minW, minH, maxW, maxH));
 805     }
 806 
 807     @Override
 808     public boolean rejectFocusRequest(FocusEvent.Cause cause) {
 809         // Cross-app activation requests are not allowed.
 810         if (cause != FocusEvent.Cause.MOUSE_EVENT &&
 811             !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive())
 812         {
 813             focusLogger.fine("the app is inactive, so the request is rejected");
 814             return true;
 815         }
 816         return false;
 817     }
 818 
 819     @Override
 820     public boolean requestWindowFocus() {
 821         execute(ptr -> {
 822             if (CWrapper.NSWindow.canBecomeMainWindow(ptr)) {
 823                 CWrapper.NSWindow.makeMainWindow(ptr);
 824             }
 825             CWrapper.NSWindow.makeKeyAndOrderFront(ptr);
 826         });
 827         return true;
 828     }
 829 
 830     @Override
 831     public boolean isActive() {
 832         AtomicBoolean ref = new AtomicBoolean();
 833         execute(ptr -> {
 834             ref.set(CWrapper.NSWindow.isKeyWindow(ptr));
 835         });
 836         return ref.get();
 837     }
 838 
 839     @Override
 840     public void updateFocusableWindowState() {
 841         final boolean isFocusable = isNativelyFocusableWindow();
 842         setStyleBits(SHOULD_BECOME_KEY | SHOULD_BECOME_MAIN, isFocusable); // set both bits at once
 843     }
 844 
 845     @Override
 846     public void setAlwaysOnTop(boolean isAlwaysOnTop) {
 847         setStyleBits(ALWAYS_ON_TOP, isAlwaysOnTop);
 848     }
 849 
 850     @Override
 851     public void setOpacity(float opacity) {
 852         execute(ptr -> CWrapper.NSWindow.setAlphaValue(ptr, opacity));
 853     }
 854 
 855     @Override
 856     public void setOpaque(boolean isOpaque) {
 857         execute(ptr -> CWrapper.NSWindow.setOpaque(ptr, isOpaque));
 858         boolean isTextured = (peer == null) ? false : peer.isTextured();
 859         if (!isTextured) {
 860             if (!isOpaque) {
 861                 execute(ptr -> CWrapper.NSWindow.setBackgroundColor(ptr, 0));
 862             } else if (peer != null) {
 863                 Color color = peer.getBackground();
 864                 if (color != null) {
 865                     int rgb = color.getRGB();
 866                     execute(ptr->CWrapper.NSWindow.setBackgroundColor(ptr, rgb));
 867                 }
 868             }
 869         }
 870 
 871         //This is a temporary workaround. Looks like after 7124236 will be fixed
 872         //the correct place for invalidateShadow() is CGLayer.drawInCGLContext.
 873         SwingUtilities.invokeLater(this::invalidateShadow);
 874     }
 875 
 876     @Override
 877     public void enterFullScreenMode() {
 878         isFullScreenMode = true;
 879         execute(CPlatformWindow::nativeEnterFullScreenMode);
 880     }
 881 
 882     @Override
 883     public void exitFullScreenMode() {
 884         execute(CPlatformWindow::nativeExitFullScreenMode);
 885         isFullScreenMode = false;
 886     }
 887 
 888     @Override
 889     public boolean isFullScreenMode() {
 890         return isFullScreenMode;
 891     }
 892 
 893     @Override
 894     public void setWindowState(int windowState) {
 895         if (peer == null || !peer.isVisible()) {
 896             // setVisible() applies the state
 897             return;
 898         }
 899 
 900         int prevWindowState = peer.getState();
 901         if (prevWindowState == windowState) return;
 902 
 903         if ((windowState & Frame.ICONIFIED) != 0) {
 904             // Treat all state bit masks with ICONIFIED bit as ICONIFIED state.
 905             windowState = Frame.ICONIFIED;
 906         }
 907         switch (windowState) {
 908             case Frame.ICONIFIED:
 909                 if (prevWindowState == Frame.MAXIMIZED_BOTH) {
 910                     // let's return into the normal states first
 911                     // the zoom call toggles between the normal and the max states
 912                     unmaximize();
 913                 }
 914                 execute(CWrapper.NSWindow::miniaturize);
 915                 break;
 916             case Frame.MAXIMIZED_BOTH:
 917                 if (prevWindowState == Frame.ICONIFIED) {
 918                     // let's return into the normal states first
 919                     execute(CWrapper.NSWindow::deminiaturize);
 920                 }
 921                 maximize();
 922                 break;
 923             case Frame.NORMAL:
 924                 if (prevWindowState == Frame.ICONIFIED) {
 925                     execute(CWrapper.NSWindow::deminiaturize);
 926                 } else if (prevWindowState == Frame.MAXIMIZED_BOTH) {
 927                     // the zoom call toggles between the normal and the max states
 928                     unmaximize();
 929                 }
 930                 break;
 931             default:
 932                 throw new RuntimeException("Unknown window state: " + windowState);
 933         }
 934 
 935         // NOTE: the SWP.windowState field gets updated to the newWindowState
 936         //       value when the native notification comes to us
 937     }
 938 
 939     @Override
 940     public void setModalBlocked(boolean blocked) {
 941         if (target.getModalExclusionType() == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) {
 942             return;
 943         }
 944 
 945         if (blocked) {
 946             // We are going to show a modal window. Previously displayed window will be
 947             // blocked/disabled. So we have to send mouse exited event to it now, since
 948             // all mouse events are discarded for blocked/disabled windows.
 949             execute(ptr -> nativeSynthesizeMouseEnteredExitedEvents(ptr, CocoaConstants.NSMouseExited));
 950         }
 951 
 952         execute(ptr -> nativeSetEnabled(ptr, !blocked));
 953         checkBlockingAndOrder();
 954     }
 955 
 956     public final void invalidateShadow() {
 957         execute(ptr -> nativeRevalidateNSWindowShadow(ptr));
 958     }
 959 
 960     // ----------------------------------------------------------------------
 961     //                          UTILITY METHODS
 962     // ----------------------------------------------------------------------
 963 
 964     /**
 965      * Find image to install into Title or into Application icon. First try
 966      * icons installed for toplevel. Null is returned, if there is no icon and
 967      * default Duke image should be used.
 968      */
 969     private CImage getImageForTarget() {
 970         CImage icon = null;
 971         try {
 972             icon = CImage.getCreator().createFromImages(target.getIconImages());
 973         } catch (Exception ignored) {
 974             // Perhaps the icon passed into Java is broken. Skipping this icon.
 975         }
 976         return icon;
 977     }
 978 
 979     /*
 980      * Returns LWWindowPeer associated with this delegate.
 981      */
 982     @Override
 983     public LWWindowPeer getPeer() {
 984         return peer;
 985     }
 986 
 987     @Override
 988     public boolean isUnderMouse() {
 989         return contentView.isUnderMouse();
 990     }
 991 
 992     public CPlatformView getContentView() {
 993         return contentView;
 994     }
 995 
 996     @Override
 997     public long getLayerPtr() {
 998         return contentView.getWindowLayerPtr();
 999     }
1000 
1001     private void validateSurface() {
1002         SurfaceData surfaceData = getSurfaceData();
1003         if (surfaceData instanceof CGLSurfaceData) {
1004             ((CGLSurfaceData)surfaceData).validate();
1005         }
1006     }
1007 
1008     void flushBuffers() {
1009         if (isVisible() && !nativeBounds.isEmpty() && !isFullScreenMode) {
1010             try {
1011                 LWCToolkit.invokeAndWait(new Runnable() {
1012                     @Override
1013                     public void run() {
1014                         //Posting an empty to flush the EventQueue without blocking the main thread
1015                     }
1016                 }, target);
1017             } catch (InvocationTargetException e) {
1018                 e.printStackTrace();
1019             }
1020         }
1021     }
1022 
1023     /**
1024      * Helper method to get a pointer to the native view from the PlatformWindow.
1025      */
1026     static long getNativeViewPtr(PlatformWindow platformWindow) {
1027         long nativePeer = 0L;
1028         if (platformWindow instanceof CPlatformWindow) {
1029             nativePeer = ((CPlatformWindow) platformWindow).getContentView().getAWTView();
1030         } else if (platformWindow instanceof CViewPlatformEmbeddedFrame){
1031             nativePeer = ((CViewPlatformEmbeddedFrame) platformWindow).getNSViewPtr();
1032         }
1033         return nativePeer;
1034     }
1035 
1036     /*************************************************************
1037      * Callbacks from the AWTWindow and AWTView objc classes.
1038      *************************************************************/
1039     private void deliverWindowFocusEvent(boolean gained, CPlatformWindow opposite){
1040         // Fix for 7150349: ingore "gained" notifications when the app is inactive.
1041         if (gained && !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive()) {
1042             focusLogger.fine("the app is inactive, so the notification is ignored");
1043             return;
1044         }
1045 
1046         LWWindowPeer oppositePeer = (opposite == null)? null : opposite.getPeer();
1047         responder.handleWindowFocusEvent(gained, oppositePeer);
1048     }
1049 
1050     protected void deliverMoveResizeEvent(int x, int y, int width, int height,
1051                                         boolean byUser) {
1052         AtomicBoolean ref = new AtomicBoolean();
1053         execute(ptr -> {
1054             ref.set(CWrapper.NSWindow.isZoomed(ptr));
1055         });
1056         isZoomed = ref.get();
1057         checkZoom();
1058 
1059         final Rectangle oldB = nativeBounds;
1060         nativeBounds = new Rectangle(x, y, width, height);
1061         if (peer != null) {
1062             peer.notifyReshape(x, y, width, height);
1063             // System-dependent appearance optimization.
1064             if ((byUser && !oldB.getSize().equals(nativeBounds.getSize()))
1065                     || isFullScreenAnimationOn) {
1066                 flushBuffers();
1067             }
1068         }
1069     }
1070 
1071     private void deliverWindowClosingEvent() {
1072         if (peer != null && peer.getBlocker() == null) {
1073             peer.postEvent(new WindowEvent(target, WindowEvent.WINDOW_CLOSING));
1074         }
1075     }
1076 
1077     private void deliverIconify(final boolean iconify) {
1078         if (peer != null) {
1079             peer.notifyIconify(iconify);
1080         }
1081         if (iconify) {
1082             isIconifyAnimationActive = false;
1083         }
1084     }
1085 
1086     private void deliverZoom(final boolean isZoomed) {
1087         if (peer != null) {
1088             peer.notifyZoom(isZoomed);
1089         }
1090     }
1091 
1092     private void checkZoom() {
1093         if (peer != null) {
1094             int state = peer.getState();
1095             if (state != Frame.MAXIMIZED_BOTH && isMaximized()) {
1096                 deliverZoom(true);
1097             } else if (state == Frame.MAXIMIZED_BOTH && !isMaximized()) {
1098                 deliverZoom(false);
1099             }
1100         }
1101     }
1102 
1103     private void deliverNCMouseDown() {
1104         if (peer != null) {
1105             peer.notifyNCMouseDown();
1106         }
1107     }
1108 
1109     /*
1110      * Our focus model is synthetic and only non-simple window
1111      * may become natively focusable window.
1112      */
1113     private boolean isNativelyFocusableWindow() {
1114         if (peer == null) {
1115             return false;
1116         }
1117 
1118         return !peer.isSimpleWindow() && target.getFocusableWindowState();
1119     }
1120 
1121     private boolean isBlocked() {
1122         LWWindowPeer blocker = (peer != null) ? peer.getBlocker() : null;
1123         return (blocker != null);
1124     }
1125 
1126     /*
1127      * An utility method for the support of the auto request focus.
1128      * Updates the focusable state of the window under certain
1129      * circumstances.
1130      */
1131     private void updateFocusabilityForAutoRequestFocus(boolean isFocusable) {
1132         if (target.isAutoRequestFocus() || !isNativelyFocusableWindow()) return;
1133         setStyleBits(SHOULD_BECOME_KEY | SHOULD_BECOME_MAIN, isFocusable); // set both bits at once
1134     }
1135 
1136     private boolean checkBlockingAndOrder() {
1137         LWWindowPeer blocker = (peer == null)? null : peer.getBlocker();
1138         if (blocker == null) {
1139             return false;
1140         }
1141 
1142         if (blocker instanceof CPrinterDialogPeer) {
1143             return true;
1144         }
1145 
1146         CPlatformWindow pWindow = (CPlatformWindow)blocker.getPlatformWindow();
1147 
1148         pWindow.orderAboveSiblings();
1149 
1150         pWindow.execute(ptr -> {
1151             CWrapper.NSWindow.orderFrontRegardless(ptr);
1152             CWrapper.NSWindow.makeKeyAndOrderFront(ptr);
1153             CWrapper.NSWindow.makeMainWindow(ptr);
1154         });
1155         return true;
1156     }
1157 
1158     private boolean isIconified() {
1159         boolean isIconified = false;
1160         if (target instanceof Frame) {
1161             int state = ((Frame)target).getExtendedState();
1162             if ((state & Frame.ICONIFIED) != 0) {
1163                 isIconified = true;
1164             }
1165         }
1166         return isIconifyAnimationActive || isIconified;
1167     }
1168 
1169     private boolean isOneOfOwnersOrSelf(CPlatformWindow window) {
1170         while (window != null) {
1171             if (this == window) {
1172                 return true;
1173             }
1174             window = window.owner;
1175         }
1176         return false;
1177     }
1178 
1179     private CPlatformWindow getRootOwner() {
1180         CPlatformWindow rootOwner = this;
1181         while (rootOwner.owner != null) {
1182             rootOwner = rootOwner.owner;
1183         }
1184         return rootOwner;
1185     }
1186 
1187     private void orderAboveSiblings() {
1188         // Recursively pop up the windows from the very bottom, (i.e. root owner) so that
1189         // the windows are ordered above their nearest owner; ancestors of the window,
1190         // which is going to become 'main window', are placed above their siblings.
1191         CPlatformWindow rootOwner = getRootOwner();
1192         if (rootOwner.isVisible() && !rootOwner.isIconified()) {
1193             rootOwner.execute(CWrapper.NSWindow::orderFront);
1194         }
1195         // Do not order child windows of iconified owner.
1196         if (!rootOwner.isIconified()) {
1197             final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
1198             orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target));
1199         }
1200     }
1201 
1202     private void orderAboveSiblingsImpl(Window[] windows) {
1203         ArrayList<Window> childWindows = new ArrayList<Window>();
1204 
1205         final ComponentAccessor componentAccessor = AWTAccessor.getComponentAccessor();
1206         final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
1207         Arrays.sort(windows, siblingsComparator);
1208         // Go through the list of windows and perform ordering.
1209         CPlatformWindow pwUnder = null;
1210         for (Window w : windows) {
1211             boolean iconified = false;
1212             final Object p = componentAccessor.getPeer(w);
1213             if (p instanceof LWWindowPeer) {
1214                 CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow();
1215                 iconified = isIconified();
1216                 if (pw != null && pw.isVisible() && !iconified) {
1217                     // If the window is one of ancestors of 'main window' or is going to become main by itself,
1218                     // the window should be ordered above its siblings; otherwise the window is just ordered
1219                     // above its nearest parent.
1220                     if (pw.isOneOfOwnersOrSelf(this)) {
1221                         pw.execute(CWrapper.NSWindow::orderFront);
1222                     } else {
1223                         if (pwUnder == null) {
1224                             pwUnder = pw.owner;
1225                         }
1226                         pwUnder.execute(underPtr -> {
1227                             pw.execute(ptr -> {
1228                                 CWrapper.NSWindow.orderWindow(ptr, CWrapper.NSWindow.NSWindowAbove, underPtr);
1229                             });
1230                         });
1231                         pwUnder = pw;
1232                     }
1233                     pw.applyWindowLevel(w);
1234                 }
1235             }
1236             // Retrieve the child windows for each window from the list except iconified ones
1237             // and store them for future use.
1238             // Note: we collect data about child windows even for invisible owners, since they may have
1239             // visible children.
1240             if (!iconified) {
1241                 childWindows.addAll(Arrays.asList(windowAccessor.getOwnedWindows(w)));
1242             }
1243         }
1244         // If some windows, which have just been ordered, have any child windows, let's start new iteration
1245         // and order these child windows.
1246         if (!childWindows.isEmpty()) {
1247             orderAboveSiblingsImpl(childWindows.toArray(new Window[0]));
1248         }
1249     }
1250 
1251     protected void applyWindowLevel(Window target) {
1252         if (target.isAlwaysOnTop() && target.getType() != Window.Type.POPUP) {
1253             execute(ptr->CWrapper.NSWindow.setLevel(ptr, CWrapper.NSWindow.NSFloatingWindowLevel));
1254         } else if (target.getType() == Window.Type.POPUP) {
1255             execute(ptr->CWrapper.NSWindow.setLevel(ptr, CWrapper.NSWindow.NSPopUpMenuWindowLevel));
1256         }
1257     }
1258 
1259     // ----------------------------------------------------------------------
1260     //                          NATIVE CALLBACKS
1261     // ----------------------------------------------------------------------
1262 
1263     private void windowWillMiniaturize() {
1264         isIconifyAnimationActive = true;
1265     }
1266 
1267     private void windowDidBecomeMain() {
1268         lastBecomeMainTime = System.currentTimeMillis();
1269         if (checkBlockingAndOrder()) return;
1270         // If it's not blocked, make sure it's above its siblings
1271         orderAboveSiblings();
1272     }
1273 
1274     private void windowWillEnterFullScreen() {
1275         isFullScreenAnimationOn = true;
1276     }
1277 
1278     private void windowDidEnterFullScreen() {
1279         isInFullScreen = true;
1280         isFullScreenAnimationOn = false;
1281     }
1282 
1283     private void windowWillExitFullScreen() {
1284         isFullScreenAnimationOn = true;
1285     }
1286 
1287     private void windowDidExitFullScreen() {
1288         isInFullScreen = false;
1289         isFullScreenAnimationOn = false;
1290     }
1291 }