插件市场安装优化
This commit is contained in:
lincube
2026-03-11 06:38:11 +08:00
parent 5003ff1be2
commit 2781d7e0d9
17 changed files with 907 additions and 89 deletions

View File

@@ -1195,11 +1195,22 @@ public partial class MainWindow
var restoreButton = new Button
{
Content = L("settings.launcher.restore_button", "Unhide"),
MinWidth = 110,
Padding = new Thickness(12, 6),
Width = 36,
Height = 36,
Padding = new Thickness(0),
Background = Brushes.Transparent,
BorderThickness = new Thickness(0),
Tag = new LauncherHiddenItemToken(hiddenItem.Kind, hiddenItem.Key)
};
restoreButton.Content = new FluentIcons.Avalonia.Fluent.SymbolIcon
{
Symbol = FluentIcons.Common.Symbol.Eye,
IconVariant = FluentIcons.Common.IconVariant.Regular,
FontSize = 18,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
ToolTip.SetTip(restoreButton, L("settings.launcher.restore_button", "Unhide"));
restoreButton.Click += OnRestoreLauncherHiddenItemClick;
return new SettingsExpanderItem

View File

@@ -158,6 +158,7 @@ public partial class MainWindow
}
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
UpdateVideoWallpaperPreviewVisibility();
}
private void OnNightModeChecked(object? sender, RoutedEventArgs e)
@@ -344,6 +345,7 @@ public partial class MainWindow
var placement = GetSelectedWallpaperPlacement();
DesktopWallpaperLayer.Background = CreateWallpaperBrush(_wallpaperBitmap, placement, false);
WallpaperPreviewViewport.Background = CreateWallpaperBrush(_wallpaperBitmap, placement, true);
UpdateVideoWallpaperPreviewVisibility();
}
private void UpdateWallpaperDisplay()
@@ -628,12 +630,99 @@ public partial class MainWindow
EnableHardwareDecoding = false
};
}
}
if (_previewVideoWallpaperPlayer is null && WallpaperPreviewVideoView is not null)
private void EnsureDesktopVideoFrameRefreshTimer()
{
if (_desktopVideoFrameRefreshTimer is not null)
{
_previewVideoWallpaperPlayer = new MediaPlayer(_libVlc);
WallpaperPreviewVideoView.MediaPlayer = _previewVideoWallpaperPlayer;
return;
}
_desktopVideoFrameRefreshTimer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(33)
};
_desktopVideoFrameRefreshTimer.Tick += OnDesktopVideoFrameRefreshTimerTick;
}
private void StartDesktopVideoFrameRefreshTimer()
{
EnsureDesktopVideoFrameRefreshTimer();
if (_desktopVideoFrameRefreshTimer?.IsEnabled == false)
{
_desktopVideoFrameRefreshTimer.Start();
}
}
private void StopDesktopVideoFrameRefreshTimer()
{
if (_desktopVideoFrameRefreshTimer?.IsEnabled == true)
{
_desktopVideoFrameRefreshTimer.Stop();
}
}
private void OnDesktopVideoFrameRefreshTimerTick(object? sender, EventArgs e)
{
PushDesktopVideoFrameToWallpaperImage();
}
private void UpdateVideoWallpaperPreviewVisibility()
{
var shouldShowPreview =
_wallpaperMediaType == WallpaperMediaType.Video &&
_isSettingsOpen &&
SettingsPage.IsVisible &&
WallpaperSettingsPanel.IsVisible &&
_wallpaperPreviewSnapshotBitmap is not null;
WallpaperPreviewVideoImage.IsVisible = shouldShowPreview;
if (shouldShowPreview && !ReferenceEquals(WallpaperPreviewVideoImage.Source, _wallpaperPreviewSnapshotBitmap))
{
WallpaperPreviewVideoImage.Source = _wallpaperPreviewSnapshotBitmap;
}
}
private void InvalidateVideoWallpaperPreviewSnapshot()
{
_wallpaperPreviewSnapshotPending = true;
_wallpaperPreviewSnapshotBitmap?.Dispose();
_wallpaperPreviewSnapshotBitmap = null;
WallpaperPreviewVideoImage.Source = null;
}
private void CaptureVideoWallpaperPreviewSnapshotFromStagingBuffer()
{
if (!_wallpaperPreviewSnapshotPending ||
_desktopVideoStagingBuffer is null ||
_desktopVideoFrameWidth <= 0 ||
_desktopVideoFrameHeight <= 0 ||
_desktopVideoFramePitch <= 0)
{
return;
}
_wallpaperPreviewSnapshotBitmap?.Dispose();
_wallpaperPreviewSnapshotBitmap = new WriteableBitmap(
new PixelSize(_desktopVideoFrameWidth, _desktopVideoFrameHeight),
new Vector(96, 96),
PixelFormat.Bgra8888,
AlphaFormat.Opaque);
using var framebuffer = _wallpaperPreviewSnapshotBitmap.Lock();
var rows = Math.Min(framebuffer.Size.Height, _desktopVideoFrameHeight);
var bytesPerRow = Math.Min(framebuffer.RowBytes, _desktopVideoFramePitch);
for (var row = 0; row < rows; row++)
{
var sourceOffset = row * _desktopVideoFramePitch;
var destinationPtr = IntPtr.Add(framebuffer.Address, row * framebuffer.RowBytes);
Marshal.Copy(_desktopVideoStagingBuffer, sourceOffset, destinationPtr, bytesPerRow);
}
_wallpaperPreviewSnapshotPending = false;
WallpaperPreviewVideoImage.Source = _wallpaperPreviewSnapshotBitmap;
UpdateVideoWallpaperPreviewVisibility();
}
private bool ConfigureDesktopVideoRenderer()
@@ -685,6 +774,7 @@ public partial class MainWindow
(uint)_desktopVideoFrameHeight,
(uint)_desktopVideoFramePitch);
DesktopVideoWallpaperImage.Source = _desktopVideoBitmap;
InvalidateVideoWallpaperPreviewSnapshot();
return true;
}
catch
@@ -745,31 +835,6 @@ public partial class MainWindow
private void OnDesktopVideoFrameDisplay(IntPtr opaque, IntPtr picture)
{
Interlocked.Exchange(ref _desktopVideoFrameDirtyFlag, 1);
ScheduleDesktopVideoFrameUiRefresh();
}
private void ScheduleDesktopVideoFrameUiRefresh()
{
if (Interlocked.Exchange(ref _desktopVideoFrameUiRefreshScheduledFlag, 1) == 1)
{
return;
}
Dispatcher.UIThread.Post(() =>
{
try
{
PushDesktopVideoFrameToWallpaperImage();
}
finally
{
Interlocked.Exchange(ref _desktopVideoFrameUiRefreshScheduledFlag, 0);
if (Volatile.Read(ref _desktopVideoFrameDirtyFlag) == 1)
{
ScheduleDesktopVideoFrameUiRefresh();
}
}
}, DispatcherPriority.Render);
}
private void PushDesktopVideoFrameToWallpaperImage()
@@ -812,18 +877,22 @@ public partial class MainWindow
{
DesktopVideoWallpaperImage.Source = _desktopVideoBitmap;
}
CaptureVideoWallpaperPreviewSnapshotFromStagingBuffer();
}
private void ReleaseDesktopVideoRendererResources()
{
Interlocked.Exchange(ref _desktopVideoFrameDirtyFlag, 0);
Interlocked.Exchange(ref _desktopVideoFrameUiRefreshScheduledFlag, 0);
if (DesktopVideoWallpaperImage is not null)
{
DesktopVideoWallpaperImage.Source = null;
}
InvalidateVideoWallpaperPreviewSnapshot();
WallpaperPreviewVideoImage.Source = null;
_desktopVideoBitmap?.Dispose();
_desktopVideoBitmap = null;
_desktopVideoStagingBuffer = null;
@@ -855,10 +924,8 @@ public partial class MainWindow
{
EnsureVideoWallpaperPlayers();
if (_videoWallpaperPlayer is null ||
_previewVideoWallpaperPlayer is null ||
_libVlc is null ||
DesktopVideoWallpaperImage is null ||
WallpaperPreviewVideoView is null)
DesktopVideoWallpaperImage is null)
{
_wallpaperStatus = L("settings.wallpaper.video_player_unavailable", "Video player is unavailable.");
StopVideoWallpaper();
@@ -873,15 +940,13 @@ public partial class MainWindow
}
_videoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia?.Dispose();
_videoWallpaperMedia = new Media(_libVlc, new Uri(videoPath));
_previewVideoWallpaperMedia = new Media(_libVlc, new Uri(videoPath));
_videoWallpaperMedia.AddOption(":input-repeat=65535");
_previewVideoWallpaperMedia.AddOption(":input-repeat=65535");
InvalidateVideoWallpaperPreviewSnapshot();
_videoWallpaperPlayer.Play(_videoWallpaperMedia);
_previewVideoWallpaperPlayer.Play(_previewVideoWallpaperMedia);
StartDesktopVideoFrameRefreshTimer();
DesktopVideoWallpaperImage.IsVisible = true;
WallpaperPreviewVideoView.IsVisible = true;
UpdateVideoWallpaperPreviewVisibility();
}
catch (Exception ex)
{
@@ -897,26 +962,17 @@ public partial class MainWindow
DesktopVideoWallpaperImage.IsVisible = false;
}
if (WallpaperPreviewVideoView is not null)
{
WallpaperPreviewVideoView.IsVisible = false;
}
WallpaperPreviewVideoImage.IsVisible = false;
if (_videoWallpaperPlayer is not null)
{
_videoWallpaperPlayer.Stop();
}
if (_previewVideoWallpaperPlayer is not null)
{
_previewVideoWallpaperPlayer.Stop();
}
StopDesktopVideoFrameRefreshTimer();
ReleaseDesktopVideoRendererResources();
_videoWallpaperMedia?.Dispose();
_videoWallpaperMedia = null;
_previewVideoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia = null;
}
private void PersistSettings()
@@ -2379,7 +2435,14 @@ public partial class MainWindow
_isSettingsOpen = true;
UpdateDesktopPageAwareComponentContext();
UpdateAdaptiveTextSystem();
ApplyWallpaperBrush();
if (_wallpaperMediaType == WallpaperMediaType.Video)
{
UpdateVideoWallpaperPreviewVisibility();
}
else
{
ApplyWallpaperBrush();
}
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
if (_settingsContentPanelTransform is not null)
{
@@ -2387,6 +2450,7 @@ public partial class MainWindow
}
SettingsPage.IsVisible = true;
SettingsPage.Opacity = 0;
UpdateVideoWallpaperPreviewVisibility();
UpdateSettingsViewportInsets(Math.Max(1, _currentDesktopCellSize));
UpdateWallpaperPreviewLayout();
@@ -2416,7 +2480,11 @@ public partial class MainWindow
_isSettingsOpen = false;
UpdateDesktopPageAwareComponentContext();
UpdateAdaptiveTextSystem();
ApplyWallpaperBrush();
UpdateVideoWallpaperPreviewVisibility();
if (_wallpaperMediaType != WallpaperMediaType.Video)
{
ApplyWallpaperBrush();
}
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
if (immediate)
@@ -2608,7 +2676,7 @@ public partial class MainWindow
internal Border WallpaperPreviewHost => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewHost")!;
internal Border WallpaperPreviewFrame => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewFrame")!;
internal Border WallpaperPreviewViewport => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewViewport")!;
internal LibVLCSharp.Avalonia.VideoView? WallpaperPreviewVideoView => WallpaperSettingsPanel.FindControl<LibVLCSharp.Avalonia.VideoView>("WallpaperPreviewVideoView");
internal Image WallpaperPreviewVideoImage => WallpaperSettingsPanel.FindControl<Image>("WallpaperPreviewVideoImage")!;
internal Grid WallpaperPreviewGrid => WallpaperSettingsPanel.FindControl<Grid>("WallpaperPreviewGrid")!;
internal Border WallpaperPreviewTopStatusBarHost => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewTopStatusBarHost")!;
internal StackPanel WallpaperPreviewTopStatusComponentsPanel => WallpaperSettingsPanel.FindControl<StackPanel>("WallpaperPreviewTopStatusComponentsPanel")!;

