Minor tweaks

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2021-09-01 15:26:36 +08:00
parent 01dd43c356
commit 2c106ffef9
23 changed files with 182 additions and 252 deletions

View File

@ -16,8 +16,8 @@ win32 {
CONFIG += windeployqt CONFIG += windeployqt
CONFIG -= embed_manifest_exe CONFIG -= embed_manifest_exe
LIBS += -luser32 -lshell32 -ldwmapi LIBS += -luser32 -lshell32 -ldwmapi
RC_FILE = $$PWD/windows.rc RC_FILE = $$PWD/example.rc
OTHER_FILES += $$PWD/windows.manifest OTHER_FILES += $$PWD/example.manifest
} }
win32 { win32 {
CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../debug -lFramelessHelperd CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../debug -lFramelessHelperd

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="org.wangwenx190.framelessapplication" version="1.0.0.0"/> <assemblyIdentity type="win32" name="org.wangwenx190.framelesshelper.demo" version="1.0.0.0"/>
<dependency> <dependency>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>

View File

@ -24,9 +24,9 @@
#include <windows.h> #include <windows.h>
IDI_ICON1 ICON "windows.ico" IDI_ICON1 ICON "example.ico"
//CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "windows.manifest" //CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "example.manifest"
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0 FILEVERSION 1,0,0,0
@ -45,14 +45,11 @@ BEGIN
BEGIN BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "Comments", "Built by the Qt Toolkit."
VALUE "CompanyName", "wangwenx190" VALUE "CompanyName", "wangwenx190"
VALUE "FileDescription", "A FramelessHelper based Qt application." VALUE "FileDescription", "FramelessHelper Demo Application"
VALUE "FileVersion", "1.0.0.0" VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", ""
VALUE "LegalCopyright", "MIT License" VALUE "LegalCopyright", "MIT License"
VALUE "OriginalFilename", "" VALUE "ProductName", "Demo"
VALUE "ProductName", "Test Application"
VALUE "ProductVersion", "1.0.0.0" VALUE "ProductVersion", "1.0.0.0"
END END
END END

View File

@ -18,7 +18,7 @@ set(SOURCES
if(WIN32) if(WIN32)
enable_language(RC) enable_language(RC)
list(APPEND SOURCES ../windows.rc ../windows.manifest) list(APPEND SOURCES ../example.rc ../example.manifest)
endif() endif()
add_executable(MainWindow WIN32 ${SOURCES}) add_executable(MainWindow WIN32 ${SOURCES})

View File

@ -131,7 +131,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>WIndow Title</string> <string>Window Title</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>

View File

@ -28,22 +28,10 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// High DPI scaling is enabled by default from Qt 6
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
// Windows: we are using the manifest file to get maximum compatibility
// because some APIs are not supprted on old systems such as Windows 7
// and Windows 8. And once we have set the DPI awareness level in the
// manifest file, any attemptation to try to change it through API will
// fail. In other words, Qt won't be able to enable or disable high DPI
// scaling or change the DPI awareness level once we have set it in the
// manifest file. So the following two lines are uesless actually (However,
// they are still useful on other platforms).
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
// Don't round the scale factor.
// This will break QWidget applications because they can't render correctly.
// Qt Quick applications won't have this issue.
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif #endif
#endif #endif
@ -51,7 +39,6 @@ int main(int argc, char *argv[])
QApplication application(argc, argv); QApplication application(argc, argv);
MainWindow mainWindow; MainWindow mainWindow;
mainWindow.resize(800, 600);
mainWindow.show(); mainWindow.show();
return QApplication::exec(); return QApplication::exec();

View File

@ -33,6 +33,8 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(par
setAttribute(Qt::WA_DontCreateNativeAncestors); setAttribute(Qt::WA_DontCreateNativeAncestors);
createWinId(); createWinId();
resize(800, 600);
appMainWindow = new Ui::MainWindow; appMainWindow = new Ui::MainWindow;
appMainWindow->setupUi(this); appMainWindow->setupUi(this);
@ -60,6 +62,8 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(par
titleBarWidget->maximizeButton->setChecked(isMaximized()); titleBarWidget->maximizeButton->setChecked(isMaximized());
titleBarWidget->maximizeButton->setToolTip(isMaximized() ? tr("Restore") : tr("Maximize")); titleBarWidget->maximizeButton->setToolTip(isMaximized() ? tr("Restore") : tr("Maximize"));
}); });
setWindowTitle(tr("Hello, World!"));
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()

View File

@ -15,7 +15,7 @@ set(SOURCES
if(WIN32) if(WIN32)
enable_language(RC) enable_language(RC)
list(APPEND SOURCES ../windows.rc ../windows.manifest) list(APPEND SOURCES ../example.rc ../example.manifest)
endif() endif()
add_executable(Quick WIN32 ${SOURCES}) add_executable(Quick WIN32 ${SOURCES})

View File

@ -30,22 +30,10 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// High DPI scaling is enabled by default from Qt 6
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
// Windows: we are using the manifest file to get maximum compatibility
// because some APIs are not supprted on old systems such as Windows 7
// and Windows 8. And once we have set the DPI awareness level in the
// manifest file, any attemptation to try to change it through API will
// fail. In other words, Qt won't be able to enable or disable high DPI
// scaling or change the DPI awareness level once we have set it in the
// manifest file. So the following two lines are uesless actually (However,
// they are still useful on other platforms).
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
// Don't round the scale factor.
// This will break QWidget applications because they can't render correctly.
// Qt Quick applications won't have this issue.
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif #endif
#endif #endif

View File

@ -16,7 +16,7 @@ set(SOURCES
if(WIN32) if(WIN32)
enable_language(RC) enable_language(RC)
list(APPEND SOURCES ../windows.rc ../windows.manifest) list(APPEND SOURCES ../example.rc ../example.manifest)
endif() endif()
add_executable(Widget WIN32 ${SOURCES}) add_executable(Widget WIN32 ${SOURCES})

View File

@ -28,22 +28,10 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// High DPI scaling is enabled by default from Qt 6
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
// Windows: we are using the manifest file to get maximum compatibility
// because some APIs are not supprted on old systems such as Windows 7
// and Windows 8. And once we have set the DPI awareness level in the
// manifest file, any attemptation to try to change it through API will
// fail. In other words, Qt won't be able to enable or disable high DPI
// scaling or change the DPI awareness level once we have set it in the
// manifest file. So the following two lines are uesless actually (However,
// they are still useful on other platforms).
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
// Don't round the scale factor.
// This will break QWidget applications because they can't render correctly.
// Qt Quick applications won't have this issue.
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif #endif
#endif #endif
@ -51,7 +39,6 @@ int main(int argc, char *argv[])
QApplication application(argc, argv); QApplication application(argc, argv);
Widget widget; Widget widget;
widget.resize(800, 600);
widget.show(); widget.show();
return QApplication::exec(); return QApplication::exec();

View File

@ -113,10 +113,12 @@ void Widget::paintEvent(QPaintEvent *event)
void Widget::setupUi() void Widget::setupUi()
{ {
setWindowTitle(tr("Hello, World!"));
resize(800, 600);
const QWindow *win = windowHandle(); const QWindow *win = windowHandle();
const int resizeBorderHeight = Utilities::getSystemMetric(win, SystemMetric::ResizeBorderHeight, false); const int resizeBorderThickness = Utilities::getSystemMetric(win, SystemMetric::ResizeBorderThickness, false);
const int titleBarHeight = Utilities::getSystemMetric(win, SystemMetric::TitleBarHeight, false); const int titleBarHeight = Utilities::getSystemMetric(win, SystemMetric::TitleBarHeight, false);
const int systemButtonHeight = titleBarHeight + resizeBorderHeight; const int systemButtonHeight = titleBarHeight + resizeBorderThickness;
const QSize systemButtonSize = {qRound(static_cast<qreal>(systemButtonHeight) * 1.5), systemButtonHeight}; const QSize systemButtonSize = {qRound(static_cast<qreal>(systemButtonHeight) * 1.5), systemButtonHeight};
m_minimizeButton = new QPushButton(this); m_minimizeButton = new QPushButton(this);
m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton")); m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton"));

View File

@ -26,11 +26,11 @@
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
#include "utilities.h"
#include "framelesswindowsmanager.h"
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include "framelesswindowsmanager.h"
#include "utilities.h"
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -44,7 +44,7 @@ void FramelessHelper::removeWindowFrame(QWindow *window)
} }
window->setFlags(window->flags() | Qt::FramelessWindowHint); window->setFlags(window->flags() | Qt::FramelessWindowHint);
window->installEventFilter(this); window->installEventFilter(this);
window->setProperty(Constants::framelessMode_flag, true); window->setProperty(Constants::kFramelessModeFlag, true);
} }
void FramelessHelper::bringBackWindowFrame(QWindow *window) void FramelessHelper::bringBackWindowFrame(QWindow *window)
@ -55,7 +55,7 @@ void FramelessHelper::bringBackWindowFrame(QWindow *window)
} }
window->removeEventFilter(this); window->removeEventFilter(this);
window->setFlags(window->flags() & ~Qt::FramelessWindowHint); window->setFlags(window->flags() & ~Qt::FramelessWindowHint);
window->setProperty(Constants::framelessMode_flag, false); window->setProperty(Constants::kFramelessModeFlag, false);
} }
bool FramelessHelper::eventFilter(QObject *object, QEvent *event) bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
@ -75,8 +75,7 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
return false; return false;
} }
const auto window = qobject_cast<QWindow *>(object); const auto window = qobject_cast<QWindow *>(object);
const int resizeBorderWidth = FramelessWindowsManager::getResizeBorderWidth(window); const int resizeBorderThickness = FramelessWindowsManager::getResizeBorderThickness(window);
const int resizeBorderHeight = FramelessWindowsManager::getResizeBorderHeight(window);
const int titleBarHeight = FramelessWindowsManager::getTitleBarHeight(window); const int titleBarHeight = FramelessWindowsManager::getTitleBarHeight(window);
const bool resizable = FramelessWindowsManager::getResizable(window); const bool resizable = FramelessWindowsManager::getResizable(window);
const int windowWidth = window->width(); const int windowWidth = window->width();
@ -86,30 +85,30 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
#else #else
const QPoint localMousePosition = mouseEvent->windowPos().toPoint(); const QPoint localMousePosition = mouseEvent->windowPos().toPoint();
#endif #endif
const Qt::Edges edges = [window, resizeBorderWidth, resizeBorderHeight, windowWidth, &localMousePosition] { const Qt::Edges edges = [window, resizeBorderThickness, windowWidth, &localMousePosition] {
const int windowHeight = window->height(); const int windowHeight = window->height();
if (localMousePosition.y() <= resizeBorderHeight) { if (localMousePosition.y() <= resizeBorderThickness) {
if (localMousePosition.x() <= resizeBorderWidth) { if (localMousePosition.x() <= resizeBorderThickness) {
return Qt::TopEdge | Qt::LeftEdge; return Qt::TopEdge | Qt::LeftEdge;
} }
if (localMousePosition.x() >= (windowWidth - resizeBorderWidth)) { if (localMousePosition.x() >= (windowWidth - resizeBorderThickness)) {
return Qt::TopEdge | Qt::RightEdge; return Qt::TopEdge | Qt::RightEdge;
} }
return Qt::Edges{Qt::TopEdge}; return Qt::Edges{Qt::TopEdge};
} }
if (localMousePosition.y() >= (windowHeight - resizeBorderHeight)) { if (localMousePosition.y() >= (windowHeight - resizeBorderThickness)) {
if (localMousePosition.x() <= resizeBorderWidth) { if (localMousePosition.x() <= resizeBorderThickness) {
return Qt::BottomEdge | Qt::LeftEdge; return Qt::BottomEdge | Qt::LeftEdge;
} }
if (localMousePosition.x() >= (windowWidth - resizeBorderWidth)) { if (localMousePosition.x() >= (windowWidth - resizeBorderThickness)) {
return Qt::BottomEdge | Qt::RightEdge; return Qt::BottomEdge | Qt::RightEdge;
} }
return Qt::Edges{Qt::BottomEdge}; return Qt::Edges{Qt::BottomEdge};
} }
if (localMousePosition.x() <= resizeBorderWidth) { if (localMousePosition.x() <= resizeBorderThickness) {
return Qt::Edges{Qt::LeftEdge}; return Qt::Edges{Qt::LeftEdge};
} }
if (localMousePosition.x() >= (windowWidth - resizeBorderWidth)) { if (localMousePosition.x() >= (windowWidth - resizeBorderThickness)) {
return Qt::Edges{Qt::RightEdge}; return Qt::Edges{Qt::RightEdge};
} }
return Qt::Edges{}; return Qt::Edges{};
@ -125,10 +124,10 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
&& !hitTestVisible; && !hitTestVisible;
} }
if (window->windowState() == Qt::WindowNoState) { if (window->windowState() == Qt::WindowNoState) {
isInTitlebarArea = (localMousePosition.y() > resizeBorderHeight) isInTitlebarArea = (localMousePosition.y() > resizeBorderThickness)
&& (localMousePosition.y() <= (titleBarHeight + resizeBorderHeight)) && (localMousePosition.y() <= (titleBarHeight + resizeBorderThickness))
&& (localMousePosition.x() > resizeBorderWidth) && (localMousePosition.x() > resizeBorderThickness)
&& (localMousePosition.x() < (windowWidth - resizeBorderWidth)) && (localMousePosition.x() < (windowWidth - resizeBorderThickness))
&& !hitTestVisible; && !hitTestVisible;
} }

