8007220: [macosx] Setting popupmenu on TrayIcon do not work if done *after* adding TrayIcon
Reviewed-by: anthony, serb
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java Thu Dec 19 16:49:27 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java Fri Dec 20 14:42:37 2013 +0400
@@ -76,8 +76,9 @@
menuPeer = (CPopupMenu)popup.getPeer();
if (menuPeer == null) {
popup.addNotify();
+ menuPeer = (CPopupMenu)popup.getPeer();
}
- }catch (Exception e){
+ } catch (Exception e) {
e.printStackTrace();
}
}
@@ -97,7 +98,12 @@
//invocation from the AWTTrayIcon.m
public long getPopupMenuModel(){
if(popup == null) {
- return 0L;
+ PopupMenu popupMenu = target.getPopupMenu();
+ if (popupMenu != null) {
+ popup = popupMenu;
+ } else {
+ return 0L;
+ }
}
return checkAndCreatePopupPeer().getModel();
}
@@ -134,6 +140,10 @@
dummyFrame.dispose();
+ if (popup != null) {
+ popup.removeNotify();
+ }
+
LWCToolkit.targetDisposedPeer(target, this);
target = null;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/TrayIcon/AddPopupAfterShowTest/AddPopupAfterShowTest.html Fri Dec 20 14:42:37 2013 +0400
@@ -0,0 +1,45 @@
+<!--
+ 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.
+-->
+
+<html>
+<!--
+ @test
+ @bug 8007220
+ @summary The popup menu is not added to the tray icon after it was added to tray
+ @author Petr Pchelko
+ @library ../../regtesthelpers
+ @build Sysout
+ @run applet/manual=yesno AddPopupAfterShowTest.html
+ -->
+<head>
+ <title> AddPopupAfterShowTest </title>
+</head>
+<body>
+
+<h1>AddPopupAfterShowTest<br>Bug ID: 8007220</h1>
+
+<p> See the dialog box (usually in upper left corner) for instructions</p>
+
+<APPLET CODE="AddPopupAfterShowTest.class" WIDTH=200 HEIGHT=200></APPLET>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/TrayIcon/AddPopupAfterShowTest/AddPopupAfterShowTest.java Fri Dec 20 14:42:37 2013 +0400
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+
+import test.java.awt.regtesthelpers.Sysout;
+
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+public class AddPopupAfterShowTest extends Applet {
+ @Override
+ public void init() {
+ if (!SystemTray.isSupported()) {
+ Sysout.createDialogWithInstructions(new String[]{
+ "Press PASS, the System Tray is not supported"});
+ return;
+ }
+
+
+ String[] instructions = {
+ "1) The red circle icon was added to the system tray.",
+ "2) Check that a popup menu is opened when the icon is clicked.",
+ "3) If true the test is passed, otherwise failed."};
+ Sysout.createDialogWithInstructions(instructions);
+ }
+
+ @Override
+ public void start() {
+ setSize(200, 200);
+ show();
+
+ createSystemTrayIcon();
+ }
+
+ 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
+ SystemTray.getSystemTray().add(trayIcon);
+ trayIcon.setPopupMenu(createTrayIconPopupMenu());
+ } 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() {
+ final PopupMenu trayIconPopupMenu = new PopupMenu();
+ final MenuItem popupMenuItem = new MenuItem("TEST PASSED!");
+ trayIconPopupMenu.add(popupMenuItem);
+ return trayIconPopupMenu;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/TrayIcon/PopupMenuLeakTest/PopupMenuLeakTest.java Fri Dec 20 14:42:37 2013 +0400
@@ -0,0 +1,149 @@
+/*
+ * 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
+ @run main/othervm -Xmx50m PopupMenuLeakTest
+ */
+
+import java.awt.*;
+import javax.swing.SwingUtilities;
+import sun.awt.SunToolkit;
+
+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<WeakReference<TrayIcon>> iconWeakReference = new AtomicReference<>();
+ static final AtomicReference<WeakReference<PopupMenu>> popupWeakReference = new AtomicReference<>();
+
+ public static void main(String[] args) throws Exception {
+ 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);
+ }
+
+ private static void assertCollected(WeakReference<?> reference, String message) {
+ java.util.List<byte[]> bytes = new ArrayList<>();
+ for (int i = 0; i < 5; i ++) {
+ try {
+ while (true) {
+ bytes.add(new byte[1024]);
+ }
+ } catch (OutOfMemoryError err) {
+ bytes = new ArrayList<>();
+ }
+ }
+ 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() {
+ final PopupMenu trayIconPopupMenu = new PopupMenu();
+ final MenuItem popupMenuItem = new MenuItem("TEST!");
+ trayIconPopupMenu.add(popupMenuItem);
+ return trayIconPopupMenu;
+ }
+
+ private static void sleep() {
+ ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) { }
+ }
+}