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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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
11 changes: 4 additions & 7 deletions wv2util/AppState.cs
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wv2util
namespace wv2util
{
public class AppState
{
private static AppOverrideList s_AppOverrideList = new AppOverrideList();
public static AppOverrideList GetAppOverrideList() => s_AppOverrideList;

private static ExperimentalFeatureList s_ExperimentalFeatureList = new ExperimentalFeatureList();
public static ExperimentalFeatureList GetExperimentalFeatureList() => s_ExperimentalFeatureList;

private static RuntimeList s_RuntimeList = new RuntimeList();
public static RuntimeList GetRuntimeList() => s_RuntimeList;

Expand Down
141 changes: 141 additions & 0 deletions wv2util/ExperimentalFeature.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace wv2util
{
public class ExperimentalFeature : IEquatable<ExperimentalFeature>, IComparable<ExperimentalFeature>
{
public string Name { get; set; }

private bool m_IsEnabled;

public bool IsEnabled
{
get { return m_IsEnabled; }
set
{
if (value)
{
m_IsEnabled = m_turnOn();
return;
}
else
{
m_turnOff();
}
m_IsEnabled = value;
}
}

public string Description { get; set; }

private Func<bool> m_turnOn;
private Action m_turnOff;

public ExperimentalFeature(Func<bool> turnOn, Action turnOff, Func<bool> isOn)
{
this.m_turnOn = turnOn;
this.m_turnOff = turnOff;
m_IsEnabled = isOn();
}

public int CompareTo(ExperimentalFeature other)
{
return Name.CompareTo(other.Name);
}

public bool Equals(ExperimentalFeature other)
{
return Name.Equals(other.Name);
}
}

public class EnvVarExperimentalFeature : ExperimentalFeature
{
public EnvVarExperimentalFeature(string envVar, string onVal, string offVal) : base(
() =>
{
// Turn on:
Environment.SetEnvironmentVariable(envVar, onVal, EnvironmentVariableTarget.User);
return true;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable(envVar, offVal, EnvironmentVariableTarget.Machine);
},
() =>
{
string val = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.User);
return val != null && val == onVal;
})
{
}
}

public class ExperimentalFeatureList : ObservableCollection<ExperimentalFeature>
{
public ExperimentalFeatureList()
{
// Canary self-hosting
Items.Add(new ExperimentalFeature(
() =>
{
var runtimes = AppState.GetRuntimeList();

// Only if Canary is installed turn self-hosting on
if (runtimes.Any(runtime => runtime.Channel == "Canary"))
{
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "1", EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
return true;
}

const string canaryLink = "https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en";
if (MessageBox.Show(
$"Before turning on this feature you need to have Canary installed from {canaryLink}. Do you want to install it now?",
"Canary missing", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
System.Diagnostics.Process.Start(canaryLink);
}

return false;
},
() =>
{
// Turn off:
Environment.SetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", null, EnvironmentVariableTarget.User);
AppState.GetAppOverrideList().FromSystem();
},
() =>
{
string val = Environment.GetEnvironmentVariable("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", EnvironmentVariableTarget.User);
return val != null && val == "1";
}
)
{
Name = "Preview WebView2 Runtime",
Description = "Host apps use canary WebView2 runtime if installed instead of stable."
});

// Visual Hosting
Items.Add(new EnvVarExperimentalFeature(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the environment variable to set this override versus a registry key?
Pros:

  • overrides in the environment variables will have higher precedent than registry.

Cons:

  • changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
  • the mechanism we're switching to for selfhost uses registry (Vicky or Victor will know if its HKLM or HKCU) so using registry here will be more likely to reflect that actual state.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to the environment variables won't apply to processes that have already started, unlike changes to the registry.
If the process already started, nothing can change its runtime regardless of the method we choose to change this, right?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the host app creates another webview2. The next webview2 created will respect the updated regkey but the updated env var isn't applied to the already running host app process.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that, I just thought that's an unlikely scenario, but I guess it can still happen.

"COREWEBVIEW2_FORCED_HOSTING_MODE",
"COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL",
null)
{
Name = "Visual hosting",
Description = "Host apps use visual hosting instead of regular window hosting."
});

// To add more experimental features to the runtimes either:
// add EnvVarExperimentalFeature if the feature is controlled only by an enviroment variable
// OR
// add ExperimentalFeature with on, off and check delegates if the feature requires more specific operations
}
}
}
42 changes: 38 additions & 4 deletions wv2util/MainWindow.xaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,9 +9,10 @@
Title="WebView2Utilities"
Height="700" Width="1100" ResizeMode="CanResizeWithGrip" MinWidth="662" MinHeight="360">
<Window.Resources>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>
<ObjectDataProvider x:Key="AppOverrideList" ObjectType="{x:Type local:AppState}" MethodName="GetAppOverrideList"/>
<ObjectDataProvider x:Key="ExperimentalFeatureList" ObjectType="{x:Type local:AppState}" MethodName="GetExperimentalFeatureList"/>
<ObjectDataProvider x:Key="RuntimeList" ObjectType="{x:Type local:AppState}" MethodName="GetRuntimeList"/>
<ObjectDataProvider x:Key="HostAppList" ObjectType="{x:Type local:AppState}" MethodName="GetHostAppList"/>

<CollectionViewSource Source="{StaticResource AppOverrideList}" x:Key="AppOverrideSortedList">
<CollectionViewSource.SortDescriptions>
Expand DownExpand Up@@ -296,7 +297,7 @@
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Overrides "/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="Reload_Click"/>
<Button x:Name="OverridesReload" Content="&#x1F503;" Click="OverridesReload_Click"/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Expand DownExpand Up@@ -349,6 +350,39 @@
</Grid>
</TabItem>

<!-- App Experimental Features List -->
<TabItem DataContext="{Binding Source={StaticResource ExperimentalFeatureList}}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Experimental "/>
</StackPanel>
</TabItem.Header>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView x:Name="ExperimentalFeatureList" ItemsSource="{Binding}" Grid.Row="0" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader>Name</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader>Enabled</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName=CheckBoxColumn, Path=Width}">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Description}">
<GridViewColumnHeader>Description</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>

<!-- About tab -->
<TabItem>
<TabItem.Header>
Expand Down
8 changes: 2 additions & 6 deletions wv2util/MainWindow.xaml.cs
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand All@@ -11,11 +9,9 @@
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;
using CheckBox = System.Windows.Controls.CheckBox;
using Clipboard = System.Windows.Clipboard;
using ElapsedEventArgs = System.Timers.ElapsedEventArgs;
using FolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog;
using SaveFileDialog = System.Windows.Forms.SaveFileDialog;
using Timer = System.Timers.Timer;

namespace wv2util
Expand DownExpand Up@@ -75,7 +71,7 @@ private void EnvVarButton_Click(object sender, RoutedEventArgs e)
protected RuntimeList RuntimeListData => AppState.GetRuntimeList();
protected HostAppList HostAppsListData => AppState.GetHostAppList();

private void Reload_Click(object sender, RoutedEventArgs e)
private void OverridesReload_Click(object sender, RoutedEventArgs e)
{
AppOverrideListData.FromSystem();
}
Expand Down
1 change: 1 addition & 0 deletions wv2util/wv2util.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,7 @@
<Compile Include="CreateReportWindow.xaml.cs">
<DependentUpon>CreateReportWindow.xaml</DependentUpon>
</Compile>
<Compile Include="ExperimentalFeature.cs" />
<Compile Include="HostAppList.cs" />
<Compile Include="HwndUtil.cs" />
<Compile Include="ProcessUtil.cs" />
Expand Down