2014-11-24 17:40:06 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2014 dorkbox, llc
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2016-10-11 15:23:58 +02:00
|
|
|
package dorkbox.systemTray.swingUI;
|
2014-11-03 02:11:03 +01:00
|
|
|
|
2015-11-09 16:13:57 +01:00
|
|
|
import java.awt.AWTException;
|
|
|
|
import java.awt.Image;
|
|
|
|
import java.awt.SystemTray;
|
|
|
|
import java.awt.TrayIcon;
|
2014-11-03 02:11:03 +01:00
|
|
|
import java.awt.event.MouseAdapter;
|
|
|
|
import java.awt.event.MouseEvent;
|
2016-09-26 02:06:27 +02:00
|
|
|
import java.io.File;
|
2014-11-03 02:11:03 +01:00
|
|
|
|
2016-09-22 15:21:22 +02:00
|
|
|
import javax.swing.ImageIcon;
|
2016-10-03 20:13:00 +02:00
|
|
|
import javax.swing.JPopupMenu;
|
2016-09-22 15:21:22 +02:00
|
|
|
|
2016-10-21 12:36:55 +02:00
|
|
|
import dorkbox.systemTray.MenuItem;
|
|
|
|
import dorkbox.systemTray.Tray;
|
|
|
|
|
2014-11-03 02:11:03 +01:00
|
|
|
/**
|
2016-10-11 15:23:58 +02:00
|
|
|
* Class for handling all system tray interaction, via Swing.
|
2016-09-22 15:21:22 +02:00
|
|
|
*
|
2016-10-11 15:23:58 +02:00
|
|
|
* It doesn't work well AT ALL on linux. See bugs:
|
2016-09-22 15:21:22 +02:00
|
|
|
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6267936
|
|
|
|
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
|
|
|
|
* https://stackoverflow.com/questions/331407/java-trayicon-using-image-with-transparent-background/3882028#3882028
|
2014-11-03 02:11:03 +01:00
|
|
|
*/
|
2016-09-26 02:06:27 +02:00
|
|
|
@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "WeakerAccess"})
|
2016-10-21 12:36:55 +02:00
|
|
|
public final
|
|
|
|
class _SwingTray extends Tray implements SwingUI {
|
2016-10-10 01:15:17 +02:00
|
|
|
private volatile SystemTray tray;
|
|
|
|
private volatile TrayIcon trayIcon;
|
|
|
|
|
|
|
|
// is the system tray visible or not.
|
|
|
|
private volatile boolean visible = true;
|
2014-11-24 17:40:06 +01:00
|
|
|
|
2016-10-09 16:28:32 +02:00
|
|
|
// Called in the EDT
|
2015-06-28 01:47:02 +02:00
|
|
|
public
|
2016-10-09 22:40:28 +02:00
|
|
|
_SwingTray(final dorkbox.systemTray.SystemTray systemTray) {
|
2016-10-21 12:36:55 +02:00
|
|
|
super();
|
2016-09-26 02:06:27 +02:00
|
|
|
|
2016-10-11 15:23:58 +02:00
|
|
|
if (!SystemTray.isSupported()) {
|
|
|
|
throw new RuntimeException("System Tray is not supported in this configuration! Please write an issue and include your OS " +
|
|
|
|
"type and configuration");
|
2016-10-10 11:07:01 +02:00
|
|
|
}
|
|
|
|
|
2016-10-09 22:40:28 +02:00
|
|
|
_SwingTray.this.tray = SystemTray.getSystemTray();
|
2014-11-03 02:11:03 +01:00
|
|
|
|
2016-10-21 12:36:55 +02:00
|
|
|
// we override various methods, because each tray implementation is SLIGHTLY different. This allows us customization.
|
|
|
|
final SwingMenu swingMenu = new SwingMenu(null) {
|
2015-11-09 16:13:57 +01:00
|
|
|
@Override
|
|
|
|
public
|
2016-10-21 12:36:55 +02:00
|
|
|
void setEnabled(final MenuItem menuItem) {
|
|
|
|
dispatch(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public
|
|
|
|
void run() {
|
|
|
|
boolean enabled = menuItem.getEnabled();
|
|
|
|
|
|
|
|
if (visible && !enabled) {
|
|
|
|
tray.remove(trayIcon);
|
|
|
|
visible = false;
|
|
|
|
}
|
|
|
|
else if (!visible && enabled) {
|
|
|
|
try {
|
|
|
|
tray.add(trayIcon);
|
|
|
|
visible = true;
|
|
|
|
} catch (AWTException e) {
|
|
|
|
dorkbox.systemTray.SystemTray.logger.error("Error adding the icon back to the tray", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2015-11-09 16:13:57 +01:00
|
|
|
}
|
2014-11-03 02:11:03 +01:00
|
|
|
|
2014-11-24 17:40:06 +01:00
|
|
|
@Override
|
2015-06-28 01:47:02 +02:00
|
|
|
public
|
2016-10-21 12:36:55 +02:00
|
|
|
void setImage(final MenuItem menuItem) {
|
|
|
|
final File image = menuItem.getImage();
|
|
|
|
if (image == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public
|
|
|
|
void run() {
|
|
|
|
// stupid java won't scale it right away, so we have to do this twice to get the correct size
|
|
|
|
final Image trayImage = new ImageIcon(image.getAbsolutePath()).getImage();
|
|
|
|
trayImage.flush();
|
|
|
|
|
|
|
|
if (trayIcon == null) {
|
|
|
|
// here we init. everything
|
|
|
|
trayIcon = new TrayIcon(trayImage);
|
|
|
|
|
|
|
|
JPopupMenu popupMenu = (JPopupMenu) _native;
|
|
|
|
popupMenu.pack();
|
|
|
|
popupMenu.setFocusable(true);
|
|
|
|
|
|
|
|
// appindicators DO NOT support anything other than PLAIN gtk-menus (which we hack to support swing menus)
|
|
|
|
// they ALSO do not support tooltips, so we cater to the lowest common denominator
|
|
|
|
// trayIcon.setToolTip("app name");
|
|
|
|
|
|
|
|
trayIcon.addMouseListener(new MouseAdapter() {
|
|
|
|
@Override
|
|
|
|
public
|
|
|
|
void mousePressed(MouseEvent e) {
|
|
|
|
TrayPopup popupMenu = (TrayPopup) _native;
|
|
|
|
popupMenu.doShow(e.getPoint(), 0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
tray.add(trayIcon);
|
|
|
|
} catch (AWTException e) {
|
|
|
|
dorkbox.systemTray.SystemTray.logger.error("TrayIcon could not be added.", e);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
trayIcon.setImage(trayImage);
|
2016-02-12 02:30:33 +01:00
|
|
|
}
|
2016-09-28 17:20:13 +02:00
|
|
|
|
2016-10-21 12:36:55 +02:00
|
|
|
((TrayPopup) _native).setTitleBarImage(image);
|
2016-02-12 02:30:33 +01:00
|
|
|
}
|
2016-10-21 12:36:55 +02:00
|
|
|
});
|
|
|
|
}
|
2016-10-09 20:20:23 +02:00
|
|
|
|
2016-10-21 12:36:55 +02:00
|
|
|
@Override
|
|
|
|
public
|
|
|
|
void setText(final MenuItem menuItem) {
|
|
|
|
// no op
|
2014-11-24 17:40:06 +01:00
|
|
|
}
|
2016-10-10 01:15:17 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public
|
2016-10-21 12:36:55 +02:00
|
|
|
void setShortcut(final MenuItem menuItem) {
|
|
|
|
// no op
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public
|
|
|
|
void remove() {
|
|
|
|
dispatch(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public
|
|
|
|
void run() {
|
|
|
|
if (trayIcon != null) {
|
|
|
|
tray.remove(trayIcon);
|
|
|
|
trayIcon = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
tray = null;
|
2016-10-10 01:15:17 +02:00
|
|
|
}
|
2016-10-21 12:36:55 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
super.remove();
|
2016-10-10 01:15:17 +02:00
|
|
|
}
|
2016-10-21 12:36:55 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
bind(swingMenu, null, systemTray);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public
|
|
|
|
boolean hasImage() {
|
|
|
|
return tray.getTrayIcons().length > 0;
|
2016-10-10 01:15:17 +02:00
|
|
|
}
|
2014-11-03 02:11:03 +01:00
|
|
|
}
|