Skip to content

Commit 8d93a57

Browse files
authored
Code Quality: Removed WinUIEx dependency (#15834)
1 parent 7fc6344 commit 8d93a57

File tree

9 files changed

+327
-123
lines changed

9 files changed

+327
-123
lines changed

.github/NOTICE.md

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -199,35 +199,6 @@ The above copyright notice and this permission notice shall be included in all c
199199
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
200200
```
201201

202-
## INI File Parser
203-
204-
**Source**: [https://github.com/rickyah/ini-parser](https://github.com/rickyah/ini-parser)
205-
206-
### License
207-
208-
```
209-
The MIT License (MIT)
210-
211-
Copyright (c) 2008 Ricardo Amores Hernández
212-
213-
Permission is hereby granted, free of charge, to any person obtaining a copy of
214-
this software and associated documentation files (the "Software"), to deal in
215-
the Software without restriction, including without limitation the rights to
216-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
217-
the Software, and to permit persons to whom the Software is furnished to do so,
218-
subject to the following conditions:
219-
220-
The above copyright notice and this permission notice shall be included in all
221-
copies or substantial portions of the Software.
222-
223-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
224-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
225-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
226-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
227-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
228-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
229-
```
230-
231202
## SevenZipSharp
232203

233204
**Source**: [https://github.com/files-community/SevenZipSharp](https://github.com/files-community/SevenZipSharp)
@@ -645,36 +616,6 @@ A "contributor" is any person that distributes its contribution under this licen
645616
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
646617
```
647618

648-
## WinUIEx
649-
650-
**Source**: [https://github.com/dotMorten/WinUIEx](https://github.com/dotMorten/WinUIEx)
651-
652-
### License
653-
654-
```
655-
MIT License
656-
657-
Copyright (c) 2021 Morten Nielsen
658-
659-
Permission is hereby granted, free of charge, to any person obtaining a copy
660-
of this software and associated documentation files (the "Software"), to deal
661-
in the Software without restriction, including without limitation the rights
662-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
663-
copies of the Software, and to permit persons to whom the Software is
664-
furnished to do so, subject to the following conditions:
665-
666-
The above copyright notice and this permission notice shall be included in all
667-
copies or substantial portions of the Software.
668-
669-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
670-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
671-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
672-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
673-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
674-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
675-
SOFTWARE.
676-
```
677-
678619
## libgit2sharp
679620

680621
**Source**: [https://github.com/libgit2/libgit2sharp](https://github.com/libgit2/libgit2sharp)
@@ -732,4 +673,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
732673
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
733674
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
734675
DEALINGS IN THE SOFTWARE.
735-
```
676+
```

src/Files.App/Data/Contexts/Window/WindowContext.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,18 @@ public WindowContext()
2525
IsRunningAsAdmin = WindowsSecurityService.IsAppElevated();
2626
CanDragAndDrop = WindowsSecurityService.CanDragAndDrop();
2727

28-
MainWindow.Instance.PresenterChanged += Window_PresenterChanged;
28+
MainWindow.Instance.AppWindow.Changed += AppWindow_Changed;
2929
}
3030

31-
private void Window_PresenterChanged(object? sender, AppWindowPresenter e)
31+
private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
3232
{
33-
SetProperty(
34-
ref isCompactOverlay,
35-
e.Kind is AppWindowPresenterKind.CompactOverlay,
36-
nameof(IsCompactOverlay));
33+
if (args.DidPresenterChange)
34+
{
35+
SetProperty(
36+
ref isCompactOverlay,
37+
sender.Presenter.Kind is AppWindowPresenterKind.CompactOverlay,
38+
nameof(IsCompactOverlay));
39+
}
3740
}
3841
}
3942
}

