Skip to content

Commit 8f4b4aa

Browse files
committed
Lots of progress on High-DPI support in Windows. Only enabled in Debug x64 configuration.
1 parent 660d6e4 commit 8f4b4aa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+885
-330
lines changed

CUI/CUI.vcxproj

+3
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@
473473
<ClCompile Include="CUIDialog.cpp" />
474474
<ClCompile Include="CUIOGLWindow.cpp" />
475475
<ClCompile Include="CUIPropertySheet.cpp" />
476+
<ClCompile Include="CUIScaler.cpp" />
476477
<ClCompile Include="CUISubWindowInfo.cpp" />
477478
<ClCompile Include="CUIThemes.cpp" />
478479
<ClCompile Include="CUIWindow.cpp" />
@@ -482,8 +483,10 @@
482483
<ClInclude Include="CUIColorButton.h" />
483484
<ClInclude Include="CUIDefines.h" />
484485
<ClInclude Include="CUIDialog.h" />
486+
<ClInclude Include="CUIModuleHolder.h" />
485487
<ClInclude Include="CUIOGLWindow.h" />
486488
<ClInclude Include="CUIPropertySheet.h" />
489+
<ClInclude Include="CUIScaler.h" />
487490
<ClInclude Include="CUISubWindowInfo.h" />
488491
<ClInclude Include="CUIThemes.h" />
489492
<ClInclude Include="CUIWindow.h" />

CUI/CUI.vcxproj.filters

+9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
<ClCompile Include="CUIWindowResizer.cpp">
3636
<Filter>Source Files</Filter>
3737
</ClCompile>
38+
<ClCompile Include="CUIScaler.cpp">
39+
<Filter>Source Files</Filter>
40+
</ClCompile>
3841
</ItemGroup>
3942
<ItemGroup>
4043
<ClInclude Include="CUIColorButton.h">
@@ -64,5 +67,11 @@
6467
<ClInclude Include="CUIWindowResizer.h">
6568
<Filter>Header Files</Filter>
6669
</ClInclude>
70+
<ClInclude Include="CUIModuleHolder.h">
71+
<Filter>Header Files</Filter>
72+
</ClInclude>
73+
<ClInclude Include="CUIScaler.h">
74+
<Filter>Header Files</Filter>
75+
</ClInclude>
6776
</ItemGroup>
6877
</Project>

CUI/CUIModuleHolder.h

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef __CUIMODULEHOLDER_H__
2+
#define __CUIMODULEHOLDER_H__
3+
4+
#include <CUI/CUIWindow.h>
5+
6+
class CUIExport CUIModuleHolder
7+
{
8+
public:
9+
CUIModuleHolder(LPCTSTR libraryName)
10+
{
11+
m_hModule = LoadLibrary(libraryName);
12+
}
13+
~CUIModuleHolder(void)
14+
{
15+
if (m_hModule != NULL)
16+
{
17+
FreeLibrary(m_hModule);
18+
}
19+
}
20+
protected:
21+
HMODULE m_hModule;
22+
};
23+
24+
#endif // __CUIMODULEHOLDER_H__

