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 -= embed_manifest_exe
LIBS += -luser32 -lshell32 -ldwmapi
RC_FILE = $$PWD/windows.rc
OTHER_FILES += $$PWD/windows.manifest
RC_FILE = $$PWD/example.rc
OTHER_FILES += $$PWD/example.manifest
}
win32 {
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"?>
<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>
<dependentAssembly>
<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>
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
FILEVERSION 1,0,0,0
@ -45,14 +45,11 @@ BEGIN
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "Built by the Qt Toolkit."
VALUE "CompanyName", "wangwenx190"
VALUE "FileDescription", "A FramelessHelper based Qt application."
VALUE "FileDescription", "FramelessHelper Demo Application"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", ""
VALUE "LegalCopyright", "MIT License"
VALUE "OriginalFilename", ""
VALUE "ProductName", "Test Application"
VALUE "ProductName", "Demo"
VALUE "ProductVersion", "1.0.0.0"
END
END

View File

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

View File

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

View File

@ -28,22 +28,10 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// High DPI scaling is enabled by default from Qt 6
#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_UseHighDpiPixmaps);
#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);
#endif
#endif
@ -51,7 +39,6 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
MainWindow mainWindow;
mainWindow.resize(800, 600);
mainWindow.show();
return QApplication::exec();

View File

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

View File

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

View File

@ -30,22 +30,10 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// High DPI scaling is enabled by default from Qt 6
#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_UseHighDpiPixmaps);
#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);
#endif
#endif

View File

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

View File

@ -28,22 +28,10 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// High DPI scaling is enabled by default from Qt 6
#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_UseHighDpiPixmaps);
#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);
#endif
#endif
@ -51,7 +39,6 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
Widget widget;
widget.resize(800, 600);
widget.show();
return QApplication::exec();

View File

@ -113,10 +113,12 @@ void Widget::paintEvent(QPaintEvent *event)
void Widget::setupUi()
{
setWindowTitle(tr("Hello, World!"));
resize(800, 600);
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 systemButtonHeight = titleBarHeight + resizeBorderHeight;
const int systemButtonHeight = titleBarHeight + resizeBorderThickness;
const QSize systemButtonSize = {qRound(static_cast<qreal>(systemButtonHeight) * 1.5), systemButtonHeight};
m_minimizeButton = new QPushButton(this);
m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton"));

View File

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

View File

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

View File

@ -26,8 +26,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/qwindow.h>
#include <QtCore/qt_windows.h>
#include <QtGui/qwindow.h>
#include <shellapi.h>
#include "utilities.h"
@ -48,12 +48,12 @@
#ifndef IsMinimized
// Only available since Windows 2000
#define IsMinimized(window) (IsIconic(window))
#define IsMinimized(window) (IsIconic(window) != FALSE)
#endif
#ifndef IsMaximized
// Only available since Windows 2000
#define IsMaximized(window) (IsZoomed(window))
#define IsMaximized(window) (IsZoomed(window) != FALSE)
#endif
#ifndef GET_X_LPARAM
@ -68,6 +68,9 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
// The thickness of an auto-hide taskbar in pixels.
static constexpr int kAutoHideTaskbarThickness = 2;
[[nodiscard]] static inline bool shouldHaveWindowFrame()
{
if (Utilities::shouldUseNativeTitleBar()) {
@ -75,8 +78,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
// want to use the native title bar.
return true;
}
const bool should = qEnvironmentVariableIsSet(Constants::preserveNativeFrame_flag);
const bool force = qEnvironmentVariableIsSet(Constants::forcePreserveNativeFrame_flag);
const bool should = qEnvironmentVariableIsSet(Constants::kPreserveNativeFrameFlag);
const bool force = qEnvironmentVariableIsSet(Constants::kForcePreserveNativeFrameFlag);
if (should || force) {
if (force) {
return true;
@ -90,10 +93,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
return false;
}
// The thickness of an auto-hide taskbar in pixels.
static const int kAutoHideTaskbarThicknessPx = 2;
static const int kAutoHideTaskbarThicknessPy = kAutoHideTaskbarThicknessPx;
struct FramelessHelperWinData
{
[[nodiscard]] bool create() {
@ -162,7 +161,7 @@ static inline void installHelper(QWindow *window, const bool enable)
const WId winId = window->winId();
Utilities::updateFrameMargins(winId, !enable);
Utilities::triggerFrameChange(winId);
window->setProperty(Constants::framelessMode_flag, enable);
window->setProperty(Constants::kFramelessModeFlag, enable);
}
FramelessHelperWin::FramelessHelperWin() = default;
@ -212,7 +211,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return false;
}
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;
}
switch (msg->message) {
@ -291,18 +290,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break;
}
if (!msg->wParam) {
if (msg->wParam == FALSE) {
*result = 0;
return true;
}
bool nonClientAreaExists = false;
const auto clientRect = &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0]);
if (shouldHaveWindowFrame()) {
// Store the original top before the default window proc
// applies the default frame.
const LONG originalTop = clientRect->top;
// 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) {
*result = ret;
return true;
@ -311,6 +309,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// default frame was applied.
clientRect->top = originalTop;
}
bool nonClientAreaExists = false;
// 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
// 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
// do not appear because you don't need them (because you can't resize
// a window when it's maximized unless you restore it).
const int rbh = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderHeight, true);
clientRect->top += rbh;
const int rbt = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true);
clientRect->top += rbt;
if (!shouldHaveWindowFrame()) {
clientRect->bottom -= rbh;
const int rbw = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderWidth, true);
clientRect->left += rbw;
clientRect->right -= rbw;
clientRect->bottom -= rbt;
clientRect->left += rbt;
clientRect->right -= rbt;
}
nonClientAreaExists = true;
}
@ -353,7 +351,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo);
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
// auto-hide taskbar on the given edge of the monitor
// we're currently on.
@ -364,7 +369,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
_abd.uEdge = edge;
_abd.rc = monitorInfo.rcMonitor;
const auto hTaskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &_abd));
return hTaskbar != nullptr;
return (hTaskbar != nullptr);
};
top = hasAutohideTaskbar(ABE_TOP);
bottom = hasAutohideTaskbar(ABE_BOTTOM);
@ -380,16 +385,27 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
_abd.hWnd = FindWindowW(L"Shell_TrayWnd", nullptr);
if (_abd.hWnd) {
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);
if (!taskbarMonitor) {
qWarning() << "Failed to retrieve the screen that contains the task bar.";
break;
}
if (taskbarMonitor == windowMonitor) {
SHAppBarMessage(ABM_GETTASKBARPOS, &_abd);
edge = _abd.uEdge;
}
} else {
qWarning() << "Failed to retrieve the task bar window handle.";
break;
}
top = edge == ABE_TOP;
bottom = edge == ABE_BOTTOM;
left = edge == ABE_LEFT;
right = edge == ABE_RIGHT;
top = (edge == ABE_TOP);
bottom = (edge == ABE_BOTTOM);
left = (edge == ABE_LEFT);
right = (edge == ABE_RIGHT);
}
// If there's a taskbar on any side of the monitor, reduce
// 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.
if (top) {
// Peculiarly, when we're fullscreen,
clientRect->top += kAutoHideTaskbarThicknessPy;
clientRect->top += kAutoHideTaskbarThickness;
nonClientAreaExists = true;
} else if (bottom) {
clientRect->bottom -= kAutoHideTaskbarThicknessPy;
clientRect->bottom -= kAutoHideTaskbarThickness;
nonClientAreaExists = true;
} else if (left) {
clientRect->left += kAutoHideTaskbarThicknessPx;
clientRect->left += kAutoHideTaskbarThickness;
nonClientAreaExists = true;
} else if (right) {
clientRect->right -= kAutoHideTaskbarThicknessPx;
clientRect->right -= kAutoHideTaskbarThickness;
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
// Don't use "*result = 0" otherwise the window won't respond
// to the window active state change.
*result = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, -1);
} else {
if (static_cast<BOOL>(msg->wParam)) {
*result = FALSE;
*result = DefWindowProcW(msg->hwnd, WM_NCACTIVATE, msg->wParam, -1);
} else {
if (msg->wParam == FALSE) {
*result = TRUE;
} else {
*result = FALSE;
}
}
return true;
@ -562,15 +578,19 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break;
}
POINT winLocalMouse = {0, 0};
GetCursorPos(&winLocalMouse); // Or {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)}
ScreenToClient(msg->hwnd, &winLocalMouse);
POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) {
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)};
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 int rbw = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderWidth, true);
const int rbh = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderHeight, true);
const int rbt = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true);
const int tbh = Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, true);
bool isTitleBar = false;
if (IsMaximized(msg->hwnd) || (window->windowState() == Qt::WindowFullScreen)) {
@ -579,15 +599,15 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
&& !Utilities::isHitTestVisibleInChrome(window);
}
if (window->windowState() == Qt::WindowNoState) {
isTitleBar = (localMouse.y() > rbh) && (localMouse.y() <= (rbh + tbh))
&& (localMouse.x() > rbw) && (localMouse.x() < (ww - rbw))
isTitleBar = (localMouse.y() > rbt) && (localMouse.y() <= (rbt + tbh))
&& (localMouse.x() > rbt) && (localMouse.x() < (ww - rbt))
&& !Utilities::isHitTestVisibleInChrome(window);
}
const bool isTop = localMouse.y() <= rbh;
const bool isTop = localMouse.y() <= rbt;
if (shouldHaveWindowFrame()) {
// This will handle the left, right and bottom parts of the frame
// 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) {
*result = originalRet;
return true;
@ -608,19 +628,19 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
*result = HTCLIENT;
return true;
} else {
const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, rbw, rbh, ww, isTop, window] {
const LONG wh = clientRect.bottom;
const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, rbt, ww, isTop, window]{
if (IsMaximized(msg->hwnd)) {
if (isTitleBar) {
return HTCAPTION;
}
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.
const qreal factor = (isTop || isBottom) ? 2.0 : 1.0;
const bool isLeft = (localMouse.x() <= qRound(static_cast<qreal>(rbw) * factor));
const bool isRight = (localMouse.x() >= (ww - 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>(rbt) * factor)));
const bool fixedSize = Utilities::isWindowFixedSize(window);
const auto getBorderValue = [fixedSize](int value) -> int {
return fixedSize ? HTCLIENT : value;
@ -653,7 +673,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return HTCAPTION;
}
return HTCLIENT;
} ();
}();
*result = hitTestResult;
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));
Q_EMIT resizeBorderWidthChanged(val);
}
qreal FramelessQuickHelper::resizeBorderHeight() const
{
return FramelessWindowsManager::getResizeBorderHeight(window());
}
void FramelessQuickHelper::setResizeBorderHeight(const qreal val)
{
FramelessWindowsManager::setResizeBorderHeight(window(), qRound(val));
Q_EMIT resizeBorderHeightChanged(val);
FramelessWindowsManager::setResizeBorderThickness(window(), qRound(val));
Q_EMIT resizeBorderThicknessChanged(val);
}
qreal FramelessQuickHelper::titleBarHeight() const

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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