This commit is contained in:
crschnick 2024-06-19 16:10:21 +00:00
parent 1f7174db86
commit cecc6b0880
38 changed files with 183 additions and 96 deletions

View file

@ -12,6 +12,7 @@ import io.xpipe.core.util.XPipeInstallation;
import lombok.Getter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@ -110,7 +111,7 @@ public class AppBeaconServer {
}
private void start() throws IOException {
server = HttpServer.create(new InetSocketAddress("localhost", port), 10);
server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), port), 10);
BeaconInterface.getAll().forEach(beaconInterface -> {
server.createContext(beaconInterface.getPath(), new BeaconRequestHandler<>(beaconInterface));
});

View file

@ -3,7 +3,7 @@ package io.xpipe.app.browser;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.core.AppStyle;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.browser.file;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FileSystem;

View file

@ -10,7 +10,7 @@ import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.BindingsHelper;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.comp.base;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.CompStructure;
import io.xpipe.app.fxcomps.SimpleCompStructure;

View file

@ -5,7 +5,7 @@ import io.xpipe.app.comp.base.DialogComp;
import io.xpipe.app.comp.base.ErrorOverlayComp;
import io.xpipe.app.comp.base.PopupMenuButtonComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.fxcomps.Comp;

View file

@ -1,16 +1,16 @@
package io.xpipe.app.core;
import io.xpipe.app.comp.AppLayoutComp;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.LicenseProvider;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.stage.Stage;
import lombok.Getter;
import lombok.SneakyThrows;

View file

@ -1,5 +1,6 @@
package io.xpipe.app.core;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.launcher.LauncherInput;
import javafx.scene.control.Alert;

View file

@ -2,6 +2,7 @@ package io.xpipe.app.core;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import javafx.beans.property.SimpleBooleanProperty;

View file

@ -1,6 +1,7 @@
package io.xpipe.app.core;
import io.xpipe.app.comp.base.ModalOverlayComp;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.fxcomps.impl.TooltipAugment;
import io.xpipe.app.issue.ErrorEvent;

View file