src/Files.App/Data/Items/WindowEx.cs

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Microsoft.UI.Windowing;
5+
using Microsoft.UI.Xaml;
6+
using System.Runtime.InteropServices;
7+
using Windows.Foundation;
8+
using Windows.Foundation.Collections;
9+
using Windows.Storage;
10+
using Windows.Win32;
11+
using Windows.Win32.Foundation;
12+
using Windows.Win32.Graphics.Gdi;
13+
using Windows.Win32.UI.WindowsAndMessaging;
14+
15+
namespace Files.App.Data.Items
16+
{
17+
/// <summary>
18+
/// Represents base <see cref="Window"/> class to extend its features.
19+
/// </summary>
20+
public unsafe class WindowEx : Window
21+
{
22+
private readonly WNDPROC _oldWndProc;
23+
private readonly WNDPROC _newWndProc;
24+
25+
private readonly ApplicationDataContainer _applicationDataContainer = ApplicationData.Current.LocalSettings;
26+
27+
/// <summary>
28+
/// Gets hWnd of this <see cref="Window"/>.
29+
/// </summary>
30+
public nint WindowHandle { get; }
31+
32+
/// <summary>
33+
/// Gets min width of this <see cref="Window"/>.
34+
/// </summary>
35+
public int MinWidth { get; }
36+
37+
/// <summary>
38+
/// Gets min height of this <see cref="Window"/>.
39+
/// </summary>
40+
public int MinHeight { get; }
41+
42+
private bool _IsMaximizable = true;
43+
/// <summary>
44+
/// Gets or sets a value that indicates whether this <see cref="Window"/> can be maximizable.
45+
/// </summary>
46+
public bool IsMaximizable
47+
{
48+
get => _IsMaximizable;
49+
set
50+
{
51+
_IsMaximizable = value;
52+
53+
if (AppWindow.Presenter is OverlappedPresenter overlapped)
54+
overlapped.IsMaximizable = value;
55+
56+
if (value)
57+
{
58+
// WORKAROUND:
59+
// https://github.com/microsoft/microsoft-ui-xaml/issues/8431
60+
// NOTE:
61+
// Indicates to the Shell that the window should not be treated as full-screen
62+
// not to mess up the taskbar when being full-screen mode.
63+
// This property should only be set if the "Automatically hide the taskbar" in Windows 11,
64+
// or "Automatically hide the taskbar in desktop mode" in Windows 10 is enabled.
65+
// Setting this property when the setting is disabled will result in the taskbar overlapping the application.
66+
if (AppLifecycleHelper.IsAutoHideTaskbarEnabled())
67+
Win32PInvoke.SetPropW(WindowHandle, "NonRudeHWND", new IntPtr(1));
68+
}
69+
}
70+
}
71+
72+
private bool _IsMinimizable = true;
73+
/// <summary>
74+
/// Gets or sets a value that indicates whether this <see cref="Window"/> can be minimizable.
75+
/// </summary>
76+
public bool IsMinimizable
77+
{
78+
get => _IsMinimizable;
79+
set
80+
{
81+
_IsMinimizable = value;
82+
83+
if (AppWindow.Presenter is OverlappedPresenter overlapped)
84+
overlapped.IsMinimizable = value;
85+
}
86+
}
87+
88+
/// <summary>
89+
/// Initializes <see cref="WindowEx"/> class.
90+
/// </summary>
91+
/// <param name="minWidth">Min width to set when initialized.</param>
92+
/// <param name="minHeight">Min height to set when initialized.</param>
93+
public unsafe WindowEx(int minWidth = 400, int minHeight = 300)
94+
{
95+
WindowHandle = WinRT.Interop.WindowNative.GetWindowHandle(this);
96+
MinWidth = minWidth;
97+
MinHeight = minHeight;
98+
IsMaximizable = true;
99+
IsMinimizable = true;
100+
101+
RestoreWindowPlacementData();
102+
103+
_newWndProc = new(NewWindowProc);
104+
var pNewWndProc = Marshal.GetFunctionPointerForDelegate(_newWndProc);
105+
var pOldWndProc = PInvoke.SetWindowLongPtr(new(WindowHandle), WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, pNewWndProc);
106+
_oldWndProc = Marshal.GetDelegateForFunctionPointer<WNDPROC>(pOldWndProc);
107+
108+
Closed += (s, e) => { StoreWindowPlacementData(); };
109+
}
110+
111+
private unsafe void StoreWindowPlacementData()
112+
{
113+
// Save window placement only for MainWindow
114+
if (!GetType().Name.Equals(nameof(MainWindow), StringComparison.OrdinalIgnoreCase))
115+
return;
116+
117+
// Store monitor info
118+
using var data = new SystemIO.MemoryStream();
119+
using var sw = new SystemIO.BinaryWriter(data);
120+
121+
var monitors = GetAllMonitorInfo();
122+
int nMonitors = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS);
123+
sw.Write(nMonitors);
124+
125+
foreach (var monitor in monitors)
126+
{
127+
sw.Write(monitor.Item1);
128+
sw.Write(monitor.Item2.Left);
129+
sw.Write(monitor.Item2.Top);
130+
sw.Write(monitor.Item2.Right);
131+
sw.Write(monitor.Item2.Bottom);
132+
}
133+
134+
WINDOWPLACEMENT placement = default;
135+
PInvoke.GetWindowPlacement(new(WindowHandle), ref placement);
136+
137+
int structSize = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
138+
IntPtr buffer = Marshal.AllocHGlobal(structSize);
139+
Marshal.StructureToPtr(placement, buffer, false);
140+
byte[] placementData = new byte[structSize];
141+
Marshal.Copy(buffer, placementData, 0, structSize);
142+
Marshal.FreeHGlobal(buffer);
143+
144+
sw.Write(placementData);
145+
sw.Flush();
146+
147+
var values = GetDataStore(out _, true);
148+
149+
if (_applicationDataContainer.Containers.ContainsKey("WinUIEx"))
150+
_applicationDataContainer.Values.Remove("WinUIEx");
151+
152+
values["MainWindowPlacementData"] = Convert.ToBase64String(data.ToArray());
153+
}
154+
155+
private void RestoreWindowPlacementData()
156+
{
157+
// Save window placement only for MainWindow
158+
if (!GetType().Name.Equals(nameof(MainWindow), StringComparison.OrdinalIgnoreCase))
159+
return;
160+
161+
var values = GetDataStore(out var oldDataExists, false);
162+
163+
byte[]? data = null;
164+
if (values.TryGetValue(oldDataExists ? "WindowPersistance_FilesMainWindow" : "MainWindowPlacementData", out object? value))
165+
{
166+
if (value is string base64)
167+
data = Convert.FromBase64String(base64);
168+
}
169+
170+
if (data is null)
171+
return;
172+
173+
SystemIO.BinaryReader br = new(new SystemIO.MemoryStream(data));
174+
175+
// Check if monitor layout changed since we stored position
176+
var monitors = GetAllMonitorInfo();
177+
int monitorCount = br.ReadInt32();
178+
int nMonitors = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS);
179+
if (monitorCount != nMonitors)
180+
return;
181+
182+
for (int i = 0; i < monitorCount; i++)
183+
{
184+
var pMonitor = monitors[i];
185+
br.ReadString();
186+
if (pMonitor.Item2.Left != br.ReadDouble() ||
187+
pMonitor.Item2.Top != br.ReadDouble() ||
188+
pMonitor.Item2.Right != br.ReadDouble() ||
189+
pMonitor.Item2.Bottom != br.ReadDouble())
190+
return;
191+
}
192+
193+
int structSize = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
194+
byte[] placementData = br.ReadBytes(structSize);
195+
IntPtr buffer = Marshal.AllocHGlobal(structSize);
196+
Marshal.Copy(placementData, 0, buffer, structSize);
197+
var windowPlacementData = (WINDOWPLACEMENT)Marshal.PtrToStructure(buffer, typeof(WINDOWPLACEMENT))!;
198+
199+
Marshal.FreeHGlobal(buffer);
200+
201+
// Ignore anything by maximized or normal
202+
if (windowPlacementData.showCmd == (SHOW_WINDOW_CMD)0x0002 /*SW_INVALIDATE*/ &&
203+
windowPlacementData.flags == WINDOWPLACEMENT_FLAGS.WPF_RESTORETOMAXIMIZED)
204+
windowPlacementData.showCmd = SHOW_WINDOW_CMD.SW_MAXIMIZE;
205+
else if (windowPlacementData.showCmd != SHOW_WINDOW_CMD.SW_MAXIMIZE)
206+
windowPlacementData.showCmd = SHOW_WINDOW_CMD.SW_NORMAL;
207+
208+
PInvoke.SetWindowPlacement(new(WindowHandle), in windowPlacementData);
209+
210+
return;
211+
}
212+
213+
private IPropertySet GetDataStore(out bool oldDataExists, bool useNewStore = true)
214+
{
215+
IPropertySet values;
216+
oldDataExists = false;
217+
218+
if (_applicationDataContainer.Containers.TryGetValue("Files", out var dataContainer))
219+
{
220+
values = dataContainer.Values;
221+
}
222+
else if (!useNewStore && _applicationDataContainer.Containers.TryGetValue("WinUIEx", out var oldDataContainer))
223+
{
224+
values = oldDataContainer.Values;
225+
oldDataExists = true;
226+
}
227+
else
228+
{
229+
values = _applicationDataContainer.CreateContainer(
230+
"Files",
231+
ApplicationDataCreateDisposition.Always).Values;
232+
}
233+
234+
return values;
235+
}
236+
237+
private unsafe List<Tuple<string, Rect>> GetAllMonitorInfo()
238+
{
239+
List<Tuple<string, Rect>> monitors = [];
240+
MONITORENUMPROC callback = new((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
241+
{
242+
MONITORINFOEXW info = default;
243+
info.monitorInfo.cbSize = (uint)Marshal.SizeOf<MONITORINFOEXW>();
244+
245+
PInvoke.GetMonitorInfo(monitor, (MONITORINFO*)&info);
246+
247+
monitors.Add(new(
248+
info.szDevice.ToString(),
249+
new(new Point(rect->left, rect->top), new Point(rect->right, rect->bottom))));
250+
251+
return true;
252+
});
253+
254+
LPARAM lParam = default;
255+
bool ok = PInvoke.EnumDisplayMonitors(new(nint.Zero), (RECT*)null, callback, lParam);
256+
if (!ok)
257+
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
258+
259+
return monitors;
260+
}
261+
262+
private LRESULT NewWindowProc(HWND param0, uint param1, WPARAM param2, LPARAM param3)
263+
{
264+
switch (param1)
265+
{
266+
case 0x0024: /*WM_GETMINMAXINFO*/
267+
{
268+
var dpi = PInvoke.GetDpiForWindow(new(param0));
269+
float scalingFactor = (float)dpi / 96;
270+
271+
var minMaxInfo = Marshal.PtrToStructure<MINMAXINFO>(param3);
272+
minMaxInfo.ptMinTrackSize.X = (int)(MinWidth * scalingFactor);
273+
minMaxInfo.ptMinTrackSize.Y = (int)(MinHeight * scalingFactor);
274+
Marshal.StructureToPtr(minMaxInfo, param3, true);
275+
break;
276+
}
277+
}
278+
279+
return PInvoke.CallWindowProc(_oldWndProc, param0, param1, param2, param3);
280+
}
281+
}
282+
}

src/Files.App/Files.App.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
8686
<PackageReference Include="TagLibSharp" Version="2.3.0" />
8787
<PackageReference Include="Tulpep.ActiveDirectoryObjectPicker" Version="3.0.11" />
88-
<PackageReference Include="WinUIEx" Version="2.3.4" />
8988
<PackageReference Include="Vanara.Windows.Extensions" Version="4.0.1" />
9089
<PackageReference Include="Vanara.Windows.Shell" Version="4.0.1" />
9190
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />

0 commit comments

Comments
 (0)