Skip to content
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
34 changes: 25 additions & 9 deletions config/tweaks.json
Original file line number Diff line number Diff line change
Expand Up @@ -1459,28 +1459,44 @@
],
"link": "https://winutil.christitus.com/code-reference/tweaks/customize-preferences/scrollbars"
},
"WPFToggleMultiplaneOverlay": {
"WPFMultiplaneOverlay": {
"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",
"panel": "2",
"Type": "Toggle",
"Type": "Combobox",
Comment thread
mewclouds marked this conversation as resolved.
"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."
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"registry": [
{
"Path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\Dwm",
"Name": "OverlayTestMode",
"Value": "0",
"Type": "DWord",
"OriginalValue": "5",
"DefaultState": "true"
"DefaultValue": "0",
"Values": {
"Enabled": "<RemoveEntry>",
"Disabled (Compatibility)": "5",
"Fully Disabled": "5"
}
},
{
"Path": "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers",
"Name": "DisableOverlays",
"Value": "0",
"Type": "DWord",
"OriginalValue": "1",
"DefaultState": "true"
"DefaultValue": "0",
"Values": {
"Enabled": "<RemoveEntry>",
"Disabled (Compatibility)": "<RemoveEntry>",
"Fully Disabled": "1"
}
}
],
"link": "https://winutil.christitus.com/code-reference/tweaks/customize-preferences/multiplaneoverlay"
Expand Down
2 changes: 2 additions & 0 deletions docs/src/content/docs/code-reference/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ Update UI
- `Description`: What it does
- `category`: Essential/Advanced/Customize
- `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
- `OriginalValue/State`: For undo functionality

Expand Down
36 changes: 36 additions & 0 deletions functions/private/Get-WinUtilRegistryComboState.ps1
Original file line number Diff line number Diff line change
@@ -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."
}
24 changes: 24 additions & 0 deletions functions/private/Get-WinUtilRegistryComboValue.ps1
Original file line number Diff line number Diff line change
@@ -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 }
}
}
2 changes: 1 addition & 1 deletion functions/private/Invoke-WinUtilCurrentSystem.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Function Invoke-WinUtilCurrentSystem {
$serviceKeys = $entry.service
$entryType = $entry.Type

if ($registryKeys -or $serviceKeys) {
if (($registryKeys -or $serviceKeys) -and $entryType -ne "Combobox") {
$Values = @()

if ($entryType -eq "Toggle") {
Expand Down
2 changes: 1 addition & 1 deletion functions/private/Invoke-WinUtilTweaks.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function Invoke-WinUtilTweaks {
}
}
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)
}
}
Expand Down
78 changes: 78 additions & 0 deletions functions/private/Set-WinUtilRegistryComboState.ps1
Original file line number Diff line number Diff line change
@@ -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"
}
}
87 changes: 83 additions & 4 deletions functions/public/Invoke-WPFUIElements.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ function Invoke-WPFUIElements {
Description = $entryInfo.description
Type = $entryInfo.type
ComboItems = $entryInfo.ComboItems
ComboDescriptions = $entryInfo.ComboDescriptions
Registry = $entryInfo.registry
Checked = $entryInfo.Checked
ButtonWidth = $entryInfo.ButtonWidth
GroupName = $entryInfo.GroupName # Added for RadioButton groupings
Expand Down Expand Up @@ -247,6 +249,7 @@ function Invoke-WPFUIElements {
$label = New-Object Windows.Controls.Label
$label.Content = $entryInfo.Content
$label.HorizontalAlignment = "Left"
$label.ToolTip = $entryInfo.Description
$label.VerticalAlignment = "Center"
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$label.UseLayoutRounding = $true
Expand All @@ -261,11 +264,27 @@ function Invoke-WPFUIElements {
$comboBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "ButtonMargin")
$comboBox.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$comboBox.UseLayoutRounding = $true
$comboBox.Tag = [pscustomobject]@{
Registry = $entryInfo.Registry
State = $null
}
[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.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.UseLayoutRounding = $true
$comboBox.Items.Add($comboBoxItem) | Out-Null
Expand All @@ -274,22 +293,82 @@ function Invoke-WPFUIElements {
$horizontalStackPanel.Children.Add($comboBox) | 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
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
$comboBox.Add_SelectionChanged({
$selectedItem = $this.SelectedItem
if ($selectedItem) {
$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" {
Expand Down
Loading