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.GraphicsConfiguration; 32 import java.awt.GraphicsDevice; 33 import java.awt.GraphicsEnvironment; 34 import java.awt.PopupMenu; 35 import java.awt.Point; 36 import java.awt.TrayIcon; 37 import java.awt.Image; 38 import java.awt.Insets; 39 import java.awt.Toolkit; 40 import java.awt.geom.AffineTransform; 41 import java.awt.peer.TrayIconPeer; 42 import java.awt.image.*; 43 44 import sun.awt.AWTAccessor; 45 import sun.awt.SunToolkit; 46 import sun.awt.image.IntegerComponentRaster; 47 48 final class WTrayIconPeer extends WObjectPeer implements TrayIconPeer { 49 static final int TRAY_ICON_WIDTH = 16; 50 static final int TRAY_ICON_HEIGHT = 16; 51 static final int TRAY_ICON_MASK_SIZE = (TRAY_ICON_WIDTH * TRAY_ICON_HEIGHT) / 8; 52 53 IconObserver observer = new IconObserver(); 54 boolean firstUpdate = true; 55 Frame popupParent = new Frame("PopupMessageWindow"); 56 PopupMenu popup; 57 58 @Override 59 protected void disposeImpl() { 60 if (popupParent != null) { 61 popupParent.dispose(); 62 } 63 popupParent.dispose(); 64 _dispose(); 65 WToolkit.targetDisposedPeer(target, this); 66 } 67 68 WTrayIconPeer(TrayIcon target) { 69 this.target = target; 70 popupParent.addNotify(); 71 create(); 72 updateImage(); 73 } 74 75 @Override 76 public void updateImage() { 77 Image image = ((TrayIcon)target).getImage(); 78 if (image != null) { 79 updateNativeImage(image); 80 } 81 } 82 83 @Override 84 public native void setToolTip(String tooltip); 85 86 @Override 87 public synchronized void showPopupMenu(final int x, final int y) { 88 if (isDisposed()) 89 return; 90 91 SunToolkit.executeOnEventHandlerThread(target, () -> { 92 PopupMenu newPopup = ((TrayIcon)target).getPopupMenu(); 93 if (popup != newPopup) { 94 if (popup != null) { 95 popupParent.remove(popup); 96 } 97 if (newPopup != null) { 98 popupParent.add(newPopup); 99 } 100 popup = newPopup; 101 } 102 if (popup != null) { 103 WPopupMenuPeer peer = AWTAccessor.getMenuComponentAccessor() 104 .getPeer(popup); 105 peer.show(popupParent, new Point(x, y)); 106 } 107 }); 108 } 109 110 @Override 111 public void displayMessage(String caption, String text, String messageType) { 112 // The situation when both caption and text are null is processed in the shared code. 113 if (caption == null) { 114 caption = ""; 115 } 116 if (text == null) { 117 text = ""; 118 } 119 _displayMessage(caption, text, messageType); 120 } 121 122 123 // *********************************************** 124 // *********************************************** 125 126 127 synchronized void updateNativeImage(Image image) { 128 if (isDisposed()) 129 return; 130 131 boolean autosize = ((TrayIcon)target).isImageAutoSize(); 132 133 BufferedImage bufImage = new BufferedImage(TRAY_ICON_WIDTH, TRAY_ICON_HEIGHT, 134 BufferedImage.TYPE_INT_ARGB); 135 Graphics2D gr = bufImage.createGraphics(); 136 if (gr != null) { 137 try { 138 gr.setPaintMode(); 139 GraphicsEnvironment ge = GraphicsEnvironment. 140 getLocalGraphicsEnvironment(); 141 Toolkit toolkit = Toolkit.getDefaultToolkit(); 142 GraphicsDevice[] gds = ge.getScreenDevices(); 143 GraphicsDevice device = ge.getDefaultScreenDevice(); 144 Insets in = new Insets(0, 0, 0, 0); 145 for (GraphicsDevice gd : gds) { 146 GraphicsConfiguration gc = gd.getDefaultConfiguration(); 147 Insets insets = toolkit.getScreenInsets(gc); 148 if (insets.bottom > in.bottom 149 || insets.top > in.top 150 || insets.left > in.left 151 || insets.right > in.right) { 152 in = insets; 153 device = gd; 154 } 155 } 156 AffineTransform tx = device.getDefaultConfiguration(). 157 getDefaultTransform(); 158 gr.setTransform(tx); 159 gr.drawImage(image, 0, 0, (autosize ? TRAY_ICON_WIDTH : image.getWidth(observer)), 160 (autosize ? TRAY_ICON_HEIGHT : image.getHeight(observer)), observer); 161 162 createNativeImage(bufImage); 163 164 updateNativeIcon(!firstUpdate); 165 if (firstUpdate) firstUpdate = false; 166 167 } finally { 168 gr.dispose(); 169 } 170 } 171 } 172 173 void createNativeImage(BufferedImage bimage) { 174 Raster raster = bimage.getRaster(); 175 byte[] andMask = new byte[TRAY_ICON_MASK_SIZE]; 176 int pixels[] = ((DataBufferInt)raster.getDataBuffer()).getData(); 177 int npixels = pixels.length; 178 int ficW = raster.getWidth(); 179 180 for (int i = 0; i < npixels; i++) { 181 int ibyte = i / 8; 182 int omask = 1 << (7 - (i % 8)); 183 184 if ((pixels[i] & 0xff000000) == 0) { 185 // Transparent bit 186 if (ibyte < andMask.length) { 187 andMask[ibyte] |= omask; 188 } 189 } 190 } 191 192 if (raster instanceof IntegerComponentRaster) { 193 ficW = ((IntegerComponentRaster)raster).getScanlineStride(); 194 } 195 setNativeIcon(((DataBufferInt)bimage.getRaster().getDataBuffer()).getData(), 196 andMask, ficW, raster.getWidth(), raster.getHeight()); 197 } 198 199 void postEvent(AWTEvent event) { 200 WToolkit.postEvent(WToolkit.targetToAppContext(target), event); 201 } 202 203 native void create(); 204 synchronized native void _dispose(); 205 206 /* 207 * Updates/adds the icon in/to the system tray. 208 * @param doUpdate if {@code true}, updates the icon, 209 * otherwise, adds the icon 210 */ 211 native void updateNativeIcon(boolean doUpdate); 212 213 native void setNativeIcon(int[] rData, byte[] andMask, int nScanStride, 214 int width, int height); 215 216 native void _displayMessage(String caption, String text, String messageType); 217 218 class IconObserver implements ImageObserver { 219 @Override 220 public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) { 221 if (image != ((TrayIcon)target).getImage() || // if the image has been changed 222 isDisposed()) 223 { 224 return false; 225 } 226 if ((flags & (ImageObserver.FRAMEBITS | ImageObserver.ALLBITS | 227 ImageObserver.WIDTH | ImageObserver.HEIGHT)) != 0) 228 { 229 updateNativeImage(image); 230 } 231 return (flags & ImageObserver.ALLBITS) == 0; 232 } 233 } 234 }