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