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