diff --git a/Directory.Build.props b/Directory.Build.props
index 5ce44b5859c3..c802b771d62d 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,13 +5,16 @@
net10.0
$(BaseTargetFramework)-desktop
+
+ Linux
+
$(DesktopTargetFramework)
$(DesktopTargetFramework)
- true
+ true
false
- true
+ true
preview
nullable
diff --git a/Files.slnx b/Files.slnx
index f55a46d960a1..00bc1588e772 100644
--- a/Files.slnx
+++ b/Files.slnx
@@ -44,6 +44,11 @@
+
+
+
+
+
diff --git a/src/Files.App.Storage/Legacy/HomeFolder/LinuxHomeFolder.cs b/src/Files.App.Storage/Legacy/HomeFolder/DesktopHomeFolder.cs
similarity index 92%
rename from src/Files.App.Storage/Legacy/HomeFolder/LinuxHomeFolder.cs
rename to src/Files.App.Storage/Legacy/HomeFolder/DesktopHomeFolder.cs
index 1a9efb937cf3..a0093bc46b6d 100644
--- a/src/Files.App.Storage/Legacy/HomeFolder/LinuxHomeFolder.cs
+++ b/src/Files.App.Storage/Legacy/HomeFolder/DesktopHomeFolder.cs
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: MPL-2.0
using Files.Platform.Abstractions;
-using Files.Platform.Abstractions.Gvfs;
+using Files.Platform.Abstractions.Network;
using Files.Platform.Abstractions.Recent;
using Files.Platform.Abstractions.Volumes;
using OwlCore.Storage.System.IO;
@@ -10,7 +10,7 @@
namespace Files.App.Storage.Storables
{
- public sealed class LinuxHomeFolder : IHomeFolder
+ public sealed class DesktopHomeFolder : IHomeFolder
{
private readonly IUserDirectories directories;
private readonly IVolumeService volumes;
@@ -20,7 +20,7 @@ public sealed class LinuxHomeFolder : IHomeFolder
public string Id => "Home";
public string Name => "Home";
- public LinuxHomeFolder(IUserDirectories directories, IVolumeService volumes, IRecentFilesStore recentFiles, INetworkLocationService network)
+ public DesktopHomeFolder(IUserDirectories directories, IVolumeService volumes, IRecentFilesStore recentFiles, INetworkLocationService network)
{
this.directories = directories;
this.volumes = volumes;
diff --git a/src/Files.App/Actions/Open/OpenSettingsFileAction.cs b/src/Files.App/Actions/Open/OpenSettingsFileAction.cs
index 94007495e874..a832a4fc7eeb 100644
--- a/src/Files.App/Actions/Open/OpenSettingsFileAction.cs
+++ b/src/Files.App/Actions/Open/OpenSettingsFileAction.cs
@@ -32,7 +32,7 @@ public async Task ExecuteAsync(object? parameter = null)
try
{
var settingsJsonFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appdata:///local/{Constants.LocalSettings.SettingsFolderName}/{Constants.LocalSettings.UserSettingsFileName}"));
- await NavigationHelpers.OpenFileLinuxAsync(settingsJsonFile.Path);
+ await NavigationHelpers.OpenFileDesktopAsync(settingsJsonFile.Path);
}
catch (Exception ex)
{
diff --git a/src/Files.App/Actions/Open/OpenTerminalAction.cs b/src/Files.App/Actions/Open/OpenTerminalAction.cs
index 13d9113ab050..5e602ffbf4eb 100644
--- a/src/Files.App/Actions/Open/OpenTerminalAction.cs
+++ b/src/Files.App/Actions/Open/OpenTerminalAction.cs
@@ -13,7 +13,7 @@ internal partial class OpenTerminalAction : ObservableObject, IAction
public virtual string Label
- => Strings.OpenTerminalLinux.GetLocalizedResource();
+ => Strings.OpenTerminalDesktop.GetLocalizedResource();
public virtual string Description
=> Strings.OpenTerminalDescription.GetLocalizedResource();
@@ -46,10 +46,10 @@ public Task ExecuteAsync(object? parameter = null)
if (paths.Length is 0)
return Task.CompletedTask;
- return OpenLinuxTerminalsAsync(paths);
+ return OpenDesktopTerminalsAsync(paths);
}
- private static async Task OpenLinuxTerminalsAsync(string[] paths)
+ private static async Task OpenDesktopTerminalsAsync(string[] paths)
{
var launcher = Ioc.Default.GetRequiredService();
foreach (var path in paths)
diff --git a/src/Files.App/Actions/Open/OpenTerminalAsAdminAction.cs b/src/Files.App/Actions/Open/OpenTerminalAsAdminAction.cs
index a367a6a2832f..da3874f9758a 100644
--- a/src/Files.App/Actions/Open/OpenTerminalAsAdminAction.cs
+++ b/src/Files.App/Actions/Open/OpenTerminalAsAdminAction.cs
@@ -7,7 +7,7 @@ namespace Files.App.Actions
internal sealed partial class OpenTerminalAsAdminAction : OpenTerminalAction
{
public override string Label
- => Strings.OpenTerminalAsAdminLinux.GetLocalizedResource();
+ => Strings.OpenTerminalAsAdminDesktop.GetLocalizedResource();
public override string Description
=> Strings.OpenTerminalAsAdminDescription.GetLocalizedResource();
diff --git a/src/Files.App/Actions/Open/OpenTerminalFromHomeAction.cs b/src/Files.App/Actions/Open/OpenTerminalFromHomeAction.cs
index bce11d9f8ca8..510a61d45637 100644
--- a/src/Files.App/Actions/Open/OpenTerminalFromHomeAction.cs
+++ b/src/Files.App/Actions/Open/OpenTerminalFromHomeAction.cs
@@ -9,7 +9,7 @@ internal sealed partial class OpenTerminalFromHomeAction : OpenTerminalAction
private IHomePageContext HomePageContext { get; } = Ioc.Default.GetRequiredService();
public override string Label
- => Strings.OpenTerminalLinux.GetLocalizedResource();
+ => Strings.OpenTerminalDesktop.GetLocalizedResource();
public override string Description
=> Strings.OpenTerminalDescription.GetLocalizedResource();
diff --git a/src/Files.App/Actions/Open/OpenTerminalFromSidebarAction.cs b/src/Files.App/Actions/Open/OpenTerminalFromSidebarAction.cs
index 56c4a16facf5..a06c0eeb8174 100644
--- a/src/Files.App/Actions/Open/OpenTerminalFromSidebarAction.cs
+++ b/src/Files.App/Actions/Open/OpenTerminalFromSidebarAction.cs
@@ -9,7 +9,7 @@ internal sealed partial class OpenTerminalFromSidebarAction : OpenTerminalAction
private ISidebarContext SidebarContext { get; } = Ioc.Default.GetRequiredService();
public override string Label
- => Strings.OpenTerminalLinux.GetLocalizedResource();
+ => Strings.OpenTerminalDesktop.GetLocalizedResource();
public override string Description
=> Strings.OpenTerminalDescription.GetLocalizedResource();
diff --git a/src/Files.App/App.xaml b/src/Files.App/App.xaml
index f349ebdf88c6..ba18ac25fd0c 100644
--- a/src/Files.App/App.xaml
+++ b/src/Files.App/App.xaml
@@ -181,7 +181,7 @@
-
+
diff --git a/src/Files.App/Constants.cs b/src/Files.App/Constants.cs
index 2b7dd68f1cae..6b0598399c2c 100644
--- a/src/Files.App/Constants.cs
+++ b/src/Files.App/Constants.cs
@@ -208,13 +208,12 @@ public static class DragAndDrop
public static class UserEnvironmentPaths
{
- private static readonly Files.Platform.Linux.LinuxUserDirectories _userDirectories = new();
+ private static readonly IUserDirectories _userDirectories = DesktopPlatform.CreateUserDirectories();
public static readonly string DesktopPath = _userDirectories.Desktop;
public static readonly string DownloadsPath = _userDirectories.Downloads;
- // XDG data home (~/.local/share)
public static readonly string LocalAppDataPath = Environment.GetEnvironmentVariable("XDG_DATA_HOME") is { Length: > 0 } dataHome && System.IO.Path.IsPathRooted(dataHome)
? dataHome
: System.IO.Path.Combine(_userDirectories.Home, ".local", "share");
diff --git a/src/Files.App/Data/Commands/HotKey/HotKeyHelpers.Linux.cs b/src/Files.App/Data/Commands/HotKey/HotKeyHelpers.Desktop.cs
similarity index 100%
rename from src/Files.App/Data/Commands/HotKey/HotKeyHelpers.Linux.cs
rename to src/Files.App/Data/Commands/HotKey/HotKeyHelpers.Desktop.cs
diff --git a/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs b/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs
index 20145cb3bbec..695e50b9098c 100644
--- a/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs
+++ b/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs
@@ -16,11 +16,11 @@ public sealed partial class HomePageContext : ObservableObject, IHomePageContext
private static IHomeFolder CreateHomeFolder()
{
- return new LinuxHomeFolder(
+ return new DesktopHomeFolder(
Ioc.Default.GetRequiredService(),
Ioc.Default.GetRequiredService(),
Ioc.Default.GetRequiredService(),
- Ioc.Default.GetRequiredService());
+ Ioc.Default.GetRequiredService());
}
private WidgetCardItem? rightClickedItem = null;
diff --git a/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.Linux.cs b/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.Desktop.cs
similarity index 93%
rename from src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.Linux.cs
rename to src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.Desktop.cs
index 9a99b13d307b..34d51a64833c 100644
--- a/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.Linux.cs
+++ b/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.Desktop.cs
@@ -4,8 +4,8 @@
using Files.Platform.Abstractions;
using Files.Platform.Abstractions.Launching;
using Files.Platform.Abstractions.Mime;
-using Files.Platform.Linux.Launching;
-using Files.Platform.Linux.Mime;
+using Files.Platform.Posix.Launching;
+using Files.Platform.Posix.Mime;
using Files.App.ViewModels.Layouts;
using Microsoft.Extensions.Logging;
@@ -31,7 +31,7 @@ public static Task> GetItemContextCommandsW
}, cancellationToken);
}
- private static Task> GetLinuxItemContextCommandsAsync(
+ private static Task> GetDesktopItemContextCommandsAsync(
string? workingDir, List selectedItems, bool shiftPressed, bool showOpenMenu, CancellationToken cancellationToken)
{
var shellItems = ShellContextFlyoutFactory.GetShellContextmenuAsync(shiftPressed: shiftPressed, showOpenMenu: showOpenMenu,
@@ -41,7 +41,7 @@ private static Task> GetLinuxItemContextCom
return Task.Run(async () =>
{
var items = await shellItems.ConfigureAwait(false);
- if (!includeServiceMenus || !targets.All(LinuxServiceMenuService.IsLocalFileSystemTarget))
+ if (!includeServiceMenus || !targets.All(PosixServiceMenuService.IsLocalFileSystemTarget))
return items;
try
@@ -57,7 +57,7 @@ private static Task> GetLinuxItemContextCom
Text = DisplaySanitizer.Field(action.Application.Name),
Glyph = "\xE756",
ShowInSearchPage = true,
- Command = new AsyncRelayCommand(() => NavigationHelpers.RunServiceMenuLinuxAsync(captured, targets)),
+ Command = new AsyncRelayCommand(() => NavigationHelpers.RunServiceMenuDesktopAsync(captured, targets)),
};
if (string.IsNullOrWhiteSpace(action.Submenu))
items.Add(item);
@@ -88,7 +88,7 @@ private static Task> GetLinuxItemContextCom
///
/// Builds the "New" submenu from : Folder, Text Document and the files in ~/Templates.
///
- internal static List GetLinuxNewItemItems(bool canCreateFileInPage, ContextMenuCommandSnapshot? createFolder = null, CancellationToken cancellationToken = default)
+ internal static List GetDesktopNewItemItems(bool canCreateFileInPage, ContextMenuCommandSnapshot? createFolder = null, CancellationToken cancellationToken = default)
{
var list = new List()
{
diff --git a/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.RootActions.cs b/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.RootActions.cs
index 5058fb9648cd..7e915263623c 100644
--- a/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.RootActions.cs
+++ b/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.RootActions.cs
@@ -47,7 +47,7 @@ internal static ContextMenuFlyoutItemViewModel GetRootActionsItem(List RootActionsHelper.OpenTerminalAsync(terminalTarget)),
});
}
diff --git a/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.cs b/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.cs
index 703e8746a110..d4fdf05a6b91 100644
--- a/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.cs
+++ b/src/Files.App/Data/Factories/ContentPageContextFlyoutFactory.cs
@@ -33,7 +33,7 @@ public static List GetItemContextCommandsWithout
public static Task> GetItemContextShellCommandsAsync(string? workingDir, List selectedItems, bool shiftPressed, bool showOpenMenu, CancellationToken cancellationToken)
{
- return GetLinuxItemContextCommandsAsync(workingDir, selectedItems, shiftPressed, showOpenMenu, cancellationToken);
+ return GetDesktopItemContextCommandsAsync(workingDir, selectedItems, shiftPressed, showOpenMenu, cancellationToken);
}
public static List Filter(List items, List selectedItems, bool shiftPressed, CurrentInstanceViewModel currentInstanceViewModel, bool removeOverflowMenu = true)
@@ -370,7 +370,7 @@ private static List BuildBaseItemMenuItems(Conte
ThemedIconStyle = state.Commands[Commands.AddItem].Glyph.ThemedIconStyle
},
Text = state.Commands[Commands.AddItem].Label,
- Items = GetLinuxNewItemItems(state.CanCreateFileInPage, state.Commands[Commands.CreateFolder], cancellationToken),
+ Items = GetDesktopNewItemItems(state.CanCreateFileInPage, state.Commands[Commands.CreateFolder], cancellationToken),
ShowItem = !state.ItemsSelected,
ShowInFtpPage = true
},
@@ -878,7 +878,7 @@ private static ContextMenuBuildState CaptureMenuState(BaseLayoutViewModel comman
public static List GetNewItemItems(BaseLayoutViewModel commandsViewModel, bool canCreateFileInPage)
{
- return GetLinuxNewItemItems(canCreateFileInPage);
+ return GetDesktopNewItemItems(canCreateFileInPage);
}
}
}
diff --git a/src/Files.App/Data/Factories/PropertiesNavigationItemsFactory.cs b/src/Files.App/Data/Factories/PropertiesNavigationItemsFactory.cs
index 138c3b65796b..8d113ad848e9 100644
--- a/src/Files.App/Data/Factories/PropertiesNavigationItemsFactory.cs
+++ b/src/Files.App/Data/Factories/PropertiesNavigationItemsFactory.cs
@@ -66,7 +66,7 @@ public static ObservableCollection Initialize(object i
{
var isShortcut = listedItem.IsShortcut;
if (OperatingSystem.IsLinux() && !isShortcut)
- isShortcut = LinuxShortcutHelper.IsShortcutLike(listedItem.ItemPath);
+ isShortcut = DesktopShortcutHelper.IsShortcutLike(listedItem.ItemPath);
var isLibrary = listedItem.IsLibrary;
var fileExt = listedItem.FileExtension;
var isFolder = listedItem.PrimaryItemAttribute == Windows.Storage.StorageItemTypes.Folder;
diff --git a/src/Files.App/Data/Factories/ShellContextFlyoutFactory.Linux.cs b/src/Files.App/Data/Factories/ShellContextFlyoutFactory.Desktop.cs
similarity index 90%
rename from src/Files.App/Data/Factories/ShellContextFlyoutFactory.Linux.cs
rename to src/Files.App/Data/Factories/ShellContextFlyoutFactory.Desktop.cs
index 0e178b806e70..87e857ebea24 100644
--- a/src/Files.App/Data/Factories/ShellContextFlyoutFactory.Linux.cs
+++ b/src/Files.App/Data/Factories/ShellContextFlyoutFactory.Desktop.cs
@@ -14,7 +14,7 @@ public static partial class ShellContextFlyoutFactory
/// Linux has no shell extension menu. The only entry produced is the "Open with" submenu for a single file,
/// shaped like the Windows "openas" entry so the existing layout code swaps it in.
///
- private static Task> GetLinuxContextMenuAsync(List? selectedItems, CancellationToken cancellationToken)
+ private static Task> GetDesktopContextMenuAsync(List? selectedItems, CancellationToken cancellationToken)
{
var path = selectedItems is { Count: 1 } &&
selectedItems[0].PrimaryItemAttribute == Windows.Storage.StorageItemTypes.File
@@ -61,7 +61,7 @@ private static async Task LoadOpenWithItemsAsync(ContextMenuFlyoutItemViewModel
items.Add(new ContextMenuFlyoutItemViewModel
{
Text = captured.Id == defaultApp?.Id ? $"{captured.Name} ({Strings.Default.GetLocalizedResource()})" : captured.Name,
- BitmapIcon = await LinuxAppIcons.GetBitmapAsync(captured),
+ BitmapIcon = await DesktopAppIcons.GetBitmapAsync(captured),
Command = new AsyncRelayCommand(() => launcher.OpenWithAsync(captured, [path])),
});
}
@@ -72,7 +72,7 @@ private static async Task LoadOpenWithItemsAsync(ContextMenuFlyoutItemViewModel
items.Add(new ContextMenuFlyoutItemViewModel
{
Text = Strings.ChooseAnotherApp.GetLocalizedResource() + "…",
- Command = new AsyncRelayCommand(() => LinuxOpenWithDialog.ShowAsync(path)),
+ Command = new AsyncRelayCommand(() => DesktopOpenWithDialog.ShowAsync(path)),
});
}
}
diff --git a/src/Files.App/Data/Factories/ShellContextFlyoutHelper.cs b/src/Files.App/Data/Factories/ShellContextFlyoutHelper.cs
index 19e2c91743b6..b1c83c1adfef 100644
--- a/src/Files.App/Data/Factories/ShellContextFlyoutHelper.cs
+++ b/src/Files.App/Data/Factories/ShellContextFlyoutHelper.cs
@@ -24,7 +24,7 @@ public static partial class ShellContextFlyoutFactory
public static async Task> GetShellContextmenuAsync(bool showOpenMenu, bool shiftPressed, string? workingDirectory, List? selectedItems, CancellationToken cancellationToken)
{
// No shell extensions on Linux: skip the Win32 shell menu entirely (no COM, no delay)
- return await GetLinuxContextMenuAsync(selectedItems, cancellationToken);
+ return await GetDesktopContextMenuAsync(selectedItems, cancellationToken);
}
diff --git a/src/Files.App/Data/Items/DriveItem.cs b/src/Files.App/Data/Items/DriveItem.cs
index 30c5fcabf67c..a1bb213aa2e4 100644
--- a/src/Files.App/Data/Items/DriveItem.cs
+++ b/src/Files.App/Data/Items/DriveItem.cs
@@ -257,7 +257,7 @@ public static async Task CreateFromPropertiesAsync(StorageFolder root
// The label already is the display name (volume label, " Volume" or "File System")
item.Text = !string.IsNullOrWhiteSpace(label) ? label : root.DisplayName;
if (string.IsNullOrWhiteSpace(item.Text) && root.Path is "/")
- item.Text = Strings.LinuxFileSystemRoot.GetLocalizedResource();
+ item.Text = Strings.DesktopFileSystemRoot.GetLocalizedResource();
item.Type = type;
item.MenuOptions = new ContextMenuOptions
{
@@ -312,7 +312,7 @@ public async Task UpdatePropertiesAsync()
var info = await Task.Run(() =>
{
- if (Files.Platform.Linux.Volumes.HeadlessDriveFixture.Find(Path) is { } synthetic)
+ if (Files.Platform.Posix.Volumes.HeadlessDriveFixture.Find(Path) is { } synthetic)
return (Total: (long)synthetic.TotalBytes, Free: (long)synthetic.FreeBytes, Format: synthetic.FileSystem);
var driveInfo = new SystemIO.DriveInfo(Path ?? throw new InvalidOperationException("The drive path has not been initialized."));
diff --git a/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs b/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs
index 1eab604f6c57..6ede6ccd572f 100644
--- a/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs
+++ b/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs
@@ -570,18 +570,18 @@ public bool IsSelectedItemShortcut
}
}
- private bool isLinuxOpenTargetAvailable;
- public bool IsLinuxOpenTargetAvailable
+ private bool isDesktopOpenTargetAvailable;
+ public bool IsDesktopOpenTargetAvailable
{
- get => isLinuxOpenTargetAvailable;
+ get => isDesktopOpenTargetAvailable;
set
{
- if (SetProperty(ref isLinuxOpenTargetAvailable, value))
+ if (SetProperty(ref isDesktopOpenTargetAvailable, value))
OnPropertyChanged(nameof(IsOpenTargetVisible));
}
}
- public bool IsOpenTargetVisible => IsSelectedItemShortcut || IsLinuxOpenTargetAvailable;
+ public bool IsOpenTargetVisible => IsSelectedItemShortcut || IsDesktopOpenTargetAvailable;
private string? desktopEntryName;
public string? DesktopEntryName
diff --git a/src/Files.App/Dialogs/LinuxOpenWithDialog.cs b/src/Files.App/Dialogs/DesktopOpenWithDialog.cs
similarity index 93%
rename from src/Files.App/Dialogs/LinuxOpenWithDialog.cs
rename to src/Files.App/Dialogs/DesktopOpenWithDialog.cs
index 9d23da40eee5..2b8e38cef218 100644
--- a/src/Files.App/Dialogs/LinuxOpenWithDialog.cs
+++ b/src/Files.App/Dialogs/DesktopOpenWithDialog.cs
@@ -12,7 +12,7 @@ namespace Files.App.Dialogs
///
/// Lets the user choose an installed application to open a file with, optionally making it the default.
///
- internal static class LinuxOpenWithDialog
+ internal static class DesktopOpenWithDialog
{
public static async Task ShowAsync(string path)
{
@@ -36,7 +36,7 @@ public static async Task ShowAsync(string path)
_ = LoadIconAsync(image, app);
}
- var always = new CheckBox { Content = Strings.LinuxAlwaysUseApp.GetLocalizedResource() };
+ var always = new CheckBox { Content = Strings.DesktopAlwaysUseApp.GetLocalizedResource() };
var content = new StackPanel { Spacing = 12, MinWidth = 320 };
content.Children.Add(new TextBlock { Text = Path.GetFileName(path), TextTrimming = TextTrimming.CharacterEllipsis });
content.Children.Add(list);
@@ -67,7 +67,7 @@ private static async Task LoadIconAsync(Image image, DesktopApplication app)
{
try
{
- image.Source = await LinuxAppIcons.GetBitmapAsync(app, 20);
+ image.Source = await DesktopAppIcons.GetBitmapAsync(app, 20);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
diff --git a/src/Files.App/Files.App.csproj b/src/Files.App/Files.App.csproj
index 578b1e23fcd4..0b467e87ee36 100644
--- a/src/Files.App/Files.App.csproj
+++ b/src/Files.App/Files.App.csproj
@@ -88,11 +88,15 @@
-
+
+
+
+
+
$(DefineConstants);UNO_WAYLAND
@@ -102,7 +106,7 @@
-
+
@@ -115,6 +119,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
$(DefaultItemExcludes);Assets/Libraries/**;Assets/FilesOpenDialog/**;Assets/WSL/**;Assets/tile-0-*.png;Assets/AppTiles/**/*.png
@@ -128,9 +147,9 @@
-
+
diff --git a/src/Files.App/Helpers/Application/AppLifecycleHelper.cs b/src/Files.App/Helpers/Application/AppLifecycleHelper.cs
index 9cd693844b82..3c9ab8800c4e 100644
--- a/src/Files.App/Helpers/Application/AppLifecycleHelper.cs
+++ b/src/Files.App/Helpers/Application/AppLifecycleHelper.cs
@@ -316,9 +316,7 @@ public static IServiceProvider ConfigureHost(AppModel appModel)
services
// Platform services
- .AddLinuxPlatform()
- .AddSingleton(_ => Program.SingleInstance ?? new Files.Platform.Linux.Instance.LinuxSingleInstanceService())
- .AddLinuxSystemIntegration()
+ .AddDesktopPlatform()
// Settings services
.AddSingleton()
.AddSingleton(sp => new AppearanceSettingsService(((UserSettingsService)sp.GetRequiredService()).GetSharingContext()))
diff --git a/src/Files.App/Helpers/Application/AppToastNotificationHelper.Linux.cs b/src/Files.App/Helpers/Application/AppToastNotificationHelper.Desktop.cs
similarity index 100%
rename from src/Files.App/Helpers/Application/AppToastNotificationHelper.Linux.cs
rename to src/Files.App/Helpers/Application/AppToastNotificationHelper.Desktop.cs
diff --git a/src/Files.App/Helpers/CredentialsHelpers.cs b/src/Files.App/Helpers/CredentialsHelpers.cs
index ba48ea348d84..058f909143f0 100644
--- a/src/Files.App/Helpers/CredentialsHelpers.cs
+++ b/src/Files.App/Helpers/CredentialsHelpers.cs
@@ -5,12 +5,12 @@ namespace Files.App.Helpers
{
internal sealed class CredentialsHelpers
{
- // Linux: the Secret Service (libsecret backend) through ISecretStore; PasswordVault does not exist there
- private static ISecretStore? LinuxStore => OperatingSystem.IsLinux() ? Ioc.Default.GetService() : null;
+ // Desktop heads: the platform secret store (Secret Service on Linux) through ISecretStore; PasswordVault does not exist there
+ private static ISecretStore? PlatformStore => OperatingSystem.IsWindows() ? null : Ioc.Default.GetService();
public static void SavePassword(string resourceName, string username, string password)
{
- if (LinuxStore is { } store)
+ if (PlatformStore is { } store)
{
store.Save(resourceName, username, password);
return;
@@ -25,7 +25,7 @@ public static void SavePassword(string resourceName, string username, string pas
// Remove saved credentials from the vault
public static void DeleteSavedPassword(string resourceName, string username)
{
- if (LinuxStore is { } store)
+ if (PlatformStore is { } store)
{
store.Delete(resourceName, username);
return;
@@ -39,7 +39,7 @@ public static void DeleteSavedPassword(string resourceName, string username)
public static string GetPassword(string resourceName, string username)
{
- if (LinuxStore is { } store)
+ if (PlatformStore is { } store)
return store.Get(resourceName, username) ?? string.Empty;
try
diff --git a/src/Files.App/Helpers/Layout/LayoutPreferencesDatabase.Linux.cs b/src/Files.App/Helpers/Layout/LayoutPreferencesDatabase.Desktop.cs
similarity index 100%
rename from src/Files.App/Helpers/Layout/LayoutPreferencesDatabase.Linux.cs
rename to src/Files.App/Helpers/Layout/LayoutPreferencesDatabase.Desktop.cs
diff --git a/src/Files.App/Helpers/MenuFlyout/LinuxAppIcons.cs b/src/Files.App/Helpers/MenuFlyout/DesktopAppIcons.cs
similarity index 96%
rename from src/Files.App/Helpers/MenuFlyout/LinuxAppIcons.cs
rename to src/Files.App/Helpers/MenuFlyout/DesktopAppIcons.cs
index ab1aed0f5acc..2b5750e9d2c8 100644
--- a/src/Files.App/Helpers/MenuFlyout/LinuxAppIcons.cs
+++ b/src/Files.App/Helpers/MenuFlyout/DesktopAppIcons.cs
@@ -3,7 +3,7 @@
using Files.Platform.Abstractions.Icons;
using Files.Platform.Abstractions.Mime;
-using Files.Platform.Linux.Icons;
+using Files.Platform.Posix.Icons;
using Microsoft.UI.Xaml.Media.Imaging;
using System.Collections.Concurrent;
using System.IO;
@@ -13,7 +13,7 @@ namespace Files.App.Helpers
///
/// Loads application icons (from the icon theme) for menus and dialogs.
///
- internal static class LinuxAppIcons
+ internal static class DesktopAppIcons
{
private static readonly ConcurrentDictionary<(string Name, uint Size), byte[]?> cache = new();
diff --git a/src/Files.App/Helpers/Navigation/ArchiveOpenTempStore.Linux.cs b/src/Files.App/Helpers/Navigation/ArchiveOpenTempStore.Desktop.cs
similarity index 100%
rename from src/Files.App/Helpers/Navigation/ArchiveOpenTempStore.Linux.cs
rename to src/Files.App/Helpers/Navigation/ArchiveOpenTempStore.Desktop.cs
diff --git a/src/Files.App/Helpers/Navigation/NavigationHelpers.Linux.cs b/src/Files.App/Helpers/Navigation/NavigationHelpers.Desktop.cs
similarity index 68%
rename from src/Files.App/Helpers/Navigation/NavigationHelpers.Linux.cs
rename to src/Files.App/Helpers/Navigation/NavigationHelpers.Desktop.cs
index 951c5746066f..df71f4ef67de 100644
--- a/src/Files.App/Helpers/Navigation/NavigationHelpers.Linux.cs
+++ b/src/Files.App/Helpers/Navigation/NavigationHelpers.Desktop.cs
@@ -5,8 +5,8 @@
using Files.Platform.Abstractions.Archives;
using Files.Platform.Abstractions.Launching;
using Files.Platform.Abstractions.Mime;
-using Files.Platform.Linux.Launching;
-using Files.Platform.Linux.Mime;
+using Files.Platform.Posix.Launching;
+using Files.Platform.Posix.Mime;
using Files.Shared.Helpers;
using Microsoft.Extensions.Logging;
using System.Globalization;
@@ -20,14 +20,14 @@ namespace Files.App.Helpers
///
public static partial class NavigationHelpers
{
- private static ILauncherService LinuxLauncher => Ioc.Default.GetRequiredService();
+ private static ILauncherService DesktopLauncher => Ioc.Default.GetRequiredService();
// A double click can raise the open command twice; a second navigation to the archive would need two Back presses
private static readonly InFlightOpenGate archiveOpenGate = new();
- private static IMimeTypeService LinuxMimeTypes => Ioc.Default.GetRequiredService();
+ private static IMimeTypeService DesktopMimeTypes => Ioc.Default.GetRequiredService();
- private static async Task OpenPathLinuxAsync(string path, IShellPage associatedInstance, bool openViaApplicationPicker, IEnumerable? selectItems, bool forceOpenInNewTab)
+ private static async Task OpenPathDesktopAsync(string path, IShellPage associatedInstance, bool openViaApplicationPicker, IEnumerable? selectItems, bool forceOpenInNewTab)
{
try
{
@@ -66,7 +66,7 @@ private static async Task OpenPathLinuxAsync(string path, IShellPage assoc
if (isArchiveRoot || resolved.Item is not OwlCore.Storage.IFile member)
{
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenFailedTitle.GetLocalizedResource(), Strings.LinuxOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenFailedTitle.GetLocalizedResource(), Strings.DesktopOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
return false;
}
@@ -76,9 +76,9 @@ private static async Task OpenPathLinuxAsync(string path, IShellPage assoc
if (temporaryPath is null)
return false;
- var openedMember = await OpenFileLinuxAsync(temporaryPath, openViaApplicationPicker);
+ var openedMember = await OpenFileDesktopAsync(temporaryPath, openViaApplicationPicker);
if (!openedMember)
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenFailedTitle.GetLocalizedResource(), Strings.LinuxOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenFailedTitle.GetLocalizedResource(), Strings.DesktopOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
return openedMember;
}
@@ -91,9 +91,9 @@ private static async Task OpenPathLinuxAsync(string path, IShellPage assoc
return false;
}
- var opened = await OpenFileLinuxAsync(path, openViaApplicationPicker);
+ var opened = await OpenFileDesktopAsync(path, openViaApplicationPicker);
if (!opened)
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenFailedTitle.GetLocalizedResource(), Strings.LinuxOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenFailedTitle.GetLocalizedResource(), Strings.DesktopOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
return opened;
}
@@ -135,22 +135,22 @@ private static async Task OpenPathLinuxAsync(string path, IShellPage assoc
catch (Exception ex)
{
App.Logger.LogWarning(ex, "Failed to extract archive member {Name}", DisplaySanitizer.Field(name));
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenFailedTitle.GetLocalizedResource(), Strings.LinuxOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(name)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenFailedTitle.GetLocalizedResource(), Strings.DesktopOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(name)));
return null;
}
}
internal static async Task OpenPreviewFileAsync(string path)
{
- if (!await OpenFilesLinuxAsync([path]))
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenFailedTitle.GetLocalizedResource(), Strings.LinuxOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
+ if (!await OpenFilesDesktopAsync([path]))
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenFailedTitle.GetLocalizedResource(), Strings.DesktopOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(path)));
}
///
/// Opens several files. Files that need a gate (executables, launchers) are opened one by one through
- /// ; plain documents are passed to their default applications together.
+ /// ; plain documents are passed to their default applications together.
///
- private static async Task OpenFilesLinuxAsync(IEnumerable paths)
+ private static async Task OpenFilesDesktopAsync(IEnumerable paths)
{
var list = paths.ToList();
@@ -158,8 +158,8 @@ private static async Task OpenFilesLinuxAsync(IEnumerable paths)
if (list.Count > Constants.Actions.MaxSelectedItems)
{
var confirmed = await DialogDisplayHelper.ShowDialogAsync(
- Strings.LinuxOpenManyTitle.GetLocalizedFormatResource(list.Count),
- Strings.LinuxOpenManyText.GetLocalizedResource(),
+ Strings.DesktopOpenManyTitle.GetLocalizedFormatResource(list.Count),
+ Strings.DesktopOpenManyText.GetLocalizedResource(),
Strings.Open.GetLocalizedResource(),
Strings.Cancel.GetLocalizedResource());
@@ -168,7 +168,7 @@ private static async Task OpenFilesLinuxAsync(IEnumerable paths)
}
var success = true;
- var plain = new List<(string Path, LinuxOpenPlan Plan)>();
+ var plain = new List<(string Path, DesktopOpenPlan Plan)>();
foreach (var path in list)
{
var plan = await PlanAsync(path);
@@ -184,7 +184,7 @@ private static async Task OpenFilesLinuxAsync(IEnumerable paths)
success = false;
if (verified.Count > 0)
- success &= await LinuxLauncher.OpenAsync(verified);
+ success &= await DesktopLauncher.OpenAsync(verified);
return success;
}
@@ -193,19 +193,19 @@ private static async Task OpenFilesLinuxAsync(IEnumerable paths)
/// Everything decided about a file before any dialog: the resolved target, its identity, the decision and the
/// parsed .desktop entry. The same entry object is shown in the dialog and launched.
///
- private sealed record LinuxOpenPlan(OpenAction Action, string Target, FileIdentity? Identity, DesktopEntryParser.Entry? Entry, IReadOnlyList? Argv = null, IReadOnlyList>? Invocations = null)
+ private sealed record DesktopOpenPlan(OpenAction Action, string Target, FileIdentity? Identity, DesktopEntryParser.Entry? Entry, IReadOnlyList? Argv = null, IReadOnlyList>? Invocations = null)
{
public bool StillValid() => Identity is { } id && id.StillMatches(Target);
}
- private static async Task PlanAsync(string path)
+ private static async Task PlanAsync(string path)
{
var target = ResolveFinalTarget(path);
var identity = FileIdentity.TryCapture(target);
if (identity is null)
- return new LinuxOpenPlan(OpenAction.Refuse, target, null, null);
+ return new DesktopOpenPlan(OpenAction.Refuse, target, null, null);
- var mime = await LinuxMimeTypes.GetMimeTypeAsync(path);
+ var mime = await DesktopMimeTypes.GetMimeTypeAsync(path);
var hasExec = (identity.Value.Mode & 0b001_001_001) != 0;
// Read the bytes once; the identity must be unchanged afterwards so the bytes belong to that version
@@ -242,14 +242,14 @@ private static async Task PlanAsync(string path)
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
{
- return new LinuxOpenPlan(OpenAction.Refuse, target, null, null);
+ return new DesktopOpenPlan(OpenAction.Refuse, target, null, null);
}
if (!identity.Value.StillMatches(target))
- return new LinuxOpenPlan(OpenAction.Refuse, target, null, null);
+ return new DesktopOpenPlan(OpenAction.Refuse, target, null, null);
var action = OpenDecision.Decide(desktop, desktop == DesktopState.Valid && IsInApplicationsDirectory(target), hasExec, OpenDecision.Sniff(head), mime);
- return new LinuxOpenPlan(action, target, identity, entry, argv);
+ return new DesktopOpenPlan(action, target, identity, entry, argv);
}
///
@@ -270,10 +270,10 @@ private static string ResolveFinalTarget(string path)
return path;
}
- internal static async Task OpenFileLinuxAsync(string path, bool openViaApplicationPicker = false)
+ internal static async Task OpenFileDesktopAsync(string path, bool openViaApplicationPicker = false)
{
if (openViaApplicationPicker)
- return await LinuxOpenWithDialog.ShowAsync(path);
+ return await DesktopOpenWithDialog.ShowAsync(path);
return await ExecutePlanAsync(path, await PlanAsync(path));
}
@@ -282,7 +282,7 @@ internal static async Task OpenFileLinuxAsync(string path, bool openViaApp
/// Runs an executable with the dropped items as arguments. The complete argv (target and every item) is shown and
/// exactly that argv is run; anything that is not a confirmable executable, or too large to show in full, is refused.
///
- internal static async Task RunWithItemsLinuxAsync(string executablePath, IReadOnlyList arguments)
+ internal static async Task RunWithItemsDesktopAsync(string executablePath, IReadOnlyList arguments)
{
var plan = await PlanAsync(executablePath);
var argv = new List(arguments.Count + 1) { plan.Target };
@@ -290,23 +290,23 @@ internal static async Task RunWithItemsLinuxAsync(string executablePath, I
if (!OpenDecision.NeedsRunConfirmation(plan.Action) || DisplaySanitizer.FullArguments(argv) is not { } lines)
{
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenRefusedTitle.GetLocalizedResource(), Strings.LinuxOpenRefusedText.GetLocalizedFormatResource(DisplaySanitizer.Field(plan.Target)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenRefusedTitle.GetLocalizedResource(), Strings.DesktopOpenRefusedText.GetLocalizedFormatResource(DisplaySanitizer.Field(plan.Target)));
return false;
}
var confirmed = await DialogDisplayHelper.ShowDialogAsync(
- Strings.LinuxRunExecutableTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(plan.Target), 60)),
- Strings.LinuxWouldRun.GetLocalizedResource() + "\n" + string.Join('\n', lines),
+ Strings.DesktopRunExecutableTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(plan.Target), 60)),
+ Strings.DesktopWouldRun.GetLocalizedResource() + "\n" + string.Join('\n', lines),
Strings.Run.GetLocalizedResource(),
Strings.Cancel.GetLocalizedResource());
if (!confirmed)
return true;
- return plan.StillValid() ? await LinuxLauncher.RunExecutableAsync(argv[0], argv.Skip(1).ToList(), Path.GetDirectoryName(argv[0])) : false;
+ return plan.StillValid() ? await DesktopLauncher.RunExecutableAsync(argv[0], argv.Skip(1).ToList(), Path.GetDirectoryName(argv[0])) : false;
}
- internal static async Task RunServiceMenuLinuxAsync(ServiceMenuAction action, IReadOnlyList targets)
+ internal static async Task RunServiceMenuDesktopAsync(ServiceMenuAction action, IReadOnlyList targets)
{
var culture = CultureInfo.CurrentUICulture;
var tooManyInvocations = false;
@@ -314,17 +314,17 @@ internal static async Task RunServiceMenuLinuxAsync(ServiceMenuAction acti
if (servicePlan is null)
{
var message = tooManyInvocations
- ? Strings.LinuxServiceMenuTooManyTargetsText.GetLocalizedFormatResource(ServiceMenuLaunchPlan.MaxPerTargetLaunches)
- : Strings.LinuxServiceMenuRefusedText.GetLocalizedResource();
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxServiceMenuTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(action.Application.Name, 60)), message);
+ ? Strings.DesktopServiceMenuTooManyTargetsText.GetLocalizedFormatResource(ServiceMenuLaunchPlan.MaxPerTargetLaunches)
+ : Strings.DesktopServiceMenuRefusedText.GetLocalizedResource();
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopServiceMenuTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(action.Application.Name, 60)), message);
return false;
}
- var plan = new LinuxOpenPlan(OpenAction.LaunchDesktopConfirm, action.Application.DesktopFilePath, servicePlan.Identity,
+ var plan = new DesktopOpenPlan(OpenAction.LaunchDesktopConfirm, action.Application.DesktopFilePath, servicePlan.Identity,
servicePlan.Entry, Invocations: servicePlan.Invocations);
return await ExecutePlanAsync(plan.Target, plan);
}
- private static async Task ExecutePlanAsync(string path, LinuxOpenPlan plan)
+ private static async Task ExecutePlanAsync(string path, DesktopOpenPlan plan)
{
var target = plan.Target;
var workingDirectory = Path.GetDirectoryName(target);
@@ -334,38 +334,38 @@ private static async Task ExecutePlanAsync(string path, LinuxOpenPlan plan
async Task ChangedAsync()
{
App.Logger.LogWarning("File changed before it was opened: {Path}", target);
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxFileChangedTitle.GetLocalizedResource(), Strings.LinuxFileChangedText.GetLocalizedFormatResource(DisplaySanitizer.Field(target)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopFileChangedTitle.GetLocalizedResource(), Strings.DesktopFileChangedText.GetLocalizedFormatResource(DisplaySanitizer.Field(target)));
return false;
}
switch (plan.Action)
{
case OpenAction.Refuse:
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenRefusedTitle.GetLocalizedResource(), Strings.LinuxOpenRefusedText.GetLocalizedFormatResource(DisplaySanitizer.Field(target)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenRefusedTitle.GetLocalizedResource(), Strings.DesktopOpenRefusedText.GetLocalizedFormatResource(DisplaySanitizer.Field(target)));
return false;
case OpenAction.RunBinaryWithConfirm:
{
var confirmed = await DialogDisplayHelper.ShowDialogAsync(
- Strings.LinuxRunExecutableTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(target), 60)),
- Strings.LinuxRunBinaryText.GetLocalizedFormatResource(DisplaySanitizer.Escape(target)),
+ Strings.DesktopRunExecutableTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(target), 60)),
+ Strings.DesktopRunBinaryText.GetLocalizedFormatResource(DisplaySanitizer.Escape(target)),
Strings.Run.GetLocalizedResource(),
Strings.Cancel.GetLocalizedResource());
if (!confirmed)
return true;
- return plan.StillValid() ? await LinuxLauncher.RunExecutableAsync(target, null, workingDirectory) : await ChangedAsync();
+ return plan.StillValid() ? await DesktopLauncher.RunExecutableAsync(target, null, workingDirectory) : await ChangedAsync();
}
case OpenAction.RunScriptWithConfirm:
{
var dialog = new DynamicDialog(new DynamicDialogViewModel()
{
- TitleText = Strings.LinuxRunExecutableTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(target), 60)),
- SubtitleText = Strings.LinuxRunExecutableText.GetLocalizedFormatResource(DisplaySanitizer.Escape(target)),
+ TitleText = Strings.DesktopRunExecutableTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(target), 60)),
+ SubtitleText = Strings.DesktopRunExecutableText.GetLocalizedFormatResource(DisplaySanitizer.Escape(target)),
PrimaryButtonText = Strings.Run.GetLocalizedResource(),
- SecondaryButtonText = Strings.LinuxDisplayFile.GetLocalizedResource(),
+ SecondaryButtonText = Strings.DesktopDisplayFile.GetLocalizedResource(),
CloseButtonText = Strings.Cancel.GetLocalizedResource(),
DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Secondary | DynamicDialogButtons.Cancel
});
@@ -380,7 +380,7 @@ async Task ChangedAsync()
switch (OpenDecision.Resolve(plan.Action, choice))
{
case FollowUp.RunExact:
- return plan.StillValid() ? await LinuxLauncher.RunExecutableAsync(target, null, workingDirectory) : await ChangedAsync();
+ return plan.StillValid() ? await DesktopLauncher.RunExecutableAsync(target, null, workingDirectory) : await ChangedAsync();
case FollowUp.DisplayAsText:
return plan.StillValid() ? await DisplayAsTextAsync(target) : await ChangedAsync();
default:
@@ -402,13 +402,13 @@ async Task ChangedAsync()
return true;
}
if (!plan.StillValid()) return await ChangedAsync();
- success &= await LinuxLauncher.RunCommandAsync(argv, application.RunInTerminal);
+ success &= await DesktopLauncher.RunCommandAsync(argv, application.RunInTerminal);
}
return success;
}
default:
- return plan.StillValid() ? await LinuxLauncher.OpenAsync([path]) : await ChangedAsync();
+ return plan.StillValid() ? await DesktopLauncher.OpenAsync([path]) : await ChangedAsync();
}
}
@@ -421,11 +421,11 @@ private static async Task DisplayAsTextAsync(string target)
var editor = await registry.GetDefaultApplicationAsync("text/plain") ?? (await registry.GetApplicationsForMimeTypeAsync("text/plain")).FirstOrDefault();
if (editor is null)
{
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenFailedTitle.GetLocalizedResource(), Strings.LinuxOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(target)));
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenFailedTitle.GetLocalizedResource(), Strings.DesktopOpenFailedText.GetLocalizedFormatResource(DisplaySanitizer.Field(target)));
return false;
}
- return await LinuxLauncher.OpenWithAsync(editor, [target]);
+ return await DesktopLauncher.OpenWithAsync(editor, [target]);
}
private static async Task ShowLauncherConfirmationAsync(string target, string claimedName, IReadOnlyList argv, bool inTerminal, bool isServiceMenu = false)
@@ -433,14 +433,14 @@ private static async Task ShowLauncherConfirmationAsync(string target, str
// What will run must be shown in full; if it cannot be, it does not run
if (DisplaySanitizer.FullArguments(argv) is not { } lines)
{
- await DialogDisplayHelper.ShowDialogAsync(Strings.LinuxOpenRefusedTitle.GetLocalizedResource(), Strings.LinuxCommandTooLong.GetLocalizedResource());
+ await DialogDisplayHelper.ShowDialogAsync(Strings.DesktopOpenRefusedTitle.GetLocalizedResource(), Strings.DesktopCommandTooLong.GetLocalizedResource());
return false;
}
var panel = new Microsoft.UI.Xaml.Controls.StackPanel { Spacing = 8 };
- panel.Children.Add(new Microsoft.UI.Xaml.Controls.TextBlock { Text = Strings.LinuxFileLabel.GetLocalizedResource() + " " + DisplaySanitizer.Escape(target), TextWrapping = Microsoft.UI.Xaml.TextWrapping.Wrap, IsTextSelectionEnabled = true });
- panel.Children.Add(new Microsoft.UI.Xaml.Controls.TextBlock { Text = Strings.LinuxClaimsToBe.GetLocalizedResource() + " " + DisplaySanitizer.Field(claimedName), TextWrapping = Microsoft.UI.Xaml.TextWrapping.Wrap });
- panel.Children.Add(new Microsoft.UI.Xaml.Controls.TextBlock { Text = Strings.LinuxWouldRun.GetLocalizedResource() + (inTerminal ? " (" + Strings.LinuxInTerminal.GetLocalizedResource() + ")" : string.Empty) });
+ panel.Children.Add(new Microsoft.UI.Xaml.Controls.TextBlock { Text = Strings.DesktopFileLabel.GetLocalizedResource() + " " + DisplaySanitizer.Escape(target), TextWrapping = Microsoft.UI.Xaml.TextWrapping.Wrap, IsTextSelectionEnabled = true });
+ panel.Children.Add(new Microsoft.UI.Xaml.Controls.TextBlock { Text = Strings.DesktopClaimsToBe.GetLocalizedResource() + " " + DisplaySanitizer.Field(claimedName), TextWrapping = Microsoft.UI.Xaml.TextWrapping.Wrap });
+ panel.Children.Add(new Microsoft.UI.Xaml.Controls.TextBlock { Text = Strings.DesktopWouldRun.GetLocalizedResource() + (inTerminal ? " (" + Strings.DesktopInTerminal.GetLocalizedResource() + ")" : string.Empty) });
panel.Children.Add(new Microsoft.UI.Xaml.Controls.ScrollViewer
{
MaxHeight = 240,
@@ -457,9 +457,9 @@ private static async Task ShowLauncherConfirmationAsync(string target, str
var dialog = new DynamicDialog(new DynamicDialogViewModel()
{
TitleText = isServiceMenu
- ? Strings.LinuxServiceMenuTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(claimedName, 60))
- : Strings.LinuxUntrustedLauncherTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(target), 60)),
- SubtitleText = (isServiceMenu ? Strings.LinuxServiceMenuConfirmationText : Strings.LinuxUntrustedLauncherText).GetLocalizedResource(),
+ ? Strings.DesktopServiceMenuTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(claimedName, 60))
+ : Strings.DesktopUntrustedLauncherTitle.GetLocalizedFormatResource(DisplaySanitizer.Field(Path.GetFileName(target), 60)),
+ SubtitleText = (isServiceMenu ? Strings.DesktopServiceMenuConfirmationText : Strings.DesktopUntrustedLauncherText).GetLocalizedResource(),
DisplayControl = panel,
PrimaryButtonText = Strings.Run.GetLocalizedResource(),
CloseButtonText = Strings.Cancel.GetLocalizedResource(),
diff --git a/src/Files.App/Helpers/Navigation/NavigationHelpers.cs b/src/Files.App/Helpers/Navigation/NavigationHelpers.cs
index cb42f0e63189..51598da4043c 100644
--- a/src/Files.App/Helpers/Navigation/NavigationHelpers.cs
+++ b/src/Files.App/Helpers/Navigation/NavigationHelpers.cs
@@ -386,9 +386,9 @@ await SafetyExtensions.IgnoreExceptions(async () =>
: navigationArg == MainPageViewModel.SelectedTabItem?.NavigationParameter?.NavigationParameter;
if (isCurrent)
{
- var title = $"{windowTitle} - {(OperatingSystem.IsLinux() ? Strings.LinuxAppDisplayName.GetLocalizedResource() : "Files")}";
- title = Files.Platform.Linux.Windowing.X11WindowChrome.SanitizeTitle(MainWindow.FormatRootModeTitle(title));
- MainWindow.Instance.UpdateLinuxWindowTitle(title);
+ var title = $"{windowTitle} - {(OperatingSystem.IsLinux() ? Strings.DesktopAppDisplayName.GetLocalizedResource() : "Files")}";
+ title = Files.Platform.Posix.WindowTitle.Sanitize(MainWindow.FormatRootModeTitle(title));
+ MainWindow.Instance.UpdateWindowTitle(title);
MainWindow.Instance.AppWindow.Title = title;
}
});
@@ -425,7 +425,7 @@ public static Task OpenTabInNewWindowAsync(string tabArgs, int? dropX = nu
}
// The Linux app has one window per process, so a new window is a second process that skips single instance forwarding
- private static Task LaunchNewLinuxInstance()
+ private static Task LaunchNewDesktopInstance()
{
try
{
@@ -442,7 +442,7 @@ private static Task LaunchNewLinuxInstance()
startInfo.Environment["FILES_NO_SINGLE_INSTANCE"] = "1";
startInfo.ArgumentList.Add("--new-window");
- if (Files.Platform.Linux.Elevation.RootActionMode.IsRequested(Program.LaunchArguments))
+ if (Files.Platform.Posix.Elevation.RootActionMode.IsRequested(Program.LaunchArguments))
startInfo.ArgumentList.Add("--root");
System.Diagnostics.Process.Start(startInfo)?.Dispose();
}
@@ -467,7 +467,7 @@ public static void OpenInSecondaryPane(IShellPage associatedInstance, ListedItem
public static Task LaunchNewWindowAsync()
{
if (OperatingSystem.IsLinux())
- return LaunchNewLinuxInstance();
+ return LaunchNewDesktopInstance();
return Launcher.LaunchUriAsync(new Uri("files-dev:?window=")).AsTask();
}
@@ -499,7 +499,7 @@ public static async Task OpenSelectedItemsAsync(IShellPage associatedInstance, b
!Ioc.Default.GetRequiredService().IsArchiveFileName(x.GetRequiredPath()))
)
{
- opened = await OpenFilesLinuxAsync(selectedItems.Select(x => x.GetRequiredPath()));
+ opened = await OpenFilesDesktopAsync(selectedItems.Select(x => x.GetRequiredPath()));
}
if (opened)
@@ -534,7 +534,7 @@ public static async Task OpenItemsWithExecutableAsync(IShellPage associatedInsta
if (workingDirectory.StartsWith(Constants.UserEnvironmentPaths.RecycleBinPath, StringComparison.Ordinal))
return;
- await RunWithItemsLinuxAsync(executablePath, items.Select(item => item.Path).ToArray());
+ await RunWithItemsDesktopAsync(executablePath, items.Select(item => item.Path).ToArray());
}
///
@@ -573,7 +573,7 @@ public static async Task OpenPath(string path, IShellPage associatedInstan
return true;
}
- return await OpenPathLinuxAsync(path, associatedInstance, openViaApplicationPicker, selectItems, forceOpenInNewTab);
+ return await OpenPathDesktopAsync(path, associatedInstance, openViaApplicationPicker, selectItems, forceOpenInNewTab);
}
diff --git a/src/Files.App/Helpers/RootActionsHelper.cs b/src/Files.App/Helpers/RootActionsHelper.cs
index 6a2fd57b5e73..c8daab9e2508 100644
--- a/src/Files.App/Helpers/RootActionsHelper.cs
+++ b/src/Files.App/Helpers/RootActionsHelper.cs
@@ -4,8 +4,9 @@
using Files.Platform.Abstractions.Clipboard;
using Files.Platform.Abstractions.Launching;
using Files.Platform.Abstractions.Elevation;
+using Files.Platform.Posix.Elevation;
+using Files.Platform.Posix.Launching;
using Files.Platform.Linux.Elevation;
-using Files.Platform.Linux.Launching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.IO;
diff --git a/src/Files.App/MainWindow.Linux.cs b/src/Files.App/MainWindow.Linux.cs
index 5e33cabff562..764faf9f44ee 100644
--- a/src/Files.App/MainWindow.Linux.cs
+++ b/src/Files.App/MainWindow.Linux.cs
@@ -16,13 +16,13 @@ namespace Files.App
{
public sealed partial class MainWindow
{
- private X11WindowChrome? _linuxChrome;
+ private X11WindowChrome? _desktopChrome;
private PropertyChangedEventHandler? _appearanceChanged;
private EventHandler? _systemAppearanceChanged;
private bool _chromeEventsAttached;
private int _dragStart;
private int _titleHeight;
- private string? _linuxWindowTitle;
+ private string? _desktopWindowTitle;
#if UNO_WAYLAND
private bool _waylandWindow;
// The Wayland host implements caption regions, move and maximize itself (InputNonClientPointerSource, presenter).
@@ -32,35 +32,35 @@ public sealed partial class MainWindow
#endif
public bool UseClientSideDecorations => OperatingSystem.IsLinux() &&
Ioc.Default.GetRequiredService().Get("UseClientSideDecorations", true);
- public bool HasClientSideDecorations => (_linuxChrome?.SupportsClientSideDecorations == true || IsWaylandWindow) && UseClientSideDecorations;
- public bool IsLinuxWindowMaximized => _linuxChrome?.IsMaximized ??
+ public bool HasClientSideDecorations => (_desktopChrome?.SupportsClientSideDecorations == true || IsWaylandWindow) && UseClientSideDecorations;
+ public bool IsWindowMaximized => _desktopChrome?.IsMaximized ??
(IsWaylandWindow && AppWindow.Presenter is OverlappedPresenter { State: OverlappedPresenterState.Maximized });
- public event EventHandler? LinuxChromeChanged;
+ public event EventHandler? ChromeChanged;
internal static string FormatRootModeTitle(string title) => title + (RootActionsAvailability.Mode.Indicator switch
{
- RootModeIndicator.RootMode => Strings.LinuxRootModeSuffix.GetLocalizedResource(),
- RootModeIndicator.RunningAsRoot => Strings.LinuxRunningAsRootSuffix.GetLocalizedResource(),
+ RootModeIndicator.RootMode => Strings.DesktopRootModeSuffix.GetLocalizedResource(),
+ RootModeIndicator.RunningAsRoot => Strings.DesktopRunningAsRootSuffix.GetLocalizedResource(),
_ => string.Empty,
});
- public void InitializeLinuxChrome()
+ public void InitializeChrome()
{
if (!OperatingSystem.IsLinux())
return;
var nativeWindow = Uno.UI.Xaml.WindowHelper.GetNativeWindow(this);
- if (_linuxChrome is null && nativeWindow is X11NativeWindow native)
- _linuxChrome = X11WindowChrome.TryCreate((nuint)native.WindowId);
+ if (_desktopChrome is null && nativeWindow is X11NativeWindow native)
+ _desktopChrome = X11WindowChrome.TryCreate((nuint)native.WindowId);
#if UNO_WAYLAND
// Only the X11 and Wayland hosts are registered, so any other native window is the Wayland surface.
_waylandWindow = nativeWindow is not null and not X11NativeWindow;
#endif
if (!HasClientSideDecorations)
- _linuxChrome?.HideRegions();
- if (_linuxWindowTitle is not null)
- _linuxChrome?.SetTitle(_linuxWindowTitle);
+ _desktopChrome?.HideRegions();
+ if (_desktopWindowTitle is not null)
+ _desktopChrome?.SetTitle(_desktopWindowTitle);
ExtendsContentIntoTitleBar = HasClientSideDecorations;
if (AppWindow.Presenter is OverlappedPresenter presenter)
@@ -71,62 +71,62 @@ public void InitializeLinuxChrome()
_chromeEventsAttached = true;
AppWindow.Changed += (_, _) =>
{
- UpdateLinuxChromeRegions(_dragStart, _titleHeight);
- LinuxChromeChanged?.Invoke(this, EventArgs.Empty);
+ UpdateChromeRegions(_dragStart, _titleHeight);
+ ChromeChanged?.Invoke(this, EventArgs.Empty);
};
Closed += (_, _) =>
{
Ioc.Default.GetRequiredService().PropertyChanged -= _appearanceChanged;
Ioc.Default.GetRequiredService().Changed -= _systemAppearanceChanged;
X11AppearanceSupport.Changed -= _systemAppearanceChanged;
- _linuxChrome?.Dispose(); _linuxChrome = null;
+ _desktopChrome?.Dispose(); _desktopChrome = null;
};
var appearance = Ioc.Default.GetRequiredService();
_appearanceChanged = (_, e) =>
{
if (e.PropertyName is nameof(IAppearanceSettingsService.WindowOpacity) or nameof(IAppearanceSettingsService.BackdropMode) or nameof(IAppearanceSettingsService.BackgroundOpacity))
- DispatcherQueue.TryEnqueue(ApplyLinuxWindowOpacity);
+ DispatcherQueue.TryEnqueue(ApplyDesktopWindowOpacity);
};
appearance.PropertyChanged += _appearanceChanged;
- _systemAppearanceChanged = (_, _) => DispatcherQueue.TryEnqueue(ApplyLinuxWindowOpacity);
+ _systemAppearanceChanged = (_, _) => DispatcherQueue.TryEnqueue(ApplyDesktopWindowOpacity);
Ioc.Default.GetRequiredService().Changed += _systemAppearanceChanged;
X11AppearanceSupport.Changed += _systemAppearanceChanged;
}
- ApplyLinuxWindowOpacity();
+ ApplyDesktopWindowOpacity();
Ioc.Default.GetRequiredService().ApplyResources();
- LinuxChromeChanged?.Invoke(this, EventArgs.Empty);
+ ChromeChanged?.Invoke(this, EventArgs.Empty);
}
- private void ApplyLinuxWindowOpacity()
+ private void ApplyDesktopWindowOpacity()
{
var appearance = Ioc.Default.GetRequiredService();
var highContrast = Ioc.Default.GetRequiredService().Current.HighContrast == true;
var support = X11AppearanceSupport.Current;
- _linuxChrome?.SetWindowOpacity(!highContrast && support.WindowOpacity == OpacitySupport.Supported ? appearance.WindowOpacity : 1);
+ _desktopChrome?.SetWindowOpacity(!highContrast && support.WindowOpacity == OpacitySupport.Supported ? appearance.WindowOpacity : 1);
var mode = support.Resolve(appearance.BackdropMode, highContrast);
Uno.UI.Xaml.WindowHelper.SetBackground(this, new SolidColorBrush(mode == BackdropMode.Solid ?
(appearance.AppThemeMode == "Dark" || appearance.AppThemeMode == "Default" && Files.Platform.Linux.Theme.LinuxColorScheme.IsDark ? Colors.Black : Colors.White) : Colors.Transparent));
- _linuxChrome?.SetBlur(mode == BackdropMode.Blur);
+ _desktopChrome?.SetBlur(mode == BackdropMode.Blur);
}
public void SetClientSideDecorations(bool enabled)
{
Ioc.Default.GetRequiredService().Set("UseClientSideDecorations", enabled);
- InitializeLinuxChrome();
+ InitializeChrome();
}
- public void UpdateLinuxWindowTitle(string title)
+ public void UpdateWindowTitle(string title)
{
// Uno 6.7 can leave the native title unchanged after setting AppWindow.Title.
- _linuxWindowTitle = title;
- _linuxChrome?.SetTitle(title);
+ _desktopWindowTitle = title;
+ _desktopChrome?.SetTitle(title);
}
- public void ToggleLinuxWindowMaximize()
+ public void ToggleWindowMaximize()
{
- if (_linuxChrome is not null)
- _linuxChrome.ToggleMaximize();
+ if (_desktopChrome is not null)
+ _desktopChrome.ToggleMaximize();
else if (IsWaylandWindow && AppWindow.Presenter is OverlappedPresenter presenter)
{
if (presenter.State == OverlappedPresenterState.Maximized)
@@ -136,7 +136,7 @@ public void ToggleLinuxWindowMaximize()
}
}
- public void UpdateLinuxChromeRegions(int dragStart, int titleHeight)
+ public void UpdateChromeRegions(int dragStart, int titleHeight)
{
_dragStart = dragStart;
_titleHeight = titleHeight;
@@ -155,7 +155,7 @@ public void UpdateLinuxChromeRegions(int dragStart, int titleHeight)
]);
return;
}
- _linuxChrome?.SetRegions((int)(root.ActualWidth * scale), (int)(root.ActualHeight * scale),
+ _desktopChrome?.SetRegions((int)(root.ActualWidth * scale), (int)(root.ActualHeight * scale),
(int)(dragStart * scale), (int)((root.ActualWidth - dragStart - 138) * scale),
(int)(titleHeight * scale), Math.Max(1, (int)(5 * scale)));
}
diff --git a/src/Files.App/MainWindow.xaml.cs b/src/Files.App/MainWindow.xaml.cs
index dd1f36d56784..8fc7ebf6fd60 100644
--- a/src/Files.App/MainWindow.xaml.cs
+++ b/src/Files.App/MainWindow.xaml.cs
@@ -35,7 +35,7 @@ public MainWindow() : base(416, 316)
InitializeComponent();
ExtendsContentIntoTitleBar = UseClientSideDecorations;
- Title = OperatingSystem.IsLinux() ? Strings.LinuxAppDisplayName.GetLocalizedResource() : "Files";
+ Title = OperatingSystem.IsLinux() ? Strings.DesktopAppDisplayName.GetLocalizedResource() : "Files";
Title = FormatRootModeTitle(Title);
AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
diff --git a/src/Files.App/Platforms/Desktop/App.Desktop.cs b/src/Files.App/Platforms/Desktop/App.Desktop.cs
index d68f80b46dfc..3ddac90196e3 100644
--- a/src/Files.App/Platforms/Desktop/App.Desktop.cs
+++ b/src/Files.App/Platforms/Desktop/App.Desktop.cs
@@ -102,15 +102,7 @@ private void StartInstanceRequestListener()
try
{
var settings = Ioc.Default.GetRequiredService().GeneralSettingsService;
- var fileManager = Ioc.Default.GetRequiredService();
-
- async Task Apply()
- {
- if (settings.UseAsDefaultFileManager)
- await fileManager.StartAsync();
- else
- await fileManager.StopAsync();
- }
+ async Task Apply() => await DesktopPlatform.SetDefaultFileManagerAsync(settings.UseAsDefaultFileManager);
await Apply();
settings.PropertyChanged += async (_, e) =>
diff --git a/src/Files.App/Platforms/Desktop/DesktopPlatform.cs b/src/Files.App/Platforms/Desktop/DesktopPlatform.cs
new file mode 100644
index 000000000000..ffd0dd2a37c1
--- /dev/null
+++ b/src/Files.App/Platforms/Desktop/DesktopPlatform.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Files Community
+// Licensed under the MIT License.
+
+using Files.Platform.Linux.Instance;
+using Microsoft.Extensions.DependencyInjection;
+using Windows.ApplicationModel.DataTransfer;
+
+namespace Files.App
+{
+ ///
+ /// The single place where the shared app layer binds to the desktop head's platform assembly.
+ ///
+ internal static class DesktopPlatform
+ {
+ ///
+ /// Creates the user directories before the DI container exists (used by static path constants).
+ ///
+ public static IUserDirectories CreateUserDirectories()
+ => new Files.Platform.Linux.LinuxUserDirectories();
+
+ ///
+ /// Adds the file list of a drag to in the format other applications of the desktop read.
+ ///
+ public static void SetDraggedFiles(DataPackage data, IReadOnlyList paths)
+ => data.SetData(Files.Platform.Linux.Clipboard.ClipboardFormats.UriList, Files.Platform.Linux.Clipboard.ClipboardFormats.BuildUriList(paths));
+
+ ///
+ /// Gets the effective display scale used to size windows from physical pixels.
+ ///
+ public static double GetDisplayScale()
+ => Files.Platform.Linux.Windowing.DisplayScaleResolver.GetEffectiveScale();
+
+ ///
+ /// Starts or stops the desktop's file manager service (FileManager1 on Linux).
+ ///
+ public static Task SetDefaultFileManagerAsync(bool enabled)
+ {
+ var fileManager = Ioc.Default.GetRequiredService();
+ return enabled ? fileManager.StartAsync() : fileManager.StopAsync();
+ }
+
+ ///
+ /// Registers the platform and system integration services of the desktop head.
+ ///
+ public static IServiceCollection AddDesktopPlatform(this IServiceCollection services)
+ => services
+ .AddLinuxPlatform()
+ .AddSingleton(_ => Program.SingleInstance ?? new LinuxSingleInstanceService())
+ .AddLinuxSystemIntegration();
+ }
+}
diff --git a/src/Files.App/Platforms/Desktop/Program.Linux.cs b/src/Files.App/Platforms/Desktop/Program.Linux.cs
new file mode 100644
index 000000000000..ed69c76ae083
--- /dev/null
+++ b/src/Files.App/Platforms/Desktop/Program.Linux.cs
@@ -0,0 +1,136 @@
+// Copyright (c) Files Community
+// Licensed under the MIT License.
+
+using Files.Platform.Abstractions.Instance;
+using Files.Platform.Linux.Elevation;
+using Files.Platform.Linux.Instance;
+using Files.Platform.Linux.Windowing;
+using Uno.UI.Hosting;
+
+namespace Files.App
+{
+ ///
+ /// The Linux (Wayland/X11) part of the entry point: startup environment, single instance and the Uno host.
+ ///
+ internal sealed partial class Program
+ {
+ ///
+ /// Gets the single instance service this process owns. Null when single instance handling is disabled.
+ ///
+ internal static LinuxSingleInstanceService? SingleInstance { get; private set; }
+
+ private static bool TryRunPlatformHelper(string[] args, out int exitCode)
+ => Files.Platform.Linux.Previews.HtmlSnapshotHelper.TryRunHelper(args, out exitCode);
+
+ ///
+ /// Applies the root startup environment. Returns false when the process must not continue.
+ ///
+ private static bool TryApplyStartupEnvironment(string[] args)
+ {
+ try
+ {
+ using var trace = Files.Platform.Abstractions.Diagnostics.PerformanceTrace.Begin("startup.root-environment");
+ RootStartupEnvironment.Apply();
+ }
+ catch (System.IO.IOException)
+ {
+ Console.Error.WriteLine("[Files] Refusing root startup: root's account and settings directories must be exclusively controlled by root.");
+ return false;
+ }
+ RootActionsAvailability.Configure(args);
+ return true;
+ }
+
+ private static void InitializePlatform()
+ {
+ // Selawik weights (Regular/Semibold/Bold/Light) are matched by family name + weight through fontconfig
+ Files.Platform.Linux.Native.FontConfigNative.RegisterFontDirectory(System.IO.Path.Combine(AppContext.BaseDirectory, "Assets", "Fonts", "Linux"));
+
+ // Uno reads Xft.dpi itself; this covers sessions that only export GDK/Qt scale variables
+ Files.Platform.Linux.Windowing.DisplayScaleResolver.ApplyToProcess();
+ }
+
+ ///
+ /// Returns false when the command line was forwarded to the running instance.
+ ///
+ private static bool TryBecomePrimaryInstance(string[] args)
+ {
+ // Root-mode launches use a separate process so they never change or forward into an ordinary window.
+ // Ordinary second launches forward through D-Bus (socket fallback).
+ // FILES_NO_SINGLE_INSTANCE=1 skips this (for running several instances side by side while developing).
+ var noSingleInstance = !RootActionsAvailability.Mode.UseSingleInstance || Environment.GetEnvironmentVariable("FILES_NO_SINGLE_INSTANCE") == "1";
+
+ // Keep the flag from leaking into apps and terminals launched from this instance
+ Environment.SetEnvironmentVariable("FILES_NO_SINGLE_INSTANCE", null);
+
+ if (noSingleInstance)
+ return true;
+
+ var singleInstance = new LinuxSingleInstanceService();
+ var request = new InstanceRequest(InstanceRequestKind.CommandLine, Environment.CurrentDirectory, args);
+
+ bool isPrimary;
+ try
+ {
+ using var trace = Files.Platform.Abstractions.Diagnostics.PerformanceTrace.Begin("startup.single-instance");
+ isPrimary = singleInstance.TryBecomePrimaryAsync(request).GetAwaiter().GetResult();
+ }
+ catch (Exception ex) when (ex is System.IO.IOException or InvalidOperationException or System.Net.Sockets.SocketException or UnauthorizedAccessException)
+ {
+ Console.Error.WriteLine($"[Files] Single instance check failed, continuing: {ex.Message}");
+ isPrimary = true;
+ }
+
+ if (!isPrimary)
+ {
+ Console.Error.WriteLine("[Files] Forwarded the command line to the running instance.");
+ return false;
+ }
+
+ SingleInstance = singleInstance;
+ return true;
+ }
+
+ ///
+ /// Builds the Uno host for the display server and runs it until the app exits.
+ ///
+ private static void RunHost()
+ {
+ // Software GL (llvmpipe) is slower than Uno's software renderer; FILES_RENDERER=software|opengl|gles|vulkan overrides
+ var (renderingBackend, reason) = RenderingBackendSelector.Resolve(Environment.GetEnvironmentVariable, RenderingBackendSelector.HasGpuDevice);
+ Console.Error.WriteLine($"[Files] Rendering backend: {renderingBackend} ({reason ?? "default"})");
+
+ using (var trace = Files.Platform.Abstractions.Diagnostics.PerformanceTrace.Begin("startup.cursor"))
+ CursorSettingsResolver.ApplyToProcess();
+
+ var hostBuilder = UnoPlatformHostBuilder.Create()
+ .App(() => new App());
+#if UNO_WAYLAND
+ // Preferred when WAYLAND_DISPLAY is set; UNO_SKIA_HOST=x11|wayland|auto overrides the choice
+ hostBuilder = hostBuilder.UseWayland();
+#endif
+ var host = hostBuilder
+ .UseX11(x11 => x11.RenderingBackend(renderingBackend switch
+ {
+ RenderingBackendChoice.Software => X11RenderingBackend.Software,
+ RenderingBackendChoice.OpenGL => X11RenderingBackend.OpenGL,
+ RenderingBackendChoice.OpenGLES => X11RenderingBackend.OpenGLES,
+ RenderingBackendChoice.Vulkan => X11RenderingBackend.Vulkan,
+ _ => X11RenderingBackend.Default,
+ }))
+ .Build();
+
+ using var scaleCancellation = new CancellationTokenSource();
+ var scaleWatcher = DisplayScaleResolver.WatchCompositorScaleAsync(scaleCancellation.Token);
+ try
+ {
+ host.Run();
+ }
+ finally
+ {
+ scaleCancellation.Cancel();
+ scaleWatcher.GetAwaiter().GetResult();
+ }
+ }
+ }
+}
diff --git a/src/Files.App/Platforms/Desktop/Program.cs b/src/Files.App/Platforms/Desktop/Program.cs
index d2fdcf03eb65..a2de0e4fc56c 100644
--- a/src/Files.App/Platforms/Desktop/Program.cs
+++ b/src/Files.App/Platforms/Desktop/Program.cs
@@ -1,12 +1,7 @@
// Copyright (c) Files Community
// Licensed under the MIT License.
-using Files.Platform.Abstractions.Instance;
-using Files.Platform.Linux.Instance;
-using Files.Platform.Linux.Elevation;
-using Files.Platform.Linux.Windowing;
using System.Text;
-using Uno.UI.Hosting;
namespace Files.App
{
@@ -14,7 +9,7 @@ namespace Files.App
/// Represents the entry point of the Files app on Uno Platform (Skia desktop, Wayland/X11).
/// Replaces Program.cs, which is built for Windows only (WinAppSDK AppInstance redirection).
///
- internal sealed class Program
+ internal sealed partial class Program
{
///
/// Gets or sets the semaphore a parked (background) instance waits on. Unused on desktop for now.
@@ -31,105 +26,30 @@ internal sealed class Program
///
public static string[] LaunchArguments { get; private set; } = [];
- ///
- /// Gets the single instance service this process owns. Null when single instance handling is disabled.
- ///
- internal static LinuxSingleInstanceService? SingleInstance { get; private set; }
-
[STAThread]
public static int Main(string[] args)
{
- if (Files.Platform.Linux.Previews.HtmlSnapshotHelper.TryRunHelper(args, out var helperExitCode)) return helperExitCode;
- try
- {
- using var trace = Files.Platform.Abstractions.Diagnostics.PerformanceTrace.Begin("startup.root-environment");
- RootStartupEnvironment.Apply();
- }
- catch (System.IO.IOException)
- {
- Console.Error.WriteLine("[Files] Refusing root startup: root's account and settings directories must be exclusively controlled by root.");
+ if (TryRunPlatformHelper(args, out var helperExitCode))
+ return helperExitCode;
+
+ if (!TryApplyStartupEnvironment(args))
return 1;
- }
- RootActionsAvailability.Configure(args);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
- // Selawik weights (Regular/Semibold/Bold/Light) are matched by family name + weight through fontconfig
- Files.Platform.Linux.Native.FontConfigNative.RegisterFontDirectory(System.IO.Path.Combine(AppContext.BaseDirectory, "Assets", "Fonts", "Linux"));
+ InitializePlatform();
LaunchArguments = args;
- // Uno reads Xft.dpi itself; this covers sessions that only export GDK/Qt scale variables
- Files.Platform.Linux.Windowing.DisplayScaleResolver.ApplyToProcess();
-
- // Root-mode launches use a separate process so they never change or forward into an ordinary window.
- // Ordinary second launches forward through D-Bus (socket fallback).
- // FILES_NO_SINGLE_INSTANCE=1 skips this (for running several instances side by side while developing).
- var noSingleInstance = !RootActionsAvailability.Mode.UseSingleInstance || Environment.GetEnvironmentVariable("FILES_NO_SINGLE_INSTANCE") == "1";
-
- // Keep the flag from leaking into apps and terminals launched from this instance
- Environment.SetEnvironmentVariable("FILES_NO_SINGLE_INSTANCE", null);
-
- if (!noSingleInstance)
- {
- var singleInstance = new LinuxSingleInstanceService();
- var request = new InstanceRequest(InstanceRequestKind.CommandLine, Environment.CurrentDirectory, args);
-
- bool isPrimary;
- try
- {
- using var trace = Files.Platform.Abstractions.Diagnostics.PerformanceTrace.Begin("startup.single-instance");
- isPrimary = singleInstance.TryBecomePrimaryAsync(request).GetAwaiter().GetResult();
- }
- catch (Exception ex) when (ex is System.IO.IOException or InvalidOperationException or System.Net.Sockets.SocketException or UnauthorizedAccessException)
- {
- Console.Error.WriteLine($"[Files] Single instance check failed, continuing: {ex.Message}");
- isPrimary = true;
- }
-
- if (!isPrimary)
- {
- Console.Error.WriteLine("[Files] Forwarded the command line to the running instance.");
- return 0;
- }
-
- SingleInstance = singleInstance;
- }
-
- // Software GL (llvmpipe) is slower than Uno's software renderer; FILES_RENDERER=software|opengl|gles|vulkan overrides
- var (renderingBackend, reason) = RenderingBackendSelector.Resolve(Environment.GetEnvironmentVariable, RenderingBackendSelector.HasGpuDevice);
- Console.Error.WriteLine($"[Files] Rendering backend: {renderingBackend} ({reason ?? "default"})");
-
- using (var trace = Files.Platform.Abstractions.Diagnostics.PerformanceTrace.Begin("startup.cursor"))
- CursorSettingsResolver.ApplyToProcess();
-
- var hostBuilder = UnoPlatformHostBuilder.Create()
- .App(() => new App());
-#if UNO_WAYLAND
- // Preferred when WAYLAND_DISPLAY is set; UNO_SKIA_HOST=x11|wayland|auto overrides the choice
- hostBuilder = hostBuilder.UseWayland();
-#endif
- var host = hostBuilder
- .UseX11(x11 => x11.RenderingBackend(renderingBackend switch
- {
- RenderingBackendChoice.Software => X11RenderingBackend.Software,
- RenderingBackendChoice.OpenGL => X11RenderingBackend.OpenGL,
- RenderingBackendChoice.OpenGLES => X11RenderingBackend.OpenGLES,
- RenderingBackendChoice.Vulkan => X11RenderingBackend.Vulkan,
- _ => X11RenderingBackend.Default,
- }))
- .Build();
+ if (!TryBecomePrimaryInstance(args))
+ return 0;
- using var scaleCancellation = new CancellationTokenSource();
- var scaleWatcher = DisplayScaleResolver.WatchCompositorScaleAsync(scaleCancellation.Token);
try
{
- host.Run();
+ RunHost();
}
finally
{
- scaleCancellation.Cancel();
- scaleWatcher.GetAwaiter().GetResult();
FileTagsHelper.DrainPendingWritesAsync().GetAwaiter().GetResult();
}
diff --git a/src/Files.App/Platforms/Desktop/Services/DesktopFileDragHelper.cs b/src/Files.App/Platforms/Desktop/Services/DesktopFileDragHelper.cs
index 8690a1100632..380278dcb2f8 100644
--- a/src/Files.App/Platforms/Desktop/Services/DesktopFileDragHelper.cs
+++ b/src/Files.App/Platforms/Desktop/Services/DesktopFileDragHelper.cs
@@ -106,7 +106,7 @@ public static void StartDrag(DataPackage data, IEnumerable paths)
var existing = ExistingPaths(paths);
if (existing.Count > 0)
- data.SetData(Files.Platform.Linux.Clipboard.ClipboardFormats.UriList, Files.Platform.Linux.Clipboard.ClipboardFormats.BuildUriList(existing));
+ DesktopPlatform.SetDraggedFiles(data, existing);
}
///
diff --git a/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs b/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs
index 7edce704d6dc..8bb392b2d75b 100644
--- a/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs
+++ b/src/Files.App/Platforms/Desktop/Services/LinuxIconHelper.cs
@@ -149,7 +149,7 @@ internal static IconColorScheme CurrentColorScheme
try
{
byte[]? data;
- using (var stream = Files.Platform.Linux.Previews.PreviewFile.OpenRead(iconPath))
+ using (var stream = Files.Platform.Posix.Previews.PreviewFile.OpenRead(iconPath))
data = DesktopEntryDisplay.ReadBounded(stream, MaxIconFileSize);
if (data is null)
diff --git a/src/Files.App/Platforms/Desktop/ViewModels/ShellViewModel.Linux.cs b/src/Files.App/Platforms/Desktop/ViewModels/ShellViewModel.Desktop.cs
similarity index 84%
rename from src/Files.App/Platforms/Desktop/ViewModels/ShellViewModel.Linux.cs
rename to src/Files.App/Platforms/Desktop/ViewModels/ShellViewModel.Desktop.cs
index ae540f5f385f..77822b2ea1cb 100644
--- a/src/Files.App/Platforms/Desktop/ViewModels/ShellViewModel.Linux.cs
+++ b/src/Files.App/Platforms/Desktop/ViewModels/ShellViewModel.Desktop.cs
@@ -8,9 +8,9 @@
using Files.Platform.Abstractions.Enumeration;
using Files.Platform.Abstractions.Trash;
using Files.Platform.Abstractions.Watching;
-using Files.Platform.Linux.Enumeration;
-using Files.Platform.Linux.Mime;
-using Files.Platform.Linux.Watching;
+using Files.Platform.Posix.Enumeration;
+using Files.Platform.Posix.Mime;
+using Files.Platform.Posix.Watching;
using Files.Shared.Helpers;
using Microsoft.Extensions.Logging;
using OwlCore.Storage;
@@ -27,15 +27,15 @@ namespace Files.App.ViewModels
///
public sealed partial class ShellViewModel
{
- private Files.Platform.Abstractions.Watching.IFolderWatcher? _linuxWatcher;
- public bool IsLinuxWatcherPolling => _linuxWatcher?.IsPolling == true;
- private CancellationTokenSource? _linuxRefreshDebounce;
- private readonly List _linuxRepositoryWatchers = [];
- private Action? _linuxTrashUnsubscribe;
- private CancellationTokenSource? _linuxGitDebounce;
- private readonly FolderChangeBatch _linuxChangeBatch = new();
- private CancellationTokenSource? _linuxChangeCts;
- private int _linuxChangePending;
+ private Files.Platform.Abstractions.Watching.IFolderWatcher? _desktopWatcher;
+ public bool IsDesktopWatcherPolling => _desktopWatcher?.IsPolling == true;
+ private CancellationTokenSource? _desktopRefreshDebounce;
+ private readonly List _desktopRepositoryWatchers = [];
+ private Action? _desktopTrashUnsubscribe;
+ private CancellationTokenSource? _desktopGitDebounce;
+ private readonly FolderChangeBatch _desktopChangeBatch = new();
+ private CancellationTokenSource? _desktopChangeCts;
+ private int _desktopChangePending;
// The listed location as a storable; set for archive folders, which have no WinRT equivalent
private StorableWithPath? currentStorable;
@@ -43,14 +43,14 @@ public sealed partial class ShellViewModel
///
/// Lists into filesAndFolders. Returns 3 on success and -1 on failure.
///
- private async Task EnumerateLinuxFolderAsync(string path, CancellationToken cancellationToken, LibraryItem? library)
+ private async Task EnumerateDesktopFolderAsync(string path, CancellationToken cancellationToken, LibraryItem? library)
{
if (path.StartsWith(Constants.UserEnvironmentPaths.RecycleBinPath, StringComparison.Ordinal))
- return await EnumerateLinuxTrashAsync(path, cancellationToken);
+ return await EnumerateDesktopTrashAsync(path, cancellationToken);
currentStorable = null;
if (FileExtensionHelpers.IsZipPath(path, isArchiveFileName: Ioc.Default.GetRequiredService().IsArchiveFileName))
- return await EnumerateLinuxArchiveAsync(path, cancellationToken, library);
+ return await EnumerateDesktopArchiveAsync(path, cancellationToken, library);
if (!Directory.Exists(path))
{
@@ -116,7 +116,7 @@ await Task.Run(async () =>
if (entry.IsHidden && !includeHidden)
continue;
- var item = CreateLinuxListedItem(entry);
+ var item = CreateDesktopListedItem(entry);
try { item.PreloadedIconData = await iconCache.GetIconAsync(item.ItemPath, item.FileExtension, entry.IsDirectory, iconSize); } catch (Exception ex) { App.Logger.LogWarning(ex, "Could not load icon for {Path}", item.ItemPath); }
pending.Add(item);
@@ -144,7 +144,7 @@ await Task.Run(async () =>
await ApplyFilesAndFoldersChangesAsync();
// Uno does not raise the container update callbacks that normally trigger this, so the status columns are filled in here
- _ = LoadLinuxRepositoryPropertiesAsync(cancellationToken);
+ _ = LoadDesktopRepositoryPropertiesAsync(cancellationToken);
// desktop.ini based customization has no Linux equivalent; the Windows services are stubs
_ = dispatcherQueue.EnqueueOrInvokeAsync(CheckForSolutionFile, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
@@ -166,7 +166,7 @@ await Task.Run(async () =>
/// Lists an archive root or a folder inside an archive through (read-only, no watcher).
/// Returns 5 on success and -1 on failure.
///
- private async Task EnumerateLinuxArchiveAsync(string path, CancellationToken cancellationToken, LibraryItem? library)
+ private async Task EnumerateDesktopArchiveAsync(string path, CancellationToken cancellationToken, LibraryItem? library)
{
HasNoWatcher = true;
@@ -283,7 +283,7 @@ await Task.Run(async () =>
return 5;
}
- private async Task LoadLinuxRepositoryPropertiesAsync(CancellationToken cancellationToken)
+ private async Task LoadDesktopRepositoryPropertiesAsync(CancellationToken cancellationToken)
{
if (!IsValidGitDirectory || EnabledGitProperties is GitProperties.None)
return;
@@ -304,12 +304,12 @@ private async Task LoadLinuxRepositoryPropertiesAsync(CancellationToken cancella
}
// Items inside a repository use the Git item type so the status/commit columns can be filled in on demand
- private ListedItem NewLinuxItem() => IsValidGitDirectory ? new GitItem() : new ListedItem(null);
+ private ListedItem NewDesktopItem() => IsValidGitDirectory ? new GitItem() : new ListedItem(null);
///
/// Lists the freedesktop.org trash (trash:///) through . Returns 4 on success.
///
- private async Task EnumerateLinuxTrashAsync(string path, CancellationToken cancellationToken)
+ private async Task EnumerateDesktopTrashAsync(string path, CancellationToken cancellationToken)
{
currentStorageFolder = null;
HasNoWatcher = false;
@@ -327,7 +327,7 @@ private async Task EnumerateLinuxTrashAsync(string path, CancellationToken
FileSizeBytes = 0,
};
- var items = await BuildLinuxTrashItemsAsync(cancellationToken);
+ var items = await BuildDesktopTrashItemsAsync(cancellationToken);
if (cancellationToken.IsCancellationRequested)
return -1;
@@ -342,7 +342,7 @@ private async Task EnumerateLinuxTrashAsync(string path, CancellationToken
return 4;
}
- private async Task> BuildLinuxTrashItemsAsync(CancellationToken cancellationToken)
+ private async Task> BuildDesktopTrashItemsAsync(CancellationToken cancellationToken)
{
var trashed = await StorageTrashBinService.GetAllRecycleBinFoldersAsync();
var iconCache = Ioc.Default.GetRequiredService();
@@ -392,15 +392,15 @@ private async Task> BuildLinuxTrashItemsAsync(CancellationToken
// Diffs the trash against the listed items by trash path and applies only the additions and removals, so the
// selection and scroll position survive. Falls back to a full apply when grouping or a filter is active.
- private async Task RefreshLinuxTrashIncrementallyAsync()
+ private async Task RefreshDesktopTrashIncrementallyAsync()
{
if (isDisposed || WorkingDirectory != Constants.UserEnvironmentPaths.RecycleBinPath)
return;
- var cts = _linuxRefreshDebounce;
+ var cts = _desktopRefreshDebounce;
var token = cts?.Token ?? CancellationToken.None;
- var fresh = await BuildLinuxTrashItemsAsync(token);
+ var fresh = await BuildDesktopTrashItemsAsync(token);
if (token.IsCancellationRequested)
return;
@@ -448,15 +448,15 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
});
}
- private async Task RefreshLinuxTrashAfterChangeAsync()
+ private async Task RefreshDesktopTrashAfterChangeAsync()
{
- _linuxRefreshDebounce?.Cancel();
- var cts = _linuxRefreshDebounce = new CancellationTokenSource();
+ _desktopRefreshDebounce?.Cancel();
+ var cts = _desktopRefreshDebounce = new CancellationTokenSource();
try
{
await Task.Delay(300, cts.Token);
- await RefreshLinuxTrashIncrementallyAsync();
+ await RefreshDesktopTrashIncrementallyAsync();
}
catch (OperationCanceledException)
{
@@ -468,17 +468,17 @@ private async Task RefreshLinuxTrashAfterChangeAsync()
}
// Trash changes are pushed by ITrashService.Watcher rather than by a folder watcher on trash:///
- private void WatchForLinuxTrashChanges()
+ private void WatchForDesktopTrashChanges()
{
if (isDisposed)
return;
- CloseLinuxWatcher();
+ CloseDesktopWatcher();
try
{
var notifier = Ioc.Default.GetRequiredService().Watcher;
- void OnChanged(object? s, EventArgs e) => _ = RefreshLinuxTrashAfterChangeAsync();
+ void OnChanged(object? s, EventArgs e) => _ = RefreshDesktopTrashAfterChangeAsync();
notifier.ItemAdded += OnChanged;
notifier.ItemDeleted += OnChanged;
@@ -487,7 +487,7 @@ private void WatchForLinuxTrashChanges()
notifier.RefreshRequested += OnChanged;
notifier.StartWatcher();
- _linuxTrashUnsubscribe = () =>
+ _desktopTrashUnsubscribe = () =>
{
notifier.ItemAdded -= OnChanged;
notifier.ItemDeleted -= OnChanged;
@@ -502,7 +502,7 @@ private void WatchForLinuxTrashChanges()
}
}
- private ListedItem CreateLinuxListedItem(FileSystemEntryInfo entry)
+ private ListedItem CreateDesktopListedItem(FileSystemEntryInfo entry)
{
var opacity = entry.IsHidden ? Constants.UI.DimItemOpacity : 1d;
var modified = entry.LastWriteTimeUtc.ToLocalTime();
@@ -511,7 +511,7 @@ private ListedItem CreateLinuxListedItem(FileSystemEntryInfo entry)
if (entry.IsDirectory)
{
- var folder = NewLinuxItem();
+ var folder = NewDesktopItem();
folder.PrimaryItemAttribute = StorageItemTypes.Folder;
folder.ItemNameRaw = entry.Name;
folder.ItemDateModifiedReal = modified;
@@ -524,7 +524,7 @@ private ListedItem CreateLinuxListedItem(FileSystemEntryInfo entry)
folder.ItemPath = entry.FullPath;
folder.FileSize = null;
folder.FileSizeBytes = 0;
- ApplyLinuxLinkInfo(folder, entry);
+ ApplyDesktopLinkInfo(folder, entry);
return folder;
}
@@ -537,7 +537,7 @@ private ListedItem CreateLinuxListedItem(FileSystemEntryInfo entry)
itemType = !string.IsNullOrEmpty(localizedType) ? localizedType : extension.Trim('.') + " " + itemType;
}
- var item = NewLinuxItem();
+ var item = NewDesktopItem();
item.PrimaryItemAttribute = StorageItemTypes.File;
item.FileExtension = extension;
item.IsHiddenItem = entry.IsHidden;
@@ -552,7 +552,7 @@ private ListedItem CreateLinuxListedItem(FileSystemEntryInfo entry)
item.ItemPath = entry.FullPath;
item.FileSize = entry.Length.ToSizeString();
item.FileSizeBytes = entry.Length;
- ApplyLinuxLinkInfo(item, entry);
+ ApplyDesktopLinkInfo(item, entry);
// Display only: the name comes from the strictly parsed entry; opening goes through the launcher confirmation
if (!entry.IsBrokenSymlink && DesktopEntryDisplay.IsDesktopFile(entry.Name) &&
@@ -571,21 +571,21 @@ private static void ApplyLinkInfoCore(ListedItem item, string? linkTarget, bool
item.SymLinkTarget = linkTarget;
item.IsBrokenSymLink = broken;
if (broken)
- item.ItemType = Strings.LinuxBrokenLink.GetLocalizedResource();
+ item.ItemType = Strings.DesktopBrokenLink.GetLocalizedResource();
}
- private static void ApplyLinuxLinkInfo(ListedItem item, FileSystemEntryInfo entry)
+ private static void ApplyDesktopLinkInfo(ListedItem item, FileSystemEntryInfo entry)
{
if (entry.IsSymlink)
ApplyLinkInfoCore(item, entry.LinkTarget ?? string.Empty, entry.IsBrokenSymlink);
}
- private void WatchForLinuxFolderChanges(string path)
+ private void WatchForDesktopFolderChanges(string path)
{
if (isDisposed)
return;
- CloseLinuxWatcher();
+ CloseDesktopWatcher();
try
{
@@ -601,11 +601,11 @@ private void WatchForLinuxFolderChanges(string path)
void OnPath(object? s, FolderChangeEventArgs e)
{
if (string.Equals(e.FullPath, folder, StringComparison.Ordinal))
- _linuxChangeBatch.RequestFullRefresh();
+ _desktopChangeBatch.RequestFullRefresh();
else
- _linuxChangeBatch.Add(e.FullPath);
+ _desktopChangeBatch.Add(e.FullPath);
- ScheduleLinuxChanges(folder);
+ ScheduleDesktopChanges(folder);
}
watcherInstance.Created += OnPath;
@@ -613,17 +613,17 @@ void OnPath(object? s, FolderChangeEventArgs e)
watcherInstance.Changed += OnPath;
watcherInstance.Renamed += (_, e) =>
{
- _linuxChangeBatch.AddRename(e.OldFullPath, e.FullPath);
- ScheduleLinuxChanges(folder);
+ _desktopChangeBatch.AddRename(e.OldFullPath, e.FullPath);
+ ScheduleDesktopChanges(folder);
};
watcherInstance.RescanRequired += (_, _) =>
{
- _linuxChangeBatch.RequestFullRefresh();
- ScheduleLinuxChanges(folder);
+ _desktopChangeBatch.RequestFullRefresh();
+ ScheduleDesktopChanges(folder);
};
watcherInstance.Start();
- _linuxWatcher = watcherInstance;
+ _desktopWatcher = watcherInstance;
}
catch (Exception ex)
{
@@ -632,10 +632,10 @@ void OnPath(object? s, FolderChangeEventArgs e)
}
// Used by the trash, whose changes always reload the whole listing
- private async Task RefreshAfterLinuxChangeAsync()
+ private async Task RefreshAfterDesktopChangeAsync()
{
- _linuxRefreshDebounce?.Cancel();
- var cts = _linuxRefreshDebounce = new CancellationTokenSource();
+ _desktopRefreshDebounce?.Cancel();
+ var cts = _desktopRefreshDebounce = new CancellationTokenSource();
try
{
@@ -648,21 +648,21 @@ private async Task RefreshAfterLinuxChangeAsync()
}
// The first event of a burst opens a short window; everything arriving inside it is applied together
- private void ScheduleLinuxChanges(string folder)
+ private void ScheduleDesktopChanges(string folder)
{
- if (Interlocked.Exchange(ref _linuxChangePending, 1) == 1)
+ if (Interlocked.Exchange(ref _desktopChangePending, 1) == 1)
return;
var cts = new CancellationTokenSource();
- Interlocked.Exchange(ref _linuxChangeCts, cts)?.Cancel();
+ Interlocked.Exchange(ref _desktopChangeCts, cts)?.Cancel();
_ = Task.Run(async () =>
{
try
{
await Task.Delay(150, cts.Token);
- Interlocked.Exchange(ref _linuxChangePending, 0);
- await ApplyLinuxChangesAsync(folder, cts.Token);
+ Interlocked.Exchange(ref _desktopChangePending, 0);
+ await ApplyDesktopChangesAsync(folder, cts.Token);
}
catch (OperationCanceledException)
{
@@ -714,9 +714,9 @@ private bool TryApplyIncrementalDisplayChanges(List desired)
/// Applies a burst of watcher events as add, remove, rename and update operations on the existing items. Falls back to a
/// full reload when events were lost or the burst was too large.
///
- private async Task ApplyLinuxChangesAsync(string folder, CancellationToken cancellationToken)
+ private async Task ApplyDesktopChangesAsync(string folder, CancellationToken cancellationToken)
{
- var snapshot = _linuxChangeBatch.Drain();
+ var snapshot = _desktopChangeBatch.Drain();
if (cancellationToken.IsCancellationRequested || isDisposed)
return;
@@ -778,7 +778,7 @@ private async Task ApplyLinuxChangesAsync(string folder, CancellationToken cance
case FolderChangeKind.Rename:
var renamed = items[op.Path];
var target = entries[op.NewPath!];
- if (CanRenameLinuxItemInPlace(renamed, target))
+ if (CanRenameDesktopItemInPlace(renamed, target))
{
await dispatcherQueue.EnqueueOrInvokeAsync(() =>
{
@@ -793,7 +793,7 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
{
filesAndFolders.Remove(renamed);
removedAny = true;
- if (await TryCreateLinuxItemAsync(target, iconCache, iconSize) is { } recreated)
+ if (await TryCreateDesktopItemAsync(target, iconCache, iconSize) is { } recreated)
added.Add(recreated);
}
break;
@@ -801,7 +801,7 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
case FolderChangeKind.Update:
var existing = items[op.Path];
var fresh = entries[op.Path];
- if (IsSameLinuxItemKind(existing, fresh))
+ if (IsSameDesktopItemKind(existing, fresh))
{
await dispatcherQueue.EnqueueOrInvokeAsync(() =>
{
@@ -821,13 +821,13 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
{
filesAndFolders.Remove(existing);
removedAny = true;
- if (await TryCreateLinuxItemAsync(fresh, iconCache, iconSize) is { } replaced)
+ if (await TryCreateDesktopItemAsync(fresh, iconCache, iconSize) is { } replaced)
added.Add(replaced);
}
break;
case FolderChangeKind.Add:
- if (await TryCreateLinuxItemAsync(entries[op.Path], iconCache, iconSize) is { } created)
+ if (await TryCreateDesktopItemAsync(entries[op.Path], iconCache, iconSize) is { } created)
added.Add(created);
break;
}
@@ -851,11 +851,11 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
}
}
- private async Task TryCreateLinuxItemAsync(FileSystemEntryInfo entry, IIconCacheService iconCache, uint iconSize)
+ private async Task TryCreateDesktopItemAsync(FileSystemEntryInfo entry, IIconCacheService iconCache, uint iconSize)
{
try
{
- var item = CreateLinuxListedItem(entry);
+ var item = CreateDesktopListedItem(entry);
try { item.PreloadedIconData = await iconCache.GetIconAsync(item.ItemPath, item.FileExtension, entry.IsDirectory, iconSize); } catch (Exception ex) { App.Logger.LogWarning(ex, "Could not load icon for {Path}", item.ItemPath); }
return item;
}
@@ -866,27 +866,27 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() =>
}
// A rename keeps the item (and its position) only when nothing derived from the name changes
- private static bool CanRenameLinuxItemInPlace(ListedItem item, FileSystemEntryInfo target)
- => IsSameLinuxItemKind(item, target) &&
+ private static bool CanRenameDesktopItemInPlace(ListedItem item, FileSystemEntryInfo target)
+ => IsSameDesktopItemKind(item, target) &&
string.Equals(Path.GetExtension(item.ItemPath), Path.GetExtension(target.Name), StringComparison.OrdinalIgnoreCase) &&
item.IsHiddenItem == target.IsHidden;
- private static bool IsSameLinuxItemKind(ListedItem item, FileSystemEntryInfo entry)
+ private static bool IsSameDesktopItemKind(ListedItem item, FileSystemEntryInfo entry)
=> item.IsFolder == entry.IsDirectory &&
item.IsBrokenSymLink == entry.IsBrokenSymlink &&
item.SymLinkTarget == (entry.IsSymlink ? entry.LinkTarget ?? string.Empty : null) &&
item.DisplayNameOverride is null;
// Raises GitDirectoryUpdated when the repository metadata changes (commit, checkout, stage, fetch) so the status columns refresh
- private void WatchForLinuxRepositoryChanges()
+ private void WatchForDesktopRepositoryChanges()
{
if (isDisposed || string.IsNullOrEmpty(GitDirectory))
return;
- DisposeLinuxRepositoryWatchers();
+ DisposeDesktopRepositoryWatchers();
// .git may be a gitfile (linked worktree, submodule); HEAD and the index live in the git dir, refs in the common dir
- if (Files.Platform.Linux.Search.GitDirectoryResolver.Resolve(GitDirectory) is not var (gitDir, commonDir))
+ if (Files.Platform.Posix.Search.GitDirectoryResolver.Resolve(GitDirectory) is not var (gitDir, commonDir))
return;
try
@@ -912,7 +912,7 @@ void OnChanged(string root, FolderChangeEventArgs e)
if (e.Name.EndsWith(".lock", StringComparison.Ordinal) || relative.StartsWith("objects/", StringComparison.Ordinal) || relative.Contains("/objects/", StringComparison.Ordinal))
return;
- ScheduleLinuxGitRefresh();
+ ScheduleDesktopGitRefresh();
}
foreach (var (path, recursive) in targets.DistinctBy(t => t.Path))
@@ -927,7 +927,7 @@ void OnChanged(string root, FolderChangeEventArgs e)
watcherInstance.Changed += (_, e) => OnChanged(root, e);
watcherInstance.Renamed += (_, e) => OnChanged(root, e);
watcherInstance.Start();
- _linuxRepositoryWatchers.Add(watcherInstance);
+ _desktopRepositoryWatchers.Add(watcherInstance);
}
}
catch (Exception ex)
@@ -937,22 +937,22 @@ void OnChanged(string root, FolderChangeEventArgs e)
}
// Several watchers fire for one Git command; coalesce them into one reload
- private void ScheduleLinuxGitRefresh()
+ private void ScheduleDesktopGitRefresh()
{
var cts = new CancellationTokenSource();
- Interlocked.Exchange(ref _linuxGitDebounce, cts)?.Cancel();
+ Interlocked.Exchange(ref _desktopGitDebounce, cts)?.Cancel();
_ = Task.Delay(TimeSpan.FromMilliseconds(400), cts.Token).ContinueWith(
_ => dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
- await ReloadLinuxGitPropertiesAsync();
+ await ReloadDesktopGitPropertiesAsync();
GitDirectoryUpdated?.Invoke(null, null!);
}),
cts.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
}
// The Git columns are loaded once per item; after the repository changed they are stale, so reset the flags and reload
- private async Task ReloadLinuxGitPropertiesAsync()
+ private async Task ReloadDesktopGitPropertiesAsync()
{
if (isDisposed || !IsValidGitDirectory)
return;
@@ -976,24 +976,24 @@ private async Task ReloadLinuxGitPropertiesAsync()
}
}
- private void DisposeLinuxRepositoryWatchers()
+ private void DisposeDesktopRepositoryWatchers()
{
- foreach (var w in _linuxRepositoryWatchers)
+ foreach (var w in _desktopRepositoryWatchers)
w.Dispose();
- _linuxRepositoryWatchers.Clear();
+ _desktopRepositoryWatchers.Clear();
}
- private void CloseLinuxWatcher()
+ private void CloseDesktopWatcher()
{
- DisposeLinuxRepositoryWatchers();
- Interlocked.Exchange(ref _linuxGitDebounce, null)?.Cancel();
- _linuxRefreshDebounce?.Cancel();
- Interlocked.Exchange(ref _linuxChangeCts, null)?.Cancel();
- Interlocked.Exchange(ref _linuxChangePending, 0);
- _linuxChangeBatch.Drain();
- _linuxWatcher?.Dispose();
- _linuxWatcher = null;
- Interlocked.Exchange(ref _linuxTrashUnsubscribe, null)?.Invoke();
+ DisposeDesktopRepositoryWatchers();
+ Interlocked.Exchange(ref _desktopGitDebounce, null)?.Cancel();
+ _desktopRefreshDebounce?.Cancel();
+ Interlocked.Exchange(ref _desktopChangeCts, null)?.Cancel();
+ Interlocked.Exchange(ref _desktopChangePending, 0);
+ _desktopChangeBatch.Drain();
+ _desktopWatcher?.Dispose();
+ _desktopWatcher = null;
+ Interlocked.Exchange(ref _desktopTrashUnsubscribe, null)?.Invoke();
}
}
}
diff --git a/src/Files.App/Platforms/Desktop/WindowEx.cs b/src/Files.App/Platforms/Desktop/WindowEx.cs
index 2620a7cd8548..ab980929d7d3 100644
--- a/src/Files.App/Platforms/Desktop/WindowEx.cs
+++ b/src/Files.App/Platforms/Desktop/WindowEx.cs
@@ -97,7 +97,7 @@ private void ApplyDefaultSize()
{
var work = DisplayArea.Primary.WorkArea;
// AppWindow sizes are physical pixels; the caps are logical
- var scale = Files.Platform.Linux.Windowing.DisplayScaleResolver.GetEffectiveScale();
+ var scale = DesktopPlatform.GetDisplayScale();
var width = Math.Clamp((int)(work.Width * 0.8), Math.Min((int)(MinWidth * scale), work.Width), (int)(1600 * scale));
var height = Math.Clamp((int)(work.Height * 0.8), Math.Min((int)(MinHeight * scale), work.Height), (int)(1000 * scale));
AppWindow.Resize(new Windows.Graphics.SizeInt32 { Width = width, Height = height });
diff --git a/src/Files.App/Services/App/AppResourcesService.Linux.cs b/src/Files.App/Services/App/AppResourcesService.Linux.cs
index a38771791c40..d38d1fef8ea4 100644
--- a/src/Files.App/Services/App/AppResourcesService.Linux.cs
+++ b/src/Files.App/Services/App/AppResourcesService.Linux.cs
@@ -16,21 +16,21 @@ namespace Files.App.Services
public sealed partial class ResourcesService
{
private readonly Dictionary _manualColors = new();
- private readonly HashSet _linuxOverrides = new();
+ private readonly HashSet _desktopOverrides = new();
private ISystemAppearanceService SystemAppearance => Ioc.Default.GetRequiredService();
private bool _refreshing;
private static readonly string[] SurfaceKeys = ["App.Theme.BackgroundBrush", "App.Theme.AddressBar.BackgroundBrush",
"App.Theme.Toolbar.BackgroundBrush", "App.Theme.Sidebar.BackgroundBrush", "App.Theme.FileArea.BackgroundBrush",
"App.Theme.FileArea.SecondaryBackgroundBrush", "App.Theme.InfoPane.BackgroundBrush", "ToolbarBackgroundBrush", "TabViewItemHeaderBackgroundSelected"];
- private void InitializeLinuxAppearance()
+ private void InitializeDesktopAppearance()
{
if (!OperatingSystem.IsLinux()) return;
SystemAppearance.Changed += (_, _) => MainWindow.Instance.DispatcherQueue.TryEnqueue(ApplyResources);
X11AppearanceSupport.Changed += (_, _) => MainWindow.Instance.DispatcherQueue.TryEnqueue(ApplyResources);
AppThemeModeService.AppThemeModeChanged += (_, _) =>
{
- if (!_refreshing) UpdateLinuxAppearanceResources();
+ if (!_refreshing) UpdateDesktopAppearanceResources();
};
_ = RefreshSystemAppearanceAsync();
}
@@ -41,7 +41,7 @@ private async Task RefreshSystemAppearanceAsync()
catch (OperationCanceledException) { }
}
- private void SetLinuxManualColor(string key, Color color)
+ private void SetDesktopManualColor(string key, Color color)
{
if (color.A == 0) _manualColors.Remove(key);
else _manualColors[key] = color;
@@ -58,15 +58,15 @@ private void SetLinuxManualColor(string key, Color color)
return null;
}
- private void UpdateLinuxAppearanceResources()
+ private void UpdateDesktopAppearanceResources()
{
if (!OperatingSystem.IsLinux() || _refreshing) return;
_refreshing = true;
try
{
var resources = Application.Current.Resources;
- foreach (var key in _linuxOverrides) resources.Remove(key);
- _linuxOverrides.Clear();
+ foreach (var key in _desktopOverrides) resources.Remove(key);
+ _desktopOverrides.Clear();
var settings = UserSettingsService.AppearanceSettingsService;
var system = SystemAppearance.Current;
var dark = AppThemeModeService.AppThemeMode == ElementTheme.Dark ||
@@ -125,7 +125,7 @@ private void UpdateLinuxAppearanceResources()
{
resources[key] = key.StartsWith("SystemAccentColor", StringComparison.Ordinal) || key == "App.Theme.FillColorAttention"
? (object)color : new SolidColorBrush(color);
- _linuxOverrides.Add(key);
+ _desktopOverrides.Add(key);
}
}
finally { _refreshing = false; }
diff --git a/src/Files.App/Services/App/AppResourcesService.cs b/src/Files.App/Services/App/AppResourcesService.cs
index dd99b84a2c2b..5ab6155a51e8 100644
--- a/src/Files.App/Services/App/AppResourcesService.cs
+++ b/src/Files.App/Services/App/AppResourcesService.cs
@@ -19,7 +19,7 @@ public ResourcesService()
{
UpdateAppearanceResources();
#if HAS_UNO
- InitializeLinuxAppearance();
+ InitializeDesktopAppearance();
#endif
UserSettingsService.AppearanceSettingsService.PropertyChanged += AppearanceSettingsService_PropertyChanged;
@@ -102,7 +102,7 @@ public void SetAppThemeBackgroundColor(Color appThemeBackgroundColor)
#if HAS_UNO
if (OperatingSystem.IsLinux())
{
- SetLinuxManualColor("App.Theme.BackgroundBrush", appThemeBackgroundColor);
+ SetDesktopManualColor("App.Theme.BackgroundBrush", appThemeBackgroundColor);
return;
}
#endif
@@ -115,7 +115,7 @@ public void SetAppThemeAddressBarBackgroundColor(Color appThemeAddressBarBackgro
#if HAS_UNO
if (OperatingSystem.IsLinux())
{
- SetLinuxManualColor("App.Theme.AddressBar.BackgroundBrush", appThemeAddressBarBackgroundColor);
+ SetDesktopManualColor("App.Theme.AddressBar.BackgroundBrush", appThemeAddressBarBackgroundColor);
return;
}
#endif
@@ -131,7 +131,7 @@ public void SetAppThemeToolbarBackgroundColor(Color appThemeToolbarBackgroundCol
#if HAS_UNO
if (OperatingSystem.IsLinux())
{
- SetLinuxManualColor("App.Theme.Toolbar.BackgroundBrush", appThemeToolbarBackgroundColor);
+ SetDesktopManualColor("App.Theme.Toolbar.BackgroundBrush", appThemeToolbarBackgroundColor);
return;
}
#endif
@@ -144,7 +144,7 @@ public void SetAppThemeSidebarBackgroundColor(Color appThemeSidebarBackgroundCol
#if HAS_UNO
if (OperatingSystem.IsLinux())
{
- SetLinuxManualColor("App.Theme.Sidebar.BackgroundBrush", appThemeSidebarBackgroundColor);
+ SetDesktopManualColor("App.Theme.Sidebar.BackgroundBrush", appThemeSidebarBackgroundColor);
return;
}
#endif
@@ -157,7 +157,7 @@ public void SetAppThemeFileAreaBackgroundColor(Color appThemeFileAreaBackgroundC
#if HAS_UNO
if (OperatingSystem.IsLinux())
{
- SetLinuxManualColor("App.Theme.FileArea.BackgroundBrush", appThemeFileAreaBackgroundColor);
+ SetDesktopManualColor("App.Theme.FileArea.BackgroundBrush", appThemeFileAreaBackgroundColor);
return;
}
#endif
@@ -170,7 +170,7 @@ public void SetAppThemeFileAreaSecondaryBackgroundColor(Color appThemeFileAreaSe
#if HAS_UNO
if (OperatingSystem.IsLinux())
{
- SetLinuxManualColor("App.Theme.FileArea.SecondaryBackgroundBrush", appThemeFileAreaSecondaryBackgroundColor);
+ SetDesktopManualColor("App.Theme.FileArea.SecondaryBackgroundBrush", appThemeFileAreaSecondaryBackgroundColor);
return;
}
#endif
@@ -183,7 +183,7 @@ public void SetAppThemeInfoPaneBackgroundColor(Color appThemeInfoPaneBackgroundC
#if HAS_UNO
if (OperatingSystem.IsLinux())
{
- SetLinuxManualColor("App.Theme.InfoPane.BackgroundBrush", appThemeInfoPaneBackgroundColor);
+ SetDesktopManualColor("App.Theme.InfoPane.BackgroundBrush", appThemeInfoPaneBackgroundColor);
return;
}
#endif
@@ -206,7 +206,7 @@ public void SetScrollInertiaEnabled(bool enableScrollInertia)
public void ApplyResources()
{
#if HAS_UNO
- UpdateLinuxAppearanceResources();
+ UpdateDesktopAppearanceResources();
#endif
AppThemeModeService.ApplyResources();
}
diff --git a/src/Files.App/Services/App/AppThemeModeService.cs b/src/Files.App/Services/App/AppThemeModeService.cs
index 6c6009cbc81c..2465b6135919 100644
--- a/src/Files.App/Services/App/AppThemeModeService.cs
+++ b/src/Files.App/Services/App/AppThemeModeService.cs
@@ -65,9 +65,10 @@ public AppThemeModeService()
UISettings.ColorValuesChanged += UISettings_ColorValuesChanged;
#if HAS_UNO
- Files.Platform.Linux.Theme.LinuxColorScheme.Initialize();
- Files.Platform.Linux.Theme.LinuxColorScheme.Changed += async (_, _) =>
+ var appearance = Ioc.Default.GetRequiredService();
+ appearance.Changed += async (_, _) =>
await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => SetAppThemeMode());
+ _ = appearance.RefreshAsync();
#endif
}
@@ -78,7 +79,7 @@ private static ElementTheme ResolveRootTheme(ElementTheme theme)
{
#if HAS_UNO
if (theme is ElementTheme.Default)
- return Files.Platform.Linux.Theme.LinuxColorScheme.IsDark ? ElementTheme.Dark : ElementTheme.Light;
+ return Ioc.Default.GetService()?.Current.IsDark == true ? ElementTheme.Dark : ElementTheme.Light;
#endif
return theme;
}
diff --git a/src/Files.App/Services/Git/LibGit2NativeResolver.cs b/src/Files.App/Services/Git/LibGit2NativeResolver.cs
index 4789103c75d1..b2d87ca3ea1a 100644
--- a/src/Files.App/Services/Git/LibGit2NativeResolver.cs
+++ b/src/Files.App/Services/Git/LibGit2NativeResolver.cs
@@ -1,7 +1,7 @@
// Copyright (c) Files Community
// Licensed under the MIT License.
-using Files.Platform.Linux.Native;
+using Files.Platform.Posix.Native;
using LibGit2Sharp;
using System.IO;
using System.Reflection;
diff --git a/src/Files.App/Services/SizeProvider/CachedSizeProvider.Linux.cs b/src/Files.App/Services/SizeProvider/CachedSizeProvider.Desktop.cs
similarity index 100%
rename from src/Files.App/Services/SizeProvider/CachedSizeProvider.Linux.cs
rename to src/Files.App/Services/SizeProvider/CachedSizeProvider.Desktop.cs
diff --git a/src/Files.App/Services/Storage/StorageDevicesService.cs b/src/Files.App/Services/Storage/StorageDevicesService.cs
index 1d4e93f27195..c15769fb84ea 100644
--- a/src/Files.App/Services/Storage/StorageDevicesService.cs
+++ b/src/Files.App/Services/Storage/StorageDevicesService.cs
@@ -12,19 +12,19 @@ public sealed class RemovableDrivesService : IRemovableDrivesService
{
public IStorageDeviceWatcher CreateWatcher()
{
- return new LinuxStorageDeviceWatcher();
+ return new DesktopStorageDeviceWatcher();
}
public async IAsyncEnumerable GetDrivesAsync()
{
// Mounted drives (mountinfo + UDisks2 labels), volumes that are not mounted yet and MTP devices (GVfs)
- var entries = await LinuxDriveCatalog.EnumerateAsync().ConfigureAwait(false);
- var linuxPending = entries.Select(entry => entry.CreateAsync()).ToList();
+ var entries = await DesktopDriveCatalog.EnumerateAsync().ConfigureAwait(false);
+ var desktopPending = entries.Select(entry => entry.CreateAsync()).ToList();
- await foreach (var completed in Task.WhenEach(linuxPending))
+ await foreach (var completed in Task.WhenEach(desktopPending))
{
- if (await completed is { } linuxItem)
- yield return linuxItem;
+ if (await completed is { } desktopItem)
+ yield return desktopItem;
}
}
diff --git a/src/Files.App/Services/Storage/StorageNetworkService.Linux.cs b/src/Files.App/Services/Storage/StorageNetworkService.Linux.cs
index ddbc1a86f134..3e6b9d4375d4 100644
--- a/src/Files.App/Services/Storage/StorageNetworkService.Linux.cs
+++ b/src/Files.App/Services/Storage/StorageNetworkService.Linux.cs
@@ -2,7 +2,7 @@
// Licensed under the MIT License.
using Files.App.Dialogs;
-using Files.Platform.Abstractions.Gvfs;
+using Files.Platform.Abstractions.Network;
using Files.Platform.Linux.Gvfs;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Xaml.Controls;
@@ -25,7 +25,7 @@ public sealed partial class NetworkService
private static bool IsNetworkKind(GvfsMount mount)
=> mount.Kind is not (GvfsMountKind.Mtp or GvfsMountKind.Gphoto);
- private void StartLinuxWatching()
+ private void StartPlatformWatching()
{
if (Gvfs is not { } gvfs)
return;
@@ -50,8 +50,8 @@ await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(async () =>
App.Logger.LogInformation("Watching GVfs mounts in {Directory} ({Count} now)", NetworkRootPath, gvfs.GetMounts().Count);
}
- private IEnumerable GetLinuxNetworkItems()
- => (Gvfs?.GetMounts() ?? []).Where(IsNetworkKind).Select(m => (IFolder)LinuxDriveCatalog.CreateNetworkItem(m));
+ private IEnumerable GetPlatformNetworkItems()
+ => (Gvfs?.GetMounts() ?? []).Where(IsNetworkKind).Select(m => (IFolder)DesktopDriveCatalog.CreateNetworkItem(m));
///
public Task GetNetworkAvailabilityAsync()
@@ -85,7 +85,7 @@ public async Task OpenMapNetworkDriveDialogAsync()
DynamicDialog? dialog = null;
var input = new TextBox
{
- PlaceholderText = Strings.LinuxConnectToServerPlaceholder.GetLocalizedResource(),
+ PlaceholderText = Strings.DesktopConnectToServerPlaceholder.GetLocalizedResource(),
MinWidth = 320d,
};
@@ -99,9 +99,9 @@ public async Task OpenMapNetworkDriveDialogAsync()
dialog = new DynamicDialog(new DynamicDialogViewModel()
{
- TitleText = Strings.LinuxConnectToServerTitle.GetLocalizedResource(),
- SubtitleText = Strings.LinuxConnectToServerSubtitle.GetLocalizedResource(),
- PrimaryButtonText = Strings.LinuxConnectToServerButton.GetLocalizedResource(),
+ TitleText = Strings.DesktopConnectToServerTitle.GetLocalizedResource(),
+ SubtitleText = Strings.DesktopConnectToServerSubtitle.GetLocalizedResource(),
+ PrimaryButtonText = Strings.DesktopConnectToServerButton.GetLocalizedResource(),
CloseButtonText = Strings.Cancel.GetLocalizedResource(),
DisplayControl = new StackPanel { Children = { input } },
DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Cancel,
@@ -121,8 +121,8 @@ public async Task OpenMapNetworkDriveDialogAsync()
if (!await gvfs.ConnectAsync(uri))
{
await DialogDisplayHelper.ShowDialogAsync(
- Strings.LinuxConnectToServerTitle.GetLocalizedResource(),
- string.Format(Strings.LinuxConnectToServerFailed.GetLocalizedResource(), uri));
+ Strings.DesktopConnectToServerTitle.GetLocalizedResource(),
+ string.Format(Strings.DesktopConnectToServerFailed.GetLocalizedResource(), uri));
}
}
diff --git a/src/Files.App/Services/Storage/StorageNetworkService.cs b/src/Files.App/Services/Storage/StorageNetworkService.cs
index 21edc24e61f4..886181f2db27 100644
--- a/src/Files.App/Services/Storage/StorageNetworkService.cs
+++ b/src/Files.App/Services/Storage/StorageNetworkService.cs
@@ -48,20 +48,20 @@ public NetworkService()
lock (_Computers)
_Computers.Add(networkItem);
- StartLinuxWatching();
+ StartPlatformWatching();
}
///
public async Task> GetComputersAsync()
{
// Connected GVfs locations (smb, sftp, ftp, dav, nfs...); LINUX-TODO(network-discovery): browse the LAN with Avahi
- return await Task.FromResult(GetLinuxNetworkItems());
+ return await Task.FromResult(GetPlatformNetworkItems());
}
///
public async Task> GetShortcutsAsync()
{
- return await Task.FromResult(GetLinuxNetworkItems());
+ return await Task.FromResult(GetPlatformNetworkItems());
}
///
diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw
index cced72f02c60..9987b4738393 100644
--- a/src/Files.App/Strings/en-US/Resources.resw
+++ b/src/Files.App/Strings/en-US/Resources.resw
@@ -4813,37 +4813,37 @@
New text document
-
+
Always use this app for this file type
-
+
Run "{0}"?
-
+
This is an executable text file ({0}). Do you want to run it or display its contents?
-
+
Display
-
+
Launch "{0}"?
-
+
This launcher is not installed and not trusted. Only run launchers from sources you trust.
-
+
This is an executable program ({0}). Only run programs from sources you trust.
-
+
Open {0} files?
-
+
Opening many files at once may be slow or unintended.
-
+
Cannot open file
-
+
No application could open {0}.
@@ -4859,16 +4859,16 @@
The archive could not be extracted
-
+
File changed
-
+
{0} changed after it was checked, so it was not opened.
-
+
Cannot open file
-
+
{0} is an executable-looking or invalid file that cannot be opened safely.
@@ -4877,73 +4877,73 @@
... and {0} more entries
-
+
Mount
-
+
Unmount
-
+
Disconnect
-
+
Connect to server
-
+
Enter the address of a server, for example smb://server/share, sftp://user@host/, ftp://host/ or davs://host/path. Saved credentials from your desktop keyring are used; passwords cannot be typed here.
-
+
smb://server/share
-
+
Connect
-
+
Could not connect to {0}. Check the address, and make sure the gio tool and the GVfs services are installed.
-
+
Problem with the device
-
+
You are not authorized to do this.
-
+
This drive is not mounted.
-
+
File:
-
+
Claims to be:
-
+
Would run:
-
+
in a terminal
-
+
The command is too long to be shown in full, so it will not be run.
-
+
Use Files as default file manager
-
+
Let other applications reveal files in Files (org.freedesktop.FileManager1).
-
+
Open in terminal
-
+
Show option to open folders in the terminal
-
+
Open in terminal as administrator
{0} more folders…
-
+
Broken link
@@ -4970,20 +4970,20 @@
"{0}" could not be installed. Make sure it is a valid font file.
Shown when installing a font on Linux.
-
+
LinuxFiles
Display name of the Linux port, shown in the window title and About page on Linux.
-
+
Show window controls in the tab bar
-
+
Minimize
-
+
Maximize
-
+
Restore
@@ -4993,7 +4993,7 @@
Browse the contents of the selected archive like a folder
-
+
File System
@@ -5042,25 +5042,25 @@
Preparing...
-
+
This service-menu action will run the command shown below on your selection. Only run actions from sources you trust.
-
+
This service-menu action has changed, is too large, or uses an unsupported command. Shell commands and embedded file substitutions are not supported.
-
+
Run service-menu action “{0}”?
-
+
This service-menu action runs a separate command for each item. Select at most {0} items and try again.
-
+
Open in terminal as root
-
+
(Root mode)
-
+
(Running as root)
@@ -5075,64 +5075,64 @@
Makes the whole window see-through. Requires a compositing window manager.
-
+
Files
-
+
System (GTK/portal)
-
+
Colour source
-
+
Use Files colours, Adwaita, or available system colours. Missing GTK colours use the app palette. Your light/dark and custom colour choices are preserved.
-
+
Window background
-
+
Solid
-
+
Transparent
-
+
Blur
-
+
A translucent background keeps text and icons opaque. Blur requires the KWin X11 blur effect. Renderer support may vary.
-
+
Use an opaque background. Background transparency and KWin blur depend on the compositor.
-
+
This compositor or bridge does not advertise the requested effect, or high contrast is enabled. Using a solid background.
-
+
Background opacity
-
+
Opacity of the background tint in Transparent or Blur mode. Text, icons and popups stay opaque.
-
+
xwayland-satellite does not forward whole-window opacity. This control is unavailable.
-
+
Whole-window opacity support is unknown for this compositor or bridge. This control is unavailable.
-
+
No X11 compositing manager was detected. Whole-window opacity is unavailable.
-
+
Fades the entire window, including text and icons. Requires compositor support.
-
+
High contrast keeps the window opaque. Your opacity choice is retained.
-
+
Detect display scale from the compositor (experimental)
-
+
Requires a restart. Uses the focused compositor output scale (niri, sway or Hyprland), KDE display scale, or GNOME text scale when no display or toolkit scale is configured. Scale changes require a restart. May double-scale on some setups.
diff --git a/src/Files.App/Styles/AdwaitaResources.xaml b/src/Files.App/Styles/AdwaitaResources.xaml
index 8aae1e23a1f1..c844bfccbca8 100644
--- a/src/Files.App/Styles/AdwaitaResources.xaml
+++ b/src/Files.App/Styles/AdwaitaResources.xaml
@@ -39,7 +39,7 @@
-
+
@@ -197,7 +197,7 @@
-
+
diff --git a/src/Files.App/Styles/LinuxDesktopResources.xaml b/src/Files.App/Styles/DesktopResources.xaml
similarity index 97%
rename from src/Files.App/Styles/LinuxDesktopResources.xaml
rename to src/Files.App/Styles/DesktopResources.xaml
index 6f0df36a58ca..c483f2daf881 100644
--- a/src/Files.App/Styles/LinuxDesktopResources.xaml
+++ b/src/Files.App/Styles/DesktopResources.xaml
@@ -1,6 +1,6 @@
@@ -8,8 +8,8 @@
ms-appx:///Assets/Fonts/Linux/selawk.ttf#Selawik
ms-appx:///Uno.Fonts.Fluent/Fonts/uno-fluentui-assets.ttf#Symbols
- ms-appx:///Uno.Fonts.Fluent/Fonts/uno-fluentui-assets.ttf#Symbols
- DejaVu Sans Mono, Liberation Mono, monospace
+ ms-appx:///Uno.Fonts.Fluent/Fonts/uno-fluentui-assets.ttf#Symbols
+ DejaVu Sans Mono, Liberation Mono, monospace
@@ -291,7 +291,7 @@
-
+
@@ -324,7 +324,7 @@
-
+
diff --git a/src/Files.App/UserControls/FilePreviews/PreviewTextRenderer.cs b/src/Files.App/UserControls/FilePreviews/PreviewTextRenderer.cs
index aa05680be9e4..68b8276e7f0e 100644
--- a/src/Files.App/UserControls/FilePreviews/PreviewTextRenderer.cs
+++ b/src/Files.App/UserControls/FilePreviews/PreviewTextRenderer.cs
@@ -33,7 +33,7 @@ public static class PreviewTextRenderer
public static FontFamily GetMonospaceFont()
{
- if (Application.Current?.Resources.TryGetValue("Files.Linux.MonospaceFontFamily", out var value) == true && value is FontFamily family)
+ if (Application.Current?.Resources.TryGetValue("Files.Desktop.MonospaceFontFamily", out var value) == true && value is FontFamily family)
return family;
return new FontFamily("Consolas");
diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml.cs b/src/Files.App/UserControls/NavigationToolbar.xaml.cs
index 84d89ed5a41e..8d9b062c81a7 100644
--- a/src/Files.App/UserControls/NavigationToolbar.xaml.cs
+++ b/src/Files.App/UserControls/NavigationToolbar.xaml.cs
@@ -361,7 +361,7 @@ async Task AddItemsAsync(string header, IAsyncEnumerable storabl
var path = storable.Id;
var flyoutItem = new MenuFlyoutItem()
{
- Text = path is "/" ? Strings.LinuxFileSystemRoot.GetLocalizedResource() : string.IsNullOrEmpty(storable.Name) ? path : storable.Name,
+ Text = path is "/" ? Strings.DesktopFileSystemRoot.GetLocalizedResource() : string.IsNullOrEmpty(storable.Name) ? path : storable.Name,
Icon = new FontIcon() { Glyph = "\uE8B7" }, // As a placeholder
};
e.Flyout.Items.Add(flyoutItem);
diff --git a/src/Files.App/UserControls/StatusCenter/StatusCenter.xaml b/src/Files.App/UserControls/StatusCenter/StatusCenter.xaml
index 2b8dc04d305c..336b52d0556c 100644
--- a/src/Files.App/UserControls/StatusCenter/StatusCenter.xaml
+++ b/src/Files.App/UserControls/StatusCenter/StatusCenter.xaml
@@ -19,7 +19,7 @@
-
+
diff --git a/src/Files.App/UserControls/TabBar/TabBar.Linux.cs b/src/Files.App/UserControls/TabBar/TabBar.Desktop.cs
similarity index 52%
rename from src/Files.App/UserControls/TabBar/TabBar.Linux.cs
rename to src/Files.App/UserControls/TabBar/TabBar.Desktop.cs
index 55d3eecb60be..0bf595e628e5 100644
--- a/src/Files.App/UserControls/TabBar/TabBar.Linux.cs
+++ b/src/Files.App/UserControls/TabBar/TabBar.Desktop.cs
@@ -10,35 +10,35 @@ namespace Files.App.UserControls.TabBar
{
public sealed partial class TabBar
{
- private void InitializeLinuxCaptionButtons()
+ private void InitializeCaptionButtons()
{
if (!OperatingSystem.IsLinux())
return;
- MainWindow.Instance.InitializeLinuxChrome();
- MainWindow.Instance.LinuxChromeChanged -= LinuxChromeChanged;
- MainWindow.Instance.LinuxChromeChanged += LinuxChromeChanged;
- Unloaded -= LinuxCaptionButtons_Unloaded;
- Unloaded += LinuxCaptionButtons_Unloaded;
- UpdateLinuxCaptionButtons();
+ MainWindow.Instance.InitializeChrome();
+ MainWindow.Instance.ChromeChanged -= OnChromeChanged;
+ MainWindow.Instance.ChromeChanged += OnChromeChanged;
+ Unloaded -= CaptionButtons_Unloaded;
+ Unloaded += CaptionButtons_Unloaded;
+ UpdateCaptionButtons();
_ = NavigationHelpers.UpdateInstancePropertiesAsync(Items.ElementAtOrDefault(App.AppModel.TabStripSelectedIndex)?.NavigationParameter?.NavigationParameter);
}
- private void LinuxCaptionButtons_Unloaded(object sender, RoutedEventArgs e)
- => MainWindow.Instance.LinuxChromeChanged -= LinuxChromeChanged;
+ private void CaptionButtons_Unloaded(object sender, RoutedEventArgs e)
+ => MainWindow.Instance.ChromeChanged -= OnChromeChanged;
- private void LinuxChromeChanged(object? sender, EventArgs e) => UpdateLinuxCaptionButtons();
+ private void OnChromeChanged(object? sender, EventArgs e) => UpdateCaptionButtons();
- private void UpdateLinuxCaptionButtons()
+ private void UpdateCaptionButtons()
{
var window = MainWindow.Instance;
- LinuxCaptionButtons.Visibility = window.HasClientSideDecorations ? Visibility.Visible : Visibility.Collapsed;
+ CaptionButtons.Visibility = window.HasClientSideDecorations ? Visibility.Visible : Visibility.Collapsed;
ClientSideDecorationsMenuItem.Visibility = Visibility.Visible;
ClientSideDecorationsMenuItem.IsChecked = window.UseClientSideDecorations;
- var maximizeLabel = (window.IsLinuxWindowMaximized ? "LinuxRestoreWindow" : "LinuxMaximizeWindow").GetLocalizedResource();
- AutomationProperties.SetName(LinuxMaximizeButton, maximizeLabel);
- ToolTipService.SetToolTip(LinuxMaximizeButton, maximizeLabel);
- LinuxMaximizeIcon.Glyph = window.IsLinuxWindowMaximized ? "\uE923" : "\uE922";
+ var maximizeLabel = (window.IsWindowMaximized ? "DesktopRestoreWindow" : "DesktopMaximizeWindow").GetLocalizedResource();
+ AutomationProperties.SetName(MaximizeButton, maximizeLabel);
+ ToolTipService.SetToolTip(MaximizeButton, maximizeLabel);
+ MaximizeIcon.Glyph = window.IsWindowMaximized ? "\uE923" : "\uE922";
UpdateTitleBarInsets();
}
@@ -55,7 +55,7 @@ private void MinimizeWindow_Click(object sender, RoutedEventArgs e)
private void MaximizeWindow_Click(object sender, RoutedEventArgs e)
{
- MainWindow.Instance.ToggleLinuxWindowMaximize();
+ MainWindow.Instance.ToggleWindowMaximize();
}
private void CloseWindow_Click(object sender, RoutedEventArgs e) => MainWindow.Instance.Close();
diff --git a/src/Files.App/UserControls/TabBar/TabBar.xaml b/src/Files.App/UserControls/TabBar/TabBar.xaml
index 7e14e387b3a9..c61c937ed0c9 100644
--- a/src/Files.App/UserControls/TabBar/TabBar.xaml
+++ b/src/Files.App/UserControls/TabBar/TabBar.xaml
@@ -39,7 +39,7 @@
@@ -256,12 +256,12 @@
-
-