jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java
changeset 2 90ce3da70b43
child 439 3488710b02f8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,510 @@
+/*
+ * Copyright 2003-2006 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.awt.X11;
+
+import java.awt.*;
+import java.awt.image.*;
+import sun.awt.X11GraphicsConfig;
+import sun.awt.image.ToolkitImage;
+import sun.awt.image.ImageRepresentation;
+
+import java.util.logging.*;
+
+public class XIconWindow extends XBaseWindow {
+    private final static Logger log = Logger.getLogger("sun.awt.X11.XIconWindow");
+    XDecoratedPeer parent;
+    Dimension size;
+    long iconPixmap = 0;
+    long iconMask = 0;
+    int iconWidth = 0;
+    int iconHeight = 0;
+    XIconWindow(XDecoratedPeer parent) {
+        super(new XCreateWindowParams(new Object[] {
+            PARENT, parent,
+            DELAYED, Boolean.TRUE}));
+    }
+
+    void instantPreInit(XCreateWindowParams params) {
+        super.instantPreInit(params);
+        this.parent = (XDecoratedPeer)params.get(PARENT);
+    }
+
+    /**
+     * @return array of XIconsSize structures, caller must free this array after use.
+     */
+    private XIconSize[] getIconSizes() {
+        XToolkit.awtLock();
+        try {
+            AwtGraphicsConfigData adata = parent.getGraphicsConfigurationData();
+            final long screen = adata.get_awt_visInfo().get_screen();
+            final long display = XToolkit.getDisplay();
+
+            if (log.isLoggable(Level.FINEST)) log.finest(adata.toString());
+
+            long status =
+                XlibWrapper.XGetIconSizes(display, XToolkit.getDefaultRootWindow(),
+                                          XlibWrapper.larg1, XlibWrapper.iarg1);
+            if (status == 0) {
+                return null;
+            }
+            int count = Native.getInt(XlibWrapper.iarg1);
+            long sizes_ptr = Native.getLong(XlibWrapper.larg1); // XIconSize*
+            log.log(Level.FINEST, "count = {1}, sizes_ptr = {0}", new Object[] {Long.valueOf(sizes_ptr), Integer.valueOf(count)});
+            XIconSize[] res = new XIconSize[count];
+            for (int i = 0; i < count; i++, sizes_ptr += XIconSize.getSize()) {
+                res[i] = new XIconSize(sizes_ptr);
+                log.log(Level.FINEST, "sizes_ptr[{1}] = {0}", new Object[] {res[i], Integer.valueOf(i)});
+            }
+            return res;
+        } finally {
+            XToolkit.awtUnlock();
+        }
+    }
+
+    private Dimension calcIconSize(int widthHint, int heightHint) {
+        if (XWM.getWMID() == XWM.ICE_WM) {
+            // ICE_WM has a bug - it only displays icons of the size
+            // 16x16, while reporting 32x32 in its size list
+            log.log(Level.FINEST, "Returning ICE_WM icon size: 16x16");
+            return new Dimension(16, 16);
+        }
+
+        XIconSize[] sizeList = getIconSizes();
+        log.log(Level.FINEST, "Icon sizes: {0}", new Object[] {sizeList});
+        if (sizeList == null) {
+            // No icon sizes so we simply fall back to 16x16
+            return new Dimension(16, 16);
+        }
+        boolean found = false;
+        int dist = 0xffffffff, newDist, diff = 0, closestHeight, closestWidth;
+        int saveWidth = 0, saveHeight = 0;
+        for (int i = 0; i < sizeList.length; i++) {
+            if (widthHint >= sizeList[i].get_min_width() &&
+                widthHint <= sizeList[i].get_max_width() &&
+                heightHint >= sizeList[i].get_min_height() &&
+                heightHint <= sizeList[i].get_max_height()) {
+                found = true;
+                if ((((widthHint-sizeList[i].get_min_width())
+                      % sizeList[i].get_width_inc()) == 0) &&
+                    (((heightHint-sizeList[i].get_min_height())
+                      % sizeList[i].get_height_inc()) ==0)) {
+                    /* Found an exact match */
+                    saveWidth = widthHint;
+                    saveHeight = heightHint;
+                    dist = 0;
+                    break;
+                }
+                diff = widthHint - sizeList[i].get_min_width();
+                if (diff == 0) {
+                    closestWidth = widthHint;
+                } else {
+                    diff = diff%sizeList[i].get_width_inc();
+                    closestWidth = widthHint - diff;
+                }
+                diff = heightHint - sizeList[i].get_min_height();
+                if (diff == 0) {
+                    closestHeight = heightHint;
+                } else {
+                    diff = diff%sizeList[i].get_height_inc();
+                    closestHeight = heightHint - diff;
+                }
+                newDist = closestWidth*closestWidth +
+                    closestHeight*closestHeight;
+                if (dist > newDist) {
+                    saveWidth = closestWidth;
+                    saveHeight = closestHeight;
+                    dist = newDist;
+                }
+            }
+        }
+        if (log.isLoggable(Level.FINEST)) {
+            log.finest("found=" + found);
+        }
+        if (!found) {
+            if (log.isLoggable(Level.FINEST)) {
+                log.finest("widthHint=" + widthHint + ", heightHint=" + heightHint
+                           + ", saveWidth=" + saveWidth + ", saveHeight=" + saveHeight
+                           + ", max_width=" + sizeList[0].get_max_width()
+                           + ", max_height=" + sizeList[0].get_max_height()
+                           + ", min_width=" + sizeList[0].get_min_width()
+                           + ", min_height=" + sizeList[0].get_min_height());
+            }
+
+            if (widthHint  > sizeList[0].get_max_width() ||
+                heightHint > sizeList[0].get_max_height())
+            {
+                // Icon image too big
+                /* determine which way to scale */
+                int wdiff = widthHint - sizeList[0].get_max_width();
+                int hdiff = heightHint - sizeList[0].get_max_height();
+                if (log.isLoggable(Level.FINEST)) {
+                    log.finest("wdiff=" + wdiff + ", hdiff=" + hdiff);
+                }
+                if (wdiff >= hdiff) { /* need to scale width more  */
+                    saveWidth = sizeList[0].get_max_width();
+                    saveHeight =
+                        (int)(((double)sizeList[0].get_max_width()/widthHint) * heightHint);
+                } else {
+                    saveWidth =
+                        (int)(((double)sizeList[0].get_max_height()/heightHint) * widthHint);
+                    saveHeight = sizeList[0].get_max_height();
+                }
+            } else if (widthHint  < sizeList[0].get_min_width() ||
+                       heightHint < sizeList[0].get_min_height())
+            {
+                // Icon image too small
+                saveWidth = (sizeList[0].get_min_width()+sizeList[0].get_max_width())/2;
+                saveHeight = (sizeList[0].get_min_height()+sizeList[0].get_max_height())/2;
+            } else {
+                // Icon image fits within right size
+                saveWidth = widthHint;
+                saveHeight = widthHint;
+            }
+        }
+
+        XToolkit.awtLock();
+        try {
+            XlibWrapper.XFree(sizeList[0].pData);
+        } finally {
+            XToolkit.awtUnlock();
+        }
+
+        if (log.isLoggable(Level.FINEST)) {
+            log.finest("return " + saveWidth + "x" + saveHeight);
+        }
+        return new Dimension(saveWidth, saveHeight);
+    }
+
+    /**
+     * @return preffered icon size calculated from specific icon
+     */
+    Dimension getIconSize(int widthHint, int heightHint) {
+        if (size == null) {
+            size = calcIconSize(widthHint, heightHint);
+        }
+        return size;
+    }
+
+   /**
+    * This function replaces iconPixmap handle with new image
+    * It does not replace window's hints, so it should be
+    * called only from setIconImage()
+    */
+   void replaceImage(Image img)
+    {
+        if (parent == null) {
+            return;
+        }
+        //Prepare image
+        //create new buffered image of desired size
+        //in current window's color model
+        BufferedImage bi = null;
+        if (img != null && iconWidth != 0 && iconHeight != 0) {
+            GraphicsConfiguration defaultGC = parent.getGraphicsConfiguration().getDevice().getDefaultConfiguration();
+            ColorModel model = defaultGC.getColorModel();
+            WritableRaster raster = model.createCompatibleWritableRaster(iconWidth, iconHeight);
+            bi = new BufferedImage(model, raster, model.isAlphaPremultiplied(), null);
+            Graphics g = bi.getGraphics();
+            try {
+                //We need to draw image on SystemColors.window
+                //for using as iconWindow's background
+                g.setColor(SystemColor.window);
+                g.fillRect(0, 0, iconWidth, iconHeight);
+                if (g instanceof Graphics2D) {
+                    ((Graphics2D)g).setComposite(AlphaComposite.Src);
+                }
+                g.drawImage(img, 0, 0, iconWidth, iconHeight, null);
+            } finally {
+                g.dispose();
+            }
+        }
+        //create pixmap
+        XToolkit.awtLock();
+        try {
+            if (iconPixmap != 0) {
+                XlibWrapper.XFreePixmap(XToolkit.getDisplay(), iconPixmap);
+                iconPixmap = 0;
+                log.finest("Freed previous pixmap");
+            }
+            if (bi == null || iconWidth == 0 || iconHeight == 0) {
+                return;  //The iconPixmap is 0 now, we have done everything
+            }
+            AwtGraphicsConfigData adata = parent.getGraphicsConfigurationData();
+            awtImageData awtImage = adata.get_awtImage(0);
+            XVisualInfo visInfo = adata.get_awt_visInfo();
+            iconPixmap = XlibWrapper.XCreatePixmap(XToolkit.getDisplay(),
+                                                   XlibWrapper.RootWindow(XToolkit.getDisplay(), visInfo.get_screen()),
+                                                   iconWidth,
+                                                   iconHeight,
+                                                   awtImage.get_Depth()
+                                                   );
+            if (iconPixmap == 0) {
+                log.finest("Can't create new pixmap for icon");
+                return; //Can't do nothing
+            }
+            //Transform image data
+            long bytes = 0;
+            DataBuffer srcBuf = bi.getData().getDataBuffer();
+            if (srcBuf instanceof DataBufferByte) {
+                byte[] buf = ((DataBufferByte)srcBuf).getData();
+                ColorData cdata = adata.get_color_data(0);
+                int num_colors = cdata.get_awt_numICMcolors();
+                for (int i = 0; i < buf.length; i++) {
+                    buf[i] = (buf[i] >= num_colors) ?
+                        0 : cdata.get_awt_icmLUT2Colors(buf[i]);
+                }
+                bytes = Native.toData(buf);
+            } else if (srcBuf instanceof DataBufferInt) {
+                bytes = Native.toData(((DataBufferInt)srcBuf).getData());
+            } else if (srcBuf instanceof DataBufferUShort) {
+                bytes = Native.toData(((DataBufferUShort)srcBuf).getData());
+            } else {
+                throw new IllegalArgumentException("Unknown data buffer: " + srcBuf);
+            }
+            int bpp = awtImage.get_wsImageFormat().get_bits_per_pixel();
+            int slp =awtImage.get_wsImageFormat().get_scanline_pad();
+            int bpsl = paddedwidth(iconWidth*bpp, slp) >> 3;
+            if (((bpsl << 3) / bpp) < iconWidth) {
+                log.finest("Image format doesn't fit to icon width");
+                return;
+            }
+            long dst = XlibWrapper.XCreateImage(XToolkit.getDisplay(),
+                                                visInfo.get_visual(),
+                                                (int)awtImage.get_Depth(),
+                                                (int)XlibWrapper.ZPixmap,
+                                                0,
+                                                bytes,
+                                                iconWidth,
+                                                iconHeight,
+                                                32,
+                                                bpsl);
+            if (dst == 0) {
+                log.finest("Can't create XImage for icon");
+                XlibWrapper.XFreePixmap(XToolkit.getDisplay(), iconPixmap);
+                iconPixmap = 0;
+                return;
+            } else {
+                log.finest("Created XImage for icon");
+            }
+            long gc = XlibWrapper.XCreateGC(XToolkit.getDisplay(), iconPixmap, 0, 0);
+            if (gc == 0) {
+                log.finest("Can't create GC for pixmap");
+                XlibWrapper.XFreePixmap(XToolkit.getDisplay(), iconPixmap);
+                iconPixmap = 0;
+                return;
+            } else {
+                log.finest("Created GC for pixmap");
+            }
+            try {
+                XlibWrapper.XPutImage(XToolkit.getDisplay(), iconPixmap, gc,
+                                      dst, 0, 0, 0, 0, iconWidth, iconHeight);
+            } finally {
+                XlibWrapper.XFreeGC(XToolkit.getDisplay(), gc);
+            }
+        } finally {
+            XToolkit.awtUnlock();
+        }
+    }
+
+   /**
+    * This function replaces iconPixmap handle with new image
+    * It does not replace window's hints, so it should be
+    * called only from setIconImage()
+    */
+    void replaceMask(Image img) {
+        if (parent == null) {
+            return;
+        }
+        //Prepare image
+        BufferedImage bi = null;
+        if (img != null && iconWidth != 0 && iconHeight != 0) {
+            bi = new BufferedImage(iconWidth, iconHeight, BufferedImage.TYPE_INT_ARGB);
+            Graphics g = bi.getGraphics();
+            try {
+                g.drawImage(img, 0, 0, iconWidth, iconHeight, null);
+            } finally {
+                g.dispose();
+            }
+        }
+        //create mask
+        XToolkit.awtLock();
+        try {
+            if (iconMask != 0) {
+                XlibWrapper.XFreePixmap(XToolkit.getDisplay(), iconMask);
+                iconMask = 0;
+                log.finest("Freed previous mask");
+            }
+            if (bi == null || iconWidth == 0 || iconHeight == 0) {
+                return;  //The iconMask is 0 now, we have done everything
+            }
+            AwtGraphicsConfigData adata = parent.getGraphicsConfigurationData();
+            awtImageData awtImage = adata.get_awtImage(0);
+            XVisualInfo visInfo = adata.get_awt_visInfo();
+            ColorModel cm = bi.getColorModel();
+            DataBuffer srcBuf = bi.getRaster().getDataBuffer();
+            int sidx = 0;//index of source element
+            int bpl = (iconWidth + 7) >> 3;//bytes per line
+            byte[] destBuf = new byte[bpl * iconHeight];
+            int didx = 0;//index of destination element
+            for (int i = 0; i < iconHeight; i++) {
+                int dbit = 0;//index of current bit
+                int cv = 0;
+                for (int j = 0; j < iconWidth; j++) {
+                    if (cm.getAlpha(srcBuf.getElem(sidx)) != 0 ) {
+                        cv = cv + (1 << dbit);
+                    }
+                    dbit++;
+                    if (dbit == 8) {
+                        destBuf[didx] = (byte)cv;
+                        cv = 0;
+                        dbit = 0;
+                        didx++;
+                    }
+                    sidx++;
+                }
+            }
+            iconMask = XlibWrapper.XCreateBitmapFromData(XToolkit.getDisplay(),
+                XlibWrapper.RootWindow(XToolkit.getDisplay(), visInfo.get_screen()),
+                Native.toData(destBuf),
+                iconWidth, iconHeight);
+        } finally {
+            XToolkit.awtUnlock();
+        }
+    }
+
+    /**
+     * Sets icon image by selecting one of the images from the list.
+     * The selected image is the one having the best matching size.
+     */
+    void setIconImages(java.util.List<XIconInfo> icons) {
+        if (icons == null || icons.size() == 0) return;
+
+        int minDiff = Integer.MAX_VALUE;
+        Image min = null;
+        for (XIconInfo iconInfo : icons) {
+            if (iconInfo.isValid()) {
+                Image image = iconInfo.getImage();
+                Dimension dim = calcIconSize(image.getWidth(null), image.getHeight(null));
+                int widthDiff = Math.abs(dim.width - image.getWidth(null));
+                int heightDiff = Math.abs(image.getHeight(null) - dim.height);
+
+                // "=" below allows to select the best matching icon
+                if (minDiff >= (widthDiff + heightDiff)) {
+                    minDiff = (widthDiff + heightDiff);
+                    min = image;
+                }
+            }
+        }
+        if (min != null) {
+            log.log(Level.FINER, "Icon: {0}x{1}", new Object[] { min.getWidth(null), min.getHeight(null)});
+            setIconImage(min);
+        }
+    }
+
+    void setIconImage(Image img) {
+        if (img == null) {
+            //if image is null, reset to default image
+            replaceImage(null);
+            replaceMask(null);
+        } else {
+            //get image size
+            int width;
+            int height;
+            if (img instanceof ToolkitImage) {
+                ImageRepresentation ir = ((ToolkitImage)img).getImageRep();
+                ir.reconstruct(ImageObserver.ALLBITS);
+                width = ir.getWidth();
+                height = ir.getHeight();
+            }
+            else {
+                width = img.getWidth(null);
+                height = img.getHeight(null);
+            }
+            Dimension iconSize = getIconSize(width, height);
+            if (iconSize != null) {
+                log.log(Level.FINEST, "Icon size: {0}", iconSize);
+                iconWidth = iconSize.width;
+                iconHeight = iconSize.height;
+            } else {
+                log.finest("Error calculating image size");
+                iconWidth = 0;
+                iconHeight = 0;
+            }
+            replaceImage(img);
+            replaceMask(img);
+        }
+        //create icon window and set XWMHints
+        XToolkit.awtLock();
+        try {
+            AwtGraphicsConfigData adata = parent.getGraphicsConfigurationData();
+            awtImageData awtImage = adata.get_awtImage(0);
+            XVisualInfo visInfo = adata.get_awt_visInfo();
+            XWMHints hints = parent.getWMHints();
+            window = hints.get_icon_window();
+            if (window == 0) {
+                log.finest("Icon window wasn't set");
+                XCreateWindowParams params = getDelayedParams();
+                params.add(BORDER_PIXEL, Long.valueOf(XToolkit.getAwtDefaultFg()));
+                params.add(BACKGROUND_PIXMAP, iconPixmap);
+                params.add(COLORMAP, adata.get_awt_cmap());
+                params.add(DEPTH, awtImage.get_Depth());
+                params.add(VISUAL_CLASS, (int)XlibWrapper.InputOutput);
+                params.add(VISUAL, visInfo.get_visual());
+                params.add(VALUE_MASK, XlibWrapper.CWBorderPixel | XlibWrapper.CWColormap | XlibWrapper.CWBackPixmap);
+                params.add(PARENT_WINDOW, XlibWrapper.RootWindow(XToolkit.getDisplay(), visInfo.get_screen()));
+                params.add(BOUNDS, new Rectangle(0, 0, iconWidth, iconHeight));
+                params.remove(DELAYED);
+                init(params);
+                if (getWindow() == 0) {
+                    log.finest("Can't create new icon window");
+                } else {
+                    log.finest("Created new icon window");
+                }
+            }
+            if (getWindow() != 0) {
+                XlibWrapper.XSetWindowBackgroundPixmap(XToolkit.getDisplay(), getWindow(), iconPixmap);
+                XlibWrapper.XClearWindow(XToolkit.getDisplay(), getWindow());
+            }
+            // Provide both pixmap and window, WM or Taskbar will use the one they find more appropriate
+            long newFlags = hints.get_flags() | XlibWrapper.IconPixmapHint | XlibWrapper.IconMaskHint;
+            if (getWindow()  != 0) {
+                newFlags |= XlibWrapper.IconWindowHint;
+            }
+            hints.set_flags(newFlags);
+            hints.set_icon_pixmap(iconPixmap);
+            hints.set_icon_mask(iconMask);
+            hints.set_icon_window(getWindow());
+            XlibWrapper.XSetWMHints(XToolkit.getDisplay(), parent.getShell(), hints.pData);
+            log.finest("Set icon window hint");
+        } finally {
+            XToolkit.awtUnlock();
+        }
+    }
+
+    static int paddedwidth(int number, int boundary)
+    {
+        return (((number) + ((boundary) - 1)) & (~((boundary) - 1)));
+    }
+}