/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* @test @bug 8007220 @summary Reference to the popup leaks after the TrayIcon is removed @author Petr Pchelko @library ../../../../lib/testlibrary/ @build ExtendedRobot @run main/othervm -Xmx50m PopupMenuLeakTest */ import java.awt.*; import javax.swing.SwingUtilities; import java.awt.image.BufferedImage; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicReference; public class PopupMenuLeakTest { static final AtomicReference> iconWeakReference = new AtomicReference<>(); static final AtomicReference> popupWeakReference = new AtomicReference<>(); static ExtendedRobot robot; static Frame popupMenuParentFrame; public static void main(String[] args) throws Exception { robot = new ExtendedRobot(); SwingUtilities.invokeAndWait(PopupMenuLeakTest::createSystemTrayIcon); sleep(); // To make the test automatic we explicitly call addNotify on a popup to create the peer SwingUtilities.invokeAndWait(PopupMenuLeakTest::addNotifyPopup); sleep(); SwingUtilities.invokeAndWait(PopupMenuLeakTest::removeIcon); sleep(); assertCollected(popupWeakReference.get(), "Failed, reference to popup not collected"); assertCollected(iconWeakReference.get(), "Failed, reference to tray icon not collected"); } private static void addNotifyPopup() { PopupMenu menu = popupWeakReference.get().get(); if (menu == null) { throw new RuntimeException("Failed: popup collected too early"); } menu.addNotify(); } private static void removeIcon() { TrayIcon icon = iconWeakReference.get().get(); if (icon == null) { throw new RuntimeException("Failed: TrayIcon collected too early"); } SystemTray.getSystemTray().remove(icon); PopupMenu menu = popupWeakReference.get().get(); popupMenuParentFrame.remove(menu); popupMenuParentFrame.dispose(); } private static void assertCollected(WeakReference reference, String message) { java.util.List bytes = new ArrayList<>(); for (int i = 0; i < 5; i ++) { try { while (true) { bytes.add(new byte[1024]); } } catch (OutOfMemoryError err) { } } if (reference.get() != null) { throw new RuntimeException(message); } } private static void createSystemTrayIcon() { final TrayIcon trayIcon = new TrayIcon(createTrayIconImage()); trayIcon.setImageAutoSize(true); try { // Add tray icon to system tray *before* adding popup menu to demonstrate buggy behaviour trayIcon.setPopupMenu(createTrayIconPopupMenu()); SystemTray.getSystemTray().add(trayIcon); iconWeakReference.set(new WeakReference<>(trayIcon)); popupWeakReference.set(new WeakReference<>(trayIcon.getPopupMenu())); } catch (final AWTException awte) { awte.printStackTrace(); } } private static Image createTrayIconImage() { /** * Create a small image of a red circle to use as the icon for the tray icon */ int trayIconImageSize = 32; final BufferedImage trayImage = new BufferedImage(trayIconImageSize, trayIconImageSize, BufferedImage.TYPE_INT_ARGB); final Graphics2D trayImageGraphics = (Graphics2D) trayImage.getGraphics(); trayImageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); trayImageGraphics.setColor(new Color(255, 255, 255, 0)); trayImageGraphics.fillRect(0, 0, trayImage.getWidth(), trayImage.getHeight()); trayImageGraphics.setColor(Color.red); int trayIconImageInset = 4; trayImageGraphics.fillOval(trayIconImageInset, trayIconImageInset, trayImage.getWidth() - 2 * trayIconImageInset, trayImage.getHeight() - 2 * trayIconImageInset); trayImageGraphics.setColor(Color.darkGray); trayImageGraphics.drawOval(trayIconImageInset, trayIconImageInset, trayImage.getWidth() - 2 * trayIconImageInset, trayImage.getHeight() - 2 * trayIconImageInset); return trayImage; } private static PopupMenu createTrayIconPopupMenu() { popupMenuParentFrame = new Frame(); popupMenuParentFrame.setSize(200, 200); popupMenuParentFrame.setVisible(true); final PopupMenu trayIconPopupMenu = new PopupMenu(); final MenuItem popupMenuItem = new MenuItem("TEST!"); trayIconPopupMenu.add(popupMenuItem); popupMenuParentFrame.add(trayIconPopupMenu); return trayIconPopupMenu; } private static void sleep() { robot.waitForIdle(100); } }