001: /*
002: * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025: package sun.awt.X11;
026:
027: import java.awt.*;
028: import java.awt.image.*;
029: import sun.awt.X11GraphicsConfig;
030: import sun.awt.image.ToolkitImage;
031: import sun.awt.image.ImageRepresentation;
032:
033: import java.util.logging.*;
034:
035: public class XIconWindow extends XBaseWindow {
036: private final static Logger log = Logger
037: .getLogger("sun.awt.X11.XIconWindow");
038: XDecoratedPeer parent;
039: Dimension size;
040: long iconPixmap = 0;
041: long iconMask = 0;
042: int iconWidth = 0;
043: int iconHeight = 0;
044:
045: XIconWindow(XDecoratedPeer parent) {
046: super (new XCreateWindowParams(new Object[] { PARENT, parent,
047: DELAYED, Boolean.TRUE }));
048: }
049:
050: void instantPreInit(XCreateWindowParams params) {
051: super .instantPreInit(params);
052: this .parent = (XDecoratedPeer) params.get(PARENT);
053: }
054:
055: /**
056: * @return array of XIconsSize structures, caller must free this array after use.
057: */
058: private XIconSize[] getIconSizes() {
059: XToolkit.awtLock();
060: try {
061: AwtGraphicsConfigData adata = parent
062: .getGraphicsConfigurationData();
063: final long screen = adata.get_awt_visInfo().get_screen();
064: final long display = XToolkit.getDisplay();
065:
066: if (log.isLoggable(Level.FINEST))
067: log.finest(adata.toString());
068:
069: long status = XlibWrapper.XGetIconSizes(display, XToolkit
070: .getDefaultRootWindow(), XlibWrapper.larg1,
071: XlibWrapper.iarg1);
072: if (status == 0) {
073: return null;
074: }
075: int count = Native.getInt(XlibWrapper.iarg1);
076: long sizes_ptr = Native.getLong(XlibWrapper.larg1); // XIconSize*
077: log.log(Level.FINEST, "count = {1}, sizes_ptr = {0}",
078: new Object[] { Long.valueOf(sizes_ptr),
079: Integer.valueOf(count) });
080: XIconSize[] res = new XIconSize[count];
081: for (int i = 0; i < count; i++, sizes_ptr += XIconSize
082: .getSize()) {
083: res[i] = new XIconSize(sizes_ptr);
084: log.log(Level.FINEST, "sizes_ptr[{1}] = {0}",
085: new Object[] { res[i], Integer.valueOf(i) });
086: }
087: return res;
088: } finally {
089: XToolkit.awtUnlock();
090: }
091: }
092:
093: private Dimension calcIconSize(int widthHint, int heightHint) {
094: if (XWM.getWMID() == XWM.ICE_WM) {
095: // ICE_WM has a bug - it only displays icons of the size
096: // 16x16, while reporting 32x32 in its size list
097: log.log(Level.FINEST, "Returning ICE_WM icon size: 16x16");
098: return new Dimension(16, 16);
099: }
100:
101: XIconSize[] sizeList = getIconSizes();
102: log.log(Level.FINEST, "Icon sizes: {0}",
103: new Object[] { sizeList });
104: if (sizeList == null) {
105: // No icon sizes so we simply fall back to 16x16
106: return new Dimension(16, 16);
107: }
108: boolean found = false;
109: int dist = 0xffffffff, newDist, diff = 0, closestHeight, closestWidth;
110: int saveWidth = 0, saveHeight = 0;
111: for (int i = 0; i < sizeList.length; i++) {
112: if (widthHint >= sizeList[i].get_min_width()
113: && widthHint <= sizeList[i].get_max_width()
114: && heightHint >= sizeList[i].get_min_height()
115: && heightHint <= sizeList[i].get_max_height()) {
116: found = true;
117: if ((((widthHint - sizeList[i].get_min_width()) % sizeList[i]
118: .get_width_inc()) == 0)
119: && (((heightHint - sizeList[i].get_min_height()) % sizeList[i]
120: .get_height_inc()) == 0)) {
121: /* Found an exact match */
122: saveWidth = widthHint;
123: saveHeight = heightHint;
124: dist = 0;
125: break;
126: }
127: diff = widthHint - sizeList[i].get_min_width();
128: if (diff == 0) {
129: closestWidth = widthHint;
130: } else {
131: diff = diff % sizeList[i].get_width_inc();
132: closestWidth = widthHint - diff;
133: }
134: diff = heightHint - sizeList[i].get_min_height();
135: if (diff == 0) {
136: closestHeight = heightHint;
137: } else {
138: diff = diff % sizeList[i].get_height_inc();
139: closestHeight = heightHint - diff;
140: }
141: newDist = closestWidth * closestWidth + closestHeight
142: * closestHeight;
143: if (dist > newDist) {
144: saveWidth = closestWidth;
145: saveHeight = closestHeight;
146: dist = newDist;
147: }
148: }
149: }
150: if (log.isLoggable(Level.FINEST)) {
151: log.finest("found=" + found);
152: }
153: if (!found) {
154: if (log.isLoggable(Level.FINEST)) {
155: log.finest("widthHint=" + widthHint + ", heightHint="
156: + heightHint + ", saveWidth=" + saveWidth
157: + ", saveHeight=" + saveHeight + ", max_width="
158: + sizeList[0].get_max_width() + ", max_height="
159: + sizeList[0].get_max_height() + ", min_width="
160: + sizeList[0].get_min_width() + ", min_height="
161: + sizeList[0].get_min_height());
162: }
163:
164: if (widthHint > sizeList[0].get_max_width()
165: || heightHint > sizeList[0].get_max_height()) {
166: // Icon image too big
167: /* determine which way to scale */
168: int wdiff = widthHint - sizeList[0].get_max_width();
169: int hdiff = heightHint - sizeList[0].get_max_height();
170: if (log.isLoggable(Level.FINEST)) {
171: log.finest("wdiff=" + wdiff + ", hdiff=" + hdiff);
172: }
173: if (wdiff >= hdiff) { /* need to scale width more */
174: saveWidth = sizeList[0].get_max_width();
175: saveHeight = (int) (((double) sizeList[0]
176: .get_max_width() / widthHint) * heightHint);
177: } else {
178: saveWidth = (int) (((double) sizeList[0]
179: .get_max_height() / heightHint) * widthHint);
180: saveHeight = sizeList[0].get_max_height();
181: }
182: } else if (widthHint < sizeList[0].get_min_width()
183: || heightHint < sizeList[0].get_min_height()) {
184: // Icon image too small
185: saveWidth = (sizeList[0].get_min_width() + sizeList[0]
186: .get_max_width()) / 2;
187: saveHeight = (sizeList[0].get_min_height() + sizeList[0]
188: .get_max_height()) / 2;
189: } else {
190: // Icon image fits within right size
191: saveWidth = widthHint;
192: saveHeight = widthHint;
193: }
194: }
195:
196: XToolkit.awtLock();
197: try {
198: XlibWrapper.XFree(sizeList[0].pData);
199: } finally {
200: XToolkit.awtUnlock();
201: }
202:
203: if (log.isLoggable(Level.FINEST)) {
204: log.finest("return " + saveWidth + "x" + saveHeight);
205: }
206: return new Dimension(saveWidth, saveHeight);
207: }
208:
209: /**
210: * @return preffered icon size calculated from specific icon
211: */
212: Dimension getIconSize(int widthHint, int heightHint) {
213: if (size == null) {
214: size = calcIconSize(widthHint, heightHint);
215: }
216: return size;
217: }
218:
219: /**
220: * This function replaces iconPixmap handle with new image
221: * It does not replace window's hints, so it should be
222: * called only from setIconImage()
223: */
224: void replaceImage(Image img) {
225: if (parent == null) {
226: return;
227: }
228: //Prepare image
229: //create new buffered image of desired size
230: //in current window's color model
231: BufferedImage bi = null;
232: if (img != null && iconWidth != 0 && iconHeight != 0) {
233: GraphicsConfiguration defaultGC = parent
234: .getGraphicsConfiguration().getDevice()
235: .getDefaultConfiguration();
236: ColorModel model = defaultGC.getColorModel();
237: WritableRaster raster = model
238: .createCompatibleWritableRaster(iconWidth,
239: iconHeight);
240: bi = new BufferedImage(model, raster, model
241: .isAlphaPremultiplied(), null);
242: Graphics g = bi.getGraphics();
243: try {
244: //We need to draw image on SystemColors.window
245: //for using as iconWindow's background
246: g.setColor(SystemColor.window);
247: g.fillRect(0, 0, iconWidth, iconHeight);
248: if (g instanceof Graphics2D) {
249: ((Graphics2D) g).setComposite(AlphaComposite.Src);
250: }
251: g.drawImage(img, 0, 0, iconWidth, iconHeight, null);
252: } finally {
253: g.dispose();
254: }
255: }
256: //create pixmap
257: XToolkit.awtLock();
258: try {
259: if (iconPixmap != 0) {
260: XlibWrapper.XFreePixmap(XToolkit.getDisplay(),
261: iconPixmap);
262: iconPixmap = 0;
263: log.finest("Freed previous pixmap");
264: }
265: if (bi == null || iconWidth == 0 || iconHeight == 0) {
266: return; //The iconPixmap is 0 now, we have done everything
267: }
268: AwtGraphicsConfigData adata = parent
269: .getGraphicsConfigurationData();
270: awtImageData awtImage = adata.get_awtImage(0);
271: XVisualInfo visInfo = adata.get_awt_visInfo();
272: iconPixmap = XlibWrapper.XCreatePixmap(XToolkit
273: .getDisplay(), XlibWrapper.RootWindow(XToolkit
274: .getDisplay(), visInfo.get_screen()), iconWidth,
275: iconHeight, awtImage.get_Depth());
276: if (iconPixmap == 0) {
277: log.finest("Can't create new pixmap for icon");
278: return; //Can't do nothing
279: }
280: //Transform image data
281: long bytes = 0;
282: DataBuffer srcBuf = bi.getData().getDataBuffer();
283: if (srcBuf instanceof DataBufferByte) {
284: byte[] buf = ((DataBufferByte) srcBuf).getData();
285: ColorData cdata = adata.get_color_data(0);
286: int num_colors = cdata.get_awt_numICMcolors();
287: for (int i = 0; i < buf.length; i++) {
288: buf[i] = (buf[i] >= num_colors) ? 0 : cdata
289: .get_awt_icmLUT2Colors(buf[i]);
290: }
291: bytes = Native.toData(buf);
292: } else if (srcBuf instanceof DataBufferInt) {
293: bytes = Native.toData(((DataBufferInt) srcBuf)
294: .getData());
295: } else if (srcBuf instanceof DataBufferUShort) {
296: bytes = Native.toData(((DataBufferUShort) srcBuf)
297: .getData());
298: } else {
299: throw new IllegalArgumentException(
300: "Unknown data buffer: " + srcBuf);
301: }
302: int bpp = awtImage.get_wsImageFormat().get_bits_per_pixel();
303: int slp = awtImage.get_wsImageFormat().get_scanline_pad();
304: int bpsl = paddedwidth(iconWidth * bpp, slp) >> 3;
305: if (((bpsl << 3) / bpp) < iconWidth) {
306: log.finest("Image format doesn't fit to icon width");
307: return;
308: }
309: long dst = XlibWrapper.XCreateImage(XToolkit.getDisplay(),
310: visInfo.get_visual(), (int) awtImage.get_Depth(),
311: (int) XlibWrapper.ZPixmap, 0, bytes, iconWidth,
312: iconHeight, 32, bpsl);
313: if (dst == 0) {
314: log.finest("Can't create XImage for icon");
315: XlibWrapper.XFreePixmap(XToolkit.getDisplay(),
316: iconPixmap);
317: iconPixmap = 0;
318: return;
319: } else {
320: log.finest("Created XImage for icon");
321: }
322: long gc = XlibWrapper.XCreateGC(XToolkit.getDisplay(),
323: iconPixmap, 0, 0);
324: if (gc == 0) {
325: log.finest("Can't create GC for pixmap");
326: XlibWrapper.XFreePixmap(XToolkit.getDisplay(),
327: iconPixmap);
328: iconPixmap = 0;
329: return;
330: } else {
331: log.finest("Created GC for pixmap");
332: }
333: try {
334: XlibWrapper.XPutImage(XToolkit.getDisplay(),
335: iconPixmap, gc, dst, 0, 0, 0, 0, iconWidth,
336: iconHeight);
337: } finally {
338: XlibWrapper.XFreeGC(XToolkit.getDisplay(), gc);
339: }
340: } finally {
341: XToolkit.awtUnlock();
342: }
343: }
344:
345: /**
346: * This function replaces iconPixmap handle with new image
347: * It does not replace window's hints, so it should be
348: * called only from setIconImage()
349: */
350: void replaceMask(Image img) {
351: if (parent == null) {
352: return;
353: }
354: //Prepare image
355: BufferedImage bi = null;
356: if (img != null && iconWidth != 0 && iconHeight != 0) {
357: bi = new BufferedImage(iconWidth, iconHeight,
358: BufferedImage.TYPE_INT_ARGB);
359: Graphics g = bi.getGraphics();
360: try {
361: g.drawImage(img, 0, 0, iconWidth, iconHeight, null);
362: } finally {
363: g.dispose();
364: }
365: }
366: //create mask
367: XToolkit.awtLock();
368: try {
369: if (iconMask != 0) {
370: XlibWrapper
371: .XFreePixmap(XToolkit.getDisplay(), iconMask);
372: iconMask = 0;
373: log.finest("Freed previous mask");
374: }
375: if (bi == null || iconWidth == 0 || iconHeight == 0) {
376: return; //The iconMask is 0 now, we have done everything
377: }
378: AwtGraphicsConfigData adata = parent
379: .getGraphicsConfigurationData();
380: awtImageData awtImage = adata.get_awtImage(0);
381: XVisualInfo visInfo = adata.get_awt_visInfo();
382: ColorModel cm = bi.getColorModel();
383: DataBuffer srcBuf = bi.getRaster().getDataBuffer();
384: int sidx = 0;//index of source element
385: int bpl = (iconWidth + 7) >> 3;//bytes per line
386: byte[] destBuf = new byte[bpl * iconHeight];
387: int didx = 0;//index of destination element
388: for (int i = 0; i < iconHeight; i++) {
389: int dbit = 0;//index of current bit
390: int cv = 0;
391: for (int j = 0; j < iconWidth; j++) {
392: if (cm.getAlpha(srcBuf.getElem(sidx)) != 0) {
393: cv = cv + (1 << dbit);
394: }
395: dbit++;
396: if (dbit == 8) {
397: destBuf[didx] = (byte) cv;
398: cv = 0;
399: dbit = 0;
400: didx++;
401: }
402: sidx++;
403: }
404: }
405: iconMask = XlibWrapper.XCreateBitmapFromData(XToolkit
406: .getDisplay(), XlibWrapper.RootWindow(XToolkit
407: .getDisplay(), visInfo.get_screen()), Native
408: .toData(destBuf), iconWidth, iconHeight);
409: } finally {
410: XToolkit.awtUnlock();
411: }
412: }
413:
414: /**
415: * Sets icon image by selecting one of the images from the list.
416: * The selected image is the one having the best matching size.
417: */
418: void setIconImages(java.util.List<XIconInfo> icons) {
419: if (icons == null || icons.size() == 0)
420: return;
421:
422: int minDiff = Integer.MAX_VALUE;
423: Image min = null;
424: for (XIconInfo iconInfo : icons) {
425: if (iconInfo.isValid()) {
426: Image image = iconInfo.getImage();
427: Dimension dim = calcIconSize(image.getWidth(null),
428: image.getHeight(null));
429: int widthDiff = Math.abs(dim.width
430: - image.getWidth(null));
431: int heightDiff = Math.abs(image.getHeight(null)
432: - dim.height);
433:
434: // "=" below allows to select the best matching icon
435: if (minDiff >= (widthDiff + heightDiff)) {
436: minDiff = (widthDiff + heightDiff);
437: min = image;
438: }
439: }
440: }
441: if (min != null) {
442: log.log(Level.FINER, "Icon: {0}x{1}", new Object[] {
443: min.getWidth(null), min.getHeight(null) });
444: setIconImage(min);
445: }
446: }
447:
448: void setIconImage(Image img) {
449: if (img == null) {
450: //if image is null, reset to default image
451: replaceImage(null);
452: replaceMask(null);
453: } else {
454: //get image size
455: int width;
456: int height;
457: if (img instanceof ToolkitImage) {
458: ImageRepresentation ir = ((ToolkitImage) img)
459: .getImageRep();
460: ir.reconstruct(ImageObserver.ALLBITS);
461: width = ir.getWidth();
462: height = ir.getHeight();
463: } else {
464: width = img.getWidth(null);
465: height = img.getHeight(null);
466: }
467: Dimension iconSize = getIconSize(width, height);
468: if (iconSize != null) {
469: log.log(Level.FINEST, "Icon size: {0}", iconSize);
470: iconWidth = iconSize.width;
471: iconHeight = iconSize.height;
472: } else {
473: log.finest("Error calculating image size");
474: iconWidth = 0;
475: iconHeight = 0;
476: }
477: replaceImage(img);
478: replaceMask(img);
479: }
480: //create icon window and set XWMHints
481: XToolkit.awtLock();
482: try {
483: AwtGraphicsConfigData adata = parent
484: .getGraphicsConfigurationData();
485: awtImageData awtImage = adata.get_awtImage(0);
486: XVisualInfo visInfo = adata.get_awt_visInfo();
487: XWMHints hints = parent.getWMHints();
488: window = hints.get_icon_window();
489: if (window == 0) {
490: log.finest("Icon window wasn't set");
491: XCreateWindowParams params = getDelayedParams();
492: params.add(BORDER_PIXEL, Long.valueOf(XToolkit
493: .getAwtDefaultFg()));
494: params.add(BACKGROUND_PIXMAP, iconPixmap);
495: params.add(COLORMAP, adata.get_awt_cmap());
496: params.add(DEPTH, awtImage.get_Depth());
497: params.add(VISUAL_CLASS, (int) XlibWrapper.InputOutput);
498: params.add(VISUAL, visInfo.get_visual());
499: params.add(VALUE_MASK, XlibWrapper.CWBorderPixel
500: | XlibWrapper.CWColormap
501: | XlibWrapper.CWBackPixmap);
502: params.add(PARENT_WINDOW, XlibWrapper.RootWindow(
503: XToolkit.getDisplay(), visInfo.get_screen()));
504: params.add(BOUNDS, new Rectangle(0, 0, iconWidth,
505: iconHeight));
506: params.remove(DELAYED);
507: init(params);
508: if (getWindow() == 0) {
509: log.finest("Can't create new icon window");
510: } else {
511: log.finest("Created new icon window");
512: }
513: }
514: if (getWindow() != 0) {
515: XlibWrapper.XSetWindowBackgroundPixmap(XToolkit
516: .getDisplay(), getWindow(), iconPixmap);
517: XlibWrapper.XClearWindow(XToolkit.getDisplay(),
518: getWindow());
519: }
520: // Provide both pixmap and window, WM or Taskbar will use the one they find more appropriate
521: long newFlags = hints.get_flags()
522: | XlibWrapper.IconPixmapHint
523: | XlibWrapper.IconMaskHint;
524: if (getWindow() != 0) {
525: newFlags |= XlibWrapper.IconWindowHint;
526: }
527: hints.set_flags(newFlags);
528: hints.set_icon_pixmap(iconPixmap);
529: hints.set_icon_mask(iconMask);
530: hints.set_icon_window(getWindow());
531: XlibWrapper.XSetWMHints(XToolkit.getDisplay(), parent
532: .getShell(), hints.pData);
533: log.finest("Set icon window hint");
534: } finally {
535: XToolkit.awtUnlock();
536: }
537: }
538:
539: static int paddedwidth(int number, int boundary) {
540: return (((number) + ((boundary) - 1)) & (~((boundary) - 1)));
541: }
542: }
|