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