Question

I'm trying to develop a Mac OsX app provided by a system tray icon, so after the first attempt with the simplest code to achieve it I noticed that every apps tray icon's (both system and user apps) on mac osX (10.8) allows to activate the relative popup menu with both left and right click on it but with my project only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code:

public class SystemTrayDemo
{
    private SystemTray tray;
    private TrayIcon tray_icon;

    public SystemTrayDemo()
    {
        if (!SystemTray.isSupported())
        {
            JOptionPane.showMessageDialog(null, "System tray not supported!");
            return;
        }
        else
           tray = SystemTray.getSystemTray();

        final PopupMenu popup = new PopupMenu(); 

        MenuItem exit = new MenuItem("Exit");

        exit.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                if (tray != null)
                {                    
                    tray.remove(tray_icon);
                    System.exit(0);
                }
            }
        });

        popup.add(exit);

        //add tray icon
        tray_icon = new TrayIcon(getIcon("images/wifi.png"), "Open documents...", popup);
        tray_icon.setImageAutoSize(true);

        try
        {            
            tray.add(tray_icon); // adds icon
        }
        catch (AWTException ex) {}
    }


    private Image getIcon(String name)
    {
        URL _url = getClass().getResource(name);
        return new ImageIcon(_url).getImage();
    }

    public static void main(String args[])
    {
        new SystemTrayDemo();
    }
}

but how I already said, only through left mouse button click. So during a further attempt I've tried to mimic the behavior of the tray icons of every other apps using a MouseListener and firing a left button event on right click event using dispatchEvent() method like so:

    public static void fireMouseEvent(Component c)
    {
        MouseEvent me = new MouseEvent(c, // which
                    MouseEvent.MOUSE_CLICKED, // what
                    System.currentTimeMillis(), // when
                    MouseEvent.BUTTON1_MASK, // no modifiers
                    0, 0, // where: at (10, 10}
                    1, // only 1 click 
                    true); // popup trigger

        c.dispatchEvent(me);
    }

the event will handled by the mouse listener but obviously TrayIcon Class is not a Component subclass and therefore the source of MouseEvent is null and I get a NPE. Here's my MouseListener:

    class MouseAdapt extends java.awt.event.MouseAdapter
    {

        public void mouseClicked(java.awt.event.MouseEvent me)
        {
            int button = me.getButton();

            if(button == java.awt.event.MouseEvent.BUTTON3)
            {
                fireMouseEvent(me.getComponent());
            }
        }
    }

    try
    {            
        tray.add(tray_icon); // aggiungi l'icona
        tray_icon.addMouseListener(new MouseAdapt());
    }
    catch (AWTException ex) {}

Sorry for my english, I hope that someone who have ever had some experience with that kind of projects can help me. I've searched for hours but with no luck. Thank You for your help.

Was it helpful?

Solution

Edit: There's now a library working to fix all of this here: https://github.com/dorkbox/SystemTray


to activate the [TrayIcon] relative popup menu with both left and right click

This is simply not possible on Mac + Java currently. Using reflection to invoke the underlying triggers doesn't seem to help. This is a bug.

https://bugs.openjdk.java.net/browse/JDK-8041890

only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code

Even this is broken in some Java versions (7u79), fixed with an upgrade...

https://bugs.openjdk.java.net/browse/JDK-7158615

Cross-Platform TrayIcon Support:

Albeit slightly off-topic, I wanted to add, some projects use a JXTrayIcon to accomplish some fancy drop-down menus in Linux/Windows, etc. These also cause problems on Mac despite a click-bug it already suffers from today as well as bugs with Gnome3 requiring a completely separate hack. But on Mac, any attempt to use the decorated menus causes the menu to linger and is a very bad experience for the end-user. The solution I settled on was to use AWT for Mac, Swing for everything else. The Java TrayIcon support is in dire need of a rewrite. JavaFX claims to help this initiative, but it's staged for Java 9. In the mean time, I'm sticking to OS-dependent hacks.

Related Tray Issues for Other Platforms

Furthermore, some Linux distributions like Ubuntu have removed the tray icon by default in the Unity desktop, causing further headaches. https://askubuntu.com/a/457212/412004

In addition, the transparency of the icon is replaced with a gray color on Gtk/Gnome or Qt/KDE powered desktops (Both OpenJDK and Oracle JRE suffer this) https://stackoverflow.com/a/3882028/3196753 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521

In addition, Gnome3 powered desktops may show it in the wrong corner, not at all, or it may show but be unclickable (Both OpenJDK and Oracle JRE suffer this) https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=660157 https://bugzilla.redhat.com/show_bug.cgi?id=1014448

In addition to that, high-DPI screens on Windows have a bug that draws the icon incorrectly: Windows 8 Distorts my TrayIcon

So in summary, the state of the System Tray in Java is OK, but due to the combination of factors is quite fragmented and buggy in JDK6, JDK7 and JDK8.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top