Skip to content

Code Quality: Introduced IWindowsWallpaperService #15811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/Files.App/Actions/Content/Background/BaseSetAsAction.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright (c) 2024 Files Community
// Licensed under the MIT License. See the LICENSE.

using Microsoft.UI.Xaml.Controls;
using Windows.Foundation.Metadata;

namespace Files.App.Actions
{
internal abstract class BaseSetAsAction : ObservableObject, IAction
Expand Down Expand Up @@ -28,6 +31,21 @@ public BaseSetAsAction()

public abstract Task ExecuteAsync(object? parameter = null);

protected async void ShowErrorDialog(string message)
{
var errorDialog = new ContentDialog()
{
Title = "FailedToSetBackground".GetLocalizedResource(),
Content = message,
PrimaryButtonText = "OK".GetLocalizedResource(),
};

if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
errorDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot;

await errorDialog.TryShowAsync();
}

private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Files.App.Actions
{
internal sealed class SetAsLockscreenBackgroundAction : BaseSetAsAction
{
private readonly IWindowsWallpaperService WindowsWallpaperService = Ioc.Default.GetRequiredService<IWindowsWallpaperService>();

public override string Label
=> "SetAsLockscreen".GetLocalizedResource();

Expand All @@ -20,10 +22,19 @@ public override RichGlyph Glyph

public override Task ExecuteAsync(object? parameter = null)
{
if (context.SelectedItem is not null)
return WallpaperHelpers.SetAsBackgroundAsync(WallpaperType.LockScreen, context.SelectedItem.ItemPath);
if (context.SelectedItem is null)
return Task.CompletedTask;

try
{
return WindowsWallpaperService.SetLockScreenWallpaper(context.SelectedItem.ItemPath);
}
catch (Exception ex)
{
ShowErrorDialog(ex.Message);

return Task.CompletedTask;
return Task.CompletedTask;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Files.App.Actions
{
internal sealed class SetAsSlideshowBackgroundAction : BaseSetAsAction
{
private readonly IWindowsWallpaperService WindowsWallpaperService = Ioc.Default.GetRequiredService<IWindowsWallpaperService>();

public override string Label
=> "SetAsSlideshow".GetLocalizedResource();

Expand All @@ -21,7 +23,15 @@ public override RichGlyph Glyph
public override Task ExecuteAsync(object? parameter = null)
{
var paths = context.SelectedItems.Select(item => item.ItemPath).ToArray();
WallpaperHelpers.SetSlideshow(paths);

try
{
WindowsWallpaperService.SetDesktopSlideshow(paths);
}
catch (Exception ex)
{
ShowErrorDialog(ex.Message);
}

return Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Files.App.Actions
{
internal sealed class SetAsWallpaperBackgroundAction : BaseSetAsAction
{
private readonly IWindowsWallpaperService WindowsWallpaperService = Ioc.Default.GetRequiredService<IWindowsWallpaperService>();

public override string Label
=> "SetAsBackground".GetLocalizedResource();

Expand All @@ -20,8 +22,17 @@ public override RichGlyph Glyph

public override Task ExecuteAsync(object? parameter = null)
{
if (context.SelectedItem is not null)
return WallpaperHelpers.SetAsBackgroundAsync(WallpaperType.Desktop, context.SelectedItem.ItemPath);
if (context.SelectedItem is null)
return Task.CompletedTask;

try
{
WindowsWallpaperService.SetDesktopWallpaper(context.SelectedItem.ItemPath);
}
catch (Exception ex)
{
ShowErrorDialog(ex.Message);
}

return Task.CompletedTask;
}
Expand Down
29 changes: 29 additions & 0 deletions src/Files.App/Data/Contracts/IWindowsWallpaperService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2024 Files Community
// Licensed under the MIT License. See the LICENSE.

namespace Files.App.Data.Contracts
{
/// <summary>
/// Provides service for manipulating shell wallpapers on Windows.
/// </summary>
public interface IWindowsWallpaperService
{
/// <summary>
/// Sets desktop wallpaper using the specified image path.
/// </summary>
/// <param name="szPath">The image path to assign as the desktop wallpaper.</param>
void SetDesktopWallpaper(string szPath);

/// <summary>
/// Sets desktop slideshow using the specified image paths.
/// </summary>
/// <param name="aszPaths">The image paths to use to set as slideshow.</param>
void SetDesktopSlideshow(string[] aszPaths);

/// <summary>
/// Gets lock screen wallpaper using the specified image path.
/// </summary>
/// <param name="szPath">The image path to use to set as lock screen wallpaper.</param>
Task SetLockScreenWallpaper(string szPath);
}
}
1 change: 1 addition & 0 deletions src/Files.App/Helpers/Application/AppLifecycleHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ public static IHost ConfigureHost()
.AddSingleton<ISidebarContext, SidebarContext>()
// Services
.AddSingleton<IWindowsIniService, WindowsIniService>()
.AddSingleton<IWindowsWallpaperService, WindowsWallpaperService>()
.AddSingleton<IAppThemeModeService, AppThemeModeService>()
.AddSingleton<IDialogService, DialogService>()
.AddSingleton<ICommonDialogService, CommonDialogService>()
Expand Down
5 changes: 5 additions & 0 deletions src/Files.App/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,8 @@ LocalAlloc
InitializeAcl
AddAce
LocalFree
IDesktopWallpaper
DesktopWallpaper
SHCreateShellItemArrayFromIDLists
ILCreateFromPath
CLSIDFromString
79 changes: 79 additions & 0 deletions src/Files.App/Services/Windows/WindowsWallpaperService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2024 Files Community
// Licensed under the MIT License. See the LICENSE.

using Windows.Storage;
using Windows.System.UserProfile;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.System.Com;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.Shell.Common;

namespace Files.App.Services
{
/// <inheritdoc cref="IWindowsWallpaperService"/>
public sealed class WindowsWallpaperService : IWindowsWallpaperService
{
/// <inheritdoc/>
public unsafe void SetDesktopWallpaper(string szPath)
{
PInvoke.CoCreateInstance(
new Guid("{C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD}"),
null,
CLSCTX.CLSCTX_LOCAL_SERVER,
out IDesktopWallpaper desktopWallpaper)
.ThrowOnFailure();

desktopWallpaper.GetMonitorDevicePathCount(out var dwMonitorCount);

fixed (char* pszPath = szPath)
{
var pwszPath = new PWSTR(pszPath);

for (uint dwIndex = 0; dwIndex < dwMonitorCount; dwIndex++)
{
desktopWallpaper.GetMonitorDevicePathAt(dwIndex, out var pMonitorID);
desktopWallpaper.SetWallpaper(pMonitorID, pwszPath);
}
}
}

/// <inheritdoc/>
public unsafe void SetDesktopSlideshow(string[] aszPaths)
{
PInvoke.CoCreateInstance(
new Guid("{C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD}"),
null,
CLSCTX.CLSCTX_LOCAL_SERVER,
out IDesktopWallpaper desktopWallpaper)
.ThrowOnFailure();

var dwCount = (uint)aszPaths.Length;

fixed (ITEMIDLIST** idList = new ITEMIDLIST*[dwCount])
{
for (uint dwIndex = 0u; dwIndex < dwCount; dwIndex++)
{
var id = PInvoke.ILCreateFromPath(aszPaths[dwIndex]);
idList[dwIndex] = id;
}

// Get shell item array from images to use for slideshow
PInvoke.SHCreateShellItemArrayFromIDLists(dwCount, idList, out var shellItemArray);

// Set slideshow
desktopWallpaper.SetSlideshow(shellItemArray);
}

// Set wallpaper to fill desktop.
desktopWallpaper.SetPosition(DESKTOP_WALLPAPER_POSITION.DWPOS_FILL);
}

/// <inheritdoc/>
public async Task SetLockScreenWallpaper(string szPath)
{
IStorageFile sourceFile = await StorageFile.GetFileFromPathAsync(szPath);
await LockScreen.SetImageFileAsync(sourceFile);
}
}
}
81 changes: 0 additions & 81 deletions src/Files.App/Utils/Global/WallpaperHelpers.cs

This file was deleted.