forked from dorkbox/SystemTray
Changed synchronized -> volatile, changed how synchronized works for
menuEntries Changed setState -> setChecked for checkbox entry
This commit is contained in:
parent
d104c7e510
commit
b3b4300179
@ -26,12 +26,12 @@ import dorkbox.util.SwingUtil;
|
||||
@SuppressWarnings("unused")
|
||||
public
|
||||
class Checkbox extends Entry {
|
||||
private boolean isChecked = false;
|
||||
private String text;
|
||||
private ActionListener callback;
|
||||
private volatile boolean isChecked = false;
|
||||
private volatile String text;
|
||||
private volatile ActionListener callback;
|
||||
|
||||
private boolean enabled = true;
|
||||
private char mnemonicKey;
|
||||
private volatile boolean enabled = true;
|
||||
private volatile char mnemonicKey;
|
||||
|
||||
public
|
||||
Checkbox() {
|
||||
@ -54,7 +54,7 @@ class Checkbox extends Entry {
|
||||
* @param parent the parent of this menu, null if the parent is the system tray
|
||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void bind(final CheckboxPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||
super.bind(peer, parent, systemTray);
|
||||
|
||||
@ -68,7 +68,7 @@ class Checkbox extends Entry {
|
||||
/**
|
||||
* @return true if this checkbox is selected, false if not.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
boolean getChecked() {
|
||||
return isChecked;
|
||||
}
|
||||
@ -78,8 +78,8 @@ class Checkbox extends Entry {
|
||||
*
|
||||
* @param isChecked true to show the checkbox, false to hide it
|
||||
*/
|
||||
public synchronized
|
||||
void setState(boolean isChecked) {
|
||||
public
|
||||
void setChecked(boolean isChecked) {
|
||||
this.isChecked = isChecked;
|
||||
|
||||
if (peer != null) {
|
||||
@ -90,7 +90,7 @@ class Checkbox extends Entry {
|
||||
/**
|
||||
* Gets the callback assigned to this menu entry
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
ActionListener getCallback() {
|
||||
return callback;
|
||||
}
|
||||
@ -100,7 +100,7 @@ class Checkbox extends Entry {
|
||||
*
|
||||
* @param callback the callback to set. If null, the callback is safely removed.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setCallback(final ActionListener callback) {
|
||||
this.callback = callback;
|
||||
if (peer != null) {
|
||||
@ -111,7 +111,7 @@ class Checkbox extends Entry {
|
||||
/**
|
||||
* @return true if this item is enabled, or false if it is disabled.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
boolean getEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
@ -119,7 +119,7 @@ class Checkbox extends Entry {
|
||||
/**
|
||||
* Enables, or disables the entry.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setEnabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
|
||||
@ -131,7 +131,7 @@ class Checkbox extends Entry {
|
||||
/**
|
||||
* @return the text label that the menu entry has assigned
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
String getText() {
|
||||
return text;
|
||||
}
|
||||
@ -141,7 +141,7 @@ class Checkbox extends Entry {
|
||||
*
|
||||
* @param text the new text to set
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setText(final String text) {
|
||||
this.text = text;
|
||||
|
||||
@ -157,7 +157,7 @@ class Checkbox extends Entry {
|
||||
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
||||
* of it will be underlined.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
char getShortcut() {
|
||||
return this.mnemonicKey;
|
||||
}
|
||||
@ -170,7 +170,7 @@ class Checkbox extends Entry {
|
||||
*
|
||||
* @param key this is the key to set as the mnemonic
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setShortcut(final char key) {
|
||||
this.mnemonicKey = key;
|
||||
|
||||
@ -187,7 +187,7 @@ class Checkbox extends Entry {
|
||||
*
|
||||
* @param key this is the VK key to set as the mnemonic
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setShortcut(final int key) {
|
||||
this.mnemonicKey = SwingUtil.getFromVirtualKey(key);
|
||||
|
||||
|
@ -28,8 +28,8 @@ class Entry {
|
||||
private static final AtomicInteger MENU_ID_COUNTER = new AtomicInteger(0);
|
||||
private final int id = Entry.MENU_ID_COUNTER.getAndIncrement();
|
||||
|
||||
private Menu parent;
|
||||
private SystemTray systemTray;
|
||||
private volatile Menu parent;
|
||||
private volatile SystemTray systemTray;
|
||||
|
||||
protected volatile EntryPeer peer;
|
||||
|
||||
@ -45,7 +45,7 @@ class Entry {
|
||||
* @param parent the parent of this menu, null if the parent is the system tray
|
||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void bind(final EntryPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||
this.parent = parent;
|
||||
this.systemTray = systemTray;
|
||||
@ -59,7 +59,7 @@ class Entry {
|
||||
/**
|
||||
* @return the parent menu (of this entry or menu) or null if we are the root menu
|
||||
*/
|
||||
public final synchronized
|
||||
public final
|
||||
Menu getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
@ -67,7 +67,7 @@ class Entry {
|
||||
/**
|
||||
* @return the system tray that this menu is ultimately attached to
|
||||
*/
|
||||
public final synchronized
|
||||
public final
|
||||
SystemTray getSystemTray() {
|
||||
return this.systemTray;
|
||||
}
|
||||
@ -75,7 +75,7 @@ class Entry {
|
||||
/**
|
||||
* Removes this menu entry from the menu and releases all system resources associated with this menu entry
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void remove() {
|
||||
if (peer != null) {
|
||||
peer.remove();
|
||||
|
@ -41,6 +41,7 @@ import dorkbox.systemTray.peer.MenuPeer;
|
||||
@SuppressWarnings("unused")
|
||||
public
|
||||
class Menu extends MenuItem {
|
||||
// access on this object must be synchronized for object visibility
|
||||
final List<Entry> menuEntries = new ArrayList<Entry>();
|
||||
|
||||
public
|
||||
@ -112,12 +113,20 @@ class Menu extends MenuItem {
|
||||
* @param parent the parent of this menu, null if the parent is the system tray
|
||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void bind(final MenuPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||
super.bind(peer, parent, systemTray);
|
||||
|
||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||
final Entry menuEntry = menuEntries.get(i);
|
||||
List<Entry> copy;
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
// a copy is made to prevent deadlocks from occurring when operating in different threads
|
||||
copy = new ArrayList<Entry>(menuEntries);
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0, menuEntriesSize = copy.size(); i < menuEntriesSize; i++) {
|
||||
final Entry menuEntry = copy.get(i);
|
||||
peer.add(this, menuEntry, i);
|
||||
}
|
||||
}
|
||||
@ -204,7 +213,7 @@ class Menu extends MenuItem {
|
||||
}
|
||||
|
||||
checkbox.setEnabled(entry.isEnabled());
|
||||
checkbox.setState(entry.getState());
|
||||
checkbox.setChecked(entry.getState());
|
||||
checkbox.setShortcut(entry.getMnemonic());
|
||||
checkbox.setText(entry.getText());
|
||||
|
||||
@ -265,8 +274,10 @@ class Menu extends MenuItem {
|
||||
/**
|
||||
* Adds a menu entry, separator, or sub-menu to this menu.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
<T extends Entry> T add(final T entry, int index) {
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
if (index == -1) {
|
||||
menuEntries.add(entry);
|
||||
} else {
|
||||
@ -276,6 +287,7 @@ class Menu extends MenuItem {
|
||||
}
|
||||
menuEntries.add(index, entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (peer != null) {
|
||||
((MenuPeer) peer).add(this, entry, index);
|
||||
@ -295,9 +307,10 @@ class Menu extends MenuItem {
|
||||
/**
|
||||
* Gets the last menu entry or sub-menu, ignoring status and separators
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
Entry getLast() {
|
||||
// Must be wrapped in a synchronized block for object visibility
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
if (!menuEntries.isEmpty()) {
|
||||
Entry entry;
|
||||
for (int i = menuEntries.size() - 1; i >= 0; i--) {
|
||||
@ -308,6 +321,7 @@ class Menu extends MenuItem {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -317,13 +331,14 @@ class Menu extends MenuItem {
|
||||
*
|
||||
* @param menuIndex the menu entry index to use to retrieve the menu entry.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
Entry get(final int menuIndex) {
|
||||
if (menuIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Must be wrapped in a synchronized block for object visibility
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
if (!menuEntries.isEmpty()) {
|
||||
int count = 0;
|
||||
for (Entry entry : menuEntries) {
|
||||
@ -338,6 +353,7 @@ class Menu extends MenuItem {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -347,46 +363,77 @@ class Menu extends MenuItem {
|
||||
*
|
||||
* @param entry This is the menu entry to remove
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void remove(final Entry entry) {
|
||||
// null is passed in when a sub-menu is removing itself from us (because they have already called "remove" and have also
|
||||
// removed themselves from the menuEntries)
|
||||
if (entry != null) {
|
||||
Entry toRemove = null;
|
||||
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
for (Iterator<Entry> iterator = menuEntries.iterator(); iterator.hasNext(); ) {
|
||||
final Entry entry__ = iterator.next();
|
||||
if (entry__ == entry) {
|
||||
iterator.remove();
|
||||
entry.remove();
|
||||
toRemove = entry__;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toRemove != null) {
|
||||
toRemove.remove();
|
||||
toRemove = null;
|
||||
}
|
||||
|
||||
|
||||
// now check to see if a spacer is at the top/bottom of the list (and remove it if so. This is a recursive function.
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
if (!menuEntries.isEmpty()) {
|
||||
if (menuEntries.get(0) instanceof dorkbox.systemTray.Separator) {
|
||||
remove(menuEntries.get(0));
|
||||
toRemove = menuEntries.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toRemove != null) {
|
||||
remove(toRemove);
|
||||
toRemove = null;
|
||||
}
|
||||
|
||||
|
||||
// now check to see if a spacer is at the top/bottom of the list (and remove it if so. This is a recursive function.
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
if (!menuEntries.isEmpty()) {
|
||||
if (menuEntries.get(menuEntries.size()-1) instanceof dorkbox.systemTray.Separator) {
|
||||
remove(menuEntries.get(menuEntries.size() - 1));
|
||||
toRemove = menuEntries.get(menuEntries.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toRemove != null) {
|
||||
remove(toRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This removes all menu entries from this menu
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void clear() {
|
||||
List<Entry> copy;
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
// a copy is made to prevent deadlocks from occurring when operating in different threads
|
||||
// have to make copy because we are deleting all of them, and sub-menus remove themselves from parents
|
||||
ArrayList<Entry> menuEntriesCopy = new ArrayList<Entry>(this.menuEntries);
|
||||
for (Entry entry : menuEntriesCopy) {
|
||||
copy = new ArrayList<Entry>(menuEntries);
|
||||
menuEntries.clear();
|
||||
}
|
||||
|
||||
for (Entry entry : copy) {
|
||||
entry.remove();
|
||||
}
|
||||
menuEntries.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -394,7 +441,7 @@ class Menu extends MenuItem {
|
||||
* This removes all menu entries from this menu AND this menu from it's parent
|
||||
*/
|
||||
@Override
|
||||
public synchronized
|
||||
public
|
||||
void remove() {
|
||||
clear();
|
||||
|
||||
|
@ -33,13 +33,13 @@ import dorkbox.util.SwingUtil;
|
||||
@SuppressWarnings({"unused", "SameParameterValue", "WeakerAccess"})
|
||||
public
|
||||
class MenuItem extends Entry {
|
||||
private String text;
|
||||
private File imageFile;
|
||||
private ActionListener callback;
|
||||
private volatile String text;
|
||||
private volatile File imageFile;
|
||||
private volatile ActionListener callback;
|
||||
|
||||
// default enabled is always true
|
||||
private boolean enabled = true;
|
||||
private char mnemonicKey;
|
||||
private volatile boolean enabled = true;
|
||||
private volatile char mnemonicKey;
|
||||
|
||||
public
|
||||
MenuItem() {
|
||||
@ -124,7 +124,7 @@ class MenuItem extends Entry {
|
||||
* @param parent the parent of this menu, null if the parent is the system tray
|
||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void bind(final MenuItemPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||
super.bind(peer, parent, systemTray);
|
||||
|
||||
@ -135,7 +135,7 @@ class MenuItem extends Entry {
|
||||
peer.setShortcut(this);
|
||||
}
|
||||
|
||||
private synchronized
|
||||
private
|
||||
void setImage_(final File imageFile) {
|
||||
this.imageFile = imageFile;
|
||||
|
||||
@ -149,7 +149,7 @@ class MenuItem extends Entry {
|
||||
* <p>
|
||||
* This file can also be a cached file, depending on how the image was assigned to this entry.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
File getImage() {
|
||||
return imageFile;
|
||||
}
|
||||
@ -157,7 +157,7 @@ class MenuItem extends Entry {
|
||||
/**
|
||||
* Gets the callback assigned to this menu entry
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
ActionListener getCallback() {
|
||||
return callback;
|
||||
}
|
||||
@ -165,7 +165,7 @@ class MenuItem extends Entry {
|
||||
/**
|
||||
* @return true if this item is enabled, or false if it is disabled.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
boolean getEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
@ -173,7 +173,7 @@ class MenuItem extends Entry {
|
||||
/**
|
||||
* Enables, or disables the entry.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setEnabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
|
||||
@ -185,7 +185,7 @@ class MenuItem extends Entry {
|
||||
/**
|
||||
* @return the text label that the menu entry has assigned
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
String getText() {
|
||||
return text;
|
||||
}
|
||||
@ -195,7 +195,7 @@ class MenuItem extends Entry {
|
||||
*
|
||||
* @param text the new text to set
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setText(final String text) {
|
||||
this.text = text;
|
||||
|
||||
@ -280,7 +280,7 @@ class MenuItem extends Entry {
|
||||
/**
|
||||
* @return true if this menu entry has an image assigned to it, or is just text.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
boolean hasImage() {return imageFile != null;}
|
||||
|
||||
/**
|
||||
@ -288,7 +288,7 @@ class MenuItem extends Entry {
|
||||
*
|
||||
* @param callback the callback to set. If null, the callback is safely removed.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setCallback(final ActionListener callback) {
|
||||
this.callback = callback;
|
||||
|
||||
@ -304,7 +304,7 @@ class MenuItem extends Entry {
|
||||
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
||||
* of it will be underlined.
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
char getShortcut() {
|
||||
return this.mnemonicKey;
|
||||
}
|
||||
@ -317,7 +317,7 @@ class MenuItem extends Entry {
|
||||
*
|
||||
* @param key this is the key to set as the mnemonic
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setShortcut(final char key) {
|
||||
this.mnemonicKey = key;
|
||||
|
||||
@ -334,7 +334,7 @@ class MenuItem extends Entry {
|
||||
*
|
||||
* @param key this is the VK key to set as the mnemonic
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setShortcut(final int key) {
|
||||
this.mnemonicKey = SwingUtil.getFromVirtualKey(key);
|
||||
|
||||
@ -344,7 +344,7 @@ class MenuItem extends Entry {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized
|
||||
public
|
||||
void remove() {
|
||||
if (peer != null) {
|
||||
setImage_(null);
|
||||
|
@ -33,7 +33,7 @@ class Status extends Entry {
|
||||
* @param parent the parent of this menu, null if the parent is the system tray
|
||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void bind(final StatusPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||
super.bind(peer, parent, systemTray);
|
||||
|
||||
@ -43,7 +43,7 @@ class Status extends Entry {
|
||||
/**
|
||||
* @return the text label that the menu entry has assigned
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
String getText() {
|
||||
return text;
|
||||
}
|
||||
@ -53,7 +53,7 @@ class Status extends Entry {
|
||||
*
|
||||
* @param text the new text to set
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setText(final String text) {
|
||||
this.text = text;
|
||||
|
||||
|
@ -20,7 +20,6 @@ class Tray extends Menu {
|
||||
|
||||
// appindicators DO NOT support anything other than PLAIN gtk-menus (which we hack to support swing menus)
|
||||
// they ALSO do not support tooltips, so we cater to the lowest common denominator
|
||||
// trayIcon.setToolTip("app name");
|
||||
|
||||
private volatile String statusText;
|
||||
|
||||
@ -32,7 +31,7 @@ class Tray extends Menu {
|
||||
/**
|
||||
* Gets the 'status' string assigned to the system tray
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
String getStatus() {
|
||||
return statusText;
|
||||
}
|
||||
@ -42,15 +41,19 @@ class Tray extends Menu {
|
||||
*
|
||||
* @param statusText the text you want displayed, null if you want to remove the 'status' string
|
||||
*/
|
||||
public synchronized
|
||||
public
|
||||
void setStatus(final String statusText) {
|
||||
this.statusText = statusText;
|
||||
|
||||
// status is ALWAYS at 0 index...
|
||||
Entry menuEntry = null;
|
||||
|
||||
synchronized (menuEntries) {
|
||||
// access on this object must be synchronized for object visibility
|
||||
if (!menuEntries.isEmpty()) {
|
||||
menuEntry = menuEntries.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (menuEntry instanceof Status) {
|
||||
// set the text or delete...
|
||||
|
@ -91,7 +91,7 @@ class SwingMenuItemCheckbox implements CheckboxPeer {
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
// this will run on the EDT, since we are calling it from the EDT
|
||||
menuItem.setState(!isChecked);
|
||||
menuItem.setChecked(!isChecked);
|
||||
|
||||
// we want it to run on the EDT, but with our own action event info (so it is consistent across all platforms)
|
||||
ActionListener cb = menuItem.getCallback();
|
||||
|
Loading…
Reference in New Issue
Block a user