win: Prefer integers instead of strings for OS version comparison
* Add a WinOSVersionInfo struct holding the major and minor version and build number for a Windows release. * Extract a static WinSalInstance::getWinOSVersionInfo from WinSalInstance::getOSVersion that returns a corresponding version info. * Adjust the local getOSVersionString helper to take integers for major and minor version instead of an "NT version" string that is a dot-separated version number containing both of these. * Use WinSalInstance::getWinOSVersionInfo in ImplDrawNativeControl to compare the major version + build number to identify Windows 11 instead of relying on WinSalInstance::getOSVersion to return a string starting with "Windows 11". Change-Id: I6fe727c1c0f928c03216e406cdb1b7735c1ab3ad Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176059 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
This commit is contained in:
parent
92f5913aef
commit
a43b5e3de4
3 changed files with 55 additions and 36 deletions
|
@ -24,9 +24,17 @@
|
|||
#include <osl/conditn.hxx>
|
||||
|
||||
#include <salinst.hxx>
|
||||
#include <win/salframe.h>
|
||||
|
||||
class SalYieldMutex;
|
||||
|
||||
struct WinOSVersionInfo
|
||||
{
|
||||
DWORD m_nMajorVersion = 0;
|
||||
DWORD m_nMinorVersion = 0;
|
||||
DWORD m_nBuildNumber = 0;
|
||||
};
|
||||
|
||||
class WinSalInstance : public SalInstance
|
||||
{
|
||||
public:
|
||||
|
@ -72,6 +80,7 @@ public:
|
|||
virtual OUString GetConnectionIdentifier() override;
|
||||
virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override;
|
||||
|
||||
static WinOSVersionInfo getWinOSVersionInfo();
|
||||
virtual OUString getOSVersion() override;
|
||||
virtual void BeforeAbort(const OUString&, bool) override;
|
||||
|
||||
|
|
|
@ -1045,16 +1045,16 @@ static OUString getWinArch()
|
|||
}
|
||||
}
|
||||
|
||||
static OUString getOSVersionString(const OUString& aNtVersionString, DWORD nBuildNumber)
|
||||
static OUString getOSVersionString(DWORD nMajorVersion, DWORD nMinorVersion, DWORD nBuildNumber)
|
||||
{
|
||||
OUStringBuffer result = u"Windows";
|
||||
if (aNtVersionString == "6.1")
|
||||
if (nMajorVersion == 6 && nMinorVersion == 1)
|
||||
result.append(" 7 Service Pack 1");
|
||||
else if (aNtVersionString == "6.2")
|
||||
else if (nMajorVersion == 6 && nMinorVersion == 2)
|
||||
result.append(" 8");
|
||||
else if (aNtVersionString == "6.3")
|
||||
else if (nMajorVersion == 6 && nMinorVersion == 3)
|
||||
result.append(" 8.1");
|
||||
else if (aNtVersionString == "10.0")
|
||||
else if (nMajorVersion == 10 && nMinorVersion == 0)
|
||||
{
|
||||
if (nBuildNumber >= 22000)
|
||||
result.append(" 11");
|
||||
|
@ -1066,12 +1066,12 @@ static OUString getOSVersionString(const OUString& aNtVersionString, DWORD nBuil
|
|||
|
||||
result.append(getWinArch());
|
||||
|
||||
if (!aNtVersionString.isEmpty() || nBuildNumber)
|
||||
if (nMajorVersion || nMinorVersion || nBuildNumber)
|
||||
{
|
||||
result.append(" (");
|
||||
if (!aNtVersionString.isEmpty())
|
||||
if (nMajorVersion || nMinorVersion)
|
||||
{
|
||||
result.append(aNtVersionString);
|
||||
result.append(OUString::number(nMajorVersion) + u"." + OUString::number(nMinorVersion));
|
||||
if (nBuildNumber)
|
||||
result.append(" ");
|
||||
}
|
||||
|
@ -1083,10 +1083,11 @@ static OUString getOSVersionString(const OUString& aNtVersionString, DWORD nBuil
|
|||
return result.makeStringAndClear();
|
||||
}
|
||||
|
||||
OUString WinSalInstance::getOSVersion()
|
||||
WinOSVersionInfo WinSalInstance::getWinOSVersionInfo()
|
||||
{
|
||||
static const OUString result = []
|
||||
static const WinOSVersionInfo aResult = []
|
||||
{
|
||||
WinOSVersionInfo aVersion;
|
||||
// GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
|
||||
// subject to manifest-based behavior since Windows 8.1, so give wrong results.
|
||||
// Another approach would be to use NetWkstaGetInfo, but that has some small
|
||||
|
@ -1094,7 +1095,6 @@ OUString WinSalInstance::getOSVersion()
|
|||
// poor network connections.
|
||||
// So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
|
||||
bool bHaveVerFromKernel32 = false;
|
||||
OUString aNtVersion;
|
||||
if (HMODULE h_kernel32 = GetModuleHandleW(L"kernel32.dll"))
|
||||
{
|
||||
wchar_t szPath[MAX_PATH];
|
||||
|
@ -1113,8 +1113,8 @@ OUString WinSalInstance::getOSVersion()
|
|||
&& dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
|
||||
{
|
||||
VS_FIXEDFILEINFO* vi1 = static_cast<VS_FIXEDFILEINFO*>(pBlock);
|
||||
aNtVersion = (OUString::number(HIWORD(vi1->dwProductVersionMS)) + "."
|
||||
+ OUString::number(LOWORD(vi1->dwProductVersionMS)));
|
||||
aVersion.m_nMajorVersion = HIWORD(vi1->dwProductVersionMS);
|
||||
aVersion.m_nMinorVersion = LOWORD(vi1->dwProductVersionMS);
|
||||
bHaveVerFromKernel32 = true;
|
||||
}
|
||||
}
|
||||
|
@ -1123,7 +1123,6 @@ OUString WinSalInstance::getOSVersion()
|
|||
}
|
||||
// Now use RtlGetVersion (which is not subject to deprecation for GetVersion(Ex) API)
|
||||
// to get build number and SP info
|
||||
DWORD nBuildNumber = 0;
|
||||
if (HMODULE h_ntdll = GetModuleHandleW(L"ntdll.dll"))
|
||||
{
|
||||
if (auto RtlGetVersion
|
||||
|
@ -1134,15 +1133,23 @@ OUString WinSalInstance::getOSVersion()
|
|||
if (STATUS_SUCCESS == RtlGetVersion(&vi2))
|
||||
{
|
||||
if (!bHaveVerFromKernel32) // we failed above; let's hope this would be useful
|
||||
aNtVersion = (OUString::number(vi2.dwMajorVersion) + "."
|
||||
+ OUString::number(vi2.dwMinorVersion));
|
||||
nBuildNumber = vi2.dwBuildNumber;
|
||||
{
|
||||
aVersion.m_nMajorVersion = vi2.dwMajorVersion;
|
||||
aVersion.m_nMinorVersion = vi2.dwMinorVersion;
|
||||
}
|
||||
aVersion.m_nBuildNumber = vi2.dwBuildNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
return getOSVersionString(aNtVersion, nBuildNumber);
|
||||
return aVersion;
|
||||
}();
|
||||
return result;
|
||||
return aResult;
|
||||
}
|
||||
|
||||
OUString WinSalInstance::getOSVersion()
|
||||
{
|
||||
WinOSVersionInfo aInfo = getWinOSVersionInfo();
|
||||
return getOSVersionString(aInfo.m_nMajorVersion, aInfo.m_nMinorVersion, aInfo.m_nBuildNumber);
|
||||
}
|
||||
|
||||
void WinSalInstance::BeforeAbort(const OUString&, bool)
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <win/salgdi.h>
|
||||
#include <win/saldata.hxx>
|
||||
#include <win/salframe.h>
|
||||
#include <win/salinst.h>
|
||||
#include <win/scoped_gdi.hxx>
|
||||
#include <win/wingdiimpl.hxx>
|
||||
|
||||
|
@ -911,25 +912,27 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
|
|||
else
|
||||
iState = bChecked ? TS_CHECKED : TS_NORMAL;
|
||||
|
||||
if (bUseDarkMode && GetSalInstance()->getOSVersion().startsWith(u"Windows 11")
|
||||
&& (bChecked
|
||||
|| (nState & (ControlState::PRESSED) || (nState & ControlState::ROLLOVER))))
|
||||
if (bUseDarkMode && (bChecked || (nState & (ControlState::PRESSED) || (nState & ControlState::ROLLOVER))))
|
||||
{
|
||||
// tdf#152534 workaround bug with Windows 11 Dark theme using
|
||||
// light blue as highlight color which gives insufficient
|
||||
// contrast for hovered-over or pressed/checked toolbar buttons:
|
||||
// manually draw background (using color a bit lighter than background
|
||||
// for non-highlighted items) and draw a frame around it
|
||||
ScopedHBRUSH aBgColorBrush(CreateSolidBrush(RGB(38, 38, 38)));
|
||||
FillRect(hDC, &rc, aBgColorBrush.get());
|
||||
const Color aFrameColor = Application::GetSettings().GetStyleSettings().GetDisableColor();
|
||||
ScopedHBRUSH aFrameBrush(CreateSolidBrush(
|
||||
RGB(aFrameColor.GetRed(), aFrameColor.GetGreen(), aFrameColor.GetBlue())));
|
||||
FrameRect(hDC, &rc, aFrameBrush.get());
|
||||
const WinOSVersionInfo aVersion = WinSalInstance::getWinOSVersionInfo();
|
||||
if (aVersion.m_nMajorVersion == 10 && aVersion.m_nBuildNumber >= 22000)
|
||||
{
|
||||
// tdf#152534 workaround bug with Windows 11 Dark theme using
|
||||
// light blue as highlight color which gives insufficient
|
||||
// contrast for hovered-over or pressed/checked toolbar buttons:
|
||||
// manually draw background (using color a bit lighter than background
|
||||
// for non-highlighted items) and draw a frame around it
|
||||
ScopedHBRUSH aBgColorBrush(CreateSolidBrush(RGB(38, 38, 38)));
|
||||
FillRect(hDC, &rc, aBgColorBrush.get());
|
||||
const Color aFrameColor = Application::GetSettings().GetStyleSettings().GetDisableColor();
|
||||
ScopedHBRUSH aFrameBrush(CreateSolidBrush(
|
||||
RGB(aFrameColor.GetRed(), aFrameColor.GetGreen(), aFrameColor.GetBlue())));
|
||||
FrameRect(hDC, &rc, aFrameBrush.get());
|
||||
|
||||
DrawThemeText(hTheme, hDC, iPart, iState, o3tl::toW(aCaption.getStr()), -1,
|
||||
DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &rc);
|
||||
return true;
|
||||
DrawThemeText(hTheme, hDC, iPart, iState, o3tl::toW(aCaption.getStr()), -1,
|
||||
DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &rc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
|
||||
|
|
Loading…
Reference in a new issue