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