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