CUI/CUIScaler.cpp

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#include "CUIScaler.h"
2+
#include "CUIModuleHolder.h"
3+
4+
#ifdef _DEBUG
5+
#include <VersionHelpers.h>
6+
bool CUIScaler::sm_use32bit = IsWindowsXPOrGreater();
7+
#else // _DEBUG
8+
bool CUIScaler::sm_use32bit = false;
9+
#endif // !_DEBUG
10+
11+
typedef enum MONITOR_DPI_TYPE {
12+
MDT_EFFECTIVE_DPI = 0,
13+
MDT_ANGULAR_DPI = 1,
14+
MDT_RAW_DPI = 2,
15+
MDT_DEFAULT = MDT_EFFECTIVE_DPI
16+
} MONITOR_DPI_TYPE;
17+
18+
typedef HRESULT(WINAPI *PFNGETDPIFORMONITOR)(
19+
_In_ HMONITOR hmonitor,
20+
_In_ MONITOR_DPI_TYPE dpiType,
21+
_Out_ UINT *dpiX,
22+
_Out_ UINT *dpiY);
23+
24+
class ShcoreHolder : public CUIModuleHolder
25+
{
26+
public:
27+
ShcoreHolder(void)
28+
: CUIModuleHolder("Shcore.dll")
29+
, m_getDpiForMonitor(NULL)
30+
{
31+
if (m_hModule != NULL)
32+
{
33+
m_getDpiForMonitor = (PFNGETDPIFORMONITOR)GetProcAddress(m_hModule,
34+
"GetDpiForMonitor");
35+
}
36+
}
37+
~ShcoreHolder(void)
38+
{
39+
m_getDpiForMonitor = NULL;
40+
}
41+
PFNGETDPIFORMONITOR m_getDpiForMonitor;
42+
};
43+
44+
static ShcoreHolder s_shcore;
45+
46+
CUIScaler::CUIScaler(CUIWindow *window)
47+
: m_window(window) // window is our owner; do not retain.
48+
, m_hScaleSrcDC(NULL)
49+
, m_hScaleDstDC(NULL)
50+
, m_scaleFactor(1.0)
51+
, m_dpiX(96)
52+
, m_dpiY(96)
53+
{
54+
getScaleFactor(true);
55+
}
56+
57+
CUIScaler::~CUIScaler(void)
58+
{
59+
}
60+
61+
void CUIScaler::dealloc(void)
62+
{
63+
// DO NOT RELEASE m_window: it is our owner.
64+
TCObject::dealloc();
65+
if (m_hScaleSrcDC != NULL)
66+
{
67+
DeleteDC(m_hScaleSrcDC);
68+
}
69+
if (m_hScaleDstDC != NULL)
70+
{
71+
DeleteDC(m_hScaleDstDC);
72+
}
73+
}
74+
75+
double CUIScaler::getScaleFactor(
76+
bool recalculate /*= false*/,
77+
UINT *dpiX /*= NULL*/,
78+
UINT *dpiY /*= NULL*/)
79+
{
80+
if (recalculate)
81+
{
82+
m_scaleFactor = 1.0;
83+
m_dpiX = m_dpiY = 96;
84+
if (s_shcore.m_getDpiForMonitor != NULL)
85+
{
86+
HMONITOR hMonitor = MonitorFromWindow(m_window->getHWindow(),
87+
MONITOR_DEFAULTTOPRIMARY);
88+
UINT ldpiX, ldpiY;
89+
if (s_shcore.m_getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI,
90+
&ldpiX, &ldpiY) == S_OK)
91+
{
92+
m_dpiX = (UINT)fmax(96, ldpiX);
93+
m_dpiY = (UINT)fmax(96, ldpiY);
94+
// Don't go below 1.0, and if X and Y differ, go with the higher
95+
// value. That's probably not going to work right, but I don't
96+
// have any way to test non-square-pixel displays.
97+
m_scaleFactor = fmax(1.0, fmax(m_dpiX, m_dpiY) / 96.0);
98+
}
99+
}
100+
}
101+
if (dpiX != NULL)
102+
{
103+
*dpiX = m_dpiX;
104+
}
105+
if (dpiY != NULL)
106+
{
107+
*dpiY = m_dpiY;
108+
}
109+
return m_scaleFactor;
110+
}
111+
112+
bool CUIScaler::scaleBitmap(
113+
HBITMAP hSrc,
114+
HBITMAP& hDst,
115+
double scaleFactor /*= -1*/)
116+
{
117+
if (scaleFactor == -1.0)
118+
{
119+
scaleFactor = m_scaleFactor;
120+
}
121+
if (m_hScaleSrcDC == NULL)
122+
{
123+
m_hScaleSrcDC = CreateCompatibleDC(NULL);
124+
if (m_hScaleSrcDC == NULL)
125+
{
126+
return false;
127+
}
128+
}
129+
if (m_hScaleDstDC == NULL)
130+
{
131+
m_hScaleDstDC = CreateCompatibleDC(NULL);
132+
if (m_hScaleDstDC == NULL)
133+
{
134+
return false;
135+
}
136+
}
137+
SIZE srcSize;
138+
if (!m_window->getBitmapSize(hSrc, srcSize))
139+
{
140+
return false;
141+
}
142+
SIZE dstSize;
143+
dstSize.cx = (int)(srcSize.cx * scaleFactor);
144+
dstSize.cy = (int)(srcSize.cy * scaleFactor);
145+
BYTE *bmBuffer;
146+
hDst = m_window->createDIBSection(m_hScaleDstDC, dstSize.cx, dstSize.cy, m_dpiX, m_dpiY,
147+
&bmBuffer, sm_use32bit);
148+
if (hDst != NULL)
149+
{
150+
HBITMAP hOldDst = (HBITMAP)SelectObject(m_hScaleDstDC, hDst);
151+
HBITMAP hOldSrc = (HBITMAP)SelectObject(m_hScaleSrcDC, hSrc);
152+
SetStretchBltMode(m_hScaleDstDC, COLORONCOLOR);
153+
bool retValue = StretchBlt(m_hScaleDstDC, 0, 0, dstSize.cx, dstSize.cy, m_hScaleSrcDC,
154+
0, 0, srcSize.cx, srcSize.cy, SRCCOPY) != FALSE;
155+
SelectObject(m_hScaleSrcDC, hOldSrc);
156+
SelectObject(m_hScaleDstDC, hOldDst);
157+
if (!retValue)
158+
{
159+
DeleteObject(hDst);
160+
hDst = NULL;
161+
}
162+
return retValue;
163+
}
164+
return false;
165+
}

CUI/CUIScaler.h

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef __CUISCALER_H__
2+
#define __CUISCALER_H__
3+
4+
#include <CUI/CUIWindow.h>
5+
6+
class CUIExport CUIScaler : public TCObject
7+
{
8+
public:
9+
CUIScaler(CUIWindow *window);
10+
double getScaleFactor(bool recalculate = false, UINT *dpiX = NULL,
11+
UINT *dpiY = NULL);
12+
int scale(int points) { return (int)(points * getScaleFactor()); }
13+
int unscale(int pixels) { return (int)(pixels / getScaleFactor()); }
14+
bool scaleBitmap(HBITMAP hSrc, HBITMAP& hDst, double scaleFactor = -1.0);
15+
static bool use32bit(void) { return sm_use32bit; }
16+
static UINT imageListCreateFlags(void)
17+
{
18+
return use32bit() ? ILC_COLOR32 : ILC_COLOR24 | ILC_MASK;
19+
}
20+
protected:
21+
virtual ~CUIScaler(void);
22+
virtual void dealloc(void);
23+
24+
CUIWindow *m_window;
25+
HDC m_hScaleSrcDC;
26+
HDC m_hScaleDstDC;
27+
double m_scaleFactor;
28+
UINT m_dpiX;
29+
UINT m_dpiY;
30+
static bool sm_use32bit;
31+
};
32+
33+
#endif // __CUISCALER_H__

0 commit comments

Comments
 (0)