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