Merge
authorddehaven
Mon, 19 Sep 2016 13:12:28 -0700
changeset 41388 1a4a7fe92ac6
parent 41035 9cb87c88ed85 (current diff)
parent 41387 9c22dbd69da3 (diff)
child 41389 21cd852c2b60
Merge
jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.html
--- a/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m	Wed Jul 05 22:14:30 2017 +0200
+++ b/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m	Mon Sep 19 13:12:28 2016 -0700
@@ -376,7 +376,6 @@
 {
     void (^copy)() = [block copy];
     NSInteger encode = (NSInteger) copy;
-    [copy retain];
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
                                         location: NSMakePoint(0,0)
--- a/jdk/src/java.desktop/share/classes/java/awt/TextField.java	Wed Jul 05 22:14:30 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/TextField.java	Mon Sep 19 13:12:28 2016 -0700
@@ -159,8 +159,8 @@
      * @param      text       the text to be displayed. If
      *             {@code text} is {@code null}, the empty
      *             string {@code ""} will be displayed.
-     *             If {@code text} contains EOL character, then
-     *             it will be replaced by space character.
+     *             If {@code text} contains EOL and/or LF characters, then
+     *             each will be replaced by space character.
      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
      * returns true.
      * @see java.awt.GraphicsEnvironment#isHeadless
@@ -192,8 +192,8 @@
      * @param      text       the text to be displayed. If
      *             {@code text} is {@code null}, the empty
      *             string {@code ""} will be displayed.
-     *             If {@code text} contains EOL character, then
-     *             it will be replaced by space character.
+     *             If {@code text} contains EOL and/or LF characters, then
+     *             each will be replaced by space character.
      * @param      columns     the number of columns.  If
      *             {@code columns} is less than {@code 0},
      *             {@code columns} is set to {@code 0}.
@@ -300,8 +300,8 @@
      * @param      t       the new text. If
      *             {@code t} is {@code null}, the empty
      *             string {@code ""} will be displayed.
-     *             If {@code t} contains EOL character, then
-     *             it will be replaced by space character.
+     *             If {@code t} contains EOL and/or LF characters, then
+     *             each will be replaced by space character.
      * @see         java.awt.TextComponent#getText
      */
     public void setText(String t) {
--- a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c	Wed Jul 05 22:14:30 2017 +0200
+++ b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c	Mon Sep 19 13:12:28 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -553,30 +553,43 @@
 METHODDEF(void)
 sun_jpeg_output_message (j_common_ptr cinfo)
 {
-  char buffer[JMSG_LENGTH_MAX];
-  jstring string;
-  imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
-  JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
-  jobject theObject;
-
-  /* Create the message */
-  (*cinfo->err->format_message) (cinfo, buffer);
-
-  // Create a new java string from the message
-  string = (*env)->NewStringUTF(env, buffer);
-  CHECK_NULL(string);
-
-  theObject = data->imageIOobj;
-
-  if (cinfo->is_decompressor) {
-      (*env)->CallVoidMethod(env, theObject,
-                             JPEGImageReader_warningWithMessageID,
-                             string);
-  } else {
-      (*env)->CallVoidMethod(env, theObject,
-                             JPEGImageWriter_warningWithMessageID,
-                             string);
-  }
+    char buffer[JMSG_LENGTH_MAX];
+    jstring string;
+    imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
+    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+    jobject theObject;
+
+    /* Create the message */
+    (*cinfo->err->format_message) (cinfo, buffer);
+
+    // Create a new java string from the message
+    string = (*env)->NewStringUTF(env, buffer);
+    CHECK_NULL(string);
+
+    theObject = data->imageIOobj;
+
+    if (cinfo->is_decompressor) {
+        struct jpeg_source_mgr *src = ((j_decompress_ptr)cinfo)->src;
+        RELEASE_ARRAYS(env, data, src->next_input_byte);
+        (*env)->CallVoidMethod(env, theObject,
+            JPEGImageReader_warningWithMessageID,
+            string);
+        if ((*env)->ExceptionOccurred(env)
+            || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
+            cinfo->err->error_exit(cinfo);
+        }
+    } else {
+        struct jpeg_destination_mgr *dest = ((j_compress_ptr)cinfo)->dest;
+        RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
+        (*env)->CallVoidMethod(env, theObject,
+            JPEGImageWriter_warningWithMessageID,
+            string);
+        if ((*env)->ExceptionOccurred(env)
+            || !GET_ARRAYS(env, data,
+            (const JOCTET **)(&dest->next_output_byte))) {
+            cinfo->err->error_exit(cinfo);
+        }
+    }
 }
 
 /* End of verbatim copy from jpegdecoder.c */
@@ -1043,6 +1056,7 @@
         if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
             cinfo->err->error_exit((j_common_ptr) cinfo);
         }
+        RELEASE_ARRAYS(env, data, src->next_input_byte);
         return;
     }
 
