From beaa0d01e36f0ddf3bf7b09b7437d773371eb797 Mon Sep 17 00:00:00 2001 From: crschnick Date: Thu, 4 Sep 2025 20:02:53 +0000 Subject: [PATCH] Cleanup --- .../beacon/impl/DaemonFocusExchangeImpl.java | 2 +- .../app/browser/BrowserFullSessionComp.java | 2 +- .../browser/file/BrowserFileOverviewComp.java | 3 +- .../file/BrowserFileSelectionListComp.java | 4 +- .../file/BrowserFileSystemTabModel.java | 2 +- app/src/main/java/io/xpipe/app/comp/Comp.java | 61 ++++++++- app/src/main/java/io/xpipe/app/comp/README.md | 52 +------ .../xpipe/app/comp/augment/GrowAugment.java | 81 ----------- .../comp/base/AppMainWindowContentComp.java | 2 +- .../io/xpipe/app/comp/base/FilterComp.java | 5 +- .../app/comp/base/PrettyImageHelper.java | 4 +- .../xpipe/app/core/AppActionLinkDetector.java | 51 ------- .../xpipe/app/core/AppDesktopIntegration.java | 2 +- .../main/java/io/xpipe/app/core/AppFont.java | 2 + .../java/io/xpipe/app/core/AppFontSizes.java | 4 +- .../main/java/io/xpipe/app/core/AppTheme.java | 2 +- .../app/core/check/AppGnomeScaleDialog.java | 2 +- .../java/io/xpipe/app/core/mode/BaseMode.java | 2 +- .../java/io/xpipe/app/core/mode/GuiMode.java | 2 +- .../io/xpipe/app/core/mode/OperationMode.java | 10 +- .../xpipe/app/core/window/AppMainWindow.java | 50 +++---- .../app/core/window/AppModifiedStage.java | 8 +- .../xpipe/app/core/window/AppSideWindow.java | 97 +++++++++++++ ...pWindowHelper.java => AppWindowStyle.java} | 127 ++++-------------- .../app/hub/comp/DenseStoreEntryComp.java | 3 - .../io/xpipe/app/hub/comp/StoreEntryComp.java | 2 - .../xpipe/app/hub/comp/StoreLayoutComp.java | 10 +- .../io/xpipe/app/issue/ErrorHandlerComp.java | 3 +- .../io/xpipe/app/platform/InputHelper.java | 12 -- .../xpipe/app/terminal/TerminalDockComp.java | 2 +- .../java/io/xpipe/app/util/AskpassAlert.java | 5 +- .../java/io/xpipe/app/util/AsktextAlert.java | 5 +- .../java/io/xpipe/app/util/RemminaHelper.java | 4 +- .../LocalIdentityConvertHubLeafProvider.java | 2 +- 34 files changed, 245 insertions(+), 380 deletions(-) delete mode 100644 app/src/main/java/io/xpipe/app/comp/augment/GrowAugment.java delete mode 100644 app/src/main/java/io/xpipe/app/core/AppActionLinkDetector.java create mode 100644 app/src/main/java/io/xpipe/app/core/window/AppSideWindow.java rename app/src/main/java/io/xpipe/app/core/window/{AppWindowHelper.java => AppWindowStyle.java} (54%) diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java index 02ea966c2..3e84df39a 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java @@ -11,7 +11,7 @@ public class DaemonFocusExchangeImpl extends DaemonFocusExchange { @Override public Object handle(HttpExchange exchange, Request msg) { OperationMode.switchUp(OperationMode.GUI); - var w = AppMainWindow.getInstance(); + var w = AppMainWindow.get(); if (w != null) { w.focus(); } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java index 01dbe98f0..ceaa21c53 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java @@ -75,7 +75,7 @@ public class BrowserFullSessionComp extends SimpleComp { loadingStack.apply(struc -> struc.get().setPickOnBounds(false)); var delayedStack = new DelayedInitComp( left, () -> StoreViewState.get() != null && StoreViewState.get().isInitialized()); - delayedStack.hide(AppMainWindow.getInstance().getStage().widthProperty().lessThan(1000)); + delayedStack.hide(AppMainWindow.get().getStage().widthProperty().lessThan(1000)); var splitPane = new LeftSplitPaneComp(delayedStack, loadingStack) .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) .withOnDividerChange(d -> { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java index 2426b98cd..8b4102045 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.browser.file; import io.xpipe.app.browser.icon.BrowserIcons; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.SimpleComp; -import io.xpipe.app.comp.augment.GrowAugment; import io.xpipe.app.comp.base.HorizontalComp; import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.ext.FileEntry; @@ -42,7 +41,7 @@ public class BrowserFileOverviewComp extends SimpleComp { event.consume(); }); l.setAlignment(Pos.CENTER_LEFT); - GrowAugment.create(true, false).augment(l); + l.setMaxWidth(10000); return l; }); }; diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSelectionListComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSelectionListComp.java index a417adb7a..4dfb88690 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSelectionListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSelectionListComp.java @@ -5,7 +5,7 @@ import io.xpipe.app.comp.SimpleComp; import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.PrettyImageHelper; import io.xpipe.app.core.AppStyle; -import io.xpipe.app.core.window.AppWindowHelper; +import io.xpipe.app.core.window.AppWindowStyle; import io.xpipe.app.platform.BindingsHelper; import io.xpipe.app.platform.PlatformThread; @@ -42,7 +42,7 @@ public class BrowserFileSelectionListComp extends SimpleComp { public static Image snapshot(ObservableList list) { var r = new BrowserFileSelectionListComp(list).styleClass("drag").createRegion(); var scene = new Scene(r); - AppWindowHelper.setupStylesheets(scene); + AppWindowStyle.addStylesheets(scene); AppStyle.addStylesheets(scene); SnapshotParameters parameters = new SnapshotParameters(); parameters.setFill(Color.TRANSPARENT); diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java index 643402460..ccefe590c 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java @@ -301,7 +301,7 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab> { } public Comp grow(boolean width, boolean height) { - return apply(GrowAugment.create(width, height)); + return apply(struc -> { + struc.get().parentProperty().addListener((c, o, n) -> { + if (o instanceof Region) { + if (width) { + struc.get().prefWidthProperty().unbind(); + } + if (height) { + struc.get().prefHeightProperty().unbind(); + } + } + + bindGrow(struc.get(), n, width, height); + }); + + bindGrow(struc.get(), struc.get().getParent(), width, height); + }); + } + + private void bindGrow(Region r, Node parent, boolean width, boolean height) { + if (!(parent instanceof Region p)) { + return; + } + + if (width) { + r.prefWidthProperty() + .bind(Bindings.createDoubleBinding( + () -> { + var val = p.getWidth() + - p.getInsets().getLeft() + - p.getInsets().getRight(); + if (val <= 0) { + return Region.USE_COMPUTED_SIZE; + } + + // Floor to prevent rounding issues which cause an infinite growing + return Math.floor(val); + }, + p.widthProperty(), + p.insetsProperty())); + } + if (height) { + r.prefHeightProperty() + .bind(Bindings.createDoubleBinding( + () -> { + var val = p.getHeight() + - p.getInsets().getTop() + - p.getInsets().getBottom(); + if (val <= 0) { + return Region.USE_COMPUTED_SIZE; + } + + // Floor to prevent rounding issues which cause an infinite growing + return Math.floor(val); + }, + p.heightProperty(), + p.insetsProperty())); + } } public Comp tooltip(ObservableValue text) { diff --git a/app/src/main/java/io/xpipe/app/comp/README.md b/app/src/main/java/io/xpipe/app/comp/README.md index 4f445f51b..f599e526e 100644 --- a/app/src/main/java/io/xpipe/app/comp/README.md +++ b/app/src/main/java/io/xpipe/app/comp/README.md @@ -1,8 +1,6 @@ -# FxComps - Compound Components for JavaFX +# Compound Components -The FxComps library provides a new approach to creating JavaFX interfaces and -offers a quicker and more robust user interface development workflow. -This library is compatible and can be used with any other JavaFX library. +As a basis, JavaFX nodes are created and manage via comps (compound components). ## Principles @@ -12,11 +10,6 @@ It is advantageous to define a certain component to be a factory that can create an instances of a JavaFX Node each time it is called. By using this factory architecture, the scene contents can be rebuilt entirely by invoking the root component factory. -See the [hot reload](#Hot-Reload) section on how this can be used. - -Of course, if a component is a compound component that has children, -the parent factory has to incorporate the child factories into its creation process. -This can be done in fxcomps. #### A comp should produce a transparent representation of Regions and Controls @@ -86,44 +79,3 @@ If you for example bind your IDE Hot Reload to F4 and your Scene reload listener you can almost instantly apply any changes made to your GUI code without restarting. You can also implement a similar solution to also reload your stylesheets and translations. -## Library contents - -Aside from the base classes needed to implement the principles listed above, -this library also comes with a few very basic Comp implementations and some Augments. -These are very general implementations and can be seen as example implementations. - -#### Comps - -- [HorizontalComp](src/main/java/io/xpipe/fxcomps/comp/HorizontalComp.java) / - [VerticalComp](src/main/java/io/xpipe/fxcomps/comp/VerticalComp.java): Simple Comp implementation to create a - HBox/VBox using Comps as input -- [StackComp](src/main/java/io/xpipe/fxcomps/comp/StackComp.java): Simple Comp implementation to easily create a stack - pane using Comps as input -- [StackComp](src/main/java/io/xpipe/fxcomps/comp/LabelComp.java): Simple Comp implementation for a label - -#### Augments - -- [GrowAugment](src/main/java/io/xpipe/fxcomps/augment/GrowAugment.java): Binds the width/height of a Comp to its - parent, adjusted for parent padding -- [PopupMenuComp](src/main/java/io/xpipe/fxcomps/augment/PopupMenuAugment.java): Allows you to show a context menu when - a comp is left-clicked in addition to right-click - -## Creating a basic comp - -As the central idea of this library is that you create your own Comps, it is designed to be very simple: - -````java - var b = Comp.of(() -> new Button("Button")); - var l = Comp.of(() -> new Label("Label")); - - // Create an HBox factory and apply some Augments to it - var layoutFactory = new HorizontalComp(List.of(b, l)) - .apply(struc -> struc.get().setAlignment(Pos.CENTER)) - .apply(GrowAugment.create(true, true)) - .styleClass("layout"); - - // You can now create node instances of your layout - var region = layoutFactory.createRegion(); -```` - -Most simple Comp definitions can be defined inline with the `Comp.of(...)` method. diff --git a/app/src/main/java/io/xpipe/app/comp/augment/GrowAugment.java b/app/src/main/java/io/xpipe/app/comp/augment/GrowAugment.java deleted file mode 100644 index cafdb5349..000000000 --- a/app/src/main/java/io/xpipe/app/comp/augment/GrowAugment.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.xpipe.app.comp.augment; - -import io.xpipe.app.comp.CompStructure; - -import javafx.beans.binding.Bindings; -import javafx.scene.Node; -import javafx.scene.layout.Region; - -public class GrowAugment> implements Augment { - - private final boolean width; - private final boolean height; - - private GrowAugment(boolean width, boolean height) { - this.width = width; - this.height = height; - } - - public static > GrowAugment create(boolean width, boolean height) { - return new GrowAugment<>(width, height); - } - - private void bind(Region r, Node parent) { - if (!(parent instanceof Region p)) { - return; - } - - if (width) { - r.prefWidthProperty() - .bind(Bindings.createDoubleBinding( - () -> { - var val = p.getWidth() - - p.getInsets().getLeft() - - p.getInsets().getRight(); - if (val <= 0) { - return Region.USE_COMPUTED_SIZE; - } - - // Floor to prevent rounding issues which cause an infinite growing - return Math.floor(val); - }, - p.widthProperty(), - p.insetsProperty())); - } - if (height) { - r.prefHeightProperty() - .bind(Bindings.createDoubleBinding( - () -> { - var val = p.getHeight() - - p.getInsets().getTop() - - p.getInsets().getBottom(); - if (val <= 0) { - return Region.USE_COMPUTED_SIZE; - } - - // Floor to prevent rounding issues which cause an infinite growing - return Math.floor(val); - }, - p.heightProperty(), - p.insetsProperty())); - } - } - - @Override - public void augment(S struc) { - struc.get().parentProperty().addListener((c, o, n) -> { - if (o instanceof Region) { - if (width) { - struc.get().prefWidthProperty().unbind(); - } - if (height) { - struc.get().prefHeightProperty().unbind(); - } - } - - bind(struc.get(), n); - }); - - bind(struc.get(), struc.get().getParent()); - } -} diff --git a/app/src/main/java/io/xpipe/app/comp/base/AppMainWindowContentComp.java b/app/src/main/java/io/xpipe/app/comp/base/AppMainWindowContentComp.java index f1834b820..e01a1d187 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/AppMainWindowContentComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/AppMainWindowContentComp.java @@ -126,7 +126,7 @@ public class AppMainWindowContentComp extends SimpleComp { overlay.addListener((ListChangeListener) c -> { if (c.next() && c.wasAdded()) { - AppMainWindow.getInstance().focus(); + AppMainWindow.get().focus(); // Close blocking modal windows var childWindows = Window.getWindows().stream() diff --git a/app/src/main/java/io/xpipe/app/comp/base/FilterComp.java b/app/src/main/java/io/xpipe/app/comp/base/FilterComp.java index 88612fce7..06368ecb5 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/FilterComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/FilterComp.java @@ -3,8 +3,8 @@ package io.xpipe.app.comp.base; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.CompStructure; import io.xpipe.app.comp.SimpleCompStructure; -import io.xpipe.app.core.AppActionLinkDetector; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.core.AppOpenArguments; import io.xpipe.app.platform.PlatformThread; import javafx.beans.binding.Bindings; @@ -18,6 +18,7 @@ import javafx.scene.input.MouseButton; import atlantafx.base.controls.CustomTextField; import org.kordamp.ikonli.javafx.FontIcon; +import java.util.List; import java.util.Objects; public class FilterComp extends Comp> { @@ -76,7 +77,7 @@ public class FilterComp extends Comp> { filter.textProperty().addListener((observable, oldValue, n) -> { // Handle pasted xpipe URLs if (n != null && n.startsWith("xpipe://")) { - AppActionLinkDetector.handle(n, false); + AppOpenArguments.handle(List.of(n)); filter.setText(null); return; } diff --git a/app/src/main/java/io/xpipe/app/comp/base/PrettyImageHelper.java b/app/src/main/java/io/xpipe/app/comp/base/PrettyImageHelper.java index 9f99cfd32..61e8a9080 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/PrettyImageHelper.java +++ b/app/src/main/java/io/xpipe/app/comp/base/PrettyImageHelper.java @@ -37,8 +37,8 @@ public class PrettyImageHelper { private static ObservableValue rasterizedImageIfExistsScaled( String img, int height, int... availableSizes) { - ObservableDoubleValue obs = AppMainWindow.getInstance() != null - ? AppMainWindow.getInstance().displayScale() + ObservableDoubleValue obs = AppMainWindow.get() != null + ? AppMainWindow.get().displayScale() : new SimpleDoubleProperty(1.0); return Bindings.createStringBinding( () -> { diff --git a/app/src/main/java/io/xpipe/app/core/AppActionLinkDetector.java b/app/src/main/java/io/xpipe/app/core/AppActionLinkDetector.java deleted file mode 100644 index 018391947..000000000 --- a/app/src/main/java/io/xpipe/app/core/AppActionLinkDetector.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.xpipe.app.core; - -import io.xpipe.app.core.window.AppDialog; - -import javafx.scene.input.Clipboard; -import javafx.scene.input.DataFormat; - -import lombok.Setter; - -import java.util.List; - -public class AppActionLinkDetector { - - @Setter - private static String lastDetectedAction; - - private static String getClipboardAction() { - var content = Clipboard.getSystemClipboard().getContent(DataFormat.URL); - if (content == null) { - content = Clipboard.getSystemClipboard().getContent(DataFormat.PLAIN_TEXT); - } - - return content != null ? content.toString() : null; - } - - public static void handle(String content, boolean showAlert) { - var detected = AppOpenArguments.parseActions(content); - if (detected.size() == 0) { - return; - } - - if (showAlert && !showAlert()) { - return; - } - - AppOpenArguments.handle(List.of(content)); - } - - public static void detectOnPaste() { - var content = getClipboardAction(); - if (content == null) { - return; - } - lastDetectedAction = content; - handle(content, false); - } - - private static boolean showAlert() { - return AppDialog.confirm("clipboardActionDetected"); - } -} diff --git a/app/src/main/java/io/xpipe/app/core/AppDesktopIntegration.java b/app/src/main/java/io/xpipe/app/core/AppDesktopIntegration.java index 4656bd25e..73bd39c62 100644 --- a/app/src/main/java/io/xpipe/app/core/AppDesktopIntegration.java +++ b/app/src/main/java/io/xpipe/app/core/AppDesktopIntegration.java @@ -68,7 +68,7 @@ public class AppDesktopIntegration { }); // Set dock icon explicitly on macOS - // This is necessary in case XPipe was started through a script as it will have no icon otherwise + // This is necessary in case the app was started through a script as it will have no icon otherwise if (AppProperties.get().isDeveloperMode() && AppLogs.get().isWriteToSysout() && Taskbar.isTaskbarSupported()) { diff --git a/app/src/main/java/io/xpipe/app/core/AppFont.java b/app/src/main/java/io/xpipe/app/core/AppFont.java index c3e8b46a8..75e800ddf 100644 --- a/app/src/main/java/io/xpipe/app/core/AppFont.java +++ b/app/src/main/java/io/xpipe/app/core/AppFont.java @@ -19,6 +19,8 @@ public class AppFont { // Load ikonli fonts TrackEvent.info("Loading ikonli fonts ..."); new FontIcon("mdi2s-stop"); + new FontIcon("mdal-360"); + new FontIcon("bi-alarm"); TrackEvent.info("Loading bundled fonts ..."); AppResources.with( diff --git a/app/src/main/java/io/xpipe/app/core/AppFontSizes.java b/app/src/main/java/io/xpipe/app/core/AppFontSizes.java index 019ae1f5a..751729407 100644 --- a/app/src/main/java/io/xpipe/app/core/AppFontSizes.java +++ b/app/src/main/java/io/xpipe/app/core/AppFontSizes.java @@ -108,7 +108,7 @@ public class AppFontSizes { } } - private static AppFontSizes interSize(AppFontSizes s) { + private static AppFontSizes fallbackFontSize(AppFontSizes s) { if (s == BASE_10) { return BASE_10; } else if (s == BASE_10_5) { @@ -128,7 +128,7 @@ public class AppFontSizes { case OsType.MacOs ignored -> mac; case OsType.Windows ignored -> windows; }; - return inter ? interSize(r) : r; + return inter ? fallbackFontSize(r) : r; } public static AppFontSizes getDefault() { diff --git a/app/src/main/java/io/xpipe/app/core/AppTheme.java b/app/src/main/java/io/xpipe/app/core/AppTheme.java index c6ac99a3b..8abc1d892 100644 --- a/app/src/main/java/io/xpipe/app/core/AppTheme.java +++ b/app/src/main/java/io/xpipe/app/core/AppTheme.java @@ -215,7 +215,7 @@ public class AppTheme { } PlatformThread.runLaterIfNeeded(() -> { - var window = AppMainWindow.getInstance(); + var window = AppMainWindow.get(); if (window == null) { return; } diff --git a/app/src/main/java/io/xpipe/app/core/check/AppGnomeScaleDialog.java b/app/src/main/java/io/xpipe/app/core/check/AppGnomeScaleDialog.java index 116ca60f2..b4d980d70 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppGnomeScaleDialog.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppGnomeScaleDialog.java @@ -15,7 +15,7 @@ public class AppGnomeScaleDialog { return; } - if (AppMainWindow.getInstance() == null) { + if (AppMainWindow.get() == null) { return; } diff --git a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java index f8dad39c5..9e3ececce 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java @@ -55,7 +55,7 @@ public class BaseMode extends OperationMode { return; } - // For debugging + // For debugging error handling // if (true) throw new IllegalStateException(); TrackEvent.info("Initializing base mode components ..."); diff --git a/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java b/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java index 44136e951..488a72bdc 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java @@ -40,7 +40,7 @@ public class GuiMode extends PlatformMode { LicenseProvider.get().init(); PlatformThread.runLaterIfNeededBlocking(() -> { - AppMainWindow.getInstance().show(); + AppMainWindow.get().show(); }); } } diff --git a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java index d11a05e79..7f01a9c46 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java @@ -1,7 +1,6 @@ package io.xpipe.app.core.mode; import io.xpipe.app.beacon.AppBeaconServer; -import io.xpipe.app.browser.BrowserFullSessionModel; import io.xpipe.app.core.*; import io.xpipe.app.core.check.AppDebugModeCheck; import io.xpipe.app.core.check.AppDirectoryPermissionsCheck; @@ -17,7 +16,6 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.update.AppDistributionType; import io.xpipe.app.util.*; import io.xpipe.core.FailableRunnable; -import io.xpipe.core.OsType; import io.xpipe.core.XPipeDaemonMode; import javafx.application.Platform; @@ -141,8 +139,8 @@ public abstract class OperationMode { public static XPipeDaemonMode getStartupMode() { var event = TrackEvent.withInfo("Startup mode determined"); - if (AppMainWindow.getInstance() != null - && AppMainWindow.getInstance().getStage().isShowing()) { + if (AppMainWindow.get() != null + && AppMainWindow.get().getStage().isShowing()) { event.tag("mode", "gui").tag("reason", "windowShowing").handle(); return XPipeDaemonMode.GUI; } @@ -374,8 +372,8 @@ public abstract class OperationMode { BACKGROUND.onSwitchTo(); if (newMode != GUI - && AppMainWindow.getInstance() != null - && AppMainWindow.getInstance().getStage().isShowing()) { + && AppMainWindow.get() != null + && AppMainWindow.get().getStage().isShowing()) { GUI.onSwitchTo(); newMode = GUI; } else { diff --git a/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java b/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java index 277646f9e..a5cbb7085 100644 --- a/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java +++ b/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java @@ -11,7 +11,7 @@ import io.xpipe.app.prefs.CloseBehaviourDialog; import io.xpipe.app.update.AppDistributionType; import io.xpipe.app.platform.NativeWinWindowControl; import io.xpipe.app.platform.PlatformThread; -import io.xpipe.app.util.ThreadHelper; +import io.xpipe.app.util.GlobalTimer; import io.xpipe.core.OsType; import javafx.beans.binding.Bindings; @@ -35,7 +35,6 @@ import lombok.extern.jackson.Jacksonized; import java.io.IOException; import java.time.Duration; import java.time.Instant; -import java.time.temporal.ChronoUnit; import javax.imageio.ImageIO; public class AppMainWindow { @@ -52,7 +51,6 @@ public class AppMainWindow { private final Stage stage; private final BooleanProperty windowActive = new SimpleBooleanProperty(false); - private Thread thread; private volatile Instant lastUpdate; private boolean shown = false; @@ -105,11 +103,12 @@ public class AppMainWindow { if (AppPrefs.get() != null) { stage.opacityProperty().bind(PlatformThread.sync(AppPrefs.get().windowOpacity())); } - AppWindowHelper.addIcons(stage); - AppWindowHelper.setupStylesheets(stage.getScene()); - AppWindowHelper.setupClickShield(stage); - AppWindowHelper.addMaximizedPseudoClass(stage); - AppWindowHelper.addFontSize(stage); + AppWindowStyle.addIcons(stage); + AppWindowStyle.addStylesheets(stage.getScene()); + AppWindowStyle.addNavigationStyleClasses(stage.getScene()); + AppWindowStyle.addClickShield(stage); + AppWindowStyle.addMaximizedPseudoClass(stage); + AppWindowStyle.addFontSize(stage); AppTheme.initThemeHandlers(stage); AppWindowTitle.getTitle().subscribe(s -> { @@ -147,7 +146,7 @@ public class AppMainWindow { }); } - public static AppMainWindow getInstance() { + public static AppMainWindow get() { return INSTANCE; } @@ -186,29 +185,18 @@ public class AppMainWindow { } private synchronized void onChange() { - lastUpdate = Instant.now(); - if (thread == null) { - thread = ThreadHelper.unstarted(() -> { - while (true) { - var toStop = lastUpdate.plus(Duration.of(1, ChronoUnit.SECONDS)); - if (Instant.now().isBefore(toStop)) { - var toSleep = Duration.between(Instant.now(), toStop); - if (!toSleep.isNegative()) { - var ms = toSleep.toMillis(); - ThreadHelper.sleep(ms); - } - } else { - break; - } - } + var timestamp = Instant.now(); + lastUpdate = timestamp; + // Reduce printed window updates + GlobalTimer.delay(() -> { + if (!timestamp.equals(lastUpdate)) { + return; + } - synchronized (AppMainWindow.this) { - logChange(); - thread = null; - } - }); - thread.start(); - } + synchronized (AppMainWindow.this) { + logChange(); + } + }, Duration.ofSeconds(1)); } private void logChange() { diff --git a/app/src/main/java/io/xpipe/app/core/window/AppModifiedStage.java b/app/src/main/java/io/xpipe/app/core/window/AppModifiedStage.java index 77d09cbc0..43176f5f1 100644 --- a/app/src/main/java/io/xpipe/app/core/window/AppModifiedStage.java +++ b/app/src/main/java/io/xpipe/app/core/window/AppModifiedStage.java @@ -83,8 +83,8 @@ public class AppModifiedStage extends Stage { case OsType.Linux ignored -> {} case OsType.MacOs ignored -> { var ctrl = new NativeMacOsWindowControl(stage); - var seamlessFrame = AppMainWindow.getInstance() != null - && AppMainWindow.getInstance().getStage() == stage + var seamlessFrame = AppMainWindow.get() != null + && AppMainWindow.get().getStage() == stage && !AppPrefs.get().performanceMode().get() && mergeFrame(); var seamlessFrameApplied = ctrl.setAppearance( @@ -108,8 +108,8 @@ public class AppModifiedStage extends Stage { boolean seamlessFrame; if (AppPrefs.get().performanceMode().get() || !mergeFrame() - || AppMainWindow.getInstance() == null - || stage != AppMainWindow.getInstance().getStage()) { + || AppMainWindow.get() == null + || stage != AppMainWindow.get().getStage()) { seamlessFrame = false; } else { // This is not available on Windows 10 diff --git a/app/src/main/java/io/xpipe/app/core/window/AppSideWindow.java b/app/src/main/java/io/xpipe/app/core/window/AppSideWindow.java new file mode 100644 index 000000000..3a386fc3f --- /dev/null +++ b/app/src/main/java/io/xpipe/app/core/window/AppSideWindow.java @@ -0,0 +1,97 @@ +package io.xpipe.app.core.window; + +import io.xpipe.app.platform.PlatformInit; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; +import javafx.scene.input.KeyEvent; +import javafx.scene.paint.Color; +import javafx.stage.Stage; +import lombok.SneakyThrows; + +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class AppSideWindow { + + public static Optional showBlockingAlert(Consumer c) { + PlatformInit.init(true); + + Supplier supplier = () -> { + Alert a = createEmptyAlert(); + var s = (Stage) a.getDialogPane().getScene().getWindow(); + s.setOnShown(event -> { + Platform.runLater(() -> { + AppWindowBounds.clampWindow(s).ifPresent(rectangle2D -> { + s.setX(rectangle2D.getMinX()); + s.setY(rectangle2D.getMinY()); + // Somehow we have to set max size as setting the normal size does not work? + s.setMaxWidth(rectangle2D.getWidth()); + s.setMaxHeight(rectangle2D.getHeight()); + }); + }); + event.consume(); + }); + AppWindowBounds.fixInvalidStagePosition(s); + AppWindowStyle.addFontSize(s); + a.getDialogPane().getScene().addEventHandler(KeyEvent.KEY_PRESSED, event -> { + if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(event)) { + s.close(); + event.consume(); + return; + } + + if (event.getCode().equals(KeyCode.ESCAPE)) { + s.close(); + event.consume(); + } + }); + return a; + }; + + AtomicReference> result = new AtomicReference<>(); + if (!Platform.isFxApplicationThread()) { + CountDownLatch latch = new CountDownLatch(1); + Platform.runLater(() -> { + try { + Alert a = supplier.get(); + c.accept(a); + result.set(a.showAndWait()); + } catch (Throwable t) { + result.set(Optional.empty()); + } finally { + latch.countDown(); + } + }); + try { + latch.await(); + } catch (InterruptedException ignored) { + } + } else { + Alert a = supplier.get(); + c.accept(a); + result.set(a.showAndWait()); + } + return result.get(); + } + + public static Alert createEmptyAlert() { + Alert alert = new Alert(Alert.AlertType.NONE); + if (AppMainWindow.get() != null) { + alert.initOwner(AppMainWindow.get().getStage()); + } + alert.getDialogPane().getScene().setFill(Color.TRANSPARENT); + var stage = (Stage) alert.getDialogPane().getScene().getWindow(); + AppModifiedStage.prepareStage(stage); + AppWindowStyle.addIcons(stage); + AppWindowStyle.addStylesheets(alert.getDialogPane().getScene()); + AppWindowStyle.addNavigationStyleClasses(alert.getDialogPane().getScene()); + return alert; + } +} diff --git a/app/src/main/java/io/xpipe/app/core/window/AppWindowHelper.java b/app/src/main/java/io/xpipe/app/core/window/AppWindowStyle.java similarity index 54% rename from app/src/main/java/io/xpipe/app/core/window/AppWindowHelper.java rename to app/src/main/java/io/xpipe/app/core/window/AppWindowStyle.java index 602605689..57968e362 100644 --- a/app/src/main/java/io/xpipe/app/core/window/AppWindowHelper.java +++ b/app/src/main/java/io/xpipe/app/core/window/AppWindowStyle.java @@ -2,8 +2,6 @@ package io.xpipe.app.core.window; import io.xpipe.app.core.*; import io.xpipe.app.issue.TrackEvent; -import io.xpipe.app.platform.InputHelper; -import io.xpipe.app.platform.PlatformInit; import io.xpipe.core.OsType; import javafx.application.Platform; @@ -11,23 +9,15 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.PseudoClass; import javafx.scene.Scene; -import javafx.scene.control.Alert; -import javafx.scene.control.ButtonType; import javafx.scene.input.*; -import javafx.scene.paint.Color; import javafx.stage.Stage; -import lombok.SneakyThrows; - import java.time.Duration; import java.time.Instant; -import java.util.Optional; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; +import java.util.List; import java.util.function.Consumer; -import java.util.function.Supplier; -public class AppWindowHelper { +public class AppWindowStyle { public static void addMaximizedPseudoClass(Stage stage) { stage.getScene().rootProperty().subscribe(root -> { @@ -43,6 +33,29 @@ public class AppWindowHelper { }); } + public static void addNavigationStyleClasses(Scene scene) { + Consumer onInput = kb -> { + var r = scene.getRoot(); + if (r != null) { + // This property is broken on some systems + var acc = Platform.isAccessibilityActive(); + r.pseudoClassStateChanged(PseudoClass.getPseudoClass("key-navigation"), kb); + r.pseudoClassStateChanged(PseudoClass.getPseudoClass("normal-navigation"), !kb); + r.pseudoClassStateChanged(PseudoClass.getPseudoClass("accessibility-navigation"), acc); + } + }; + + scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + var c = event.getCode(); + var list = List.of(KeyCode.SPACE, KeyCode.ENTER, KeyCode.SHIFT, KeyCode.TAB); + onInput.accept(list.stream().anyMatch(keyCode -> keyCode == c) + || event.getCode().isNavigationKey()); + }); + scene.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { + onInput.accept(false); + }); + } + public static void addIcons(Stage stage) { stage.getIcons().clear(); @@ -59,82 +72,7 @@ public class AppWindowHelper { }); } - @SneakyThrows - public static Optional showBlockingAlert(Consumer c) { - PlatformInit.init(true); - - Supplier supplier = () -> { - Alert a = AppWindowHelper.createEmptyAlert(); - var s = (Stage) a.getDialogPane().getScene().getWindow(); - s.setOnShown(event -> { - Platform.runLater(() -> { - AppWindowBounds.clampWindow(s).ifPresent(rectangle2D -> { - s.setX(rectangle2D.getMinX()); - s.setY(rectangle2D.getMinY()); - // Somehow we have to set max size as setting the normal size does not work? - s.setMaxWidth(rectangle2D.getWidth()); - s.setMaxHeight(rectangle2D.getHeight()); - }); - }); - event.consume(); - }); - AppWindowBounds.fixInvalidStagePosition(s); - AppWindowHelper.addFontSize(s); - a.getDialogPane().getScene().addEventHandler(KeyEvent.KEY_PRESSED, event -> { - if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(event)) { - s.close(); - event.consume(); - return; - } - - if (event.getCode().equals(KeyCode.ESCAPE)) { - s.close(); - event.consume(); - } - }); - return a; - }; - - AtomicReference> result = new AtomicReference<>(); - if (!Platform.isFxApplicationThread()) { - CountDownLatch latch = new CountDownLatch(1); - Platform.runLater(() -> { - try { - Alert a = supplier.get(); - c.accept(a); - result.set(a.showAndWait()); - } catch (Throwable t) { - result.set(Optional.empty()); - } finally { - latch.countDown(); - } - }); - try { - latch.await(); - } catch (InterruptedException ignored) { - } - } else { - Alert a = supplier.get(); - c.accept(a); - result.set(a.showAndWait()); - } - return result.get(); - } - - public static Alert createEmptyAlert() { - Alert alert = new Alert(Alert.AlertType.NONE); - if (AppMainWindow.getInstance() != null) { - alert.initOwner(AppMainWindow.getInstance().getStage()); - } - alert.getDialogPane().getScene().setFill(Color.TRANSPARENT); - var stage = (Stage) alert.getDialogPane().getScene().getWindow(); - AppModifiedStage.prepareStage(stage); - addIcons(stage); - setupStylesheets(alert.getDialogPane().getScene()); - return alert; - } - - public static void setupStylesheets(Scene scene) { + public static void addStylesheets(Scene scene) { AppStyle.addStylesheets(scene); scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> { @@ -146,20 +84,9 @@ public class AppWindowHelper { } }); TrackEvent.debug("Set stylesheet reload listener"); - - InputHelper.onNavigationInput(scene, (kb) -> { - var r = scene.getRoot(); - if (r != null) { - // This property is broken on some systems - var acc = Platform.isAccessibilityActive(); - r.pseudoClassStateChanged(PseudoClass.getPseudoClass("key-navigation"), kb); - r.pseudoClassStateChanged(PseudoClass.getPseudoClass("normal-navigation"), !kb); - r.pseudoClassStateChanged(PseudoClass.getPseudoClass("accessibility-navigation"), acc); - } - }); } - public static void setupClickShield(Stage stage) { + public static void addClickShield(Stage stage) { if (OsType.getLocal() != OsType.MACOS) { return; } diff --git a/app/src/main/java/io/xpipe/app/hub/comp/DenseStoreEntryComp.java b/app/src/main/java/io/xpipe/app/hub/comp/DenseStoreEntryComp.java index 0644fa509..a817320e1 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/DenseStoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/DenseStoreEntryComp.java @@ -1,7 +1,6 @@ package io.xpipe.app.hub.comp; import io.xpipe.app.comp.Comp; -import io.xpipe.app.comp.augment.GrowAugment; import io.xpipe.app.core.AppFontSizes; import javafx.beans.binding.Bindings; @@ -139,8 +138,6 @@ public class DenseStoreEntryComp extends StoreEntryComp { HBox.setHgrow(cr, Priority.ALWAYS); grid.addRow(0, controls); - GrowAugment.create(true, false).augment(grid); - grid.getStyleClass().add("store-entry-grid"); grid.getStyleClass().add("dense"); diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java index fd822ffcd..c9d02e389 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java @@ -5,7 +5,6 @@ import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.SimpleComp; import io.xpipe.app.comp.SimpleCompStructure; import io.xpipe.app.comp.augment.ContextMenuAugment; -import io.xpipe.app.comp.augment.GrowAugment; import io.xpipe.app.comp.base.*; import io.xpipe.app.core.*; import io.xpipe.app.hub.action.HubBranchProvider; @@ -126,7 +125,6 @@ public abstract class StoreEntryComp extends SimpleComp { var button = new Button(); button.setGraphic(r); - GrowAugment.create(true, false).augment(new SimpleCompStructure<>(r)); button.getStyleClass().add("store-entry-comp"); button.setPadding(Insets.EMPTY); button.setMaxWidth(5000); diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java index 3fd8394bf..4ddf3c0bc 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java @@ -4,7 +4,6 @@ import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.SimpleComp; import io.xpipe.app.comp.base.DelayedInitComp; import io.xpipe.app.comp.base.LeftSplitPaneComp; -import io.xpipe.app.core.AppActionLinkDetector; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.core.window.AppMainWindow; import io.xpipe.app.platform.InputHelper; @@ -26,7 +25,7 @@ public class StoreLayoutComp extends SimpleComp { private Region createContent() { var left = new StoreSidebarComp(); - left.hide(AppMainWindow.getInstance().getStage().widthProperty().lessThan(1000)); + left.hide(AppMainWindow.get().getStage().widthProperty().lessThan(1000)); left.minWidth(270); left.maxWidth(500); left.minHeight(0); @@ -40,13 +39,6 @@ public class StoreLayoutComp extends SimpleComp { AppLayoutModel.get().getSavedState().setSidebarWidth(aDouble); }); comp.styleClass("store-layout"); - comp.apply(struc -> { - InputHelper.onKeyCombination( - struc.get(), new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN), true, keyEvent -> { - AppActionLinkDetector.detectOnPaste(); - keyEvent.consume(); - }); - }); return comp.createRegion(); } } diff --git a/app/src/main/java/io/xpipe/app/issue/ErrorHandlerComp.java b/app/src/main/java/io/xpipe/app/issue/ErrorHandlerComp.java index de3d396af..e22f23b28 100644 --- a/app/src/main/java/io/xpipe/app/issue/ErrorHandlerComp.java +++ b/app/src/main/java/io/xpipe/app/issue/ErrorHandlerComp.java @@ -1,7 +1,6 @@ package io.xpipe.app.issue; import io.xpipe.app.comp.SimpleComp; -import io.xpipe.app.comp.augment.GrowAugment; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.core.AppFontSizes; import io.xpipe.app.core.AppI18n; @@ -66,7 +65,7 @@ public class ErrorHandlerComp extends SimpleComp { }); }); b.disable(busy); - b.apply(GrowAugment.create(true, false)); + b.maxWidth(2000); return b.createRegion(); } diff --git a/app/src/main/java/io/xpipe/app/platform/InputHelper.java b/app/src/main/java/io/xpipe/app/platform/InputHelper.java index e4a7700a5..37c149404 100644 --- a/app/src/main/java/io/xpipe/app/platform/InputHelper.java +++ b/app/src/main/java/io/xpipe/app/platform/InputHelper.java @@ -62,16 +62,4 @@ public class InputHelper { target.addEventHandler(KeyEvent.KEY_PRESSED, e); } } - - public static void onNavigationInput(EventTarget target, Consumer r) { - target.addEventFilter(KeyEvent.KEY_PRESSED, event -> { - var c = event.getCode(); - var list = List.of(KeyCode.SPACE, KeyCode.ENTER, KeyCode.SHIFT, KeyCode.TAB); - r.accept(list.stream().anyMatch(keyCode -> keyCode == c) - || event.getCode().isNavigationKey()); - }); - target.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { - r.accept(false); - }); - } } diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalDockComp.java b/app/src/main/java/io/xpipe/app/terminal/TerminalDockComp.java index bff501a7f..915733f5a 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalDockComp.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalDockComp.java @@ -78,7 +78,7 @@ public class TerminalDockComp extends SimpleComp { } private void setupListeners(StackPane stack) { - var s = AppMainWindow.getInstance().getStage(); + var s = AppMainWindow.get().getStage(); var bounds = new ChangeListener() { @Override diff --git a/app/src/main/java/io/xpipe/app/util/AskpassAlert.java b/app/src/main/java/io/xpipe/app/util/AskpassAlert.java index 02f865953..0de8ef601 100644 --- a/app/src/main/java/io/xpipe/app/util/AskpassAlert.java +++ b/app/src/main/java/io/xpipe/app/util/AskpassAlert.java @@ -2,7 +2,8 @@ package io.xpipe.app.util; import io.xpipe.app.comp.base.SecretFieldComp; import io.xpipe.app.core.AppI18n; -import io.xpipe.app.core.window.AppWindowHelper; +import io.xpipe.app.core.window.AppSideWindow; +import io.xpipe.app.core.window.AppWindowStyle; import io.xpipe.app.secret.SecretManager; import io.xpipe.app.secret.SecretQueryResult; import io.xpipe.app.secret.SecretQueryState; @@ -24,7 +25,7 @@ public class AskpassAlert { public static SecretQueryResult queryRaw(String prompt, InPlaceSecretValue secretValue, boolean stealFocus) { var prop = new SimpleObjectProperty<>(secretValue); - var r = AppWindowHelper.showBlockingAlert(alert -> { + var r = AppSideWindow.showBlockingAlert(alert -> { alert.initModality(Modality.NONE); alert.setTitle(AppI18n.get("askpassAlertTitle")); alert.setHeaderText(prompt); diff --git a/app/src/main/java/io/xpipe/app/util/AsktextAlert.java b/app/src/main/java/io/xpipe/app/util/AsktextAlert.java index ad88fc04a..bb6193190 100644 --- a/app/src/main/java/io/xpipe/app/util/AsktextAlert.java +++ b/app/src/main/java/io/xpipe/app/util/AsktextAlert.java @@ -2,7 +2,8 @@ package io.xpipe.app.util; import io.xpipe.app.comp.base.TextFieldComp; import io.xpipe.app.core.AppI18n; -import io.xpipe.app.core.window.AppWindowHelper; +import io.xpipe.app.core.window.AppSideWindow; +import io.xpipe.app.core.window.AppWindowStyle; import javafx.animation.AnimationTimer; import javafx.application.Platform; @@ -17,7 +18,7 @@ public class AsktextAlert { public static Optional query(String prompt) { var prop = new SimpleObjectProperty(); - var r = AppWindowHelper.showBlockingAlert(alert -> { + var r = AppSideWindow.showBlockingAlert(alert -> { alert.setTitle(AppI18n.get("asktextAlertTitle")); alert.setHeaderText(prompt); alert.setAlertType(Alert.AlertType.CONFIRMATION); diff --git a/app/src/main/java/io/xpipe/app/util/RemminaHelper.java b/app/src/main/java/io/xpipe/app/util/RemminaHelper.java index 52bf95373..39e73e5d8 100644 --- a/app/src/main/java/io/xpipe/app/util/RemminaHelper.java +++ b/app/src/main/java/io/xpipe/app/util/RemminaHelper.java @@ -77,9 +77,9 @@ public class RemminaHelper { .getValue(), password != null ? password : "", Math.round( - AppMainWindow.getInstance().getStage().getWidth()), + AppMainWindow.get().getStage().getWidth()), Math.round( - AppMainWindow.getInstance().getStage().getHeight())); + AppMainWindow.get().getStage().getHeight())); Files.createDirectories(file.getParent()); Files.writeString(file, string); return file; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/identity/LocalIdentityConvertHubLeafProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/identity/LocalIdentityConvertHubLeafProvider.java index 8a6414af1..1b86d0f4c 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/identity/LocalIdentityConvertHubLeafProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/identity/LocalIdentityConvertHubLeafProvider.java @@ -78,7 +78,7 @@ public class LocalIdentityConvertHubLeafProvider implements HubLeafProvider { - var found = AppMainWindow.getInstance() + var found = AppMainWindow.get() .getStage() .getScene() .getRoot()