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