1 /*
2  * Copyright (c) 2003, 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.X11;
26 
27 import java.awt.*;
28 import java.awt.geom.Point2D;
29 import java.lang.ref.WeakReference;
30 
31 import sun.awt.IconInfo;
32 import sun.awt.AWTAccessor;
33 import sun.awt.SunToolkit;
34 
35 class XWarningWindow extends XWindow {
36     private static final int SHOWING_DELAY = 330;
37     private static final int HIDING_DELAY = 2000;
38 
39     private final Window ownerWindow;
40     private WeakReference<XWindowPeer> ownerPeer;
41     private long parentWindow;
42 
43     private static final String OWNER = "OWNER";
44     private InfoWindow.Tooltip tooltip;
45 
46     /**
47      * Animation stage.
48      */
49     private volatile int currentIcon = 0;
50 
51     /* -1 - uninitialized.
52      * 0 - 16x16
53      * 1 - 24x24
54      * 2 - 32x32
55      * 3 - 48x48
56      */
57     private int currentSize = -1;
58     private static IconInfo[][] icons;
getSecurityIconInfo(int size, int num)59     private static IconInfo getSecurityIconInfo(int size, int num) {
60         synchronized (XWarningWindow.class) {
61             if (icons == null) {
62                 icons = new IconInfo[4][3];
63                 if (XlibWrapper.dataModel == 32) {
64                     icons[0][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw16_png.security_icon_bw16_png);
65                     icons[0][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim16_png.security_icon_interim16_png);
66                     icons[0][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow16_png.security_icon_yellow16_png);
67                     icons[1][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw24_png.security_icon_bw24_png);
68                     icons[1][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim24_png.security_icon_interim24_png);
69                     icons[1][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow24_png.security_icon_yellow24_png);
70                     icons[2][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw32_png.security_icon_bw32_png);
71                     icons[2][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim32_png.security_icon_interim32_png);
72                     icons[2][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow32_png.security_icon_yellow32_png);
73                     icons[3][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw48_png.security_icon_bw48_png);
74                     icons[3][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim48_png.security_icon_interim48_png);
75                     icons[3][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow48_png.security_icon_yellow48_png);
76                 } else {
77                     icons[0][0] = new IconInfo(sun.awt.AWTIcon64_security_icon_bw16_png.security_icon_bw16_png);
78                     icons[0][1] = new IconInfo(sun.awt.AWTIcon64_security_icon_interim16_png.security_icon_interim16_png);
79                     icons[0][2] = new IconInfo(sun.awt.AWTIcon64_security_icon_yellow16_png.security_icon_yellow16_png);
80                     icons[1][0] = new IconInfo(sun.awt.AWTIcon64_security_icon_bw24_png.security_icon_bw24_png);
81                     icons[1][1] = new IconInfo(sun.awt.AWTIcon64_security_icon_interim24_png.security_icon_interim24_png);
82                     icons[1][2] = new IconInfo(sun.awt.AWTIcon64_security_icon_yellow24_png.security_icon_yellow24_png);
83                     icons[2][0] = new IconInfo(sun.awt.AWTIcon64_security_icon_bw32_png.security_icon_bw32_png);
84                     icons[2][1] = new IconInfo(sun.awt.AWTIcon64_security_icon_interim32_png.security_icon_interim32_png);
85                     icons[2][2] = new IconInfo(sun.awt.AWTIcon64_security_icon_yellow32_png.security_icon_yellow32_png);
86                     icons[3][0] = new IconInfo(sun.awt.AWTIcon64_security_icon_bw48_png.security_icon_bw48_png);
87                     icons[3][1] = new IconInfo(sun.awt.AWTIcon64_security_icon_interim48_png.security_icon_interim48_png);
88                     icons[3][2] = new IconInfo(sun.awt.AWTIcon64_security_icon_yellow48_png.security_icon_yellow48_png);
89                 }
90             }
91         }
92         final int sizeIndex = size % icons.length;
93         return icons[sizeIndex][num % icons[sizeIndex].length];
94     }
95 
updateIconSize()96     private void updateIconSize() {
97         int newSize = -1;
98 
99         if (ownerWindow != null) {
100             Insets insets = ownerWindow.getInsets();
101             int max = Math.max(insets.top, Math.max(insets.bottom,
102                         Math.max(insets.left, insets.right)));
103             if (max < 24) {
104                 newSize = 0;
105             } else if (max < 32) {
106                 newSize = 1;
107             } else if (max < 48) {
108                 newSize = 2;
109             } else {
110                 newSize = 3;
111             }
112         }
113         // Make sure we have a valid size
114         if (newSize == -1) {
115             newSize = 0;
116         }
117 
118         // Note: this is not the most wise solution to use awtLock here,
119         // this should have been sync'ed with the stateLock. However,
120         // the awtLock must be taken first (see XBaseWindow.getStateLock()),
121         // and we need the awtLock anyway to update the shape of the icon.
122         // So it's easier to use just one lock instead.
123         XToolkit.awtLock();
124         try {
125             if (newSize != currentSize) {
126                 currentSize = newSize;
127                 IconInfo ico = getSecurityIconInfo(currentSize, 0);
128                 XlibWrapper.SetBitmapShape(XToolkit.getDisplay(), getWindow(),
129                         ico.getWidth(), ico.getHeight(), ico.getIntData());
130                 AWTAccessor.getWindowAccessor().setSecurityWarningSize(
131                         ownerWindow, ico.getWidth(), ico.getHeight());
132             }
133         } finally {
134             XToolkit.awtUnlock();
135         }
136     }
137 
getSecurityIconInfo()138     private IconInfo getSecurityIconInfo() {
139         updateIconSize();
140         return getSecurityIconInfo(currentSize, currentIcon);
141     }
142 
XWarningWindow(final Window ownerWindow, long parentWindow, XWindowPeer ownerPeer)143     XWarningWindow(final Window ownerWindow, long parentWindow, XWindowPeer ownerPeer) {
144         super(new XCreateWindowParams(new Object[] {
145                         TARGET, ownerWindow,
146                         OWNER, Long.valueOf(parentWindow)
147         }));
148         this.ownerWindow = ownerWindow;
149         this.parentWindow = parentWindow;
150         this.tooltip = new InfoWindow.Tooltip(null, getTarget(),
151                 new InfoWindow.Tooltip.LiveArguments() {
152                     public boolean isDisposed() {
153                         return XWarningWindow.this.isDisposed();
154                     }
155                     public Rectangle getBounds() {
156                         return XWarningWindow.this.getBounds();
157                     }
158                     public String getTooltipString() {
159                         return XWarningWindow.this.ownerWindow.getWarningString();
160                     }
161                 });
162         this.ownerPeer = new WeakReference<XWindowPeer>(ownerPeer);
163     }
164 
requestNoTaskbar()165     private void requestNoTaskbar() {
166         XNETProtocol netProtocol = XWM.getWM().getNETProtocol();
167         if (netProtocol != null) {
168             netProtocol.requestState(this, netProtocol.XA_NET_WM_STATE_SKIP_TASKBAR, true);
169         }
170     }
171 
172     @Override
postInit(XCreateWindowParams params)173     void postInit(XCreateWindowParams params) {
174         super.postInit(params);
175         XToolkit.awtLock();
176         try {
177             XWM.setMotifDecor(this, false, 0, 0);
178             XWM.setOLDecor(this, false, 0);
179 
180             long parentWindow = ((Long)params.get(OWNER)).longValue();
181             XlibWrapper.XSetTransientFor(XToolkit.getDisplay(),
182                     getWindow(), parentWindow);
183 
184             XWMHints hints = getWMHints();
185             hints.set_flags(hints.get_flags() | (int)XUtilConstants.InputHint | (int)XUtilConstants.StateHint);
186             hints.set_input(false);
187             hints.set_initial_state(XUtilConstants.NormalState);
188             XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData);
189 
190             initWMProtocols();
191             requestNoTaskbar();
192         } finally {
193             XToolkit.awtUnlock();
194         }
195     }
196 
197     /**
198      * @param x,y,w,h coordinates of the untrusted window
199      */
reposition(int x, int y, int w, int h)200     public void reposition(int x, int y, int w, int h) {
201         Point2D point = AWTAccessor.getWindowAccessor().
202             calculateSecurityWarningPosition(ownerWindow,
203                 x, y, w, h);
204         reshape((int)point.getX(), (int)point.getY(), getWidth(), getHeight());
205     }
206 
getWMName()207     protected String getWMName() {
208         return "Warning window";
209     }
210 
getGraphics()211     public Graphics getGraphics() {
212         if ((surfaceData == null) || (ownerWindow == null)) return null;
213         return getGraphics(surfaceData,
214                                  getColor(),
215                                  getBackground(),
216                                  getFont());
217     }
paint(Graphics g, int x, int y, int width, int height)218     void paint(Graphics g, int x, int y, int width, int height) {
219         g.drawImage(getSecurityIconInfo().getImage(), 0, 0, null);
220     }
221 
getWarningString()222     String getWarningString() {
223         return ownerWindow.getWarningString();
224     }
225 
getWidth()226     int getWidth() {
227         return getSecurityIconInfo().getWidth();
228     }
229 
getHeight()230     int getHeight() {
231         return getSecurityIconInfo().getHeight();
232     }
233 
getBackground()234     Color getBackground() {
235         return SystemColor.window;
236     }
getColor()237     Color getColor() {
238         return Color.black;
239     }
getFont()240     Font getFont () {
241         return ownerWindow.getFont();
242     }
243 
244     @Override
repaint()245     public void repaint() {
246         final Rectangle bounds = getBounds();
247         final Graphics g = getGraphics();
248         if (g != null) {
249             try {
250                 paint(g, 0, 0, bounds.width, bounds.height);
251             } finally {
252                 g.dispose();
253             }
254         }
255     }
256     @Override
handleExposeEvent(XEvent xev)257     public void handleExposeEvent(XEvent xev) {
258         super.handleExposeEvent(xev);
259 
260         XExposeEvent xe = xev.get_xexpose();
261         final int x = scaleDown(xe.get_x());
262         final int y = scaleDown(xe.get_y());
263         final int width = scaleDown(xe.get_width());
264         final int height = scaleDown(xe.get_height());
265         SunToolkit.executeOnEventHandlerThread(target,
266                 new Runnable() {
267                     public void run() {
268                         final Graphics g = getGraphics();
269                         if (g != null) {
270                             try {
271                                 paint(g, x, y, width, height);
272                             } finally {
273                                 g.dispose();
274                             }
275                         }
276                     }
277                 });
278     }
279 
280     @Override
isEventDisabled(XEvent e)281     protected boolean isEventDisabled(XEvent e) {
282         return true;
283     }
284 
285     /** Send a synthetic UnmapNotify in order to withdraw the window.
286      */
withdraw()287     private void withdraw() {
288         XEvent req = new XEvent();
289         try {
290             long root;
291             XToolkit.awtLock();
292             try {
293                 root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber());
294             }
295             finally {
296                 XToolkit.awtUnlock();
297             }
298 
299             req.set_type(XConstants.UnmapNotify);
300 
301             XUnmapEvent umev = req.get_xunmap();
302 
303             umev.set_event(root);
304             umev.set_window(getWindow());
305             umev.set_from_configure(false);
306 
307             XToolkit.awtLock();
308             try {
309                 XlibWrapper.XSendEvent(XToolkit.getDisplay(),
310                         root,
311                         false,
312                         XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
313                         req.pData);
314             }
315             finally {
316                 XToolkit.awtUnlock();
317             }
318         } finally {
319             req.dispose();
320         }
321     }
322 
323     @Override
stateChanged(long time, int oldState, int newState)324     protected void stateChanged(long time, int oldState, int newState) {
325         if (newState == XUtilConstants.IconicState) {
326             super.xSetVisible(false);
327             withdraw();
328         }
329     }
330 
331     @Override
setMouseAbove(boolean above)332     protected void setMouseAbove(boolean above) {
333         super.setMouseAbove(above);
334         XWindowPeer p = ownerPeer.get();
335         if (p != null) {
336             p.updateSecurityWarningVisibility();
337         }
338     }
339 
340     @Override
enterNotify(long window)341     protected void enterNotify(long window) {
342         super.enterNotify(window);
343         if (window == getWindow()) {
344             tooltip.enter();
345         }
346     }
347 
348     @Override
leaveNotify(long window)349     protected void leaveNotify(long window) {
350         super.leaveNotify(window);
351         if (window == getWindow()) {
352             tooltip.exit();
353         }
354     }
355 
356     @Override
xSetVisible(boolean visible)357     public void xSetVisible(boolean visible) {
358         super.xSetVisible(visible);
359 
360         // The _NET_WM_STATE_SKIP_TASKBAR got reset upon hiding/showing,
361         // so we request it every time whenever we change the visibility.
362         requestNoTaskbar();
363     }
364 
365     private final Runnable hidingTask = new Runnable() {
366         public void run() {
367             xSetVisible(false);
368         }
369     };
370 
371     private final Runnable showingTask = new Runnable() {
372         public void run() {
373             if (!isVisible()) {
374                 xSetVisible(true);
375                 updateIconSize();
376                 XWindowPeer peer = ownerPeer.get();
377                 if (peer != null) {
378                     peer.repositionSecurityWarning();
379                 }
380             }
381             repaint();
382             if (currentIcon > 0) {
383                 currentIcon--;
384                 XToolkit.schedule(showingTask, SHOWING_DELAY);
385             }
386         }
387     };
388 
setSecurityWarningVisible(boolean visible, boolean doSchedule)389     public void setSecurityWarningVisible(boolean visible, boolean doSchedule) {
390         if (visible) {
391             XToolkit.remove(hidingTask);
392             XToolkit.remove(showingTask);
393             if (isVisible()) {
394                 currentIcon = 0;
395             } else {
396                 currentIcon = 3;
397             }
398             if (doSchedule) {
399                 XToolkit.schedule(showingTask, 1);
400             } else {
401                 showingTask.run();
402             }
403         } else {
404             XToolkit.remove(showingTask);
405             XToolkit.remove(hidingTask);
406             if (!isVisible()) {
407                 return;
408             }
409             if (doSchedule) {
410                 XToolkit.schedule(hidingTask, HIDING_DELAY);
411             } else {
412                 hidingTask.run();
413             }
414         }
415     }
416 }
417