/* * Copyright (c) 2003, 2006, 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.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* if (log.isLoggable(Level.FINEST)) { 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); if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "sizes_ptr[{1}] = {0}", new Object[] {String.valueOf(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(); if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "Icon sizes: {0}", new Object[] {String.valueOf(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) { if (log.isLoggable(Level.FINER)) { 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) { if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "Icon size: {0}", String.valueOf(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))); } }