@@ -1798,9 +1812,14 @@
                                cinfo->out_color_space,
                                cinfo->num_components,
                                profileData);
+        if ((*env)->ExceptionOccurred(env)
+            || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
+            cinfo->err->error_exit((j_common_ptr) cinfo);
+        }
         if (reset) {
             jpeg_abort_decompress(cinfo);
         }
+        RELEASE_ARRAYS(env, data, src->next_input_byte);
     }
 
     return retval;
@@ -2010,6 +2029,7 @@
     jpeg_start_decompress(cinfo);
 
     if (numBands !=  cinfo->output_components) {
+        RELEASE_ARRAYS(env, data, src->next_input_byte);
         JNU_ThrowByName(env, "javax/imageio/IIOException",
                         "Invalid argument to native readImage");
         return data->abortFlag;
@@ -2018,6 +2038,7 @@
     if (cinfo->output_components <= 0 ||
         cinfo->image_width > (0xffffffffu / (unsigned int)cinfo->output_components))
     {
+        RELEASE_ARRAYS(env, data, src->next_input_byte);
         JNU_ThrowByName(env, "javax/imageio/IIOException",
                         "Invalid number of output components");
         return data->abortFlag;
@@ -2041,15 +2062,24 @@
             // the first interesting pass.
             jpeg_start_output(cinfo, cinfo->input_scan_number);
             if (wantUpdates) {
+                RELEASE_ARRAYS(env, data, src->next_input_byte);
                 (*env)->CallVoidMethod(env, this,
                                        JPEGImageReader_passStartedID,
                                        cinfo->input_scan_number-1);
+                if ((*env)->ExceptionOccurred(env)
+                    || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
+                    cinfo->err->error_exit((j_common_ptr) cinfo);
+                }
             }
         } else if (wantUpdates) {
+            RELEASE_ARRAYS(env, data, src->next_input_byte);
             (*env)->CallVoidMethod(env, this,
                                    JPEGImageReader_passStartedID,
                                    0);
-
+            if ((*env)->ExceptionOccurred(env)
+                || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
+                cinfo->err->error_exit((j_common_ptr) cinfo);
+            }
         }
 
         // Skip until the first interesting line
@@ -2137,8 +2167,13 @@
             done = TRUE;
         }
         if (wantUpdates) {
+            RELEASE_ARRAYS(env, data, src->next_input_byte);
             (*env)->CallVoidMethod(env, this,
                                    JPEGImageReader_passCompleteID);
+            if ((*env)->ExceptionOccurred(env)
+                || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
+                cinfo->err->error_exit((j_common_ptr) cinfo);
+            }
         }
 
     }
