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