Thread safety when quitting the application: Altering vault states (unlocking/locking/...) will now trigger a listener (on the fx application thread) which sets an AtomicBoolean. Previously the value has been read by an AWT thread from a (non-volatile) BooleanBinding

This commit is contained in:
Sebastian Stenzel
2019-08-29 17:13:32 +02:00
parent 5196dbe9af
commit 73314ee985
@@ -1,13 +1,10 @@
package org.cryptomator.ui.traymenu; package org.cryptomator.ui.traymenu;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.fxapp.FxApplication; import org.cryptomator.ui.fxapp.FxApplication;
import org.fxmisc.easybind.EasyBind;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@@ -15,13 +12,13 @@ import java.awt.Desktop;
import java.awt.Menu; import java.awt.Menu;
import java.awt.MenuItem; import java.awt.MenuItem;
import java.awt.PopupMenu; import java.awt.PopupMenu;
import java.awt.desktop.QuitEvent;
import java.awt.desktop.QuitResponse; import java.awt.desktop.QuitResponse;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.EventObject; import java.util.EventObject;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer; import java.util.function.Consumer;
@TrayMenuScoped @TrayMenuScoped
@@ -33,7 +30,7 @@ class TrayMenuController {
private final Settings settings; private final Settings settings;
private final ObservableList<Vault> vaults; private final ObservableList<Vault> vaults;
private final PopupMenu menu; private final PopupMenu menu;
private final BooleanBinding allLocked; private final AtomicBoolean allVaultsAreLocked;
@Inject @Inject
TrayMenuController(ResourceBundle resourceBundle, FxApplicationStarter fxApplicationStarter, @Named("shutdownLatch") CountDownLatch shutdownLatch, Settings settings, ObservableList<Vault> vaults) { TrayMenuController(ResourceBundle resourceBundle, FxApplicationStarter fxApplicationStarter, @Named("shutdownLatch") CountDownLatch shutdownLatch, Settings settings, ObservableList<Vault> vaults) {
@@ -43,7 +40,7 @@ class TrayMenuController {
this.settings = settings; this.settings = settings;
this.vaults = vaults; this.vaults = vaults;
this.menu = new PopupMenu(); this.menu = new PopupMenu();
this.allLocked = Bindings.isEmpty(vaults.filtered(Vault::isUnlocked)); // TODO better use Vault::isNotLocked ;) this.allVaultsAreLocked = new AtomicBoolean();
} }
public PopupMenu getMenu() { public PopupMenu getMenu() {
@@ -73,6 +70,7 @@ class TrayMenuController {
private void vaultListChanged(@SuppressWarnings("unused") Observable observable) { private void vaultListChanged(@SuppressWarnings("unused") Observable observable) {
rebuildMenu(); rebuildMenu();
allVaultsAreLocked.set(vaults.stream().allMatch(Vault::isLocked));
} }
private void rebuildMenu() { private void rebuildMenu() {
@@ -134,7 +132,7 @@ class TrayMenuController {
} }
private void handleQuitRequest(EventObject e, QuitResponse response) { private void handleQuitRequest(EventObject e, QuitResponse response) {
if (allLocked.get()) { if (allVaultsAreLocked.get()) {
response.performQuit(); // really? response.performQuit(); // really?
} else { } else {
fxApplicationStarter.get(true).thenAccept(app -> app.showQuitWindow(response)); fxApplicationStarter.get(true).thenAccept(app -> app.showQuitWindow(response));