mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-10 10:01:16 +10:00
Make MPO tweak a three-state control (#4897)
* refactor: make MPO tweak a three-state control * docs: explain MPO tweak states * docs: address code review comments * refactor: make Multiplane Overlay config-driven
This commit is contained in:
+25
-9
@@ -1459,28 +1459,44 @@
|
|||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/code-reference/tweaks/customize-preferences/scrollbars"
|
"link": "https://winutil.christitus.com/code-reference/tweaks/customize-preferences/scrollbars"
|
||||||
},
|
},
|
||||||
"WPFToggleMultiplaneOverlay": {
|
"WPFMultiplaneOverlay": {
|
||||||
"Content": "Multiplane Overlay",
|
"Content": "Multiplane Overlay",
|
||||||
"Description": "Multiplane Overlay compose multiple image layers, which can sometimes cause issues with graphics cards.",
|
"Description": "Multiplane Overlay composes multiple image layers, which can sometimes cause issues with graphics cards. Changes to this preference are applied immediately.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Combobox",
|
||||||
|
"ComboItems": [
|
||||||
|
"Enabled",
|
||||||
|
"Disabled (Compatibility)",
|
||||||
|
"Fully Disabled"
|
||||||
|
],
|
||||||
|
"ComboDescriptions": {
|
||||||
|
"Enabled": "Uses Windows' default overlay behavior.",
|
||||||
|
"Disabled (Compatibility)": "Disables MPO using OverlayTestMode=5, the less aggressive compatibility method.",
|
||||||
|
"Fully Disabled": "Disables MPO using OverlayTestMode=5 and DisableOverlays=1, the more aggressive method."
|
||||||
|
},
|
||||||
"registry": [
|
"registry": [
|
||||||
{
|
{
|
||||||
"Path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\Dwm",
|
"Path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\Dwm",
|
||||||
"Name": "OverlayTestMode",
|
"Name": "OverlayTestMode",
|
||||||
"Value": "0",
|
|
||||||
"Type": "DWord",
|
"Type": "DWord",
|
||||||
"OriginalValue": "5",
|
"DefaultValue": "0",
|
||||||
"DefaultState": "true"
|
"Values": {
|
||||||
|
"Enabled": "<RemoveEntry>",
|
||||||
|
"Disabled (Compatibility)": "5",
|
||||||
|
"Fully Disabled": "5"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Path": "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers",
|
"Path": "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers",
|
||||||
"Name": "DisableOverlays",
|
"Name": "DisableOverlays",
|
||||||
"Value": "0",
|
|
||||||
"Type": "DWord",
|
"Type": "DWord",
|
||||||
"OriginalValue": "1",
|
"DefaultValue": "0",
|
||||||
"DefaultState": "true"
|
"Values": {
|
||||||
|
"Enabled": "<RemoveEntry>",
|
||||||
|
"Disabled (Compatibility)": "<RemoveEntry>",
|
||||||
|
"Fully Disabled": "1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/code-reference/tweaks/customize-preferences/multiplaneoverlay"
|
"link": "https://winutil.christitus.com/code-reference/tweaks/customize-preferences/multiplaneoverlay"
|
||||||
|
|||||||
@@ -385,6 +385,8 @@ Update UI
|
|||||||
- `Description`: What it does
|
- `Description`: What it does
|
||||||
- `category`: Essential/Advanced/Customize
|
- `category`: Essential/Advanced/Customize
|
||||||
- `registry`: Registry changes to make
|
- `registry`: Registry changes to make
|
||||||
|
- `registry[].Values`: Per-state values for a registry-backed combobox
|
||||||
|
- `registry[].DefaultValue`: Effective value when the registry entry is absent
|
||||||
- `service`: Services to change
|
- `service`: Services to change
|
||||||
- `OriginalValue/State`: For undo functionality
|
- `OriginalValue/State`: For undo functionality
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
function Get-WinUtilRegistryComboState {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Finds the configured combo-box state matching the current registry values.
|
||||||
|
|
||||||
|
.PARAMETER Registry
|
||||||
|
Registry settings containing a value mapping for each supported state.
|
||||||
|
|
||||||
|
.OUTPUTS
|
||||||
|
The name of the matching state.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
$Registry
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($state in $Registry[0].Values.PSObject.Properties) {
|
||||||
|
$stateMatches = $true
|
||||||
|
foreach ($setting in @($Registry)) {
|
||||||
|
$currentValue = Get-WinUtilRegistryComboValue -Setting $setting
|
||||||
|
$actualValue = if ($currentValue.Exists -and $null -ne $currentValue.Value) { $currentValue.Value } else { $setting.DefaultValue }
|
||||||
|
$configuredValue = $setting.Values.PSObject.Properties[$state.Name].Value
|
||||||
|
# Removal represents the effective Windows default when matching the current state.
|
||||||
|
$expectedValue = if ($configuredValue -eq "<RemoveEntry>") { $setting.DefaultValue } else { $configuredValue }
|
||||||
|
if ([string]$actualValue -ne [string]$expectedValue) {
|
||||||
|
$stateMatches = $false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($stateMatches) {
|
||||||
|
return $state.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Registry values do not match a supported state."
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
function Get-WinUtilRegistryComboValue {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Reads one registry value for a registry-backed combo-box state.
|
||||||
|
|
||||||
|
.PARAMETER Setting
|
||||||
|
The registry setting from the combo-box configuration.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
$Setting
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$item = Get-ItemProperty -Path $Setting.Path -Name $Setting.Name -ErrorAction Stop
|
||||||
|
$property = $item.PSObject.Properties[$Setting.Name]
|
||||||
|
return [pscustomobject]@{ Exists = $null -ne $property; Value = $property.Value }
|
||||||
|
} catch [System.Management.Automation.PSArgumentException] {
|
||||||
|
# The registry provider uses PSArgumentException when a named value is absent.
|
||||||
|
return [pscustomobject]@{ Exists = $false; Value = $null }
|
||||||
|
} catch [System.Management.Automation.ItemNotFoundException] {
|
||||||
|
return [pscustomobject]@{ Exists = $false; Value = $null }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ Function Invoke-WinUtilCurrentSystem {
|
|||||||
$serviceKeys = $entry.service
|
$serviceKeys = $entry.service
|
||||||
$entryType = $entry.Type
|
$entryType = $entry.Type
|
||||||
|
|
||||||
if ($registryKeys -or $serviceKeys) {
|
if (($registryKeys -or $serviceKeys) -and $entryType -ne "Combobox") {
|
||||||
$Values = @()
|
$Values = @()
|
||||||
|
|
||||||
if ($entryType -eq "Toggle") {
|
if ($entryType -eq "Toggle") {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ function Invoke-WinUtilTweaks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($sync.configs.tweaks.$CheckBox.registry) {
|
if ($sync.configs.tweaks.$CheckBox.registry) {
|
||||||
$sync.configs.tweaks.$CheckBox.registry | ForEach-Object {
|
$sync.configs.tweaks.$CheckBox.registry | Where-Object { -not $psitem.Values } | ForEach-Object {
|
||||||
Set-WinUtilRegistry -Name $psitem.Name -Path $psitem.Path -Type $psitem.Type -Value $psitem.$($values.registry)
|
Set-WinUtilRegistry -Name $psitem.Name -Path $psitem.Path -Type $psitem.Type -Value $psitem.$($values.registry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
function Set-WinUtilRegistryComboState {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Applies and verifies a config-defined registry combo-box state.
|
||||||
|
|
||||||
|
.PARAMETER Registry
|
||||||
|
Registry settings containing a value mapping for each supported state.
|
||||||
|
|
||||||
|
.PARAMETER State
|
||||||
|
The state name to apply.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
$Registry,
|
||||||
|
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string]$State
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($Registry[0].Values.PSObject.Properties.Name -notcontains $State) {
|
||||||
|
throw "Unknown registry state '$State'."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Preserve exact prior values so a partial update can be rolled back.
|
||||||
|
$previousValues = foreach ($setting in @($Registry)) {
|
||||||
|
$currentValue = Get-WinUtilRegistryComboValue -Setting $setting
|
||||||
|
[pscustomobject]@{ Setting = $setting; Exists = $currentValue.Exists; Value = $currentValue.Value }
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
foreach ($setting in @($Registry)) {
|
||||||
|
$configuredValue = $setting.Values.PSObject.Properties[$State].Value
|
||||||
|
$previousValue = $previousValues | Where-Object Setting -EQ $setting
|
||||||
|
if ($configuredValue -ne "<RemoveEntry>" -or $previousValue.Exists) {
|
||||||
|
Set-WinUtilRegistry -Name $setting.Name -Path $setting.Path -Type $setting.Type -Value $configuredValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set-WinUtilRegistry reports write errors without throwing, so verify each result explicitly.
|
||||||
|
foreach ($setting in @($Registry)) {
|
||||||
|
$configuredValue = $setting.Values.PSObject.Properties[$State].Value
|
||||||
|
$currentValue = Get-WinUtilRegistryComboValue -Setting $setting
|
||||||
|
$writeMatches = if ($configuredValue -eq "<RemoveEntry>") {
|
||||||
|
-not $currentValue.Exists
|
||||||
|
} else {
|
||||||
|
$currentValue.Exists -and [string]$currentValue.Value -eq [string]$configuredValue
|
||||||
|
}
|
||||||
|
if (-not $writeMatches) {
|
||||||
|
throw "The registry values did not match the requested state."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
$applyError = $_.Exception.Message
|
||||||
|
if ([string]::IsNullOrWhiteSpace($applyError)) {
|
||||||
|
$applyError = "The registry values did not match the requested state."
|
||||||
|
}
|
||||||
|
$rollbackFailed = $false
|
||||||
|
foreach ($previousValue in $previousValues) {
|
||||||
|
try {
|
||||||
|
$currentValue = Get-WinUtilRegistryComboValue -Setting $previousValue.Setting
|
||||||
|
if ($previousValue.Exists -or $currentValue.Exists) {
|
||||||
|
$rollbackValue = if ($previousValue.Exists) { $previousValue.Value } else { "<RemoveEntry>" }
|
||||||
|
Set-WinUtilRegistry -Name $previousValue.Setting.Name -Path $previousValue.Setting.Path -Type $previousValue.Setting.Type -Value $rollbackValue
|
||||||
|
}
|
||||||
|
$restoredValue = Get-WinUtilRegistryComboValue -Setting $previousValue.Setting
|
||||||
|
if ($restoredValue.Exists -ne $previousValue.Exists -or ($restoredValue.Exists -and [string]$restoredValue.Value -ne [string]$previousValue.Value)) {
|
||||||
|
$rollbackFailed = $true
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
$rollbackFailed = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($rollbackFailed) {
|
||||||
|
throw "Unable to apply registry state '$State': $applyError. The previous registry state could not be restored."
|
||||||
|
}
|
||||||
|
throw "Unable to apply registry state '$State': $applyError"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -76,6 +76,8 @@ function Invoke-WPFUIElements {
|
|||||||
Description = $entryInfo.description
|
Description = $entryInfo.description
|
||||||
Type = $entryInfo.type
|
Type = $entryInfo.type
|
||||||
ComboItems = $entryInfo.ComboItems
|
ComboItems = $entryInfo.ComboItems
|
||||||
|
ComboDescriptions = $entryInfo.ComboDescriptions
|
||||||
|
Registry = $entryInfo.registry
|
||||||
Checked = $entryInfo.Checked
|
Checked = $entryInfo.Checked
|
||||||
ButtonWidth = $entryInfo.ButtonWidth
|
ButtonWidth = $entryInfo.ButtonWidth
|
||||||
GroupName = $entryInfo.GroupName # Added for RadioButton groupings
|
GroupName = $entryInfo.GroupName # Added for RadioButton groupings
|
||||||
@@ -247,6 +249,7 @@ function Invoke-WPFUIElements {
|
|||||||
$label = New-Object Windows.Controls.Label
|
$label = New-Object Windows.Controls.Label
|
||||||
$label.Content = $entryInfo.Content
|
$label.Content = $entryInfo.Content
|
||||||
$label.HorizontalAlignment = "Left"
|
$label.HorizontalAlignment = "Left"
|
||||||
|
$label.ToolTip = $entryInfo.Description
|
||||||
$label.VerticalAlignment = "Center"
|
$label.VerticalAlignment = "Center"
|
||||||
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
|
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
|
||||||
$label.UseLayoutRounding = $true
|
$label.UseLayoutRounding = $true
|
||||||
@@ -261,11 +264,27 @@ function Invoke-WPFUIElements {
|
|||||||
$comboBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "ButtonMargin")
|
$comboBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "ButtonMargin")
|
||||||
$comboBox.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
|
$comboBox.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
|
||||||
$comboBox.UseLayoutRounding = $true
|
$comboBox.UseLayoutRounding = $true
|
||||||
|
$comboBox.Tag = [pscustomobject]@{
|
||||||
|
Registry = $entryInfo.Registry
|
||||||
|
State = $null
|
||||||
|
}
|
||||||
[System.Windows.Automation.AutomationProperties]::SetName($comboBox, $entryInfo.Content)
|
[System.Windows.Automation.AutomationProperties]::SetName($comboBox, $entryInfo.Content)
|
||||||
|
|
||||||
foreach ($comboitem in ($entryInfo.ComboItems -split " ")) {
|
$comboItems = if ($entryInfo.ComboItems -is [string]) {
|
||||||
|
$entryInfo.ComboItems -split " "
|
||||||
|
} else {
|
||||||
|
@($entryInfo.ComboItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($comboitem in $comboItems) {
|
||||||
$comboBoxItem = New-Object Windows.Controls.ComboBoxItem
|
$comboBoxItem = New-Object Windows.Controls.ComboBoxItem
|
||||||
$comboBoxItem.Content = $comboitem
|
$comboBoxItem.Content = $comboitem
|
||||||
|
if ($entryInfo.ComboDescriptions) {
|
||||||
|
$comboDescription = $entryInfo.ComboDescriptions.PSObject.Properties[$comboitem].Value
|
||||||
|
if ($comboDescription) {
|
||||||
|
$comboBoxItem.ToolTip = $comboDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
$comboBoxItem.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
|
$comboBoxItem.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
|
||||||
$comboBoxItem.UseLayoutRounding = $true
|
$comboBoxItem.UseLayoutRounding = $true
|
||||||
$comboBox.Items.Add($comboBoxItem) | Out-Null
|
$comboBox.Items.Add($comboBoxItem) | Out-Null
|
||||||
@@ -274,22 +293,82 @@ function Invoke-WPFUIElements {
|
|||||||
$horizontalStackPanel.Children.Add($comboBox) | Out-Null
|
$horizontalStackPanel.Children.Add($comboBox) | Out-Null
|
||||||
$itemsControl.Items.Add($horizontalStackPanel) | Out-Null
|
$itemsControl.Items.Add($horizontalStackPanel) | Out-Null
|
||||||
|
|
||||||
$comboBox.SelectedIndex = 0
|
if ($entryInfo.Registry -and @($entryInfo.Registry)[0].Values) {
|
||||||
|
try {
|
||||||
|
$comboBox.Tag.State = Get-WinUtilRegistryComboState -Registry $entryInfo.Registry
|
||||||
|
$comboBox.SelectedIndex = @($comboBox.Items.Content).IndexOf([string]$comboBox.Tag.State)
|
||||||
|
} catch {
|
||||||
|
$unknownStateItem = New-Object Windows.Controls.ComboBoxItem
|
||||||
|
$unknownStateItem.Content = "Custom / Unknown - select a state"
|
||||||
|
$unknownStateItem.IsEnabled = $false
|
||||||
|
$unknownStateItem.ToolTip = "$($_.Exception.Message) Select one of the supported states to replace these values."
|
||||||
|
$comboBox.Items.Add($unknownStateItem) | Out-Null
|
||||||
|
$comboBox.SelectedItem = $unknownStateItem
|
||||||
|
$comboBox.ToolTip = $unknownStateItem.ToolTip
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$comboBox.SelectedIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
# Set initial text
|
# Set initial text
|
||||||
if ($comboBox.Items.Count -gt 0) {
|
if ($comboBox.Items.Count -gt 0) {
|
||||||
$comboBox.Text = $comboBox.Items[0].Content
|
$comboBox.Text = $comboBox.SelectedItem.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sync[$entryInfo.Name] = $comboBox
|
||||||
|
|
||||||
# Add SelectionChanged event handler to update the text property
|
# Add SelectionChanged event handler to update the text property
|
||||||
$comboBox.Add_SelectionChanged({
|
$comboBox.Add_SelectionChanged({
|
||||||
$selectedItem = $this.SelectedItem
|
$selectedItem = $this.SelectedItem
|
||||||
if ($selectedItem) {
|
if ($selectedItem) {
|
||||||
$this.Text = $selectedItem.Content
|
$this.Text = $selectedItem.Content
|
||||||
|
$registry = $this.Tag.Registry
|
||||||
|
if ($registry -and $selectedItem.IsEnabled -and $selectedItem.Content -ne $this.Tag.State) {
|
||||||
|
try {
|
||||||
|
Set-WinUtilRegistryComboState -Registry $registry -State $selectedItem.Content
|
||||||
|
$this.Tag.State = $selectedItem.Content
|
||||||
|
$this.ToolTip = $null
|
||||||
|
$unknownStateItem = @($this.Items) | Where-Object Content -EQ "Custom / Unknown - select a state" | Select-Object -First 1
|
||||||
|
if ($unknownStateItem) {
|
||||||
|
$this.Items.Remove($unknownStateItem)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
$applyError = $_.Exception.Message
|
||||||
|
if ([string]::IsNullOrWhiteSpace($applyError)) {
|
||||||
|
$applyError = "Unable to apply registry state '$($selectedItem.Content)'."
|
||||||
|
}
|
||||||
|
$previousState = if ($this.Tag.State) { $this.Tag.State } else { "Custom / Unknown - select a state" }
|
||||||
|
$this.SelectedItem = @($this.Items) | Where-Object Content -EQ $previousState | Select-Object -First 1
|
||||||
|
[System.Windows.MessageBox]::Show(
|
||||||
|
$applyError,
|
||||||
|
"WinUtil",
|
||||||
|
[System.Windows.MessageBoxButton]::OK,
|
||||||
|
[System.Windows.MessageBoxImage]::Warning
|
||||||
|
) | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
$sync[$entryInfo.Name] = $comboBox
|
if ($entryInfo.Registry -and @($entryInfo.Registry)[0].Values -and $entryInfo.Link) {
|
||||||
|
$textBlock = New-Object Windows.Controls.TextBlock
|
||||||
|
$textBlock.Name = $comboBox.Name + "Link"
|
||||||
|
$textBlock.Text = "(?)"
|
||||||
|
$textBlock.ToolTip = $entryInfo.Link
|
||||||
|
$textBlock.Style = $HoverTextBlockStyle
|
||||||
|
$textBlock.UseLayoutRounding = $true
|
||||||
|
$textBlock.VerticalAlignment = "Center"
|
||||||
|
$textBlock.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSize")
|
||||||
|
$textBlock.Tag = $comboBox
|
||||||
|
|
||||||
|
$textBlock.Add_MouseUp({
|
||||||
|
[System.Object]$Sender = $args[0]
|
||||||
|
Start-Process $Sender.ToolTip -ErrorAction Stop
|
||||||
|
})
|
||||||
|
|
||||||
|
$horizontalStackPanel.Children.Add($textBlock) | Out-Null
|
||||||
|
$sync[$textBlock.Name] = $textBlock
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"Button" {
|
"Button" {
|
||||||
|
|||||||
@@ -189,6 +189,14 @@ Describe "Tweaks config" {
|
|||||||
foreach ($registryEntry in @($tweak.Value.registry)) {
|
foreach ($registryEntry in @($tweak.Value.registry)) {
|
||||||
if ($null -eq $registryEntry) { continue }
|
if ($null -eq $registryEntry) { continue }
|
||||||
|
|
||||||
|
if ($registryEntry.Values) {
|
||||||
|
if ($registryEntry.PSObject.Properties.Name -notcontains "DefaultValue" -or
|
||||||
|
[string]::IsNullOrWhiteSpace([string]$registryEntry.DefaultValue)) {
|
||||||
|
$invalidTweaks.Add("$($tweak.Name),registry")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if ($registryEntry.PSObject.Properties.Name -notcontains "OriginalValue" -or
|
if ($registryEntry.PSObject.Properties.Name -notcontains "OriginalValue" -or
|
||||||
[string]::IsNullOrWhiteSpace([string]$registryEntry.OriginalValue)) {
|
[string]::IsNullOrWhiteSpace([string]$registryEntry.OriginalValue)) {
|
||||||
$invalidTweaks.Add("$($tweak.Name),registry")
|
$invalidTweaks.Add("$($tweak.Name),registry")
|
||||||
@@ -429,6 +437,19 @@ Describe "UI-rendered config entries" {
|
|||||||
if (-not (Test-WinUtilHasNonEmptyProperty -Object $entry.Value -Name "ComboItems")) {
|
if (-not (Test-WinUtilHasNonEmptyProperty -Object $entry.Value -Name "ComboItems")) {
|
||||||
$invalidEntries.Add("$($entry.Name) combobox missing ComboItems")
|
$invalidEntries.Add("$($entry.Name) combobox missing ComboItems")
|
||||||
}
|
}
|
||||||
|
$statefulRegistry = @($entry.Value.registry | Where-Object Values)
|
||||||
|
if ($statefulRegistry.Count -gt 0) {
|
||||||
|
$comboItems = @($entry.Value.ComboItems)
|
||||||
|
if ($statefulRegistry.Count -ne @($entry.Value.registry).Count) {
|
||||||
|
$invalidEntries.Add("$($entry.Name) registry states must all use Values")
|
||||||
|
} else {
|
||||||
|
foreach ($setting in $statefulRegistry) {
|
||||||
|
if (Compare-Object $comboItems @($setting.Values.PSObject.Properties.Name)) {
|
||||||
|
$invalidEntries.Add("$($entry.Name) ComboItems and registry states do not match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (-not (Test-WinUtilHasNonEmptyProperty -Object $entry.Value -Name "Description")) {
|
if (-not (Test-WinUtilHasNonEmptyProperty -Object $entry.Value -Name "Description")) {
|
||||||
$invalidEntries.Add("$($entry.Name) missing Description")
|
$invalidEntries.Add("$($entry.Name) missing Description")
|
||||||
@@ -442,7 +463,12 @@ Describe "UI-rendered config entries" {
|
|||||||
foreach ($registryEntry in @($entry.Value.registry)) {
|
foreach ($registryEntry in @($entry.Value.registry)) {
|
||||||
if ($null -eq $registryEntry) { continue }
|
if ($null -eq $registryEntry) { continue }
|
||||||
|
|
||||||
foreach ($missingField in (Get-WinUtilMissingRequiredFields -EntryName "$($entry.Name),registry" -Entry $registryEntry -RequiredFields @("Path", "Name", "Type", "Value", "OriginalValue"))) {
|
$requiredRegistryFields = if ($entry.Value.Type -eq "Combobox" -and $statefulRegistry.Count -gt 0) {
|
||||||
|
@("Path", "Name", "Type", "DefaultValue", "Values")
|
||||||
|
} else {
|
||||||
|
@("Path", "Name", "Type", "Value", "OriginalValue")
|
||||||
|
}
|
||||||
|
foreach ($missingField in (Get-WinUtilMissingRequiredFields -EntryName "$($entry.Name),registry" -Entry $registryEntry -RequiredFields $requiredRegistryFields)) {
|
||||||
$invalidEntries.Add($missingField)
|
$invalidEntries.Add($missingField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,178 @@
|
|||||||
|
#===========================================================================
|
||||||
|
# Tests - Multiplane Overlay
|
||||||
|
#===========================================================================
|
||||||
|
|
||||||
|
BeforeAll {
|
||||||
|
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||||
|
$script:config = Get-Content (Join-Path $script:repoRoot "config\tweaks.json") -Raw | ConvertFrom-Json
|
||||||
|
$script:states = $script:config.WPFMultiplaneOverlay.registry
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Get-WinUtilRegistryComboState.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Get-WinUtilRegistryComboValue.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilRegistryComboState.ps1")
|
||||||
|
|
||||||
|
function Set-WinUtilRegistry {
|
||||||
|
param($Name, $Path, $Type, $Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Multiplane Overlay configuration" {
|
||||||
|
It "keeps every state and registry action in tweaks.json" {
|
||||||
|
$script:config.WPFMultiplaneOverlay.Type | Should -Be "Combobox"
|
||||||
|
$script:config.WPFMultiplaneOverlay.ComboItems | Should -Be @("Enabled", "Disabled (Compatibility)", "Fully Disabled")
|
||||||
|
$script:states.Count | Should -Be 2
|
||||||
|
$script:states[0].Values.PSObject.Properties.Name | Should -Be $script:config.WPFMultiplaneOverlay.ComboItems
|
||||||
|
$script:states[0].Values.PSObject.Properties.Value | Should -Be @("<RemoveEntry>", "5", "5")
|
||||||
|
$script:states[1].Values.PSObject.Properties.Value | Should -Be @("<RemoveEntry>", "<RemoveEntry>", "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
It "uses the generic combo registry handler" {
|
||||||
|
$renderer = Get-Content (Join-Path $script:repoRoot "functions\public\Invoke-WPFUIElements.ps1") -Raw
|
||||||
|
|
||||||
|
$renderer | Should -Match 'Get-WinUtilRegistryComboState'
|
||||||
|
$renderer | Should -Match 'Set-WinUtilRegistryComboState'
|
||||||
|
$renderer | Should -Not -Match 'WPFMultiplaneOverlay'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-WinUtilRegistryComboState" {
|
||||||
|
It "treats missing registry properties and paths as absent" -TestCases @(
|
||||||
|
@{ Exception = [System.Management.Automation.PSArgumentException]::new("Property is missing") }
|
||||||
|
@{ Exception = [System.Management.Automation.ItemNotFoundException]::new("Path is missing") }
|
||||||
|
) {
|
||||||
|
param($Exception)
|
||||||
|
Mock Get-ItemProperty { throw $Exception }
|
||||||
|
|
||||||
|
Get-WinUtilRegistryComboState -Registry $script:states | Should -Be "Enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "reports Enabled when the values are absent or zero" -TestCases @(
|
||||||
|
@{ OverlayTestMode = $null; DisableOverlays = $null }
|
||||||
|
@{ OverlayTestMode = 0; DisableOverlays = 0 }
|
||||||
|
) {
|
||||||
|
param($OverlayTestMode, $DisableOverlays)
|
||||||
|
Mock Get-ItemProperty {
|
||||||
|
if ($Name -eq "OverlayTestMode") {
|
||||||
|
return [pscustomobject]@{ OverlayTestMode = $OverlayTestMode }
|
||||||
|
}
|
||||||
|
[pscustomobject]@{ DisableOverlays = $DisableOverlays }
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-WinUtilRegistryComboState -Registry $script:states | Should -Be "Enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "reports each disabled state" -TestCases @(
|
||||||
|
@{ OverlayTestMode = 5; DisableOverlays = $null; Expected = "Disabled (Compatibility)" }
|
||||||
|
@{ OverlayTestMode = 5; DisableOverlays = 1; Expected = "Fully Disabled" }
|
||||||
|
) {
|
||||||
|
param($OverlayTestMode, $DisableOverlays, $Expected)
|
||||||
|
Mock Get-ItemProperty {
|
||||||
|
if ($Name -eq "OverlayTestMode") {
|
||||||
|
return [pscustomobject]@{ OverlayTestMode = $OverlayTestMode }
|
||||||
|
}
|
||||||
|
[pscustomobject]@{ DisableOverlays = $DisableOverlays }
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-WinUtilRegistryComboState -Registry $script:states | Should -Be $Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
It "rejects an unsupported combination" {
|
||||||
|
Mock Get-ItemProperty {
|
||||||
|
if ($Name -eq "OverlayTestMode") {
|
||||||
|
return [pscustomobject]@{ OverlayTestMode = 0 }
|
||||||
|
}
|
||||||
|
[pscustomobject]@{ DisableOverlays = 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Get-WinUtilRegistryComboState -Registry $script:states } | Should -Throw "Registry values do not match a supported state."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Set-WinUtilRegistryComboState" {
|
||||||
|
BeforeEach {
|
||||||
|
$script:registryValues = @{ OverlayTestMode = 0; DisableOverlays = 0 }
|
||||||
|
Mock Get-ItemProperty {
|
||||||
|
param($Path, $Name)
|
||||||
|
$registryName = [string]$Name
|
||||||
|
if ($script:registryValues.ContainsKey($registryName)) {
|
||||||
|
$result = [pscustomobject]@{}
|
||||||
|
$result | Add-Member -NotePropertyName $registryName -NotePropertyValue $script:registryValues[$registryName]
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
[pscustomobject]@{}
|
||||||
|
}
|
||||||
|
Mock Set-WinUtilRegistry {
|
||||||
|
param($Name, $Path, $Type, $Value)
|
||||||
|
if ($Value -eq "<RemoveEntry>") {
|
||||||
|
$script:registryValues.Remove($Name)
|
||||||
|
} else {
|
||||||
|
$script:registryValues[$Name] = [int]$Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "applies each configured state" -TestCases @(
|
||||||
|
@{ State = "Enabled"; OverlayTestMode = $null; DisableOverlays = $null }
|
||||||
|
@{ State = "Disabled (Compatibility)"; OverlayTestMode = 5; DisableOverlays = $null }
|
||||||
|
@{ State = "Fully Disabled"; OverlayTestMode = 5; DisableOverlays = 1 }
|
||||||
|
) {
|
||||||
|
param($State, $OverlayTestMode, $DisableOverlays)
|
||||||
|
|
||||||
|
Set-WinUtilRegistryComboState -Registry $script:states -State $State
|
||||||
|
|
||||||
|
$script:registryValues.OverlayTestMode | Should -Be $OverlayTestMode
|
||||||
|
$script:registryValues.DisableOverlays | Should -Be $DisableOverlays
|
||||||
|
}
|
||||||
|
|
||||||
|
It "restores previous values when verification fails" {
|
||||||
|
Mock Set-WinUtilRegistry {
|
||||||
|
param($Name, $Path, $Type, $Value)
|
||||||
|
if ($Name -eq "DisableOverlays" -and $Value -eq 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($Value -eq "<RemoveEntry>") {
|
||||||
|
$script:registryValues.Remove($Name)
|
||||||
|
} else {
|
||||||
|
$script:registryValues[$Name] = [int]$Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Set-WinUtilRegistryComboState -Registry $script:states -State "Fully Disabled" } | Should -Throw "Unable to apply registry state*"
|
||||||
|
$script:registryValues.OverlayTestMode | Should -Be 0
|
||||||
|
$script:registryValues.DisableOverlays | Should -Be 0
|
||||||
|
}
|
||||||
|
|
||||||
|
It "restores absence when a state cannot be applied" {
|
||||||
|
$script:registryValues.Clear()
|
||||||
|
Mock Set-WinUtilRegistry {
|
||||||
|
param($Name, $Path, $Type, $Value)
|
||||||
|
if ($Name -eq "DisableOverlays" -and $Value -eq 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($Value -eq "<RemoveEntry>") {
|
||||||
|
$script:registryValues.Remove($Name)
|
||||||
|
} else {
|
||||||
|
$script:registryValues[$Name] = [int]$Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Set-WinUtilRegistryComboState -Registry $script:states -State "Fully Disabled" } | Should -Throw "Unable to apply registry state*"
|
||||||
|
$script:registryValues.ContainsKey("OverlayTestMode") | Should -BeFalse
|
||||||
|
$script:registryValues.ContainsKey("DisableOverlays") | Should -BeFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
It "reports when the previous values cannot be restored" {
|
||||||
|
Mock Set-WinUtilRegistry {
|
||||||
|
param($Name, $Path, $Type, $Value)
|
||||||
|
if (($Name -eq "DisableOverlays" -and $Value -eq 1) -or ($Name -eq "OverlayTestMode" -and $Value -eq 0)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($Value -eq "<RemoveEntry>") {
|
||||||
|
$script:registryValues.Remove($Name)
|
||||||
|
} else {
|
||||||
|
$script:registryValues[$Name] = [int]$Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Set-WinUtilRegistryComboState -Registry $script:states -State "Fully Disabled" } | Should -Throw "*previous registry state could not be restored*"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -148,7 +148,6 @@ Describe "Set-WinUtilRegistry" {
|
|||||||
$registryPath = "HKLM:\Software\WinUtilTest"
|
$registryPath = "HKLM:\Software\WinUtilTest"
|
||||||
$script:testPathResults["HKU:\"] = $true
|
$script:testPathResults["HKU:\"] = $true
|
||||||
$script:testPathResults[$registryPath] = $true
|
$script:testPathResults[$registryPath] = $true
|
||||||
|
|
||||||
Set-WinUtilRegistry -Path $registryPath -Name "ObsoleteValue" -Type "String" -Value "<RemoveEntry>"
|
Set-WinUtilRegistry -Path $registryPath -Name "ObsoleteValue" -Type "String" -Value "<RemoveEntry>"
|
||||||
|
|
||||||
Should -Invoke -CommandName Set-ItemProperty -Times 0 -Exactly
|
Should -Invoke -CommandName Set-ItemProperty -Times 0 -Exactly
|
||||||
@@ -159,6 +158,7 @@ Describe "Set-WinUtilRegistry" {
|
|||||||
$ErrorAction -eq "Stop"
|
$ErrorAction -eq "Stop"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Describe "Set-WinUtilService" {
|
Describe "Set-WinUtilService" {
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ Describe "Invoke-WinUtilTweaks" {
|
|||||||
$Name -eq "DiagTrack" -and $StartupType -eq "Disabled"
|
$Name -eq "DiagTrack" -and $StartupType -eq "Disabled"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Describe "Invoke-WPFtweaksbutton" {
|
Describe "Invoke-WPFtweaksbutton" {
|
||||||
|
|||||||
Reference in New Issue
Block a user