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