Example: special case for Win11

1. On Win11 we don't need to paint the frame border, the OS will always draw one for us.
2. Fix the wrong coordinate of the right and bottom frame border of the widget example.
3. Improve the Qt Quick example.
4. Correctly detect the OS version when building against Qt below 5.9.
5. Other minor tweaks.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-01-07 11:10:28 +08:00
parent 7ddde978e8
commit e85e3f891e
6 changed files with 113 additions and 17 deletions

View File

@ -121,7 +121,7 @@ void MainWindow::changeEvent(QEvent *event)
void MainWindow::paintEvent(QPaintEvent *event)
{
QMainWindow::paintEvent(event);
if (windowState() == Qt::WindowNoState) {
if ((windowState() == Qt::WindowNoState) && !Utilities::isWin11OrGreater()) {
const int w = width();
const int h = height();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))

View File

@ -22,11 +22,71 @@
* SOFTWARE.
*/
#include "../../utilities.h"
#include "../../framelessquickhelper.h"
#include <QtGui/qguiapplication.h>
#include <QtQml/qqmlapplicationengine.h>
#include <QtQuickControls2/qquickstyle.h>
FRAMELESSHELPER_USE_NAMESPACE
static constexpr const char qtquicknamespace[] = "wangwenx190.Utils";
class UtilFunctions : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(UtilFunctions)
Q_PROPERTY(bool isWindowsHost READ isWindowsHost CONSTANT)
Q_PROPERTY(bool isWindows10OrGreater READ isWindows10OrGreater CONSTANT)
Q_PROPERTY(bool isWindows11OrGreater READ isWindows11OrGreater CONSTANT)
Q_PROPERTY(QColor activeFrameBorderColor READ activeFrameBorderColor CONSTANT)
Q_PROPERTY(QColor inactiveFrameBorderColor READ inactiveFrameBorderColor CONSTANT)
Q_PROPERTY(qreal frameBorderThickness READ frameBorderThickness CONSTANT)
public:
explicit UtilFunctions(QObject *parent = nullptr) : QObject(parent) {}
~UtilFunctions() override = default;
inline bool isWindowsHost() const {
#ifdef Q_OS_WINDOWS
return true;
#else
return false;
#endif
}
inline bool isWindows10OrGreater() const {
#ifdef Q_OS_WINDOWS
return Utilities::isWin10OrGreater();
#else
return false;
#endif
}
inline bool isWindows11OrGreater() const {
#ifdef Q_OS_WINDOWS
return Utilities::isWin11OrGreater();
#else
return false;
#endif
}
inline QColor activeFrameBorderColor() const {
const ColorizationArea area = Utilities::getColorizationArea();
const bool colorizedBorder = ((area == ColorizationArea::TitleBar_WindowBorder)
|| (area == ColorizationArea::All));
return (colorizedBorder ? Utilities::getColorizationColor() : Qt::black);
}
inline QColor inactiveFrameBorderColor() const {
return Qt::darkGray;
}
inline qreal frameBorderThickness() const {
return 1.0;
}
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
@ -48,7 +108,12 @@ int main(int argc, char *argv[])
QQuickStyle::setStyle(QStringLiteral("Default"));
#endif
qmlRegisterType<FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickHelper)>("wangwenx190.Utils", 1, 0, "FramelessHelper");
qmlRegisterSingletonType<UtilFunctions>(qtquicknamespace, 1, 0, "Utils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
return new UtilFunctions();
});
qmlRegisterType<FramelessQuickHelper>(qtquicknamespace, 1, 0, "FramelessHelper");
const QUrl mainQmlUrl(QStringLiteral("qrc:///qml/main.qml"));
const QMetaObject::Connection connection = QObject::connect(
@ -71,3 +136,5 @@ int main(int argc, char *argv[])
return QGuiApplication::exec();
}
#include "main.moc"

View File

