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