Make Cryptomator a foreground app when restoring from status bar icon

This commit is contained in:
Sebastian Stenzel
2016-08-29 20:14:48 +02:00
parent 21d70b5ae4
commit dc58ba434a
7 changed files with 111 additions and 2 deletions
@@ -8,11 +8,13 @@
*******************************************************************************/
package org.cryptomator.ui;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import javax.inject.Singleton;
import org.cryptomator.ui.controllers.MainController;
import org.cryptomator.ui.jni.MacFunctions;
import org.cryptomator.ui.settings.Localization;
import org.cryptomator.ui.util.AsyncTaskService;
import org.cryptomator.ui.util.DeferredCloser;
@@ -34,4 +36,6 @@ interface CryptomatorComponent {
Localization localization();
ExitUtil exitUtil();
Optional<MacFunctions> nativeMacFunctions();
}
@@ -19,6 +19,7 @@ import org.cryptomator.crypto.engine.impl.CryptoEngineModule;
import org.cryptomator.frontend.FrontendFactory;
import org.cryptomator.frontend.webdav.WebDavModule;
import org.cryptomator.frontend.webdav.WebDavServer;
import org.cryptomator.ui.jni.JniModule;
import org.cryptomator.ui.model.VaultObjectMapperProvider;
import org.cryptomator.ui.settings.Settings;
import org.cryptomator.ui.settings.SettingsProvider;
@@ -33,7 +34,7 @@ import dagger.Provides;
import javafx.application.Application;
import javafx.stage.Stage;
@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class})
@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class, JniModule.class})
class CryptomatorModule {
private static final Logger LOG = LoggerFactory.getLogger(CryptomatorModule.class);
@@ -21,6 +21,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@@ -32,6 +33,8 @@ import javax.script.ScriptException;
import javax.swing.SwingUtilities;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.ui.jni.JniException;
import org.cryptomator.ui.jni.MacFunctions;
import org.cryptomator.ui.settings.Localization;
import org.cryptomator.ui.settings.Settings;
import org.slf4j.Logger;
@@ -48,12 +51,14 @@ class ExitUtil {
private final Stage mainWindow;
private final Localization localization;
private final Settings settings;
private final Optional<MacFunctions> macFunctions;
@Inject
public ExitUtil(@Named("mainWindow") Stage mainWindow, Localization localization, Settings settings) {
public ExitUtil(@Named("mainWindow") Stage mainWindow, Localization localization, Settings settings, Optional<MacFunctions> macFunctions) {
this.mainWindow = mainWindow;
this.localization = localization;
this.settings = settings;
this.macFunctions = macFunctions;
}
public void initExitHandler(Runnable exitCommand) {
@@ -88,6 +93,7 @@ class ExitUtil {
if (Platform.isImplicitExit()) {
exitCommand.run();
} else {
macFunctions.ifPresent(JniException.ignore(MacFunctions::transformToAgentApplication));
mainWindow.close();
this.showTrayNotification(trayIcon);
}
@@ -189,6 +195,7 @@ class ExitUtil {
private void restoreFromTray(ActionEvent event) {
Platform.runLater(() -> {
macFunctions.ifPresent(JniException.ignore(MacFunctions::transformToForegroundApplication));
mainWindow.show();
mainWindow.requestFocus();
});
@@ -16,6 +16,8 @@ import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.ui.controllers.MainController;
import org.cryptomator.ui.jni.JniException;
import org.cryptomator.ui.jni.MacFunctions;
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
import org.cryptomator.ui.util.DeferredCloser;
import org.cryptomator.ui.util.SingleInstanceManager;
@@ -67,6 +69,7 @@ public class MainApplication extends Application {
}
// show window and start observing its focus:
comp.nativeMacFunctions().ifPresent(JniException.ignore(MacFunctions::transformToForegroundApplication));
primaryStage.show();
ActiveWindowStyleSupport.startObservingFocus(primaryStage);
comp.exitUtil().initExitHandler(this::quit);
@@ -0,0 +1,24 @@
package org.cryptomator.ui.jni;
import java.util.function.Consumer;
/**
* Thrown to indicate that a JNI call didn't succeed, i.e. returned an unexpected return value.
*/
public class JniException extends RuntimeException {
protected JniException(String message) {
super(message);
}
public static <T> Consumer<T> ignore(Consumer<T> consumer) {
return value -> {
try {
consumer.accept(value);
} catch (RuntimeException e) {
// no-op
}
};
}
}
@@ -0,0 +1,33 @@
package org.cryptomator.ui.jni;
import java.util.Optional;
import javax.inject.Singleton;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dagger.Module;
import dagger.Provides;
@Module
public class JniModule {
private static final Logger LOG = LoggerFactory.getLogger(JniModule.class);
@Provides
@Singleton
Optional<MacFunctions> provideMacFunctions(MacFunctions macFunctions) {
if (SystemUtils.IS_OS_MAC) {
try {
System.loadLibrary("MacFunctions");
return Optional.of(macFunctions);
} catch (UnsatisfiedLinkError e) {
LOG.error("Could not load JNI lib from path {}", System.getProperty("java.library.path"));
}
}
return Optional.empty();
}
}
@@ -0,0 +1,37 @@
package org.cryptomator.ui.jni;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class MacFunctions {
@Inject
MacFunctions() {
}
/**
* Makes the current application a foreground application, which appears in the Dock and the Application Switcher.
*/
public void transformToForegroundApplication() {
int errorCode = transformToForegroundApplication0();
if (errorCode != 0) {
throw new JniException("Failed to make app a foreground app. Error code " + errorCode);
}
}
private native int transformToForegroundApplication0();
/**
* Makes the current application an agent app. Agent apps do not appear in the Dock or in the Force Quit window.
*/
public void transformToAgentApplication() {
int errorCode = transformToAgentApplication0();
if (errorCode != 0) {
throw new JniException("Failed to make app an agent app. Error code " + errorCode);
}
}
private native int transformToAgentApplication0();
}