jdk/src/solaris/classes/sun/awt/X11/XWarningWindow.java
changeset 2472 b7aba00cabb6
parent 2 90ce3da70b43
child 2804 a947dcefc8cb
--- a/jdk/src/solaris/classes/sun/awt/X11/XWarningWindow.java	Wed Mar 25 13:37:08 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWarningWindow.java	Thu Mar 26 14:38:46 2009 +0300
@@ -25,16 +25,194 @@
 package sun.awt.X11;
 
 import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.Point2D;
+import java.lang.ref.WeakReference;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.pipe.Region;
+import sun.awt.AWTAccessor;
+import sun.awt.SunToolkit;
 
 class XWarningWindow extends XWindow {
-    final static int defaultHeight = 27;
+    private final static int showingDelay = 330;
+    private final static int hidingDelay = 2000;
+
+    private final Window ownerWindow;
+    private WeakReference<XWindowPeer> ownerPeer;
+
+    public final Window getOwnerWindow() {
+        return ownerWindow;
+    }
+    private long parentWindow;
+
+    private final static String OWNER = "OWNER";
+
+    private static XIconInfo[][] icons;
+
+    private InfoWindow.Tooltip tooltip;
+
+    private static synchronized XIconInfo getSecurityIconInfo(int size, int num) {
+        if (icons == null) {
+            icons = new XIconInfo[4][3];
+            if (XlibWrapper.dataModel == 32) {
+                icons[0][0] = new XIconInfo(XAWTIcon32_security_icon_bw16_png.security_icon_bw16_png);
+                icons[0][1] = new XIconInfo(XAWTIcon32_security_icon_interim16_png.security_icon_interim16_png);
+                icons[0][2] = new XIconInfo(XAWTIcon32_security_icon_yellow16_png.security_icon_yellow16_png);
+                icons[1][0] = new XIconInfo(XAWTIcon32_security_icon_bw24_png.security_icon_bw24_png);
+                icons[1][1] = new XIconInfo(XAWTIcon32_security_icon_interim24_png.security_icon_interim24_png);
+                icons[1][2] = new XIconInfo(XAWTIcon32_security_icon_yellow24_png.security_icon_yellow24_png);
+                icons[2][0] = new XIconInfo(XAWTIcon32_security_icon_bw32_png.security_icon_bw32_png);
+                icons[2][1] = new XIconInfo(XAWTIcon32_security_icon_interim32_png.security_icon_interim32_png);
+                icons[2][2] = new XIconInfo(XAWTIcon32_security_icon_yellow32_png.security_icon_yellow32_png);
+                icons[3][0] = new XIconInfo(XAWTIcon32_security_icon_bw48_png.security_icon_bw48_png);
+                icons[3][1] = new XIconInfo(XAWTIcon32_security_icon_interim48_png.security_icon_interim48_png);
+                icons[3][2] = new XIconInfo(XAWTIcon32_security_icon_yellow48_png.security_icon_yellow48_png);
+            } else {
+                icons[0][0] = new XIconInfo(XAWTIcon64_security_icon_bw16_png.security_icon_bw16_png);
+                icons[0][1] = new XIconInfo(XAWTIcon64_security_icon_interim16_png.security_icon_interim16_png);
+                icons[0][2] = new XIconInfo(XAWTIcon64_security_icon_yellow16_png.security_icon_yellow16_png);
+                icons[1][0] = new XIconInfo(XAWTIcon64_security_icon_bw24_png.security_icon_bw24_png);
+                icons[1][1] = new XIconInfo(XAWTIcon64_security_icon_interim24_png.security_icon_interim24_png);
+                icons[1][2] = new XIconInfo(XAWTIcon64_security_icon_yellow24_png.security_icon_yellow24_png);
+                icons[2][0] = new XIconInfo(XAWTIcon64_security_icon_bw32_png.security_icon_bw32_png);
+                icons[2][1] = new XIconInfo(XAWTIcon64_security_icon_interim32_png.security_icon_interim32_png);
+                icons[2][2] = new XIconInfo(XAWTIcon64_security_icon_yellow32_png.security_icon_yellow32_png);
+                icons[3][0] = new XIconInfo(XAWTIcon64_security_icon_bw48_png.security_icon_bw48_png);
+                icons[3][1] = new XIconInfo(XAWTIcon64_security_icon_interim48_png.security_icon_interim48_png);
+                icons[3][2] = new XIconInfo(XAWTIcon64_security_icon_yellow48_png.security_icon_yellow48_png);
+            }
+        }
+        final int sizeIndex = size % icons.length;
+        return icons[sizeIndex][num % icons[sizeIndex].length];
+    }
+
+    private volatile int currentIcon = 0;
+
+    /* -1 - uninitialized yet
+     * 0 - 16x16
+     * 1 - 24x24
+     * 2 - 32x32
+     * 3 - 48x48
+     */
+    private volatile int currentSize = -1;
+
+    /** Indicates whether the shape of the window must be updated
+     */
+    private volatile boolean sizeUpdated = true;
+
+    private synchronized boolean updateIconSize() {
+        int newSize = currentSize;
+
+        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;
+            }
+        }
+        if (newSize != currentSize) {
+            currentSize = newSize;
+            sizeUpdated = true;
+        }
+        return sizeUpdated;
+    }
 
