Skip to content

Commit 06e7304

Browse files
committed
- Fix issue #425: "No byte order mark on save" option throws stream closed exception add unit test
- Apply dark mode to window titlebar
1 parent 260fe2e commit 06e7304

File tree

7 files changed

+142
-4
lines changed

7 files changed

+142
-4
lines changed

src/Application/Application.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@
174174
</Compile>
175175
<Compile Include="Program.cs"></Compile>
176176
<Compile Include="Properties\AssemblyInfo.cs" />
177+
<Compile Include="Win32Helpers.cs" />
177178
<Compile Include="XmlDiffWrapper.cs" />
178179
<EmbeddedResource Include="FormGotoLine.resx">
179180
<DependentUpon>FormGotoLine.cs</DependentUpon>

src/Application/FormMain.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,13 +1753,37 @@ protected virtual void OnSettingsChanged(object sender, string name)
17531753
this._analytics.SetEnabled(this._settings.GetBoolean("AllowAnalytics", false));
17541754
}
17551755
break;
1756+
case "Theme":
1757+
OnThemeChanged();
1758+
break;
17561759
}
17571760

17581761
this._delayedActions.StartDelayedAction("DelaySaveSettings",
17591762
() => SaveSettings(new CancelEventArgs()),
17601763
TimeSpan.FromSeconds(1));
17611764
}
17621765

1766+
private void OnThemeChanged()
1767+
{
1768+
if ((ColorTheme)this._settings["Theme"] == ColorTheme.Light)
1769+
{
1770+
ThemeAllControls(this, false);
1771+
}
1772+
else
1773+
{
1774+
ThemeAllControls(this, true);
1775+
}
1776+
}
1777+
1778+
private void ThemeAllControls(Control parent, bool darkMode)
1779+
{
1780+
Win32Helpers.UseImmersiveDarkMode(this.Handle, darkMode);
1781+
foreach (Control control in parent.Controls)
1782+
{
1783+
ThemeAllControls(control, darkMode);
1784+
}
1785+
}
1786+
17631787
public void SaveErrors(string filename)
17641788
{
17651789
this._taskList.Save(filename);

src/Application/Win32Helpers.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace XmlNotepad
5+
{
6+
internal enum DWMWINDOWATTRIBUTE : uint
7+
{
8+
DWMWA_NCRENDERING_ENABLED,
9+
DWMWA_NCRENDERING_POLICY,
10+
DWMWA_TRANSITIONS_FORCEDISABLED,
11+
DWMWA_ALLOW_NCPAINT,
12+
DWMWA_CAPTION_BUTTON_BOUNDS,
13+
DWMWA_NONCLIENT_RTL_LAYOUT,
14+
DWMWA_FORCE_ICONIC_REPRESENTATION,
15+
DWMWA_FLIP3D_POLICY,
16+
DWMWA_EXTENDED_FRAME_BOUNDS,
17+
DWMWA_HAS_ICONIC_BITMAP,
18+
DWMWA_DISALLOW_PEEK,
19+
DWMWA_EXCLUDED_FROM_PEEK,
20+
DWMWA_CLOAK,
21+
DWMWA_CLOAKED,
22+
DWMWA_FREEZE_REPRESENTATION,
23+
DWMWA_PASSIVE_UPDATE_MODE,
24+
DWMWA_USE_HOSTBACKDROPBRUSH,
25+
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19,
26+
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
27+
DWMWA_WINDOW_CORNER_PREFERENCE = 33,
28+
DWMWA_BORDER_COLOR,
29+
DWMWA_CAPTION_COLOR,
30+
DWMWA_TEXT_COLOR,
31+
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
32+
DWMWA_SYSTEMBACKDROP_TYPE,
33+
DWMWA_LAST
34+
};
35+
36+
37+
internal static class Win32Helpers
38+
{
39+
[DllImport("Dwmapi")]
40+
static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE dwAttribute, ref int attrValue, uint cbAttribute);
41+
42+
internal static bool UseImmersiveDarkMode(IntPtr handle, bool enabled)
43+
{
44+
if (IsWindows10OrGreater(17763))
45+
{
46+
var attribute = DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1;
47+
if (IsWindows10OrGreater(18985))
48+
{
49+
attribute = DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE;
50+
}
51+
52+
int useImmersiveDarkMode = enabled ? 1 : 0;
53+
return DwmSetWindowAttribute(handle, attribute,
54+
ref useImmersiveDarkMode, sizeof(int)) == 0;
55+
}
56+
57+
return false;
58+
}
59+
60+
private static bool IsWindows10OrGreater(int build = -1)
61+
{
62+
return Environment.OSVersion.Version.Major >= 10 &&
63+
Environment.OSVersion.Version.Build >= build;
64+
}
65+
66+
}
67+
}

