1 /* 2 * Copyright (c) 1996, 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 package sun.awt.windows; 26 27 import java.awt.*; 28 import java.awt.event.*; 29 import java.awt.image.*; 30 import java.awt.peer.*; 31 32 import java.beans.*; 33 34 import java.util.*; 35 import java.util.List; 36 import sun.util.logging.PlatformLogger; 37 import java.awt.geom.AffineTransform; 38 import sun.awt.*; 39 40 import sun.java2d.pipe.Region; 41 import sun.swing.SwingUtilities2; 42 43 public class WWindowPeer extends WPanelPeer implements WindowPeer, 44 DisplayChangedListener 45 { 46 47 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WWindowPeer"); 48 private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.windows.screen.WWindowPeer"); 49 50 // we can't use WDialogPeer as blocker may be an instance of WPrintDialogPeer that 51 // extends WWindowPeer, not WDialogPeer 52 private WWindowPeer modalBlocker = null; 53 54 private boolean isOpaque; 55 56 private TranslucentWindowPainter painter; 57 58 /* 59 * A key used for storing a list of active windows in AppContext. The value 60 * is a list of windows, sorted by the time of activation: later a window is 61 * activated, greater its index is in the list. 62 */ 63 private static final StringBuffer ACTIVE_WINDOWS_KEY = 64 new StringBuffer("active_windows_list"); 65 66 /* 67 * Listener for 'activeWindow' KFM property changes. It is added to each 68 * AppContext KFM. See ActiveWindowListener inner class below. 69 */ 70 private static PropertyChangeListener activeWindowListener = 71 new ActiveWindowListener(); 72 73 /* 74 * The object is a listener for the AppContext.GUI_DISPOSED property. 75 */ 76 private static final PropertyChangeListener guiDisposedListener = 77 new GuiDisposedListener(); 78 79 /* 80 * Called (on the Toolkit thread) before the appropriate 81 * WindowStateEvent is posted to the EventQueue. 82 */ 83 private WindowListener windowListener; 84 private float scaleX; 85 private float scaleY; 86 87 /** 88 * Initialize JNI field IDs 89 */ 90 private static native void initIDs(); 91 static { 92 initIDs(); 93 } 94 95 // WComponentPeer overrides 96 @Override 97 @SuppressWarnings("unchecked") 98 protected void disposeImpl() { 99 AppContext appContext = SunToolkit.targetToAppContext(target); 100 synchronized (appContext) { 101 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 102 if (l != null) { 103 l.remove(this); 104 } 105 } 106 107 // Remove ourself from the Map of DisplayChangeListeners 108 GraphicsConfiguration gc = getGraphicsConfiguration(); 109 ((Win32GraphicsDevice)gc.getDevice()).removeDisplayChangedListener(this); 110 111 synchronized (getStateLock()) { 112 TranslucentWindowPainter currentPainter = painter; 113 if (currentPainter != null) { 114 currentPainter.flush(); 115 // don't set the current one to null here; reduces the chances of 116 // MT issues (like NPEs) 117 } 118 } 119 120 super.disposeImpl(); 121 } 122 123 // WindowPeer implementation 124 125 @Override 126 public void toFront() { 127 updateFocusableWindowState(); 128 _toFront(); 129 } 130 private native void _toFront(); 131 132 @Override 133 public native void toBack(); 134 135 private native void setAlwaysOnTopNative(boolean value); 136 137 public void setAlwaysOnTop(boolean value) { 138 if ((value && ((Window)target).isVisible()) || !value) { 139 setAlwaysOnTopNative(value); 140 } 141 } 142 143 @Override 144 public void updateAlwaysOnTopState() { 145 setAlwaysOnTop(((Window)target).isAlwaysOnTop()); 146 } 147 148 @Override 149 public void updateFocusableWindowState() { 150 setFocusableWindow(((Window)target).isFocusableWindow()); 151 } 152 native void setFocusableWindow(boolean value); 153 154 // FramePeer & DialogPeer partial shared implementation 155 156 public void setTitle(String title) { 157 // allow a null title to pass as an empty string. 158 if (title == null) { 159 title = ""; 160 } 161 _setTitle(title); 162 } 163 private native void _setTitle(String title); 164 165 public void setResizable(boolean resizable) { 166 _setResizable(resizable); 167 } 168 169 private native void _setResizable(boolean resizable); 170 171 // Toolkit & peer internals 172 173 WWindowPeer(Window target) { 174 super(target); 175 } 176 177 @Override 178 void initialize() { 179 super.initialize(); 180 181 updateInsets(insets_); 182 183 if (!((Window) target).isFontSet()) { 184 ((Window) target).setFont(defaultFont); 185 setFont(defaultFont); 186 } 187 if (!((Window) target).isForegroundSet()) { 188 ((Window) target).setForeground(SystemColor.windowText); 189 } 190 if (!((Window) target).isBackgroundSet()) { 191 ((Window) target).setBackground(SystemColor.window); 192 } 193 194 // Express our interest in display changes 195 GraphicsConfiguration gc = getGraphicsConfiguration(); 196 Win32GraphicsDevice gd = (Win32GraphicsDevice) gc.getDevice(); 197 gd.addDisplayChangedListener(this); 198 scaleX = gd.getDefaultScaleX(); 199 scaleY = gd.getDefaultScaleY(); 200 201 initActiveWindowsTracking((Window)target); 202 203 updateIconImages(); 204 205 Shape shape = ((Window)target).getShape(); 206 if (shape != null) { 207 applyShape(Region.getInstance(shape, null)); 208 } 209 210 float opacity = ((Window)target).getOpacity(); 211 if (opacity < 1.0f) { 212 setOpacity(opacity); 213 } 214 215 synchronized (getStateLock()) { 216 // default value of a boolean field is 'false', so set isOpaque to 217 // true here explicitly 218 this.isOpaque = true; 219 setOpaque(((Window)target).isOpaque()); 220 } 221 } 222 223 native void createAwtWindow(WComponentPeer parent); 224 225 private volatile Window.Type windowType = Window.Type.NORMAL; 226 227 // This method must be called for Window, Dialog, and Frame before creating 228 // the hwnd 229 void preCreate(WComponentPeer parent) { 230 windowType = ((Window)target).getType(); 231 } 232 233 @Override 234 void create(WComponentPeer parent) { 235 preCreate(parent); 236 createAwtWindow(parent); 237 } 238 239 @Override 240 final WComponentPeer getNativeParent() { 241 final Container owner = ((Window) target).getOwner(); 242 return (WComponentPeer) WToolkit.targetToPeer(owner); 243 } 244 245 // should be overriden in WDialogPeer 246 protected void realShow() { 247 super.show(); 248 } 249 250 @Override 251 public void show() { 252 updateFocusableWindowState(); 253 254 boolean alwaysOnTop = ((Window)target).isAlwaysOnTop(); 255 256 // Fix for 4868278. 257 // If we create a window with a specific GraphicsConfig, and then move it with 258 // setLocation() or setBounds() to another one before its peer has been created, 259 // then calling Window.getGraphicsConfig() returns wrong config. That may lead 260 // to some problems like wrong-placed tooltips. It is caused by calling 261 // super.displayChanged() in WWindowPeer.displayChanged() regardless of whether 262 // GraphicsDevice was really changed, or not. So we need to track it here. 263 updateGC(); 264 265 realShow(); 266 updateMinimumSize(); 267 268 if (((Window)target).isAlwaysOnTopSupported() && alwaysOnTop) { 269 setAlwaysOnTop(alwaysOnTop); 270 } 271 272 synchronized (getStateLock()) { 273 if (!isOpaque) { 274 updateWindow(true); 275 } 276 } 277 278 // See https://javafx-jira.kenai.com/browse/RT-32570 279 WComponentPeer owner = getNativeParent(); 280 if (owner != null && owner.isLightweightFramePeer()) { 281 Rectangle b = getBounds(); 282 handleExpose(0, 0, b.width, b.height); 283 } 284 } 285 286 // Synchronize the insets members (here & in helper) with actual window 287 // state. 288 native void updateInsets(Insets i); 289 290 static native int getSysMinWidth(); 291 static native int getSysMinHeight(); 292 static native int getSysIconWidth(); 293 static native int getSysIconHeight(); 294 static native int getSysSmIconWidth(); 295 static native int getSysSmIconHeight(); 296 /**windows/classes/sun/awt/windows/ 297 * Creates native icon from specified raster data and updates 298 * icon for window and all descendant windows that inherit icon. 299 * Raster data should be passed in the ARGB form. 300 * Note that raster data format was changed to provide support 301 * for XP icons with alpha-channel 302 */ 303 native void setIconImagesData(int[] iconRaster, int w, int h, 304 int[] smallIconRaster, int smw, int smh); 305 306 synchronized native void reshapeFrame(int x, int y, int width, int height); 307 308 native Dimension getNativeWindowSize(); 309 310 public Dimension getScaledWindowSize() { 311 return getNativeWindowSize(); 312 } 313 314 public boolean requestWindowFocus(FocusEvent.Cause cause) { 315 if (!focusAllowedFor()) { 316 return false; 317 } 318 return requestWindowFocus(cause == FocusEvent.Cause.MOUSE_EVENT); 319 } 320 private native boolean requestWindowFocus(boolean isMouseEventCause); 321 322 public boolean focusAllowedFor() { 323 Window window = (Window)this.target; 324 if (!window.isVisible() || 325 !window.isEnabled() || 326 !window.isFocusableWindow()) 327 { 328 return false; 329 } 330 if (isModalBlocked()) { 331 return false; 332 } 333 return true; 334 } 335 336 @Override 337 void hide() { 338 WindowListener listener = windowListener; 339 if (listener != null) { 340 // We're not getting WINDOW_CLOSING from the native code when hiding 341 // the window programmatically. So, create it and notify the listener. 342 listener.windowClosing(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); 343 } 344 super.hide(); 345 } 346 347 // WARNING: it's called on the Toolkit thread! 348 @Override 349 void preprocessPostEvent(AWTEvent event) { 350 if (event instanceof WindowEvent) { 351 WindowListener listener = windowListener; 352 if (listener != null) { 353 switch(event.getID()) { 354 case WindowEvent.WINDOW_CLOSING: 355 listener.windowClosing((WindowEvent)event); 356 break; 357 case WindowEvent.WINDOW_ICONIFIED: 358 listener.windowIconified((WindowEvent)event); 359 break; 360 } 361 } 362 } 363 } 364 365 synchronized void addWindowListener(WindowListener l) { 366 windowListener = AWTEventMulticaster.add(windowListener, l); 367 } 368 369 synchronized void removeWindowListener(WindowListener l) { 370 windowListener = AWTEventMulticaster.remove(windowListener, l); 371 } 372 373 @Override 374 public void updateMinimumSize() { 375 Dimension minimumSize = null; 376 if (((Component)target).isMinimumSizeSet()) { 377 minimumSize = ((Component)target).getMinimumSize(); 378 } 379 if (minimumSize != null) { 380 int msw = getSysMinWidth(); 381 int msh = getSysMinHeight(); 382 int w = (minimumSize.width >= msw) ? minimumSize.width : msw; 383 int h = (minimumSize.height >= msh) ? minimumSize.height : msh; 384 setMinSize(w, h); 385 } else { 386 setMinSize(0, 0); 387 } 388 } 389 390 @Override 391 public void updateIconImages() { 392 java.util.List<Image> imageList = ((Window)target).getIconImages(); 393 if (imageList == null || imageList.size() == 0) { 394 setIconImagesData(null, 0, 0, null, 0, 0); 395 } else { 396 int w = getSysIconWidth(); 397 int h = getSysIconHeight(); 398 int smw = getSysSmIconWidth(); 399 int smh = getSysSmIconHeight(); 400 AffineTransform tx = getGraphicsConfiguration().getDefaultTransform(); 401 w = Region.clipScale(w, tx.getScaleX()); 402 h = Region.clipScale(h, tx.getScaleY()); 403 smw = Region.clipScale(smw, tx.getScaleX()); 404 smh = Region.clipScale(smh, tx.getScaleY()); 405 DataBufferInt iconData = SunToolkit.getScaledIconData(imageList, 406 w, h); 407 DataBufferInt iconSmData = SunToolkit.getScaledIconData(imageList, 408 smw, smh); 409 if (iconData != null && iconSmData != null) { 410 setIconImagesData(iconData.getData(), w, h, 411 iconSmData.getData(), smw, smh); 412 } else { 413 setIconImagesData(null, 0, 0, null, 0, 0); 414 } 415 } 416 } 417 418 native void setMinSize(int width, int height); 419 420 /* 421 * ---- MODALITY SUPPORT ---- 422 */ 423 424 /** 425 * Some modality-related code here because WFileDialogPeer, WPrintDialogPeer and 426 * WPageDialogPeer are descendants of WWindowPeer, not WDialogPeer 427 */ 428 429 public boolean isModalBlocked() { 430 return modalBlocker != null; 431 } 432 433 @Override 434 public void setModalBlocked(Dialog dialog, boolean blocked) { 435 synchronized (((Component)getTarget()).getTreeLock()) // State lock should always be after awtLock 436 { 437 // use WWindowPeer instead of WDialogPeer because of FileDialogs and PrintDialogs 438 WWindowPeer blockerPeer = AWTAccessor.getComponentAccessor() 439 .getPeer(dialog); 440 if (blocked) 441 { 442 modalBlocker = blockerPeer; 443 // handle native dialogs separately, as they may have not 444 // got HWND yet; modalEnable/modalDisable is called from 445 // their setHWnd() methods 446 if (blockerPeer instanceof WFileDialogPeer) { 447 ((WFileDialogPeer)blockerPeer).blockWindow(this); 448 } else if (blockerPeer instanceof WPrintDialogPeer) { 449 ((WPrintDialogPeer)blockerPeer).blockWindow(this); 450 } else { 451 modalDisable(dialog, blockerPeer.getHWnd()); 452 } 453 } else { 454 modalBlocker = null; 455 if (blockerPeer instanceof WFileDialogPeer) { 456 ((WFileDialogPeer)blockerPeer).unblockWindow(this); 457 } else if (blockerPeer instanceof WPrintDialogPeer) { 458 ((WPrintDialogPeer)blockerPeer).unblockWindow(this); 459 } else { 460 modalEnable(dialog); 461 } 462 } 463 } 464 } 465 466 native void modalDisable(Dialog blocker, long blockerHWnd); 467 native void modalEnable(Dialog blocker); 468 469 /* 470 * Returns all the ever active windows from the current AppContext. 471 * The list is sorted by the time of activation, so the latest 472 * active window is always at the end. 473 */ 474 @SuppressWarnings("unchecked") 475 public static long[] getActiveWindowHandles(Component target) { 476 AppContext appContext = SunToolkit.targetToAppContext(target); 477 if (appContext == null) return null; 478 synchronized (appContext) { 479 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 480 if (l == null) { 481 return null; 482 } 483 long[] result = new long[l.size()]; 484 for (int j = 0; j < l.size(); j++) { 485 result[j] = l.get(j).getHWnd(); 486 } 487 return result; 488 } 489 } 490 491 /* 492 * ----DISPLAY CHANGE SUPPORT---- 493 */ 494 495 /* 496 * Called from native code when we have been dragged onto another screen. 497 */ 498 void draggedToNewScreen() { 499 SunToolkit.executeOnEventHandlerThread((Component)target,new Runnable() 500 { 501 @Override 502 public void run() { 503 displayChanged(); 504 } 505 }); 506 } 507 508 public void updateGC() { 509 int scrn = getScreenImOn(); 510 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 511 log.finer("Screen number: " + scrn); 512 } 513 514 // get current GD 515 Win32GraphicsDevice oldDev = winGraphicsConfig.getDevice(); 516 517 Win32GraphicsDevice newDev; 518 GraphicsDevice devs[] = GraphicsEnvironment 519 .getLocalGraphicsEnvironment() 520 .getScreenDevices(); 521 // Occasionally during device addition/removal getScreenImOn can return 522 // a non-existing screen number. Use the default device in this case. 523 if (scrn >= devs.length) { 524 newDev = (Win32GraphicsDevice)GraphicsEnvironment 525 .getLocalGraphicsEnvironment().getDefaultScreenDevice(); 526 } else { 527 newDev = (Win32GraphicsDevice)devs[scrn]; 528 } 529 530 // Set winGraphicsConfig to the default GC for the monitor this Window 531 // is now mostly on. 532 winGraphicsConfig = (Win32GraphicsConfig)newDev 533 .getDefaultConfiguration(); 534 if (screenLog.isLoggable(PlatformLogger.Level.FINE)) { 535 if (winGraphicsConfig == null) { 536 screenLog.fine("Assertion (winGraphicsConfig != null) failed"); 537 } 538 } 539 540 // if on a different display, take off old GD and put on new GD 541 if (oldDev != newDev) { 542 oldDev.removeDisplayChangedListener(this); 543 newDev.addDisplayChangedListener(this); 544 } 545 546 AWTAccessor.getComponentAccessor(). 547 setGraphicsConfiguration((Component)target, winGraphicsConfig); 548 549 checkDPIChange(oldDev, newDev); 550 } 551 552 private void checkDPIChange(Win32GraphicsDevice oldDev, 553 Win32GraphicsDevice newDev) { 554 float newScaleX = newDev.getDefaultScaleX(); 555 float newScaleY = newDev.getDefaultScaleY(); 556 557 if (scaleX != newScaleX || scaleY != newScaleY) { 558 windowDPIChange(oldDev.getScreen(), scaleX, scaleY, 559 newDev.getScreen(), newScaleX, newScaleY); 560 scaleX = newScaleX; 561 scaleY = newScaleY; 562 } 563 } 564 565 /** 566 * From the DisplayChangedListener interface. 567 * 568 * This method handles a display change - either when the display settings 569 * are changed, or when the window has been dragged onto a different 570 * display. 571 * Called after a change in the display mode. This event 572 * triggers replacing the surfaceData object (since that object 573 * reflects the current display depth information, which has 574 * just changed). 575 */ 576 @Override 577 public void displayChanged() { 578 updateGC(); 579 } 580 581 /** 582 * Part of the DisplayChangedListener interface: components 583 * do not need to react to this event 584 */ 585 @Override 586 public void paletteChanged() { 587 } 588 589 private native int getScreenImOn(); 590 591 // Used in Win32GraphicsDevice. 592 public final native void setFullScreenExclusiveModeState(boolean state); 593 594 /* 595 * ----END DISPLAY CHANGE SUPPORT---- 596 */ 597 598 public void grab() { 599 nativeGrab(); 600 } 601 602 public void ungrab() { 603 nativeUngrab(); 604 } 605 private native void nativeGrab(); 606 private native void nativeUngrab(); 607 608 private final boolean hasWarningWindow() { 609 return ((Window)target).getWarningString() != null; 610 } 611 612 boolean isTargetUndecorated() { 613 return true; 614 } 615 616 // These are the peer bounds. They get updated at: 617 // 1. the WWindowPeer.setBounds() method. 618 // 2. the native code (on WM_SIZE/WM_MOVE) 619 private volatile int sysX = 0; 620 private volatile int sysY = 0; 621 private volatile int sysW = 0; 622 private volatile int sysH = 0; 623 624 @Override 625 public native void repositionSecurityWarning(); 626 627 @Override 628 public void setBounds(int x, int y, int width, int height, int op) { 629 sysX = x; 630 sysY = y; 631 sysW = width; 632 sysH = height; 633 634 int cx = x + width / 2; 635 int cy = y + height / 2; 636 GraphicsConfiguration current = getGraphicsConfiguration(); 637 GraphicsConfiguration other = SwingUtilities2.getGraphicsConfigurationAtPoint(current, cx, cy); 638 if (!current.equals(other)) { 639 AffineTransform tx = other.getDefaultTransform(); 640 double otherScaleX = tx.getScaleX(); 641 double otherScaleY = tx.getScaleY(); 642 initScales(); 643 if (scaleX != otherScaleX || scaleY != otherScaleY) { 644 x = (int) Math.floor(x * otherScaleX / scaleX); 645 y = (int) Math.floor(y * otherScaleY / scaleY); 646 } 647 } 648 649 super.setBounds(x, y, width, height, op); 650 } 651 652 private final void initScales() { 653 654 if (scaleX >= 1 && scaleY >= 1) { 655 return; 656 } 657 658 GraphicsConfiguration gc = getGraphicsConfiguration(); 659 if (gc instanceof Win32GraphicsConfig) { 660 Win32GraphicsDevice gd = ((Win32GraphicsConfig) gc).getDevice(); 661 scaleX = gd.getDefaultScaleX(); 662 scaleY = gd.getDefaultScaleY(); 663 } else { 664 AffineTransform tx = gc.getDefaultTransform(); 665 scaleX = (float) tx.getScaleX(); 666 scaleY = (float) tx.getScaleY(); 667 } 668 } 669 670 @Override 671 public void print(Graphics g) { 672 // We assume we print the whole frame, 673 // so we expect no clip was set previously 674 Shape shape = AWTAccessor.getWindowAccessor().getShape((Window)target); 675 if (shape != null) { 676 g.setClip(shape); 677 } 678 super.print(g); 679 } 680 681 private void replaceSurfaceDataRecursively(Component c) { 682 if (c instanceof Container) { 683 for (Component child : ((Container)c).getComponents()) { 684 replaceSurfaceDataRecursively(child); 685 } 686 } 687 final Object cp = AWTAccessor.getComponentAccessor().getPeer(c); 688 if (cp instanceof WComponentPeer) { 689 ((WComponentPeer)cp).replaceSurfaceDataLater(); 690 } 691 } 692 693 public final Graphics getTranslucentGraphics() { 694 synchronized (getStateLock()) { 695 return isOpaque ? null : painter.getBackBuffer(false).getGraphics(); 696 } 697 } 698 699 @Override 700 public void setBackground(Color c) { 701 super.setBackground(c); 702 synchronized (getStateLock()) { 703 if (!isOpaque && ((Window)target).isVisible()) { 704 updateWindow(true); 705 } 706 } 707 } 708 709 private native void setOpacity(int iOpacity); 710 private float opacity = 1.0f; 711 712 @Override 713 public void setOpacity(float opacity) { 714 if (!((SunToolkit)((Window)target).getToolkit()). 715 isWindowOpacitySupported()) 716 { 717 return; 718 } 719 720 if (opacity < 0.0f || opacity > 1.0f) { 721 throw new IllegalArgumentException( 722 "The value of opacity should be in the range [0.0f .. 1.0f]."); 723 } 724 725 if (((this.opacity == 1.0f && opacity < 1.0f) || 726 (this.opacity < 1.0f && opacity == 1.0f)) && 727 !Win32GraphicsEnvironment.isVistaOS()) 728 { 729 // non-Vista OS: only replace the surface data if opacity status 730 // changed (see WComponentPeer.isAccelCapable() for more) 731 replaceSurfaceDataRecursively((Component)getTarget()); 732 } 733 734 this.opacity = opacity; 735 736 final int maxOpacity = 0xff; 737 int iOpacity = (int)(opacity * maxOpacity); 738 if (iOpacity < 0) { 739 iOpacity = 0; 740 } 741 if (iOpacity > maxOpacity) { 742 iOpacity = maxOpacity; 743 } 744 745 setOpacity(iOpacity); 746 747 synchronized (getStateLock()) { 748 if (!isOpaque && ((Window)target).isVisible()) { 749 updateWindow(true); 750 } 751 } 752 } 753 754 private native void setOpaqueImpl(boolean isOpaque); 755 756 @Override 757 public void setOpaque(boolean isOpaque) { 758 synchronized (getStateLock()) { 759 if (this.isOpaque == isOpaque) { 760 return; 761 } 762 } 763 764 Window target = (Window)getTarget(); 765 766 if (!isOpaque) { 767 SunToolkit sunToolkit = (SunToolkit)target.getToolkit(); 768 if (!sunToolkit.isWindowTranslucencySupported() || 769 !sunToolkit.isTranslucencyCapable(target.getGraphicsConfiguration())) 770 { 771 return; 772 } 773 } 774 775 boolean isVistaOS = Win32GraphicsEnvironment.isVistaOS(); 776 777 if (this.isOpaque != isOpaque && !isVistaOS) { 778 // non-Vista OS: only replace the surface data if the opacity 779 // status changed (see WComponentPeer.isAccelCapable() for more) 780 replaceSurfaceDataRecursively(target); 781 } 782 783 synchronized (getStateLock()) { 784 this.isOpaque = isOpaque; 785 setOpaqueImpl(isOpaque); 786 if (isOpaque) { 787 TranslucentWindowPainter currentPainter = painter; 788 if (currentPainter != null) { 789 currentPainter.flush(); 790 painter = null; 791 } 792 } else { 793 painter = TranslucentWindowPainter.createInstance(this); 794 } 795 } 796 797 if (isVistaOS) { 798 // On Vista: setting the window non-opaque makes the window look 799 // rectangular, though still catching the mouse clicks within 800 // its shape only. To restore the correct visual appearance 801 // of the window (i.e. w/ the correct shape) we have to reset 802 // the shape. 803 Shape shape = target.getShape(); 804 if (shape != null) { 805 target.setShape(shape); 806 } 807 } 808 809 if (target.isVisible()) { 810 updateWindow(true); 811 } 812 } 813 814 native void updateWindowImpl(int[] data, int width, int height); 815 816 @Override 817 public void updateWindow() { 818 updateWindow(false); 819 } 820 821 private void updateWindow(boolean repaint) { 822 Window w = (Window)target; 823 synchronized (getStateLock()) { 824 if (isOpaque || !w.isVisible() || 825 (w.getWidth() <= 0) || (w.getHeight() <= 0)) 826 { 827 return; 828 } 829 TranslucentWindowPainter currentPainter = painter; 830 if (currentPainter != null) { 831 currentPainter.updateWindow(repaint); 832 } else if (log.isLoggable(PlatformLogger.Level.FINER)) { 833 log.finer("Translucent window painter is null in updateWindow"); 834 } 835 } 836 } 837 838 native void windowDPIChange(int prevScreen, float prevScaleX, float prevScaleY, 839 int newScreen, float newScaleX, float newScaleY); 840 841 /* 842 * The method maps the list of the active windows to the window's AppContext, 843 * then the method registers ActiveWindowListener, GuiDisposedListener listeners; 844 * it executes the initilialization only once per AppContext. 845 */ 846 @SuppressWarnings("unchecked") 847 private static void initActiveWindowsTracking(Window w) { 848 AppContext appContext = AppContext.getAppContext(); 849 synchronized (appContext) { 850 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 851 if (l == null) { 852 l = new LinkedList<WWindowPeer>(); 853 appContext.put(ACTIVE_WINDOWS_KEY, l); 854 appContext.addPropertyChangeListener(AppContext.GUI_DISPOSED, guiDisposedListener); 855 856 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 857 kfm.addPropertyChangeListener("activeWindow", activeWindowListener); 858 } 859 } 860 } 861 862 /* 863 * The GuiDisposedListener class listens for the AppContext.GUI_DISPOSED property, 864 * it removes the list of the active windows from the disposed AppContext and 865 * unregisters ActiveWindowListener listener. 866 */ 867 private static class GuiDisposedListener implements PropertyChangeListener { 868 @Override 869 public void propertyChange(PropertyChangeEvent e) { 870 boolean isDisposed = (Boolean)e.getNewValue(); 871 if (isDisposed != true) { 872 if (log.isLoggable(PlatformLogger.Level.FINE)) { 873 log.fine(" Assertion (newValue != true) failed for AppContext.GUI_DISPOSED "); 874 } 875 } 876 AppContext appContext = AppContext.getAppContext(); 877 synchronized (appContext) { 878 appContext.remove(ACTIVE_WINDOWS_KEY); 879 appContext.removePropertyChangeListener(AppContext.GUI_DISPOSED, this); 880 881 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 882 kfm.removePropertyChangeListener("activeWindow", activeWindowListener); 883 } 884 } 885 } 886 887 /* 888 * Static inner class, listens for 'activeWindow' KFM property changes and 889 * updates the list of active windows per AppContext, so the latest active 890 * window is always at the end of the list. The list is stored in AppContext. 891 */ 892 @SuppressWarnings("unchecked") 893 private static class ActiveWindowListener implements PropertyChangeListener { 894 @Override 895 public void propertyChange(PropertyChangeEvent e) { 896 Window w = (Window)e.getNewValue(); 897 if (w == null) { 898 return; 899 } 900 AppContext appContext = SunToolkit.targetToAppContext(w); 901 synchronized (appContext) { 902 WWindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w); 903 // add/move wp to the end of the list 904 List<WWindowPeer> l = (List<WWindowPeer>)appContext.get(ACTIVE_WINDOWS_KEY); 905 if (l != null) { 906 l.remove(wp); 907 l.add(wp); 908 } 909 } 910 } 911 } 912 }