1 /* 2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.windows; 27 28 import java.awt.Graphics2D; 29 import java.awt.AWTEvent; 30 import java.awt.Frame; 31 import java.awt.GraphicsEnvironment; 32 import java.awt.PopupMenu; 33 import java.awt.Point; 34 import java.awt.TrayIcon; 35 import java.awt.Image; 36 import java.awt.geom.AffineTransform; 37 import java.awt.peer.TrayIconPeer; 38 import java.awt.image.*; 39 40 import sun.awt.AWTAccessor; 41 import sun.awt.SunToolkit; 42 import sun.awt.image.IntegerComponentRaster; 43 import sun.java2d.pipe.Region; 44 45 final class WTrayIconPeer extends WObjectPeer implements TrayIconPeer { 46 static final int TRAY_ICON_WIDTH = 16; 47 static final int TRAY_ICON_HEIGHT = 16; 48 static final int TRAY_ICON_MASK_SIZE = (TRAY_ICON_WIDTH * TRAY_ICON_HEIGHT) / 8; 49 50 IconObserver observer = new IconObserver(); 51 boolean firstUpdate = true; 52 Frame popupParent = new Frame("PopupMessageWindow"); 53 PopupMenu popup; 54 55 @Override 56 protected void disposeImpl() { 57 if (popupParent != null) { 58 popupParent.dispose(); 59 } 60 popupParent.dispose(); 61 _dispose(); 62 WToolkit.targetDisposedPeer(target, this); 63 } 64 65 WTrayIconPeer(TrayIcon target) { 66 this.target = target; 67 popupParent.addNotify(); 68 create(); 69 updateImage(); 70 } 71 72 @Override 73 public void updateImage() { 74 Image image = ((TrayIcon)target).getImage(); 75 if (image != null) { 76 updateNativeImage(image); 77 } 78 } 79 80 @Override 81 public native void setToolTip(String tooltip); 82 83 @Override 84 public synchronized void showPopupMenu(final int x, final int y) { 85 if (isDisposed()) 86 return; 87 88 SunToolkit.executeOnEventHandlerThread(target, () -> { 89 PopupMenu newPopup = ((TrayIcon)target).getPopupMenu(); 90 if (popup != newPopup) { 91 if (popup != null) { 92 popupParent.remove(popup); 93 } 94 if (newPopup != null) { 95 popupParent.add(newPopup); 96 } 97 popup = newPopup; 98 } 99 if (popup != null) { 100 WPopupMenuPeer peer = AWTAccessor.getMenuComponentAccessor() 101 .getPeer(popup); 102 peer.show(popupParent, new Point(x, y)); 103 } 104 }); 105 } 106 107 @Override 108 public void displayMessage(String caption, String text, String messageType) { 109 // The situation when both caption and text are null is processed in the shared code. 110 if (caption == null) { 111 caption = ""; 112 } 113 if (text == null) { 114 text = ""; 115 } 116 _displayMessage(caption, text, messageType); 117 } 118 119 120 // *********************************************** 121 // *********************************************** 122 123 124 synchronized void updateNativeImage(Image image) { 125 if (isDisposed()) 126 return; 127 128 boolean autosize = ((TrayIcon)target).isImageAutoSize(); 129 AffineTransform tx = GraphicsEnvironment.getLocalGraphicsEnvironment(). 130 getDefaultScreenDevice().getDefaultConfiguration(). 131 getDefaultTransform(); 132 int w = Region.clipScale(TRAY_ICON_WIDTH, tx.getScaleX()); 133 int h = Region.clipScale(TRAY_ICON_HEIGHT, tx.getScaleY()); 134 int imgWidth = Region.clipScale(image.getWidth(observer), tx.getScaleX()); 135 int imgHeight = Region.clipScale(image.getHeight(observer), tx.getScaleY()); 136 BufferedImage bufImage = new BufferedImage(w, 137 h, BufferedImage.TYPE_INT_ARGB); 138 Graphics2D gr = bufImage.createGraphics(); 139 if (gr != null) { 140 try { 141 gr.setPaintMode(); 142 143 gr.drawImage(image, 0, 0, (autosize ? w : imgWidth), 144 (autosize ? h : imgHeight), observer); 145 146 createNativeImage(bufImage); 147 148 updateNativeIcon(!firstUpdate); 149 if (firstUpdate) firstUpdate = false; 150 151 } finally { 152 gr.dispose(); 153 } 154 } 155 } 156 157 void createNativeImage(BufferedImage bimage) { 158 Raster raster = bimage.getRaster(); 159 byte[] andMask = new byte[TRAY_ICON_MASK_SIZE]; 160 int pixels[] = ((DataBufferInt)raster.getDataBuffer()).getData(); 161 int npixels = pixels.length; 162 int ficW = raster.getWidth(); 163 164 for (int i = 0; i < npixels; i++) { 165 int ibyte = i / 8; 166 int omask = 1 << (7 - (i % 8)); 167 168 if ((pixels[i] & 0xff000000) == 0) { 169 // Transparent bit 170 if (ibyte < andMask.length) { 171 andMask[ibyte] |= omask; 172 } 173 } 174 } 175 176 if (raster instanceof IntegerComponentRaster) { 177 ficW = ((IntegerComponentRaster)raster).getScanlineStride(); 178 } 179 setNativeIcon(((DataBufferInt)bimage.getRaster().getDataBuffer()).getData(), 180 andMask, ficW, raster.getWidth(), raster.getHeight()); 181 } 182 183 void postEvent(AWTEvent event) { 184 WToolkit.postEvent(WToolkit.targetToAppContext(target), event); 185 } 186 187 native void create(); 188 synchronized native void _dispose(); 189 190 /* 191 * Updates/adds the icon in/to the system tray. 192 * @param doUpdate if {@code true}, updates the icon, 193 * otherwise, adds the icon 194 */ 195 native void updateNativeIcon(boolean doUpdate); 196 197 native void setNativeIcon(int[] rData, byte[] andMask, int nScanStride, 198 int width, int height); 199 200 native void _displayMessage(String caption, String text, String messageType); 201 202 class IconObserver implements ImageObserver { 203 @Override 204 public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) { 205 if (image != ((TrayIcon)target).getImage() || // if the image has been changed 206 isDisposed()) 207 { 208 return false; 209 } 210 if ((flags & (ImageObserver.FRAMEBITS | ImageObserver.ALLBITS | 211 ImageObserver.WIDTH | ImageObserver.HEIGHT)) != 0) 212 { 213 updateNativeImage(image); 214 } 215 return (flags & ImageObserver.ALLBITS) == 0; 216 } 217 } 218 }