Added SWT compatible tray type (it is just a wrapper for SWT SystemTray)

This commit is contained in:
nathan 2016-02-14 21:54:21 +01:00
parent bb0eb87e90
commit 444562f3c6
4 changed files with 420 additions and 15 deletions

View File

@ -21,6 +21,7 @@ import dorkbox.systemTray.linux.GtkSystemTray;
import dorkbox.systemTray.linux.jna.AppIndicator;
import dorkbox.systemTray.linux.jna.GtkSupport;
import dorkbox.systemTray.swing.SwingSystemTray;
import dorkbox.systemTray.swt.SwtSystemTray;
import dorkbox.util.OS;
import dorkbox.util.Property;
import dorkbox.util.process.ShellProcessBuilder;
@ -76,7 +77,10 @@ class SystemTray {
// maybe we should load the SWT version? (SWT's use of GTK is incompatible with how we use GTK)
if (isSwtLoaded) {
try {
trayType = SwtSystemTray.class;
} catch (Throwable ignored) {
}
}
else {
// Note: AppIndicators DO NOT support tooltips. We could try to create one, by creating a GTK widget and attaching it on

View File

@ -0,0 +1,167 @@
/*
* Copyright 2016 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.
*/
package dorkbox.systemTray.swt;
import dorkbox.systemTray.ImageUtil;
import dorkbox.systemTray.MenuEntry;
import dorkbox.systemTray.SystemTray;
import dorkbox.systemTray.SystemTrayMenuAction;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import java.io.InputStream;
import java.net.URL;
class SwtMenuEntry implements MenuEntry {
private final Menu parent;
private final SystemTray systemTray;
private final MenuItem menuItem;
private final Listener selectionListener;
private volatile String text;
String imagePath;
private Image image;
volatile SystemTrayMenuAction callback;
public
SwtMenuEntry(final Menu parentMenu,
final String label,
final String imagePath,
final Image image,
final SystemTrayMenuAction callback,
final SystemTray systemTray) {
this.parent = parentMenu;
this.text = label;
this.imagePath = imagePath;
this.image = image;
this.callback = callback;
this.systemTray = systemTray;
menuItem = new MenuItem(parentMenu, SWT.PUSH);
menuItem.setText(label);
selectionListener = new Listener() {
public
void handleEvent(Event event) {
handle();
}
};
menuItem.addListener(SWT.Selection, selectionListener);
if (image != null && !image.isDisposed()) {
menuItem.setImage(image);
}
}
private
void handle() {
SystemTrayMenuAction cb = this.callback;
if (cb != null) {
cb.onClick(systemTray, this);
}
}
@Override
public
String getText() {
return text;
}
@Override
public
void setText(final String newText) {
this.text = newText;
menuItem.setText(newText);
}
private
void setImage_(final String imagePath) {
if (imagePath == null) {
menuItem.setImage(null);
image = null;
}
else {
image = new Image(parent.getShell().getDisplay(), imagePath);
menuItem.setImage(image);
}
}
@Override
public
void setImage(final String imagePath) {
if (imagePath == null) {
setImage_(null);
}
else {
setImage_(ImageUtil.iconPath(imagePath));
}
}
@Override
public
void setImage(final URL imageUrl) {
if (imageUrl == null) {
setImage_(null);
}
else {
setImage_(ImageUtil.iconPath(imageUrl));
}
}
@Override
public
void setImage(final String cacheName, final InputStream imageStream) {
if (imageStream == null) {
setImage_(null);
}
else {
setImage_(ImageUtil.iconPath(cacheName, imageStream));
}
}
@Override
@Deprecated
public
void setImage(final InputStream imageStream) {
if (imageStream == null) {
setImage_(null);
}
else {
setImage_(ImageUtil.iconPathNoCache(imageStream));
}
}
@Override
public
void setCallback(final SystemTrayMenuAction callback) {
this.callback = callback;
}
@Override
public
void remove() {
if (image != null) {
image.dispose();
}
menuItem.dispose();
}
}

View File

@ -0,0 +1,234 @@
/*
* Copyright 2016 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.
*/
package dorkbox.systemTray.swt;
import dorkbox.systemTray.ImageUtil;
import dorkbox.systemTray.MenuEntry;
import dorkbox.systemTray.SystemTrayMenuAction;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TrayItem;
import java.io.InputStream;
import java.net.URL;
/**
* Class for handling all system tray interaction, via SWING
*/
public
class SwtSystemTray extends dorkbox.systemTray.SystemTray {
// volatile SwingSystemTrayMenuPopup menu;
volatile MenuItem connectionStatusItem;
//
// volatile SystemTray tray;
// volatile TrayIcon trayIcon;
private final Display display;
private final Shell shell;
private final TrayItem tray;
volatile boolean isActive = false;
private final Menu menu;
/**
* Creates a new system tray handler class.
*/
public
SwtSystemTray() {
super();
display = Display.getCurrent();
shell = display.getShells()[0];
tray = new TrayItem(display.getSystemTray(), SWT.NONE);
menu = new Menu(shell, SWT.POP_UP);
tray.addListener(SWT.MenuDetect, new Listener() {
public void handleEvent(Event event) {
menu.setVisible(true);
}
});
tray.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
menu.setVisible(true);
}
});
}
@Override
public
void shutdown() {
synchronized (this) {
for (MenuEntry menuEntry : menuEntries) {
menuEntry.remove();
}
menuEntries.clear();
connectionStatusItem = null;
tray.dispose();
}
}
@Override
public
void setStatus(final String infoString) {
synchronized (this) {
if (connectionStatusItem == null && infoString != null && !infoString.isEmpty()) {
deleteMenu();
connectionStatusItem = new MenuItem(menu, SWT.PUSH);
connectionStatusItem.setText(infoString);
connectionStatusItem.setEnabled(false);
createMenu();
}
else {
if (infoString == null || infoString.isEmpty()) {
// deletes the status entry only
connectionStatusItem.dispose();
connectionStatusItem = null;
}
else {
connectionStatusItem.setText(infoString);
}
}
}
}
/**
* Deletes the contents of the menu, and unreferences everything in it.
*/
private void deleteMenu() {
// have to remove status from menu
if (connectionStatusItem != null) {
connectionStatusItem.dispose();
}
synchronized (menuEntries) {
// have to remove all other menu entries
for (int i = 0; i < menuEntries.size(); i++) {
SwtMenuEntry menuEntry__ = (SwtMenuEntry) menuEntries.get(i);
menuEntry__.remove();
}
}
}
/**
* recreates the menu items
*/
private void createMenu() {
synchronized (menuEntries) {
// now add back other menu entries
final SwtMenuEntry[] swtMenuEntries = menuEntries.toArray(new SwtMenuEntry[0]);
menuEntries.clear();
for (int i = 0; i < swtMenuEntries.length; i++) {
SwtMenuEntry menuEntry__ = swtMenuEntries[i];
addMenuEntry_(menuEntry__.getText(), menuEntry__.imagePath, menuEntry__.callback);
}
}
}
@Override
protected
void setIcon_(final String iconPath) {
tray.setImage(new Image(display, iconPath));
}
/**
* Will add a new menu entry, or update one if it already exists
*/
private
void addMenuEntry_(final String menuText, final String imagePath, final SystemTrayMenuAction callback) {
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
synchronized (this) {
synchronized (menuEntries) {
MenuEntry menuEntry = getMenuEntry(menuText);
if (menuEntry != null) {
throw new IllegalArgumentException("Menu entry already exists for given label '" + menuText + "'");
}
else {
final Image image;
if (imagePath != null) {
image = new Image(display, imagePath);
} else {
image = null;
}
menuEntry = new SwtMenuEntry(menu, menuText, imagePath, image, callback, this);
menuEntries.add(menuEntry);
}
}
}
}
@Override
public
void addMenuEntry(String menuText, final String imagePath, final SystemTrayMenuAction callback) {
if (imagePath == null) {
addMenuEntry_(menuText, null, callback);
}
else {
addMenuEntry_(menuText, ImageUtil.iconPath(imagePath), callback);
}
}
@Override
public
void addMenuEntry(final String menuText, final URL imageUrl, final SystemTrayMenuAction callback) {
if (imageUrl == null) {
addMenuEntry_(menuText, null, callback);
}
else {
addMenuEntry_(menuText, ImageUtil.iconPath(imageUrl), callback);
}
}
@Override
public
void addMenuEntry(final String menuText, final String cacheName, final InputStream imageStream, final SystemTrayMenuAction callback) {
if (imageStream == null) {
addMenuEntry_(menuText, null, callback);
}
else {
addMenuEntry_(menuText, ImageUtil.iconPath(cacheName, imageStream), callback);
}
}
@Override
@Deprecated
public
void addMenuEntry(final String menuText, final InputStream imageStream, final SystemTrayMenuAction callback) {
if (imageStream == null) {
addMenuEntry_(menuText, null, callback);
}
else {
addMenuEntry_(menuText, ImageUtil.iconPathNoCache(imageStream), callback);
}
}
}

View File

@ -24,7 +24,6 @@ import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import java.io.File;
import java.net.URL;
/**
@ -42,12 +41,6 @@ class TestTraySwt {
public static
void main(String[] args) {
// ONLY if manually loading JNA jars.
//
// Not necessary if using the official JNA downloaded from https://github.com/twall/jna AND THAT JAR is on the classpath
//
System.load(new File("../../resources/Dependencies/jna/linux_64/libjna.so").getAbsolutePath()); //64bit linux library
new TestTraySwt();
}
@ -58,14 +51,12 @@ class TestTraySwt {
public
TestTraySwt() {
Display display = new Display ();
Shell shell = new Shell(display);
final Shell shell = new Shell(display);
Text helloWorldTest = new Text(shell, SWT.NONE);
helloWorldTest.setText("Hello World SWT");
helloWorldTest.setText("Hello World SWT ................. ");
helloWorldTest.pack();
shell.pack();
shell.open ();
this.systemTray = SystemTray.getSystemTray();
if (systemTray == null) {
@ -111,13 +102,22 @@ class TestTraySwt {
public
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
systemTray.shutdown();
shell.close(); // close down SWT shell
//System.exit(0); not necessary if all non-daemon threads have stopped.
}
});
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose ();
display.dispose();
}
}