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