diff --git a/.gitignore b/.gitignore
index 0f84d98..d524ecc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,6 +40,9 @@ bld/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
+# Visual Studio Code
+.vscode
+
# Visual Studio 2017 auto generated files
Generated\ Files/
diff --git a/FlowLauncher/Components/FlowIntegration/FirstLoadingPageAttribute.cs b/FlowLauncher/Components/FlowIntegration/FirstLoadingPageAttribute.cs
deleted file mode 100644
index 76c71a1..0000000
--- a/FlowLauncher/Components/FlowIntegration/FirstLoadingPageAttribute.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using FlowLauncher.Components.UI;
-using FlowNet.Collector;
-
-namespace FlowLauncher.Components.FlowIntegration;
-
-///
-/// Mark a view model class as a first-loading page, this class must have an empty
-/// constructor and implement .
-///
-[CollectorMeta("FlowLauncher.Components.FlowIntegration.Page.RegisterFirstLoading")]
-[CollectorMeta.SupportsNamedType(TypeGenerationMode.EmptyConstructor, true)]
-[CollectorMeta.SupportsMethod>]
-[AttributeUsage(AttributeTargets.Class)]
-public sealed class FirstLoadingPageAttribute : Attribute;
diff --git a/FlowLauncher/Components/FlowIntegration/Page.cs b/FlowLauncher/Components/FlowIntegration/Page.cs
index 6f74a01..46c0242 100644
--- a/FlowLauncher/Components/FlowIntegration/Page.cs
+++ b/FlowLauncher/Components/FlowIntegration/Page.cs
@@ -1,4 +1,5 @@
using FlowLauncher.Components.UI;
+using FlowNet.Collector;
namespace FlowLauncher.Components.FlowIntegration;
@@ -16,3 +17,22 @@ public static Task Register(PageViewModel page)
return Task.CompletedTask;
}
}
+
+///
+/// Mark a view model class as a first-loading page, this class must have an empty
+/// constructor and implement .
+///
+[CollectorMeta("FlowLauncher.Components.FlowIntegration.Page.RegisterFirstLoading")]
+[CollectorMeta.SupportsNamedType(TypeGenerationMode.EmptyConstructor, true)]
+[CollectorMeta.SupportsMethod>]
+[AttributeUsage(AttributeTargets.Class)]
+public sealed class FirstLoadingPageAttribute : Attribute;
+
+///
+/// Mark a view model class as a page, this class must have an empty constructor and
+/// implement .
+///
+[CollectorMeta("FlowLauncher.Components.FlowIntegration.Page.RegisterFirstLoading")]
+[CollectorMeta.SupportsNamedType(TypeGenerationMode.EmptyConstructor)]
+[AttributeUsage(AttributeTargets.Class)]
+public sealed class PageAttribute : Attribute;
diff --git a/FlowLauncher/Components/FlowIntegration/PageAttribute.cs b/FlowLauncher/Components/FlowIntegration/PageAttribute.cs
deleted file mode 100644
index ee4aeb1..0000000
--- a/FlowLauncher/Components/FlowIntegration/PageAttribute.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using FlowLauncher.Components.UI;
-using FlowNet.Collector;
-
-namespace FlowLauncher.Components.FlowIntegration;
-
-///
-/// Mark a view model class as a page, this class must have an empty constructor and
-/// implement .
-///
-[CollectorMeta("FlowLauncher.Components.FlowIntegration.Page.RegisterFirstLoading")]
-[CollectorMeta.SupportsNamedType(TypeGenerationMode.EmptyConstructor)]
-[AttributeUsage(AttributeTargets.Class)]
-public sealed class PageAttribute : Attribute;
diff --git a/FlowLauncher/Components/FlowIntegration/PlatformSelector.cs b/FlowLauncher/Components/FlowIntegration/PlatformSelector.cs
new file mode 100644
index 0000000..2caf396
--- /dev/null
+++ b/FlowLauncher/Components/FlowIntegration/PlatformSelector.cs
@@ -0,0 +1,45 @@
+using System.Runtime.InteropServices;
+using FlowNet.Collector;
+
+namespace FlowLauncher.Components.FlowIntegration;
+
+// ReSharper disable InconsistentNaming
+public enum FlowPlatform
+{
+ Windows = 0,
+ Linux = 1,
+ MacOS = 2,
+ FreeBSD = 3,
+}
+// ReSharper restore InconsistentNaming
+
+[Flow.Scope("fl:tool:platform-selector")]
+public static partial class PlatformSelector
+{
+ private static readonly OSPlatform[] PlatformEnum = [
+ OSPlatform.Windows,
+ OSPlatform.Linux,
+ OSPlatform.OSX,
+ OSPlatform.FreeBSD
+ ];
+
+ [Flow.Task]
+ private static Task StartsWith(params IEnumerable prefix)
+ => Task.FromResult(prefix.Any(RuntimeInformation.RuntimeIdentifier.StartsWith));
+
+ [Flow.Task]
+ private static Task Is(params IEnumerable platform)
+ => Task.FromResult(platform.Any(p => RuntimeInformation.IsOSPlatform(PlatformEnum[(int)p])));
+
+#pragma warning disable CS9113 // Parameter is unread.
+
+ [AttributeUsage(AttributeTargets.All)]
+ [CollectionFilterMeta("fl:tool:platform-selector:starts-with")]
+ public sealed class StartsWithAttribute(params string[] prefix) : Attribute;
+
+ [AttributeUsage(AttributeTargets.All)]
+ [CollectionFilterMeta("fl:tool:platform-selector:is")]
+ public sealed class IsAttribute(params FlowPlatform[] platform) : Attribute;
+
+#pragma warning restore CS9113 // Parameter is unread.
+}
diff --git a/FlowLauncher/Components/FlowIntegration/PlatformWindow.cs b/FlowLauncher/Components/FlowIntegration/PlatformWindow.cs
new file mode 100644
index 0000000..dfd4b6e
--- /dev/null
+++ b/FlowLauncher/Components/FlowIntegration/PlatformWindow.cs
@@ -0,0 +1,21 @@
+using Avalonia.Controls;
+using FlowNet.Collector;
+
+namespace FlowLauncher.Components.FlowIntegration;
+
+public static class PlatformWindow
+{
+
+ public static Task SetCurrentSessionWindowFactory(Func window)
+ {
+ Program.CurrentSessionWindowFactory = window;
+ return Task.CompletedTask;
+ }
+}
+
+[CollectorMeta("FlowLauncher.Components.FlowIntegration.PlatformWindow.SetCurrentSessionWindowFactory")]
+[CollectorMeta.RequiresAttr(typeof(PlatformSelector.IsAttribute))]
+[CollectorMeta.SupportsMethod>]
+[CollectorMeta.SupportsNamedType(TypeGenerationMode.EmptyConstructor, true)]
+[AttributeUsage(AttributeTargets.Class)]
+public sealed class PlatformWindowAttribute : Attribute;
diff --git a/FlowLauncher/Components/Platforms/LinuxWindow.axaml.cs b/FlowLauncher/Components/Platforms/LinuxWindow.axaml.cs
index e745d69..bb3955f 100644
--- a/FlowLauncher/Components/Platforms/LinuxWindow.axaml.cs
+++ b/FlowLauncher/Components/Platforms/LinuxWindow.axaml.cs
@@ -1,7 +1,10 @@
+using FlowLauncher.Components.FlowIntegration;
using FlowLauncher.Components.UI;
namespace FlowLauncher.Components.Platforms;
+[PlatformSelector.Is(FlowPlatform.Linux)]
+[PlatformWindow]
public sealed partial class LinuxWindow : BaseWindow
{
public LinuxWindow()
diff --git a/FlowLauncher/Components/Platforms/MacWindow.axaml.cs b/FlowLauncher/Components/Platforms/MacWindow.axaml.cs
index 4a2c465..0efc13e 100644
--- a/FlowLauncher/Components/Platforms/MacWindow.axaml.cs
+++ b/FlowLauncher/Components/Platforms/MacWindow.axaml.cs
@@ -1,10 +1,13 @@
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
+using FlowLauncher.Components.FlowIntegration;
using FlowLauncher.Components.UI;
namespace FlowLauncher.Components.Platforms;
+[PlatformSelector.Is(FlowPlatform.MacOS)]
+[PlatformWindow]
public sealed partial class MacWindow : BaseWindow
{
public MacWindow()
diff --git a/FlowLauncher/Components/Platforms/WindowsWindow.axaml.cs b/FlowLauncher/Components/Platforms/WindowsWindow.axaml.cs
index e7dbcca..c98b865 100644
--- a/FlowLauncher/Components/Platforms/WindowsWindow.axaml.cs
+++ b/FlowLauncher/Components/Platforms/WindowsWindow.axaml.cs
@@ -3,10 +3,13 @@
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
+using FlowLauncher.Components.FlowIntegration;
using FlowLauncher.Components.UI;
namespace FlowLauncher.Components.Platforms;
+[PlatformSelector.Is(FlowPlatform.Windows)]
+[PlatformWindow]
public sealed partial class WindowsWindow : BaseWindow
{
public static readonly StyledProperty UseNativeWindowFrameProperty =
diff --git a/FlowLauncher/FlowLauncher.csproj b/FlowLauncher/FlowLauncher.csproj
index e6e0fe8..9099b92 100644
--- a/FlowLauncher/FlowLauncher.csproj
+++ b/FlowLauncher/FlowLauncher.csproj
@@ -78,7 +78,7 @@
-
+
diff --git a/FlowLauncher/Program.cs b/FlowLauncher/Program.cs
index 67491eb..ecd46ad 100644
--- a/FlowLauncher/Program.cs
+++ b/FlowLauncher/Program.cs
@@ -2,7 +2,6 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Threading;
-using FlowLauncher.Components.Platforms;
namespace FlowLauncher;
@@ -68,13 +67,13 @@ private static void AppMain(Application application, string[] args)
OnProgramExit.SetResult();
}
+ internal static Func? CurrentSessionWindowFactory { private get; set; } = null;
+
private static void CreateMainWindow()
{
- Window mainWindow;
- if (OperatingSystem.IsWindows()) mainWindow = new WindowsWindow();
- else if (OperatingSystem.IsMacOS()) mainWindow = new MacWindow();
- else if (OperatingSystem.IsLinux()) mainWindow = new LinuxWindow();
- else throw new NotSupportedException($"Platform not supported: {RuntimeInformation.OSDescription}");
+ if (CurrentSessionWindowFactory == null)
+ throw new NotSupportedException($"Platform not supported: {RuntimeInformation.OSDescription}");
+ var mainWindow = CurrentSessionWindowFactory();
mainWindow.Show();
}