[CmdPal] Add Mica and Mica Alt materials to the Dock (#51470)

## Summary of the Pull Request

The Dock currently offers Acrylic and Transparent, while the main
Command Palette window also supports Mica materials. This adds **Mica**
and **Mica Alt** to **Dock > Appearance > Material**, with live
switching and an independent saved selection.

## PR Checklist

- [ ] **Closes:** No linked issue yet; this is a feature proposal.
- [ ] **Communication:** Seeking maintainer feedback; prior agreement
has not been obtained.
- [x] **Tests:** Added persistence coverage; all 262 focused Dock and
settings-page tests pass.
- [x] **Localization:** Reuses existing localized material labels and
Mica explanation.
- [ ] **Dev docs:** Not applicable; no developer documentation changes.
- [x] **New binaries:** None; no dependency or installer changes.
- [ ] **Documentation updated:** The separate MicrosoftDocs user guide
is not updated in this PR.

## Detailed Description of the Pull Request / Additional comments

- Render Mica and Mica Alt with native `MicaController` instances using
`MicaKind.Base` and `MicaKind.BaseAlt`.
- Synchronize the system backdrop with the Dock's theme and dispose the
previous controller when switching materials or closing the Dock.
- Preserve the existing Acrylic and Transparent rendering paths and enum
values.
- Disable background colorization and images while a Mica material is
selected. Retain those settings for switching back to Acrylic or
Transparent.
- Keep the Dock material independent of the main palette's material.
- Show the Mica explanation inside the Material expander, using the same
card and text styling as the Appearance page.
- Fall back from unsupported Mica/Mica Alt to Acrylic, then Transparent
if Acrylic is also unsupported. Keep Acrylic tint and opacity parameters
ready for the fallback.

## Validation Steps Performed

- Built the x64 Release Command Palette UI successfully with Visual
Studio MSBuild and .NET 10.
- Ran the focused Dock and settings-page tests through VSTest: **262
passed, 0 failed**, including four new save/reload cases covering every
material and palette independence.
- Exercised the production backdrop methods with native support results
simulated: **19 cases passed**, covering both Mica variants,
Acrylic/Transparent fallbacks, configuration availability, repeated
updates, theme changes and controller cleanup. This checks control flow,
not rendering on an older OS.
- Verified the Dock Mica explanation uses the same text styling and
SettingsCard-inside-SettingsExpander layout as the Appearance page.
- Manually validated the four-item Material dropdown and Mica/Mica Alt
in an installed local test build on Windows 11 x64; the requester
confirmed the feature works.
- `git diff --cached --check`: passed.

Build limitation: unchanged native components were reused from the
installed PowerToys package because the local C++ toolchain is
unavailable. This was a non-AOT app build; a full native/AOT build and
multi-monitor/ARM64 validation remain for CI or maintainer testing.
Actual fallback rendering on Windows 10 (including build 19041) has not
been tested; that still needs an older supported system.

## Video: Dock material with another app focused

Tested Mica and Mica Alt on Windows 11 x64 with Notepad focused. The
Dock retained its appearance in both cases; no switch to a flat fallback
background was observed. The recording below shows the material settings
and switching to Notepad.



https://github.com/user-attachments/assets/3cf8df62-a67c-4cdd-b261-5527b29b126e
This commit is contained in:
Denis Mahmutovic authored and GitHub committed 2026-10-27 19:50:33 +00:00
1 parent f0a6c26738
commit 5868a0a124
7 files changed
+128 -7

No files matched your search

@@ -71,11 +71,17 @@ public sealed partial class DockAppearanceSettingsViewModel : ObservableObject,
_settingsService.UpdateSettings(s => s with { DockSettings = s.DockSettings with { Backdrop = value } });
OnPropertyChanged();
OnPropertyChanged(nameof(BackdropIndex));
OnPropertyChanged(nameof(IsMicaBackdrop));
OnPropertyChanged(nameof(SupportsColorization));
DebouncedReapply();
}
}
}
public bool IsMicaBackdrop => Backdrop is DockBackdrop.Mica or DockBackdrop.MicaAlt;
public bool SupportsColorization => !IsMicaBackdrop;
public ColorizationMode ColorizationMode
{
get => _settingsService.Settings.DockSettings.ColorizationMode;
@@ -475,6 +475,8 @@ public enum DockBackdrop
{
Transparent,
Acrylic,
Mica,
MicaAlt,
}
#pragma warning restore SA1402 // File may only contain a single type
@@ -80,9 +80,11 @@ public sealed partial class DockWindow : WindowEx,
private DockViewModel viewModel;
private DockControl _dock;
private DesktopAcrylicController? _acrylicController;
private MicaController? _micaController;
private SystemBackdropConfiguration? _configurationSource;
private bool _isUpdatingBackdrop;
private BackdropParameters? _lastAppliedAcrylicBackdrop;
private MicaKind? _lastAppliedMicaKind;
private DockSize _lastSize;
private bool _isDisposed;
private DockAppBarMode _appBarMode;
@@ -316,7 +318,7 @@ public sealed partial class DockWindow : WindowEx,
private void InitializeBackdropSupport()
{
if (DesktopAcrylicController.IsSupported())
if (DesktopAcrylicController.IsSupported() || MicaController.IsSupported())
{
_configurationSource = new SystemBackdropConfiguration
{
@@ -337,6 +339,16 @@ public sealed partial class DockWindow : WindowEx,
try
{
if (_configurationSource is not null)
{
_configurationSource.Theme = _themeService.CurrentDockTheme.Theme switch
{
ElementTheme.Light => SystemBackdropTheme.Light,
ElementTheme.Dark => SystemBackdropTheme.Dark,
_ => SystemBackdropTheme.Default,
};
}
switch (_settings.Backdrop)
{
case DockBackdrop.Transparent:
@@ -348,6 +360,14 @@ public sealed partial class DockWindow : WindowEx,
break;
case DockBackdrop.Mica:
SetupMica(MicaKind.Base);
break;
case DockBackdrop.MicaAlt:
SetupMica(MicaKind.BaseAlt);
break;
case DockBackdrop.Acrylic:
default:
SetupDesktopAcrylic(_themeService.CurrentDockTheme.BackdropParameters);
@@ -376,6 +396,15 @@ public sealed partial class DockWindow : WindowEx,
private void CleanupBackdropControllers()
{
if (_micaController is not null)
{
_micaController.RemoveAllSystemBackdropTargets();
_micaController.Dispose();
_micaController = null;
}
_lastAppliedMicaKind = null;
if (_acrylicController is not null)
{
_acrylicController.RemoveAllSystemBackdropTargets();
@@ -422,7 +451,29 @@ public sealed partial class DockWindow : WindowEx,
_lastAppliedAcrylicBackdrop = backdrop;
}
private void DisposeAcrylic()
private void SetupMica(MicaKind kind)
{
if (_configurationSource is null || !MicaController.IsSupported())
{
// Try Acrylic before the transparent fallback on systems without Mica support.
SetupDesktopAcrylic(_themeService.CurrentDockTheme.BackdropParameters);
return;
}
if (_micaController is not null && _lastAppliedMicaKind == kind)
{
return;
}
CleanupBackdropControllers();
SystemBackdrop = null;
_micaController = new MicaController { Kind = kind };
_micaController.AddSystemBackdropTarget(this.As<ICompositionSupportsSystemBackdrop>());
_micaController.SetSystemBackdropConfiguration(_configurationSource);
_lastAppliedMicaKind = kind;
}
private void DisposeBackdrop()
{
CleanupBackdropControllers();
_configurationSource = null;
@@ -1841,7 +1892,7 @@ public sealed partial class DockWindow : WindowEx,
WeakReferenceMessenger.Default.UnregisterAll(this);
StopCollapseTimer();
DisposeAcrylic();
DisposeBackdrop();
_dock.Dispose();
_windowViewModel.Dispose();
@@ -151,7 +151,8 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
// Compute DockThemeSnapshot from DockSettings
var dockSettings = _settingsService.Settings.DockSettings;
var dockIntensity = Math.Clamp(dockSettings.CustomThemeColorIntensity, 0, 100);
var isMicaDock = dockSettings.Backdrop is DockBackdrop.Mica or DockBackdrop.MicaAlt;
var dockIntensity = isMicaDock ? 0 : Math.Clamp(dockSettings.CustomThemeColorIntensity, 0, 100);
IThemeProvider dockProvider = dockIntensity > 0 && dockSettings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor or ColorizationMode.Image
? _colorfulThemeProvider
: _normalThemeProvider;
@@ -164,7 +165,7 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
_ => Colors.Transparent,
};
var dockEffectiveTheme = GetElementTheme((ElementTheme)dockSettings.Theme);
var dockImageSource = dockSettings.ColorizationMode == ColorizationMode.Image
var dockImageSource = !isMicaDock && dockSettings.ColorizationMode == ColorizationMode.Image
? LoadImageSafe(dockSettings.BackgroundImagePath)
: null;
var dockStretch = dockSettings.BackgroundImageFit switch
@@ -176,6 +177,8 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
var dockContext = new ThemeContext
{
// Mica uses system defaults; keep Acrylic parameters ready for its fallback.
BackdropStyle = BackdropStyle.Acrylic,
Tint = dockTint,
ColorIntensity = dockIntensity,
Theme = dockEffectiveTheme,
@@ -174,7 +174,7 @@
</controls:SettingsCard>
<!-- Backdrop Style -->
<controls:SettingsCard
<controls:SettingsExpander
x:Uid="DockAppearance_Backdrop_SettingsCard"
HeaderIcon="{ui:FontIcon Glyph=&#xF5EF;}"
local:SettingsPageTarget.Id="backdrop">
@@ -184,13 +184,32 @@
SelectedIndex="{x:Bind ViewModel.DockAppearance.BackdropIndex, Mode=TwoWay}">
<ComboBoxItem x:Uid="DockAppearance_Backdrop_Transparent" />
<ComboBoxItem x:Uid="DockAppearance_Backdrop_Acrylic" />
<ComboBoxItem x:Uid="Settings_GeneralPage_BackdropStyle_Mica" />
<ComboBoxItem x:Uid="Settings_GeneralPage_BackdropStyle_MicaAlt" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsExpander.Items>
<controls:SettingsCard
x:Uid="Settings_GeneralPage_MicaBackdrop_SettingsCard"
HorizontalContentAlignment="Stretch"
ContentAlignment="Vertical"
Visibility="{x:Bind ViewModel.DockAppearance.IsMicaBackdrop, Mode=OneWay}">
<TextBlock
x:Uid="Settings_GeneralPage_MicaBackdrop_DescriptionTextBlock"
Margin="24"
HorizontalAlignment="Stretch"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
HorizontalTextAlignment="Center"
TextAlignment="Center"
TextWrapping="WrapWholeWords" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- Background / Colorization Section -->
<controls:SettingsExpander
x:Uid="DockAppearance_Background_SettingsExpander"
HeaderIcon="{ui:FontIcon Glyph=&#xE790;}"
IsEnabled="{x:Bind ViewModel.DockAppearance.SupportsColorization, Mode=OneWay}"
IsExpanded="{x:Bind ViewModel.DockAppearance.IsColorizationDetailsExpanded, Mode=TwoWay}"
local:SettingsPageTarget.Id="background">
<ComboBox
@@ -246,6 +246,8 @@ public sealed partial class DockSettingsPage : Page, IDisposable
{
DockBackdrop.Transparent => 0,
DockBackdrop.Acrylic => 1,
DockBackdrop.Mica => 2,
DockBackdrop.MicaAlt => 3,
_ => 1,
};
@@ -253,6 +255,8 @@ public sealed partial class DockSettingsPage : Page, IDisposable
{
0 => DockBackdrop.Transparent,
1 => DockBackdrop.Acrylic,
2 => DockBackdrop.Mica,
3 => DockBackdrop.MicaAlt,
_ => DockBackdrop.Acrylic,
};
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using Microsoft.CmdPal.UI.ViewModels.Settings;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.CmdPal.UI.ViewModels.UnitTests;
[TestClass]
public class DockMaterialPersistenceTests
{
[TestMethod]
[DataRow(DockBackdrop.Transparent, "Transparent")]
[DataRow(DockBackdrop.Acrylic, "Acrylic")]
[DataRow(DockBackdrop.Mica, "Mica")]
[DataRow(DockBackdrop.MicaAlt, "MicaAlt")]
public void SaveAndReload_PreservesDockMaterialIndependentlyOfPalette(DockBackdrop material, string persistedName)
{
var settings = new SettingsModel
{
BackdropStyle = BackdropStyle.MicaAlt,
DockSettings = new DockSettings { Backdrop = material },
};
var json = JsonSerializer.Serialize(settings, JsonSerializationContext.Default.SettingsModel);
using var document = JsonDocument.Parse(json);
Assert.AreEqual(persistedName, document.RootElement.GetProperty("DockSettings").GetProperty("Backdrop").GetString());
var reloaded = JsonSerializer.Deserialize(json, JsonSerializationContext.Default.SettingsModel);
Assert.IsNotNull(reloaded);
Assert.AreEqual(material, reloaded.DockSettings.Backdrop);
Assert.AreEqual(BackdropStyle.MicaAlt, reloaded.BackdropStyle, "Changing the Dock material must not change the palette material.");
}
}