/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.lwawt.macosx;

import sun.awt.AWTAccessor;
import sun.awt.IconInfo;
import sun.awt.SunToolkit;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.opengl.CGLLayer;
import sun.lwawt.LWWindowPeer;
import sun.lwawt.PlatformEventNotifier;
import sun.lwawt.SecurityWarningWindow;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.lang.ref.WeakReference;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public final class CWarningWindow extends CPlatformWindow
        implements SecurityWarningWindow, PlatformEventNotifier {

    private static class Lock {};
    private final Lock lock = new Lock();

    private final static int SHOWING_DELAY = 300;
    private final static int HIDING_DELAY = 2000;

    private Rectangle bounds = new Rectangle();
    private final WeakReference<LWWindowPeer> ownerPeer;
    private final Window ownerWindow;

    
Animation stage.
/** * Animation stage. */
private volatile int currentIcon = 0; /* -1 - uninitialized. * 0 - 16x16 * 1 - 24x24 * 2 - 32x32 * 3 - 48x48 */ private int currentSize = -1; private static IconInfo[][] icons; private static IconInfo getSecurityIconInfo(int size, int num) { synchronized (CWarningWindow.class) { if (icons == null) { icons = new IconInfo[4][3]; icons[0][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw16_png.security_icon_bw16_png); icons[0][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim16_png.security_icon_interim16_png); icons[0][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow16_png.security_icon_yellow16_png); icons[1][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw24_png.security_icon_bw24_png); icons[1][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim24_png.security_icon_interim24_png); icons[1][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow24_png.security_icon_yellow24_png); icons[2][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw32_png.security_icon_bw32_png); icons[2][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim32_png.security_icon_interim32_png); icons[2][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow32_png.security_icon_yellow32_png); icons[3][0] = new IconInfo(sun.awt.AWTIcon32_security_icon_bw48_png.security_icon_bw48_png); icons[3][1] = new IconInfo(sun.awt.AWTIcon32_security_icon_interim48_png.security_icon_interim48_png); icons[3][2] = new IconInfo(sun.awt.AWTIcon32_security_icon_yellow48_png.security_icon_yellow48_png); } } final int sizeIndex = size % icons.length; return icons[sizeIndex][num % icons[sizeIndex].length]; } public CWarningWindow(final Window _ownerWindow, final LWWindowPeer _ownerPeer) { super(); this.ownerPeer = new WeakReference<LWWindowPeer>(_ownerPeer); this.ownerWindow = _ownerWindow; initialize(null, null, _ownerPeer.getPlatformWindow()); setOpaque(false); String warningString = ownerWindow.getWarningString(); if (warningString != null) { contentView.setToolTip(ownerWindow.getWarningString()); } updateIconSize(); }
@paramx,y,w,h coordinates of the untrusted window
/** * @param x,y,w,h coordinates of the untrusted window */
public void reposition(int x, int y, int w, int h) { final Point2D point = AWTAccessor.getWindowAccessor(). calculateSecurityWarningPosition(ownerWindow, x, y, w, h); setBounds((int)point.getX(), (int)point.getY(), getWidth(), getHeight()); } public void setVisible(boolean visible, boolean doSchedule) { synchronized (scheduler) { if (showingTaskHandle != null) { showingTaskHandle.cancel(false); showingTaskHandle = null; } if (hidingTaskHandle != null) { hidingTaskHandle.cancel(false); hidingTaskHandle = null; } if (visible) { if (isVisible()) { currentIcon = 0; } else { currentIcon = 2; } showingTaskHandle = scheduler.schedule(showingTask, 50, TimeUnit.MILLISECONDS); } else { if (!isVisible()) { return; } if (doSchedule) { hidingTaskHandle = scheduler.schedule(hidingTask, HIDING_DELAY, TimeUnit.MILLISECONDS); } else { hidingTaskHandle = scheduler.schedule(hidingTask, 50, TimeUnit.MILLISECONDS); } } } } @Override public void notifyIconify(boolean iconify) { } @Override public void notifyZoom(boolean isZoomed) { } @Override public void notifyExpose(final Rectangle r) { repaint(); } @Override public void notifyReshape(int x, int y, int w, int h) { } @Override public void notifyUpdateCursor() { } @Override public void notifyActivation(boolean activation, LWWindowPeer opposite) { } @Override public void notifyNCMouseDown() { } @Override public void notifyMouseEvent(int id, long when, int button, int x, int y, int screenX, int screenY, int modifiers, int clickCount, boolean popupTrigger, byte[] bdata) { LWWindowPeer peer = ownerPeer.get(); if (id == MouseEvent.MOUSE_EXITED) { if (peer != null) { peer.updateSecurityWarningVisibility(); } } else if(id == MouseEvent.MOUSE_ENTERED) { if (peer != null) { peer.updateSecurityWarningVisibility(); } } } public Rectangle getBounds() { synchronized (lock) { return bounds.getBounds(); } } @Override public boolean isVisible() { synchronized (lock) { return visible; } } @Override public void setVisible(boolean visible) { synchronized (lock) { execute(ptr -> { // Actually show or hide the window if (visible) { CWrapper.NSWindow.orderFront(ptr); } else { CWrapper.NSWindow.orderOut(ptr); } }); this.visible = visible; // Manage parent-child relationship when showing if (visible) { // Order myself above my parent if (owner != null && owner.isVisible()) { owner.execute(ownerPtr -> { execute(ptr -> { CWrapper.NSWindow.orderWindow(ptr, CWrapper.NSWindow.NSWindowAbove, ownerPtr); }); }); // do not allow security warning to be obscured by other windows applyWindowLevel(ownerWindow); } } } } @Override public void notifyMouseWheelEvent(long when, int x, int y, int modifiers, int scrollType, int scrollAmount, int wheelRotation, double preciseWheelRotation, byte[] bdata) { } @Override public void notifyKeyEvent(int id, long when, int modifiers, int keyCode, char keyChar, int keyLocation) { } protected int getInitialStyleBits() { int styleBits = 0; CPlatformWindow.SET(styleBits, CPlatformWindow.UTILITY, true); return styleBits; } protected void deliverMoveResizeEvent(int x, int y, int width, int height, boolean byUser) { boolean isResize; synchronized (lock) { isResize = (bounds.width != width || bounds.height != height); bounds = new Rectangle(x, y, width, height); } if (isResize) { replaceSurface(); } super.deliverMoveResizeEvent(x, y, width, height, byUser); } protected CPlatformResponder createPlatformResponder() { return new CPlatformResponder(this, false); } protected CPlatformView createContentView() { return new CPlatformView() { public GraphicsConfiguration getGraphicsConfiguration() { LWWindowPeer peer = ownerPeer.get(); return peer.getGraphicsConfiguration(); } public Rectangle getBounds() { return CWarningWindow.this.getBounds(); } public CGLLayer createCGLayer() { return new CGLLayer(null) { public Rectangle getBounds() { return CWarningWindow.this.getBounds(); } public GraphicsConfiguration getGraphicsConfiguration() { LWWindowPeer peer = ownerPeer.get(); return peer.getGraphicsConfiguration(); } public boolean isOpaque() { return false; } }; } }; } private void updateIconSize() { int newSize = -1; if (ownerWindow != null) { Insets insets = ownerWindow.getInsets(); int max = Math.max(insets.top, Math.max(insets.bottom, Math.max(insets.left, insets.right))); if (max < 24) { newSize = 0; } else if (max < 32) { newSize = 1; } else if (max < 48) { newSize = 2; } else { newSize = 3; } } // Make sure we have a valid size if (newSize == -1) { newSize = 0; } synchronized (lock) { if (newSize != currentSize) { currentSize = newSize; IconInfo ico = getSecurityIconInfo(currentSize, 0); AWTAccessor.getWindowAccessor().setSecurityWarningSize( ownerWindow, ico.getWidth(), ico.getHeight()); } } } private final Graphics getGraphics() { SurfaceData sd = contentView.getSurfaceData(); if (ownerWindow == null || sd == null) { return null; } return transformGraphics(new SunGraphics2D(sd, SystemColor.windowText, SystemColor.window, ownerWindow.getFont())); } private void repaint() { final Graphics g = getGraphics(); if (g != null) { try { ((Graphics2D) g).setComposite(AlphaComposite.Src); g.drawImage(getSecurityIconInfo().getImage(), 0, 0, null); } finally { g.dispose(); } } } private void replaceSurface() { SurfaceData oldData = contentView.getSurfaceData(); replaceSurfaceData(); if (oldData != null && oldData != contentView.getSurfaceData()) { oldData.flush(); } } private int getWidth() { return getSecurityIconInfo().getWidth(); } private int getHeight() { return getSecurityIconInfo().getHeight(); } private IconInfo getSecurityIconInfo() { return getSecurityIconInfo(currentSize, currentIcon); } private final Runnable hidingTask = new Runnable() { public void run() { synchronized (lock) { setVisible(false); } synchronized (scheduler) { hidingTaskHandle = null; } } }; private final Runnable showingTask = new Runnable() { public void run() { synchronized (lock) { if (!isVisible()) { setVisible(true); } repaint(); } synchronized (scheduler) { if (currentIcon > 0) { currentIcon--; showingTaskHandle = scheduler.schedule(showingTask, SHOWING_DELAY, TimeUnit.MILLISECONDS); } else { showingTaskHandle = null; } } } }; private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); private ScheduledFuture hidingTaskHandle; private ScheduledFuture showingTaskHandle; }