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 }