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