View File

@ -88,15 +88,14 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
namespace Constants namespace Constants
{ {
[[maybe_unused]] const char framelessMode_flag[] = "_FRAMELESSHELPER_FRAMELESS_MODE"; [[maybe_unused]] constexpr char kFramelessModeFlag[] = "_FRAMELESSHELPER_FRAMELESS_MODE";
[[maybe_unused]] const char resizeBorderWidth_flag[] = "_FRAMELESSHELPER_RESIZE_BORDER_WIDTH"; [[maybe_unused]] constexpr char kResizeBorderThicknessFlag[] = "_FRAMELESSHELPER_RESIZE_BORDER_THICKNESS";
[[maybe_unused]] const char resizeBorderHeight_flag[] = "_FRAMELESSHELPER_RESIZE_BORDER_HEIGHT"; [[maybe_unused]] constexpr char kTitleBarHeightFlag[] = "_FRAMELESSHELPER_TITLE_BAR_HEIGHT";
[[maybe_unused]] const char titleBarHeight_flag[] = "_FRAMELESSHELPER_TITLE_BAR_HEIGHT"; [[maybe_unused]] constexpr char kHitTestVisibleInChromeFlag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE_IN_CHROME";
[[maybe_unused]] const char hitTestVisibleInChrome_flag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE_IN_CHROME"; [[maybe_unused]] constexpr char kUseNativeTitleBarFlag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR";
[[maybe_unused]] const char useNativeTitleBar_flag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR"; [[maybe_unused]] constexpr char kPreserveNativeFrameFlag[] = "_FRAMELESSHELPER_PRESERVE_NATIVE_WINDOW_FRAME";
[[maybe_unused]] const char preserveNativeFrame_flag[] = "_FRAMELESSHELPER_PRESERVE_NATIVE_WINDOW_FRAME"; [[maybe_unused]] constexpr char kForcePreserveNativeFrameFlag[] = "_FRAMELESSHELPER_FORCE_PRESERVE_NATIVE_WINDOW_FRAME";
[[maybe_unused]] const char forcePreserveNativeFrame_flag[] = "_FRAMELESSHELPER_FORCE_PRESERVE_NATIVE_WINDOW_FRAME"; [[maybe_unused]] constexpr char kWindowFixedSizeFlag[] = "_FRAMELESSHELPER_WINDOW_FIXED_SIZE";
[[maybe_unused]] const char windowFixedSize_flag[] = "_FRAMELESSHELPER_WINDOW_FIXED_SIZE";
} }