@ -1,29 +1,28 @@
package io.xpipe.app.core;
import atlantafx.base.theme.*;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.process.OsType;
import javafx.animation.*;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.ColorScheme;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.css.PseudoClass;
import javafx.event.EventHandler;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.stage.WindowEvent;
import javafx.util.Duration;
import atlantafx.base.theme.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.SneakyThrows;
@ -45,8 +44,6 @@ public class AppTheme {
return;
}
initWindowsThemeHandler(stage);
Runnable r = () -> {
AppPrefs.get().theme.subscribe(t -> {
Theme.ALL.forEach(
@ -74,46 +71,6 @@ public class AppTheme {
}
}
private static void initWindowsThemeHandler(Window stage) {
if (OsType.getLocal() != OsType.WINDOWS) {
return;
}
EventHandler<WindowEvent> windowTheme = new EventHandler<>() {
@Override
public void handle(WindowEvent event) {
if (!stage.isShowing()) {
return;
}
try {
// var c = new WindowControl(stage);
// c.setWindowAttribute(20, AppPrefs.get().theme.getValue().isDark());
// c.setWindowAttribute(34, 0xFFFFFFFEL);
// c.redraw();
} catch (Throwable e) {
ErrorEvent.fromThrowable(e).handle();
}
stage.removeEventFilter(WindowEvent.WINDOW_SHOWN, this);
}
};
if (stage.isShowing()) {
windowTheme.handle(null);
} else {
stage.addEventFilter(WindowEvent.WINDOW_SHOWN, windowTheme);
}
AppPrefs.get().theme.addListener((observable, oldValue, newValue) -> {
Platform.runLater(() -> {
var transition = new PauseTransition(Duration.millis(300));
transition.setOnFinished(e -> {
windowTheme.handle(null);
});
transition.play();
});
});
}
public static void init() {
if (init) {
return;

View file

@ -3,6 +3,7 @@ package io.xpipe.app.core.check;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.*;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.util.PlatformState;
import io.xpipe.app.util.WindowsRegistry;
import io.xpipe.core.process.OsType;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.core.check;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import javafx.scene.control.Alert;

View file

@ -4,7 +4,7 @@ import io.xpipe.app.browser.file.LocalFileSystem;
import io.xpipe.app.browser.icon.FileIconManager;
import io.xpipe.app.core.App;
import io.xpipe.app.core.AppGreetings;
import io.xpipe.app.core.AppMainWindow;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.core.check.AppPtbCheck;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.issue.ErrorEvent;

View file

@ -3,6 +3,7 @@ package io.xpipe.app.core.mode;
import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.*;
import io.xpipe.app.core.check.AppFontLoadingCheck;
import io.xpipe.app.core.window.ModifiedStage;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.UpdateAvailableAlert;
@ -34,6 +35,7 @@ public abstract class PlatformMode extends OperationMode {
AppStyle.init();
AppImages.init();
AppLayoutModel.init();
ModifiedStage.hook();
TrackEvent.info("Finished essential component initialization before platform");
TrackEvent.info("Launching application ...");

View file

@ -1,5 +1,9 @@
package io.xpipe.app.core;
package io.xpipe.app.core.window;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppImages;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppTheme;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
@ -7,7 +11,6 @@ import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.prefs.CloseBehaviourAlert;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Rectangle2D;
@ -15,20 +18,21 @@ import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import lombok.Builder;
import lombok.Getter;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import javax.imageio.ImageIO;
public class AppMainWindow {
@ -48,6 +52,8 @@ public class AppMainWindow {
public static AppMainWindow init(Stage stage) {
INSTANCE = new AppMainWindow(stage);
var scene = new Scene(new Region(), -1, -1, false);
scene.setFill(Color.TRANSPARENT);
stage.initStyle(StageStyle.UNIFIED);
stage.setScene(scene);
AppWindowHelper.setupStylesheets(stage.getScene());
return INSTANCE;

View file

@ -1,6 +1,7 @@
package io.xpipe.app.core;
package io.xpipe.app.core.window;
import io.xpipe.app.comp.base.LoadingOverlayComp;
import io.xpipe.app.core.*;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;

View file

@ -0,0 +1,17 @@
package io.xpipe.app.core.window;
import lombok.Getter;
@Getter
public enum DmwaWindowAttribute {
DWMWA_USE_IMMERSIVE_DARK_MODE(20),
DWMWA_BORDER_COLOR(34),
DWMWA_SYSTEMBACKDROP_TYPE(38),
DWMWA_WINDOW_CORNER_PREFERENCE(33);
private final int value;
DmwaWindowAttribute(int value) {
this.value = value;
}
}

View file

@ -0,0 +1,18 @@
package io.xpipe.app.core.window;
public enum DwmSystemBackDropType {
NONE(1),
MICA(2),
MICA_ALT(4),
ACRYLIC(3);
private final int value;
DwmSystemBackDropType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View file

@ -0,0 +1,41 @@
package io.xpipe.app.core.window;
import javafx.scene.control.Alert;
import javafx.scene.control.Dialog;
import javafx.stage.Stage;
import javafx.stage.Window;
import lombok.SneakyThrows;
public class ModifiedAlertStage {
@SneakyThrows
public static void setForAlert(Alert alert) {
var dialogClass = Dialog.class;
var dialogField = dialogClass.getDeclaredField("dialog");
dialogField.setAccessible(true);
var dialog = (Dialog<?>) dialogField.get(alert);
var c = Class.forName("javafx.scene.control.HeavyweightDialog");
var positionStageMethod = c.getDeclaredMethod("positionStage");
positionStageMethod.setAccessible(true);
var stageField = c.getDeclaredField("stage");
stageField.setAccessible(true);
var m = new Stage() {
@SneakyThrows
@Override public void centerOnScreen() {
Window owner = getOwner();
if (owner != null) {
positionStageMethod.invoke(dialog);
} else {
if (getWidth() > 0 && getHeight() > 0) {
super.centerOnScreen();
}
}
}
};
stageField.set(alert,m);
}
}

View file

@ -0,0 +1,38 @@
package io.xpipe.app.core.window;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.process.OsType;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
import javafx.stage.Window;
import lombok.SneakyThrows;
public class ModifiedStage extends Stage {
@SneakyThrows
@SuppressWarnings("unchecked")
public static void hook() {
var windowsField = Window.class.getDeclaredField("windows");
windowsField.setAccessible(true);
ObservableList<Window> list = (ObservableList<Window>) windowsField.get(null);
list.addListener((ListChangeListener<Window>) c -> {
if (c.next() && c.wasAdded()) {
var added = c.getAddedSubList().getFirst();
if (added instanceof Stage stage) {
applyStage(stage);
}
}
});
}
private static void applyStage(Stage stage) {
if (OsType.getLocal() != OsType.WINDOWS) {
return;
}
var ctrl = new NativeWinWindowControl(stage);
ctrl.setWindowAttribute(DmwaWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE.getValue(), AppPrefs.get().theme.getValue().isDark());
ctrl.setWindowBackdrop(DwmSystemBackDropType.ACRYLIC);
}
}

View file

@ -1,25 +1,25 @@
package io.xpipe.app.util;
import javafx.stage.Window;
package io.xpipe.app.core.window;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import javafx.stage.Window;
import lombok.Getter;
import lombok.SneakyThrows;
import java.lang.reflect.Method;
@Getter
public class WindowControl {
public class NativeWinWindowControl {
private final WinDef.HWND windowHandle;
public WindowControl(Window stage) throws Exception {
Method tkStageGetter = stage.getClass().getSuperclass().getDeclaredMethod("getPeer");
@SneakyThrows
public NativeWinWindowControl(Window stage) {
Method tkStageGetter = Window.class.getDeclaredMethod("getPeer");
tkStageGetter.setAccessible(true);
Object tkStage = tkStageGetter.invoke(stage);
Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow");
@ -32,7 +32,7 @@ public class WindowControl {
this.windowHandle = hwnd;
}
public WindowControl(WinDef.HWND windowHandle) {
public NativeWinWindowControl(WinDef.HWND windowHandle) {
this.windowHandle = windowHandle;
}
@ -53,14 +53,18 @@ public class WindowControl {
WinDef.DWORD.SIZE);
}
public void redraw() {
User32.INSTANCE.RedrawWindow(
windowHandle, null, null, new WinDef.DWORD(User32.RDW_FRAME | User32.RDW_VALIDATE));
public void setWindowBackdrop(DwmSystemBackDropType backdrop) {
DwmSupport.INSTANCE.DwmSetWindowAttribute(
windowHandle,
DmwaWindowAttribute.DWMWA_SYSTEMBACKDROP_TYPE.getValue(),
new WinDef.DWORDByReference(new WinDef.DWORD(backdrop.getValue())),
WinDef.DWORD.SIZE
);
}
public interface DwmSupport extends Library {
DwmSupport INSTANCE = Native.load("dwmapi", DwmSupport.class);
DwmSupport INSTANCE = com.sun.jna.Native.load("dwmapi", DwmSupport.class);
WinNT.HRESULT DwmSetWindowAttribute(
WinDef.HWND hwnd, int dwAttribute, PointerType pvAttribute, int cbAttribute);

View file

@ -4,7 +4,7 @@ import io.xpipe.app.browser.session.BrowserChooserComp;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.CompStructure;
import io.xpipe.app.fxcomps.SimpleCompStructure;

View file

@ -5,7 +5,7 @@ import io.xpipe.app.comp.base.TitledPaneComp;
import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.augment.GrowAugment;

View file

@ -2,6 +2,7 @@ package io.xpipe.app.issue;
import io.xpipe.app.core.*;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.ThreadHelper;

View file

@ -5,6 +5,7 @@ import io.xpipe.app.comp.base.ListSelectorComp;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.comp.base.TitledPaneComp;
import io.xpipe.app.core.*;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;

View file

@ -3,7 +3,7 @@ package io.xpipe.app.prefs;
import io.xpipe.app.comp.base.TileButtonComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.impl.LabelComp;
import io.xpipe.app.fxcomps.impl.VerticalComp;

View file

@ -2,7 +2,7 @@ package io.xpipe.app.prefs;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import javafx.scene.control.Alert;

View file

@ -2,7 +2,7 @@ package io.xpipe.app.prefs;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.ext.PrefsChoiceValue;

View file

@ -2,7 +2,7 @@ package io.xpipe.app.update;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.util.Hyperlinks;
import javafx.event.ActionEvent;

View file

@ -2,7 +2,7 @@ package io.xpipe.app.update;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.Hyperlinks;

View file

@ -3,7 +3,7 @@ package io.xpipe.app.util;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppStyle;
import io.xpipe.app.core.AppTheme;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.impl.SecretFieldComp;
import io.xpipe.core.util.InPlaceSecretValue;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.util;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.impl.LabelComp;
import io.xpipe.app.fxcomps.impl.SecretFieldComp;
import io.xpipe.app.prefs.AppPrefs;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.util;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.util;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.util.ProxyManagerProvider;

View file

@ -3,7 +3,7 @@ package io.xpipe.app.util;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppStyle;
import io.xpipe.app.core.AppTheme;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.impl.SecretFieldComp;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs;

View file

@ -44,6 +44,7 @@ open module io.xpipe.app {
exports io.xpipe.app.browser.session;
exports io.xpipe.app.browser.fs;
exports io.xpipe.app.browser.file;
exports io.xpipe.app.core.window;
requires com.sun.jna;
requires com.sun.jna.platform;

View file

@ -4,6 +4,9 @@
-fx-border-color: red;
}
*/
.root {
-fx-background-color: transparent;
}
.toggle-switch:has-graphic .label {
-fx-font-size: 1.7em;
@ -17,14 +20,6 @@
-fx-background-color: transparent;
}
.root:dark.background {
-fx-background-color: derive(-color-bg-default, 1%);
}
.root:light.background {
-fx-background-color: derive(-color-bg-default, -9%);
}
.edit-button.icon-button-comp {
-fx-background-radius: 4px;
-fx-border-width: 1px;