forked from dorkbox/SystemTray
Fixed swing threading issues. Fixed GTK threading issues. Code cleanup
This commit is contained in:
parent
8ddf3291ac
commit
9a48be4c74
@ -7,9 +7,9 @@ import java.awt.event.MouseAdapter;
|
|||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import dorkbox.util.DelayTimer;
|
import dorkbox.util.DelayTimer;
|
||||||
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
public class SystemTrayMenuPopup extends JPopupMenu {
|
public class SystemTrayMenuPopup extends JPopupMenu {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -22,8 +22,7 @@ public class SystemTrayMenuPopup extends JPopupMenu {
|
|||||||
this.timer = new DelayTimer("PopupMenuHider", true, new DelayTimer.Callback() {
|
this.timer = new DelayTimer("PopupMenuHider", true, new DelayTimer.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtil.invokeLater(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Point location = MouseInfo.getPointerInfo().getLocation();
|
Point location = MouseInfo.getPointerInfo().getLocation();
|
||||||
|
@ -40,6 +40,8 @@ import dorkbox.util.tray.SystemTrayMenuAction;
|
|||||||
* Lantern: https://github.com/getlantern/lantern/ Apache 2.0 License Copyright 2010 Brave New Software Project, Inc.
|
* 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 boolean useSWT = GtkSupport.usesSwtMainLoop;
|
||||||
|
|
||||||
private static final AppIndicator libappindicator = AppIndicator.INSTANCE;
|
private static final AppIndicator libappindicator = AppIndicator.INSTANCE;
|
||||||
private static final Gobject libgobject = Gobject.INSTANCE;
|
private static final Gobject libgobject = Gobject.INSTANCE;
|
||||||
private static final Gtk libgtk = Gtk.INSTANCE;
|
private static final Gtk libgtk = Gtk.INSTANCE;
|
||||||
@ -56,10 +58,12 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
private final List<Pointer> widgets = new ArrayList<Pointer>(4);
|
private final List<Pointer> widgets = new ArrayList<Pointer>(4);
|
||||||
|
|
||||||
|
|
||||||
public AppIndicatorTray() {}
|
public AppIndicatorTray() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createTray(String iconName) {
|
public void createTray(String iconName) {
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
this.appIndicator =
|
this.appIndicator =
|
||||||
libappindicator.app_indicator_new(this.appName, "indicator-messages-new", AppIndicator.CATEGORY_APPLICATION_STATUS);
|
libappindicator.app_indicator_new(this.appName, "indicator-messages-new", AppIndicator.CATEGORY_APPLICATION_STATUS);
|
||||||
|
|
||||||
@ -95,22 +99,18 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
libappindicator.app_indicator_set_icon_full(this.appIndicator, iconPath(iconName), this.appName);
|
libappindicator.app_indicator_set_icon_full(this.appIndicator, iconPath(iconName), this.appName);
|
||||||
libappindicator.app_indicator_set_status(this.appIndicator, AppIndicator.STATUS_ACTIVE);
|
libappindicator.app_indicator_set_status(this.appIndicator, AppIndicator.STATUS_ACTIVE);
|
||||||
|
|
||||||
if (!GtkSupport.usesSwtMainLoop) {
|
libgtk.gdk_threads_leave();
|
||||||
|
|
||||||
|
if (!useSWT) {
|
||||||
Thread gtkUpdateThread = new Thread() {
|
Thread gtkUpdateThread = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// notify our main thread to continue
|
// notify our main thread to continue
|
||||||
AppIndicatorTray.this.blockUntilStarted.countDown();
|
AppIndicatorTray.this.blockUntilStarted.countDown();
|
||||||
|
libgtk.gtk_main();
|
||||||
try {
|
|
||||||
libgtk.gtk_main();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
logger.warn("Unable to run main loop", t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
gtkUpdateThread.setName("GTK event loop");
|
gtkUpdateThread.setName("GTK event loop");
|
||||||
gtkUpdateThread.setDaemon(true);
|
|
||||||
gtkUpdateThread.start();
|
gtkUpdateThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +124,7 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeTray() {
|
public void removeTray() {
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
for (Pointer widget : this.widgets) {
|
for (Pointer widget : this.widgets) {
|
||||||
libgtk.gtk_widget_destroy(widget);
|
libgtk.gtk_widget_destroy(widget);
|
||||||
}
|
}
|
||||||
@ -149,12 +150,15 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.connectionStatusItem = null;
|
this.connectionStatusItem = null;
|
||||||
|
libgtk.gtk_main_quit();
|
||||||
|
|
||||||
|
libgtk.gdk_threads_leave();
|
||||||
super.removeTray();
|
super.removeTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStatus(String infoString, String iconName) {
|
public void setStatus(String infoString, String iconName) {
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
if (this.connectionStatusItem == null) {
|
if (this.connectionStatusItem == null) {
|
||||||
this.connectionStatusItem = libgtk.gtk_menu_item_new_with_label(infoString);
|
this.connectionStatusItem = libgtk.gtk_menu_item_new_with_label(infoString);
|
||||||
this.widgets.add(this.connectionStatusItem);
|
this.widgets.add(this.connectionStatusItem);
|
||||||
@ -167,6 +171,7 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
libgtk.gtk_widget_show_all(this.connectionStatusItem);
|
libgtk.gtk_widget_show_all(this.connectionStatusItem);
|
||||||
|
|
||||||
libappindicator.app_indicator_set_icon_full(this.appIndicator, iconPath(iconName), this.appName);
|
libappindicator.app_indicator_set_icon_full(this.appIndicator, iconPath(iconName), this.appName);
|
||||||
|
libgtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,7 +183,11 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
MenuEntry menuEntry = this.menuEntries.get(menuText);
|
MenuEntry menuEntry = this.menuEntries.get(menuText);
|
||||||
|
|
||||||
if (menuEntry == null) {
|
if (menuEntry == null) {
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
|
|
||||||
Pointer dashboardItem = libgtk.gtk_menu_item_new_with_label(menuText);
|
Pointer dashboardItem = libgtk.gtk_menu_item_new_with_label(menuText);
|
||||||
|
|
||||||
|
// have to watch out! These can get garbage collected!
|
||||||
Gobject.GCallback gtkCallback = new Gobject.GCallback() {
|
Gobject.GCallback gtkCallback = new Gobject.GCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void callback(Pointer instance, Pointer data) {
|
public void callback(Pointer instance, Pointer data) {
|
||||||
@ -195,8 +204,11 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
libgtk.gtk_menu_shell_append(this.menu, dashboardItem);
|
libgtk.gtk_menu_shell_append(this.menu, dashboardItem);
|
||||||
libgtk.gtk_widget_show_all(dashboardItem);
|
libgtk.gtk_widget_show_all(dashboardItem);
|
||||||
|
|
||||||
|
libgtk.gdk_threads_leave();
|
||||||
|
|
||||||
menuEntry = new MenuEntry();
|
menuEntry = new MenuEntry();
|
||||||
menuEntry.dashboardItem = dashboardItem;
|
menuEntry.dashboardItem = dashboardItem;
|
||||||
|
menuEntry.gtkCallback = gtkCallback;
|
||||||
|
|
||||||
this.menuEntries.put(menuText, menuEntry);
|
this.menuEntries.put(menuText, menuEntry);
|
||||||
} else {
|
} else {
|
||||||
@ -214,9 +226,11 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
MenuEntry menuEntry = this.menuEntries.get(origMenuText);
|
MenuEntry menuEntry = this.menuEntries.get(origMenuText);
|
||||||
|
|
||||||
if (menuEntry != null) {
|
if (menuEntry != null) {
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
libgtk.gtk_menu_item_set_label(menuEntry.dashboardItem, newMenuText);
|
libgtk.gtk_menu_item_set_label(menuEntry.dashboardItem, newMenuText);
|
||||||
|
|
||||||
Gobject.GCallback gtkCallback = new Gobject.GCallback() {
|
// have to watch out! These can get garbage collected!
|
||||||
|
menuEntry.gtkCallback = new Gobject.GCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void callback(Pointer instance, Pointer data) {
|
public void callback(Pointer instance, Pointer data) {
|
||||||
AppIndicatorTray.this.callbackExecutor.execute(new Runnable() {
|
AppIndicatorTray.this.callbackExecutor.execute(new Runnable() {
|
||||||
@ -228,9 +242,10 @@ public class AppIndicatorTray extends SystemTray {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
libgobject.g_signal_connect_data(menuEntry.dashboardItem, "activate", gtkCallback, null, null, 0);
|
libgobject.g_signal_connect_data(menuEntry.dashboardItem, "activate", menuEntry.gtkCallback, null, null, 0);
|
||||||
|
|
||||||
libgtk.gtk_widget_show_all(menuEntry.dashboardItem);
|
libgtk.gtk_widget_show_all(menuEntry.dashboardItem);
|
||||||
|
libgtk.gdk_threads_leave();
|
||||||
} else {
|
} else {
|
||||||
addMenuEntry(origMenuText, newCallback);
|
addMenuEntry(origMenuText, newCallback);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ package dorkbox.util.tray.linux;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -26,10 +25,10 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.SwingUtil;
|
||||||
import dorkbox.util.jna.linux.Gobject;
|
import dorkbox.util.jna.linux.Gobject;
|
||||||
import dorkbox.util.jna.linux.Gtk;
|
import dorkbox.util.jna.linux.Gtk;
|
||||||
import dorkbox.util.jna.linux.Gtk.GdkEventButton;
|
import dorkbox.util.jna.linux.Gtk.GdkEventButton;
|
||||||
@ -38,14 +37,13 @@ import dorkbox.util.tray.SystemTray;
|
|||||||
import dorkbox.util.tray.SystemTrayMenuAction;
|
import dorkbox.util.tray.SystemTrayMenuAction;
|
||||||
import dorkbox.util.tray.SystemTrayMenuPopup;
|
import dorkbox.util.tray.SystemTrayMenuPopup;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for handling all system tray interactions via GTK.
|
* Class for handling all system tray interactions via GTK.
|
||||||
*
|
*
|
||||||
* This is the "old" way to do it, and does not work with some desktop environments.
|
* 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 boolean useSWT = GtkSupport.usesSwtMainLoop;
|
||||||
private static final Gobject libgobject = Gobject.INSTANCE;
|
private static final Gobject libgobject = Gobject.INSTANCE;
|
||||||
private static final Gtk libgtk = Gtk.INSTANCE;
|
private static final Gtk libgtk = Gtk.INSTANCE;
|
||||||
|
|
||||||
@ -65,6 +63,7 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createTray(String iconName) {
|
public void createTray(String iconName) {
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
this.trayIcon = libgtk.gtk_status_icon_new();
|
this.trayIcon = libgtk.gtk_status_icon_new();
|
||||||
libgtk.gtk_status_icon_set_from_file(this.trayIcon, iconPath(iconName));
|
libgtk.gtk_status_icon_set_from_file(this.trayIcon, iconPath(iconName));
|
||||||
libgtk.gtk_status_icon_set_tooltip(this.trayIcon, this.appName);
|
libgtk.gtk_status_icon_set_tooltip(this.trayIcon, this.appName);
|
||||||
@ -75,7 +74,7 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
public void callback(Pointer instance, final GdkEventButton event) {
|
public void callback(Pointer instance, final GdkEventButton event) {
|
||||||
// BUTTON_PRESS only
|
// BUTTON_PRESS only
|
||||||
if (event.type == 4) {
|
if (event.type == 4) {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtil.invokeLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (GtkSystemTray.this.jmenu.isVisible()) {
|
if (GtkSystemTray.this.jmenu.isVisible()) {
|
||||||
@ -115,39 +114,27 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
};
|
};
|
||||||
// all the clicks. This is because native menu popups are a pain to figure out, so we cheat and use some java bits to do the popup
|
// all the clicks. This is because native menu popups are a pain to figure out, so we cheat and use some java bits to do the popup
|
||||||
libgobject.g_signal_connect_data(this.trayIcon, "button_press_event", gtkCallback, null, null, 0);
|
libgobject.g_signal_connect_data(this.trayIcon, "button_press_event", gtkCallback, null, null, 0);
|
||||||
|
libgtk.gdk_threads_leave();
|
||||||
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GtkSystemTray.this.jmenu = new SystemTrayMenuPopup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!GtkSupport.usesSwtMainLoop) {
|
if (!useSWT) {
|
||||||
Thread gtkUpdateThread = new Thread() {
|
Thread gtkUpdateThread = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// notify our main thread to continue
|
// notify our main thread to continue
|
||||||
GtkSystemTray.this.blockUntilStarted.countDown();
|
GtkSystemTray.this.blockUntilStarted.countDown();
|
||||||
|
libgtk.gtk_main();
|
||||||
try {
|
|
||||||
libgtk.gtk_main();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
logger.warn("Unable to run main loop", t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
gtkUpdateThread.setName("GTK event loop");
|
gtkUpdateThread.setName("GTK event loop");
|
||||||
gtkUpdateThread.setDaemon(true);
|
|
||||||
gtkUpdateThread.start();
|
gtkUpdateThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
GtkSystemTray.this.jmenu = new SystemTrayMenuPopup();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error creating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error creating tray menu", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we CANNOT continue until the GTK thread has started! (ignored if SWT is used)
|
// we CANNOT continue until the GTK thread has started! (ignored if SWT is used)
|
||||||
try {
|
try {
|
||||||
this.blockUntilStarted.await();
|
this.blockUntilStarted.await();
|
||||||
@ -158,6 +145,7 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeTray() {
|
public void removeTray() {
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
for (Pointer widget : this.widgets) {
|
for (Pointer widget : this.widgets) {
|
||||||
libgtk.gtk_widget_destroy(widget);
|
libgtk.gtk_widget_destroy(widget);
|
||||||
}
|
}
|
||||||
@ -182,12 +170,15 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
this.jmenu = null;
|
this.jmenu = null;
|
||||||
this.connectionStatusItem = null;
|
this.connectionStatusItem = null;
|
||||||
|
|
||||||
|
libgtk.gtk_main_quit();
|
||||||
|
libgtk.gdk_threads_leave();
|
||||||
|
|
||||||
super.removeTray();
|
super.removeTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStatus(final String infoString, String iconName) {
|
public void setStatus(final String infoString, String iconName) {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (GtkSystemTray.this.connectionStatusItem == null) {
|
if (GtkSystemTray.this.connectionStatusItem == null) {
|
||||||
@ -198,21 +189,11 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
GtkSystemTray.this.connectionStatusItem.setText(infoString);
|
GtkSystemTray.this.connectionStatusItem.setText(infoString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
libgtk.gdk_threads_enter();
|
||||||
libgtk.gtk_status_icon_set_from_file(GtkSystemTray.this.trayIcon, iconPath(iconName));
|
libgtk.gtk_status_icon_set_from_file(GtkSystemTray.this.trayIcon, iconPath(iconName));
|
||||||
|
libgtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,7 +201,7 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
public void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Map<String, JMenuItem> menuEntries2 = GtkSystemTray.this.menuEntries;
|
Map<String, JMenuItem> menuEntries2 = GtkSystemTray.this.menuEntries;
|
||||||
@ -251,19 +232,7 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,7 +240,7 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@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) {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Map<String, JMenuItem> menuEntries2 = GtkSystemTray.this.menuEntries;
|
Map<String, JMenuItem> menuEntries2 = GtkSystemTray.this.menuEntries;
|
||||||
@ -303,18 +272,6 @@ public class GtkSystemTray extends SystemTray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ package dorkbox.util.tray.linux;
|
|||||||
|
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.jna.linux.Gobject.GCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can only access this from within a synchronized block!
|
* Can only access this from within a synchronized block!
|
||||||
*/
|
*/
|
||||||
@ -24,6 +26,7 @@ class MenuEntry {
|
|||||||
|
|
||||||
private final int hashCode;
|
private final int hashCode;
|
||||||
public Pointer dashboardItem;
|
public Pointer dashboardItem;
|
||||||
|
public GCallback gtkCallback;
|
||||||
|
|
||||||
public MenuEntry() {
|
public MenuEntry() {
|
||||||
long time = System.nanoTime();
|
long time = System.nanoTime();
|
||||||
|
@ -17,9 +17,6 @@ package dorkbox.util.tray.swing;
|
|||||||
|
|
||||||
import java.awt.AWTException;
|
import java.awt.AWTException;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.GraphicsConfiguration;
|
|
||||||
import java.awt.GraphicsDevice;
|
|
||||||
import java.awt.GraphicsEnvironment;
|
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
@ -29,15 +26,13 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
|
import dorkbox.util.SwingUtil;
|
||||||
import dorkbox.util.tray.SystemTrayMenuAction;
|
import dorkbox.util.tray.SystemTrayMenuAction;
|
||||||
import dorkbox.util.tray.SystemTrayMenuPopup;
|
import dorkbox.util.tray.SystemTrayMenuPopup;
|
||||||
|
|
||||||
@ -62,32 +57,20 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeTray() {
|
public void removeTray() {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
SwingSystemTray.this.tray.remove(SwingSystemTray.this.trayIcon);
|
SwingSystemTray.this.tray.remove(SwingSystemTray.this.trayIcon);
|
||||||
SwingSystemTray.this.menuEntries.clear();
|
SwingSystemTray.this.menuEntries.clear();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.removeTray();
|
super.removeTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createTray(final String iconName) {
|
public void createTray(final String iconName) {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
SwingSystemTray.this.tray = SystemTray.getSystemTray();
|
SwingSystemTray.this.tray = SystemTray.getSystemTray();
|
||||||
@ -106,7 +89,7 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
Dimension size = SwingSystemTray.this.jmenu.getPreferredSize();
|
Dimension size = SwingSystemTray.this.jmenu.getPreferredSize();
|
||||||
|
|
||||||
Point point = e.getPoint();
|
Point point = e.getPoint();
|
||||||
Rectangle bounds = getScreenBoundsAt(point);
|
Rectangle bounds = SwingUtil.getScreenBoundsAt(point);
|
||||||
|
|
||||||
int x = point.x;
|
int x = point.x;
|
||||||
int y = point.y;
|
int y = point.y;
|
||||||
@ -150,19 +133,7 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error creating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error creating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image newImage(String name) {
|
Image newImage(String name) {
|
||||||
@ -171,68 +142,9 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
return new ImageIcon(iconPath).getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_SMOOTH);
|
return new ImageIcon(iconPath).getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_SMOOTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static Rectangle getSafeScreenBounds(Point pos) {
|
|
||||||
// Rectangle bounds = getScreenBoundsAt(pos);
|
|
||||||
// Insets insets = getScreenInsetsAt(pos);
|
|
||||||
//
|
|
||||||
// bounds.x += insets.left;
|
|
||||||
// bounds.y += insets.top;
|
|
||||||
// bounds.width -= insets.left + insets.right;
|
|
||||||
// bounds.height -= insets.top + insets.bottom;
|
|
||||||
//
|
|
||||||
// return bounds;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public static Insets getScreenInsetsAt(Point pos) {
|
|
||||||
// GraphicsDevice gd = getGraphicsDeviceAt(pos);
|
|
||||||
// Insets insets = null;
|
|
||||||
// if (gd != null) {
|
|
||||||
// insets = Toolkit.getDefaultToolkit().getScreenInsets(gd.getDefaultConfiguration());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return insets;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static Rectangle getScreenBoundsAt(Point pos) {
|
|
||||||
GraphicsDevice gd = getGraphicsDeviceAt(pos);
|
|
||||||
Rectangle bounds = null;
|
|
||||||
if (gd != null) {
|
|
||||||
bounds = gd.getDefaultConfiguration().getBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
return bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GraphicsDevice getGraphicsDeviceAt(Point pos) {
|
|
||||||
GraphicsDevice device;
|
|
||||||
|
|
||||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
|
||||||
GraphicsDevice lstGDs[] = ge.getScreenDevices();
|
|
||||||
|
|
||||||
ArrayList<GraphicsDevice> lstDevices = new ArrayList<GraphicsDevice>(lstGDs.length);
|
|
||||||
|
|
||||||
for (GraphicsDevice gd : lstGDs) {
|
|
||||||
|
|
||||||
GraphicsConfiguration gc = gd.getDefaultConfiguration();
|
|
||||||
Rectangle screenBounds = gc.getBounds();
|
|
||||||
|
|
||||||
if (screenBounds.contains(pos)) {
|
|
||||||
lstDevices.add(gd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lstDevices.size() > 0) {
|
|
||||||
device = lstDevices.get(0);
|
|
||||||
} else {
|
|
||||||
device = ge.getDefaultScreenDevice();
|
|
||||||
}
|
|
||||||
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStatus(final String infoString, final String iconName) {
|
public void setStatus(final String infoString, final String iconName) {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (SwingSystemTray.this.connectionStatusItem == null) {
|
if (SwingSystemTray.this.connectionStatusItem == null) {
|
||||||
@ -243,19 +155,7 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
SwingSystemTray.this.connectionStatusItem.setText(infoString);
|
SwingSystemTray.this.connectionStatusItem.setText(infoString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image trayImage = newImage(iconName);
|
Image trayImage = newImage(iconName);
|
||||||
SwingSystemTray.this.trayIcon.setImage(trayImage);
|
SwingSystemTray.this.trayIcon.setImage(trayImage);
|
||||||
@ -266,7 +166,7 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
public void addMenuEntry(final String menuText, final SystemTrayMenuAction callback) {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Map<String, JMenuItem> menuEntries2 = SwingSystemTray.this.menuEntries;
|
Map<String, JMenuItem> menuEntries2 = SwingSystemTray.this.menuEntries;
|
||||||
@ -297,19 +197,7 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -317,7 +205,7 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@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) {
|
||||||
Runnable doRun = new Runnable() {
|
SwingUtil.invokeAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Map<String, JMenuItem> menuEntries2 = SwingSystemTray.this.menuEntries;
|
Map<String, JMenuItem> menuEntries2 = SwingSystemTray.this.menuEntries;
|
||||||
@ -349,18 +237,6 @@ public class SwingSystemTray extends dorkbox.util.tray.SystemTray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
|
||||||
doRun.run();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SwingUtilities.invokeAndWait(doRun);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("Error updating tray menu", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user