forked from dorkbox/SystemTray
Changed action callback to ActionListener. Added checkbox.
This commit is contained in:
parent
4e47c5d263
commit
a07c5e8ab8
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2014 dorkbox, llc
|
* Copyright 2015 dorkbox, llc
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This represents a common menu-checkbox entry, that is cross platform in nature
|
||||||
|
*/
|
||||||
public
|
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.
|
* @return true if this checkbox is selected, false if not
|
||||||
*
|
|
||||||
* @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
|
|
||||||
*/
|
*/
|
||||||
void onClick(SystemTray systemTray, Menu parent, final Entry entry);
|
boolean getState();
|
||||||
}
|
}
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@ -97,7 +98,7 @@ interface Entry {
|
|||||||
*
|
*
|
||||||
* @param callback the callback to set. If null, the callback is safely removed.
|
* @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.
|
* Sets a menu entry shortcut key (Mnemonic) so that menu entry can be "selected" via the keyboard while the menu is displayed.
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ interface Menu extends Entry {
|
|||||||
* @param menuText string of the text you want to appear
|
* @param menuText string of the text you want to appear
|
||||||
* @param callback callback that will be executed when this menu entry is clicked
|
* @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
|
* 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 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
|
* @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
|
* 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 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
|
* @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
|
* 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 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
|
* @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
|
* 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 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
|
* @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)
|
* Adds a sub-menu entry with text (no image)
|
||||||
|
@ -17,6 +17,7 @@ package dorkbox.systemTray;
|
|||||||
|
|
||||||
import java.awt.GraphicsEnvironment;
|
import java.awt.GraphicsEnvironment;
|
||||||
import java.awt.HeadlessException;
|
import java.awt.HeadlessException;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -924,7 +925,7 @@ class SystemTray implements Menu {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
// NO OP.
|
// NO OP.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,7 +993,7 @@ class SystemTray implements Menu {
|
|||||||
* @param callback callback that will be executed when this menu entry is clicked
|
* @param callback callback that will be executed when this menu entry is clicked
|
||||||
*/
|
*/
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, Action callback) {
|
Entry addEntry(String menuText, ActionListener callback) {
|
||||||
return addEntry(menuText, (String) null, 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
|
* @param callback callback that will be executed when this menu entry is clicked
|
||||||
*/
|
*/
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, String imagePath, Action callback) {
|
Entry addEntry(String menuText, String imagePath, ActionListener callback) {
|
||||||
return systemTrayMenu.addEntry(menuText, imagePath, 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
|
* @param callback callback that will be executed when this menu entry is clicked
|
||||||
*/
|
*/
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, URL imageUrl, Action callback) {
|
Entry addEntry(String menuText, URL imageUrl, ActionListener callback) {
|
||||||
return systemTrayMenu.addEntry(menuText, imageUrl, 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
|
* @param callback callback that will be executed when this menu entry is clicked
|
||||||
*/
|
*/
|
||||||
public
|
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);
|
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
|
* @param callback callback that will be executed when this menu entry is clicked
|
||||||
*/
|
*/
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, InputStream imageStream, Action callback) {
|
Entry addEntry(String menuText, InputStream imageStream, ActionListener callback) {
|
||||||
return systemTrayMenu.addEntry(menuText, imageStream, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ class Gdi32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final int LOGPIXELSX = 88;
|
public static final int LOGPIXELSX = 88;
|
||||||
public static final int LOGPIXELSY = 90;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,8 @@ package dorkbox.systemTray.jna.linux;
|
|||||||
|
|
||||||
import static dorkbox.systemTray.SystemTray.logger;
|
import static dorkbox.systemTray.SystemTray.logger;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -24,9 +26,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import com.sun.jna.Function;
|
import com.sun.jna.Function;
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
import dorkbox.systemTray.jna.JnaHelper;
|
import dorkbox.systemTray.jna.JnaHelper;
|
||||||
import dorkbox.systemTray.util.JavaFX;
|
import dorkbox.systemTray.util.JavaFX;
|
||||||
@ -422,11 +422,11 @@ class Gtk {
|
|||||||
* @param callback will never be null.
|
* @param callback will never be null.
|
||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
void proxyClick(final Menu parent, final Entry menuEntry, final Action callback) {
|
void proxyClick(final Entry menuEntry, final ActionListener callback) {
|
||||||
Gtk.isDispatch = true;
|
Gtk.isDispatch = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
callback.onClick(parent.getSystemTray(), parent, menuEntry);
|
callback.actionPerformed(new ActionEvent(menuEntry, ActionEvent.ACTION_PERFORMED, ""));
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
SystemTray.logger.error("Error calling menu entry {} click event.", menuEntry.getText(), 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
|
// 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_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);
|
public static native void gtk_image_menu_item_set_image(Pointer image_menu_item, Pointer image);
|
||||||
|
|
||||||
|
104
src/dorkbox/systemTray/nativeUI/AwtEntryCheckbox.java
Normal file
104
src/dorkbox/systemTray/nativeUI/AwtEntryCheckbox.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -19,16 +19,16 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
|
||||||
class AwtEntryItem extends AwtEntry {
|
class AwtEntryItem extends AwtEntry {
|
||||||
|
|
||||||
private final ActionListener swingCallback;
|
private final ActionListener swingCallback;
|
||||||
|
|
||||||
private volatile Action callback;
|
private volatile ActionListener callback;
|
||||||
|
|
||||||
// this is ALWAYS called on the EDT.
|
// 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());
|
super(parent, new java.awt.MenuItem());
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
||||||
@ -53,14 +53,19 @@ class AwtEntryItem extends AwtEntry {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
void handle() {
|
void handle() {
|
||||||
if (callback != null) {
|
ActionListener cb = this.callback;
|
||||||
callback.onClick(getParent().getSystemTray(), getParent(), this);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
package dorkbox.systemTray.nativeUI;
|
package dorkbox.systemTray.nativeUI;
|
||||||
|
|
||||||
import java.awt.MenuItem;
|
import java.awt.MenuItem;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
|
|
||||||
class AwtEntrySeparator extends AwtEntry implements dorkbox.systemTray.Separator {
|
class AwtEntrySeparator extends AwtEntry implements dorkbox.systemTray.Separator {
|
||||||
|
|
||||||
// this is ALWAYS called on the EDT.
|
// this is ALWAYS called on the EDT.
|
||||||
@ -53,6 +52,6 @@ class AwtEntrySeparator extends AwtEntry implements dorkbox.systemTray.Separator
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ import static java.awt.Font.DIALOG;
|
|||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.MenuItem;
|
import java.awt.MenuItem;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
import dorkbox.systemTray.Status;
|
import dorkbox.systemTray.Status;
|
||||||
|
|
||||||
class AwtEntryStatus extends AwtEntry implements Status {
|
class AwtEntryStatus extends AwtEntry implements Status {
|
||||||
@ -70,6 +70,6 @@ class AwtEntryStatus extends AwtEntry implements Status {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,11 @@ package dorkbox.systemTray.nativeUI;
|
|||||||
|
|
||||||
import java.awt.MenuShortcut;
|
import java.awt.MenuShortcut;
|
||||||
import java.awt.PopupMenu;
|
import java.awt.PopupMenu;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.Status;
|
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
|
* NOT ALWAYS CALLED ON EDT
|
||||||
*/
|
*/
|
||||||
protected final
|
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) {
|
if (menuText == null) {
|
||||||
throw new NullPointerException("Menu text cannot be null");
|
throw new NullPointerException("Menu text cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
final AtomicReference<Entry> value = new AtomicReference<Entry>();
|
final AtomicReference<Entry> value = new AtomicReference<Entry>();
|
||||||
|
|
||||||
|
// must always be called on the EDT
|
||||||
dispatchAndWait(new Runnable() {
|
dispatchAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
Entry entry = get(menuText);
|
Entry entry = entry = new AwtEntryItem(AwtMenu.this, callback);
|
||||||
|
entry.setText(menuText);
|
||||||
if (entry == null) {
|
entry.setImage(imagePath);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
menuEntries.add(entry);
|
||||||
value.set(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
|
* NOT ALWAYS CALLED ON EDT
|
||||||
*/
|
*/
|
||||||
protected final
|
protected final
|
||||||
@ -147,28 +172,20 @@ class AwtMenu extends MenuBase implements NativeUI {
|
|||||||
|
|
||||||
final AtomicReference<Menu> value = new AtomicReference<Menu>();
|
final AtomicReference<Menu> value = new AtomicReference<Menu>();
|
||||||
|
|
||||||
|
// must always be called on the EDT
|
||||||
dispatchAndWait(new Runnable() {
|
dispatchAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
synchronized (menuEntries) {
|
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) {
|
entry.setText(menuText);
|
||||||
// must always be called on the EDT
|
entry.setImage(imagePath);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
menuEntries.add(entry);
|
menuEntries.add(entry);
|
||||||
|
value.set((Menu) entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
172
src/dorkbox/systemTray/nativeUI/GtkEntryCheckbox.java
Normal file
172
src/dorkbox/systemTray/nativeUI/GtkEntryCheckbox.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,12 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.nativeUI;
|
package dorkbox.systemTray.nativeUI;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import com.sun.jna.NativeLong;
|
import com.sun.jna.NativeLong;
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
import dorkbox.systemTray.jna.linux.GCallback;
|
import dorkbox.systemTray.jna.linux.GCallback;
|
||||||
import dorkbox.systemTray.jna.linux.Gobject;
|
import dorkbox.systemTray.jna.linux.Gobject;
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
@ -33,7 +33,7 @@ class GtkEntryItem extends GtkEntry implements GCallback {
|
|||||||
private final NativeLong nativeLong;
|
private final NativeLong nativeLong;
|
||||||
|
|
||||||
// these have to be volatile, because they can be changed from any thread
|
// these have to be volatile, because they can be changed from any thread
|
||||||
private volatile Action callback;
|
private volatile ActionListener callback;
|
||||||
private volatile Pointer image;
|
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
|
// 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!
|
* 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
|
* 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(""));
|
super(parent, Gtk.gtk_image_menu_item_new_with_mnemonic(""));
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class GtkEntryItem extends GtkEntry implements GCallback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,9 +91,9 @@ class GtkEntryItem extends GtkEntry implements GCallback {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
int callback(final Pointer instance, final Pointer data) {
|
int callback(final Pointer instance, final Pointer data) {
|
||||||
final Action cb = this.callback;
|
final ActionListener cb = this.callback;
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
Gtk.proxyClick(getParent(), GtkEntryItem.this, cb);
|
Gtk.proxyClick(GtkEntryItem.this, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Gtk.TRUE;
|
return Gtk.TRUE;
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.nativeUI;
|
package dorkbox.systemTray.nativeUI;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
import dorkbox.systemTray.Separator;
|
import dorkbox.systemTray.Separator;
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ class GtkEntrySeparator extends GtkEntry implements Separator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.nativeUI;
|
package dorkbox.systemTray.nativeUI;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
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,
|
// 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
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package dorkbox.systemTray.nativeUI;
|
package dorkbox.systemTray.nativeUI;
|
||||||
|
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -23,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
|
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
@ -62,6 +63,127 @@ class GtkMenu extends MenuBase implements NativeUI {
|
|||||||
// only needed for AppIndicator
|
// 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
|
* 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
|
// public here so that Swing/Gtk/AppIndicator can override this
|
||||||
@Override
|
@Override
|
||||||
public
|
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.
|
// a child will always remove itself from the parent.
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
|
128
src/dorkbox/systemTray/swingUI/SwingEntryCheckbox.java
Normal file
128
src/dorkbox/systemTray/swingUI/SwingEntryCheckbox.java
Normal 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) {
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ import java.io.File;
|
|||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import dorkbox.systemTray.SystemTray;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class SwingEntryItem extends SwingEntry {
|
class SwingEntryItem extends SwingEntry {
|
||||||
@ -30,10 +30,10 @@ class SwingEntryItem extends SwingEntry {
|
|||||||
private final ActionListener swingCallback;
|
private final ActionListener swingCallback;
|
||||||
|
|
||||||
private volatile boolean hasLegitIcon = false;
|
private volatile boolean hasLegitIcon = false;
|
||||||
private volatile Action callback;
|
private volatile ActionListener callback;
|
||||||
|
|
||||||
// this is ALWAYS called on the EDT.
|
// 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());
|
super(parent, new AdjustedJMenuItem());
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
||||||
@ -58,14 +58,19 @@ class SwingEntryItem extends SwingEntry {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
void handle() {
|
void handle() {
|
||||||
if (callback != null) {
|
ActionListener cb = this.callback;
|
||||||
callback.onClick(getParent().getSystemTray(), getParent(), this);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,12 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.swingUI;
|
package dorkbox.systemTray.swingUI;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import javax.swing.JSeparator;
|
import javax.swing.JSeparator;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
|
|
||||||
class SwingEntrySeparator extends SwingEntry implements dorkbox.systemTray.Separator {
|
class SwingEntrySeparator extends SwingEntry implements dorkbox.systemTray.Separator {
|
||||||
|
|
||||||
// this is ALWAYS called on the EDT.
|
// this is ALWAYS called on the EDT.
|
||||||
@ -54,6 +53,6 @@ class SwingEntrySeparator extends SwingEntry implements dorkbox.systemTray.Separ
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
package dorkbox.systemTray.swingUI;
|
package dorkbox.systemTray.swingUI;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
import dorkbox.systemTray.Status;
|
import dorkbox.systemTray.Status;
|
||||||
|
|
||||||
class SwingEntryStatus extends SwingEntry implements Status {
|
class SwingEntryStatus extends SwingEntry implements Status {
|
||||||
@ -65,7 +65,7 @@ class SwingEntryStatus extends SwingEntry implements Status {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.swingUI;
|
package dorkbox.systemTray.swingUI;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
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.
|
// 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 {
|
class SwingEntryWidget extends SwingEntry implements dorkbox.systemTray.Separator {
|
||||||
|
|
||||||
@ -57,6 +56,6 @@ class SwingEntryWidget extends SwingEntry implements dorkbox.systemTray.Separato
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package dorkbox.systemTray.swingUI;
|
package dorkbox.systemTray.swingUI;
|
||||||
|
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ import javax.swing.ImageIcon;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.Status;
|
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
|
* NOT ALWAYS CALLED ON EDT
|
||||||
*/
|
*/
|
||||||
protected final
|
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) {
|
if (menuText == null) {
|
||||||
throw new NullPointerException("Menu text cannot be null");
|
throw new NullPointerException("Menu text cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
final AtomicReference<Entry> value = new AtomicReference<Entry>();
|
final AtomicReference<Entry> value = new AtomicReference<Entry>();
|
||||||
|
|
||||||
|
// must always be called on the EDT
|
||||||
dispatchAndWait(new Runnable() {
|
dispatchAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
Entry entry = get(menuText);
|
Entry entry = new SwingEntryItem(SwingMenu.this, callback);
|
||||||
|
entry.setText(menuText);
|
||||||
if (entry == null) {
|
entry.setImage(imagePath);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
menuEntries.add(entry);
|
||||||
value.set(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
|
* NOT ALWAYS CALLED ON EDT
|
||||||
*/
|
*/
|
||||||
protected final
|
protected final
|
||||||
@ -150,28 +174,20 @@ class SwingMenu extends MenuBase implements SwingUI {
|
|||||||
|
|
||||||
final AtomicReference<Menu> value = new AtomicReference<Menu>();
|
final AtomicReference<Menu> value = new AtomicReference<Menu>();
|
||||||
|
|
||||||
|
// must always be called on the EDT
|
||||||
dispatchAndWait(new Runnable() {
|
dispatchAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
synchronized (menuEntries) {
|
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) {
|
entry.setText(menuText);
|
||||||
// must always be called on the EDT
|
entry.setImage(imagePath);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
menuEntries.add(entry);
|
menuEntries.add(entry);
|
||||||
|
value.set((Menu) entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,6 @@ package dorkbox.systemTray.util;
|
|||||||
|
|
||||||
import static dorkbox.systemTray.jna.Windows.Gdi32.GetDeviceCaps;
|
import static dorkbox.systemTray.jna.Windows.Gdi32.GetDeviceCaps;
|
||||||
import static dorkbox.systemTray.jna.Windows.Gdi32.LOGPIXELSX;
|
import static dorkbox.systemTray.jna.Windows.Gdi32.LOGPIXELSX;
|
||||||
import static dorkbox.systemTray.jna.Windows.Gdi32.LOGPIXELSY;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
@ -134,8 +133,6 @@ class ImageUtils {
|
|||||||
} else if (windowsVersion.startsWith("6.3")) {
|
} else if (windowsVersion.startsWith("6.3")) {
|
||||||
// Windows 8.1
|
// Windows 8.1
|
||||||
// Windows Server 2012 6.3.9200
|
// Windows Server 2012 6.3.9200
|
||||||
|
|
||||||
|
|
||||||
scalingFactor = 4;
|
scalingFactor = 4;
|
||||||
|
|
||||||
} else if (windowsVersion.startsWith("6.4")) {
|
} else if (windowsVersion.startsWith("6.4")) {
|
||||||
@ -154,11 +151,9 @@ class ImageUtils {
|
|||||||
|
|
||||||
Pointer screen = User32.GetDC(null);
|
Pointer screen = User32.GetDC(null);
|
||||||
int dpiX = GetDeviceCaps (screen, LOGPIXELSX);
|
int dpiX = GetDeviceCaps (screen, LOGPIXELSX);
|
||||||
int dpiY = GetDeviceCaps (screen, LOGPIXELSY);
|
|
||||||
User32.ReleaseDC(null, screen);
|
User32.ReleaseDC(null, screen);
|
||||||
|
|
||||||
System.err.println("DPI : " + dpiX + "," + dpiY);
|
System.err.println("DPI : " + dpiX);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (SystemTray.DEBUG) {
|
if (SystemTray.DEBUG) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package dorkbox.systemTray.util;
|
package dorkbox.systemTray.util;
|
||||||
|
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@ -23,7 +24,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.Separator;
|
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
|
* NOT ALWAYS CALLED ON DISPATCH
|
||||||
*/
|
*/
|
||||||
protected abstract
|
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
|
* NOT ALWAYS CALLED ON DISPATCH
|
||||||
*/
|
*/
|
||||||
protected abstract
|
protected abstract
|
||||||
@ -225,13 +233,13 @@ class MenuBase implements Menu {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, Action callback) {
|
Entry addEntry(String menuText, ActionListener callback) {
|
||||||
return addEntry(menuText, (String) null, callback);
|
return addEntry(menuText, (String) null, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, String imagePath, Action callback) {
|
Entry addEntry(String menuText, String imagePath, ActionListener callback) {
|
||||||
if (imagePath == null) {
|
if (imagePath == null) {
|
||||||
return addEntry_(menuText, null, callback);
|
return addEntry_(menuText, null, callback);
|
||||||
}
|
}
|
||||||
@ -242,7 +250,7 @@ class MenuBase implements Menu {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, URL imageUrl, Action callback) {
|
Entry addEntry(String menuText, URL imageUrl, ActionListener callback) {
|
||||||
if (imageUrl == null) {
|
if (imageUrl == null) {
|
||||||
return addEntry_(menuText, null, callback);
|
return addEntry_(menuText, null, callback);
|
||||||
}
|
}
|
||||||
@ -253,7 +261,7 @@ class MenuBase implements Menu {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final
|
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) {
|
if (imageStream == null) {
|
||||||
return addEntry_(menuText, null, callback);
|
return addEntry_(menuText, null, callback);
|
||||||
}
|
}
|
||||||
@ -264,7 +272,7 @@ class MenuBase implements Menu {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Entry addEntry(String menuText, InputStream imageStream, Action callback) {
|
Entry addEntry(String menuText, InputStream imageStream, ActionListener callback) {
|
||||||
if (imageStream == null) {
|
if (imageStream == null) {
|
||||||
return addEntry_(menuText, null, callback);
|
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
|
@Override
|
||||||
public final
|
public final
|
||||||
void setCallback(final Action callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This removes a menu entry from the dropdown menu.
|
* 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
|
@Override
|
||||||
public final
|
public final
|
||||||
void removeAll() {
|
void removeAll() {
|
||||||
|
BIN
src/dorkbox/systemTray/util/checked_32.png
Normal file
BIN
src/dorkbox/systemTray/util/checked_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 298 B |
@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package dorkbox;
|
package dorkbox;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
@ -49,8 +51,8 @@ class TestTray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SystemTray systemTray;
|
private SystemTray systemTray;
|
||||||
private Action callbackGreen;
|
private ActionListener callbackGreen;
|
||||||
private Action callbackGray;
|
private ActionListener callbackGray;
|
||||||
|
|
||||||
public
|
public
|
||||||
TestTray() {
|
TestTray() {
|
||||||
@ -59,13 +61,23 @@ class TestTray {
|
|||||||
throw new RuntimeException("Unable to load SystemTray!");
|
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.setImage(LT_GRAY_TRAIN);
|
||||||
systemTray.setStatus("No Mail");
|
systemTray.setStatus("No Mail");
|
||||||
|
|
||||||
callbackGreen = new Action() {
|
callbackGreen = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
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.setStatus("Some Mail!");
|
||||||
systemTray.setImage(GREEN_TRAIN);
|
systemTray.setImage(GREEN_TRAIN);
|
||||||
|
|
||||||
@ -76,10 +88,11 @@ class TestTray {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
callbackGray = new Action() {
|
callbackGray = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
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.setStatus(null);
|
||||||
systemTray.setImage(BLACK_TRAIN);
|
systemTray.setImage(BLACK_TRAIN);
|
||||||
|
|
||||||
@ -94,14 +107,18 @@ class TestTray {
|
|||||||
// case does not matter
|
// case does not matter
|
||||||
menuEntry.setShortcut('G');
|
menuEntry.setShortcut('G');
|
||||||
|
|
||||||
|
final Checkbox menuCheckbox = this.systemTray.addCheckbox("Euro € Mail", callbackGreen);
|
||||||
|
// case does not matter
|
||||||
|
// menuCheckbox.setShortcut('€');
|
||||||
|
|
||||||
this.systemTray.addSeparator();
|
this.systemTray.addSeparator();
|
||||||
|
|
||||||
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
||||||
submenu.setShortcut('t');
|
submenu.setShortcut('t');
|
||||||
submenu.addEntry("Disable menu", BLACK_BUS, new Action() {
|
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
submenu.setEnabled(false);
|
submenu.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -116,26 +133,26 @@ class TestTray {
|
|||||||
// systemTray.addWidget(progressBar);
|
// systemTray.addWidget(progressBar);
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
submenu.addEntry("Hide tray", LT_GRAY_BUS, new Action() {
|
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
systemTray.setEnabled(false);
|
systemTray.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
submenu.addEntry("Remove menu", BLACK_FIRE, new Action() {
|
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
submenu.remove();
|
submenu.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
systemTray.addEntry("Quit", new Action() {
|
systemTray.addEntry("Quit", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
systemTray.shutdown();
|
systemTray.shutdown();
|
||||||
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
package dorkbox;
|
package dorkbox;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
@ -59,8 +59,8 @@ class TestTrayJavaFX extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SystemTray systemTray;
|
private SystemTray systemTray;
|
||||||
private Action callbackGreen;
|
private ActionListener callbackGreen;
|
||||||
private Action callbackGray;
|
private ActionListener callbackGray;
|
||||||
|
|
||||||
public
|
public
|
||||||
TestTrayJavaFX() {
|
TestTrayJavaFX() {
|
||||||
@ -95,10 +95,11 @@ class TestTrayJavaFX extends Application {
|
|||||||
systemTray.setImage(LT_GRAY_TRAIN);
|
systemTray.setImage(LT_GRAY_TRAIN);
|
||||||
systemTray.setStatus("No Mail");
|
systemTray.setStatus("No Mail");
|
||||||
|
|
||||||
callbackGreen = new Action() {
|
callbackGreen = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
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.setStatus("Some Mail!");
|
||||||
systemTray.setImage(GREEN_TRAIN);
|
systemTray.setImage(GREEN_TRAIN);
|
||||||
|
|
||||||
@ -109,10 +110,11 @@ class TestTrayJavaFX extends Application {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
callbackGray = new Action() {
|
callbackGray = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
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.setStatus(null);
|
||||||
systemTray.setImage(BLACK_TRAIN);
|
systemTray.setImage(BLACK_TRAIN);
|
||||||
|
|
||||||
@ -127,14 +129,18 @@ class TestTrayJavaFX extends Application {
|
|||||||
// case does not matter
|
// case does not matter
|
||||||
menuEntry.setShortcut('G');
|
menuEntry.setShortcut('G');
|
||||||
|
|
||||||
|
menuEntry = this.systemTray.addEntry("Euro € Mail", GREEN_MAIL, callbackGreen);
|
||||||
|
// case does not matter
|
||||||
|
menuEntry.setShortcut('€');
|
||||||
|
|
||||||
this.systemTray.addSeparator();
|
this.systemTray.addSeparator();
|
||||||
|
|
||||||
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
||||||
submenu.setShortcut('t');
|
submenu.setShortcut('t');
|
||||||
submenu.addEntry("Disable menu", BLACK_BUS, new Action() {
|
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
submenu.setEnabled(false);
|
submenu.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -149,25 +155,25 @@ class TestTrayJavaFX extends Application {
|
|||||||
// systemTray.addWidget(progressBar);
|
// systemTray.addWidget(progressBar);
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
submenu.addEntry("Hide tray", LT_GRAY_BUS, new Action() {
|
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
systemTray.setEnabled(false);
|
systemTray.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
submenu.addEntry("Remove menu", BLACK_FIRE, new Action() {
|
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
submenu.remove();
|
submenu.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
systemTray.addEntry("Quit", new Action() {
|
systemTray.addEntry("Quit", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
systemTray.shutdown();
|
systemTray.shutdown();
|
||||||
Platform.exit(); // necessary to close javaFx
|
Platform.exit(); // necessary to close javaFx
|
||||||
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package dorkbox;
|
package dorkbox;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
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.Shell;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
import dorkbox.systemTray.Action;
|
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Entry;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
@ -58,8 +58,8 @@ class TestTraySwt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SystemTray systemTray;
|
private SystemTray systemTray;
|
||||||
private Action callbackGreen;
|
private ActionListener callbackGreen;
|
||||||
private Action callbackGray;
|
private ActionListener callbackGray;
|
||||||
|
|
||||||
public
|
public
|
||||||
TestTraySwt() {
|
TestTraySwt() {
|
||||||
@ -79,10 +79,11 @@ class TestTraySwt {
|
|||||||
systemTray.setImage(LT_GRAY_TRAIN);
|
systemTray.setImage(LT_GRAY_TRAIN);
|
||||||
systemTray.setStatus("No Mail");
|
systemTray.setStatus("No Mail");
|
||||||
|
|
||||||
callbackGreen = new Action() {
|
callbackGreen = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
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.setStatus("Some Mail!");
|
||||||
systemTray.setImage(GREEN_TRAIN);
|
systemTray.setImage(GREEN_TRAIN);
|
||||||
|
|
||||||
@ -93,10 +94,11 @@ class TestTraySwt {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
callbackGray = new Action() {
|
callbackGray = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
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.setStatus(null);
|
||||||
systemTray.setImage(BLACK_TRAIN);
|
systemTray.setImage(BLACK_TRAIN);
|
||||||
|
|
||||||
@ -111,14 +113,18 @@ class TestTraySwt {
|
|||||||
// case does not matter
|
// case does not matter
|
||||||
menuEntry.setShortcut('G');
|
menuEntry.setShortcut('G');
|
||||||
|
|
||||||
|
menuEntry = this.systemTray.addEntry("Euro € Mail", GREEN_MAIL, callbackGreen);
|
||||||
|
// case does not matter
|
||||||
|
menuEntry.setShortcut('€');
|
||||||
|
|
||||||
this.systemTray.addSeparator();
|
this.systemTray.addSeparator();
|
||||||
|
|
||||||
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
||||||
submenu.setShortcut('t');
|
submenu.setShortcut('t');
|
||||||
submenu.addEntry("Disable menu", BLACK_BUS, new Action() {
|
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
submenu.setEnabled(false);
|
submenu.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -133,25 +139,25 @@ class TestTraySwt {
|
|||||||
// systemTray.addWidget(progressBar);
|
// systemTray.addWidget(progressBar);
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
submenu.addEntry("Hide tray", LT_GRAY_BUS, new Action() {
|
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
systemTray.setEnabled(false);
|
systemTray.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
submenu.addEntry("Remove menu", BLACK_FIRE, new Action() {
|
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
submenu.remove();
|
submenu.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
systemTray.addEntry("Quit", new Action() {
|
systemTray.addEntry("Quit", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
systemTray.shutdown();
|
systemTray.shutdown();
|
||||||
|
|
||||||
display.asyncExec(new Runnable() {
|
display.asyncExec(new Runnable() {
|
||||||
|
Loading…
Reference in New Issue
Block a user