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