mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-18 10:41:26 +00:00
macOS: Only show application menu and dock icon when a Window is visible (related to #957, #283, #346, #62)
This commit is contained in:
@@ -3,11 +3,16 @@ package org.cryptomator.ui.fxapp;
|
||||
import dagger.Lazy;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableSet;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.UiTheme;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.jni.MacApplicationUiState;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
@@ -31,6 +36,8 @@ public class FxApplication extends Application {
|
||||
private final UnlockComponent.Builder unlockWindowBuilder;
|
||||
private final QuitComponent.Builder quitWindowBuilder;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
private final ObservableSet<Stage> visibleStages = FXCollections.observableSet();
|
||||
private final BooleanBinding hasVisibleStages = Bindings.isNotEmpty(visibleStages);
|
||||
|
||||
@Inject
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, UnlockComponent.Builder unlockWindowBuilder, QuitComponent.Builder quitWindowBuilder, Optional<MacFunctions> macFunctions) {
|
||||
@@ -46,6 +53,8 @@ public class FxApplication extends Application {
|
||||
LOG.trace("FxApplication.start()");
|
||||
Platform.setImplicitExit(false);
|
||||
|
||||
hasVisibleStages.addListener(this::hasVisibleStagesChanged);
|
||||
|
||||
settings.theme().addListener(this::themeChanged);
|
||||
loadSelectedStyleSheet(settings.theme().get());
|
||||
}
|
||||
@@ -55,30 +64,47 @@ public class FxApplication extends Application {
|
||||
throw new UnsupportedOperationException("Use start() instead.");
|
||||
}
|
||||
|
||||
private void addVisibleStage(Stage stage) {
|
||||
visibleStages.add(stage);
|
||||
stage.setOnHidden(evt -> visibleStages.remove(stage));
|
||||
}
|
||||
|
||||
private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue<? extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
|
||||
if (newValue) {
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToForegroundApplication);
|
||||
} else {
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToAgentApplication);
|
||||
}
|
||||
}
|
||||
|
||||
public void showPreferencesWindow() {
|
||||
Platform.runLater(() -> {
|
||||
preferencesWindow.get().showPreferencesWindow();
|
||||
Stage stage = preferencesWindow.get().showPreferencesWindow();
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing Preferences");
|
||||
});
|
||||
}
|
||||
|
||||
public void showMainWindow() {
|
||||
Platform.runLater(() -> {
|
||||
mainWindow.get().showMainWindow();
|
||||
Stage stage = mainWindow.get().showMainWindow();
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing MainWindow");
|
||||
});
|
||||
}
|
||||
|
||||
public void showUnlockWindow(Vault vault) {
|
||||
Platform.runLater(() -> {
|
||||
unlockWindowBuilder.vault(vault).build().showUnlockWindow();
|
||||
Stage stage = unlockWindowBuilder.vault(vault).build().showUnlockWindow();
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing UnlockWindow for {}", vault.getDisplayableName());
|
||||
});
|
||||
}
|
||||
|
||||
public void showQuitWindow(QuitResponse response) {
|
||||
Platform.runLater(() -> {
|
||||
quitWindowBuilder.quitResponse(response).build().showQuitWindow();
|
||||
Stage stage = quitWindowBuilder.quitResponse(response).build().showQuitWindow();
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing QuitWindow");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@ public interface MainWindowComponent {
|
||||
@FxmlScene(FxmlFile.MAIN_WINDOW)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showMainWindow() {
|
||||
default Stage showMainWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.show();
|
||||
stage.requestFocus();
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
||||
@@ -23,11 +23,12 @@ public interface PreferencesComponent {
|
||||
@FxmlScene(FxmlFile.PREFERENCES)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showPreferencesWindow() {
|
||||
default Stage showPreferencesWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.show();
|
||||
stage.requestFocus();
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
||||
@@ -25,11 +25,12 @@ public interface QuitComponent {
|
||||
@FxmlScene(FxmlFile.QUIT)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showQuitWindow() {
|
||||
default Stage showQuitWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.show();
|
||||
stage.requestFocus();
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
||||
@@ -3,6 +3,9 @@ package org.cryptomator.ui.traymenu;
|
||||
import javafx.beans.Observable;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.jni.JniException;
|
||||
import org.cryptomator.jni.MacApplicationUiState;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -10,6 +13,7 @@ import javax.inject.Inject;
|
||||
import java.awt.AWTException;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.TrayIcon;
|
||||
import java.util.Optional;
|
||||
|
||||
@TrayMenuScoped
|
||||
public class TrayIconController {
|
||||
@@ -20,15 +24,15 @@ public class TrayIconController {
|
||||
private final TrayImageFactory imageFactory;
|
||||
private final TrayMenuController trayMenuController;
|
||||
private final TrayIcon trayIcon;
|
||||
// private final Optional<MacFunctions> macFunctions;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
|
||||
@Inject
|
||||
TrayIconController(Settings settings, TrayImageFactory imageFactory, TrayMenuController trayMenuController) {
|
||||
TrayIconController(Settings settings, TrayImageFactory imageFactory, TrayMenuController trayMenuController, Optional<MacFunctions> macFunctions) {
|
||||
this.settings = settings;
|
||||
this.trayMenuController = trayMenuController;
|
||||
this.imageFactory = imageFactory;
|
||||
this.trayIcon = new TrayIcon(imageFactory.loadImage(), "Cryptomator", trayMenuController.getMenu());
|
||||
// this.macFunctions = macFunctions;
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
public void initializeTrayIcon() {
|
||||
@@ -38,6 +42,8 @@ public class TrayIconController {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
// TODO: test on windows: is this a double click?
|
||||
trayIcon.addActionListener(trayMenuController::showMainWindow);
|
||||
} else if (SystemUtils.IS_OS_MAC) {
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToAgentApplication));
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -24,10 +24,11 @@ public interface UnlockComponent {
|
||||
@FxmlScene(FxmlFile.UNLOCK)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showUnlockWindow() {
|
||||
default Stage showUnlockWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.show();
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
||||
Reference in New Issue
Block a user