forked from dorkbox/SystemTray
Fixed issues with checkboxes not working for AWT/GTK
This commit is contained in:
parent
4fe1ebf14f
commit
726a1034b0
@ -444,7 +444,13 @@ class Gtk {
|
||||
Gtk.isDispatch.set(true);
|
||||
|
||||
try {
|
||||
callback.actionPerformed(new ActionEvent(menuEntry, ActionEvent.ACTION_PERFORMED, ""));
|
||||
if (menuEntry != null) {
|
||||
callback.actionPerformed(new ActionEvent(menuEntry, ActionEvent.ACTION_PERFORMED, ""));
|
||||
} else {
|
||||
// checkbox entries will not pass the menuEntry in, because they redispatch the click event so that the checkbox state is
|
||||
// toggled
|
||||
callback.actionPerformed(null);
|
||||
}
|
||||
} finally {
|
||||
Gtk.isDispatch.set(false);
|
||||
}
|
||||
|
@ -29,7 +29,9 @@ class AwtMenuItemCheckbox implements CheckboxPeer {
|
||||
private final AwtMenu parent;
|
||||
private final java.awt.CheckboxMenuItem _native = new java.awt.CheckboxMenuItem();
|
||||
|
||||
private volatile ActionListener swingCallback;
|
||||
// these have to be volatile, because they can be changed from any thread
|
||||
private volatile ActionListener callback;
|
||||
private volatile boolean isChecked = false;
|
||||
|
||||
// this is ALWAYS called on the EDT.
|
||||
AwtMenuItemCheckbox(final AwtMenu parent) {
|
||||
@ -64,15 +66,20 @@ class AwtMenuItemCheckbox implements CheckboxPeer {
|
||||
@Override
|
||||
public
|
||||
void setCallback(final Checkbox menuItem) {
|
||||
if (swingCallback != null) {
|
||||
_native.removeActionListener(swingCallback);
|
||||
if (callback != null) {
|
||||
_native.removeActionListener(callback);
|
||||
}
|
||||
|
||||
if (menuItem.getCallback() != null) {
|
||||
swingCallback = new ActionListener() {
|
||||
callback = menuItem.getCallback(); // can be set to null
|
||||
|
||||
if (callback != null) {
|
||||
callback = new ActionListener() {
|
||||
@Override
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
// this will run on the EDT, since we are calling it from the EDT
|
||||
menuItem.setChecked(!isChecked);
|
||||
|
||||
// we want it to run on the EDT, but with our own action event info (so it is consistent across all platforms)
|
||||
ActionListener cb = menuItem.getCallback();
|
||||
if (cb != null) {
|
||||
@ -85,10 +92,7 @@ class AwtMenuItemCheckbox implements CheckboxPeer {
|
||||
}
|
||||
};
|
||||
|
||||
_native.addActionListener(swingCallback);
|
||||
}
|
||||
else {
|
||||
swingCallback = null;
|
||||
_native.addActionListener(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,12 +114,14 @@ class AwtMenuItemCheckbox implements CheckboxPeer {
|
||||
|
||||
@Override
|
||||
public
|
||||
void setChecked(final Checkbox checkbox) {
|
||||
void setChecked(final Checkbox menuItem) {
|
||||
this.isChecked = menuItem.getChecked();
|
||||
|
||||
SwingUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
_native.setState(checkbox.getChecked());
|
||||
_native.setState(isChecked);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -131,9 +137,9 @@ class AwtMenuItemCheckbox implements CheckboxPeer {
|
||||
_native.deleteShortcut();
|
||||
_native.setEnabled(false);
|
||||
|
||||
if (swingCallback != null) {
|
||||
_native.removeActionListener(swingCallback);
|
||||
swingCallback = null;
|
||||
if (callback != null) {
|
||||
_native.removeActionListener(callback);
|
||||
callback = null;
|
||||
}
|
||||
parent._native.remove(_native);
|
||||
|
||||
|
@ -26,8 +26,8 @@ import dorkbox.systemTray.util.ImageUtils;
|
||||
|
||||
abstract
|
||||
class GtkBaseMenuItem implements EntryPeer {
|
||||
private static File transparentIcon = null;
|
||||
// these are necessary BECAUSE GTK menus look funky as hell when there are some menu entries WITH icons and some WITHOUT
|
||||
private static File transparentIcon = null;
|
||||
private volatile boolean hasLegitImage = true;
|
||||
|
||||
// these have to be volatile, because they can be changed from any thread
|
||||
|
@ -15,8 +15,8 @@
|
||||
*/
|
||||
package dorkbox.systemTray.nativeUI;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
|
||||
import com.sun.jna.NativeLong;
|
||||
import com.sun.jna.Pointer;
|
||||
@ -27,18 +27,16 @@ import dorkbox.systemTray.jna.linux.GCallback;
|
||||
import dorkbox.systemTray.jna.linux.Gobject;
|
||||
import dorkbox.systemTray.jna.linux.Gtk;
|
||||
import dorkbox.systemTray.peer.CheckboxPeer;
|
||||
import dorkbox.systemTray.util.ImageUtils;
|
||||
|
||||
class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCallback {
|
||||
private static File transparentIcon = null;
|
||||
|
||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||
private final NativeLong nativeLong;
|
||||
|
||||
private final GtkMenu parent;
|
||||
|
||||
// these have to be volatile, because they can be changed from any thread
|
||||
private volatile Checkbox checkbox;
|
||||
private volatile ActionListener callback;
|
||||
private volatile boolean isChecked = false;
|
||||
private volatile Pointer image;
|
||||
|
||||
// The mnemonic will ONLY show-up once a menu entry is selected. IT WILL NOT show up before then!
|
||||
@ -54,11 +52,6 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
super(Gtk.gtk_check_menu_item_new_with_mnemonic(""));
|
||||
this.parent = parent;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
nativeLong = Gobject.g_signal_connect_object(_native, "activate", this, null, 0);
|
||||
}
|
||||
|
||||
@ -66,15 +59,9 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
@Override
|
||||
public
|
||||
int callback(final Pointer instance, final Pointer data) {
|
||||
if (checkbox != null) {
|
||||
final ActionListener cb = checkbox.getCallback();
|
||||
if (cb != null) {
|
||||
try {
|
||||
Gtk.proxyClick(checkbox, cb);
|
||||
} catch (Exception e) {
|
||||
SystemTray.logger.error("Error calling menu entry checkbox {} click event.", checkbox.getText(), e);
|
||||
}
|
||||
}
|
||||
if (callback != null) {
|
||||
// this will redispatch to our created callback via `setCallback`
|
||||
Gtk.proxyClick(null, callback);
|
||||
}
|
||||
|
||||
return Gtk.TRUE;
|
||||
@ -135,30 +122,54 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
public
|
||||
void setCallback(final Checkbox checkbox) {
|
||||
this.checkbox = checkbox;
|
||||
void setCallback(final Checkbox menuItem) {
|
||||
callback = menuItem.getCallback(); // can be set to null
|
||||
|
||||
if (callback != null) {
|
||||
callback = new ActionListener() {
|
||||
@Override
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
// this will run on the EDT, since we are calling it from the EDT
|
||||
menuItem.setChecked(!isChecked);
|
||||
|
||||
// we want it to run on the EDT, but with our own action event info (so it is consistent across all platforms)
|
||||
ActionListener cb = menuItem.getCallback();
|
||||
if (cb != null) {
|
||||
try {
|
||||
cb.actionPerformed(new ActionEvent(menuItem, ActionEvent.ACTION_PERFORMED, ""));
|
||||
} catch (Throwable throwable) {
|
||||
SystemTray.logger.error("Error calling menu entry {} click event.", menuItem.getText(), throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void setChecked(final Checkbox checkbox) {
|
||||
this.isChecked = checkbox.getChecked();
|
||||
|
||||
Gtk.dispatch(new Runnable() {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
Gtk.gtk_check_menu_item_set_active(_native, checkbox.getChecked());
|
||||
Gtk.gtk_check_menu_item_set_active(_native, isChecked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void setShortcut(final Checkbox menuItem) {
|
||||
this.mnemonicKey = Character.toLowerCase(menuItem.getShortcut());
|
||||
void setShortcut(final Checkbox checkbox) {
|
||||
this.mnemonicKey = Character.toLowerCase(checkbox.getShortcut());
|
||||
|
||||
setText(menuItem);
|
||||
setText(checkbox);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@ -177,7 +188,6 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
Gtk.gtk_container_remove(_native, image); // will automatically get destroyed if no other references to it
|
||||
image = null;
|
||||
}
|
||||
checkbox = null;
|
||||
|
||||
parent.remove(GtkMenuItemCheckbox.this);
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ class SwingMenuItemCheckbox implements CheckboxPeer {
|
||||
private final SwingMenu parent;
|
||||
private final JMenuItem _native = new AdjustedJMenuItem();
|
||||
|
||||
// these have to be volatile, because they can be changed from any thread
|
||||
private volatile ActionListener callback;
|
||||
private volatile boolean isChecked = false;
|
||||
|
||||
private volatile ActionListener swingCallback;
|
||||
|
||||
private static ImageIcon checkedIcon;
|
||||
private static ImageIcon uncheckedIcon;
|
||||
|
||||
@ -79,33 +79,38 @@ class SwingMenuItemCheckbox implements CheckboxPeer {
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
public
|
||||
void setCallback(final Checkbox menuItem) {
|
||||
if (swingCallback != null) {
|
||||
_native.removeActionListener(swingCallback);
|
||||
if (callback != null) {
|
||||
_native.removeActionListener(callback);
|
||||
}
|
||||
|
||||
swingCallback = new ActionListener() {
|
||||
@Override
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
// this will run on the EDT, since we are calling it from the EDT
|
||||
menuItem.setChecked(!isChecked);
|
||||
callback = menuItem.getCallback(); // can be set to null
|
||||
|
||||
// we want it to run on the EDT, but with our own action event info (so it is consistent across all platforms)
|
||||
ActionListener cb = menuItem.getCallback();
|
||||
if (cb != null) {
|
||||
try {
|
||||
cb.actionPerformed(new ActionEvent(menuItem, ActionEvent.ACTION_PERFORMED, ""));
|
||||
} catch (Throwable throwable) {
|
||||
SystemTray.logger.error("Error calling menu entry {} click event.", menuItem.getText(), throwable);
|
||||
if (callback != null) {
|
||||
callback = new ActionListener() {
|
||||
@Override
|
||||
public
|
||||
void actionPerformed(ActionEvent e) {
|
||||
// this will run on the EDT, since we are calling it from the EDT
|
||||
menuItem.setChecked(!isChecked);
|
||||
|
||||
// we want it to run on the EDT, but with our own action event info (so it is consistent across all platforms)
|
||||
ActionListener cb = menuItem.getCallback();
|
||||
if (cb != null) {
|
||||
try {
|
||||
cb.actionPerformed(new ActionEvent(menuItem, ActionEvent.ACTION_PERFORMED, ""));
|
||||
} catch (Throwable throwable) {
|
||||
SystemTray.logger.error("Error calling menu entry {} click event.", menuItem.getText(), throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
_native.addActionListener(swingCallback);
|
||||
_native.addActionListener(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,9 +155,9 @@ class SwingMenuItemCheckbox implements CheckboxPeer {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
if (swingCallback != null) {
|
||||
_native.removeActionListener(swingCallback);
|
||||
swingCallback = null;
|
||||
if (callback != null) {
|
||||
_native.removeActionListener(callback);
|
||||
callback = null;
|
||||
}
|
||||
|
||||
parent._native.remove(_native);
|
||||
|
Loading…
Reference in New Issue
Block a user