src/Model/XmlCache.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ public void SaveCopy(string filename)
393393
Settings settings = (Settings)this._site.GetService(typeof(Settings));
394394
if (settings != null)
395395
{
396-
noBom = (bool)settings["NoByteOrderMark"];
396+
noBom = settings.GetBoolean("NoByteOrderMark", false);
397397
if (noBom)
398398
{
399399
// then we must have an XML declaration with an encoding attribute.
@@ -414,10 +414,11 @@ public void SaveCopy(string filename)
414414
EncodingHelpers.InitializeWriterSettings(w, this._site);
415415
_doc.Save(w);
416416
}
417-
ms.Seek(0, SeekOrigin.Begin);
418-
419-
EncodingHelpers.WriteFileWithoutBOM(ms, filename);
420417

418+
using (var stm = new MemoryStream(ms.ToArray()))
419+
{
420+
EncodingHelpers.WriteFileWithoutBOM(stm, filename);
421+
}
421422
}
422423
else
423424
{

src/UnitTests/UnitTest1.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3099,9 +3099,48 @@ public void TestChangeTo()
30993099
this.SaveAndCompare("out.xml", "test8.xml");
31003100
}
31013101

3102+
[TestMethod]
3103+
[Timeout(TestMethodTimeout)]
3104+
public void TestNoByteOrderMark()
3105+
{
3106+
SetNoByteOrderMark(true);
3107+
Trace.WriteLine("TestNoByteOrderMark==========================================================");
3108+
string testFile = _testDir + "UnitTests\\test8.xml";
3109+
var w = this.LaunchNotepad(testFile);
3110+
Sleep(1000);
3111+
string outFile = Save("out.xml");
31023112

3113+
AssertUtf8Bom(testFile, true);
3114+
AssertUtf8Bom(outFile, false);
3115+
3116+
// test we can load it
3117+
XmlDocument doc = new XmlDocument();
3118+
doc.Load(outFile);
3119+
}
31033120

31043121
//==================================================================================
3122+
3123+
void SetNoByteOrderMark(bool value)
3124+
{
3125+
this.testSettings["NoByteOrderMark"] = value;
3126+
this.testSettings.Save(this.testSettings.FileName);
3127+
}
3128+
3129+
private void AssertUtf8Bom(string filename, bool expected)
3130+
{
3131+
var data = File.ReadAllBytes(filename);
3132+
bool isUtf8 = data.Length > 3 && data[0] == 0xef && data[1] == 0xBB && data[2] == 0xBF;
3133+
if (isUtf8 && !expected)
3134+
{
3135+
throw new ApplicationException("Byte order mark is present in {filename} but should not be");
3136+
}
3137+
else if (!isUtf8 && expected)
3138+
{
3139+
throw new ApplicationException("Byte order mark is not present in {filename} but should be");
3140+
}
3141+
}
3142+
3143+
31053144
private void SaveAndCompare(string outname, string compareWith)
31063145
{
31073146
string outFile = Save(outname);

src/Updates/Updates.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
<history>https://github.com/microsoft/XmlNotepad/blob/master/src/Updates/Updates.xml</history>
1010
<frequency>1.00:00:00</frequency>
1111
</application>
12+
<version number="2.9.0.15">
13+
<bug>Fix issue #425: "No byte order mark on save" option throws stream closed exception add unit test.</bug>
14+
<bug>Apply dark mode to window titlebar.</bug>
15+
</version>
1216
<version number="2.9.0.14">
1317
<bug>Fix issue #418: check setttings-file for "read-only".</bug>
1418
<bug>Fix issue #398: XmlNotepad detects xml-errors at empty nillable xsd:date Elements, but xml is correct</bug>

src/Version/Version.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@
1515
// Build Number
1616
// Revision
1717
//
18+
// This is the Master version number from which UpdateVersions will propagate to
19+
// Package.appxmanifest, Product.wxs, Bundle.wxs and Application.csproj.
1820
[assembly: AssemblyVersion("2.9.0.14")]
1921
[assembly: AssemblyFileVersion("2.9.0.14")]

0 commit comments

Comments
 (0)