|
2 | 2 | using Microsoft.UI;
|
3 | 3 | using Microsoft.UI.Windowing;
|
4 | 4 | using Microsoft.UI.Xaml;
|
| 5 | +using Microsoft.UI.Xaml.Controls.Primitives; |
5 | 6 | using WinRT.Interop;
|
6 | 7 |
|
7 | 8 | namespace Coder.Desktop.App.Controls
|
8 | 9 | {
|
9 | 10 | public static class TitleBarIcon
|
10 | 11 | {
|
11 |
| - public static void InjectIcon(Window window) |
12 |
| - { |
13 |
| - var hwnd = WindowNative.GetWindowHandle(window); |
14 |
| - var windowId = Win32Interop.GetWindowIdFromWindow(hwnd); |
15 |
| - AppWindow.GetFromWindowId(windowId).SetIcon("coder.ico"); |
16 |
| - } |
| 12 | + private static readonly Lazy<IconsManager> _iconsManager = new(() => new IconsManager()); |
17 | 13 |
|
18 | 14 | public static void SetTitlebarIcon(Window window)
|
19 | 15 | {
|
20 | 16 | var hwnd = WindowNative.GetWindowHandle(window);
|
| 17 | + var theme = window.Content is FrameworkElement fe |
| 18 | + ? fe.ActualTheme |
| 19 | + : ElementTheme.Default; |
| 20 | + _iconsManager.Value.SetTitlebarIcon(hwnd, theme == ElementTheme.Dark); |
| 21 | + } |
21 | 22 |
|
22 |
| - string iconPathDark = "Assets/coder_icon_32_dark.ico"; |
23 |
| - string iconPathLight = "Assets/coder_icon_32_light.ico"; |
| 23 | + public static void DisposeIconsManager() |
| 24 | + { |
| 25 | + _iconsManager.Value.Dispose(); |
| 26 | + } |
| 27 | + } |
24 | 28 |
|
25 |
| - var hIconDark = PInvoke.LoadImage( |
| 29 | +#pragma warning disable CsWinRT1028 // Class does not need to be partial, it's an SDK bug: |
| 30 | + public class IconsManager : IDisposable |
| 31 | +#pragma warning restore CsWinRT1028 // Class is not marked partial |
| 32 | + { |
| 33 | + private nint hIconDark; |
| 34 | + private nint hIconLight; |
| 35 | + private const string iconPathDark = "Assets/coder_icon_32_dark.ico"; |
| 36 | + private const string iconPathLight = "Assets/coder_icon_32_light.ico"; |
| 37 | + public IconsManager() { |
| 38 | + hIconDark = PInvoke.LoadImage( |
26 | 39 | IntPtr.Zero,
|
27 | 40 | iconPathDark,
|
28 | 41 | PInvoke.IMAGE_ICON,
|
29 | 42 | 0,
|
30 | 43 | 0,
|
31 | 44 | PInvoke.LR_LOADFROMFILE
|
32 | 45 | );
|
33 |
| - |
34 |
| - var hIconLight = PInvoke.LoadImage( |
| 46 | + hIconLight = PInvoke.LoadImage( |
35 | 47 | IntPtr.Zero,
|
36 | 48 | iconPathLight,
|
37 | 49 | PInvoke.IMAGE_ICON,
|
38 | 50 | 0,
|
39 | 51 | 0,
|
40 | 52 | PInvoke.LR_LOADFROMFILE
|
41 | 53 | );
|
| 54 | + } |
42 | 55 |
|
43 |
| - PInvoke.SendMessage(hwnd, PInvoke.WM_SETICON, (IntPtr)PInvoke.ICON_SMALL, hIconDark); |
44 |
| - PInvoke.SendMessage(hwnd, PInvoke.WM_SETICON, (IntPtr)PInvoke.ICON_BIG, hIconLight); |
| 56 | + public void SetTitlebarIcon(nint windowHandle, bool isDarkTheme) |
| 57 | + { |
| 58 | + PInvoke.SendMessage(windowHandle, PInvoke.WM_SETICON, (IntPtr)PInvoke.ICON_SMALL, isDarkTheme ? hIconDark : hIconLight); |
| 59 | + PInvoke.SendMessage(windowHandle, PInvoke.WM_SETICON, (IntPtr)PInvoke.ICON_BIG, isDarkTheme ? hIconLight : hIconDark); |
| 60 | + } |
| 61 | + |
| 62 | + public void Dispose() |
| 63 | + { |
| 64 | + if (hIconDark != IntPtr.Zero) |
| 65 | + { |
| 66 | + PInvoke.DestroyIcon(hIconDark); |
| 67 | + } |
| 68 | + if (hIconLight != IntPtr.Zero) |
| 69 | + { |
| 70 | + PInvoke.DestroyIcon(hIconLight); |
| 71 | + } |
| 72 | + GC.SuppressFinalize(this); |
45 | 73 | }
|
46 | 74 | }
|
47 | 75 | }
|
0 commit comments