-    Window ownerWindow;
-    XWarningWindow(Window ownerWindow, long parentWindow) {
-        super(ownerWindow, parentWindow);
+    private synchronized XIconInfo getSecurityIconInfo() {
+        updateIconSize();
+        return getSecurityIconInfo(currentSize, currentIcon);
+    }
+
+    XWarningWindow(final Window ownerWindow, long parentWindow, XWindowPeer ownerPeer) {
+        super(new XCreateWindowParams(new Object[] {
+                        TARGET, ownerWindow,
+                        OWNER, Long.valueOf(parentWindow)
+        }));
         this.ownerWindow = ownerWindow;
-        xSetVisible(true);
-        toFront();
+        this.parentWindow = parentWindow;
+        this.tooltip = new InfoWindow.Tooltip(null, getTarget(),
+                new InfoWindow.Tooltip.LiveArguments() {
+                    public boolean isDisposed() {
+                        return XWarningWindow.this.isDisposed();
+                    }
+                    public Rectangle getBounds() {
+                        return XWarningWindow.this.getBounds();
+                    }
+                    public String getTooltipString() {
+                        return XWarningWindow.this.ownerWindow.getWarningString();
+                    }
+                });
+        this.ownerPeer = new WeakReference<XWindowPeer>(ownerPeer);
+    }
+
+    private void requestNoTaskbar() {
+        XNETProtocol netProtocol = XWM.getWM().getNETProtocol();
+        if (netProtocol != null) {
+            netProtocol.requestState(this, netProtocol.XA_NET_WM_STATE_SKIP_TASKBAR, true);
+        }
+    }
+
+    @Override
+    void postInit(XCreateWindowParams params) {
+        super.postInit(params);
+        XToolkit.awtLock();
+        try {
+            XWM.setMotifDecor(this, false, 0, 0);
+            XWM.setOLDecor(this, false, 0);
+
+            long parentWindow = ((Long)params.get(OWNER)).longValue();
+            XlibWrapper.XSetTransientFor(XToolkit.getDisplay(),
+                    getWindow(), parentWindow);
+
+            XWMHints hints = getWMHints();
+            hints.set_flags(hints.get_flags() | (int)XUtilConstants.InputHint | (int)XUtilConstants.StateHint);
+            hints.set_input(false);
+            hints.set_initial_state(XUtilConstants.NormalState);
+            XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData);
+
+            initWMProtocols();
+            requestNoTaskbar();
+        } finally {
+            XToolkit.awtUnlock();
+        }
+    }
+
+    private void updateWarningWindowBounds() {
+        XWindowPeer peer = ownerPeer.get();
+        if (peer != null) {
+            synchronized (this) {
+                if (updateIconSize()) {
+                    XIconInfo ico = getSecurityIconInfo();
+                    XToolkit.awtLock();
+                    try {
+                        XlibWrapper.SetBitmapShape(XToolkit.getDisplay(), getWindow(),
+                                ico.getWidth(), ico.getHeight(), ico.getIntData());
+                    } finally {
+                        XToolkit.awtUnlock();
+                    }
+                    sizeUpdated = false;
+                    AWTAccessor.getWindowAccessor().setSecurityWarningSize(
+                            ownerWindow, ico.getWidth(), ico.getHeight());
+                }
+            }
+            peer.repositionSecurityWarning();
+        }
+    }
+
+    /**
+     * @param x,y,w,h coordinates of the untrusted window
+     */
+    public void reposition(int x, int y, int w, int h) {
+        Point2D point = AWTAccessor.getWindowAccessor().
+            calculateSecurityWarningPosition(ownerWindow,
+                x, y, w, h);
+        reshape((int)point.getX(), (int)point.getY(), getWidth(), getHeight());
     }
 
     protected String getWMName() {
@@ -49,33 +227,19 @@
                                  getFont());
     }
     void paint(Graphics g, int x, int y, int width, int height) {
-        String warningString = getWarningString();
-        Rectangle bounds = getBounds();
-        bounds.x = 0;
-        bounds.y = 0;
-        Rectangle updateRect = new Rectangle(x, y, width, height);
-        if (updateRect.intersects(bounds)) {
-            Rectangle updateArea = updateRect.intersection(bounds);
-            g.setClip(updateArea);
-            g.setColor(getBackground());
-            g.fillRect(updateArea.x, updateArea.y, updateArea.width, updateArea.height);
-            g.setColor(getColor());
-            g.setFont(getFont());
-            FontMetrics fm = g.getFontMetrics();
-            int warningWidth = fm.stringWidth(warningString);
-            int w_x = (bounds.width - warningWidth)/2;
-            int w_y = (bounds.height + fm.getMaxAscent() - fm.getMaxDescent())/2;
-            g.drawString(warningString, w_x, w_y);
-            g.drawLine(bounds.x, bounds.y+bounds.height-1, bounds.x+bounds.width-1, bounds.y+bounds.height-1);
-        }
+        g.drawImage(getSecurityIconInfo().getImage(), 0, 0, null);
     }
 
     String getWarningString() {
         return ownerWindow.getWarningString();
     }
 
