Skip to content

Commit fb914b6

Browse files
committed
properly returning (with cache) atypical DPI icons that outside may ask for
1 parent 14e42bb commit fb914b6

File tree

6 files changed

+112
-17
lines changed

6 files changed

+112
-17
lines changed

ARM64/Release/win32-dpi.exe

1.5 KB
Binary file not shown.

win32-dpi.cpp

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,39 @@ struct Window {
196196
private:
197197
long dpi = 96;
198198
int metrics [SM_CMETRICS] = { 0 };
199-
HICON icons [IconSizesCount] = { NULL };
200199
HCURSOR cursor = NULL;
201-
200+
201+
struct {
202+
HICON standard [IconSizesCount] = { NULL };
203+
204+
// cache for icons of different DPI
205+
206+
struct PerDpiIcon {
207+
WPARAM type = 0;
208+
LPARAM dpi = 0;
209+
HICON icon = NULL;
210+
};
211+
struct {
212+
PerDpiIcon * data = nullptr;
213+
std::size_t n = 0;
214+
215+
struct {
216+
bool found;
217+
PerDpiIcon * icon;
218+
219+
} find (WPARAM type, LPARAM dpi) {
220+
for (std::size_t i = 0; i != n; ++i) {
221+
if ((this->data [i].type == type) && (this->data [i].dpi == dpi))
222+
return { true, &this->data [i] };
223+
224+
if (this->data [i].dpi == 0)
225+
return { false, &this->data [i] };
226+
}
227+
return { false, nullptr };
228+
}
229+
} dpi;
230+
} icons;
231+
202232
explicit Window (HWND hWnd)
203233
: hWnd (hWnd)
204234
, dpi (GetDPI (hWnd)) {};
@@ -207,7 +237,7 @@ struct Window {
207237
// - we want crisp icons wherever possible
208238
// - including the larger sizes is just flexing
209239
//
210-
SIZE GetIconMetrics (IconSize size, UINT dpiSystem) {
240+
SIZE GetIconMetrics (IconSize size, UINT dpiSystem = 0) {
211241
switch (size) {
212242
case SmallIconSize:
213243
return { metrics [SM_CXSMICON], metrics [SM_CYSMICON] };
@@ -222,6 +252,9 @@ struct Window {
222252

223253
case ShellIconSize:
224254
case JumboIconSize:
255+
if (dpiSystem == 0) {
256+
dpiSystem = GetDPI (NULL);
257+
}
225258
if (IsWindowsVistaOrGreater () || (size == ShellIconSize)) { // XP doesn't have Jumbo
226259
if (HMODULE hShell32 = GetModuleHandle (L"SHELL32")) {
227260
HRESULT (WINAPI * ptrSHGetImageList) (int, const GUID &, void **) = NULL;
@@ -254,6 +287,26 @@ struct Window {
254287
}
255288
}
256289

290+
// MapIconSize
291+
// - selecting proper IconSize from WM_GETICON/WM_SETICON wParam
292+
// - using proper size for Windows 10 taskbar
293+
//
294+
IconSize MapIconSize (WPARAM type) {
295+
switch (type) {
296+
case ICON_BIG:
297+
if (IsWindows10OrGreater ()) {
298+
return StartIconSize;
299+
} else {
300+
return LargeIconSize;
301+
}
302+
case ICON_SMALL:
303+
case ICON_SMALL2:
304+
return SmallIconSize;
305+
default:
306+
return LargeIconSize;
307+
}
308+
}
309+
257310
// RefreshVisualMetrics
258311
// - enables us to use 'this->metrics [SM_xxx]' whenever we need some metrics
259312
// instead of calling the function at every spot
@@ -347,6 +400,33 @@ struct Window {
347400
}
348401
break;
349402

403+
case WM_GETICON:
404+
if (lParam && (lParam != this->dpi)) {
405+
406+
// OS (taskbars on different displays) or other app asked for icon in different DPI
407+
if (auto [found, data] = this->icons.dpi.find (wParam, lParam); found) {
408+
return (LRESULT) data->icon;
409+
410+
} else {
411+
auto ndpi = (long) lParam;
412+
auto size = GetIconMetrics (this->MapIconSize (wParam));
413+
auto icon = LoadBestIcon (reinterpret_cast <HINSTANCE> (&__ImageBase), MAKEINTRESOURCE (1),
414+
{ ndpi * size.cx / 96, ndpi * size.cy / 96 });
415+
if (data) {
416+
data->type = wParam;
417+
data->dpi = ndpi;
418+
data->icon = icon;
419+
}
420+
return (LRESULT) icon;
421+
}
422+
} else {
423+
switch (wParam) {
424+
case ICON_SMALL2:
425+
return (LRESULT) this->icons.standard [this->MapIconSize (wParam)];
426+
}
427+
}
428+
break;
429+
350430
case WM_DPICHANGED:
351431
return this->OnDpiChange (wParam, reinterpret_cast <const RECT *> (lParam));
352432
case WM_WINDOWPOSCHANGED:
@@ -393,7 +473,7 @@ struct Window {
393473
return 0;
394474
}
395475
LRESULT OnDestroy () {
396-
for (auto icon : this->icons) {
476+
for (auto icon : this->icons.standard) {
397477
DestroyIcon (icon);
398478
}
399479
PostQuitMessage (0);
@@ -477,10 +557,19 @@ struct Window {
477557
for (auto i = 0u; i != IconSizesCount; ++i) {
478558
if (auto icon = LoadBestIcon (reinterpret_cast <HINSTANCE> (&__ImageBase), MAKEINTRESOURCE (1),
479559
GetIconMetrics ((IconSize) i, dpiSystem))) {
480-
if (this->icons [i]) {
481-
DestroyIcon (this->icons [i]);
560+
if (this->icons.standard [i]) {
561+
DestroyIcon (this->icons.standard [i]);
482562
}
483-
this->icons [i] = icon;
563+
this->icons.standard [i] = icon;
564+
}
565+
}
566+
for (auto i = 0u; i != this->icons.dpi.n; ++i) {
567+
if (this->icons.dpi.data [i].icon) {
568+
DestroyIcon (this->icons.dpi.data [i].icon);
569+
570+
this->icons.dpi.data [i].type = 0;
571+
this->icons.dpi.data [i].dpi = 0;
572+
this->icons.dpi.data [i].icon = NULL;
484573
}
485574
}
486575

@@ -490,8 +579,8 @@ struct Window {
490579
// and surprisingly pinning it explicitly with 24x24 icon won't work either, such
491580
// icon will be scaled up to 32x32 and then down to 24x24 resulting in blurry mess
492581

493-
SendMessage (hWnd, WM_SETICON, ICON_SMALL, (LPARAM) this->icons [SmallIconSize]);
494-
SendMessage (hWnd, WM_SETICON, ICON_BIG, (LPARAM) this->icons [IsWindows10OrGreater () ? StartIconSize : LargeIconSize]);
582+
SendMessage (hWnd, WM_SETICON, ICON_SMALL, (LPARAM) this->icons.standard [MapIconSize (ICON_SMALL)]);
583+
SendMessage (hWnd, WM_SETICON, ICON_BIG, (LPARAM) this->icons.standard [MapIconSize (ICON_BIG)]);
495584

496585
return 0;
497586
}
@@ -596,7 +685,7 @@ struct Window {
596685

597686
int CALLBACK wWinMain (_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int nCmdShow) {
598687
InitCommonControls ();
599-
688+
600689
if (HMODULE hUser32 = GetModuleHandle (L"USER32")) {
601690
Symbol (hUser32, ptrEnableNonClientDpiScaling, "EnableNonClientDpiScaling");
602691
Symbol (hUser32, pfnGetDpiForSystem, "GetDpiForSystem");

win32-dpi.info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
major = 1
1010
minor = 1
1111
patch = 0
12-
build = 98
12+
build = 111
1313

1414
[versioninfo]
1515
filename = %dir%\%internalname%.rc

win32-dpi.vcxproj

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,39 +36,39 @@
3636
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
3737
<ConfigurationType>Application</ConfigurationType>
3838
<UseDebugLibraries>true</UseDebugLibraries>
39-
<PlatformToolset>v142</PlatformToolset>
39+
<PlatformToolset>v143</PlatformToolset>
4040
<CharacterSet>Unicode</CharacterSet>
4141
</PropertyGroup>
4242
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4343
<ConfigurationType>Application</ConfigurationType>
4444
<UseDebugLibraries>false</UseDebugLibraries>
45-
<PlatformToolset>v142</PlatformToolset>
45+
<PlatformToolset>v143</PlatformToolset>
4646
<WholeProgramOptimization>true</WholeProgramOptimization>
4747
<CharacterSet>Unicode</CharacterSet>
4848
</PropertyGroup>
4949
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
5050
<ConfigurationType>Application</ConfigurationType>
5151
<UseDebugLibraries>true</UseDebugLibraries>
52-
<PlatformToolset>v142</PlatformToolset>
52+
<PlatformToolset>v143</PlatformToolset>
5353
<CharacterSet>Unicode</CharacterSet>
5454
</PropertyGroup>
5555
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
5656
<ConfigurationType>Application</ConfigurationType>
5757
<UseDebugLibraries>false</UseDebugLibraries>
58-
<PlatformToolset>v142</PlatformToolset>
58+
<PlatformToolset>v143</PlatformToolset>
5959
<WholeProgramOptimization>true</WholeProgramOptimization>
6060
<CharacterSet>Unicode</CharacterSet>
6161
</PropertyGroup>
6262
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
6363
<ConfigurationType>Application</ConfigurationType>
6464
<UseDebugLibraries>true</UseDebugLibraries>
65-
<PlatformToolset>v142</PlatformToolset>
65+
<PlatformToolset>v143</PlatformToolset>
6666
<CharacterSet>Unicode</CharacterSet>
6767
</PropertyGroup>
6868
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
6969
<ConfigurationType>Application</ConfigurationType>
7070
<UseDebugLibraries>false</UseDebugLibraries>
71-
<PlatformToolset>v142</PlatformToolset>
71+
<PlatformToolset>v143</PlatformToolset>
7272
<WholeProgramOptimization>true</WholeProgramOptimization>
7373
<CharacterSet>Unicode</CharacterSet>
7474
</PropertyGroup>
@@ -137,6 +137,7 @@
137137
<RuntimeTypeInfo>false</RuntimeTypeInfo>
138138
<BufferSecurityCheck>false</BufferSecurityCheck>
139139
<ControlFlowGuard>false</ControlFlowGuard>
140+
<LanguageStandard>stdcpp20</LanguageStandard>
140141
</ClCompile>
141142
<Link>
142143
<SubSystem>Windows</SubSystem>
@@ -159,6 +160,7 @@
159160
<RuntimeTypeInfo>false</RuntimeTypeInfo>
160161
<BufferSecurityCheck>false</BufferSecurityCheck>
161162
<ControlFlowGuard>false</ControlFlowGuard>
163+
<LanguageStandard>stdcpp20</LanguageStandard>
162164
</ClCompile>
163165
<Link>
164166
<SubSystem>Windows</SubSystem>
@@ -181,6 +183,7 @@
181183
<RuntimeTypeInfo>false</RuntimeTypeInfo>
182184
<BufferSecurityCheck>false</BufferSecurityCheck>
183185
<ControlFlowGuard>false</ControlFlowGuard>
186+
<LanguageStandard>stdcpp20</LanguageStandard>
184187
</ClCompile>
185188
<Link>
186189
<SubSystem>Windows</SubSystem>
@@ -207,6 +210,7 @@
207210
<ControlFlowGuard>false</ControlFlowGuard>
208211
<StringPooling>true</StringPooling>
209212
<AssemblerOutput>All</AssemblerOutput>
213+
<LanguageStandard>stdcpp20</LanguageStandard>
210214
</ClCompile>
211215
<Link>
212216
<SubSystem>Windows</SubSystem>
@@ -245,6 +249,7 @@
245249
<ControlFlowGuard>false</ControlFlowGuard>
246250
<StringPooling>true</StringPooling>
247251
<AssemblerOutput>All</AssemblerOutput>
252+
<LanguageStandard>stdcpp20</LanguageStandard>
248253
</ClCompile>
249254
<Link>
250255
<SubSystem>Windows</SubSystem>
@@ -283,6 +288,7 @@
283288
<ControlFlowGuard>false</ControlFlowGuard>
284289
<StringPooling>true</StringPooling>
285290
<AssemblerOutput>All</AssemblerOutput>
291+
<LanguageStandard>stdcpp20</LanguageStandard>
286292
</ClCompile>
287293
<Link>
288294
<SubSystem>Windows</SubSystem>

x64/Release/win32-dpi.exe

1 KB
Binary file not shown.

x86/Release/win32-dpi.exe

1 KB
Binary file not shown.

0 commit comments

Comments
 (0)