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