View File

@ -26,8 +26,8 @@
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtGui/qwindow.h>
#include <QtCore/qt_windows.h> #include <QtCore/qt_windows.h>
#include <QtGui/qwindow.h>
#include <shellapi.h> #include <shellapi.h>
#include "utilities.h" #include "utilities.h"
@ -48,12 +48,12 @@
#ifndef IsMinimized #ifndef IsMinimized
// Only available since Windows 2000 // Only available since Windows 2000
#define IsMinimized(window) (IsIconic(window)) #define IsMinimized(window) (IsIconic(window) != FALSE)
#endif #endif
#ifndef IsMaximized #ifndef IsMaximized
// Only available since Windows 2000 // Only available since Windows 2000
#define IsMaximized(window) (IsZoomed(window)) #define IsMaximized(window) (IsZoomed(window) != FALSE)
#endif #endif
#ifndef GET_X_LPARAM #ifndef GET_X_LPARAM
@ -68,6 +68,9 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
// The thickness of an auto-hide taskbar in pixels.
static constexpr int kAutoHideTaskbarThickness = 2;
[[nodiscard]] static inline bool shouldHaveWindowFrame() [[nodiscard]] static inline bool shouldHaveWindowFrame()
{ {
if (Utilities::shouldUseNativeTitleBar()) { if (Utilities::shouldUseNativeTitleBar()) {
@ -75,8 +78,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
// want to use the native title bar. // want to use the native title bar.
return true; return true;
} }
const bool should = qEnvironmentVariableIsSet(Constants::preserveNativeFrame_flag); const bool should = qEnvironmentVariableIsSet(Constants::kPreserveNativeFrameFlag);
const bool force = qEnvironmentVariableIsSet(Constants::forcePreserveNativeFrame_flag); const bool force = qEnvironmentVariableIsSet(Constants::kForcePreserveNativeFrameFlag);
if (should || force) { if (should || force) {
if (force) { if (force) {
return true; return true;
@ -90,10 +93,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
return false; return false;
} }
// The thickness of an auto-hide taskbar in pixels.
static const int kAutoHideTaskbarThicknessPx = 2;
static const int kAutoHideTaskbarThicknessPy = kAutoHideTaskbarThicknessPx;
struct FramelessHelperWinData struct FramelessHelperWinData
{ {
[[nodiscard]] bool create() { [[nodiscard]] bool create() {
@ -162,7 +161,7 @@ static inline void installHelper(QWindow *window, const bool enable)
const WId winId = window->winId(); const WId winId = window->winId();
Utilities::updateFrameMargins(winId, !enable); Utilities::updateFrameMargins(winId, !enable);
Utilities::triggerFrameChange(winId); Utilities::triggerFrameChange(winId);
window->setProperty(Constants::framelessMode_flag, enable); window->setProperty(Constants::kFramelessModeFlag, enable);
} }
FramelessHelperWin::FramelessHelperWin() = default; FramelessHelperWin::FramelessHelperWin() = default;
@ -212,7 +211,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return false; return false;
} }
const QWindow *window = Utilities::findWindow(reinterpret_cast<WId>(msg->hwnd)); const QWindow *window = Utilities::findWindow(reinterpret_cast<WId>(msg->hwnd));
if (!window || !window->property(Constants::framelessMode_flag).toBool()) { if (!window || !window->property(Constants::kFramelessModeFlag).toBool()) {
return false; return false;
} }
switch (msg->message) { switch (msg->message) {
@ -291,18 +290,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break; break;
} }
if (!msg->wParam) { if (msg->wParam == FALSE) {
*result = 0; *result = 0;
return true; return true;
} }
bool nonClientAreaExists = false;
const auto clientRect = &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0]); const auto clientRect = &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0]);
if (shouldHaveWindowFrame()) { if (shouldHaveWindowFrame()) {
// Store the original top before the default window proc // Store the original top before the default window proc
// applies the default frame. // applies the default frame.
const LONG originalTop = clientRect->top; const LONG originalTop = clientRect->top;
// Apply the default frame // Apply the default frame
const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam); const LRESULT ret = DefWindowProcW(msg->hwnd, WM_NCCALCSIZE, TRUE, msg->lParam);
if (ret != 0) { if (ret != 0) {
*result = ret; *result = ret;
return true; return true;
@ -311,6 +309,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// default frame was applied. // default frame was applied.
clientRect->top = originalTop; clientRect->top = originalTop;
} }
bool nonClientAreaExists = false;
// We don't need this correction when we're fullscreen. We will // We don't need this correction when we're fullscreen. We will
// have the WS_POPUP size, so we don't have to worry about // have the WS_POPUP size, so we don't have to worry about
// borders, and the default frame will be fine. // borders, and the default frame will be fine.
@ -321,13 +320,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// then the window is clipped to the monitor so that the resize handle // then the window is clipped to the monitor so that the resize handle
// do not appear because you don't need them (because you can't resize // do not appear because you don't need them (because you can't resize
// a window when it's maximized unless you restore it). // a window when it's maximized unless you restore it).
const int rbh = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderHeight, true); const int rbt = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true);
clientRect->top += rbh; clientRect->top += rbt;
if (!shouldHaveWindowFrame()) { if (!shouldHaveWindowFrame()) {
clientRect->bottom -= rbh; clientRect->bottom -= rbt;
const int rbw = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderWidth, true); clientRect->left += rbt;
clientRect->left += rbw; clientRect->right -= rbt;
clientRect->right -= rbw;
} }
nonClientAreaExists = true; nonClientAreaExists = true;
} }
@ -353,7 +351,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo); monitorInfo.cbSize = sizeof(monitorInfo);
const HMONITOR monitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST); const HMONITOR monitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST);
GetMonitorInfoW(monitor, &monitorInfo); if (!monitor) {
qWarning() << "Failed to retrieve the screen that contains the current window.";
break;
}
if (GetMonitorInfoW(monitor, &monitorInfo) == FALSE) {
qWarning() << "Failed to retrieve the screen information.";
break;
}
// This helper can be used to determine if there's a // This helper can be used to determine if there's a
// auto-hide taskbar on the given edge of the monitor // auto-hide taskbar on the given edge of the monitor
// we're currently on. // we're currently on.
@ -364,7 +369,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
_abd.uEdge = edge; _abd.uEdge = edge;
_abd.rc = monitorInfo.rcMonitor; _abd.rc = monitorInfo.rcMonitor;
const auto hTaskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &_abd)); const auto hTaskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &_abd));
return hTaskbar != nullptr; return (hTaskbar != nullptr);
}; };
top = hasAutohideTaskbar(ABE_TOP); top = hasAutohideTaskbar(ABE_TOP);
bottom = hasAutohideTaskbar(ABE_BOTTOM); bottom = hasAutohideTaskbar(ABE_BOTTOM);
@ -380,16 +385,27 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
_abd.hWnd = FindWindowW(L"Shell_TrayWnd", nullptr); _abd.hWnd = FindWindowW(L"Shell_TrayWnd", nullptr);
if (_abd.hWnd) { if (_abd.hWnd) {
const HMONITOR windowMonitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST); const HMONITOR windowMonitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST);
if (!windowMonitor) {
qWarning() << "Failed to retrieve the screen that contains the current window.";
break;
}
const HMONITOR taskbarMonitor = MonitorFromWindow(_abd.hWnd, MONITOR_DEFAULTTOPRIMARY); const HMONITOR taskbarMonitor = MonitorFromWindow(_abd.hWnd, MONITOR_DEFAULTTOPRIMARY);
if (!taskbarMonitor) {
qWarning() << "Failed to retrieve the screen that contains the task bar.";
break;
}
if (taskbarMonitor == windowMonitor) { if (taskbarMonitor == windowMonitor) {
SHAppBarMessage(ABM_GETTASKBARPOS, &_abd); SHAppBarMessage(ABM_GETTASKBARPOS, &_abd);
edge = _abd.uEdge; edge = _abd.uEdge;
} }
} else {
qWarning() << "Failed to retrieve the task bar window handle.";
break;
} }
top = edge == ABE_TOP; top = (edge == ABE_TOP);
bottom = edge == ABE_BOTTOM; bottom = (edge == ABE_BOTTOM);
left = edge == ABE_LEFT; left = (edge == ABE_LEFT);
right = edge == ABE_RIGHT; right = (edge == ABE_RIGHT);
} }
// If there's a taskbar on any side of the monitor, reduce // If there's a taskbar on any side of the monitor, reduce
// our size a little bit on that edge. // our size a little bit on that edge.
@ -403,16 +419,16 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// This does however work fine for maximized. // This does however work fine for maximized.
if (top) { if (top) {
// Peculiarly, when we're fullscreen, // Peculiarly, when we're fullscreen,
clientRect->top += kAutoHideTaskbarThicknessPy; clientRect->top += kAutoHideTaskbarThickness;
nonClientAreaExists = true; nonClientAreaExists = true;
} else if (bottom) { } else if (bottom) {
clientRect->bottom -= kAutoHideTaskbarThicknessPy; clientRect->bottom -= kAutoHideTaskbarThickness;
nonClientAreaExists = true; nonClientAreaExists = true;
} else if (left) { } else if (left) {
clientRect->left += kAutoHideTaskbarThicknessPx; clientRect->left += kAutoHideTaskbarThickness;
nonClientAreaExists = true; nonClientAreaExists = true;
} else if (right) { } else if (right) {
clientRect->right -= kAutoHideTaskbarThicknessPx; clientRect->right -= kAutoHideTaskbarThickness;
nonClientAreaExists = true; nonClientAreaExists = true;
} }
} }
@ -481,12 +497,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-ncactivate // https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-ncactivate
// Don't use "*result = 0" otherwise the window won't respond // Don't use "*result = 0" otherwise the window won't respond
// to the window active state change. // to the window active state change.
*result = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, -1); *result = DefWindowProcW(msg->hwnd, WM_NCACTIVATE, msg->wParam, -1);
} else {
if (static_cast<BOOL>(msg->wParam)) {
*result = FALSE;
} else { } else {
if (msg->wParam == FALSE) {
*result = TRUE; *result = TRUE;
} else {
*result = FALSE;
} }
} }
return true; return true;
@ -562,15 +578,19 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break; break;
} }
POINT winLocalMouse = {0, 0}; POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
GetCursorPos(&winLocalMouse); // Or {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)} if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) {
ScreenToClient(msg->hwnd, &winLocalMouse); qWarning() << "Failed to translate global screen coordinate to local window coordinate.";
break;
}
const QPointF localMouse = {static_cast<qreal>(winLocalMouse.x), static_cast<qreal>(winLocalMouse.y)}; const QPointF localMouse = {static_cast<qreal>(winLocalMouse.x), static_cast<qreal>(winLocalMouse.y)};
RECT clientRect = {0, 0, 0, 0}; RECT clientRect = {0, 0, 0, 0};
GetClientRect(msg->hwnd, &clientRect); if (GetClientRect(msg->hwnd, &clientRect) == FALSE) {
qWarning() << "Failed to retrieve the client rect of the current window.";
break;
}
const LONG ww = clientRect.right; const LONG ww = clientRect.right;
const int rbw = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderWidth, true); const int rbt = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true);
const int rbh = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderHeight, true);
const int tbh = Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, true); const int tbh = Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, true);
bool isTitleBar = false; bool isTitleBar = false;
if (IsMaximized(msg->hwnd) || (window->windowState() == Qt::WindowFullScreen)) { if (IsMaximized(msg->hwnd) || (window->windowState() == Qt::WindowFullScreen)) {
@ -579,15 +599,15 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
&& !Utilities::isHitTestVisibleInChrome(window); && !Utilities::isHitTestVisibleInChrome(window);
} }
if (window->windowState() == Qt::WindowNoState) { if (window->windowState() == Qt::WindowNoState) {
isTitleBar = (localMouse.y() > rbh) && (localMouse.y() <= (rbh + tbh)) isTitleBar = (localMouse.y() > rbt) && (localMouse.y() <= (rbt + tbh))
&& (localMouse.x() > rbw) && (localMouse.x() < (ww - rbw)) && (localMouse.x() > rbt) && (localMouse.x() < (ww - rbt))
&& !Utilities::isHitTestVisibleInChrome(window); && !Utilities::isHitTestVisibleInChrome(window);
} }
const bool isTop = localMouse.y() <= rbh; const bool isTop = localMouse.y() <= rbt;
if (shouldHaveWindowFrame()) { if (shouldHaveWindowFrame()) {
// This will handle the left, right and bottom parts of the frame // This will handle the left, right and bottom parts of the frame
// because we didn't change them. // because we didn't change them.
const LRESULT originalRet = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam); const LRESULT originalRet = DefWindowProcW(msg->hwnd, WM_NCHITTEST, 0, msg->lParam);
if (originalRet != HTCLIENT) { if (originalRet != HTCLIENT) {
*result = originalRet; *result = originalRet;
return true; return true;
@ -608,19 +628,19 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
*result = HTCLIENT; *result = HTCLIENT;
return true; return true;
} else { } else {
const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, rbw, rbh, ww, isTop, window] { const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, rbt, ww, isTop, window]{
const LONG wh = clientRect.bottom;
if (IsMaximized(msg->hwnd)) { if (IsMaximized(msg->hwnd)) {
if (isTitleBar) { if (isTitleBar) {
return HTCAPTION; return HTCAPTION;
} }
return HTCLIENT; return HTCLIENT;
} }
const bool isBottom = (localMouse.y() >= (wh - rbh)); const LONG wh = clientRect.bottom;
const bool isBottom = (localMouse.y() >= (wh - rbt));
// Make the border a little wider to let the user easy to resize on corners. // Make the border a little wider to let the user easy to resize on corners.
const qreal factor = (isTop || isBottom) ? 2.0 : 1.0; const qreal factor = (isTop || isBottom) ? 2.0 : 1.0;
const bool isLeft = (localMouse.x() <= qRound(static_cast<qreal>(rbw) * factor)); const bool isLeft = (localMouse.x() <= qRound(static_cast<qreal>(rbt) * factor));
const bool isRight = (localMouse.x() >= (ww - qRound(static_cast<qreal>(rbw) * factor))); const bool isRight = (localMouse.x() >= (ww - qRound(static_cast<qreal>(rbt) * factor)));
const bool fixedSize = Utilities::isWindowFixedSize(window); const bool fixedSize = Utilities::isWindowFixedSize(window);
const auto getBorderValue = [fixedSize](int value) -> int { const auto getBorderValue = [fixedSize](int value) -> int {
return fixedSize ? HTCLIENT : value; return fixedSize ? HTCLIENT : value;
@ -653,7 +673,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return HTCAPTION; return HTCAPTION;
} }
return HTCLIENT; return HTCLIENT;
} (); }();
*result = hitTestResult; *result = hitTestResult;
return true; return true;
} }

