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