fix for GTK triggering events when setting the checkbox state. Added

checks to only dispatch events if the checkbox state is actually
changed.
This commit is contained in:
nathan 2017-01-19 01:23:36 +01:00
parent 76b006023c
commit 8d1e4bddaf
3 changed files with 71 additions and 31 deletions

View File

@ -115,7 +115,11 @@ class AwtMenuItemCheckbox implements CheckboxPeer {
@Override @Override
public public
void setChecked(final Checkbox menuItem) { void setChecked(final Checkbox menuItem) {
this.isChecked = menuItem.getChecked(); boolean checked = menuItem.getChecked();
// only dispatch if it's actually different
if (checked != this.isChecked) {
this.isChecked = checked;
SwingUtil.invokeLater(new Runnable() { SwingUtil.invokeLater(new Runnable() {
@Override @Override
@ -125,6 +129,7 @@ class AwtMenuItemCheckbox implements CheckboxPeer {
} }
}); });
} }
}
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")
@Override @Override

View File

@ -17,6 +17,7 @@ package dorkbox.systemTray.nativeUI;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicBoolean;
import com.sun.jna.Pointer; import com.sun.jna.Pointer;
@ -52,7 +53,7 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
Gobject.g_signal_connect_object(_native, "activate", this, null, 0); Gobject.g_signal_connect_object(_native, "activate", this, null, 0);
} }
// called by native code // called by native code ONLY
@Override @Override
public public
int callback(final Pointer instance, final Pointer data) { int callback(final Pointer instance, final Pointer data) {
@ -119,7 +120,11 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
}); });
} }
@SuppressWarnings("Duplicates") AtomicBoolean triggeredSetChecked = new AtomicBoolean(false);
@SuppressWarnings({"Duplicates", "StatementWithEmptyBody"})
@Override @Override
public public
void setCallback(final Checkbox menuItem) { void setCallback(final Checkbox menuItem) {
@ -130,6 +135,13 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
@Override @Override
public public
void actionPerformed(ActionEvent e) { void actionPerformed(ActionEvent e) {
if (triggeredSetChecked.getAndSet(false)) {
// note: changing the state of the checkbox will trigger "activate", which will then trigger the callback. We don't want that.
// we assume this is consistent across ALL versions and variants of GTK
// https://github.com/GNOME/gtk/blob/master/gtk/gtkcheckmenuitem.c#L317
return;
}
// this will run on the EDT, since we are calling it from the EDT // this will run on the EDT, since we are calling it from the EDT
menuItem.setChecked(!isChecked); menuItem.setChecked(!isChecked);
@ -144,22 +156,39 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
} }
} }
}; };
} }
} }
@Override @Override
public public
void setChecked(final Checkbox checkbox) { void setChecked(final Checkbox menuItem) {
this.isChecked = checkbox.getChecked(); boolean checked = menuItem.getChecked();
// only dispatch if it's actually different
if (checked != this.isChecked) {
this.isChecked = checked;
Gtk.dispatch(new Runnable() { Gtk.dispatch(new Runnable() {
@Override @Override
public public
void run() { void run() {
// note: this will trigger "activate", which will then trigger the callback. We don't want to do that, so we hack around it.
// BECAUSE we are on the GTK thread, the "set_active" call is QUEUED... so we check the callback state AFTER this.
// we assume this is consistent across ALL versions and variants of GTK
// https://github.com/GNOME/gtk/blob/master/gtk/gtkcheckmenuitem.c#L317
Gtk.gtk_check_menu_item_set_active(_native, isChecked); Gtk.gtk_check_menu_item_set_active(_native, isChecked);
if (callback != null) {
// only need to worry about this if we have a callback specified.
// This is because of how GTK handles setting the checkbox state + callbacks
triggeredSetChecked.set(true);
}
} }
}); });
} }
}
@Override @Override
public public

View File

@ -132,7 +132,11 @@ class SwingMenuItemCheckbox implements CheckboxPeer {
@Override @Override
public public
void setChecked(final Checkbox menuItem) { void setChecked(final Checkbox menuItem) {
this.isChecked = menuItem.getChecked(); boolean checked = menuItem.getChecked();
// only dispatch if it's actually different
if (checked != this.isChecked) {
this.isChecked = checked;
SwingUtil.invokeLater(new Runnable() { SwingUtil.invokeLater(new Runnable() {
@Override @Override
@ -140,12 +144,14 @@ class SwingMenuItemCheckbox implements CheckboxPeer {
void run() { void run() {
if (isChecked) { if (isChecked) {
_native.setIcon(checkedIcon); _native.setIcon(checkedIcon);
} else { }
else {
_native.setIcon(uncheckedIcon); _native.setIcon(uncheckedIcon);
} }
} }
}); });
} }
}
@Override @Override
public public