@ -35,7 +35,7 @@ Window {
title: qsTr("Hello, World!")
color: "#f0f0f0"
property real _flh_margin: ((window.visibility === Window.Maximized) | (window.visibility === Window.FullScreen)) ? 0.0 : 1.0
property real _flh_margin: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)) ? 0 : Utils.frameBorderThickness
property var _win_prev_state: null
FramelessHelper {
@ -140,8 +140,9 @@ Window {
id: windowFrame
anchors.fill: parent
color: "transparent"
visible: !Utils.isWindows11OrGreater
border {
color: window.active ? "black" : "darkGray"
color: window.active ? Utils.activeFrameBorderColor : Utils.inactiveFrameBorderColor
width: window._flh_margin
}
}

View File

@ -136,18 +136,18 @@ void Widget::changeEvent(QEvent *event)
void Widget::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
if (!isMaximized() && !isFullScreen()) {
const auto w = static_cast<qreal>(width());
const auto h = static_cast<qreal>(height());
if ((windowState() == Qt::WindowNoState) && !Utilities::isWin11OrGreater()) {
const int w = width();
const int h = height();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
using BorderLines = QList<QLineF>;
using BorderLines = QList<QLine>;
#else
using BorderLines = QVector<QLineF>;
using BorderLines = QVector<QLine>;
#endif
const BorderLines lines = {
{0, 0, w, 0},
{w, 0, w , h},
{w, h, 0, h},
{w - 1, 0, w - 1, h},
{w, h - 1, 0, h - 1},
{0, h, 0, 0}
};
const ColorizationArea area = Utilities::getColorizationArea();

View File

@ -49,6 +49,7 @@ namespace Utilities
[[nodiscard]] FRAMELESSHELPER_API bool isWin8OrGreater();
[[nodiscard]] FRAMELESSHELPER_API bool isWin8Point1OrGreater();
[[nodiscard]] FRAMELESSHELPER_API bool isWin10OrGreater();
[[nodiscard]] FRAMELESSHELPER_API bool isWin11OrGreater();
[[nodiscard]] FRAMELESSHELPER_API bool isDwmCompositionAvailable();
FRAMELESSHELPER_API void triggerFrameChange(const WId winId);
FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset);

View File

@ -44,11 +44,23 @@ Q_DECLARE_METATYPE(QMargins)
FRAMELESSHELPER_BEGIN_NAMESPACE
[[nodiscard]] static inline QPointF extractMousePositionFromLParam(const LPARAM lParam)
#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0))
[[nodiscard]] static inline bool isWindowsVersionOrGreater(const DWORD dwMajor, const DWORD dwMinor, const DWORD dwBuild)
{
const POINT nativePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
return QPointF(static_cast<qreal>(nativePos.x), static_cast<qreal>(nativePos.y));
OSVERSIONINFOEXW osvi;
SecureZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
osvi.dwMajorVersion = dwMajor;
osvi.dwMinorVersion = dwMinor;
osvi.dwBuildNumber = dwBuild;
DWORDLONG dwlConditionMask = 0;
const auto op = VER_GREATER_EQUAL;
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, op);
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, op);
return (VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask) != FALSE);
}
#endif
[[nodiscard]] static inline bool isWin10RS5OrGreater()
{
@ -57,7 +69,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17763));
#else
static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10);
static const bool result = isWindowsVersionOrGreater(10, 0, 17763);
#endif
return result;
}
@ -69,7 +81,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 18362));
#else
static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10);
static const bool result = isWindowsVersionOrGreater(10, 0, 18362);
#endif
return result;
}
@ -137,6 +149,18 @@ bool Utilities::isWin10OrGreater()
return result;
}
bool Utilities::isWin11OrGreater()
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11);
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 22000));
#else
static const bool result = isWindowsVersionOrGreater(10, 0, 22000);
#endif
return result;
}
bool Utilities::isDwmCompositionAvailable()
{
// DWM composition is always enabled and can't be disabled since Windows 8.
@ -454,7 +478,10 @@ bool Utilities::isSystemMenuRequested(const void *data, QPointF *pos)
}
if (result) {
if (pos) {
*pos = extractMousePositionFromLParam(msg->lParam);
*pos = [msg](){
const POINT nativePos = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
return QPointF(static_cast<qreal>(nativePos.x), static_cast<qreal>(nativePos.y));
}();
}
}
return result;