forked from dorkbox/SystemTray
Fixed issues with loading libappindicator (for incorrect versions), now falls back to GTK. Compiled as java6.
This commit is contained in:
parent
2ff2366325
commit
c692059150
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package dorkbox.util.tray;
|
||||
|
||||
public interface FailureCallback {
|
||||
public void createTrayFailed();
|
||||
public
|
||||
interface FailureCallback {
|
||||
void createTrayFailed();
|
||||
}
|
||||
|
@ -15,13 +15,17 @@
|
||||
*/
|
||||
package dorkbox.util.tray;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import dorkbox.util.NamedThreadFactory;
|
||||
import dorkbox.util.OS;
|
||||
import dorkbox.util.jna.linux.AppIndicator;
|
||||
import dorkbox.util.jna.linux.GtkSupport;
|
||||
import dorkbox.util.tray.linux.AppIndicatorTray;
|
||||
import dorkbox.util.tray.linux.GtkSystemTray;
|
||||
import dorkbox.util.tray.swing.SwingSystemTray;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -32,21 +36,12 @@ import java.security.SecureRandom;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import dorkbox.util.NamedThreadFactory;
|
||||
import dorkbox.util.OS;
|
||||
import dorkbox.util.jna.linux.GtkSupport;
|
||||
import dorkbox.util.tray.linux.AppIndicatorTray;
|
||||
import dorkbox.util.tray.linux.GtkSystemTray;
|
||||
import dorkbox.util.tray.swing.SwingSystemTray;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for system tray implementations.
|
||||
*/
|
||||
public abstract class SystemTray {
|
||||
public abstract
|
||||
class SystemTray {
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
private static MessageDigest digest;
|
||||
@ -80,7 +75,7 @@ public abstract class SystemTray {
|
||||
if (getenv != null && getenv.equals("Unity")) {
|
||||
try {
|
||||
trayType = AppIndicatorTray.class;
|
||||
} catch (Exception ignored) {
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +102,13 @@ public abstract class SystemTray {
|
||||
bin = new BufferedReader(new FileReader(status));
|
||||
String readLine = bin.readLine();
|
||||
if (readLine != null && readLine.contains("indicator-app")) {
|
||||
trayType = AppIndicatorTray.class;
|
||||
// make sure we can also load the library (it might be the wrong version)
|
||||
try {
|
||||
final AppIndicator instance = AppIndicator.INSTANCE;
|
||||
trayType = AppIndicatorTray.class;
|
||||
} catch (Throwable ignored) {
|
||||
logger.error("AppIndicator support detected, but unable to load the library. Falling back to GTK");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
@ -118,7 +119,7 @@ public abstract class SystemTray {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
} catch (Throwable ignored) {
|
||||
} finally {
|
||||
if (bin != null) {
|
||||
try {
|
||||
@ -129,6 +130,7 @@ public abstract class SystemTray {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (trayType == null) {
|
||||
trayType = GtkSystemTray.class;
|
||||
}
|
||||
@ -143,7 +145,8 @@ public abstract class SystemTray {
|
||||
if (trayType == null) {
|
||||
// unsupported tray
|
||||
logger.error("Unsupported tray type!");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
digest = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
@ -159,7 +162,8 @@ public abstract class SystemTray {
|
||||
protected volatile boolean active = false;
|
||||
protected String appName;
|
||||
|
||||
public static SystemTray create(String appName) {
|
||||
public static
|
||||
SystemTray create(String appName) {
|
||||
if (trayType != null) {
|
||||
try {
|
||||
SystemTray newInstance = trayType.newInstance();
|
||||
@ -167,7 +171,7 @@ public abstract class SystemTray {
|
||||
newInstance.setAppName(appName);
|
||||
}
|
||||
return newInstance;
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@ -176,34 +180,43 @@ public abstract class SystemTray {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setAppName(String appName) {
|
||||
private
|
||||
void setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
}
|
||||
|
||||
public abstract void createTray(String iconName);
|
||||
public abstract
|
||||
void createTray(String iconName);
|
||||
|
||||
public void removeTray() {
|
||||
public
|
||||
void removeTray() {
|
||||
SystemTray.this.callbackExecutor.shutdown();
|
||||
}
|
||||
|
||||
public abstract void setStatus(String infoString, String iconName);
|
||||
public abstract
|
||||
void setStatus(String infoString, String iconName);
|
||||
|
||||
public abstract void addMenuEntry(String menuText, SystemTrayMenuAction callback);
|
||||
public abstract
|
||||
void addMenuEntry(String menuText, SystemTrayMenuAction callback);
|
||||
|
||||
public abstract void updateMenuEntry(String origMenuText, String newMenuText, SystemTrayMenuAction newCallback);
|
||||
public abstract
|
||||
void updateMenuEntry(String origMenuText, String newMenuText, SystemTrayMenuAction newCallback);
|
||||
|
||||
|
||||
protected String iconPath(String fileName) {
|
||||
protected
|
||||
String iconPath(String fileName) {
|
||||
// is file sitting on drive
|
||||
File iconTest;
|
||||
if (ICON_PATH.isEmpty()) {
|
||||
iconTest = new File(fileName);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
iconTest = new File(ICON_PATH, fileName);
|
||||
}
|
||||
if (iconTest.isFile() && iconTest.canRead()) {
|
||||
return iconTest.getAbsolutePath();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (!ICON_PATH.isEmpty()) {
|
||||
fileName = ICON_PATH + "/" + fileName;
|
||||
}
|
||||
@ -291,11 +304,13 @@ public abstract class SystemTray {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
|
||||
public final void setFailureCallback(FailureCallback failureCallback) {
|
||||
public final
|
||||
void setFailureCallback(FailureCallback failureCallback) {
|
||||
this.failureCallback = failureCallback;
|
||||
}
|
||||
|
||||
public final boolean isActive() {
|
||||
public final
|
||||
boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package dorkbox.util.tray;
|
||||
|
||||
public interface SystemTrayMenuAction {
|
||||
public
|
||||
interface SystemTrayMenuAction {
|
||||
void onClick(SystemTray systemTray);
|
||||
}
|
||||
|
@ -1,46 +1,50 @@
|
||||
package dorkbox.util.tray;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.MouseInfo;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import dorkbox.util.DelayTimer;
|
||||
import dorkbox.util.SwingUtil;
|
||||
|
||||
public class SystemTrayMenuPopup extends JPopupMenu {
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public
|
||||
class SystemTrayMenuPopup extends JPopupMenu {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Allows you to customize the delay (for hiding the popup) when the cursor is "moused out" of the popup menu */
|
||||
/**
|
||||
* Allows you to customize the delay (for hiding the popup) when the cursor is "moused out" of the popup menu
|
||||
*/
|
||||
public static long hidePopupDelay = 1000L;
|
||||
|
||||
private DelayTimer timer;
|
||||
|
||||
protected boolean mouseStillOnMenu;
|
||||
// protected boolean mouseStillOnMenu;
|
||||
// private JDialog hiddenDialog;
|
||||
|
||||
public SystemTrayMenuPopup() {
|
||||
public
|
||||
SystemTrayMenuPopup() {
|
||||
super();
|
||||
setFocusable(true);
|
||||
|
||||
this.timer = new DelayTimer("PopupMenuHider", true, new DelayTimer.Callback() {
|
||||
@Override
|
||||
public void execute() {
|
||||
public
|
||||
void execute() {
|
||||
SwingUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
Point location = MouseInfo.getPointerInfo().getLocation();
|
||||
Point locationOnScreen = getLocationOnScreen();
|
||||
Dimension size = getSize();
|
||||
|
||||
if (location.x >= locationOnScreen.x && location.x < locationOnScreen.x + size.width
|
||||
&& location.y >= locationOnScreen.y && location.y < locationOnScreen.y + size.height) {
|
||||
if (location.x >= locationOnScreen.x && location.x < locationOnScreen.x + size.width &&
|
||||
location.y >= locationOnScreen.y && location.y < locationOnScreen.y + size.height) {
|
||||
|
||||
SystemTrayMenuPopup.this.timer.delay(SystemTrayMenuPopup.this.timer.getDelay());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
@ -50,7 +54,8 @@ public class SystemTrayMenuPopup extends JPopupMenu {
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseExited(MouseEvent event) {
|
||||
public
|
||||
void mouseExited(MouseEvent event) {
|
||||
// wait before checking if mouse is still on the menu
|
||||
SystemTrayMenuPopup.this.timer.delay(SystemTrayMenuPopup.this.timer.getDelay());
|
||||
}
|
||||
@ -75,7 +80,8 @@ public class SystemTrayMenuPopup extends JPopupMenu {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean makeVisible) {
|
||||
public
|
||||
void setVisible(boolean makeVisible) {
|
||||
this.timer.cancel();
|
||||
|
||||
if (makeVisible) {
|
||||
|
@ -15,13 +15,7 @@
|
||||
*/
|
||||
package dorkbox.util.tray.linux;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import dorkbox.util.jna.linux.AppIndicator;
|
||||
import dorkbox.util.jna.linux.Gobject;
|
||||
import dorkbox.util.jna.linux.Gtk;
|
||||
@ -29,16 +23,22 @@ import dorkbox.util.jna.linux.GtkSupport;
|
||||
import dorkbox.util.tray.SystemTray;
|
||||
import dorkbox.util.tray.SystemTrayMenuAction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class for handling all system tray interactions.
|
||||
*
|
||||
* <p/>
|
||||
* specialization for using app indicators in ubuntu unity
|
||||
*
|
||||
* <p/>
|
||||
* Heavily modified from
|
||||
*
|
||||
* <p/>
|
||||
* Lantern: https://github.com/getlantern/lantern/ Apache 2.0 License Copyright 2010 Brave New Software Project, Inc.
|
||||
*/
|
||||
public class AppIndicatorTray extends SystemTray {
|
||||
public
|
||||
class AppIndicatorTray extends SystemTray {
|
||||
private static final AppIndicator libappindicator = AppIndicator.INSTANCE;
|
||||
private static final Gobject libgobject = Gobject.INSTANCE;
|
||||
private static final Gtk libgtk = Gtk.INSTANCE;
|
||||
@ -54,29 +54,33 @@ public class AppIndicatorTray extends SystemTray {
|
||||
private final List<Pointer> widgets = new ArrayList<Pointer>(4);
|
||||
|
||||
|
||||
public AppIndicatorTray() {
|
||||
public
|
||||
AppIndicatorTray() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTray(String iconName) {
|
||||
public
|
||||
void createTray(String iconName) {
|
||||
libgtk.gdk_threads_enter();
|
||||
this.appIndicator =
|
||||
libappindicator.app_indicator_new(this.appName, "indicator-messages-new", AppIndicator.CATEGORY_APPLICATION_STATUS);
|
||||
this.appIndicator = libappindicator.app_indicator_new(this.appName, "indicator-messages-new",
|
||||
AppIndicator.CATEGORY_APPLICATION_STATUS);
|
||||
|
||||
/*
|
||||
* basically a hack -- we should subclass the AppIndicator type and override the fallback entry in the 'vtable', instead we just
|
||||
* hack the app indicator class itself. Not an issue unless we need other appindicators.
|
||||
*/
|
||||
AppIndicator.AppIndicatorClassStruct aiclass =
|
||||
new AppIndicator.AppIndicatorClassStruct(this.appIndicator.parent.g_type_instance.g_class);
|
||||
AppIndicator.AppIndicatorClassStruct aiclass = new AppIndicator.AppIndicatorClassStruct(
|
||||
this.appIndicator.parent.g_type_instance.g_class);
|
||||
|
||||
|
||||
aiclass.fallback = new AppIndicator.Fallback() {
|
||||
@Override
|
||||
public Pointer callback(final AppIndicator.AppIndicatorInstanceStruct self) {
|
||||
public
|
||||
Pointer callback(final AppIndicator.AppIndicatorInstanceStruct self) {
|
||||
AppIndicatorTray.this.callbackExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
logger.warn("Failed to create appindicator system tray.");
|
||||
|
||||
if (AppIndicatorTray.this.failureCallback != null) {
|
||||
@ -101,7 +105,8 @@ public class AppIndicatorTray extends SystemTray {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTray() {
|
||||
public
|
||||
void removeTray() {
|
||||
libgtk.gdk_threads_enter();
|
||||
for (Pointer widget : this.widgets) {
|
||||
libgtk.gtk_widget_destroy(widget);
|
||||
@ -135,14 +140,16 @@ public class AppIndicatorTray extends SystemTray {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(String infoString, String iconName) {
|
||||
public
|
||||
void setStatus(String infoString, String iconName) {
|
||||
libgtk.gdk_threads_enter();
|
||||
if (this.connectionStatusItem == null) {
|
||||
this.connectionStatusItem = libgtk.gtk_menu_item_new_with_label(infoString);
|
||||
this.widgets.add(this.connectionStatusItem);
|
||||
libgtk.gtk_widget_set_sensitive(this.connectionStatusItem, Gtk.FALSE);
|
||||
libgtk.gtk_menu_shell_append(this.menu, this.connectionStatusItem);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
libgtk.gtk_menu_item_set_label(this.connectionStatusItem, infoString);
|
||||
}
|
||||
|
||||
@ -156,7 +163,8 @@ public class AppIndicatorTray extends SystemTray {
|
||||
* Will add a new menu entry, or update one if it already exists
|
||||
*/
|
||||
@Override
|
||||
public void addMenuEntry(String menuText, final SystemTrayMenuAction callback) {
|
||||
public
|
||||
void addMenuEntry(String menuText, final SystemTrayMenuAction callback) {
|
||||
synchronized (this.menuEntries) {
|
||||
MenuEntry menuEntry = this.menuEntries.get(menuText);
|
||||
|
||||
@ -168,10 +176,12 @@ public class AppIndicatorTray extends SystemTray {
|
||||
// have to watch out! These can get garbage collected!
|
||||
Gobject.GCallback gtkCallback = new Gobject.GCallback() {
|
||||
@Override
|
||||
public void callback(Pointer instance, Pointer data) {
|
||||
public
|
||||
void callback(Pointer instance, Pointer data) {
|
||||
AppIndicatorTray.this.callbackExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
callback.onClick(AppIndicatorTray.this);
|
||||
}
|
||||
});
|
||||
@ -189,7 +199,8 @@ public class AppIndicatorTray extends SystemTray {
|
||||
menuEntry.gtkCallback = gtkCallback;
|
||||
|
||||
this.menuEntries.put(menuText, menuEntry);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
updateMenuEntry(menuText, menuText, callback);
|
||||
}
|
||||
}
|
||||
@ -199,7 +210,8 @@ public class AppIndicatorTray extends SystemTray {
|
||||
* Will update an already existing menu entry (or add a new one, if it doesn't exist)
|
||||
*/
|
||||
@Override
|
||||
public void updateMenuEntry(String origMenuText, String newMenuText, final SystemTrayMenuAction newCallback) {
|
||||
public
|
||||
void updateMenuEntry(String origMenuText, String newMenuText, final SystemTrayMenuAction newCallback) {
|
||||
synchronized (this.menuEntries) {
|
||||
MenuEntry menuEntry = this.menuEntries.get(origMenuText);
|
||||
|
||||
@ -210,10 +222,12 @@ public class AppIndicatorTray extends SystemTray {
|
||||
// have to watch out! These can get garbage collected!
|
||||
menuEntry.gtkCallback = new Gobject.GCallback() {
|
||||
@Override
|
||||
public void callback(Pointer instance, Pointer data) {
|
||||
public
|
||||
void callback(Pointer instance, Pointer data) {
|
||||
AppIndicatorTray.this.callbackExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
newCallback.onClick(AppIndicatorTray.this);
|
||||
}
|
||||
});
|
||||
@ -224,7 +238,8 @@ public class AppIndicatorTray extends SystemTray {
|
||||
|
||||
libgtk.gtk_widget_show_all(menuEntry.dashboardItem);
|
||||
libgtk.gdk_threads_leave();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
addMenuEntry(origMenuText, newCallback);
|
||||
}
|
||||
}
|
||||
|
@ -15,20 +15,7 @@
|
||||
*/
|
||||
package dorkbox.util.tray.linux;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import dorkbox.util.SwingUtil;
|
||||
import dorkbox.util.jna.linux.Gobject;
|
||||
import dorkbox.util.jna.linux.Gtk;
|
||||
@ -38,12 +25,22 @@ import dorkbox.util.tray.SystemTray;
|
||||
import dorkbox.util.tray.SystemTrayMenuAction;
|
||||
import dorkbox.util.tray.SystemTrayMenuPopup;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class for handling all system tray interactions via GTK.
|
||||
*
|
||||
* <p/>
|
||||
* This is the "old" way to do it, and does not work with some desktop environments.
|
||||
*/
|
||||
public class GtkSystemTray extends SystemTray {
|
||||
public
|
||||
class GtkSystemTray extends SystemTray {
|
||||
private static final Gobject libgobject = Gobject.INSTANCE;
|
||||
private static final Gtk libgtk = Gtk.INSTANCE;
|
||||
|
||||
@ -58,14 +55,17 @@ public class GtkSystemTray extends SystemTray {
|
||||
private final List<Pointer> widgets = new ArrayList<Pointer>(4);
|
||||
private Gobject.GEventCallback gtkCallback;
|
||||
|
||||
public GtkSystemTray() {
|
||||
public
|
||||
GtkSystemTray() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTray(String iconName) {
|
||||
public
|
||||
void createTray(String iconName) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
GtkSystemTray.this.jmenu = new SystemTrayMenuPopup();
|
||||
}
|
||||
});
|
||||
@ -80,28 +80,32 @@ public class GtkSystemTray extends SystemTray {
|
||||
// have to make this a field, to prevent GC on this object
|
||||
this.gtkCallback = new Gobject.GEventCallback() {
|
||||
@Override
|
||||
public void callback(Pointer system_tray, final GdkEventButton event) {
|
||||
public
|
||||
void callback(Pointer system_tray, final GdkEventButton event) {
|
||||
// BUTTON_PRESS only (any mouse click)
|
||||
if (event.type == 4) {
|
||||
SwingUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
// test this using cinnamon (which still uses status icon)
|
||||
|
||||
if (GtkSystemTray.this.jmenu.isVisible()) {
|
||||
GtkSystemTray.this.jmenu.setVisible(false);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Dimension size = GtkSystemTray.this.jmenu.getPreferredSize();
|
||||
|
||||
int x = (int) event.x_root;
|
||||
int y = (int) event.y_root;
|
||||
int y = (int) event.y_root;
|
||||
|
||||
Point point = new Point(x, y);
|
||||
Rectangle bounds = SwingUtil.getScreenBoundsAt(point);
|
||||
|
||||
if (y < bounds.y) {
|
||||
y = bounds.y;
|
||||
} else if (y + size.height > bounds.y + bounds.height) {
|
||||
}
|
||||
else if (y + size.height > bounds.y + bounds.height) {
|
||||
// our menu cannot have the top-edge snap to the mouse
|
||||
// so we make the bottom-edge snap to the mouse
|
||||
y -= size.height; // snap to edge of mouse
|
||||
@ -109,7 +113,8 @@ public class GtkSystemTray extends SystemTray {
|
||||
|
||||
if (x < bounds.x) {
|
||||
x = bounds.x;
|
||||
} else if (x + size.width > bounds.x + bounds.width) {
|
||||
}
|
||||
else if (x + size.width > bounds.x + bounds.width) {
|
||||
// our menu cannot have the left-edge snap to the mouse
|
||||
// so we make the right-edge snap to the mouse
|
||||
x -= size.width; // snap to edge of mouse
|
||||
@ -122,7 +127,8 @@ public class GtkSystemTray extends SystemTray {
|
||||
// we are at the top of the screen
|
||||
if (y < 100) {
|
||||
y += distanceToEdgeOfTray + 4;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
y -= distanceToEdgeOfTray + 4;
|
||||
}
|
||||
|
||||
@ -144,7 +150,8 @@ public class GtkSystemTray extends SystemTray {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTray() {
|
||||
public
|
||||
void removeTray() {
|
||||
libgtk.gdk_threads_enter();
|
||||
for (Pointer widget : this.widgets) {
|
||||
libgtk.gtk_widget_destroy(widget);
|
||||
@ -177,15 +184,18 @@ public class GtkSystemTray extends SystemTray {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(final String infoString, String iconName) {
|
||||
public
|
||||
void setStatus(final String infoString, String iconName) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
if (GtkSystemTray.this.connectionStatusItem == null) {
|
||||
GtkSystemTray.this.connectionStatusItem = new JMenuItem(infoString);
|
||||
GtkSystemTray.this.connectionStatusItem.setEnabled(false);
|
||||
GtkSystemTray.this.jmenu.add(GtkSystemTray.this.connectionStatusItem);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
GtkSystemTray.this.connectionStatusItem.setText(infoString);
|
||||
}
|
||||
}
|
||||
@ -200,10 +210,12 @@ public class GtkSystemTray extends SystemTray {
|
||||
* Will add a new menu entry, or update one if it already exists
|
||||
*/
|
||||
@Override
|
||||
public void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
||||
public
|
||||
void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
Map<String, JMenuItem> menuEntries2 = GtkSystemTray.this.menuEntries;
|
||||
|
||||
synchronized (menuEntries2) {
|
||||
@ -215,12 +227,14 @@ public class GtkSystemTray extends SystemTray {
|
||||
menuEntry = new JMenuItem(menuText);
|
||||
menuEntry.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
// SystemTrayMenuPopup source = (SystemTrayMenuPopup) ((JMenuItem)e.getSource()).getParent();
|
||||
|
||||
GtkSystemTray.this.callbackExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
callback.onClick(GtkSystemTray.this);
|
||||
}
|
||||
});
|
||||
@ -229,7 +243,8 @@ public class GtkSystemTray extends SystemTray {
|
||||
menu.add(menuEntry);
|
||||
|
||||
menuEntries2.put(menuText, menuEntry);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
updateMenuEntry(menuText, menuText, callback);
|
||||
}
|
||||
}
|
||||
@ -241,10 +256,12 @@ public class GtkSystemTray extends SystemTray {
|
||||
* Will update an already existing menu entry (or add a new one, if it doesn't exist)
|
||||
*/
|
||||
@Override
|
||||
public void updateMenuEntry(final String origMenuText, final String newMenuText, final SystemTrayMenuAction newCallback) {
|
||||
public
|
||||
void updateMenuEntry(final String origMenuText, final String newMenuText, final SystemTrayMenuAction newCallback) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
Map<String, JMenuItem> menuEntries2 = GtkSystemTray.this.menuEntries;
|
||||
|
||||
synchronized (menuEntries2) {
|
||||
@ -258,10 +275,12 @@ public class GtkSystemTray extends SystemTray {
|
||||
|
||||
menuEntry.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
GtkSystemTray.this.callbackExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
newCallback.onClick(GtkSystemTray.this);
|
||||
}
|
||||
});
|
||||
@ -269,7 +288,8 @@ public class GtkSystemTray extends SystemTray {
|
||||
});
|
||||
menuEntry.setText(newMenuText);
|
||||
menuEntry.revalidate();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
addMenuEntry(origMenuText, newCallback);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
package dorkbox.util.tray.linux;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import dorkbox.util.jna.linux.Gobject.GCallback;
|
||||
|
||||
/**
|
||||
@ -28,18 +27,21 @@ class MenuEntry {
|
||||
public Pointer dashboardItem;
|
||||
public GCallback gtkCallback;
|
||||
|
||||
public MenuEntry() {
|
||||
public
|
||||
MenuEntry() {
|
||||
long time = System.nanoTime();
|
||||
this.hashCode = (int) (time ^ time >>> 32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
public
|
||||
int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public
|
||||
boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
@ -15,13 +15,12 @@
|
||||
*/
|
||||
package dorkbox.util.tray.swing;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.TrayIcon;
|
||||
import dorkbox.util.SwingUtil;
|
||||
import dorkbox.util.tray.SystemTrayMenuAction;
|
||||
import dorkbox.util.tray.SystemTrayMenuPopup;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
@ -29,17 +28,11 @@ import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import dorkbox.util.SwingUtil;
|
||||
import dorkbox.util.tray.SystemTrayMenuAction;
|
||||
import dorkbox.util.tray.SystemTrayMenuPopup;
|
||||
|
||||
/**
|
||||
* Class for handling all system tray interaction, via SWING
|
||||
*/
|
||||
public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
public
|
||||
class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
|
||||
private final Map<String, JMenuItem> menuEntries = new HashMap<String, JMenuItem>(2);
|
||||
|
||||
@ -52,14 +45,18 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
/**
|
||||
* Creates a new system tray handler class.
|
||||
*/
|
||||
public SwingSystemTray() {}
|
||||
public
|
||||
SwingSystemTray() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void removeTray() {
|
||||
public
|
||||
void removeTray() {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
SwingSystemTray.this.tray.remove(SwingSystemTray.this.trayIcon);
|
||||
SwingSystemTray.this.menuEntries.clear();
|
||||
}
|
||||
@ -69,14 +66,17 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTray(final String iconName) {
|
||||
public
|
||||
void createTray(final String iconName) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
SwingSystemTray.this.tray = SystemTray.getSystemTray();
|
||||
if (SwingSystemTray.this.tray == null) {
|
||||
logger.error("The system tray is not available");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
SwingSystemTray.this.jmenu = new SystemTrayMenuPopup();
|
||||
|
||||
Image trayImage = newImage(iconName);
|
||||
@ -85,7 +85,8 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
|
||||
SwingSystemTray.this.trayIcon.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
public
|
||||
void mousePressed(MouseEvent e) {
|
||||
Dimension size = SwingSystemTray.this.jmenu.getPreferredSize();
|
||||
|
||||
Point point = e.getPoint();
|
||||
@ -96,7 +97,8 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
|
||||
if (y < bounds.y) {
|
||||
y = bounds.y;
|
||||
} else if (y + size.height > bounds.y + bounds.height) {
|
||||
}
|
||||
else if (y + size.height > bounds.y + bounds.height) {
|
||||
// our menu cannot have the top-edge snap to the mouse
|
||||
// so we make the bottom-edge snap to the mouse
|
||||
y -= size.height; // snap to edge of mouse
|
||||
@ -104,7 +106,8 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
|
||||
if (x < bounds.x) {
|
||||
x = bounds.x;
|
||||
} else if (x + size.width > bounds.x + bounds.width) {
|
||||
}
|
||||
else if (x + size.width > bounds.x + bounds.width) {
|
||||
// our menu cannot have the left-edge snap to the mouse
|
||||
// so we make the right-edge snap to the mouse
|
||||
x -= size.width; // snap to edge of mouse
|
||||
@ -135,15 +138,18 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(final String infoString, final String iconName) {
|
||||
public
|
||||
void setStatus(final String infoString, final String iconName) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
if (SwingSystemTray.this.connectionStatusItem == null) {
|
||||
SwingSystemTray.this.connectionStatusItem = new JMenuItem(infoString);
|
||||
SwingSystemTray.this.connectionStatusItem.setEnabled(false);
|
||||
SwingSystemTray.this.jmenu.add(SwingSystemTray.this.connectionStatusItem);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
SwingSystemTray.this.connectionStatusItem.setText(infoString);
|
||||
}
|
||||
}
|
||||
@ -157,10 +163,12 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
* Will add a new menu entry, or update one if it already exists
|
||||
*/
|
||||
@Override
|
||||
public void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
||||
public
|
||||
void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
Map<String, JMenuItem> menuEntries2 = SwingSystemTray.this.menuEntries;
|
||||
|
||||
synchronized (menuEntries2) {
|
||||
@ -172,10 +180,12 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
menuEntry = new JMenuItem(menuText);
|
||||
menuEntry.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
SwingSystemTray.this.callbackExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
callback.onClick(SwingSystemTray.this);
|
||||
}
|
||||
});
|
||||
@ -184,7 +194,8 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
menu.add(menuEntry);
|
||||
|
||||
menuEntries2.put(menuText, menuEntry);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
updateMenuEntry(menuText, menuText, callback);
|
||||
}
|
||||
}
|
||||
@ -196,10 +207,12 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
* Will update an already existing menu entry (or add a new one, if it doesn't exist)
|
||||
*/
|
||||
@Override
|
||||
public void updateMenuEntry(final String origMenuText, final String newMenuText, final SystemTrayMenuAction newCallback) {
|
||||
public
|
||||
void updateMenuEntry(final String origMenuText, final String newMenuText, final SystemTrayMenuAction newCallback) {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
Map<String, JMenuItem> menuEntries2 = SwingSystemTray.this.menuEntries;
|
||||
|
||||
synchronized (menuEntries2) {
|
||||
@ -213,10 +226,12 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
|
||||
menuEntry.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
SwingSystemTray.this.callbackExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public
|
||||
void run() {
|
||||
newCallback.onClick(SwingSystemTray.this);
|
||||
}
|
||||
});
|
||||
@ -224,7 +239,8 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
||||
});
|
||||
menuEntry.setText(newMenuText);
|
||||
menuEntry.revalidate();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
addMenuEntry(origMenuText, newCallback);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user