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