View File

@ -32,26 +32,15 @@ FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(pare
{ {
} }
qreal FramelessQuickHelper::resizeBorderWidth() const qreal FramelessQuickHelper::resizeBorderThickness() const
{ {
return FramelessWindowsManager::getResizeBorderWidth(window()); return FramelessWindowsManager::getResizeBorderThickness(window());
} }
void FramelessQuickHelper::setResizeBorderWidth(const qreal val) void FramelessQuickHelper::setResizeBorderThickness(const qreal val)
{ {
FramelessWindowsManager::setResizeBorderWidth(window(), qRound(val)); FramelessWindowsManager::setResizeBorderThickness(window(), qRound(val));
Q_EMIT resizeBorderWidthChanged(val); Q_EMIT resizeBorderThicknessChanged(val);
}
qreal FramelessQuickHelper::resizeBorderHeight() const
{
return FramelessWindowsManager::getResizeBorderHeight(window());
}
void FramelessQuickHelper::setResizeBorderHeight(const qreal val)
{
FramelessWindowsManager::setResizeBorderHeight(window(), qRound(val));
Q_EMIT resizeBorderHeightChanged(val);
} }
qreal FramelessQuickHelper::titleBarHeight() const qreal FramelessQuickHelper::titleBarHeight() const

View File

@ -36,8 +36,7 @@ class FRAMELESSHELPER_API FramelessQuickHelper : public QQuickItem
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessHelper) QML_NAMED_ELEMENT(FramelessHelper)
#endif #endif
Q_PROPERTY(qreal resizeBorderWidth READ resizeBorderWidth WRITE setResizeBorderWidth NOTIFY resizeBorderWidthChanged) Q_PROPERTY(qreal resizeBorderThickness READ resizeBorderThickness WRITE setResizeBorderThickness NOTIFY resizeBorderThicknessChanged)
Q_PROPERTY(qreal resizeBorderHeight READ resizeBorderHeight WRITE setResizeBorderHeight NOTIFY resizeBorderHeightChanged)
Q_PROPERTY(qreal titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged) Q_PROPERTY(qreal titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged)
Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged) Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged)
@ -45,11 +44,8 @@ public:
explicit FramelessQuickHelper(QQuickItem *parent = nullptr); explicit FramelessQuickHelper(QQuickItem *parent = nullptr);
~FramelessQuickHelper() override = default; ~FramelessQuickHelper() override = default;
Q_NODISCARD qreal resizeBorderWidth() const; Q_NODISCARD qreal resizeBorderThickness() const;
void setResizeBorderWidth(const qreal val); void setResizeBorderThickness(const qreal val);
Q_NODISCARD qreal resizeBorderHeight() const;
void setResizeBorderHeight(const qreal val);
Q_NODISCARD qreal titleBarHeight() const; Q_NODISCARD qreal titleBarHeight() const;
void setTitleBarHeight(const qreal val); void setTitleBarHeight(const qreal val);
@ -64,8 +60,7 @@ public Q_SLOTS:
void setHitTestVisibleInChrome(QQuickItem *item, const bool visible); void setHitTestVisibleInChrome(QQuickItem *item, const bool visible);
Q_SIGNALS: Q_SIGNALS:
void resizeBorderWidthChanged(qreal); void resizeBorderThicknessChanged(qreal);
void resizeBorderHeightChanged(qreal);
void titleBarHeightChanged(qreal); void titleBarHeightChanged(qreal);
void resizableChanged(bool); void resizableChanged(bool);
}; };

