Cleaned up memory leaks. Added SystemTray.getStatus(). Cleaned up support for SWT.
This commit is contained in:
parent
e129fd4e75
commit
a68c79182d
|
@ -31,6 +31,11 @@ class ImageUtil {
|
||||||
private static final Map<String, String> resourceToFilePath = new HashMap<String, String>();
|
private static final Map<String, String> resourceToFilePath = new HashMap<String, String>();
|
||||||
private static final long runtimeRandom = new SecureRandom().nextLong();
|
private static final long runtimeRandom = new SecureRandom().nextLong();
|
||||||
|
|
||||||
|
public static synchronized
|
||||||
|
void init() throws NoSuchAlgorithmException {
|
||||||
|
ImageUtil.digest = MessageDigest.getInstance("MD5");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* appIndicator/gtk require strings (which is the path)
|
* appIndicator/gtk require strings (which is the path)
|
||||||
* swing version loads as an image (which can be stream or path, we use path)
|
* swing version loads as an image (which can be stream or path, we use path)
|
||||||
|
@ -198,6 +203,7 @@ class ImageUtil {
|
||||||
return newFile.getAbsolutePath();
|
return newFile.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// must be called from synchronized block
|
||||||
private static
|
private static
|
||||||
String hashName(byte[] nameChars) {
|
String hashName(byte[] nameChars) {
|
||||||
digest.reset();
|
digest.reset();
|
||||||
|
@ -214,9 +220,4 @@ class ImageUtil {
|
||||||
// convert to alpha-numeric. see https://stackoverflow.com/questions/29183818/why-use-tostring32-and-not-tostring36
|
// convert to alpha-numeric. see https://stackoverflow.com/questions/29183818/why-use-tostring32-and-not-tostring36
|
||||||
return new BigInteger(1, digest.digest()).toString(32).toUpperCase(Locale.US);
|
return new BigInteger(1, digest.digest()).toString(32).toUpperCase(Locale.US);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized
|
|
||||||
void init() throws NoSuchAlgorithmException {
|
|
||||||
ImageUtil.digest = MessageDigest.getInstance("MD5");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,10 +95,10 @@ class SystemTray {
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe we should load the SWT version? (In order for us to work with SWT, BOTH must be GTK2!!
|
// maybe we should load the SWT version? (In order for us to work with SWT, BOTH must be GTK2!!
|
||||||
COMPATIBILITY_MODE = isJavaFxLoaded || isSwtLoaded;
|
COMPATIBILITY_MODE = OS.isLinux() && (isJavaFxLoaded || isSwtLoaded);
|
||||||
|
|
||||||
// kablooie if SWT is not configured in a way that works with us.
|
// kablooie if SWT is not configured in a way that works with us.
|
||||||
if (isSwtLoaded) {
|
if (OS.isLinux() && isSwtLoaded) {
|
||||||
// Necessary for us to work with SWT
|
// Necessary for us to work with SWT
|
||||||
// System.setProperty("SWT_GTK3", "0"); // Necessary for us to work with SWT
|
// System.setProperty("SWT_GTK3", "0"); // Necessary for us to work with SWT
|
||||||
|
|
||||||
|
@ -442,14 +442,19 @@ class SystemTray {
|
||||||
public abstract
|
public abstract
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the 'status' string assigned to the system tray
|
||||||
|
*/
|
||||||
|
public abstract
|
||||||
|
String getStatus();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a 'status' string at the first position in the popup menu. This 'status' string appears as a disabled menu entry.
|
* Sets a 'status' string at the first position in the popup menu. This 'status' string appears as a disabled menu entry.
|
||||||
*
|
*
|
||||||
* @param infoString the text you want displayed, null if you want to remove the 'status' string
|
* @param statusText the text you want displayed, null if you want to remove the 'status' string
|
||||||
*/
|
*/
|
||||||
public abstract
|
public abstract
|
||||||
void setStatus(String infoString);
|
void setStatus(String statusText);
|
||||||
|
|
||||||
protected abstract
|
protected abstract
|
||||||
void setIcon_(String iconPath);
|
void setIcon_(String iconPath);
|
||||||
|
|
|
@ -19,6 +19,8 @@ import com.sun.jna.Pointer;
|
||||||
import dorkbox.systemTray.linux.jna.AppIndicator;
|
import dorkbox.systemTray.linux.jna.AppIndicator;
|
||||||
import dorkbox.systemTray.linux.jna.GtkSupport;
|
import dorkbox.systemTray.linux.jna.GtkSupport;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for handling all system tray interactions.
|
* Class for handling all system tray interactions.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
@ -34,6 +36,9 @@ class AppIndicatorTray extends GtkTypeSystemTray {
|
||||||
private AppIndicator.AppIndicatorInstanceStruct appIndicator;
|
private AppIndicator.AppIndicatorInstanceStruct appIndicator;
|
||||||
private boolean isActive = false;
|
private boolean isActive = false;
|
||||||
|
|
||||||
|
// This is required if we have JavaFX or SWT shutdown hooks (to prevent us from shutting down twice...)
|
||||||
|
private AtomicBoolean shuttingDown = new AtomicBoolean();
|
||||||
|
|
||||||
public
|
public
|
||||||
AppIndicatorTray() {
|
AppIndicatorTray() {
|
||||||
GtkSupport.startGui();
|
GtkSupport.startGui();
|
||||||
|
@ -51,21 +56,22 @@ class AppIndicatorTray extends GtkTypeSystemTray {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void shutdown() {
|
void shutdown() {
|
||||||
GtkSupport.dispatch(new Runnable() {
|
if (!shuttingDown.getAndSet(true)) {
|
||||||
@Override
|
GtkSupport.dispatch(new Runnable() {
|
||||||
public
|
@Override
|
||||||
void run() {
|
public
|
||||||
// this hides the indicator
|
void run() {
|
||||||
appindicator.app_indicator_set_status(appIndicator, AppIndicator.STATUS_PASSIVE);
|
// STATUS_PASSIVE hides the indicator
|
||||||
Pointer p = appIndicator.getPointer();
|
appindicator.app_indicator_set_status(appIndicator, AppIndicator.STATUS_PASSIVE);
|
||||||
gobject.g_object_unref(p);
|
Pointer p = appIndicator.getPointer();
|
||||||
|
gobject.g_object_unref(p);
|
||||||
|
|
||||||
// GC it
|
appIndicator = null;
|
||||||
appIndicator = null;
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
super.shutdown();
|
super.shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -91,12 +97,7 @@ class AppIndicatorTray extends GtkTypeSystemTray {
|
||||||
*/
|
*/
|
||||||
protected
|
protected
|
||||||
void onMenuAdded(final Pointer menu) {
|
void onMenuAdded(final Pointer menu) {
|
||||||
GtkSupport.dispatch(new Runnable() {
|
// see: https://code.launchpad.net/~mterry/libappindicator/fix-menu-leak/+merge/53247
|
||||||
@Override
|
appindicator.app_indicator_set_menu(appIndicator, menu);
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
appindicator.app_indicator_set_menu(appIndicator, menu);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,19 @@ import dorkbox.systemTray.linux.jna.GtkSupport;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
class GtkMenuEntry implements MenuEntry, GCallback {
|
||||||
|
private static final AtomicInteger ID_COUNTER = new AtomicInteger();
|
||||||
|
private final int id = ID_COUNTER.getAndIncrement();
|
||||||
|
|
||||||
class GtkMenuEntry implements MenuEntry {
|
|
||||||
private static final Gtk gtk = Gtk.INSTANCE;
|
private static final Gtk gtk = Gtk.INSTANCE;
|
||||||
private static final Gobject gobject = Gobject.INSTANCE;
|
private static final Gobject gobject = Gobject.INSTANCE;
|
||||||
|
|
||||||
@SuppressWarnings("FieldCanBeLocal")
|
|
||||||
private final GCallback gtkCallback;
|
|
||||||
|
|
||||||
final Pointer menuItem;
|
final Pointer menuItem;
|
||||||
private final Pointer parentMenu;
|
final GtkTypeSystemTray parent;
|
||||||
final GtkTypeSystemTray systemTray;
|
|
||||||
|
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||||
private final NativeLong nativeLong;
|
private final NativeLong nativeLong;
|
||||||
|
|
||||||
// these have to be volatile, because they can be changed from any thread
|
// these have to be volatile, because they can be changed from any thread
|
||||||
|
@ -45,23 +47,14 @@ class GtkMenuEntry implements MenuEntry {
|
||||||
private volatile SystemTrayMenuAction callback;
|
private volatile SystemTrayMenuAction callback;
|
||||||
private volatile Pointer image;
|
private volatile Pointer image;
|
||||||
|
|
||||||
// called from inside dispatch thread
|
/**
|
||||||
GtkMenuEntry(final Pointer parentMenu, final String label, final String imagePath, final SystemTrayMenuAction callback,
|
* called from inside dispatch thread. ONLY creates the menu item, but DOES NOT attach it!
|
||||||
final GtkTypeSystemTray systemTray) {
|
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
|
||||||
this.parentMenu = parentMenu;
|
*/
|
||||||
|
GtkMenuEntry(final String label, final String imagePath, final SystemTrayMenuAction callback, final GtkTypeSystemTray parent) {
|
||||||
|
this.parent = parent;
|
||||||
this.text = label;
|
this.text = label;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.systemTray = systemTray;
|
|
||||||
|
|
||||||
// have to watch out! This can get garbage collected (so it MUST be a field)!
|
|
||||||
gtkCallback = new Gobject.GCallback() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int callback(Pointer instance, Pointer data) {
|
|
||||||
handle();
|
|
||||||
return Gtk.TRUE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
menuItem = gtk.gtk_image_menu_item_new_with_label(label);
|
menuItem = gtk.gtk_image_menu_item_new_with_label(label);
|
||||||
|
|
||||||
|
@ -76,21 +69,26 @@ class GtkMenuEntry implements MenuEntry {
|
||||||
gtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
gtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeLong = gobject.g_signal_connect_data(menuItem, "activate", gtkCallback, null, null, 0);
|
nativeLong = gobject.g_signal_connect_object(menuItem, "activate", this, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
|
||||||
void handle() {
|
// called by native code
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
int callback(final Pointer instance, final Pointer data) {
|
||||||
final SystemTrayMenuAction cb = this.callback;
|
final SystemTrayMenuAction cb = this.callback;
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
GtkTypeSystemTray.callbackExecutor.execute(new Runnable() {
|
GtkTypeSystemTray.callbackExecutor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
cb.onClick(systemTray, GtkMenuEntry.this);
|
cb.onClick(parent, GtkMenuEntry.this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Gtk.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,7 +107,7 @@ class GtkMenuEntry implements MenuEntry {
|
||||||
text = newText;
|
text = newText;
|
||||||
gtk.gtk_menu_item_set_label(menuItem, newText);
|
gtk.gtk_menu_item_set_label(menuItem, newText);
|
||||||
|
|
||||||
gtk.gtk_widget_show_all(parentMenu);
|
gtk.gtk_widget_show_all(menuItem);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -120,21 +118,23 @@ class GtkMenuEntry implements MenuEntry {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
|
if (image != null) {
|
||||||
|
gtk.gtk_widget_destroy(image);
|
||||||
|
image = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk.gtk_widget_show_all(menuItem);
|
||||||
|
|
||||||
if (imagePath != null && !imagePath.isEmpty()) {
|
if (imagePath != null && !imagePath.isEmpty()) {
|
||||||
if (image != null) {
|
|
||||||
gtk.gtk_widget_destroy(image);
|
|
||||||
}
|
|
||||||
gtk.gtk_widget_show_all(parentMenu);
|
|
||||||
|
|
||||||
image = gtk.gtk_image_new_from_file(imagePath);
|
image = gtk.gtk_image_new_from_file(imagePath);
|
||||||
|
|
||||||
gtk.gtk_image_menu_item_set_image(menuItem, image);
|
gtk.gtk_image_menu_item_set_image(menuItem, image);
|
||||||
|
gobject.g_object_ref_sink(image);
|
||||||
|
|
||||||
// must always re-set always-show after setting the image
|
// must always re-set always-show after setting the image
|
||||||
gtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
gtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk.gtk_widget_show_all(parentMenu);
|
gtk.gtk_widget_show_all(menuItem);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -202,26 +202,27 @@ class GtkMenuEntry implements MenuEntry {
|
||||||
removePrivate();
|
removePrivate();
|
||||||
|
|
||||||
// have to rebuild the menu now...
|
// have to rebuild the menu now...
|
||||||
systemTray.deleteMenu();
|
parent.deleteMenu();
|
||||||
systemTray.createMenu();
|
parent.createMenu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void removePrivate() {
|
void removePrivate() {
|
||||||
gobject.g_signal_handler_disconnect(menuItem, nativeLong);
|
callback = null;
|
||||||
gtk.gtk_menu_shell_deactivate(parentMenu, menuItem);
|
gtk.gtk_menu_shell_deactivate(parent.getMenu(), menuItem);
|
||||||
|
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
gtk.gtk_widget_destroy(image);
|
gtk.gtk_widget_destroy(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk.gtk_widget_destroy(menuItem);
|
gtk.gtk_widget_destroy(menuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
int hashCode() {
|
int hashCode() {
|
||||||
return 0;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -237,7 +238,8 @@ class GtkMenuEntry implements MenuEntry {
|
||||||
if (getClass() != obj.getClass()) {
|
if (getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkMenuEntry other = (GtkMenuEntry) obj;
|
GtkMenuEntry other = (GtkMenuEntry) obj;
|
||||||
return this.text.equals(other.text);
|
return this.id == other.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ import dorkbox.systemTray.linux.jna.Gobject;
|
||||||
import dorkbox.systemTray.linux.jna.Gtk;
|
import dorkbox.systemTray.linux.jna.Gtk;
|
||||||
import dorkbox.systemTray.linux.jna.GtkSupport;
|
import dorkbox.systemTray.linux.jna.GtkSupport;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for handling all system tray interactions via GTK.
|
* Class for handling all system tray interactions via GTK.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
@ -36,8 +38,10 @@ class GtkSystemTray extends GtkTypeSystemTray {
|
||||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||||
private NativeLong button_press_event;
|
private NativeLong button_press_event;
|
||||||
|
|
||||||
|
// This is required if we have JavaFX or SWT shutdown hooks (to prevent us from shutting down twice...)
|
||||||
|
private AtomicBoolean shuttingDown = new AtomicBoolean();
|
||||||
|
|
||||||
private volatile boolean isActive = false;
|
private volatile boolean isActive = false;
|
||||||
private volatile Pointer menu;
|
|
||||||
|
|
||||||
public
|
public
|
||||||
GtkSystemTray() {
|
GtkSystemTray() {
|
||||||
|
@ -60,41 +64,36 @@ class GtkSystemTray extends GtkTypeSystemTray {
|
||||||
void callback(Pointer notUsed, final Gtk.GdkEventButton event) {
|
void callback(Pointer notUsed, final Gtk.GdkEventButton event) {
|
||||||
// BUTTON_PRESS only (any mouse click)
|
// BUTTON_PRESS only (any mouse click)
|
||||||
if (event.type == 4) {
|
if (event.type == 4) {
|
||||||
gtk.gtk_menu_popup(menu, null, null, Gtk.gtk_status_icon_position_menu, trayIcon, 0, event.time);
|
gtk.gtk_menu_popup(getMenu(), null, null, Gtk.gtk_status_icon_position_menu, trayIcon, 0, event.time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
button_press_event = gobject.g_signal_connect_data(trayIcon, "button_press_event", gtkCallback, null, null, 0);
|
button_press_event = gobject.g_signal_connect_object(trayIcon, "button_press_event", gtkCallback, null, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called inside the gdk_threads block
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void onMenuAdded(final Pointer menu) {
|
|
||||||
this.menu = menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("FieldRepeatedlyAccessedInMethod")
|
@SuppressWarnings("FieldRepeatedlyAccessedInMethod")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void shutdown() {
|
void shutdown() {
|
||||||
GtkSupport.dispatch(new Runnable() {
|
if (!shuttingDown.getAndSet(true)) {
|
||||||
@Override
|
GtkSupport.dispatch(new Runnable() {
|
||||||
public
|
@Override
|
||||||
void run() {
|
public
|
||||||
// this hides the indicator
|
void run() {
|
||||||
gtk.gtk_status_icon_set_visible(trayIcon, false);
|
// this hides the indicator
|
||||||
gobject.g_object_unref(trayIcon);
|
gtk.gtk_status_icon_set_visible(trayIcon, false);
|
||||||
|
gobject.g_object_unref(trayIcon);
|
||||||
|
|
||||||
// GC it
|
// GC it
|
||||||
trayIcon = null;
|
trayIcon = null;
|
||||||
}
|
gtkCallback = null;
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
super.shutdown();
|
super.shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,15 +20,16 @@ import com.sun.jna.Pointer;
|
||||||
import dorkbox.systemTray.ImageUtil;
|
import dorkbox.systemTray.ImageUtil;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
import dorkbox.systemTray.SystemTrayMenuAction;
|
import dorkbox.systemTray.SystemTrayMenuAction;
|
||||||
import dorkbox.util.NamedThreadFactory;
|
|
||||||
import dorkbox.systemTray.linux.jna.Gobject;
|
import dorkbox.systemTray.linux.jna.Gobject;
|
||||||
import dorkbox.systemTray.linux.jna.Gtk;
|
import dorkbox.systemTray.linux.jna.Gtk;
|
||||||
import dorkbox.systemTray.linux.jna.GtkSupport;
|
import dorkbox.systemTray.linux.jna.GtkSupport;
|
||||||
|
import dorkbox.util.NamedThreadFactory;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derived from
|
* Derived from
|
||||||
|
@ -41,8 +42,11 @@ class GtkTypeSystemTray extends SystemTray {
|
||||||
|
|
||||||
final static ExecutorService callbackExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("SysTrayExecutor", false));
|
final static ExecutorService callbackExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("SysTrayExecutor", false));
|
||||||
|
|
||||||
private Pointer menu;
|
private volatile Pointer menu;
|
||||||
private Pointer connectionStatusItem;
|
|
||||||
|
private volatile Pointer connectionStatusItem;
|
||||||
|
private volatile String statusText = null;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
|
@ -52,54 +56,77 @@ class GtkTypeSystemTray extends SystemTray {
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
obliterateMenu();
|
obliterateMenu();
|
||||||
GtkSupport.shutdownGui();
|
|
||||||
|
|
||||||
callbackExecutor.shutdown();
|
boolean terminated = false;
|
||||||
|
try {
|
||||||
|
terminated = callbackExecutor.awaitTermination(1, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!terminated) {
|
||||||
|
callbackExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkSupport.shutdownGui();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setStatus(final String infoString) {
|
String getStatus() {
|
||||||
|
return statusText;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setStatus(final String statusText) {
|
||||||
|
this.statusText = statusText;
|
||||||
|
|
||||||
GtkSupport.dispatch(new Runnable() {
|
GtkSupport.dispatch(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
if (connectionStatusItem == null && infoString != null && !infoString.isEmpty()) {
|
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||||
|
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||||
|
if (connectionStatusItem == null && statusText != null && !statusText.isEmpty()) {
|
||||||
deleteMenu();
|
deleteMenu();
|
||||||
|
|
||||||
connectionStatusItem = gtk.gtk_menu_item_new_with_label("");
|
connectionStatusItem = gtk.gtk_menu_item_new_with_label("");
|
||||||
gobject.g_object_ref(connectionStatusItem); // so it matches with 'createMenu'
|
|
||||||
|
|
||||||
// evil hacks abound...
|
// evil hacks abound...
|
||||||
Pointer label = gtk.gtk_bin_get_child(connectionStatusItem);
|
Pointer label = gtk.gtk_bin_get_child(connectionStatusItem);
|
||||||
gtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
gtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
||||||
Pointer markup = gobject.g_markup_printf_escaped("<b>%s</b>", infoString);
|
Pointer markup = gobject.g_markup_printf_escaped("<b>%s</b>", statusText);
|
||||||
gtk.gtk_label_set_markup(label, markup);
|
gtk.gtk_label_set_markup(label, markup);
|
||||||
gobject.g_free(markup);
|
gobject.g_free(markup);
|
||||||
|
|
||||||
|
|
||||||
gtk.gtk_widget_set_sensitive(connectionStatusItem, Gtk.FALSE);
|
gtk.gtk_widget_set_sensitive(connectionStatusItem, Gtk.FALSE);
|
||||||
|
|
||||||
createMenu();
|
createMenu();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (infoString == null || infoString.isEmpty()) {
|
if (statusText == null || statusText.isEmpty()) {
|
||||||
deleteMenu();
|
// this means the status text already exists, and we are removing it
|
||||||
gtk.gtk_widget_destroy(connectionStatusItem);
|
|
||||||
connectionStatusItem = null;
|
|
||||||
|
|
||||||
|
gtk.gtk_container_remove(menu, connectionStatusItem);
|
||||||
|
connectionStatusItem = null; // because we manually delete it
|
||||||
|
|
||||||
|
gtk.gtk_widget_show_all(menu);
|
||||||
|
|
||||||
|
deleteMenu();
|
||||||
createMenu();
|
createMenu();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// here we set the text only. it already exists
|
||||||
|
|
||||||
// set bold instead
|
// set bold instead
|
||||||
// libgtk.gtk_menu_item_set_label(this.connectionStatusItem, infoString);
|
// libgtk.gtk_menu_item_set_label(this.connectionStatusItem, statusText);
|
||||||
|
|
||||||
// evil hacks abound...
|
// evil hacks abound...
|
||||||
Pointer label = gtk.gtk_bin_get_child(connectionStatusItem);
|
Pointer label = gtk.gtk_bin_get_child(connectionStatusItem);
|
||||||
gtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
gtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
||||||
Pointer markup = gobject.g_markup_printf_escaped("<b>%s</b>", infoString);
|
Pointer markup = gobject.g_markup_printf_escaped("<b>%s</b>", statusText);
|
||||||
gtk.gtk_label_set_markup(label, markup);
|
gtk.gtk_label_set_markup(label, markup);
|
||||||
gobject.g_free(markup);
|
gobject.g_free(markup);
|
||||||
|
|
||||||
|
@ -110,12 +137,59 @@ class GtkTypeSystemTray extends SystemTray {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||||
|
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||||
/**
|
/**
|
||||||
* Called inside the gdk_threads block
|
* Deletes the menu, and unreferences everything in it. ALSO recreates ONLY the menu object.
|
||||||
*/
|
*/
|
||||||
protected abstract
|
void deleteMenu() {
|
||||||
void onMenuAdded(final Pointer menu);
|
if (menu != null) {
|
||||||
|
// have to remove status from menu (but not destroy the object)
|
||||||
|
if (connectionStatusItem != null) {
|
||||||
|
gobject.g_object_force_floating(connectionStatusItem);
|
||||||
|
gtk.gtk_container_remove(menu, connectionStatusItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// have to remove all other menu entries
|
||||||
|
synchronized (menuEntries) {
|
||||||
|
for (int i = 0; i < menuEntries.size(); i++) {
|
||||||
|
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
||||||
|
|
||||||
|
gobject.g_object_force_floating(menuEntry__.menuItem);
|
||||||
|
gtk.gtk_container_remove(menu, menuEntry__.menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk.gtk_widget_destroy(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// makes a new one
|
||||||
|
menu = gtk.gtk_menu_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||||
|
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||||
|
void createMenu() {
|
||||||
|
// now add status
|
||||||
|
if (connectionStatusItem != null) {
|
||||||
|
gtk.gtk_menu_shell_append(this.menu, this.connectionStatusItem);
|
||||||
|
gobject.g_object_ref_sink(connectionStatusItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now add back other menu entries
|
||||||
|
synchronized (menuEntries) {
|
||||||
|
for (int i = 0; i < menuEntries.size(); i++) {
|
||||||
|
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
||||||
|
|
||||||
|
// will also get: gsignal.c:2516: signal 'child-added' is invalid for instance '0x7f1df8244080' of type 'GtkMenu'
|
||||||
|
gtk.gtk_menu_shell_append(this.menu, menuEntry__.menuItem);
|
||||||
|
gobject.g_object_ref_sink(menuEntry__.menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuAdded(menu);
|
||||||
|
gtk.gtk_widget_show_all(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completely obliterates the menu, no possible way to reconstruct it.
|
* Completely obliterates the menu, no possible way to reconstruct it.
|
||||||
|
@ -130,64 +204,28 @@ class GtkTypeSystemTray extends SystemTray {
|
||||||
}
|
}
|
||||||
|
|
||||||
// have to remove all other menu entries
|
// have to remove all other menu entries
|
||||||
for (int i = 0; i < menuEntries.size(); i++) {
|
synchronized (menuEntries) {
|
||||||
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
for (int i = 0; i < menuEntries.size(); i++) {
|
||||||
|
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
||||||
|
|
||||||
menuEntry__.removePrivate();
|
menuEntry__.removePrivate();
|
||||||
|
}
|
||||||
|
menuEntries.clear();
|
||||||
|
|
||||||
|
gtk.gtk_widget_destroy(menu);
|
||||||
}
|
}
|
||||||
menuEntries.clear();
|
|
||||||
|
|
||||||
// GTK menu needs a "ref_sink"
|
|
||||||
gobject.g_object_ref_sink(menu);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the menu, and unreferences everything in it. ALSO recreates ONLY the menu object.
|
* Called inside the gdk_threads block
|
||||||
*/
|
*/
|
||||||
void deleteMenu() {
|
protected
|
||||||
if (menu != null) {
|
void onMenuAdded(final Pointer menu) {};
|
||||||
// have to remove status from menu
|
|
||||||
if (connectionStatusItem != null) {
|
|
||||||
gobject.g_object_ref(connectionStatusItem);
|
|
||||||
|
|
||||||
gtk.gtk_container_remove(menu, connectionStatusItem);
|
protected
|
||||||
}
|
Pointer getMenu() {
|
||||||
|
return menu;
|
||||||
// have to remove all other menu entries
|
|
||||||
for (int i = 0; i < menuEntries.size(); i++) {
|
|
||||||
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
|
||||||
|
|
||||||
gobject.g_object_ref(menuEntry__.menuItem);
|
|
||||||
gtk.gtk_container_remove(menu, menuEntry__.menuItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GTK menu needs a "ref_sink"
|
|
||||||
gobject.g_object_ref_sink(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
menu = gtk.gtk_menu_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
// UNSAFE. must be protected inside dispatch
|
|
||||||
void createMenu() {
|
|
||||||
// now add status
|
|
||||||
if (connectionStatusItem != null) {
|
|
||||||
gtk.gtk_menu_shell_append(this.menu, this.connectionStatusItem);
|
|
||||||
gobject.g_object_unref(connectionStatusItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now add back other menu entries
|
|
||||||
for (int i = 0; i < menuEntries.size(); i++) {
|
|
||||||
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
|
||||||
|
|
||||||
// will also get: gsignal.c:2516: signal 'child-added' is invalid for instance '0x7f1df8244080' of type 'GtkMenu'
|
|
||||||
gtk.gtk_menu_shell_append(this.menu, menuEntry__.menuItem);
|
|
||||||
gobject.g_object_unref(menuEntry__.menuItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
onMenuAdded(menu);
|
|
||||||
gtk.gtk_widget_show_all(menu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -208,12 +246,10 @@ class GtkTypeSystemTray extends SystemTray {
|
||||||
|
|
||||||
if (menuEntry == null) {
|
if (menuEntry == null) {
|
||||||
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||||
// To work around this issue, we destroy then recreate the menu every time one is added.
|
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||||
deleteMenu();
|
deleteMenu();
|
||||||
|
|
||||||
menuEntry = new GtkMenuEntry(menu, menuText, imagePath, callback, GtkTypeSystemTray.this);
|
menuEntry = new GtkMenuEntry(menuText, imagePath, callback, GtkTypeSystemTray.this);
|
||||||
|
|
||||||
gobject.g_object_ref(menuEntry.menuItem); // so it matches with 'createMenu'
|
|
||||||
menuEntries.add(menuEntry);
|
menuEntries.add(menuEntry);
|
||||||
|
|
||||||
createMenu();
|
createMenu();
|
||||||
|
|
|
@ -161,14 +161,12 @@ interface Gobject extends Library {
|
||||||
|
|
||||||
|
|
||||||
void g_free(Pointer object);
|
void g_free(Pointer object);
|
||||||
void g_object_ref(Pointer object);
|
|
||||||
void g_object_unref(Pointer object);
|
void g_object_unref(Pointer object);
|
||||||
|
|
||||||
|
void g_object_force_floating(Pointer object);
|
||||||
void g_object_ref_sink(Pointer object);
|
void g_object_ref_sink(Pointer object);
|
||||||
|
|
||||||
NativeLong g_signal_connect_data(Pointer instance, String detailed_signal, Callback c_handler, Pointer data, Pointer destroy_data,
|
NativeLong g_signal_connect_object(Pointer instance, String detailed_signal, Callback c_handler, Pointer object, int connect_flags);
|
||||||
int connect_flags);
|
|
||||||
|
|
||||||
void g_signal_handler_disconnect(Pointer instance, NativeLong longAddress);
|
|
||||||
|
|
||||||
Pointer g_markup_printf_escaped(String pattern, String inputString);
|
Pointer g_markup_printf_escaped(String pattern, String inputString);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@ class GtkSupport {
|
||||||
Gtk library;
|
Gtk library;
|
||||||
|
|
||||||
boolean shouldUseGtk2 = SystemTray.FORCE_GTK2 || SystemTray.COMPATIBILITY_MODE;
|
boolean shouldUseGtk2 = SystemTray.FORCE_GTK2 || SystemTray.COMPATIBILITY_MODE;
|
||||||
alreadyRunningGTK = SystemTray.COMPATIBILITY_MODE;
|
|
||||||
|
|
||||||
|
|
||||||
// for more info on JavaFX: https://docs.oracle.com/javafx/2/system_requirements_2-2-3/jfxpub-system_requirements_2-2-3.htm
|
// for more info on JavaFX: https://docs.oracle.com/javafx/2/system_requirements_2-2-3/jfxpub-system_requirements_2-2-3.htm
|
||||||
// from the page: JavaFX 2.2.3 for Linux requires gtk2 2.18+.
|
// from the page: JavaFX 2.2.3 for Linux requires gtk2 2.18+.
|
||||||
|
@ -63,7 +61,7 @@ class GtkSupport {
|
||||||
|
|
||||||
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
||||||
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
||||||
alreadyRunningGTK |= library.gtk_main_level() != 0;
|
alreadyRunningGTK = library.gtk_main_level() != 0;
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
|
@ -79,7 +77,7 @@ class GtkSupport {
|
||||||
if (library != null) {
|
if (library != null) {
|
||||||
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
||||||
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
||||||
alreadyRunningGTK |= library.gtk_main_level() != 0;
|
alreadyRunningGTK = library.gtk_main_level() != 0;
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
|
@ -94,7 +92,7 @@ class GtkSupport {
|
||||||
|
|
||||||
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
||||||
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
||||||
alreadyRunningGTK |= library.gtk_main_level() != 0;
|
alreadyRunningGTK = library.gtk_main_level() != 0;
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
|
@ -111,7 +109,7 @@ class GtkSupport {
|
||||||
if (library != null) {
|
if (library != null) {
|
||||||
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
||||||
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
||||||
alreadyRunningGTK |= library.gtk_main_level() != 0;
|
alreadyRunningGTK = library.gtk_main_level() != 0;
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
|
@ -126,7 +124,7 @@ class GtkSupport {
|
||||||
|
|
||||||
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
|
||||||
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
|
||||||
alreadyRunningGTK |= library.gtk_main_level() != 0;
|
alreadyRunningGTK = library.gtk_main_level() != 0;
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
|
@ -153,7 +151,13 @@ class GtkSupport {
|
||||||
final Runnable take = dispatchEvents.take();
|
final Runnable take = dispatchEvents.take();
|
||||||
|
|
||||||
gtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
take.run();
|
|
||||||
|
try {
|
||||||
|
take.run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
gtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -183,13 +187,17 @@ class GtkSupport {
|
||||||
gtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
GThread.INSTANCE.g_thread_init(null);
|
GThread.INSTANCE.g_thread_init(null);
|
||||||
gtk.gtk_init_check(0, null);
|
|
||||||
|
|
||||||
|
if (!SystemTray.COMPATIBILITY_MODE) {
|
||||||
|
gtk.gtk_init_check(0, null);
|
||||||
|
}
|
||||||
// notify our main thread to continue
|
// notify our main thread to continue
|
||||||
blockUntilStarted.countDown();
|
blockUntilStarted.countDown();
|
||||||
|
|
||||||
// blocks unit quit
|
if (!SystemTray.COMPATIBILITY_MODE) {
|
||||||
gtk.gtk_main();
|
// blocks unit quit
|
||||||
|
gtk.gtk_main();
|
||||||
|
}
|
||||||
|
|
||||||
gtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
|
@ -222,7 +230,7 @@ class GtkSupport {
|
||||||
public static
|
public static
|
||||||
void shutdownGui() {
|
void shutdownGui() {
|
||||||
// If JavaFX/SWT is used, this is UNNECESSARY (an will break SWT/JavaFX shutdown)
|
// If JavaFX/SWT is used, this is UNNECESSARY (an will break SWT/JavaFX shutdown)
|
||||||
if (!alreadyRunningGTK) {
|
if (!(alreadyRunningGTK || SystemTray.COMPATIBILITY_MODE)) {
|
||||||
Gtk.INSTANCE.gtk_main_quit();
|
Gtk.INSTANCE.gtk_main_quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,9 @@ import java.net.URL;
|
||||||
public
|
public
|
||||||
class SwingSystemTray extends dorkbox.systemTray.SystemTray {
|
class SwingSystemTray extends dorkbox.systemTray.SystemTray {
|
||||||
volatile SwingSystemTrayMenuPopup menu;
|
volatile SwingSystemTrayMenuPopup menu;
|
||||||
|
|
||||||
volatile JMenuItem connectionStatusItem;
|
volatile JMenuItem connectionStatusItem;
|
||||||
|
private volatile String statusText = null;
|
||||||
|
|
||||||
volatile SystemTray tray;
|
volatile SystemTray tray;
|
||||||
volatile TrayIcon trayIcon;
|
volatile TrayIcon trayIcon;
|
||||||
|
@ -92,7 +94,15 @@ class SwingSystemTray extends dorkbox.systemTray.SystemTray {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setStatus(final String infoString) {
|
String getStatus() {
|
||||||
|
return this.statusText;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setStatus(final String statusText) {
|
||||||
|
this.statusText = statusText;
|
||||||
|
|
||||||
SwingUtil.invokeLater(new Runnable() {
|
SwingUtil.invokeLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
|
@ -100,7 +110,7 @@ class SwingSystemTray extends dorkbox.systemTray.SystemTray {
|
||||||
SwingSystemTray tray = SwingSystemTray.this;
|
SwingSystemTray tray = SwingSystemTray.this;
|
||||||
synchronized (tray) {
|
synchronized (tray) {
|
||||||
if (tray.connectionStatusItem == null) {
|
if (tray.connectionStatusItem == null) {
|
||||||
final JMenuItem connectionStatusItem = new JMenuItem(infoString);
|
final JMenuItem connectionStatusItem = new JMenuItem(statusText);
|
||||||
Font font = connectionStatusItem.getFont();
|
Font font = connectionStatusItem.getFont();
|
||||||
Font font1 = font.deriveFont(Font.BOLD);
|
Font font1 = font.deriveFont(Font.BOLD);
|
||||||
connectionStatusItem.setFont(font1);
|
connectionStatusItem.setFont(font1);
|
||||||
|
@ -111,7 +121,7 @@ class SwingSystemTray extends dorkbox.systemTray.SystemTray {
|
||||||
tray.connectionStatusItem = connectionStatusItem;
|
tray.connectionStatusItem = connectionStatusItem;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tray.connectionStatusItem.setText(infoString);
|
tray.connectionStatusItem.setText(statusText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import java.net.URL;
|
||||||
public
|
public
|
||||||
class TestTray {
|
class TestTray {
|
||||||
|
|
||||||
// horribly hacky. ONLY FOR TESTING!
|
|
||||||
public static final URL BLACK_MAIL = TestTray.class.getResource("mail.000000.24.png");
|
public static final URL BLACK_MAIL = TestTray.class.getResource("mail.000000.24.png");
|
||||||
public static final URL GREEN_MAIL = TestTray.class.getResource("mail.39AC39.24.png");
|
public static final URL GREEN_MAIL = TestTray.class.getResource("mail.39AC39.24.png");
|
||||||
public static final URL LT_GRAY_MAIL = TestTray.class.getResource("mail.999999.24.png");
|
public static final URL LT_GRAY_MAIL = TestTray.class.getResource("mail.999999.24.png");
|
||||||
|
@ -65,6 +64,7 @@ class TestTray {
|
||||||
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
||||||
systemTray.setStatus("Some Mail!");
|
systemTray.setStatus("Some Mail!");
|
||||||
systemTray.setIcon(GREEN_MAIL);
|
systemTray.setIcon(GREEN_MAIL);
|
||||||
|
|
||||||
menuEntry.setCallback(callbackGray);
|
menuEntry.setCallback(callbackGray);
|
||||||
menuEntry.setImage(BLACK_MAIL);
|
menuEntry.setImage(BLACK_MAIL);
|
||||||
menuEntry.setText("Delete Mail");
|
menuEntry.setText("Delete Mail");
|
||||||
|
@ -78,6 +78,7 @@ class TestTray {
|
||||||
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
||||||
systemTray.setStatus(null);
|
systemTray.setStatus(null);
|
||||||
systemTray.setIcon(BLACK_MAIL);
|
systemTray.setIcon(BLACK_MAIL);
|
||||||
|
|
||||||
menuEntry.setCallback(null);
|
menuEntry.setCallback(null);
|
||||||
// systemTray.setStatus("Mail Empty");
|
// systemTray.setStatus("Mail Empty");
|
||||||
systemTray.removeMenuEntry(menuEntry);
|
systemTray.removeMenuEntry(menuEntry);
|
||||||
|
|
|
@ -39,7 +39,6 @@ import java.net.URL;
|
||||||
public
|
public
|
||||||
class TestTrayJavaFX extends Application {
|
class TestTrayJavaFX extends Application {
|
||||||
|
|
||||||
// horribly hacky. ONLY FOR TESTING!
|
|
||||||
public static final URL BLACK_MAIL = TestTrayJavaFX.class.getResource("mail.000000.24.png");
|
public static final URL BLACK_MAIL = TestTrayJavaFX.class.getResource("mail.000000.24.png");
|
||||||
public static final URL GREEN_MAIL = TestTrayJavaFX.class.getResource("mail.39AC39.24.png");
|
public static final URL GREEN_MAIL = TestTrayJavaFX.class.getResource("mail.39AC39.24.png");
|
||||||
public static final URL LT_GRAY_MAIL = TestTrayJavaFX.class.getResource("mail.999999.24.png");
|
public static final URL LT_GRAY_MAIL = TestTrayJavaFX.class.getResource("mail.999999.24.png");
|
||||||
|
@ -97,8 +96,9 @@ class TestTrayJavaFX extends Application {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
||||||
systemTray.setStatus("Some Mail!");
|
|
||||||
systemTray.setIcon(GREEN_MAIL);
|
systemTray.setIcon(GREEN_MAIL);
|
||||||
|
systemTray.setStatus("Some Mail!");
|
||||||
|
|
||||||
menuEntry.setCallback(callbackGray);
|
menuEntry.setCallback(callbackGray);
|
||||||
menuEntry.setImage(BLACK_MAIL);
|
menuEntry.setImage(BLACK_MAIL);
|
||||||
menuEntry.setText("Delete Mail");
|
menuEntry.setText("Delete Mail");
|
||||||
|
@ -112,6 +112,7 @@ class TestTrayJavaFX extends Application {
|
||||||
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
||||||
systemTray.setStatus(null);
|
systemTray.setStatus(null);
|
||||||
systemTray.setIcon(BLACK_MAIL);
|
systemTray.setIcon(BLACK_MAIL);
|
||||||
|
|
||||||
menuEntry.setCallback(null);
|
menuEntry.setCallback(null);
|
||||||
// systemTray.setStatus("Mail Empty");
|
// systemTray.setStatus("Mail Empty");
|
||||||
systemTray.removeMenuEntry(menuEntry);
|
systemTray.removeMenuEntry(menuEntry);
|
||||||
|
|
|
@ -35,7 +35,6 @@ import java.net.URL;
|
||||||
public
|
public
|
||||||
class TestTraySwt {
|
class TestTraySwt {
|
||||||
|
|
||||||
// horribly hacky. ONLY FOR TESTING!
|
|
||||||
public static final URL BLACK_MAIL = TestTraySwt.class.getResource("mail.000000.24.png");
|
public static final URL BLACK_MAIL = TestTraySwt.class.getResource("mail.000000.24.png");
|
||||||
public static final URL GREEN_MAIL = TestTraySwt.class.getResource("mail.39AC39.24.png");
|
public static final URL GREEN_MAIL = TestTraySwt.class.getResource("mail.39AC39.24.png");
|
||||||
public static final URL LT_GRAY_MAIL = TestTraySwt.class.getResource("mail.999999.24.png");
|
public static final URL LT_GRAY_MAIL = TestTraySwt.class.getResource("mail.999999.24.png");
|
||||||
|
@ -55,7 +54,7 @@ class TestTraySwt {
|
||||||
|
|
||||||
public
|
public
|
||||||
TestTraySwt() {
|
TestTraySwt() {
|
||||||
Display display = new Display ();
|
final Display display = new Display ();
|
||||||
final Shell shell = new Shell(display);
|
final Shell shell = new Shell(display);
|
||||||
|
|
||||||
Text helloWorldTest = new Text(shell, SWT.NONE);
|
Text helloWorldTest = new Text(shell, SWT.NONE);
|
||||||
|
@ -77,8 +76,8 @@ class TestTraySwt {
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
||||||
systemTray.setStatus("Some Mail!");
|
systemTray.setStatus("Some Mail!");
|
||||||
|
|
||||||
systemTray.setIcon(GREEN_MAIL);
|
systemTray.setIcon(GREEN_MAIL);
|
||||||
|
|
||||||
menuEntry.setCallback(callbackGray);
|
menuEntry.setCallback(callbackGray);
|
||||||
menuEntry.setImage(BLACK_MAIL);
|
menuEntry.setImage(BLACK_MAIL);
|
||||||
menuEntry.setText("Delete Mail");
|
menuEntry.setText("Delete Mail");
|
||||||
|
@ -108,9 +107,9 @@ class TestTraySwt {
|
||||||
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
||||||
systemTray.shutdown();
|
systemTray.shutdown();
|
||||||
|
|
||||||
Display.getDefault().asyncExec(new Runnable() {
|
display.asyncExec(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
shell.close(); // close down SWT shell
|
shell.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user