1 /* 2 * Copyright (c) 2008, 2015, 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 com.sun.javafx.tk.quantum; 27 28 import java.nio.ByteBuffer; 29 import java.security.AccessController; 30 import java.security.AllPermission; 31 import java.security.Permission; 32 import java.security.PrivilegedAction; 33 import java.security.AccessControlContext; 34 import java.util.HashMap; 35 import java.util.LinkedList; 36 import java.util.List; 37 import java.util.Map; 38 39 import javafx.scene.input.KeyCombination; 40 import javafx.stage.Modality; 41 import javafx.stage.Stage; 42 import javafx.stage.StageStyle; 43 44 import com.sun.glass.events.WindowEvent; 45 import com.sun.glass.ui.*; 46 import com.sun.glass.ui.Window.Level; 47 import com.sun.javafx.PlatformUtil; 48 import com.sun.javafx.iio.common.PushbroomScaler; 49 import com.sun.javafx.iio.common.ScalerFactory; 50 import com.sun.javafx.tk.FocusCause; 51 import com.sun.javafx.tk.TKScene; 52 import com.sun.javafx.tk.TKStage; 53 import com.sun.prism.Image; 54 import com.sun.prism.PixelFormat; 55 import java.util.Locale; 56 import java.util.ResourceBundle; 57 58 class WindowStage extends GlassStage { 59 60 protected Window platformWindow; 61 62 protected javafx.stage.Stage fxStage; 63 64 private StageStyle style; 65 private GlassStage owner = null; 66 private Modality modality = Modality.NONE; 67 private final boolean securityDialog; 68 69 private OverlayWarning warning = null; 70 private boolean rtl = false; 71 private boolean transparent = false; 72 private boolean isPrimaryStage = false; 73 private boolean isAppletStage = false; // true if this is an embedded applet window 74 private boolean isPopupStage = false; 75 private boolean isInFullScreen = false; 76 77 // A flag to indicate whether a call was generated from 78 // an input event handler. 79 private boolean inEventHandler = false; 80 81 // An active window is visible && enabled && focusable. 82 // The list is maintained in the z-order, so that the last element 83 // represents the topmost window (or more accurately, the last 84 // focused window, which we assume is very close to the last topmost one). 85 private static List<WindowStage> activeWindows = new LinkedList<>(); 86 87 private static Map<Window, WindowStage> platformWindows = new HashMap<>(); 88 89 private static GlassAppletWindow appletWindow = null; 90 static void setAppletWindow(GlassAppletWindow aw) { 91 appletWindow = aw; 92 } 93 static GlassAppletWindow getAppletWindow() { 94 return appletWindow; 95 } 96 97 private static final Locale LOCALE = Locale.getDefault(); 98 99 private static final ResourceBundle RESOURCES = 100 ResourceBundle.getBundle(WindowStage.class.getPackage().getName() + 101 ".QuantumMessagesBundle", LOCALE); 102 103 104 public WindowStage(javafx.stage.Window peerWindow, boolean securityDialog, final StageStyle stageStyle, Modality modality, TKStage owner) { 105 this.style = stageStyle; 106 this.owner = (GlassStage)owner; 107 this.modality = modality; 108 this.securityDialog = securityDialog; 109 110 if (peerWindow instanceof javafx.stage.Stage) { 111 fxStage = (Stage)peerWindow; 112 } else { 113 fxStage = null; 114 } 115 116 transparent = stageStyle == StageStyle.TRANSPARENT; 117 if (owner == null) { 118 if (this.modality == Modality.WINDOW_MODAL) { 119 this.modality = Modality.NONE; 120 } 121 } 122 } 123 124 final void setIsPrimary() { 125 isPrimaryStage = true; 126 if (appletWindow != null) { 127 // this is an embedded applet stage 128 isAppletStage = true; 129 } 130 } 131 132 final void setIsPopup() { 133 isPopupStage = true; 134 } 135 136 final boolean isSecurityDialog() { 137 return securityDialog; 138 } 139 140 // Called by QuantumToolkit, so we can override initPlatformWindow in subclasses 141 public final WindowStage init(GlassSystemMenu sysmenu) { 142 initPlatformWindow(); 143 platformWindow.setEventHandler(new GlassWindowEventHandler(this)); 144 if (sysmenu.isSupported()) { 145 sysmenu.createMenuBar(); 146 platformWindow.setMenuBar(sysmenu.getMenuBar()); 147 } 148 return this; 149 } 150 151 private void initPlatformWindow() { 152 if (platformWindow == null) { 153 Application app = Application.GetApplication(); 154 if (isPrimaryStage && (null != appletWindow)) { 155 platformWindow = app.createWindow(appletWindow.getGlassWindow().getNativeWindow()); 156 } else { 157 Window ownerWindow = null; 158 if (owner instanceof WindowStage) { 159 ownerWindow = ((WindowStage)owner).platformWindow; 160 } 161 boolean resizable = false; 162 boolean focusable = true; 163 int windowMask = rtl ? Window.RIGHT_TO_LEFT : 0; 164 if (isPopupStage) { // TODO: make it a stage style? 165 windowMask |= Window.POPUP; 166 if (style == StageStyle.TRANSPARENT) { 167 windowMask |= Window.TRANSPARENT; 168 } 169 focusable = false; 170 } else { 171 switch (style) { 172 case UNIFIED: 173 if (app.supportsUnifiedWindows()) { 174 windowMask |= Window.UNIFIED; 175 } 176 // fall through 177 case DECORATED: 178 windowMask |= 179 Window.TITLED | Window.CLOSABLE | 180 Window.MINIMIZABLE | Window.MAXIMIZABLE; 181 if (ownerWindow != null || modality != Modality.NONE) { 182 windowMask &= 183 ~(Window.MINIMIZABLE | Window.MAXIMIZABLE); 184 } 185 resizable = true; 186 break; 187 case UTILITY: 188 windowMask |= Window.TITLED | Window.UTILITY | Window.CLOSABLE; 189 break; 190 default: 191 windowMask |= 192 (transparent ? Window.TRANSPARENT : Window.UNTITLED) | Window.CLOSABLE; 193 break; 194 } 195 } 196 platformWindow = 197 app.createWindow(ownerWindow, Screen.getMainScreen(), windowMask); 198 platformWindow.setResizable(resizable); 199 platformWindow.setFocusable(focusable); 200 if (securityDialog) { 201 platformWindow.setLevel(Window.Level.FLOATING); 202 } 203 } 204 } 205 platformWindows.put(platformWindow, this); 206 } 207 208 final Window getPlatformWindow() { 209 return platformWindow; 210 } 211 212 static WindowStage findWindowStage(Window platformWindow) { 213 return platformWindows.get(platformWindow); 214 } 215 216 protected GlassStage getOwner() { 217 return owner; 218 } 219 220 protected ViewScene getViewScene() { 221 return (ViewScene)getScene(); 222 } 223 224 StageStyle getStyle() { 225 return style; 226 } 227 228 @Override public TKScene createTKScene(boolean depthBuffer, boolean msaa, AccessControlContext acc) { 229 ViewScene scene = new ViewScene(depthBuffer, msaa); 230 scene.setSecurityContext(acc); 231 return scene; 232 } 233 234 /** 235 * Set the scene to be displayed in this stage 236 * 237 * @param scene The peer of the scene to be displayed 238 */ 239 @Override public void setScene(TKScene scene) { 240 GlassScene oldScene = getScene(); 241 if (oldScene == scene) { 242 // Nothing to do 243 return; 244 } 245 // RT-21465, RT-28490 246 // We don't support scene changes in full-screen mode. 247 exitFullScreen(); 248 super.setScene(scene); 249 if (scene != null) { 250 GlassScene newScene = getViewScene(); 251 View view = newScene.getPlatformView(); 252 QuantumToolkit.runWithRenderLock(() -> { 253 platformWindow.setView(view); 254 if (oldScene != null) oldScene.updateSceneState(); 255 newScene.updateSceneState(); 256 return null; 257 }); 258 requestFocus(); 259 } else { 260 QuantumToolkit.runWithRenderLock(() -> { 261 // platformWindow can be null here, if this window is owned, 262 // and its owner is being closed. 263 if (platformWindow != null) { 264 platformWindow.setView(null); 265 } 266 if (oldScene != null) { 267 oldScene.updateSceneState(); 268 } 269 return null; 270 }); 271 } 272 if (oldScene != null) { 273 ViewPainter painter = ((ViewScene)oldScene).getPainter(); 274 QuantumRenderer.getInstance().disposePresentable(painter.presentable); // latched on RT 275 } 276 } 277 278 @Override public void setBounds(float x, float y, boolean xSet, boolean ySet, 279 float w, float h, float cw, float ch, 280 float xGravity, float yGravity) 281 { 282 if (isAppletStage) { 283 xSet = ySet = false; 284 } 285 float pScale = platformWindow.getPlatformScale(); 286 int px, py; 287 if (xSet || ySet) { 288 Screen screen = platformWindow.getScreen(); 289 List<Screen> screens = Screen.getScreens(); 290 if (screens.size() > 1) { 291 float wx = xSet ? x : platformWindow.getX(); 292 float wy = ySet ? y : platformWindow.getY(); 293 float relx = screen.getX() + screen.getWidth() / 2.0f - wx; 294 float rely = screen.getY() + screen.getHeight()/ 2.0f - wy; 295 float distsq = relx * relx + rely * rely; 296 for (Screen s : Screen.getScreens()) { 297 relx = s.getX() + s.getWidth() / 2.0f - wx; 298 rely = s.getY() + s.getHeight()/ 2.0f - wy; 299 float distsq2 = relx * relx + rely * rely; 300 if (distsq2 < distsq) { 301 screen = s; 302 distsq = distsq2; 303 } 304 } 305 } 306 float sx = screen == null ? 0 : screen.getX(); 307 float sy = screen == null ? 0 : screen.getY(); 308 px = xSet ? Math.round(sx + (x - sx) * pScale) : 0; 309 py = ySet ? Math.round(sy + (y - sy) * pScale) : 0; 310 } else { 311 px = py = 0; 312 } 313 int pw = (int) (w > 0 ? Math.ceil(w * pScale) : w); 314 int ph = (int) (h > 0 ? Math.ceil(h * pScale) : h); 315 int pcw = (int) (cw > 0 ? Math.ceil(cw * pScale) : cw); 316 int pch = (int) (ch > 0 ? Math.ceil(ch * pScale) : ch); 317 platformWindow.setBounds(px, py, xSet, ySet, 318 pw, ph, pcw, pch, 319 xGravity, yGravity); 320 } 321 322 @Override 323 public float getUIScale() { 324 return platformWindow.getPlatformScale(); 325 } 326 327 @Override 328 public float getRenderScale() { 329 return platformWindow.getRenderScale(); 330 } 331 332 @Override public void setMinimumSize(int minWidth, int minHeight) { 333 float pScale = platformWindow.getPlatformScale(); 334 minWidth = (int) Math.ceil(minWidth * pScale); 335 minHeight = (int) Math.ceil(minHeight * pScale); 336 platformWindow.setMinimumSize(minWidth, minHeight); 337 } 338 339 @Override public void setMaximumSize(int maxWidth, int maxHeight) { 340 float pScale = platformWindow.getPlatformScale(); 341 maxWidth = (int) Math.ceil(maxWidth * pScale); 342 maxHeight = (int) Math.ceil(maxHeight * pScale); 343 platformWindow.setMaximumSize(maxWidth, maxHeight); 344 } 345 346 static Image findBestImage(java.util.List icons, int width, int height) { 347 Image image = null; 348 double bestSimilarity = 3; //Impossibly high value 349 for (Object icon : icons) { 350 //Iterate imageList looking for best matching image. 351 //'Similarity' measure is defined as good scale factor and small insets. 352 //best possible similarity is 0 (no scale, no insets). 353 //It's found by experimentation that good-looking results are achieved 354 //with scale factors x1, x3/4, x2/3, xN, x1/N. 355 //Check to make sure the image/image format is correct. 356 Image im = (Image)icon; 357 if (im == null || !(im.getPixelFormat() == PixelFormat.BYTE_RGB || 358 im.getPixelFormat() == PixelFormat.BYTE_BGRA_PRE || 359 im.getPixelFormat() == PixelFormat.BYTE_GRAY)) 360 { 361 continue; 362 } 363 364 int iw = im.getWidth(); 365 int ih = im.getHeight(); 366 367 if (iw > 0 && ih > 0) { 368 //Calc scale factor 369 double scaleFactor = Math.min((double)width / (double)iw, 370 (double)height / (double)ih); 371 //Calculate scaled image dimensions 372 //adjusting scale factor to nearest "good" value 373 int adjw; 374 int adjh; 375 double scaleMeasure = 1; //0 - best (no) scale, 1 - impossibly bad 376 if (scaleFactor >= 2) { 377 //Need to enlarge image more than twice 378 //Round down scale factor to multiply by integer value 379 scaleFactor = Math.floor(scaleFactor); 380 adjw = iw * (int)scaleFactor; 381 adjh = ih * (int)scaleFactor; 382 scaleMeasure = 1.0 - 0.5 / scaleFactor; 383 } else if (scaleFactor >= 1) { 384 //Don't scale 385 scaleFactor = 1.0; 386 adjw = iw; 387 adjh = ih; 388 scaleMeasure = 0; 389 } else if (scaleFactor >= 0.75) { 390 //Multiply by 3/4 391 scaleFactor = 0.75; 392 adjw = iw * 3 / 4; 393 adjh = ih * 3 / 4; 394 scaleMeasure = 0.3; 395 } else if (scaleFactor >= 0.6666) { 396 //Multiply by 2/3 397 scaleFactor = 0.6666; 398 adjw = iw * 2 / 3; 399 adjh = ih * 2 / 3; 400 scaleMeasure = 0.33; 401 } else { 402 //Multiply size by 1/scaleDivider 403 //where scaleDivider is minimum possible integer 404 //larger than 1/scaleFactor 405 double scaleDivider = Math.ceil(1.0 / scaleFactor); 406 scaleFactor = 1.0 / scaleDivider; 407 adjw = (int)Math.round((double)iw / scaleDivider); 408 adjh = (int)Math.round((double)ih / scaleDivider); 409 scaleMeasure = 1.0 - 1.0 / scaleDivider; 410 } 411 double similarity = ((double)width - (double)adjw) / (double)width + 412 ((double)height - (double)adjh) / (double)height + //Large padding is bad 413 scaleMeasure; //Large rescale is bad 414 if (similarity < bestSimilarity) { 415 bestSimilarity = similarity; 416 image = im; 417 } 418 if (similarity == 0) break; 419 } 420 } 421 return image; 422 } 423 424 @Override public void setIcons(java.util.List icons) { 425 426 int SMALL_ICON_HEIGHT = 32; 427 int SMALL_ICON_WIDTH = 32; 428 if (PlatformUtil.isMac()) { //Mac Sized Icons 429 SMALL_ICON_HEIGHT = 128; 430 SMALL_ICON_WIDTH = 128; 431 } else if (PlatformUtil.isWindows()) { //Windows Sized Icons 432 SMALL_ICON_HEIGHT = 32; 433 SMALL_ICON_WIDTH = 32; 434 } else if (PlatformUtil.isLinux()) { //Linux icons 435 SMALL_ICON_HEIGHT = 128; 436 SMALL_ICON_WIDTH = 128; 437 } 438 439 if (icons == null || icons.size() < 1) { //no icons passed in 440 platformWindow.setIcon(null); 441 return; 442 } 443 444 Image image = findBestImage(icons, SMALL_ICON_WIDTH, SMALL_ICON_HEIGHT); 445 if (image == null) { 446 //No images were found, possibly all are broken 447 return; 448 } 449 450 PushbroomScaler scaler = ScalerFactory.createScaler(image.getWidth(), image.getHeight(), 451 image.getBytesPerPixelUnit(), 452 SMALL_ICON_WIDTH, SMALL_ICON_HEIGHT, true); 453 454 //shrink the image and convert the format to INT_ARGB_PRE 455 ByteBuffer buf = (ByteBuffer) image.getPixelBuffer(); 456 byte bytes[] = new byte[buf.limit()]; 457 458 int iheight = image.getHeight(); 459 460 //Iterate through each scanline of the image 461 //and pass it one at a time to the scaling object 462 for (int z = 0; z < iheight; z++) { 463 buf.position(z*image.getScanlineStride()); 464 buf.get(bytes, 0, image.getScanlineStride()); 465 scaler.putSourceScanline(bytes, 0); 466 } 467 468 buf.rewind(); 469 470 final Image img = image.iconify(scaler.getDestination(), SMALL_ICON_WIDTH, SMALL_ICON_HEIGHT); 471 platformWindow.setIcon(PixelUtils.imageToPixels(img)); 472 } 473 474 @Override public void setTitle(String title) { 475 platformWindow.setTitle(title); 476 } 477 478 @Override public void setVisible(final boolean visible) { 479 // Before setting visible to false on the native window, we unblock 480 // other windows. 481 if (!visible) { 482 removeActiveWindow(this); 483 if (modality == Modality.WINDOW_MODAL) { 484 if (owner != null && owner instanceof WindowStage) { 485 ((WindowStage) owner).setEnabled(true); 486 } 487 } else if (modality == Modality.APPLICATION_MODAL) { 488 windowsSetEnabled(true); 489 } else { 490 // Note: This method is required to workaround a glass issue 491 // mentioned in RT-12607 492 // If the hiding stage is unfocusable (i.e. it's a PopupStage), 493 // then we don't do this to avoid stealing the focus. 494 if (!isPopupStage && owner != null && owner instanceof WindowStage) { 495 WindowStage ownerStage = (WindowStage)owner; 496 ownerStage.requestToFront(); 497 } 498 } 499 } 500 QuantumToolkit.runWithRenderLock(() -> { 501 // platformWindow can be null here, if this window is owned, 502 // and its owner is being closed. 503 if (platformWindow != null) { 504 platformWindow.setVisible(visible); 505 } 506 super.setVisible(visible); 507 return null; 508 }); 509 // After setting visible to true on the native window, we block 510 // other windows. 511 if (visible) { 512 if (modality == Modality.WINDOW_MODAL) { 513 if (owner != null && owner instanceof WindowStage) { 514 ((WindowStage) owner).setEnabled(false); 515 } 516 } else if (modality == Modality.APPLICATION_MODAL) { 517 windowsSetEnabled(false); 518 } 519 if (isAppletStage && null != appletWindow) { 520 appletWindow.assertStageOrder(); 521 } 522 } 523 524 applyFullScreen(); 525 } 526 527 @Override boolean isVisible() { 528 return platformWindow.isVisible(); 529 } 530 531 @Override public void setOpacity(float opacity) { 532 platformWindow.setAlpha(opacity); 533 GlassScene gs = getScene(); 534 if (gs != null) { 535 gs.entireSceneNeedsRepaint(); 536 } 537 } 538 539 public boolean needsUpdateWindow() { 540 return transparent && (Application.GetApplication().shouldUpdateWindow()); 541 } 542 543 @Override public void setIconified(boolean iconified) { 544 if (platformWindow.isMinimized() == iconified) { 545 return; 546 } 547 platformWindow.minimize(iconified); 548 } 549 550 @Override public void setMaximized(boolean maximized) { 551 if (platformWindow.isMaximized() == maximized) { 552 return; 553 } 554 platformWindow.maximize(maximized); 555 } 556 557 @Override 558 public void setAlwaysOnTop(boolean alwaysOnTop) { 559 // The securityDialog flag takes precedence over alwaysOnTop 560 if (securityDialog) return; 561 562 if (alwaysOnTop) { 563 if (hasPermission(alwaysOnTopPermission)) { 564 platformWindow.setLevel(Level.FLOATING); 565 } 566 } else { 567 platformWindow.setLevel(Level.NORMAL); 568 } 569 570 } 571 572 @Override public void setResizable(boolean resizable) { 573 platformWindow.setResizable(resizable); 574 // note: for child windows this is ignored and we fail silently 575 } 576 577 // Return true if this stage is trusted for full screen - doesn't have a 578 // security manager, or a permission check doesn't result in a security 579 // exeception. 580 boolean isTrustedFullScreen() { 581 return hasPermission(fullScreenPermission); 582 } 583 584 // Safely exit full screen 585 void exitFullScreen() { 586 setFullScreen(false); 587 } 588 589 boolean isApplet() { 590 return isPrimaryStage && null != appletWindow; 591 } 592 593 private boolean hasPermission(Permission perm) { 594 try { 595 final SecurityManager sm = System.getSecurityManager(); 596 if (sm != null) { 597 sm.checkPermission(perm, getAccessControlContext()); 598 } 599 return true; 600 } catch (SecurityException se) { 601 return false; 602 } 603 } 604 605 // We may need finer-grained permissions in the future, but for 606 // now AllPermission is good enough to do the job we need, such 607 // as fullscreen support for signed/unsigned application. 608 private static final Permission fullScreenPermission = new AllPermission(); 609 private static final Permission alwaysOnTopPermission = new AllPermission(); 610 611 private boolean fullScreenFromUserEvent = false; 612 613 private KeyCombination savedFullScreenExitKey = null; 614 615 public final KeyCombination getSavedFullScreenExitKey() { 616 return savedFullScreenExitKey; 617 } 618 619 private void applyFullScreen() { 620 if (platformWindow == null) { 621 // applyFullScreen() can be called from setVisible(false), while the 622 // platformWindow has already been destroyed. 623 return; 624 } 625 View v = platformWindow.getView(); 626 if (isVisible() && v != null && v.isInFullscreen() != isInFullScreen) { 627 if (isInFullScreen) { 628 // Check whether app is full screen trusted or flag is set 629 // indicating that the fullscreen request came from an input 630 // event handler. 631 // If not notify the stageListener to reset fullscreen to false. 632 final boolean isTrusted = isTrustedFullScreen(); 633 if (!isTrusted && !fullScreenFromUserEvent) { 634 exitFullScreen(); 635 fullscreenChanged(false); 636 } else { 637 v.enterFullscreen(false, false, false); 638 if (warning != null && warning.inWarningTransition()) { 639 warning.setView(getViewScene()); 640 } else { 641 boolean showWarning = true; 642 643 KeyCombination key = null; 644 String exitMessage = null; 645 646 if (isTrusted && (fxStage != null)) { 647 // copy the user set definitions for later use. 648 key = fxStage.getFullScreenExitKeyCombination(); 649 650 exitMessage = fxStage.getFullScreenExitHint(); 651 } 652 653 savedFullScreenExitKey = 654 key == null 655 ? defaultFullScreenExitKeycombo 656 : key; 657 658 if ( 659 // the hint is "" 660 "".equals(exitMessage) || 661 // if the key is NO_MATCH 662 (savedFullScreenExitKey.equals(KeyCombination.NO_MATCH)) 663 ) { 664 showWarning = false; 665 } 666 667 // the hint is not set, use the key for the message 668 if (showWarning && exitMessage == null) { 669 if (key == null) { 670 exitMessage = RESOURCES.getString("OverlayWarningESC"); 671 } else { 672 String f = RESOURCES.getString("OverlayWarningKey"); 673 exitMessage = f.format(f, savedFullScreenExitKey.toString()); 674 } 675 } 676 677 if (showWarning && warning == null) { 678 setWarning(new OverlayWarning(getViewScene())); 679 } 680 681 if (showWarning && warning != null) { 682 warning.warn(exitMessage); 683 } 684 } 685 } 686 } else { 687 if (warning != null) { 688 warning.cancel(); 689 setWarning(null); 690 } 691 v.exitFullscreen(false); 692 } 693 // Reset flag once we are done process fullscreen 694 fullScreenFromUserEvent = false; 695 } else if (!isVisible() && warning != null) { 696 // if the window is closed - re-open with fresh warning 697 warning.cancel(); 698 setWarning(null); 699 } 700 } 701 702 void setWarning(OverlayWarning newWarning) { 703 this.warning = newWarning; 704 getViewScene().synchroniseOverlayWarning(); 705 } 706 707 OverlayWarning getWarning() { 708 return warning; 709 } 710 711 @Override public void setFullScreen(boolean fullScreen) { 712 if (isInFullScreen == fullScreen) { 713 return; 714 } 715 716 // Set a flag indicating whether this method was called from 717 // an input event handler. 718 if (isInEventHandler()) { 719 fullScreenFromUserEvent = true; 720 } 721 722 GlassStage fsWindow = activeFSWindow.get(); 723 if (fullScreen && (fsWindow != null)) { 724 fsWindow.setFullScreen(false); 725 } 726 isInFullScreen = fullScreen; 727 applyFullScreen(); 728 if (fullScreen) { 729 activeFSWindow.set(this); 730 } 731 } 732 733 void fullscreenChanged(final boolean fs) { 734 if (!fs) { 735 if (activeFSWindow.compareAndSet(this, null)) { 736 isInFullScreen = false; 737 } 738 } else { 739 isInFullScreen = true; 740 activeFSWindow.set(this); 741 } 742 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 743 if (stageListener != null) { 744 stageListener.changedFullscreen(fs); 745 } 746 return null; 747 }, getAccessControlContext()); 748 } 749 750 @Override public void toBack() { 751 platformWindow.toBack(); 752 if (isAppletStage && null != appletWindow) { 753 appletWindow.assertStageOrder(); 754 } 755 } 756 757 @Override public void toFront() { 758 platformWindow.requestFocus(); // RT-17836 759 platformWindow.toFront(); 760 if (isAppletStage && null != appletWindow) { 761 appletWindow.assertStageOrder(); 762 } 763 } 764 765 @Override public void close() { 766 super.close(); 767 QuantumToolkit.runWithRenderLock(() -> { 768 // prevents closing a closed platform window 769 if (platformWindow != null) { 770 platformWindows.remove(platformWindow); 771 platformWindow.close(); 772 platformWindow = null; 773 } 774 GlassScene oldScene = getViewScene(); 775 if (oldScene != null) { 776 oldScene.updateSceneState(); 777 } 778 return null; 779 }); 780 } 781 782 // setPlatformWindowClosed is only set upon receiving platform window has 783 // closed notification. This state is necessary to prevent the platform 784 // window from being closed more than once. 785 void setPlatformWindowClosed() { 786 platformWindow = null; 787 } 788 789 static void addActiveWindow(WindowStage window) { 790 activeWindows.remove(window); 791 activeWindows.add(window); 792 } 793 794 static void removeActiveWindow(WindowStage window) { 795 activeWindows.remove(window); 796 } 797 798 final void handleFocusDisabled() { 799 if (activeWindows.isEmpty()) { 800 return; 801 } 802 WindowStage window = activeWindows.get(activeWindows.size() - 1); 803 window.setIconified(false); 804 window.requestToFront(); 805 window.requestFocus(); 806 } 807 808 @Override public boolean grabFocus() { 809 return platformWindow.grabFocus(); 810 } 811 812 @Override public void ungrabFocus() { 813 platformWindow.ungrabFocus(); 814 } 815 816 @Override public void requestFocus() { 817 platformWindow.requestFocus(); 818 } 819 820 @Override public void requestFocus(FocusCause cause) { 821 switch (cause) { 822 case TRAVERSED_FORWARD: 823 platformWindow.requestFocus(WindowEvent.FOCUS_GAINED_FORWARD); 824 break; 825 case TRAVERSED_BACKWARD: 826 platformWindow.requestFocus(WindowEvent.FOCUS_GAINED_BACKWARD); 827 break; 828 case ACTIVATED: 829 platformWindow.requestFocus(WindowEvent.FOCUS_GAINED); 830 break; 831 case DEACTIVATED: 832 platformWindow.requestFocus(WindowEvent.FOCUS_LOST); 833 break; 834 } 835 } 836 837 @Override 838 protected void setPlatformEnabled(boolean enabled) { 839 super.setPlatformEnabled(enabled); 840 platformWindow.setEnabled(enabled); 841 if (enabled) { 842 // Check if window is really enabled - to handle nested case 843 if (platformWindow.isEnabled()) { 844 requestToFront(); 845 } 846 } else { 847 removeActiveWindow(this); 848 } 849 } 850 851 void setEnabled(boolean enabled) { 852 if ((owner != null) && (owner instanceof WindowStage)) { 853 ((WindowStage) owner).setEnabled(enabled); 854 } 855 /* 856 * RT-17588 - exit if stage is closed from under us as 857 * any further access to the Glass layer 858 * will throw an exception 859 */ 860 if (enabled && (platformWindow == null || platformWindow.isClosed())) { 861 return; 862 } 863 setPlatformEnabled(enabled); 864 if (enabled) { 865 if (isAppletStage && null != appletWindow) { 866 appletWindow.assertStageOrder(); 867 } 868 } 869 } 870 871 // Note: This method is required to workaround a glass issue mentioned in RT-12607 872 protected void requestToFront() { 873 if (platformWindow != null) { 874 platformWindow.toFront(); 875 platformWindow.requestFocus(); 876 } 877 } 878 879 public void setInEventHandler(boolean inEventHandler) { 880 this.inEventHandler = inEventHandler; 881 } 882 883 public boolean isInEventHandler() { 884 return inEventHandler; 885 } 886 887 @Override 888 public void requestInput(String text, int type, double width, double height, 889 double Mxx, double Mxy, double Mxz, double Mxt, 890 double Myx, double Myy, double Myz, double Myt, 891 double Mzx, double Mzy, double Mzz, double Mzt) { 892 platformWindow.requestInput(text, type, width, height, 893 Mxx, Mxy, Mxz, Mxt, 894 Myx, Myy, Myz, Myt, 895 Mzx, Mzy, Mzz, Mzt); 896 } 897 898 @Override 899 public void releaseInput() { 900 platformWindow.releaseInput(); 901 } 902 903 @Override public void setRTL(boolean b) { 904 rtl = b; 905 } 906 907 }