diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java --- /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 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))); + } +}