+    int getWidth() {
+        return getSecurityIconInfo().getWidth();
+    }
+
     int getHeight() {
-        return defaultHeight; // should implement depending on Font
+        return getSecurityIconInfo().getHeight();
     }
 
     Color getBackground() {
@@ -97,6 +261,7 @@
         }
     }
 
+    @Override
     public void handleExposeEvent(XEvent xev) {
         super.handleExposeEvent(xev);
 
@@ -105,18 +270,156 @@
         final int y = xe.get_y();
         final int width = xe.get_width();
         final int height = xe.get_height();
-        EventQueue.invokeLater(new Runnable() {
-            public void run() {
-                Graphics g = getGraphics();
-                try {
-                    paint(g, x, y, width, height);
-                } finally {
-                    g.dispose();
-                }
-            }
-        });
+        SunToolkit.executeOnEventHandlerThread(target,
+                new Runnable() {
+                    public void run() {
+                        Graphics g = getGraphics();
+                        try {
+                            paint(g, x, y, width, height);
+                        } finally {
+                            g.dispose();
+                        }
+                    }
+                });
     }
+
+    @Override
     protected boolean isEventDisabled(XEvent e) {
         return true;
     }
+
+    /** Send a synthetic UnmapNotify in order to withdraw the window.
+     */
+    private void withdraw() {
+        XEvent req = new XEvent();
+        try {
+            long root;
+            XToolkit.awtLock();
+            try {
+                root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber());
+            }
+            finally {
+                XToolkit.awtUnlock();
+            }
+
+            req.set_type(XConstants.UnmapNotify);
+
+            XUnmapEvent umev = req.get_xunmap();
+
+            umev.set_event(root);
+            umev.set_window(getWindow());
+            umev.set_from_configure(false);
+
+            XToolkit.awtLock();
+            try {
+                XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+                        root,
+                        false,
+                        XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
+                        req.pData);
+            }
+            finally {
+                XToolkit.awtUnlock();
+            }
+        } finally {
+            req.dispose();
+        }
+    }
+
+    @Override
+    protected void stateChanged(long time, int oldState, int newState) {
+        if (newState == XUtilConstants.IconicState) {
+            super.xSetVisible(false);
+            withdraw();
+        }
+    }
+
+    @Override
+    protected void setMouseAbove(boolean above) {
+        super.setMouseAbove(above);
+        XWindowPeer p = ownerPeer.get();
+        if (p != null) {
+            p.updateSecurityWarningVisibility();
+        }
+    }
+
+    @Override
+    protected void enterNotify(long window) {
+        super.enterNotify(window);
+        if (window == getWindow()) {
+            tooltip.enter();
+        }
+    }
+
+    @Override
+    protected void leaveNotify(long window) {
+        super.leaveNotify(window);
+        if (window == getWindow()) {
+            tooltip.exit();
+        }
+    }
+
+    @Override
+    public void xSetVisible(boolean visible) {
+        super.xSetVisible(visible);
+
+        // The _NET_WM_STATE_SKIP_TASKBAR got reset upon hiding/showing,
+        // so we request it every time whenever we change the visibility.
+        requestNoTaskbar();
+    }
+
+    private final Runnable hidingTask = new Runnable() {
+        public void run() {
+            xSetVisible(false);
+        }
+    };
+
+    private final Runnable showingTask = new Runnable() {
+        public void run() {
+            new Thread() {
+                public void run() {
+                    if (!isVisible()) {
+                        xSetVisible(true);
+                        updateWarningWindowBounds();
+                    }
+                    repaint();
+                    if (currentIcon > 0) {
+                        currentIcon--;
+                        XToolkit.schedule(showingTask, showingDelay);
+                    }
+                }}.start();
+        }
+    };
+
+    public void setSecurityWarningVisible(boolean visible) {
+        setSecurityWarningVisible(visible, true);
+    }
+
+    public void setSecurityWarningVisible(boolean visible, boolean doSchedule) {
+        if (visible) {
+            XToolkit.remove(hidingTask);
+            XToolkit.remove(showingTask);
+            if (isVisible()) {
+                currentIcon = 0;
+            } else {
+                currentIcon = 3;
+            }
+            if (doSchedule) {
+                XToolkit.schedule(showingTask, 1);
+            } else {
+                showingTask.run();
+            }
+        } else {
+            XToolkit.remove(showingTask);
+            XToolkit.remove(hidingTask);
+            if (!isVisible()) {
+                return;
+            }
+            if (doSchedule) {
+                XToolkit.schedule(hidingTask, hidingDelay);
+            } else {
+                hidingTask.run();
+            }
+        }
+    }
 }