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