Changed action callback to ActionListener. Added checkbox.

This commit is contained in:
nathan 2016-10-17 11:47:25 +02:00
parent 4e47c5d263
commit a07c5e8ab8
28 changed files with 813 additions and 325 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2014 dorkbox, llc
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.systemTray;
/**
* This represents a common menu-checkbox entry, that is cross platform in nature
*/
public
interface Action {
interface Checkbox extends Entry {
/**
* This method will ALWAYS be called in the swing EDT. If there is work conducted in this method, it will slow-down the GUI.
*
* @param systemTray this is the parent, system tray object
* @param parent this is the parent menu of this menu entry
* @param entry this is the menu entry that was clicked
* @return true if this checkbox is selected, false if not
*/
void onClick(SystemTray systemTray, Menu parent, final Entry entry);
boolean getState();
}

View File

@ -16,6 +16,7 @@
package dorkbox.systemTray;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
@ -97,7 +98,7 @@ interface Entry {
*
* @param callback the callback to set. If null, the callback is safely removed.
*/
void setCallback(Action callback);
void setCallback(ActionListener callback);
/**
* Sets a menu entry shortcut key (Mnemonic) so that menu entry can be "selected" via the keyboard while the menu is displayed.

View File

@ -15,6 +15,7 @@
*/
package dorkbox.systemTray;
import java.awt.event.ActionListener;
import java.io.InputStream;
import java.net.URL;
@ -86,7 +87,7 @@ interface Menu extends Entry {
* @param menuText string of the text you want to appear
* @param callback callback that will be executed when this menu entry is clicked
*/
Entry addEntry(String menuText, Action callback);
Entry addEntry(String menuText, ActionListener callback);
/**
* Adds a menu entry with text + image
@ -95,7 +96,7 @@ interface Menu extends Entry {
* @param imagePath the image (full path required) to use. If null, no image will be used
* @param callback callback that will be executed when this menu entry is clicked
*/
Entry addEntry(String menuText, String imagePath, Action callback);
Entry addEntry(String menuText, String imagePath, ActionListener callback);
/**
* Adds a menu entry with text + image
@ -104,7 +105,7 @@ interface Menu extends Entry {
* @param imageUrl the URL of the image to use. If null, no image will be used
* @param callback callback that will be executed when this menu entry is clicked
*/
Entry addEntry(String menuText, URL imageUrl, Action callback);
Entry addEntry(String menuText, URL imageUrl, ActionListener callback);
/**
* Adds a menu entry with text + image
@ -114,7 +115,7 @@ interface Menu extends Entry {
* @param imageStream the InputStream of the image to use. If null, no image will be used
* @param callback callback that will be executed when this menu entry is clicked
*/
Entry addEntry(String menuText, String cacheName, InputStream imageStream, Action callback);
Entry addEntry(String menuText, String cacheName, InputStream imageStream, ActionListener callback);
/**
* Adds a menu entry with text + image
@ -123,10 +124,19 @@ interface Menu extends Entry {
* @param imageStream the InputStream of the image to use. If null, no image will be used
* @param callback callback that will be executed when this menu entry is clicked
*/
Entry addEntry(String menuText, InputStream imageStream, Action callback);
Entry addEntry(String menuText, InputStream imageStream, ActionListener callback);
/**
* Adds a check-box menu entry with text
*
* @param menuText string of the text you want to appear
* @param callback callback that will be executed when this menu entry is clicked
*/
Checkbox addCheckbox(String menuText, ActionListener callback);
/**
* Adds a sub-menu entry with text (no image)

View File

@ -17,6 +17,7 @@ package dorkbox.systemTray;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -924,7 +925,7 @@ class SystemTray implements Menu {
*/
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
// NO OP.
}
@ -992,7 +993,7 @@ class SystemTray implements Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
Entry addEntry(String menuText, Action callback) {
Entry addEntry(String menuText, ActionListener callback) {
return addEntry(menuText, (String) null, callback);
}
@ -1004,7 +1005,7 @@ class SystemTray implements Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
Entry addEntry(String menuText, String imagePath, Action callback) {
Entry addEntry(String menuText, String imagePath, ActionListener callback) {
return systemTrayMenu.addEntry(menuText, imagePath, callback);
}
@ -1016,7 +1017,7 @@ class SystemTray implements Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
Entry addEntry(String menuText, URL imageUrl, Action callback) {
Entry addEntry(String menuText, URL imageUrl, ActionListener callback) {
return systemTrayMenu.addEntry(menuText, imageUrl, callback);
}
@ -1029,7 +1030,7 @@ class SystemTray implements Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public
Entry addEntry(String menuText, String cacheName, InputStream imageStream, Action callback) {
Entry addEntry(String menuText, String cacheName, InputStream imageStream, ActionListener callback) {
return systemTrayMenu.addEntry(menuText, cacheName, imageStream, callback);
}
@ -1041,11 +1042,22 @@ class SystemTray implements Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
Entry addEntry(String menuText, InputStream imageStream, Action callback) {
Entry addEntry(String menuText, InputStream imageStream, ActionListener callback) {
return systemTrayMenu.addEntry(menuText, imageStream, callback);
}
/**
* Adds a check-box menu entry to the tray icon with text
*
* @param menuText string of the text you want to appear
* @param callback callback that will be executed when this menu entry is clicked
*/
@Override
public
Checkbox addCheckbox(final String menuText, final ActionListener callback) {
return systemTrayMenu.addCheckbox(menuText, callback);
}

View File

@ -32,7 +32,6 @@ class Gdi32 {
}
public static final int LOGPIXELSX = 88;
public static final int LOGPIXELSY = 90;
/**

View File

@ -17,6 +17,8 @@ package dorkbox.systemTray.jna.linux;
import static dorkbox.systemTray.SystemTray.logger;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -24,9 +26,7 @@ import java.util.concurrent.TimeUnit;
import com.sun.jna.Function;
import com.sun.jna.Pointer;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.SystemTray;
import dorkbox.systemTray.jna.JnaHelper;
import dorkbox.systemTray.util.JavaFX;
@ -422,11 +422,11 @@ class Gtk {
* @param callback will never be null.
*/
public static
void proxyClick(final Menu parent, final Entry menuEntry, final Action callback) {
void proxyClick(final Entry menuEntry, final ActionListener callback) {
Gtk.isDispatch = true;
try {
callback.onClick(parent.getSystemTray(), parent, menuEntry);
callback.actionPerformed(new ActionEvent(menuEntry, ActionEvent.ACTION_PERFORMED, ""));
} catch (Throwable throwable) {
SystemTray.logger.error("Error calling menu entry {} click event.", menuEntry.getText(), throwable);
}
@ -470,6 +470,9 @@ class Gtk {
// uses '_' to define which key is the mnemonic
public static native Pointer gtk_image_menu_item_new_with_mnemonic(String label);
public static native Pointer gtk_check_menu_item_new_with_mnemonic (String label);
public static native boolean gtk_check_menu_item_get_active (Pointer check_menu_item);
public static native void gtk_image_menu_item_set_image(Pointer image_menu_item, Pointer image);

View File

@ -0,0 +1,104 @@
/*
* Copyright 2014 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.systemTray.nativeUI;
import java.awt.CheckboxMenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.SystemTray;
class AwtEntryCheckbox extends AwtEntry implements Checkbox {
private final ActionListener swingCallback;
private volatile ActionListener callback;
// this is ALWAYS called on the EDT.
AwtEntryCheckbox(final AwtMenu parent, final ActionListener callback) {
super(parent, new java.awt.CheckboxMenuItem());
this.callback = callback;
if (callback != null) {
_native.setEnabled(true);
swingCallback = new ActionListener() {
@Override
public
void actionPerformed(ActionEvent e) {
// we want it to run on the EDT
handle();
}
};
_native.addActionListener(swingCallback);
} else {
_native.setEnabled(false);
swingCallback = null;
}
}
/**
* @return true if this checkbox is selected, false if not
*/
public
boolean getState() {
return ((CheckboxMenuItem) _native).getState();
}
@Override
public
void setCallback(final ActionListener callback) {
this.callback = callback;
}
private
void handle() {
ActionListener cb = this.callback;
if (cb != null) {
try {
cb.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ""));
} catch (Throwable throwable) {
SystemTray.logger.error("Error calling menu entry {} click event.", getText(), throwable);
}
}
}
// always called in the EDT
@Override
void renderText(final String text) {
_native.setLabel(text);
}
// not supported!
@Override
public
boolean hasImage() {
return false;
}
// not supported!
@Override
void setImage_(final File imageFile) {
}
@Override
void removePrivate() {
_native.removeActionListener(swingCallback);
}
}

View File

@ -19,16 +19,16 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.SystemTray;
class AwtEntryItem extends AwtEntry {
private final ActionListener swingCallback;
private volatile Action callback;
private volatile ActionListener callback;
// this is ALWAYS called on the EDT.
AwtEntryItem(final AwtMenu parent, final Action callback) {
AwtEntryItem(final AwtMenu parent, final ActionListener callback) {
super(parent, new java.awt.MenuItem());
this.callback = callback;
@ -53,14 +53,19 @@ class AwtEntryItem extends AwtEntry {
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
this.callback = callback;
}
private
void handle() {
if (callback != null) {
callback.onClick(getParent().getSystemTray(), getParent(), this);
ActionListener cb = this.callback;
if (cb != null) {
try {
cb.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ""));
} catch (Throwable throwable) {
SystemTray.logger.error("Error calling menu entry {} click event.", getText(), throwable);
}
}
}

View File

@ -16,10 +16,9 @@
package dorkbox.systemTray.nativeUI;
import java.awt.MenuItem;
import java.awt.event.ActionListener;
import java.io.File;
import dorkbox.systemTray.Action;
class AwtEntrySeparator extends AwtEntry implements dorkbox.systemTray.Separator {
// this is ALWAYS called on the EDT.
@ -53,6 +52,6 @@ class AwtEntrySeparator extends AwtEntry implements dorkbox.systemTray.Separator
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
}

View File

@ -19,9 +19,9 @@ import static java.awt.Font.DIALOG;
import java.awt.Font;
import java.awt.MenuItem;
import java.awt.event.ActionListener;
import java.io.File;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Status;
class AwtEntryStatus extends AwtEntry implements Status {
@ -70,6 +70,6 @@ class AwtEntryStatus extends AwtEntry implements Status {
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
}

View File

@ -18,10 +18,11 @@ package dorkbox.systemTray.nativeUI;
import java.awt.MenuShortcut;
import java.awt.PopupMenu;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.concurrent.atomic.AtomicReference;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.Status;
@ -97,36 +98,28 @@ class AwtMenu extends MenuBase implements NativeUI {
}
/**
* Will add a new menu entry, or update one if it already exists
* Will add a new menu entry
* NOT ALWAYS CALLED ON EDT
*/
protected final
Entry addEntry_(final String menuText, final File imagePath, final Action callback) {
Entry addEntry_(final String menuText, final File imagePath, final ActionListener callback) {
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
final AtomicReference<Entry> value = new AtomicReference<Entry>();
// must always be called on the EDT
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry entry = get(menuText);
if (entry == null) {
// must always be called on the EDT
entry = new AwtEntryItem(AwtMenu.this, callback);
entry.setText(menuText);
entry.setImage(imagePath);
menuEntries.add(entry);
} else if (entry instanceof AwtEntryItem) {
entry.setText(menuText);
entry.setImage(imagePath);
}
Entry entry = entry = new AwtEntryItem(AwtMenu.this, callback);
entry.setText(menuText);
entry.setImage(imagePath);
menuEntries.add(entry);
value.set(entry);
}
}
@ -136,7 +129,39 @@ class AwtMenu extends MenuBase implements NativeUI {
}
/**
* Will add a new sub-menu entry, or update one if it already exists
* Will add a new checkbox menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
@Override
protected
Checkbox addCheckbox_(final String menuText, final ActionListener callback) {
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
final AtomicReference<Checkbox> value = new AtomicReference<Checkbox>();
// must always be called on the EDT
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry entry = new AwtEntryCheckbox(AwtMenu.this, callback);
entry.setText(menuText);
menuEntries.add(entry);
value.set((Checkbox) entry);
}
}
});
return value.get();
}
/**
* Will add a new sub-menu entry
* NOT ALWAYS CALLED ON EDT
*/
protected final
@ -147,28 +172,20 @@ class AwtMenu extends MenuBase implements NativeUI {
final AtomicReference<Menu> value = new AtomicReference<Menu>();
// must always be called on the EDT
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry entry = get(menuText);
Entry entry = new AwtMenu(getSystemTray(), AwtMenu.this, new java.awt.Menu());
_native.add(((AwtMenu) entry)._native); // have to add it to our native item separately
if (entry == null) {
// must always be called on the EDT
entry = new AwtMenu(getSystemTray(), AwtMenu.this, new java.awt.Menu());
_native.add(((AwtMenu) entry)._native); // have to add it separately
entry.setText(menuText);
entry.setImage(imagePath);
value.set((Menu) entry);
} else if (entry instanceof AwtMenu) {
entry.setText(menuText);
entry.setImage(imagePath);
}
entry.setText(menuText);
entry.setImage(imagePath);
menuEntries.add(entry);
value.set((Menu) entry);
}
}
});

View File

@ -0,0 +1,172 @@
/*
* Copyright 2014 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.systemTray.nativeUI;
import java.awt.event.ActionListener;
import java.io.File;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.jna.linux.GCallback;
import dorkbox.systemTray.jna.linux.Gobject;
import dorkbox.systemTray.jna.linux.Gtk;
import dorkbox.systemTray.util.ImageUtils;
class GtkEntryCheckbox extends GtkEntry implements GCallback, Checkbox {
private static File transparentIcon = null;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private final NativeLong nativeLong;
// these have to be volatile, because they can be changed from any thread
private volatile ActionListener callback;
private volatile Pointer image;
// The mnemonic will ONLY show-up once a menu entry is selected. IT WILL NOT show up before then!
// AppIndicators will only show if you use the keyboard to navigate
// GtkStatusIconTray will show on mouse+keyboard movement
private volatile char mnemonicKey = 0;
/**
* called from inside dispatch thread. ONLY creates the menu item, but DOES NOT attach it!
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
*/
GtkEntryCheckbox(final GtkMenu parent, final ActionListener callback) {
super(parent, Gtk.gtk_check_menu_item_new_with_mnemonic(""));
this.callback = callback;
// cannot be done in a static initializer, because the tray icon size might not yet have been determined
if (transparentIcon == null) {
transparentIcon = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE);
}
if (callback != null) {
Gtk.gtk_widget_set_sensitive(_native, Gtk.TRUE);
nativeLong = Gobject.g_signal_connect_object(_native, "activate", this, null, 0);
}
else {
Gtk.gtk_widget_set_sensitive(_native, Gtk.FALSE);
nativeLong = null;
}
}
@Override
public
void setShortcut(final char key) {
this.mnemonicKey = Character.toLowerCase(key);
Gtk.dispatch(new Runnable() {
@Override
public
void run() {
renderText(getText());
}
});
}
/**
* @return true if this checkbox is selected, false if not
*/
public
boolean getState() {
return Gtk.gtk_check_menu_item_get_active(_native);
}
@Override
public
void setCallback(final ActionListener callback) {
this.callback = callback;
}
// called by native code
@Override
public
int callback(final Pointer instance, final Pointer data) {
final ActionListener cb = this.callback;
if (cb != null) {
Gtk.proxyClick(GtkEntryCheckbox.this, cb);
}
return Gtk.TRUE;
}
@Override
public
boolean hasImage() {
return true;
}
/**
* the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images.
* This is primarily only with AppIndicators, although not always.
* <p>
* called on the DISPATCH thread
*/
void setSpacerImage(final boolean everyoneElseHasImages) {
// if (true) {
// // we have a legit icon, so there is nothing else we can do.
// return;
// }
//
// if (image != null) {
// Gtk.gtk_widget_destroy(image);
// image = null;
// Gtk.gtk_widget_show_all(_native);
// }
//
// if (everyoneElseHasImages) {
// image = Gtk.gtk_image_new_from_file(transparentIcon.getAbsolutePath());
// Gtk.gtk_image_menu_item_set_image(_native, image);
//
// // must always re-set always-show after setting the image
// Gtk.gtk_image_menu_item_set_always_show_image(_native, Gtk.TRUE);
// }
//
// Gtk.gtk_widget_show_all(_native);
}
/**
* must always be called in the GTK thread
*/
void renderText(String text) {
if (this.mnemonicKey != 0) {
// they are CASE INSENSITIVE!
int i = text.toLowerCase()
.indexOf(this.mnemonicKey);
if (i >= 0) {
text = text.substring(0, i) + "_" + text.substring(i);
}
}
Gtk.gtk_menu_item_set_label(_native, text);
Gtk.gtk_widget_show_all(_native);
}
void setImage_(final File imageFile) {
}
void removePrivate() {
callback = null;
if (image != null) {
Gtk.gtk_widget_destroy(image);
image = null;
}
}
}

View File

@ -15,12 +15,12 @@
*/
package dorkbox.systemTray.nativeUI;
import java.awt.event.ActionListener;
import java.io.File;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.jna.linux.GCallback;
import dorkbox.systemTray.jna.linux.Gobject;
import dorkbox.systemTray.jna.linux.Gtk;
@ -33,7 +33,7 @@ class GtkEntryItem extends GtkEntry implements GCallback {
private final NativeLong nativeLong;
// these have to be volatile, because they can be changed from any thread
private volatile Action callback;
private volatile ActionListener callback;
private volatile Pointer image;
// these are necessary BECAUSE GTK menus look funky as hell when there are some menu entries WITH icons and some WITHOUT
@ -48,7 +48,7 @@ class GtkEntryItem extends GtkEntry implements GCallback {
* called from inside dispatch thread. ONLY creates the menu item, but DOES NOT attach it!
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
*/
GtkEntryItem(final GtkMenu parent, final Action callback) {
GtkEntryItem(final GtkMenu parent, final ActionListener callback) {
super(parent, Gtk.gtk_image_menu_item_new_with_mnemonic(""));
this.callback = callback;
@ -83,7 +83,7 @@ class GtkEntryItem extends GtkEntry implements GCallback {
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
this.callback = callback;
}
@ -91,9 +91,9 @@ class GtkEntryItem extends GtkEntry implements GCallback {
@Override
public
int callback(final Pointer instance, final Pointer data) {
final Action cb = this.callback;
final ActionListener cb = this.callback;
if (cb != null) {
Gtk.proxyClick(getParent(), GtkEntryItem.this, cb);
Gtk.proxyClick(GtkEntryItem.this, cb);
}
return Gtk.TRUE;

View File

@ -15,9 +15,9 @@
*/
package dorkbox.systemTray.nativeUI;
import java.awt.event.ActionListener;
import java.io.File;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Separator;
import dorkbox.systemTray.jna.linux.Gtk;
@ -56,7 +56,7 @@ class GtkEntrySeparator extends GtkEntry implements Separator {
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
@Override

View File

@ -15,7 +15,8 @@
*/
package dorkbox.systemTray.nativeUI;
import dorkbox.systemTray.Action;
import java.awt.event.ActionListener;
import dorkbox.systemTray.jna.linux.Gtk;
// you might wonder WHY this extends MenuEntryItem -- the reason is that an AppIndicator "status" will be offset from everyone else,
@ -47,7 +48,7 @@ class GtkEntryStatus extends GtkEntryItem {
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
@Override

View File

@ -16,6 +16,7 @@
package dorkbox.systemTray.nativeUI;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
@ -23,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
import com.sun.jna.Pointer;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.SystemTray;
@ -62,6 +63,127 @@ class GtkMenu extends MenuBase implements NativeUI {
// only needed for AppIndicator
}
/**
* Will add a new menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
protected
Entry addEntry_(final String menuText, final File imagePath, final ActionListener callback) {
// some implementations of appindicator, do NOT like having a menu added, which has no menu items yet.
// see: https://bugs.launchpad.net/glipper/+bug/1203888
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
// have to wait for the value
final AtomicReference<Entry> value = new AtomicReference<Entry>();
// must always be called on DISPATCH
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
// 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.
deleteMenu();
Entry menuEntry = new GtkEntryItem(GtkMenu.this, callback);
menuEntry.setText(menuText);
menuEntry.setImage(imagePath);
menuEntries.add(menuEntry);
value.set(menuEntry);
createMenu();
}
}
});
return value.get();
}
/**
* Will add a new checkbox menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
@Override
protected
Checkbox addCheckbox_(final String menuText, final ActionListener callback) {
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
final AtomicReference<Checkbox> value = new AtomicReference<Checkbox>();
// must always be called on DISPATCH
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
// 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.
deleteMenu();
Entry entry = new GtkEntryCheckbox(GtkMenu.this, callback);
entry.setText(menuText);
menuEntries.add(entry);
value.set((Checkbox) entry);
createMenu();
}
}
});
return value.get();
}
/**
* Will add a new menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
protected
Menu addMenu_(final String menuText, final File imagePath) {
// some implementations of appindicator, do NOT like having a menu added, which has no menu items yet.
// see: https://bugs.launchpad.net/glipper/+bug/1203888
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
final AtomicReference<Menu> value = new AtomicReference<Menu>();
// must always be called on DISPATCH
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
// 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.
deleteMenu();
GtkMenu subMenu = new GtkMenu(getSystemTray(), GtkMenu.this);
subMenu.setText(menuText);
subMenu.setImage(imagePath);
menuEntries.add(subMenu);
value.set(subMenu);
createMenu();
}
}
});
return value.get();
}
/**
* Necessary to guarantee all updates occur on the dispatch thread
*/
@ -136,10 +258,6 @@ class GtkMenu extends MenuBase implements NativeUI {
});
}
// public here so that Swing/Gtk/AppIndicator can override this
@Override
public
@ -336,98 +454,6 @@ class GtkMenu extends MenuBase implements NativeUI {
}
/**
* Will add a new menu entry, or update one if it already exists
*/
protected
Entry addEntry_(final String menuText, final File imagePath, final Action callback) {
// some implementations of appindicator, do NOT like having a menu added, which has no menu items yet.
// see: https://bugs.launchpad.net/glipper/+bug/1203888
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
// have to wait for the value
final AtomicReference<Entry> value = new AtomicReference<Entry>();
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry menuEntry = get(menuText);
if (menuEntry == null) {
// 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.
deleteMenu();
menuEntry = new GtkEntryItem(GtkMenu.this, callback);
menuEntry.setText(menuText);
menuEntry.setImage(imagePath);
menuEntries.add(menuEntry);
createMenu();
} else if (menuEntry instanceof GtkEntryItem) {
menuEntry.setText(menuText);
menuEntry.setImage(imagePath);
}
value.set(menuEntry);
}
}
});
return value.get();
}
/**
* Will add a new menu entry, or update one if it already exists
*/
protected
Menu addMenu_(final String menuText, final File imagePath) {
// some implementations of appindicator, do NOT like having a menu added, which has no menu items yet.
// see: https://bugs.launchpad.net/glipper/+bug/1203888
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
final AtomicReference<Menu> value = new AtomicReference<Menu>();
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry menuEntry = get(menuText);
if (menuEntry == null) {
// 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.
deleteMenu();
GtkMenu subMenu = new GtkMenu(getSystemTray(), GtkMenu.this);
subMenu.setText(menuText);
subMenu.setImage(imagePath);
menuEntries.add(subMenu);
value.set(subMenu);
createMenu();
} else if (menuEntry instanceof GtkMenu) {
menuEntry.setText(menuText);
menuEntry.setImage(imagePath);
value.set(((GtkMenu) menuEntry));
}
}
}
});
return value.get();
}
// a child will always remove itself from the parent.
@Override
public

View File

@ -0,0 +1,128 @@
/*
* Copyright 2014 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.systemTray.swingUI;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.SystemTray;
import dorkbox.systemTray.util.ImageUtils;
class SwingEntryCheckbox extends SwingEntry implements Checkbox {
private final ActionListener swingCallback;
private volatile ActionListener callback;
private static ImageIcon checkedIcon;
private static ImageIcon uncheckedIcon;
private volatile boolean isChecked = false;
// this is ALWAYS called on the EDT.
SwingEntryCheckbox(final SwingMenu parent, final ActionListener callback) {
super(parent, new AdjustedJMenuItem());
this.callback = callback;
if (checkedIcon == null) {
// from Brankic1979, public domain
File checkedFile = ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, ImageUtils.class.getResource("checked_32.png"));
checkedIcon = new ImageIcon(checkedFile.getAbsolutePath());
File uncheckedFile = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE);
uncheckedIcon = new ImageIcon(uncheckedFile.getAbsolutePath());
}
((JMenuItem) _native).setIcon(uncheckedIcon);
if (callback != null) {
_native.setEnabled(true);
swingCallback = new ActionListener() {
@Override
public
void actionPerformed(ActionEvent e) {
// we want it to run on the EDT
if (isChecked) {
((JMenuItem) _native).setIcon(uncheckedIcon);
} else {
((JMenuItem) _native).setIcon(checkedIcon);
}
isChecked = !isChecked;
handle();
}
};
((JMenuItem) _native).addActionListener(swingCallback);
} else {
_native.setEnabled(false);
swingCallback = null;
}
}
/**
* @return true if this checkbox is selected, false if not
*/
public
boolean getState() {
return isChecked;
}
@Override
public
void setCallback(final ActionListener callback) {
this.callback = callback;
}
private
void handle() {
ActionListener cb = this.callback;
if (cb != null) {
try {
cb.actionPerformed(new ActionEvent((Checkbox)this, ActionEvent.ACTION_PERFORMED, ""));
} catch (Throwable throwable) {
SystemTray.logger.error("Error calling menu entry {} click event.", getText(), throwable);
}
}
}
// checkbox image is always present
@Override
public
boolean hasImage() {
return true;
}
@Override
void removePrivate() {
((JMenuItem) _native).removeActionListener(swingCallback);
}
// always called in the EDT
@Override
void renderText(final String text) {
((JMenuItem) _native).setText(text);
}
@Override
void setImage_(final File imageFile) {
}
}

View File

@ -22,7 +22,7 @@ import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.SystemTray;
import dorkbox.util.SwingUtil;
class SwingEntryItem extends SwingEntry {
@ -30,10 +30,10 @@ class SwingEntryItem extends SwingEntry {
private final ActionListener swingCallback;
private volatile boolean hasLegitIcon = false;
private volatile Action callback;
private volatile ActionListener callback;
// this is ALWAYS called on the EDT.
SwingEntryItem(final SwingMenu parent, final Action callback) {
SwingEntryItem(final SwingMenu parent, final ActionListener callback) {
super(parent, new AdjustedJMenuItem());
this.callback = callback;
@ -58,14 +58,19 @@ class SwingEntryItem extends SwingEntry {
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
this.callback = callback;
}
private
void handle() {
if (callback != null) {
callback.onClick(getParent().getSystemTray(), getParent(), this);
ActionListener cb = this.callback;
if (cb != null) {
try {
cb.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ""));
} catch (Throwable throwable) {
SystemTray.logger.error("Error calling menu entry {} click event.", getText(), throwable);
}
}
}

View File

@ -15,12 +15,11 @@
*/
package dorkbox.systemTray.swingUI;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JSeparator;
import dorkbox.systemTray.Action;
class SwingEntrySeparator extends SwingEntry implements dorkbox.systemTray.Separator {
// this is ALWAYS called on the EDT.
@ -54,6 +53,6 @@ class SwingEntrySeparator extends SwingEntry implements dorkbox.systemTray.Separ
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
}

View File

@ -16,11 +16,11 @@
package dorkbox.systemTray.swingUI;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JMenuItem;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Status;
class SwingEntryStatus extends SwingEntry implements Status {
@ -65,7 +65,7 @@ class SwingEntryStatus extends SwingEntry implements Status {
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
}

View File

@ -15,12 +15,11 @@
*/
package dorkbox.systemTray.swingUI;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JComponent;
import dorkbox.systemTray.Action;
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
class SwingEntryWidget extends SwingEntry implements dorkbox.systemTray.Separator {
@ -57,6 +56,6 @@ class SwingEntryWidget extends SwingEntry implements dorkbox.systemTray.Separato
@Override
public
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
}

View File

@ -16,6 +16,7 @@
package dorkbox.systemTray.swingUI;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.concurrent.atomic.AtomicReference;
@ -23,7 +24,7 @@ import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.Status;
@ -100,36 +101,28 @@ class SwingMenu extends MenuBase implements SwingUI {
}
/**
* Will add a new menu entry, or update one if it already exists
* Will add a new menu entry
* NOT ALWAYS CALLED ON EDT
*/
protected final
Entry addEntry_(final String menuText, final File imagePath, final Action callback) {
Entry addEntry_(final String menuText, final File imagePath, final ActionListener callback) {
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
final AtomicReference<Entry> value = new AtomicReference<Entry>();
// must always be called on the EDT
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry entry = get(menuText);
if (entry == null) {
// must always be called on the EDT
entry = new SwingEntryItem(SwingMenu.this, callback);
entry.setText(menuText);
entry.setImage(imagePath);
menuEntries.add(entry);
} else if (entry instanceof SwingEntryItem) {
entry.setText(menuText);
entry.setImage(imagePath);
}
Entry entry = new SwingEntryItem(SwingMenu.this, callback);
entry.setText(menuText);
entry.setImage(imagePath);
menuEntries.add(entry);
value.set(entry);
}
}
@ -139,7 +132,38 @@ class SwingMenu extends MenuBase implements SwingUI {
}
/**
* Will add a new sub-menu entry, or update one if it already exists
* Will add a new checkbox menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
@Override
protected
Checkbox addCheckbox_(final String menuText, final ActionListener callback) {
if (menuText == null) {
throw new NullPointerException("Menu text cannot be null");
}
final AtomicReference<Checkbox> value = new AtomicReference<Checkbox>();
// must always be called on the EDT
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry entry = new SwingEntryCheckbox(SwingMenu.this, callback);
entry.setText(menuText);
menuEntries.add(entry);
value.set((Checkbox) entry);
}
}
});
return value.get();
}
/**
* Will add a new sub-menu entry
* NOT ALWAYS CALLED ON EDT
*/
protected final
@ -150,28 +174,20 @@ class SwingMenu extends MenuBase implements SwingUI {
final AtomicReference<Menu> value = new AtomicReference<Menu>();
// must always be called on the EDT
dispatchAndWait(new Runnable() {
@Override
public
void run() {
synchronized (menuEntries) {
Entry entry = get(menuText);
Entry entry = new SwingMenu(getSystemTray(), SwingMenu.this, new AdjustedJMenu());
_native.add(((SwingMenu) entry)._native); // have to add it separately
if (entry == null) {
// must always be called on the EDT
entry = new SwingMenu(getSystemTray(), SwingMenu.this, new AdjustedJMenu());
_native.add(((SwingMenu) entry)._native); // have to add it separately
entry.setText(menuText);
entry.setImage(imagePath);
value.set((Menu) entry);
} else if (entry instanceof SwingMenu) {
entry.setText(menuText);
entry.setImage(imagePath);
}
entry.setText(menuText);
entry.setImage(imagePath);
menuEntries.add(entry);
value.set((Menu) entry);
}
}
});

View File

@ -17,7 +17,6 @@ package dorkbox.systemTray.util;
import static dorkbox.systemTray.jna.Windows.Gdi32.GetDeviceCaps;
import static dorkbox.systemTray.jna.Windows.Gdi32.LOGPIXELSX;
import static dorkbox.systemTray.jna.Windows.Gdi32.LOGPIXELSY;
import java.awt.Color;
import java.awt.Dimension;
@ -134,8 +133,6 @@ class ImageUtils {
} else if (windowsVersion.startsWith("6.3")) {
// Windows 8.1
// Windows Server 2012 6.3.9200
scalingFactor = 4;
} else if (windowsVersion.startsWith("6.4")) {
@ -154,11 +151,9 @@ class ImageUtils {
Pointer screen = User32.GetDC(null);
int dpiX = GetDeviceCaps (screen, LOGPIXELSX);
int dpiY = GetDeviceCaps (screen, LOGPIXELSY);
User32.ReleaseDC(null, screen);
System.err.println("DPI : " + dpiX + "," + dpiY);
System.err.println("DPI : " + dpiX);
if (SystemTray.DEBUG) {

View File

@ -16,6 +16,7 @@
package dorkbox.systemTray.util;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
@ -23,7 +24,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.Separator;
@ -62,14 +63,21 @@ class MenuBase implements Menu {
/**
* Will add a new menu entry, or update one if it already exists
* Will add a new menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
protected abstract
Entry addEntry_(final String menuText, final File imagePath, final Action callback);
Entry addEntry_(final String menuText, final File imagePath, final ActionListener callback);
/**
* Will add a new sub-menu entry, or update one if it already exists
* Will add a new checkbox menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
protected abstract
Checkbox addCheckbox_(final String menuText, final ActionListener callback);
/**
* Will add a new sub-menu entry
* NOT ALWAYS CALLED ON DISPATCH
*/
protected abstract
@ -225,13 +233,13 @@ class MenuBase implements Menu {
@Override
public final
Entry addEntry(String menuText, Action callback) {
Entry addEntry(String menuText, ActionListener callback) {
return addEntry(menuText, (String) null, callback);
}
@Override
public final
Entry addEntry(String menuText, String imagePath, Action callback) {
Entry addEntry(String menuText, String imagePath, ActionListener callback) {
if (imagePath == null) {
return addEntry_(menuText, null, callback);
}
@ -242,7 +250,7 @@ class MenuBase implements Menu {
@Override
public final
Entry addEntry(String menuText, URL imageUrl, Action callback) {
Entry addEntry(String menuText, URL imageUrl, ActionListener callback) {
if (imageUrl == null) {
return addEntry_(menuText, null, callback);
}
@ -253,7 +261,7 @@ class MenuBase implements Menu {
@Override
public final
Entry addEntry(String menuText, String cacheName, InputStream imageStream, Action callback) {
Entry addEntry(String menuText, String cacheName, InputStream imageStream, ActionListener callback) {
if (imageStream == null) {
return addEntry_(menuText, null, callback);
}
@ -264,7 +272,7 @@ class MenuBase implements Menu {
@Override
public final
Entry addEntry(String menuText, InputStream imageStream, Action callback) {
Entry addEntry(String menuText, InputStream imageStream, ActionListener callback) {
if (imageStream == null) {
return addEntry_(menuText, null, callback);
}
@ -274,6 +282,11 @@ class MenuBase implements Menu {
}
@Override
public
Checkbox addCheckbox(final String menuText, final ActionListener callback) {
return addCheckbox_(menuText, callback);
}
@ -386,36 +399,12 @@ class MenuBase implements Menu {
}
@Override
public final
void setCallback(final Action callback) {
void setCallback(final ActionListener callback) {
}
/**
* This removes a menu entry from the dropdown menu.
*
@ -526,27 +515,6 @@ class MenuBase implements Menu {
});
}
// @Override
// public final
// void remove() {
// dispatchAndWait(new Runnable() {
// @Override
// public
// void run() {
// _native.setVisible(false);
// if (_native instanceof TrayPopup) {
// ((TrayPopup) _native).close();
// }
//
// MenuBase parent = (MenuBase) getParent();
// if (parent != null) {
// parent._native.remove(_native);
// }
// }
// });
// }
@Override
public final
void removeAll() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

View File

@ -16,9 +16,11 @@
package dorkbox;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Checkbox;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.SystemTray;
@ -49,8 +51,8 @@ class TestTray {
}
private SystemTray systemTray;
private Action callbackGreen;
private Action callbackGray;
private ActionListener callbackGreen;
private ActionListener callbackGray;
public
TestTray() {
@ -59,13 +61,23 @@ class TestTray {
throw new RuntimeException("Unable to load SystemTray!");
}
// final JPopupMenu popupMenu = new JPopupMenu();
// JMenu submenu2 = new JMenu("SubMenu1");
// submenu2.add("asdf");
// submenu2.add("asdf");
//
// // Add submenu to popup menu
// popupMenu.add(submenu2);
systemTray.setImage(LT_GRAY_TRAIN);
systemTray.setStatus("No Mail");
callbackGreen = new Action() {
callbackGreen = new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final ActionEvent e) {
final Entry entry = (Entry) e.getSource();
systemTray.setStatus("Some Mail!");
systemTray.setImage(GREEN_TRAIN);
@ -76,10 +88,11 @@ class TestTray {
}
};
callbackGray = new Action() {
callbackGray = new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final ActionEvent e) {
final Entry entry = (Entry) e.getSource();
systemTray.setStatus(null);
systemTray.setImage(BLACK_TRAIN);
@ -94,14 +107,18 @@ class TestTray {
// case does not matter
menuEntry.setShortcut('G');
final Checkbox menuCheckbox = this.systemTray.addCheckbox("Euro € Mail", callbackGreen);
// case does not matter
// menuCheckbox.setShortcut('€');
this.systemTray.addSeparator();
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
submenu.setShortcut('t');
submenu.addEntry("Disable menu", BLACK_BUS, new Action() {
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final ActionEvent e) {
submenu.setEnabled(false);
}
});
@ -116,26 +133,26 @@ class TestTray {
// systemTray.addWidget(progressBar);
// }
// });
submenu.addEntry("Hide tray", LT_GRAY_BUS, new Action() {
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final ActionEvent e) {
systemTray.setEnabled(false);
}
});
submenu.addEntry("Remove menu", BLACK_FIRE, new Action() {
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final ActionEvent e) {
submenu.remove();
}
});
systemTray.addEntry("Quit", new Action() {
systemTray.addEntry("Quit", new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final ActionEvent e) {
systemTray.shutdown();
//System.exit(0); not necessary if all non-daemon threads have stopped.
}

View File

@ -16,9 +16,9 @@
package dorkbox;
import java.awt.event.ActionListener;
import java.net.URL;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.SystemTray;
@ -59,8 +59,8 @@ class TestTrayJavaFX extends Application {
}
private SystemTray systemTray;
private Action callbackGreen;
private Action callbackGray;
private ActionListener callbackGreen;
private ActionListener callbackGray;
public
TestTrayJavaFX() {
@ -95,10 +95,11 @@ class TestTrayJavaFX extends Application {
systemTray.setImage(LT_GRAY_TRAIN);
systemTray.setStatus("No Mail");
callbackGreen = new Action() {
callbackGreen = new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
final Entry entry = (Entry) e.getSource();
systemTray.setStatus("Some Mail!");
systemTray.setImage(GREEN_TRAIN);
@ -109,10 +110,11 @@ class TestTrayJavaFX extends Application {
}
};
callbackGray = new Action() {
callbackGray = new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
final Entry entry = (Entry) e.getSource();
systemTray.setStatus(null);
systemTray.setImage(BLACK_TRAIN);
@ -127,14 +129,18 @@ class TestTrayJavaFX extends Application {
// case does not matter
menuEntry.setShortcut('G');
menuEntry = this.systemTray.addEntry("Euro € Mail", GREEN_MAIL, callbackGreen);
// case does not matter
menuEntry.setShortcut('€');
this.systemTray.addSeparator();
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
submenu.setShortcut('t');
submenu.addEntry("Disable menu", BLACK_BUS, new Action() {
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
submenu.setEnabled(false);
}
});
@ -149,25 +155,25 @@ class TestTrayJavaFX extends Application {
// systemTray.addWidget(progressBar);
// }
// });
submenu.addEntry("Hide tray", LT_GRAY_BUS, new Action() {
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
systemTray.setEnabled(false);
}
});
submenu.addEntry("Remove menu", BLACK_FIRE, new Action() {
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
submenu.remove();
}
});
systemTray.addEntry("Quit", new Action() {
systemTray.addEntry("Quit", new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
systemTray.shutdown();
Platform.exit(); // necessary to close javaFx
//System.exit(0); not necessary if all non-daemon threads have stopped.

View File

@ -16,6 +16,7 @@
package dorkbox;
import java.awt.event.ActionListener;
import java.net.URL;
import org.eclipse.swt.SWT;
@ -23,7 +24,6 @@ import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import dorkbox.systemTray.Action;
import dorkbox.systemTray.Entry;
import dorkbox.systemTray.Menu;
import dorkbox.systemTray.SystemTray;
@ -58,8 +58,8 @@ class TestTraySwt {
}
private SystemTray systemTray;
private Action callbackGreen;
private Action callbackGray;
private ActionListener callbackGreen;
private ActionListener callbackGray;
public
TestTraySwt() {
@ -79,10 +79,11 @@ class TestTraySwt {
systemTray.setImage(LT_GRAY_TRAIN);
systemTray.setStatus("No Mail");
callbackGreen = new Action() {
callbackGreen = new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
final Entry entry = (Entry) e.getSource();
systemTray.setStatus("Some Mail!");
systemTray.setImage(GREEN_TRAIN);
@ -93,10 +94,11 @@ class TestTraySwt {
}
};
callbackGray = new Action() {
callbackGray = new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
final Entry entry = (Entry) e.getSource();
systemTray.setStatus(null);
systemTray.setImage(BLACK_TRAIN);
@ -111,14 +113,18 @@ class TestTraySwt {
// case does not matter
menuEntry.setShortcut('G');
menuEntry = this.systemTray.addEntry("Euro € Mail", GREEN_MAIL, callbackGreen);
// case does not matter
menuEntry.setShortcut('€');
this.systemTray.addSeparator();
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
submenu.setShortcut('t');
submenu.addEntry("Disable menu", BLACK_BUS, new Action() {
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
submenu.setEnabled(false);
}
});
@ -133,25 +139,25 @@ class TestTraySwt {
// systemTray.addWidget(progressBar);
// }
// });
submenu.addEntry("Hide tray", LT_GRAY_BUS, new Action() {
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
systemTray.setEnabled(false);
}
});
submenu.addEntry("Remove menu", BLACK_FIRE, new Action() {
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
submenu.remove();
}
});
systemTray.addEntry("Quit", new Action() {
systemTray.addEntry("Quit", new ActionListener() {
@Override
public
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
void actionPerformed(final java.awt.event.ActionEvent e) {
systemTray.shutdown();
display.asyncExec(new Runnable() {