View File

@@ -124,21 +124,21 @@ public partial class MainWindow : Window
private LibVLC? _libVlc;
private MediaPlayer? _videoWallpaperPlayer;
private Media? _videoWallpaperMedia;
private MediaPlayer? _previewVideoWallpaperPlayer;
private Media? _previewVideoWallpaperMedia;
private readonly object _desktopVideoFrameSync = new();
private MediaPlayer.LibVLCVideoLockCb? _desktopVideoLockCallback;
private MediaPlayer.LibVLCVideoUnlockCb? _desktopVideoUnlockCallback;
private MediaPlayer.LibVLCVideoDisplayCb? _desktopVideoDisplayCallback;
private DispatcherTimer? _desktopVideoFrameRefreshTimer;
private IntPtr _desktopVideoFrameBufferPtr;
private byte[]? _desktopVideoStagingBuffer;
private WriteableBitmap? _desktopVideoBitmap;
private WriteableBitmap? _wallpaperPreviewSnapshotBitmap;
private int _desktopVideoFrameWidth;
private int _desktopVideoFrameHeight;
private int _desktopVideoFramePitch;
private int _desktopVideoFrameBufferSize;
private int _desktopVideoFrameDirtyFlag;
private int _desktopVideoFrameUiRefreshScheduledFlag;
private bool _wallpaperPreviewSnapshotPending;
private string? _wallpaperPath;
private string _wallpaperStatus = "Current background uses solid color.";
private IReadOnlyList<Color> _recommendedColors = Array.Empty<Color>();
@@ -384,15 +384,15 @@ public partial class MainWindow : Window
{
PersistSettings();
StopVideoWallpaper();
_previewVideoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia = null;
_previewVideoWallpaperPlayer?.Dispose();
_previewVideoWallpaperPlayer = null;
DisposeLauncherResources();
_videoWallpaperMedia?.Dispose();
_videoWallpaperMedia = null;
_videoWallpaperPlayer?.Dispose();
_videoWallpaperPlayer = null;
_desktopVideoFrameRefreshTimer?.Stop();
_desktopVideoFrameRefreshTimer = null;
_wallpaperPreviewSnapshotBitmap?.Dispose();
_wallpaperPreviewSnapshotBitmap = null;
_libVlc?.Dispose();
_libVlc = null;
if (_weatherDataService is IDisposable weatherServiceDisposable)

View File

@@ -6,7 +6,6 @@
xmlns:fi="using:FluentIcons.Avalonia"
xmlns:ic="using:FluentIcons.Avalonia.Fluent"
xmlns:comp="using:LanMountainDesktop.Views.Components"
xmlns:vlc="clr-namespace:LibVLCSharp.Avalonia;assembly=LibVLCSharp.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="LanMountainDesktop.Views.SettingsPages.WallpaperSettingsPage">
<Grid x:Name="WallpaperSettingsPanel"
@@ -37,11 +36,12 @@
CornerRadius="12"
Background="#30111827">
<Grid>
<vlc:VideoView x:Name="WallpaperPreviewVideoView"
IsVisible="False"
IsHitTestVisible="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<Image x:Name="WallpaperPreviewVideoImage"
IsVisible="False"
IsHitTestVisible="False"
Stretch="UniformToFill"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<Grid x:Name="WallpaperPreviewGrid"
HorizontalAlignment="Center"

View File

@@ -1,7 +1,6 @@
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using LibVLCSharp.Avalonia;
namespace LanMountainDesktop.Views;
public partial class SettingsWindow
@@ -14,7 +13,7 @@ public partial class SettingsWindow
internal Border WallpaperPreviewHost => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewHost")!;
internal Border WallpaperPreviewFrame => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewFrame")!;
internal Border WallpaperPreviewViewport => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewViewport")!;
internal LibVLCSharp.Avalonia.VideoView? WallpaperPreviewVideoView => WallpaperSettingsPanel.FindControl<LibVLCSharp.Avalonia.VideoView>("WallpaperPreviewVideoView");
internal Image WallpaperPreviewVideoImage => WallpaperSettingsPanel.FindControl<Image>("WallpaperPreviewVideoImage")!;
internal Grid WallpaperPreviewGrid => WallpaperSettingsPanel.FindControl<Grid>("WallpaperPreviewGrid")!;
internal Border WallpaperPreviewTopStatusBarHost => WallpaperSettingsPanel.FindControl<Border>("WallpaperPreviewTopStatusBarHost")!;
internal StackPanel WallpaperPreviewTopStatusComponentsPanel => WallpaperSettingsPanel.FindControl<StackPanel>("WallpaperPreviewTopStatusComponentsPanel")!;

View File

@@ -29,6 +29,8 @@ public partial class SettingsWindow
_previewVideoWallpaperPlayer = null;
_previewVideoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia = null;
_previewVideoFrameRefreshTimer?.Stop();
_previewVideoFrameRefreshTimer = null;
_libVlc?.Dispose();
_libVlc = null;
@@ -254,6 +256,7 @@ public partial class SettingsWindow
}
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
SyncVideoWallpaperPreviewPlayback();
}
private void PersistSettings()

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
@@ -12,6 +13,7 @@ using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using LanMountainDesktop.Services;
using LanMountainDesktop.Theme;
using LibVLCSharp.Shared;
@@ -157,7 +159,7 @@ public partial class SettingsWindow
{
DesktopWallpaperLayer.Background = Brushes.Transparent;
WallpaperPreviewViewport.Background = GetThemeDefaultDesktopBackground();
PlayVideoWallpaper(_wallpaperVideoPath);
SyncVideoWallpaperPreviewPlayback();
return;
}
@@ -175,6 +177,36 @@ public partial class SettingsWindow
WallpaperPreviewViewport.Background = CreateWallpaperBrush(_wallpaperBitmap, placement, true);
}
private void SyncVideoWallpaperPreviewPlayback()
{
var shouldPlay =
_wallpaperMediaType == WallpaperMediaType.Video &&
!string.IsNullOrWhiteSpace(_wallpaperVideoPath) &&
WallpaperSettingsPanel.IsVisible;
if (!shouldPlay)
{
if (_previewVideoWallpaperPlayer?.IsPlaying == true)
{
StopPreviewVideoCapture(clearSnapshot: false);
}
WallpaperPreviewVideoImage.IsVisible = WallpaperPreviewVideoImage.Source is not null && WallpaperSettingsPanel.IsVisible;
return;
}
if (WallpaperPreviewVideoImage.Source is not null)
{
WallpaperPreviewVideoImage.IsVisible = true;
return;
}
if (_previewVideoWallpaperMedia is null || _previewVideoSnapshotPending)
{
PlayVideoWallpaper(_wallpaperVideoPath!);
}
}
private void UpdateWallpaperDisplay()
{
WallpaperPathTextBlock.Text = string.IsNullOrWhiteSpace(_wallpaperPath)
@@ -417,11 +449,239 @@ public partial class SettingsWindow
private void EnsureVideoWallpaperPlayers()
{
Core.Initialize();
_libVlc ??= new LibVLC();
_previewVideoWallpaperPlayer ??= new MediaPlayer(_libVlc);
if (WallpaperPreviewVideoView is not null)
_libVlc ??= new LibVLC("--quiet");
if (_previewVideoWallpaperPlayer is null)
{
WallpaperPreviewVideoView.MediaPlayer = _previewVideoWallpaperPlayer;
_previewVideoWallpaperPlayer = new MediaPlayer(_libVlc)
{
EnableHardwareDecoding = false
};
}
}
private void EnsurePreviewVideoFrameRefreshTimer()
{
if (_previewVideoFrameRefreshTimer is not null)
{
return;
}
_previewVideoFrameRefreshTimer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(33)
};
_previewVideoFrameRefreshTimer.Tick += OnPreviewVideoFrameRefreshTimerTick;
}
private void StartPreviewVideoFrameRefreshTimer()
{
EnsurePreviewVideoFrameRefreshTimer();
if (_previewVideoFrameRefreshTimer?.IsEnabled == false)
{
_previewVideoFrameRefreshTimer.Start();
}
}
private void StopPreviewVideoFrameRefreshTimer()
{
if (_previewVideoFrameRefreshTimer?.IsEnabled == true)
{
_previewVideoFrameRefreshTimer.Stop();
}
}
private void OnPreviewVideoFrameRefreshTimerTick(object? sender, EventArgs e)
{
PushPreviewVideoFrameToWallpaperImage();
}
private void StopPreviewVideoCapture(bool clearSnapshot)
{
WallpaperPreviewVideoImage.IsVisible = false;
_previewVideoWallpaperPlayer?.Stop();
StopPreviewVideoFrameRefreshTimer();
_previewVideoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia = null;
_previewVideoSnapshotPending = false;
if (clearSnapshot)
{
ReleasePreviewVideoRendererResources();
}
}
private bool ConfigurePreviewVideoRenderer()
{
if (_previewVideoWallpaperPlayer is null)
{
return false;
}
var hostWidth = Math.Max(1, WallpaperPreviewViewport.Bounds.Width);
var hostHeight = Math.Max(1, WallpaperPreviewViewport.Bounds.Height);
var pixelWidth = Math.Max(1, (int)Math.Round(hostWidth * RenderScaling));
var pixelHeight = Math.Max(1, (int)Math.Round(hostHeight * RenderScaling));
const int maxPixelCount = 1280 * 720;
var pixelCount = (long)pixelWidth * pixelHeight;
if (pixelCount > maxPixelCount)
{
var scale = Math.Sqrt((double)maxPixelCount / pixelCount);
pixelWidth = Math.Max(1, (int)Math.Round(pixelWidth * scale));
pixelHeight = Math.Max(1, (int)Math.Round(pixelHeight * scale));
}
var pitch = pixelWidth * 4;
var bufferSize = pitch * pixelHeight;
if (bufferSize <= 0)
{
return false;
}
if (pixelWidth == _previewVideoFrameWidth &&
pixelHeight == _previewVideoFrameHeight &&
_previewVideoFrameBufferPtr != IntPtr.Zero &&
_previewVideoBitmap is not null)
{
return true;
}
ReleasePreviewVideoRendererResources();
try
{
_previewVideoFrameWidth = pixelWidth;
_previewVideoFrameHeight = pixelHeight;
_previewVideoFramePitch = pitch;
_previewVideoFrameBufferSize = bufferSize;
_previewVideoFrameBufferPtr = Marshal.AllocHGlobal(_previewVideoFrameBufferSize);
_previewVideoStagingBuffer = new byte[_previewVideoFrameBufferSize];
_previewVideoBitmap = new WriteableBitmap(
new PixelSize(_previewVideoFrameWidth, _previewVideoFrameHeight),
new Vector(96, 96),
PixelFormat.Bgra8888,
AlphaFormat.Opaque);
EnsurePreviewVideoCallbacks();
_previewVideoWallpaperPlayer.SetVideoCallbacks(
_previewVideoLockCallback!,
_previewVideoUnlockCallback!,
_previewVideoDisplayCallback!);
_previewVideoWallpaperPlayer.SetVideoFormat(
"RV32",
(uint)_previewVideoFrameWidth,
(uint)_previewVideoFrameHeight,
(uint)_previewVideoFramePitch);
WallpaperPreviewVideoImage.Source = _previewVideoBitmap;
return true;
}
catch
{
ReleasePreviewVideoRendererResources();
return false;
}
}
private void EnsurePreviewVideoCallbacks()
{
_previewVideoLockCallback ??= OnPreviewVideoFrameLock;
_previewVideoUnlockCallback ??= OnPreviewVideoFrameUnlock;
_previewVideoDisplayCallback ??= OnPreviewVideoFrameDisplay;
}
private IntPtr OnPreviewVideoFrameLock(IntPtr opaque, IntPtr planes)
{
Monitor.Enter(_previewVideoFrameSync);
if (_previewVideoFrameBufferPtr == IntPtr.Zero)
{
Marshal.WriteIntPtr(planes, IntPtr.Zero);
Monitor.Exit(_previewVideoFrameSync);
return IntPtr.Zero;
}
Marshal.WriteIntPtr(planes, _previewVideoFrameBufferPtr);
return IntPtr.Zero;
}
private void OnPreviewVideoFrameUnlock(IntPtr opaque, IntPtr picture, IntPtr planes)
{
if (Monitor.IsEntered(_previewVideoFrameSync))
{
Monitor.Exit(_previewVideoFrameSync);
}
}
private void OnPreviewVideoFrameDisplay(IntPtr opaque, IntPtr picture)
{
Interlocked.Exchange(ref _previewVideoFrameDirtyFlag, 1);
}
private void PushPreviewVideoFrameToWallpaperImage()
{
if (Interlocked.Exchange(ref _previewVideoFrameDirtyFlag, 0) == 0)
{
return;
}
if (_previewVideoBitmap is null ||
_previewVideoStagingBuffer is null ||
_previewVideoFrameBufferPtr == IntPtr.Zero ||
_previewVideoFrameBufferSize <= 0)
{
return;
}
lock (_previewVideoFrameSync)
{
if (_previewVideoFrameBufferPtr == IntPtr.Zero)
{
return;
}
Marshal.Copy(_previewVideoFrameBufferPtr, _previewVideoStagingBuffer, 0, _previewVideoFrameBufferSize);
}
using var framebuffer = _previewVideoBitmap.Lock();
var rows = Math.Min(framebuffer.Size.Height, _previewVideoFrameHeight);
var bytesPerRow = Math.Min(framebuffer.RowBytes, _previewVideoFramePitch);
for (var row = 0; row < rows; row++)
{
var sourceOffset = row * _previewVideoFramePitch;
var destinationPtr = IntPtr.Add(framebuffer.Address, row * framebuffer.RowBytes);
Marshal.Copy(_previewVideoStagingBuffer, sourceOffset, destinationPtr, bytesPerRow);
}
if (!ReferenceEquals(WallpaperPreviewVideoImage.Source, _previewVideoBitmap))
{
WallpaperPreviewVideoImage.Source = _previewVideoBitmap;
}
if (_previewVideoSnapshotPending)
{
_previewVideoSnapshotPending = false;
WallpaperPreviewVideoImage.IsVisible = WallpaperSettingsPanel.IsVisible;
StopPreviewVideoCapture(clearSnapshot: false);
WallpaperPreviewVideoImage.IsVisible = WallpaperSettingsPanel.IsVisible;
}
}
private void ReleasePreviewVideoRendererResources()
{
Interlocked.Exchange(ref _previewVideoFrameDirtyFlag, 0);
WallpaperPreviewVideoImage.Source = null;
_previewVideoBitmap?.Dispose();
_previewVideoBitmap = null;
_previewVideoStagingBuffer = null;
_previewVideoFrameWidth = 0;
_previewVideoFrameHeight = 0;
_previewVideoFramePitch = 0;
_previewVideoFrameBufferSize = 0;
lock (_previewVideoFrameSync)
{
if (_previewVideoFrameBufferPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(_previewVideoFrameBufferPtr);
_previewVideoFrameBufferPtr = IntPtr.Zero;
}
}
}
@@ -437,7 +697,14 @@ public partial class SettingsWindow
try
{
EnsureVideoWallpaperPlayers();
if (_previewVideoWallpaperPlayer is null || _libVlc is null || WallpaperPreviewVideoView is null)
if (_previewVideoWallpaperPlayer is null || _libVlc is null)
{
_wallpaperStatus = L("settings.wallpaper.video_player_unavailable", "Video player is unavailable.");
StopVideoWallpaper();
return;
}
if (!ConfigurePreviewVideoRenderer())
{
_wallpaperStatus = L("settings.wallpaper.video_player_unavailable", "Video player is unavailable.");
StopVideoWallpaper();
@@ -447,8 +714,10 @@ public partial class SettingsWindow
_previewVideoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia = new Media(_libVlc, new Uri(videoPath));
_previewVideoWallpaperMedia.AddOption(":input-repeat=65535");
_previewVideoSnapshotPending = true;
WallpaperPreviewVideoImage.IsVisible = false;
_previewVideoWallpaperPlayer.Play(_previewVideoWallpaperMedia);
WallpaperPreviewVideoView.IsVisible = true;
StartPreviewVideoFrameRefreshTimer();
}
catch (Exception ex)
{
@@ -459,14 +728,7 @@ public partial class SettingsWindow
private void StopVideoWallpaper()
{
if (WallpaperPreviewVideoView is not null)
{
WallpaperPreviewVideoView.IsVisible = false;
}
_previewVideoWallpaperPlayer?.Stop();
_previewVideoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia = null;
StopPreviewVideoCapture(clearSnapshot: true);
}
private void OnRecommendedColorClick(object? sender, RoutedEventArgs e)

View File

@@ -873,11 +873,22 @@ public partial class SettingsWindow
var restoreButton = new Button
{
Content = L("settings.launcher.restore_button", "Unhide"),
MinWidth = 110,
Padding = new Thickness(12, 6),
Width = 36,
Height = 36,
Padding = new Thickness(0),
Background = Brushes.Transparent,
BorderThickness = new Thickness(0),
Tag = new LauncherHiddenItemToken(hiddenItem.Kind, hiddenItem.Key)
};
restoreButton.Content = new FluentIcons.Avalonia.Fluent.SymbolIcon
{
Symbol = FluentIcons.Common.Symbol.Eye,
IconVariant = FluentIcons.Common.IconVariant.Regular,
FontSize = 18,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
ToolTip.SetTip(restoreButton, L("settings.launcher.restore_button", "Unhide"));
restoreButton.Click += OnRestoreLauncherHiddenItemClick;
return new SettingsExpanderItem

View File

@@ -129,6 +129,20 @@ public partial class SettingsWindow : Window
private MediaPlayer? _previewVideoWallpaperPlayer;
private Media? _previewVideoWallpaperMedia;
private LibVLC? _libVlc;
private readonly object _previewVideoFrameSync = new();
private MediaPlayer.LibVLCVideoLockCb? _previewVideoLockCallback;
private MediaPlayer.LibVLCVideoUnlockCb? _previewVideoUnlockCallback;
private MediaPlayer.LibVLCVideoDisplayCb? _previewVideoDisplayCallback;
private DispatcherTimer? _previewVideoFrameRefreshTimer;
private IntPtr _previewVideoFrameBufferPtr;
private byte[]? _previewVideoStagingBuffer;
private WriteableBitmap? _previewVideoBitmap;
private int _previewVideoFrameWidth;
private int _previewVideoFrameHeight;
private int _previewVideoFramePitch;
private int _previewVideoFrameBufferSize;
private int _previewVideoFrameDirtyFlag;
private bool _previewVideoSnapshotPending;
private string? _wallpaperPath;
private string _wallpaperStatus = "Current background uses solid color.";
private IReadOnlyList<Color> _recommendedColors = Array.Empty<Color>();