forked from I2P_Developers/i2p.i2p
DTG: Implement second TrayManager menu implementation in Swing.
Use Swing for non-Windows menus because AWT looks terrible on Linux and the button handling there is almost impossible to fix TODO: test on Mac
This commit is contained in:
@ -6,6 +6,8 @@ import java.awt.TrayIcon;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
@ -20,20 +22,17 @@ import net.i2p.desktopgui.router.RouterManager;
|
|||||||
*/
|
*/
|
||||||
class ExternalTrayManager extends TrayManager {
|
class ExternalTrayManager extends TrayManager {
|
||||||
|
|
||||||
public ExternalTrayManager(I2PAppContext ctx, Main main) {
|
public ExternalTrayManager(I2PAppContext ctx, Main main, boolean useSwing) {
|
||||||
super(ctx, main);
|
super(ctx, main, useSwing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PopupMenu getMainMenu() {
|
public PopupMenu getMainMenu() {
|
||||||
PopupMenu popup = new PopupMenu();
|
PopupMenu popup = new PopupMenu();
|
||||||
MenuItem startItem = new MenuItem(_t("Start I2P"));
|
MenuItem startItem = new MenuItem(_t("Start I2P"));
|
||||||
startItem.addActionListener(new ActionListener() {
|
startItem.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
new SwingWorker<Object, Object>() {
|
new SwingWorker<Object, Object>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object doInBackground() throws Exception {
|
protected Object doInBackground() throws Exception {
|
||||||
RouterManager.start();
|
RouterManager.start();
|
||||||
@ -48,10 +47,36 @@ class ExternalTrayManager extends TrayManager {
|
|||||||
//since that risks killing the I2P process as well.
|
//since that risks killing the I2P process as well.
|
||||||
tray.remove(trayIcon);
|
tray.remove(trayIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
popup.add(startItem);
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPopupMenu getSwingMainMenu() {
|
||||||
|
JPopupMenu popup = new JPopupMenu();
|
||||||
|
JMenuItem startItem = new JMenuItem(_t("Start I2P"));
|
||||||
|
startItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
RouterManager.start();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
trayIcon.displayMessage(_t("Starting"), _t("I2P is starting!"), TrayIcon.MessageType.INFO);
|
||||||
|
//Hide the tray icon.
|
||||||
|
//We cannot stop the desktopgui program entirely,
|
||||||
|
//since that risks killing the I2P process as well.
|
||||||
|
tray.remove(trayIcon);
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
popup.add(startItem);
|
popup.add(startItem);
|
||||||
return popup;
|
return popup;
|
||||||
|
@ -5,6 +5,9 @@ import java.awt.PopupMenu;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
import net.i2p.desktopgui.router.RouterManager;
|
import net.i2p.desktopgui.router.RouterManager;
|
||||||
@ -23,14 +26,14 @@ class InternalTrayManager extends TrayManager {
|
|||||||
private final RouterContext _context;
|
private final RouterContext _context;
|
||||||
private final Log log;
|
private final Log log;
|
||||||
private MenuItem _restartItem, _stopItem, _cancelItem;
|
private MenuItem _restartItem, _stopItem, _cancelItem;
|
||||||
|
private JMenuItem _jrestartItem, _jstopItem, _jcancelItem;
|
||||||
|
|
||||||
public InternalTrayManager(RouterContext ctx, Main main) {
|
public InternalTrayManager(RouterContext ctx, Main main, boolean useSwing) {
|
||||||
super(ctx, main);
|
super(ctx, main, useSwing);
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
log = ctx.logManager().getLog(InternalTrayManager.class);
|
log = ctx.logManager().getLog(InternalTrayManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PopupMenu getMainMenu() {
|
public PopupMenu getMainMenu() {
|
||||||
PopupMenu popup = new PopupMenu();
|
PopupMenu popup = new PopupMenu();
|
||||||
|
|
||||||
@ -171,6 +174,146 @@ class InternalTrayManager extends TrayManager {
|
|||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JPopupMenu getSwingMainMenu() {
|
||||||
|
JPopupMenu popup = new JPopupMenu();
|
||||||
|
|
||||||
|
JMenuItem browserLauncher = new JMenuItem(_t("Launch I2P Browser"));
|
||||||
|
browserLauncher.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
try {
|
||||||
|
I2PDesktop.browse("http://localhost:7657");
|
||||||
|
} catch (BrowseException e1) {
|
||||||
|
log.log(Log.WARN, "Failed to open browser!", e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JMenu desktopguiConfigurationLauncher = new JMenu(_t("Configure I2P System Tray"));
|
||||||
|
JMenuItem configSubmenu = new JMenuItem(_t("Disable"));
|
||||||
|
configSubmenu.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
configureDesktopgui(false);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final JMenuItem restartItem;
|
||||||
|
if (_context.hasWrapper()) {
|
||||||
|
restartItem = new JMenuItem(_t("Restart I2P"));
|
||||||
|
restartItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
RouterManager.restartGracefully(_context);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
restartItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final JMenuItem stopItem = new JMenuItem(_t("Stop I2P"));
|
||||||
|
stopItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
RouterManager.shutDownGracefully(_context);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final JMenuItem restartItem2;
|
||||||
|
if (_context.hasWrapper()) {
|
||||||
|
restartItem2 = new JMenuItem(_t("Restart I2P Immediately"));
|
||||||
|
restartItem2.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
RouterManager.restart(_context);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
restartItem2 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final JMenuItem stopItem2 = new JMenuItem(_t("Stop I2P Immediately"));
|
||||||
|
stopItem2.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
RouterManager.shutDown(_context);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final JMenuItem cancelItem = new JMenuItem(_t("Cancel I2P Shutdown"));
|
||||||
|
cancelItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
new SwingWorker<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
RouterManager.cancelShutdown(_context);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
popup.add(browserLauncher);
|
||||||
|
popup.addSeparator();
|
||||||
|
desktopguiConfigurationLauncher.add(configSubmenu);
|
||||||
|
popup.add(desktopguiConfigurationLauncher);
|
||||||
|
popup.addSeparator();
|
||||||
|
if (_context.hasWrapper())
|
||||||
|
popup.add(restartItem);
|
||||||
|
popup.add(stopItem);
|
||||||
|
if (_context.hasWrapper())
|
||||||
|
popup.add(restartItem2);
|
||||||
|
popup.add(stopItem2);
|
||||||
|
popup.add(cancelItem);
|
||||||
|
|
||||||
|
_jrestartItem = restartItem;
|
||||||
|
_jstopItem = stopItem;
|
||||||
|
_jcancelItem = cancelItem;
|
||||||
|
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the menu
|
* Update the menu
|
||||||
* @since 0.9.26
|
* @since 0.9.26
|
||||||
@ -179,15 +322,23 @@ class InternalTrayManager extends TrayManager {
|
|||||||
boolean x = RouterManager.isShutdownInProgress(_context);
|
boolean x = RouterManager.isShutdownInProgress(_context);
|
||||||
if (_restartItem != null)
|
if (_restartItem != null)
|
||||||
_restartItem.setEnabled(!x);
|
_restartItem.setEnabled(!x);
|
||||||
_stopItem.setEnabled(!x);
|
if (_stopItem != null)
|
||||||
_cancelItem.setEnabled(x);
|
_stopItem.setEnabled(!x);
|
||||||
|
if (_cancelItem != null)
|
||||||
|
_cancelItem.setEnabled(x);
|
||||||
|
if (_jrestartItem != null)
|
||||||
|
_jrestartItem.setEnabled(!x);
|
||||||
|
if (_jstopItem != null)
|
||||||
|
_jstopItem.setEnabled(!x);
|
||||||
|
if (_jcancelItem != null)
|
||||||
|
_jcancelItem.setEnabled(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 0.9.26 from removed gui/DesktopguiConfigurationFrame
|
* @since 0.9.26 from removed gui/DesktopguiConfigurationFrame
|
||||||
*/
|
*/
|
||||||
private void configureDesktopgui(boolean enable) {
|
private void configureDesktopgui(boolean enable) {
|
||||||
String property = "desktopgui.enabled";
|
String property = Main.PROP_ENABLE;
|
||||||
String value = Boolean.toString(enable);
|
String value = Boolean.toString(enable);
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import net.i2p.desktopgui.util.*;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.app.RouterApp;
|
import net.i2p.router.app.RouterApp;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.SystemVersion;
|
||||||
import net.i2p.util.Translate;
|
import net.i2p.util.Translate;
|
||||||
import net.i2p.util.I2PProperties.I2PPropertyCallback;
|
import net.i2p.util.I2PProperties.I2PPropertyCallback;
|
||||||
|
|
||||||
@ -29,6 +30,8 @@ public class Main implements RouterApp {
|
|||||||
private final Log log;
|
private final Log log;
|
||||||
private ClientAppState _state = UNINITIALIZED;
|
private ClientAppState _state = UNINITIALIZED;
|
||||||
private TrayManager _trayManager;
|
private TrayManager _trayManager;
|
||||||
|
public static final String PROP_ENABLE = "desktopgui.enabled";
|
||||||
|
private static final String PROP_SWING = "desktopgui.swing";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 0.9.26
|
* @since 0.9.26
|
||||||
@ -60,10 +63,11 @@ public class Main implements RouterApp {
|
|||||||
*/
|
*/
|
||||||
private synchronized void startUp() throws Exception {
|
private synchronized void startUp() throws Exception {
|
||||||
final TrayManager trayManager;
|
final TrayManager trayManager;
|
||||||
|
boolean useSwing = _appContext.getProperty(PROP_SWING, !SystemVersion.isWindows());
|
||||||
if (_context != null)
|
if (_context != null)
|
||||||
trayManager = new InternalTrayManager(_context, this);
|
trayManager = new InternalTrayManager(_context, this, useSwing);
|
||||||
else
|
else
|
||||||
trayManager = new ExternalTrayManager(_appContext, this);
|
trayManager = new ExternalTrayManager(_appContext, this, useSwing);
|
||||||
trayManager.startManager();
|
trayManager.startManager();
|
||||||
_trayManager = trayManager;
|
_trayManager = trayManager;
|
||||||
changeState(RUNNING);
|
changeState(RUNNING);
|
||||||
@ -72,14 +76,12 @@ public class Main implements RouterApp {
|
|||||||
|
|
||||||
if (_context != null) {
|
if (_context != null) {
|
||||||
_context.addPropertyCallback(new I2PPropertyCallback() {
|
_context.addPropertyCallback(new I2PPropertyCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void propertyChanged(String arg0, String arg1) {
|
public void propertyChanged(String arg0, String arg1) {
|
||||||
if(arg0.equals(Translate.PROP_LANG)) {
|
if(arg0.equals(Translate.PROP_LANG)) {
|
||||||
trayManager.languageChanged();
|
trayManager.languageChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,26 @@
|
|||||||
package net.i2p.desktopgui;
|
package net.i2p.desktopgui;
|
||||||
|
|
||||||
import java.awt.AWTException;
|
import java.awt.AWTException;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.PopupMenu;
|
import java.awt.PopupMenu;
|
||||||
import java.awt.SystemTray;
|
import java.awt.SystemTray;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.TrayIcon;
|
import java.awt.TrayIcon;
|
||||||
|
import java.awt.event.FocusEvent;
|
||||||
|
import java.awt.event.FocusListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.MouseListener;
|
import java.awt.event.MouseListener;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.event.MenuKeyEvent;
|
||||||
|
import javax.swing.event.MenuKeyListener;
|
||||||
|
import javax.swing.event.PopupMenuEvent;
|
||||||
|
import javax.swing.event.PopupMenuListener;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
|
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
|
||||||
import net.i2p.util.SystemVersion;
|
import net.i2p.util.SystemVersion;
|
||||||
@ -21,6 +32,7 @@ abstract class TrayManager {
|
|||||||
|
|
||||||
protected final I2PAppContext _appContext;
|
protected final I2PAppContext _appContext;
|
||||||
protected final Main _main;
|
protected final Main _main;
|
||||||
|
protected final boolean _useSwing;
|
||||||
///The tray area, or null if unsupported
|
///The tray area, or null if unsupported
|
||||||
protected SystemTray tray;
|
protected SystemTray tray;
|
||||||
///Our tray icon, or null if unsupported
|
///Our tray icon, or null if unsupported
|
||||||
@ -29,37 +41,99 @@ abstract class TrayManager {
|
|||||||
/**
|
/**
|
||||||
* Instantiate tray manager.
|
* Instantiate tray manager.
|
||||||
*/
|
*/
|
||||||
protected TrayManager(I2PAppContext ctx, Main main) {
|
protected TrayManager(I2PAppContext ctx, Main main, boolean useSwing) {
|
||||||
_appContext = ctx;
|
_appContext = ctx;
|
||||||
_main = main;
|
_main = main;
|
||||||
|
_useSwing = useSwing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the tray icon to the system tray and start everything up.
|
* Add the tray icon to the system tray and start everything up.
|
||||||
*/
|
*/
|
||||||
public synchronized void startManager() throws AWTException {
|
public synchronized void startManager() throws AWTException {
|
||||||
if(SystemTray.isSupported()) {
|
if (!SystemTray.isSupported())
|
||||||
// TODO figure out how to get menu to pop up on left-click
|
|
||||||
// left-click does nothing by default
|
|
||||||
// MouseListener, MouseEvent, ...
|
|
||||||
tray = SystemTray.getSystemTray();
|
|
||||||
// Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
|
||||||
String tooltip = SystemVersion.isWindows() ? _t("I2P: Right-click for menu") : null;
|
|
||||||
trayIcon = new TrayIcon(getTrayImage(), tooltip, getMainMenu());
|
|
||||||
trayIcon.setImageAutoSize(true); //Resize image to fit the system tray
|
|
||||||
tray.add(trayIcon);
|
|
||||||
// 16x16 on Windows, 24x24 on Linux, but that will probably vary
|
|
||||||
//System.out.println("Tray icon size is " + trayIcon.getSize());
|
|
||||||
trayIcon.addMouseListener(new MouseListener() {
|
|
||||||
public void mouseClicked(MouseEvent m) { updateMenu(); }
|
|
||||||
public void mouseEntered(MouseEvent m) { updateMenu(); }
|
|
||||||
public void mouseExited(MouseEvent m) { updateMenu(); }
|
|
||||||
public void mousePressed(MouseEvent m) { updateMenu(); }
|
|
||||||
public void mouseReleased(MouseEvent m) { updateMenu(); }
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new AWTException("SystemTray not supported");
|
throw new AWTException("SystemTray not supported");
|
||||||
}
|
tray = SystemTray.getSystemTray();
|
||||||
|
// Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||||
|
String tooltip = SystemVersion.isWindows() ? _t("I2P: Right-click for menu") : null;
|
||||||
|
TrayIcon ti;
|
||||||
|
if (_useSwing)
|
||||||
|
ti = getSwingTrayIcon(tooltip);
|
||||||
|
else
|
||||||
|
ti = getAWTTrayIcon(tooltip);
|
||||||
|
ti.setImageAutoSize(true); //Resize image to fit the system tray
|
||||||
|
tray.add(ti);
|
||||||
|
trayIcon = ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrayIcon getAWTTrayIcon(String tooltip) throws AWTException {
|
||||||
|
PopupMenu menu = getMainMenu();
|
||||||
|
if (!SystemVersion.isWindows())
|
||||||
|
menu.setFont(new Font("Arial", Font.BOLD, 14));
|
||||||
|
TrayIcon ti = new TrayIcon(getTrayImage(), tooltip, menu);
|
||||||
|
ti.addMouseListener(new MouseListener() {
|
||||||
|
public void mouseClicked(MouseEvent m) {}
|
||||||
|
public void mouseEntered(MouseEvent m) {}
|
||||||
|
public void mouseExited(MouseEvent m) {}
|
||||||
|
public void mousePressed(MouseEvent m) { updateMenu(); }
|
||||||
|
public void mouseReleased(MouseEvent m) { updateMenu(); }
|
||||||
|
});
|
||||||
|
return ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrayIcon getSwingTrayIcon(String tooltip) throws AWTException {
|
||||||
|
// A JPopupMenu by itself is hard to get rid of,
|
||||||
|
// so we hang it off a zero-size, undecorated JFrame.
|
||||||
|
// http://stackoverflow.com/questions/1498789/jpopupmenu-behavior
|
||||||
|
// http://stackoverflow.com/questions/2581314/how-do-you-hide-a-swing-popup-when-you-click-somewhere-else
|
||||||
|
final JFrame frame = new JFrame();
|
||||||
|
// http://stackoverflow.com/questions/2011601/jframe-without-frame-border-maximum-button-minimum-button-and-frame-icon
|
||||||
|
frame.setUndecorated(true);
|
||||||
|
frame.setMinimumSize(new Dimension(0, 0));
|
||||||
|
frame.setSize(0, 0);
|
||||||
|
final JPopupMenu menu = getSwingMainMenu();
|
||||||
|
menu.setFocusable(true);
|
||||||
|
frame.add(menu);
|
||||||
|
TrayIcon ti = new TrayIcon(getTrayImage(), tooltip, null);
|
||||||
|
ti.addMouseListener(new MouseListener() {
|
||||||
|
public void mouseClicked(MouseEvent e) {}
|
||||||
|
public void mouseEntered(MouseEvent e) {}
|
||||||
|
public void mouseExited(MouseEvent e) {}
|
||||||
|
public void mousePressed(MouseEvent e) { handle(e); }
|
||||||
|
public void mouseReleased(MouseEvent e) { handle(e); }
|
||||||
|
private void handle(MouseEvent e) {
|
||||||
|
// http://stackoverflow.com/questions/17258250/changing-the-laf-of-a-popupmenu-for-a-trayicon-in-java
|
||||||
|
// menu visible check is failsafe, for when menu gets cancelled
|
||||||
|
if (!frame.isVisible() || !menu.isVisible()) {
|
||||||
|
frame.setLocation(e.getX(), e.getY());
|
||||||
|
frame.setVisible(true);
|
||||||
|
menu.show(frame, 0, 0);
|
||||||
|
}
|
||||||
|
updateMenu();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
menu.addPopupMenuListener(new PopupMenuListener() {
|
||||||
|
public void popupMenuCanceled(PopupMenuEvent e) { frame.setVisible(false); }
|
||||||
|
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
|
||||||
|
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
|
||||||
|
});
|
||||||
|
// this is to make it go away when we click elsewhere
|
||||||
|
// doesn't do anything
|
||||||
|
menu.addFocusListener(new FocusListener() {
|
||||||
|
public void focusGained(FocusEvent e) {}
|
||||||
|
public void focusLost(FocusEvent e) { frame.setVisible(false); }
|
||||||
|
});
|
||||||
|
// this is to make it go away when we hit escape
|
||||||
|
// doesn't do anything
|
||||||
|
menu.addMenuKeyListener(new MenuKeyListener() {
|
||||||
|
public void menuKeyPressed(MenuKeyEvent e) {}
|
||||||
|
public void menuKeyReleased(MenuKeyEvent e) {}
|
||||||
|
public void menuKeyTyped(MenuKeyEvent e) {
|
||||||
|
if (e.getKeyChar() == (char) 0x1b)
|
||||||
|
frame.setVisible(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ti;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,8 +150,11 @@ abstract class TrayManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void languageChanged() {
|
public synchronized void languageChanged() {
|
||||||
if (trayIcon != null)
|
if (trayIcon != null) {
|
||||||
trayIcon.setPopupMenu(getMainMenu());
|
if (!_useSwing)
|
||||||
|
trayIcon.setPopupMenu(getMainMenu());
|
||||||
|
// else TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,6 +163,13 @@ abstract class TrayManager {
|
|||||||
*/
|
*/
|
||||||
protected abstract PopupMenu getMainMenu();
|
protected abstract PopupMenu getMainMenu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a popup menu, adding callbacks to the different items.
|
||||||
|
* @return popup menu
|
||||||
|
* @since 0.9.26
|
||||||
|
*/
|
||||||
|
protected abstract JPopupMenu getSwingMainMenu();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the menu
|
* Update the menu
|
||||||
* @since 0.9.26
|
* @since 0.9.26
|
||||||
|
Reference in New Issue
Block a user