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