View File

@ -23,17 +23,17 @@
*/ */
#include "framelesswindowsmanager.h" #include "framelesswindowsmanager.h"
#include <QtCore/qvariant.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include "utilities.h"
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION #ifdef FRAMELESSHELPER_USE_UNIX_VERSION
#include "framelesshelper.h" #include "framelesshelper.h"
#else #else
#include <QtGui/qscreen.h> #include <QtGui/qscreen.h>
#include "framelesshelper_win32.h" #include "framelesshelper_win32.h"
#endif #endif
#include "utilities.h"
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -73,7 +73,7 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject
qWarning() << object << "is not a QWidget or QQuickItem."; qWarning() << object << "is not a QWidget or QQuickItem.";
return; return;
} }
auto objList = qvariant_cast<QObjectList>(window->property(Constants::hitTestVisibleInChrome_flag)); auto objList = qvariant_cast<QObjectList>(window->property(Constants::kHitTestVisibleInChromeFlag));
if (value) { if (value) {
if (objList.isEmpty() || !objList.contains(object)) { if (objList.isEmpty() || !objList.contains(object)) {
objList.append(object); objList.append(object);
@ -83,53 +83,30 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject
objList.removeAll(object); objList.removeAll(object);
} }
} }
window->setProperty(Constants::hitTestVisibleInChrome_flag, QVariant::fromValue(objList)); window->setProperty(Constants::kHitTestVisibleInChromeFlag, QVariant::fromValue(objList));
} }
int FramelessWindowsManager::getResizeBorderWidth(const QWindow *window) int FramelessWindowsManager::getResizeBorderThickness(const QWindow *window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
if (!window) { if (!window) {
return 8; return 8;
} }
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION #ifdef FRAMELESSHELPER_USE_UNIX_VERSION
const int value = window->property(Constants::resizeBorderWidth_flag).toInt(); const int value = window->property(Constants::kResizeBorderThicknessFlag).toInt();
return value <= 0 ? 8 : value; return value <= 0 ? 8 : value;
#else #else
return Utilities::getSystemMetric(window, SystemMetric::ResizeBorderWidth, false); return Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, false);
#endif #endif
} }
void FramelessWindowsManager::setResizeBorderWidth(QWindow *window, const int value) void FramelessWindowsManager::setResizeBorderThickness(QWindow *window, const int value)
{ {
Q_ASSERT(window); Q_ASSERT(window);
if (!window || (value <= 0)) { if (!window || (value <= 0)) {
return; return;
} }
window->setProperty(Constants::resizeBorderWidth_flag, value); window->setProperty(Constants::kResizeBorderThicknessFlag, value);
}
int FramelessWindowsManager::getResizeBorderHeight(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return 8;
}
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION
const int value = window->property(Constants::resizeBorderHeight_flag).toInt();
return value <= 0 ? 8 : value;
#else
return Utilities::getSystemMetric(window, SystemMetric::ResizeBorderHeight, false);
#endif
}
void FramelessWindowsManager::setResizeBorderHeight(QWindow *window, const int value)
{
Q_ASSERT(window);
if (!window || (value <= 0)) {
return;
}
window->setProperty(Constants::resizeBorderHeight_flag, value);
} }
int FramelessWindowsManager::getTitleBarHeight(const QWindow *window) int FramelessWindowsManager::getTitleBarHeight(const QWindow *window)
@ -139,7 +116,7 @@ int FramelessWindowsManager::getTitleBarHeight(const QWindow *window)
return 23; return 23;
} }
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION #ifdef FRAMELESSHELPER_USE_UNIX_VERSION
const int value = window->property(Constants::titleBarHeight_flag).toInt(); const int value = window->property(Constants::kTitleBarHeightFlag).toInt();
return value <= 0 ? 23 : value; return value <= 0 ? 23 : value;
#else #else
return Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, false); return Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, false);
@ -152,7 +129,7 @@ void FramelessWindowsManager::setTitleBarHeight(QWindow *window, const int value
if (!window || (value <= 0)) { if (!window || (value <= 0)) {
return; return;
} }
window->setProperty(Constants::titleBarHeight_flag, value); window->setProperty(Constants::kTitleBarHeightFlag, value);
} }
bool FramelessWindowsManager::getResizable(const QWindow *window) bool FramelessWindowsManager::getResizable(const QWindow *window)
@ -162,7 +139,7 @@ bool FramelessWindowsManager::getResizable(const QWindow *window)
return false; return false;
} }
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION #ifdef FRAMELESSHELPER_USE_UNIX_VERSION
return !window->property(Constants::windowFixedSize_flag).toBool(); return !window->property(Constants::kWindowFixedSizeFlag).toBool();
#else #else
return !Utilities::isWindowFixedSize(window); return !Utilities::isWindowFixedSize(window);
#endif #endif
@ -175,7 +152,7 @@ void FramelessWindowsManager::setResizable(QWindow *window, const bool value)
return; return;
} }
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION #ifdef FRAMELESSHELPER_USE_UNIX_VERSION
window->setProperty(Constants::windowFixedSize_flag, !value); window->setProperty(Constants::kWindowFixedSizeFlag, !value);
#else #else
window->setFlag(Qt::MSWindowsFixedSizeDialogHint, !value); window->setFlag(Qt::MSWindowsFixedSizeDialogHint, !value);
#endif #endif
@ -200,7 +177,7 @@ bool FramelessWindowsManager::isWindowFrameless(const QWindow *window)
if (!window) { if (!window) {
return false; return false;
} }
return window->property(Constants::framelessMode_flag).toBool(); return window->property(Constants::kFramelessModeFlag).toBool();
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -40,10 +40,8 @@ FRAMELESSHELPER_API void addWindow(QWindow *window);
FRAMELESSHELPER_API void removeWindow(QWindow *window); FRAMELESSHELPER_API void removeWindow(QWindow *window);
[[nodiscard]] FRAMELESSHELPER_API bool isWindowFrameless(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API bool isWindowFrameless(const QWindow *window);
FRAMELESSHELPER_API void setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value = true); FRAMELESSHELPER_API void setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value = true);
[[nodiscard]] FRAMELESSHELPER_API int getResizeBorderWidth(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API int getResizeBorderThickness(const QWindow *window);
FRAMELESSHELPER_API void setResizeBorderWidth(QWindow *window, const int value); FRAMELESSHELPER_API void setResizeBorderThickness(QWindow *window, const int value);
[[nodiscard]] FRAMELESSHELPER_API int getResizeBorderHeight(const QWindow *window);
FRAMELESSHELPER_API void setResizeBorderHeight(QWindow *window, const int value);
[[nodiscard]] FRAMELESSHELPER_API int getTitleBarHeight(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API int getTitleBarHeight(const QWindow *window);
FRAMELESSHELPER_API void setTitleBarHeight(QWindow *window, const int value); FRAMELESSHELPER_API void setTitleBarHeight(QWindow *window, const int value);
[[nodiscard]] FRAMELESSHELPER_API bool getResizable(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API bool getResizable(const QWindow *window);

View File

@ -36,6 +36,9 @@ QWindow *Utilities::findWindow(const WId winId)
return nullptr; return nullptr;
} }
const QWindowList windows = QGuiApplication::topLevelWindows(); const QWindowList windows = QGuiApplication::topLevelWindows();
if (windows.isEmpty()) {
return nullptr;
}
for (auto &&window : qAsConst(windows)) { for (auto &&window : qAsConst(windows)) {
if (window && window->handle()) { if (window && window->handle()) {
if (window->winId() == winId) { if (window->winId() == winId) {
@ -48,7 +51,7 @@ QWindow *Utilities::findWindow(const WId winId)
bool Utilities::shouldUseNativeTitleBar() bool Utilities::shouldUseNativeTitleBar()
{ {
return qEnvironmentVariableIsSet(Constants::useNativeTitleBar_flag); return qEnvironmentVariableIsSet(Constants::kUseNativeTitleBarFlag);
} }
bool Utilities::isWindowFixedSize(const QWindow *window) bool Utilities::isWindowFixedSize(const QWindow *window)
@ -76,7 +79,7 @@ bool Utilities::isHitTestVisibleInChrome(const QWindow *window)
if (!window) { if (!window) {
return false; return false;
} }
const auto objs = qvariant_cast<QObjectList>(window->property(Constants::hitTestVisibleInChrome_flag)); const auto objs = qvariant_cast<QObjectList>(window->property(Constants::kHitTestVisibleInChromeFlag));
if (objs.isEmpty()) { if (objs.isEmpty()) {
return false; return false;
} }

View File

@ -29,10 +29,9 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
enum class SystemMetric enum class SystemMetric : int
{ {
ResizeBorderWidth, ResizeBorderThickness = 0,
ResizeBorderHeight,
TitleBarHeight TitleBarHeight
}; };

View File

@ -23,33 +23,38 @@
*/ */
#include "utilities.h" #include "utilities.h"
#include <QtCore/qt_windows.h>
#include <QtGui/qguiapplication.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <dwmapi.h> #include <QtCore/qsettings.h>
#include <QtCore/qt_windows.h>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
#include <QtCore/qoperatingsystemversion.h>
#else
#include <QtCore/qsysinfo.h>
#endif
#include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qplatformwindow.h> #include <QtGui/qpa/qplatformwindow.h>
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#include <QtGui/qpa/qplatformnativeinterface.h> #include <QtGui/qpa/qplatformnativeinterface.h>
#else #else
#include <QtGui/qpa/qplatformwindow_p.h> #include <QtGui/qpa/qplatformwindow_p.h>
#endif #endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) #include <dwmapi.h>
#include <QtCore/qoperatingsystemversion.h>
#else
#include <QtCore/qsysinfo.h>
#endif
Q_DECLARE_METATYPE(QMargins) Q_DECLARE_METATYPE(QMargins)
#ifndef SM_CXPADDEDBORDER #ifndef SM_CXPADDEDBORDER
// Only available since Windows Vista // Only available since Windows Vista
#define SM_CXPADDEDBORDER 92 #define SM_CXPADDEDBORDER (92)
#endif #endif
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
// The standard values of resize border width, resize border height and title bar height when DPI is 96. static constexpr char kDwmRegistryKey[] = R"(Software\Microsoft\Windows\DWM)";
static const int g_defaultResizeBorderWidth = 8, g_defaultResizeBorderHeight = 8, g_defaultTitleBarHeight = 23; static constexpr char kDwmCompositionRegistryKey[] = "Composition";
static constexpr int kDefaultResizeBorderThickness = 8;
static constexpr int kDefaultResizeBorderThicknessClassic = 4;
static constexpr int kDefaultTitleBarHeight = 23;
bool Utilities::isDwmCompositionAvailable() bool Utilities::isDwmCompositionAvailable()
{ {
@ -58,11 +63,13 @@ bool Utilities::isDwmCompositionAvailable()
return true; return true;
} }
BOOL enabled = FALSE; BOOL enabled = FALSE;
if (FAILED(DwmIsCompositionEnabled(&enabled))) { if (SUCCEEDED(DwmIsCompositionEnabled(&enabled))) {
qWarning() << "DwmIsCompositionEnabled() failed.";
return false;
}
return (enabled != FALSE); return (enabled != FALSE);
}
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
bool ok = false;
const int value = registry.value(QString::fromUtf8(kDwmCompositionRegistryKey), 0).toInt(&ok);
return (ok && (value != 0));
} }
int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue) int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue)
@ -72,10 +79,10 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric,
return 0; return 0;
} }
switch (metric) { switch (metric) {
case SystemMetric::ResizeBorderWidth: { case SystemMetric::ResizeBorderThickness: {
const int rbw = window->property(Constants::resizeBorderWidth_flag).toInt(); const int rbt = window->property(Constants::kResizeBorderThicknessFlag).toInt();
if ((rbw > 0) && !forceSystemValue) { if ((rbt > 0) && !forceSystemValue) {
return qRound(static_cast<qreal>(rbw) * (dpiScale ? window->devicePixelRatio() : 1.0)); return qRound(static_cast<qreal>(rbt) * (dpiScale ? window->devicePixelRatio() : 1.0));
} else { } else {
const int result = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); const int result = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
if (result > 0) { if (result > 0) {
@ -85,38 +92,18 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric,
return qRound(static_cast<qreal>(result) / window->devicePixelRatio()); return qRound(static_cast<qreal>(result) / window->devicePixelRatio());
} }
} else { } else {
// The padded border will disappear if DWM composition is disabled.
const int defaultRBT = (isDwmCompositionAvailable() ? kDefaultResizeBorderThickness : kDefaultResizeBorderThicknessClassic);
if (dpiScale) { if (dpiScale) {
return qRound(static_cast<qreal>(g_defaultResizeBorderWidth) * window->devicePixelRatio()); return qRound(static_cast<qreal>(defaultRBT) * window->devicePixelRatio());
} else { } else {
return g_defaultResizeBorderWidth; return defaultRBT;
}
}
}
}
case SystemMetric::ResizeBorderHeight: {
const int rbh = window->property(Constants::resizeBorderHeight_flag).toInt();
if ((rbh > 0) && !forceSystemValue) {
return qRound(static_cast<qreal>(rbh) * (dpiScale ? window->devicePixelRatio() : 1.0));
} else {
// There is no "SM_CYPADDEDBORDER".
const int result = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
if (result > 0) {
if (dpiScale) {
return result;
} else {
return qRound(static_cast<qreal>(result) / window->devicePixelRatio());
}
} else {
if (dpiScale) {
return qRound(static_cast<qreal>(g_defaultResizeBorderHeight) * window->devicePixelRatio());
} else {
return g_defaultResizeBorderHeight;
} }
} }
} }
} }
case SystemMetric::TitleBarHeight: { case SystemMetric::TitleBarHeight: {
const int tbh = window->property(Constants::titleBarHeight_flag).toInt(); const int tbh = window->property(Constants::kTitleBarHeightFlag).toInt();
if ((tbh > 0) && !forceSystemValue) { if ((tbh > 0) && !forceSystemValue) {
return qRound(static_cast<qreal>(tbh) * (dpiScale ? window->devicePixelRatio() : 1.0)); return qRound(static_cast<qreal>(tbh) * (dpiScale ? window->devicePixelRatio() : 1.0));
} else { } else {
@ -129,9 +116,9 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric,
} }
} else { } else {
if (dpiScale) { if (dpiScale) {
return qRound(static_cast<qreal>(g_defaultTitleBarHeight) * window->devicePixelRatio()); return qRound(static_cast<qreal>(kDefaultTitleBarHeight) * window->devicePixelRatio());
} else { } else {
return g_defaultTitleBarHeight; return kDefaultTitleBarHeight;
} }
} }
} }
@ -176,10 +163,9 @@ void Utilities::updateQtFrameMargins(QWindow *window, const bool enable)
if (!window) { if (!window) {
return; return;
} }
const int rbt = enable ? Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true, true) : 0;
const int tbh = enable ? Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, true, true) : 0; const int tbh = enable ? Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, true, true) : 0;
const int rbw = enable ? Utilities::getSystemMetric(window, SystemMetric::ResizeBorderWidth, true, true) : 0; const QMargins margins = {-rbt, -(rbt + tbh), -rbt, -rbt}; // left, top, right, bottom
const int rbh = enable ? Utilities::getSystemMetric(window, SystemMetric::ResizeBorderHeight, true, true) : 0;
const QMargins margins = {-rbw, -(rbh + tbh), -rbw, -rbh}; // left, top, right, bottom
const QVariant marginsVar = QVariant::fromValue(margins); const QVariant marginsVar = QVariant::fromValue(margins);
window->setProperty("_q_windowsCustomMargins", marginsVar); window->setProperty("_q_windowsCustomMargins", marginsVar);
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))