Fixed issue with keyboard navigation/mnemonics on popup window.
This commit is contained in:
parent
f2065a59fa
commit
f0fe9fa9a2
@ -147,6 +147,10 @@ class SwingSystemTray extends SwingMenu {
|
|||||||
// here we init. everything
|
// here we init. everything
|
||||||
trayIcon = new TrayIcon(trayImage);
|
trayIcon = new TrayIcon(trayImage);
|
||||||
|
|
||||||
|
JPopupMenu popupMenu = (JPopupMenu) _native;
|
||||||
|
popupMenu.pack();
|
||||||
|
popupMenu.setFocusable(true);
|
||||||
|
|
||||||
// appindicators DO NOT support anything other than PLAIN gtk-menus
|
// appindicators DO NOT support anything other than PLAIN gtk-menus
|
||||||
// they ALSO do not support tooltips, so we cater to the lowest common denominator
|
// they ALSO do not support tooltips, so we cater to the lowest common denominator
|
||||||
// trayIcon.setToolTip(SwingSystemTray.this.appName);
|
// trayIcon.setToolTip(SwingSystemTray.this.appName);
|
||||||
@ -181,22 +185,19 @@ class SwingSystemTray extends SwingMenu {
|
|||||||
x -= size.width; // snap to edge of mouse
|
x -= size.width; // snap to edge of mouse
|
||||||
}
|
}
|
||||||
|
|
||||||
// voodoo to get this to popup to have the correct parent
|
SwingSystemTrayMenuWindowsPopup popupMenu = (SwingSystemTrayMenuWindowsPopup) _native;
|
||||||
// from: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6285881
|
popupMenu.doShow(x, y);
|
||||||
((JPopupMenu) _native).setInvoker(_native);
|
|
||||||
_native.setLocation(x, y);
|
|
||||||
_native.setVisible(true);
|
|
||||||
_native.setFocusable(true);
|
|
||||||
_native.requestFocusInWindow();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
tray.add(trayIcon);
|
tray.add(trayIcon);
|
||||||
|
((SwingSystemTrayMenuWindowsPopup) _native).setIcon(iconFile);
|
||||||
} catch (AWTException e) {
|
} catch (AWTException e) {
|
||||||
dorkbox.systemTray.SystemTray.logger.error("TrayIcon could not be added.", e);
|
dorkbox.systemTray.SystemTray.logger.error("TrayIcon could not be added.", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
((SwingSystemTrayMenuWindowsPopup) _native).setIcon(iconFile);
|
||||||
trayIcon.setImage(trayImage);
|
trayIcon.setImage(trayImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,24 +16,36 @@
|
|||||||
package dorkbox.systemTray.swing;
|
package dorkbox.systemTray.swing;
|
||||||
|
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
|
import java.awt.Image;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.awt.event.WindowFocusListener;
|
import java.awt.event.WindowFocusListener;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.event.PopupMenuEvent;
|
||||||
|
import javax.swing.event.PopupMenuListener;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
import dorkbox.util.OS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This custom popup is required, because we cannot close this popup by clicking OUTSIDE the popup. For whatever reason, that does not
|
* This custom popup is required, because we cannot close this popup by clicking OUTSIDE the popup. For whatever reason, that does not
|
||||||
* work, so we must implement an "auto-hide" feature that checks if our mouse is still inside a menu every POPUP_HIDE_DELAY seconds
|
* work, so we must implement an "auto-hide" feature that checks if our mouse is still inside a menu every POPUP_HIDE_DELAY seconds
|
||||||
*/
|
*/
|
||||||
public
|
|
||||||
class SwingSystemTrayMenuWindowsPopup extends JPopupMenu {
|
class SwingSystemTrayMenuWindowsPopup extends JPopupMenu {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
// NOTE: we can use the "hidden dialog" focus window trick... only on windows and mac
|
// NOTE: we can use the "hidden dialog" focus window trick... only on windows and mac
|
||||||
private JDialog hiddenDialog;
|
private JDialog hiddenDialog;
|
||||||
|
private volatile File iconFile;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
SwingSystemTrayMenuWindowsPopup() {
|
SwingSystemTrayMenuWindowsPopup() {
|
||||||
super();
|
super();
|
||||||
setFocusable(true);
|
setFocusable(true);
|
||||||
@ -41,14 +53,51 @@ class SwingSystemTrayMenuWindowsPopup extends JPopupMenu {
|
|||||||
setBorder(new EmptyBorder(1, 1, 1, 1));
|
setBorder(new EmptyBorder(1, 1, 1, 1));
|
||||||
|
|
||||||
|
|
||||||
// Does not work correctly on linux. a window in the taskbar still shows up
|
// Initialize the hidden dialog as a headless, title-less dialog window
|
||||||
// Initialize the hidden dialog as a headless, titleless dialog window
|
this.hiddenDialog = new JDialog((Frame)null, "Tray menu");
|
||||||
this.hiddenDialog = new JDialog((Frame)null);
|
|
||||||
this.hiddenDialog.setEnabled(false);
|
|
||||||
this.hiddenDialog.setUndecorated(true);
|
this.hiddenDialog.setUndecorated(true);
|
||||||
this.hiddenDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
this.hiddenDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||||
|
this.hiddenDialog.setAlwaysOnTop(true);
|
||||||
|
|
||||||
this.hiddenDialog.setSize(1, 1);
|
// on Linux, the following two entries will **MOST OF THE TIME** prevent the hidden dialog from showing in the task-bar
|
||||||
|
// on MacOS, you need "special permission" to not have a hidden dialog show on the dock.
|
||||||
|
this.hiddenDialog.getContentPane().setLayout(null);
|
||||||
|
|
||||||
|
// this is a java 1.7 deal, so we have to use reflection to set this. It's not critical for this to be set, but it helps
|
||||||
|
// this.hiddenDialog.setType(Window.Type.POPUP);
|
||||||
|
if (OS.javaVersion >= 7) {
|
||||||
|
try {
|
||||||
|
Class<? extends JDialog> hiddenDialogClass = this.hiddenDialog.getClass();
|
||||||
|
Method[] methods = hiddenDialogClass.getMethods();
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.getName()
|
||||||
|
.equals("setType")) {
|
||||||
|
|
||||||
|
Class<Enum> cl = (Class<Enum>) Class.forName("java.awt.Window$Type");
|
||||||
|
method.invoke(this.hiddenDialog, Enum.valueOf(cl, "POPUP"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
SystemTray.logger.error("Error setting the tray popup menu type. The parent window might show on the task bar.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hiddenDialog.pack();
|
||||||
|
this.hiddenDialog.setBounds(0,0,0,0);
|
||||||
|
|
||||||
|
addPopupMenuListener(new PopupMenuListener() {
|
||||||
|
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
|
||||||
|
hiddenDialog.setVisible(false);
|
||||||
|
hiddenDialog.toBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Add the window focus listener to the hidden dialog
|
// Add the window focus listener to the hidden dialog
|
||||||
this.hiddenDialog.addWindowFocusListener(new WindowFocusListener() {
|
this.hiddenDialog.addWindowFocusListener(new WindowFocusListener() {
|
||||||
@ -57,20 +106,42 @@ class SwingSystemTrayMenuWindowsPopup extends JPopupMenu {
|
|||||||
SwingSystemTrayMenuWindowsPopup.this.setVisible(false);
|
SwingSystemTrayMenuWindowsPopup.this.setVisible(false);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void windowGainedFocus (WindowEvent we) {}
|
public void windowGainedFocus (WindowEvent we) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public
|
* Sets the icon for the title-bar, so IF it shows in the task-bar, it will have the corresponding icon as the SystemTray icon
|
||||||
void setVisible(boolean makeVisible) {
|
*/
|
||||||
this.hiddenDialog.setVisible(makeVisible);
|
void setIcon(final File iconFile) {
|
||||||
this.hiddenDialog.setEnabled(false);
|
if (this.iconFile == null || !this.iconFile.equals(iconFile)) {
|
||||||
|
this.iconFile = iconFile;
|
||||||
|
|
||||||
super.setVisible(makeVisible);
|
try {
|
||||||
|
Image image = new ImageIcon(ImageIO.read(iconFile)).getImage();
|
||||||
|
image.flush();
|
||||||
|
|
||||||
|
// we set the dialog window to have the same icon as what is on the system tray
|
||||||
|
this.hiddenDialog.setIconImage(image);
|
||||||
|
} catch (IOException e) {
|
||||||
|
SystemTray.logger.error("Error setting the icon for the popup menu task tray dialog");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void doShow(final int x, final int y) {
|
||||||
|
// critical to get the keyboard listeners working for the popup menu
|
||||||
|
setInvoker(this.hiddenDialog.getContentPane());
|
||||||
|
|
||||||
|
this.hiddenDialog.setLocation(x, y);
|
||||||
|
this.hiddenDialog.setVisible(true);
|
||||||
|
|
||||||
|
setLocation(x, y);
|
||||||
|
setVisible(true);
|
||||||
|
requestFocusInWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
|
||||||
void close() {
|
void close() {
|
||||||
this.hiddenDialog.setVisible(false);
|
this.hiddenDialog.setVisible(false);
|
||||||
this.hiddenDialog.dispatchEvent(new WindowEvent(this.hiddenDialog, WindowEvent.WINDOW_CLOSING));
|
this.hiddenDialog.dispatchEvent(new WindowEvent(this.hiddenDialog, WindowEvent.WINDOW_CLOSING));
|
||||||
|
Loading…
Reference in New Issue
Block a user