@@ -2837,7 +2872,6 @@
     if (setjmp(jerr->setjmp_buffer)) {
         /* If we get here, the JPEG code has signaled an error
            while writing. */
-        RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
         if (!(*env)->ExceptionOccurred(env)) {
             char buffer[JMSG_LENGTH_MAX];
             (*cinfo->err->format_message) ((j_common_ptr) cinfo,
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java	Wed Jul 05 22:14:30 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java	Mon Sep 19 13:12:28 2016 -0700
@@ -26,6 +26,8 @@
 
 import java.awt.*;
 import java.awt.peer.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 import sun.awt.AWTAccessor;
 import sun.awt.SunToolkit;
@@ -38,7 +40,8 @@
     static final boolean tryGtk;
     static {
         loadNativeLibraries();
-        tryGtk = Boolean.getBoolean("awt.robot.gtk");
+        tryGtk = AccessController.doPrivileged((PrivilegedAction<Boolean>)()
+                -> Boolean.getBoolean("awt.robot.gtk"));
     }
 
     private static boolean isGtkSupported =  false;
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WTrayIconPeer.java	Wed Jul 05 22:14:30 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WTrayIconPeer.java	Mon Sep 19 13:12:28 2016 -0700
@@ -28,16 +28,19 @@
 import java.awt.Graphics2D;
 import java.awt.AWTEvent;
 import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
 import java.awt.PopupMenu;
 import java.awt.Point;
 import java.awt.TrayIcon;
 import java.awt.Image;
+import java.awt.geom.AffineTransform;
 import java.awt.peer.TrayIconPeer;
 import java.awt.image.*;
 
 import sun.awt.AWTAccessor;
 import sun.awt.SunToolkit;
 import sun.awt.image.IntegerComponentRaster;
+import sun.java2d.pipe.Region;
 
 final class WTrayIconPeer extends WObjectPeer implements TrayIconPeer {
     static final int TRAY_ICON_WIDTH = 16;
@@ -123,16 +126,22 @@
             return;
 
         boolean autosize = ((TrayIcon)target).isImageAutoSize();
-
-        BufferedImage bufImage = new BufferedImage(TRAY_ICON_WIDTH, TRAY_ICON_HEIGHT,
-                                                   BufferedImage.TYPE_INT_ARGB);
+        AffineTransform tx = GraphicsEnvironment.getLocalGraphicsEnvironment().
+                getDefaultScreenDevice().getDefaultConfiguration().
+                getDefaultTransform();
+        int w = Region.clipScale(TRAY_ICON_WIDTH, tx.getScaleX());
+        int h = Region.clipScale(TRAY_ICON_HEIGHT, tx.getScaleY());
+        int imgWidth = Region.clipScale(image.getWidth(observer), tx.getScaleX());
+        int imgHeight = Region.clipScale(image.getHeight(observer), tx.getScaleY());
+        BufferedImage bufImage = new BufferedImage(w,
+                h, BufferedImage.TYPE_INT_ARGB);
         Graphics2D gr = bufImage.createGraphics();
         if (gr != null) {
             try {
                 gr.setPaintMode();
 
-                gr.drawImage(image, 0, 0, (autosize ? TRAY_ICON_WIDTH : image.getWidth(observer)),
-                             (autosize ? TRAY_ICON_HEIGHT : image.getHeight(observer)), observer);
+                gr.drawImage(image, 0, 0, (autosize ? w : imgWidth),
+                             (autosize ? h : imgHeight), observer);
 
                 createNativeImage(bufImage);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Robot/SpuriousMouseEvents/SpuriousMouseEvents.java	Mon Sep 19 13:12:28 2016 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, 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
+  @key headful
+  @bug 5097801 8163270
+  @summary Tests that no mouse events are sent to component if robot is
+           moving mouse on another screen, Xinerama
+  @run main SpuriousMouseEvents
+ */
+import java.awt.AWTException;
+import java.awt.GraphicsEnvironment;
+import java.awt.GraphicsDevice;
+import java.awt.Robot;
+import java.awt.GraphicsConfiguration;
+import java.awt.Frame;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.event.MouseEvent;
+
+public class SpuriousMouseEvents {
+
+    private static volatile boolean testPassed = true;
+
+    public static void main(String args[]) throws AWTException {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice[] gds = ge.getScreenDevices();
+        if (gds.length < 2) {
+            return;
+        }
+
+        Robot r = null;
+        try {
+            r = new Robot();
+        } catch (Exception e) {
+            throw new RuntimeException("Couldn't create AWT robot" + e);
+        }
+
+        for (int i = 1; i >= 0; i--) {
+            GraphicsDevice gd = gds[i];
+            GraphicsDevice gdo = gds[1 - i];
+            GraphicsConfiguration gc = gd.getDefaultConfiguration();
+            GraphicsConfiguration gco = gdo.getDefaultConfiguration();
+            Frame f = new Frame("Frame", gc);
+            f.setBounds(gc.getBounds().x + 100, gc.getBounds().y + 100, 200, 200);
+            f.addMouseMotionListener(new MouseMotionAdapter() {
+                public void mouseMoved(MouseEvent me) {
+                    testPassed = false;
+                }
+            });
+            f.setVisible(true);
+
+            r = new Robot(gdo);
+            int x = (int) gco.getBounds().x;
+            for (int j = x; j < x + 400; j += 10) {
+                r.mouseMove(j, 200);
+                r.delay(10);
+            }
+            r.delay(1000);
+
+            f.setVisible(false);
+            f.dispose();
+
+            if (!testPassed) {
+                break;
+            }
+        }
+
+        if (!testPassed) {
+            throw new RuntimeException("Wrong mouse events are sent");
+        }
+    }
+}
--- a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.html	Wed Jul 05 22:14:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-<!--
- Copyright (c) 2016, 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>
-<head>
-<title> MultiResolutionTrayIconTest </title>
-</head>
-<body>
-<applet code="MultiResolutionTrayIconTest.class" width=100 height=30></applet>
-
-To run test please push "Start" (if system tray is not supported, push "Pass").
-
-Two tray icons will appear (note: sometimes they can go to the tray icons pool).
-
-Please check if both of them have correct size and
-the same colouring (white rectagle in a blue mount). In this case please push "Pass".
-
-Otherwise (if the 2nd red-white small icon appears) please push "Fail".
-
-</body>
-</html>
--- a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java	Wed Jul 05 22:14:30 2017 +0200
+++ b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java	Mon Sep 19 13:12:28 2016 -0700
@@ -22,96 +22,177 @@
  */
 
 
-/*
-  @test
-  @bug 8150176 8151773
-  @summary Check if correct resolution variant is used for tray icon.
-  @author a.stepanov
-  @run applet/manual=yesno MultiResolutionTrayIconTest.html
-*/
-
-
-import java.applet.Applet;
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.image.*;
-
-
-public class MultiResolutionTrayIconTest extends Applet {
-
-    private SystemTray tray;
-    private TrayIcon   icon, iconMRI;
+/**
+ * @test
+ * @key headful
+ * @bug 8150176 8151773 8150176
+ * @summary Check if correct resolution variant is used for tray icon.
+ * @run main/manual/othervm -Dsun.java2d.uiScale=2 MultiResolutionTrayIconTest
+ */
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.SystemTray;
+import java.awt.TrayIcon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import javax.swing.JFrame;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
-    public void init() { this.setLayout(new BorderLayout()); }
-
-    public void start() {
-
-        boolean trayIsSupported = SystemTray.isSupported();
-        Button b = new Button("Start");
-        if (trayIsSupported) {
+public class MultiResolutionTrayIconTest {
+    private static SystemTray tray;
+    private static TrayIcon icon;
+    private static GridBagLayout layout;
+    private static JPanel mainControlPanel;
+    private static JPanel resultButtonPanel;
+    private static JLabel instructionText;
+    private static JButton passButton;
+    private static JButton failButton;
+    private static JButton startButton;
+    private static JFrame mainFrame;
+    private static CountDownLatch latch;
 
-            prepareIcons();
-            b.addActionListener(new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e) { doTest(); }
-            });
-        } else {
-             b.setLabel("not supported");
-             b.setEnabled(false);
-             System.out.println("system tray is not supported");
-        }
-        add(b, BorderLayout.CENTER);
-
-        validate();
-        setVisible(true);
+    public static void main(String[] args) throws Exception {
+        latch = new CountDownLatch(1);
+        createUI();
+        latch.await(200, TimeUnit.SECONDS);
     }
 
-    private BufferedImage generateImage(int w, int h, Color c) {
+    public static void createUI() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                mainFrame = new JFrame("TrayIcon Test");
+                boolean trayIsSupported = SystemTray.isSupported();
+                tray = SystemTray.getSystemTray();
+                Dimension d = tray.getTrayIconSize();
+                icon = new TrayIcon(createIcon(d.width, d.height));
+                icon.setImageAutoSize(true);
+                layout = new GridBagLayout();
+                mainControlPanel = new JPanel(layout);
+                resultButtonPanel = new JPanel(layout);
+
+                GridBagConstraints gbc = new GridBagConstraints();
+                String instructions
+                        = "<html>INSTRUCTIONS:<br>"
+                        + "Press start button to add icon to system tray.<br><br>"
+                        + "If Icon color is green test"
+                        + " passes else failed.<br><br></html>";
+
+                instructionText = new JLabel();
+                instructionText.setText(instructions);
+
+                gbc.gridx = 0;
+                gbc.gridy = 0;
+                gbc.fill = GridBagConstraints.HORIZONTAL;
+                mainControlPanel.add(instructionText, gbc);
+                startButton = new JButton("Start");
+                startButton.setActionCommand("Start");
+                if (trayIsSupported) {
+
+                    startButton.addActionListener((ActionEvent e) -> {
+                        doTest();
+                    });
+                } else {
+                    startButton.setEnabled(false);
+                    System.out.println("system tray is not supported");
+                    latch.countDown();
+                }
+                gbc.gridx = 0;
+                gbc.gridy = 0;
+                resultButtonPanel.add(startButton, gbc);
 
-        BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+                passButton = new JButton("Pass");
+                passButton.setActionCommand("Pass");
+                passButton.addActionListener((ActionEvent e) -> {
+                    latch.countDown();
+                    removeIcon();
+                    mainFrame.dispose();
+                });
+                failButton = new JButton("Fail");
+                failButton.setActionCommand("Fail");
+                failButton.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        removeIcon();
+                        latch.countDown();
+                        mainFrame.dispose();
+                        throw new RuntimeException("Test Failed");
+                    }
+                });
+                gbc.gridx = 1;
+                gbc.gridy = 0;
+                resultButtonPanel.add(passButton, gbc);
+                gbc.gridx = 2;
+                gbc.gridy = 0;
+                resultButtonPanel.add(failButton, gbc);
+
+                gbc.gridx = 0;
+                gbc.gridy = 1;
+                mainControlPanel.add(resultButtonPanel, gbc);
+
+                mainFrame.add(mainControlPanel);
+                mainFrame.setSize(400, 200);
+                mainFrame.setLocationRelativeTo(null);
+                mainFrame.setVisible(true);
+
+                mainFrame.addWindowListener(new WindowAdapter() {
+                    @Override
+                    public void windowClosing(WindowEvent e) {
+                        removeIcon();
+                        latch.countDown();
+                        mainFrame.dispose();
+                    }
+                });
+            }
+        });
+
+    }
+
+    private static BaseMultiResolutionImage createIcon(int w, int h) {
+        return new BaseMultiResolutionImage(
+                new BufferedImage[]{generateImage(w, h, 1, Color.RED),
+                    generateImage(w, h, 2, Color.GREEN)});
+    }
+
+    private static BufferedImage generateImage(int w, int h, int scale, Color c) {
+
+        int x = w * scale, y = h * scale;
+        BufferedImage img = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);
         Graphics g = img.getGraphics();
         g.setColor(c);
-        g.fillRect(0, 0, w, h);
+        g.fillRect(0, 0, x, y);
         g.setColor(Color.WHITE);
-        int r = (Math.min(w, h) >= 8) ? 3 : 1;
-        g.fillRect(r, r, w - 2 * r, h - 2 * r);
+        g.fillRect(x / 3, y / 3, x / 3, y / 3);
         return img;
     }
 
-    private void prepareIcons() {
-
-        tray = SystemTray.getSystemTray();
-        Dimension d = tray.getTrayIconSize();
-        int w = d.width, h = d.height;
+    private static void doTest() {
 
-        BufferedImage img = generateImage(w, h, Color.BLUE);
-        // use wrong icon size for "nok"
-        BufferedImage nok = generateImage(w / 2 + 2, h / 2 + 2, Color.RED);
-        BaseMultiResolutionImage mri =
-            new BaseMultiResolutionImage(new BufferedImage[] {nok, img});
-        icon = new TrayIcon(img);
-        icon.setImageAutoSize(true); // just in case
-        iconMRI = new TrayIcon(mri);
-        iconMRI.setImageAutoSize(true);
-    }
-
-    private void doTest() {
-
-        if (tray.getTrayIcons().length > 0) { return; } // icons were added already
+        if (tray.getTrayIcons().length > 0) {
+            return;
+        }
         try {
             tray.add(icon);
-            tray.add(iconMRI);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
 
-    public void stop() {
-
-        // check for null, just in case
+    private static void removeIcon() {
         if (tray != null) {
             tray.remove(icon);
-            tray.remove(iconMRI);
         }
     }
 }
+