sync with 1.x changes

This commit is contained in:
Altair Wei 2021-11-14 22:31:02 +08:00
parent 7b82375543
commit 1ebead3148
12 changed files with 217 additions and 383 deletions

View File

@ -167,7 +167,12 @@ void MainWindow::paintEvent(QPaintEvent *event)
{0, h, 0, 0}
};
painter.save();
painter.setPen({isActiveWindow() ? Qt::black : Qt::darkGray, 1});
const ColorizationArea area = Utilities::getColorizationArea();
const bool colorizedBorder = ((area == ColorizationArea::TitleBar_WindowBorder)
|| (area == ColorizationArea::AllArea));
const QColor borderColor = (isActiveWindow() ? (colorizedBorder ? Utilities::getColorizationColor() : Qt::black) : Qt::darkGray);
const auto borderThickness = static_cast<qreal>(Utilities::getWindowVisibleFrameBorderThickness(winId()));
painter.setPen({borderColor, qMax(borderThickness, devicePixelRatioF())});
painter.drawLines(lines);
painter.restore();
}

View File

@ -22,7 +22,7 @@
* SOFTWARE.
*/
#include "../../framelessquickhelper.h"
#include "quick/framelessquickhelper.h"
#include <QtGui/qguiapplication.h>
#include <QtQml/qqmlapplicationengine.h>
#include <QtQuickControls2/qquickstyle.h>

View File

@ -654,28 +654,6 @@ void FramelessHelper::handleResizeHandlerDblClicked()
}
#ifdef Q_OS_WIN
static inline bool shouldHaveWindowFrame()
{
if (Utilities::shouldUseNativeTitleBar()) {
// We have to use the original window frame unconditionally if we
// want to use the native title bar.
return true;
}
const bool should = qEnvironmentVariableIsSet(Constants::kPreserveNativeFrameFlag);
const bool force = qEnvironmentVariableIsSet(Constants::kForcePreserveNativeFrameFlag);
if (should || force) {
if (force) {
return true;
}
if (should) {
// If you preserve the window frame on Win7~8.1,
// the window will have a terrible appearance.
return Utilities::isWin10OrGreater();
}
}
return false;
}
/*!
This function works like a eventFilter, return \c true means the event has been handled.
*/
@ -783,11 +761,7 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
// preserve the four window borders. So we just remove the whole
// window frame, otherwise the code will become much more complex.
if (Utilities::shouldUseNativeTitleBar()) {
break;
}
if (msg->wParam == FALSE) {
if (static_cast<BOOL>(msg->wParam) == FALSE) {
*result = 0;
return true;
}
@ -803,20 +777,6 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
)
);
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, WM_NCCALCSIZE, TRUE, msg->lParam);
if (ret != 0) {
*result = ret;
return true;
}
// Re-apply the original top from before the size of the
// 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
@ -833,11 +793,9 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
const int resizeBorderThickness = Utilities::getSystemMetric(
window, SystemMetric::ResizeBorderThickness, true, true);
clientRect->top += resizeBorderThickness;
if (!shouldHaveWindowFrame()) {
clientRect->bottom -= resizeBorderThickness;
clientRect->left += resizeBorderThickness;
clientRect->right -= resizeBorderThickness;
}
clientRect->bottom -= resizeBorderThickness;
clientRect->left += resizeBorderThickness;
clientRect->right -= resizeBorderThickness;
nonClientAreaExists = true;
}
// Attempt to detect if there's an autohide taskbar, and if
@ -977,17 +935,13 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
// area.
case WM_NCUAHDRAWCAPTION:
case WM_NCUAHDRAWFRAME: {
if (shouldHaveWindowFrame()) {
break;
} else {
*result = 0;
return true;
}
*result = 0;
return true;
}
case WM_NCPAINT: {
// 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失
if (!Utilities::isDwmCompositionAvailable() && !shouldHaveWindowFrame()) {
if (!Utilities::isDwmCompositionAvailable()) {
// Only block WM_NCPAINT when DWM composition is disabled. If
// it's blocked when DWM composition is enabled, the frame
// shadow won't be drawn.
@ -998,26 +952,22 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
}
}
case WM_NCACTIVATE: {
if (shouldHaveWindowFrame()) {
break;
if (Utilities::isDwmCompositionAvailable()) {
// DefWindowProc won't repaint the window border if lParam
// (normally a HRGN) is -1. See the following link's "lParam"
// section:
// 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, WM_NCACTIVATE, msg->wParam, -1);
} else {
if (Utilities::isDwmCompositionAvailable()) {
// DefWindowProc won't repaint the window border if lParam
// (normally a HRGN) is -1. See the following link's "lParam"
// section:
// 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, WM_NCACTIVATE, msg->wParam, -1);
if (static_cast<BOOL>(msg->wParam) == FALSE) {
*result = TRUE;
} else {
if (msg->wParam == FALSE) {
*result = TRUE;
} else {
*result = FALSE;
}
*result = FALSE;
}
return true;
}
return true;
}
case WM_NCHITTEST: {
// 原生Win32窗口只有顶边是在窗口内部resize的其余三边都是在窗口
@ -1085,10 +1035,6 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
// another branch, if you are interested in it, you can give it a
// try.
if (Utilities::shouldUseNativeTitleBar()) {
break;
}
POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("ScreenToClient"));
@ -1108,108 +1054,72 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
bool isTitleBar = isInTitlebarArea(QPoint(qRound(localMouse.x() / scaleFactor), qRound(localMouse.y() / scaleFactor)));
/*
if (IsMaximized(msg->hwnd) || (window->windowState() == Qt::WindowFullScreen)) {
isTitleBar = (localMouse.y() >= 0) && (localMouse.y() <= titleBarHeight)
&& (localMouse.x() >= 0) && (localMouse.x() <= windowWidth)
&& !Utilities::isHitTestVisibleInChrome(window);
}
if (window->windowState() == Qt::WindowNoState) {
isTitleBar = (localMouse.y() > resizeBorderThickness) && (localMouse.y() <= titleBarHeight)
&& (localMouse.x() > resizeBorderThickness) && (localMouse.x() < (windowWidth - resizeBorderThickness))
&& !Utilities::isHitTestVisibleInChrome(window);
}
*/
const bool isTop = localMouse.y() <= resizeBorderThickness;
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, WM_NCHITTEST, 0, msg->lParam);
if (originalRet != HTCLIENT) {
*result = originalRet;
return true;
}
// At this point, we know that the cursor is inside the client area
// so it has to be either the little border at the top of our custom
// title bar or the drag bar. Apparently, it must be the drag bar or
// the little border at the top which the user can use to move or
// resize the window.
if (!IsMaximized(msg->hwnd) && isTop) {
*result = HTTOP;
return true;
}
if (isTitleBar) {
*result = HTCAPTION;
return true;
}
*result = HTCLIENT;
return true;
} else {
const LRESULT hitTestResult = [
clientRect, msg, isTitleBar, &localMouse,
resizeBorderThickness, windowWidth, isTop,
window, scaleFactor] {
if (IsMaximized(msg->hwnd)) {
if (isTitleBar) {
return HTCAPTION;
}
return HTCLIENT;
}
const LONG windowHeight = clientRect.bottom;
const bool isBottom = (localMouse.y() >= (windowHeight - resizeBorderThickness));
// 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>(resizeBorderThickness) * factor));
const bool isRight = (localMouse.x() >= (windowWidth - qRound(static_cast<qreal>(resizeBorderThickness) * factor)));
const bool fixedSize = Utilities::isWindowFixedSize(window);
const auto getBorderValue = [fixedSize](int value) -> int {
return fixedSize ? HTCLIENT : value;
};
if (isTop) {
if (isLeft) {
return getBorderValue(HTTOPLEFT);
}
if (isRight) {
return getBorderValue(HTTOPRIGHT);
}
return getBorderValue(HTTOP);
}
if (isBottom) {
if (isLeft) {
return getBorderValue(HTBOTTOMLEFT);
}
if (isRight) {
return getBorderValue(HTBOTTOMRIGHT);
}
return getBorderValue(HTBOTTOM);
}
if (isLeft) {
return getBorderValue(HTLEFT);
}
if (isRight) {
return getBorderValue(HTRIGHT);
}
const LRESULT hitTestResult = [
clientRect, msg, isTitleBar, &localMouse,
resizeBorderThickness, windowWidth, isTop,
window, scaleFactor] {
if (IsMaximized(msg->hwnd)) {
if (isTitleBar) {
return HTCAPTION;
}
return HTCLIENT;
}();
*result = hitTestResult;
return true;
}
}
const LONG windowHeight = clientRect.bottom;
const bool isBottom = (localMouse.y() >= (windowHeight - resizeBorderThickness));
// 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>(resizeBorderThickness) * factor));
const bool isRight = (localMouse.x() >= (windowWidth - qRound(static_cast<qreal>(resizeBorderThickness) * factor)));
const bool fixedSize = Utilities::isWindowFixedSize(window);
const auto getBorderValue = [fixedSize](int value) -> int {
return fixedSize ? HTCLIENT : value;
};
if (isTop) {
if (isLeft) {
return getBorderValue(HTTOPLEFT);
}
if (isRight) {
return getBorderValue(HTTOPRIGHT);
}
return getBorderValue(HTTOP);
}
if (isBottom) {
if (isLeft) {
return getBorderValue(HTBOTTOMLEFT);
}
if (isRight) {
return getBorderValue(HTBOTTOMRIGHT);
}
return getBorderValue(HTBOTTOM);
}
if (isLeft) {
return getBorderValue(HTLEFT);
}
if (isRight) {
return getBorderValue(HTRIGHT);
}
if (isTitleBar) {
return HTCAPTION;
}
return HTCLIENT;
}();
*result = hitTestResult;
return true;
}
case WM_SETICON:
case WM_SETTEXT: {
if (Utilities::shouldUseNativeTitleBar()) {
break;
}
// Disable painting while these messages are handled to prevent them
// from drawing a window caption over the client area.
SetLastError(ERROR_SUCCESS);
const LONG_PTR oldStyle = GetWindowLongPtrW(msg->hwnd, GWL_STYLE);
if (oldStyle == 0) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW"));
break;
}
// Prevent Windows from drawing the default title bar by temporarily
// toggling the WS_VISIBLE style.
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle & ~WS_VISIBLE)) == 0) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
break;
@ -1217,6 +1127,7 @@ bool FramelessHelper::handleNativeEvent(QWindow *window, const QByteArray &event
const auto winId = reinterpret_cast<WId>(msg->hwnd);
Utilities::triggerFrameChange(winId);
const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
break;

View File

@ -32,28 +32,6 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static inline bool shouldHaveWindowFrame()
{
if (Utilities::shouldUseNativeTitleBar()) {
// We have to use the original window frame unconditionally if we
// want to use the native title bar.
return true;
}
const bool should = qEnvironmentVariableIsSet(Constants::kPreserveNativeFrameFlag);
const bool force = qEnvironmentVariableIsSet(Constants::kForcePreserveNativeFrameFlag);
if (should || force) {
if (force) {
return true;
}
if (should) {
// If you preserve the window frame on Win7~8.1,
// the window will have a terrible appearance.
return Utilities::isWin10OrGreater();
}
}
return false;
}
struct FramelessHelperWinData
{
bool create() {
@ -247,29 +225,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// preserve the four window borders. So we just remove the whole
// window frame, otherwise the code will become much more complex.
if (Utilities::shouldUseNativeTitleBar()) {
break;
}
if (msg->wParam == FALSE) {
if (static_cast<BOOL>(msg->wParam) == FALSE) {
*result = 0;
return true;
}
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, WM_NCCALCSIZE, TRUE, msg->lParam);
if (ret != 0) {
*result = ret;
return true;
}
// Re-apply the original top from before the size of the
// 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
@ -281,13 +241,11 @@ 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 resizeBorderThickness = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, false, true);
const int resizeBorderThickness = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true);
clientRect->top += resizeBorderThickness;
if (!shouldHaveWindowFrame()) {
clientRect->bottom -= resizeBorderThickness;
clientRect->left += resizeBorderThickness;
clientRect->right -= resizeBorderThickness;
}
clientRect->bottom -= resizeBorderThickness;
clientRect->left += resizeBorderThickness;
clientRect->right -= resizeBorderThickness;
nonClientAreaExists = true;
}
// Attempt to detect if there's an autohide taskbar, and if
@ -427,17 +385,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// area.
case WM_NCUAHDRAWCAPTION:
case WM_NCUAHDRAWFRAME: {
if (shouldHaveWindowFrame()) {
break;
} else {
*result = 0;
return true;
}
*result = 0;
return true;
}
case WM_NCPAINT: {
// 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失
if (!Utilities::isDwmCompositionAvailable() && !shouldHaveWindowFrame()) {
if (!Utilities::isDwmCompositionAvailable()) {
// Only block WM_NCPAINT when DWM composition is disabled. If
// it's blocked when DWM composition is enabled, the frame
// shadow won't be drawn.
@ -448,26 +402,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
}
case WM_NCACTIVATE: {
if (shouldHaveWindowFrame()) {
break;
if (Utilities::isDwmCompositionAvailable()) {
// DefWindowProc won't repaint the window border if lParam
// (normally a HRGN) is -1. See the following link's "lParam"
// section:
// 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, WM_NCACTIVATE, msg->wParam, -1);
} else {
if (Utilities::isDwmCompositionAvailable()) {
// DefWindowProc won't repaint the window border if lParam
// (normally a HRGN) is -1. See the following link's "lParam"
// section:
// 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, WM_NCACTIVATE, msg->wParam, -1);
if (static_cast<BOOL>(msg->wParam) == FALSE) {
*result = TRUE;
} else {
if (msg->wParam == FALSE) {
*result = TRUE;
} else {
*result = FALSE;
}
*result = FALSE;
}
return true;
}
return true;
}
case WM_NCHITTEST: {
// 原生Win32窗口只有顶边是在窗口内部resize的其余三边都是在窗口
@ -535,10 +485,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// another branch, if you are interested in it, you can give it a
// try.
if (Utilities::shouldUseNativeTitleBar()) {
break;
}
POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("ScreenToClient"));
@ -557,99 +503,76 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (IsMaximized(msg->hwnd) || (window->windowState() == Qt::WindowFullScreen)) {
isTitleBar = (localMouse.y() >= 0) && (localMouse.y() <= titleBarHeight)
&& (localMouse.x() >= 0) && (localMouse.x() <= windowWidth)
&& !Utilities::isHitTestVisibleInChrome(window);
&& !Utilities::isHitTestVisible(window);
}
if (window->windowState() == Qt::WindowNoState) {
isTitleBar = (localMouse.y() > resizeBorderThickness) && (localMouse.y() <= titleBarHeight)
&& (localMouse.x() > resizeBorderThickness) && (localMouse.x() < (windowWidth - resizeBorderThickness))
&& !Utilities::isHitTestVisibleInChrome(window);
&& !Utilities::isHitTestVisible(window);
}
const bool isTop = localMouse.y() <= resizeBorderThickness;
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, WM_NCHITTEST, 0, msg->lParam);
if (originalRet != HTCLIENT) {
*result = originalRet;
return true;
}
// At this point, we know that the cursor is inside the client area
// so it has to be either the little border at the top of our custom
// title bar or the drag bar. Apparently, it must be the drag bar or
// the little border at the top which the user can use to move or
// resize the window.
if (!IsMaximized(msg->hwnd) && isTop) {
*result = HTTOP;
return true;
}
if (isTitleBar) {
*result = HTCAPTION;
return true;
}
*result = HTCLIENT;
return true;
} else {
const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, resizeBorderThickness, windowWidth, isTop, window]{
if (IsMaximized(msg->hwnd)) {
if (isTitleBar) {
return HTCAPTION;
}
return HTCLIENT;
}
const LONG windowHeight = clientRect.bottom;
const bool isBottom = (localMouse.y() >= (windowHeight - resizeBorderThickness));
// 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>(resizeBorderThickness) * factor));
const bool isRight = (localMouse.x() >= (windowWidth - qRound(static_cast<qreal>(resizeBorderThickness) * factor)));
const bool fixedSize = Utilities::isWindowFixedSize(window);
const auto getBorderValue = [fixedSize](int value) -> int {
return fixedSize ? HTCLIENT : value;
};
if (isTop) {
if (isLeft) {
return getBorderValue(HTTOPLEFT);
}
if (isRight) {
return getBorderValue(HTTOPRIGHT);
}
return getBorderValue(HTTOP);
}
if (isBottom) {
if (isLeft) {
return getBorderValue(HTBOTTOMLEFT);
}
if (isRight) {
return getBorderValue(HTBOTTOMRIGHT);
}
return getBorderValue(HTBOTTOM);
}
if (isLeft) {
return getBorderValue(HTLEFT);
}
if (isRight) {
return getBorderValue(HTRIGHT);
}
const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, resizeBorderThickness, windowWidth, isTop, window]{
if (IsMaximized(msg->hwnd)) {
if (isTitleBar) {
return HTCAPTION;
}
return HTCLIENT;
}();
*result = hitTestResult;
return true;
}
}
const LONG windowHeight = clientRect.bottom;
const bool isBottom = (localMouse.y() >= (windowHeight - resizeBorderThickness));
// 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>(resizeBorderThickness) * factor));
const bool isRight = (localMouse.x() >= (windowWidth - qRound(static_cast<qreal>(resizeBorderThickness) * factor)));
const bool fixedSize = Utilities::isWindowFixedSize(window);
const auto getBorderValue = [fixedSize](int value) -> int {
return fixedSize ? HTCLIENT : value;
};
if (isTop) {
if (isLeft) {
return getBorderValue(HTTOPLEFT);
}
if (isRight) {
return getBorderValue(HTTOPRIGHT);
}
return getBorderValue(HTTOP);
}
if (isBottom) {
if (isLeft) {
return getBorderValue(HTBOTTOMLEFT);
}
if (isRight) {
return getBorderValue(HTBOTTOMRIGHT);
}
return getBorderValue(HTBOTTOM);
}
if (isLeft) {
return getBorderValue(HTLEFT);
}
if (isRight) {
return getBorderValue(HTRIGHT);
}
if (isTitleBar) {
return HTCAPTION;
}
return HTCLIENT;
}();
*result = hitTestResult;
return true;
}
case WM_SETICON:
case WM_SETTEXT: {
if (Utilities::shouldUseNativeTitleBar()) {
break;
}
// Disable painting while these messages are handled to prevent them
// from drawing a window caption over the client area.
SetLastError(ERROR_SUCCESS);
const LONG_PTR oldStyle = GetWindowLongPtrW(msg->hwnd, GWL_STYLE);
if (oldStyle == 0) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW"));
break;
}
// Prevent Windows from drawing the default title bar by temporarily
// toggling the WS_VISIBLE style.
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle & ~WS_VISIBLE)) == 0) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
break;
@ -657,6 +580,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const auto winId = reinterpret_cast<WId>(msg->hwnd);
Utilities::triggerFrameChange(winId);
const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) {
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
break;
@ -665,15 +589,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
*result = ret;
return true;
}
case WM_SIZE: {
const bool normal = (msg->wParam == SIZE_RESTORED);
const bool max = (msg->wParam == SIZE_MAXIMIZED);
const bool full = (window->windowState() == Qt::WindowFullScreen);
if (normal || max || full) {
Utilities::updateFrameMargins(reinterpret_cast<WId>(msg->hwnd), (max || full));
Utilities::updateQtFrameMargins(const_cast<QWindow *>(window), true);
}
} break;
default:
break;
}

View File

@ -90,11 +90,11 @@
#endif
#ifndef GET_X_LPARAM
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_X_LPARAM(lp) (static_cast<int>(static_cast<short>(LOWORD(lp))))
#endif
#ifndef GET_Y_LPARAM
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
#define GET_Y_LPARAM(lp) (static_cast<int>(static_cast<short>(HIWORD(lp))))
#endif
#ifndef IsMinimized
@ -105,13 +105,13 @@
#define IsMaximized(window) (IsZoomed(window) != FALSE)
#endif
constexpr int kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels
constexpr UINT kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels
constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)";
constexpr char kPersonalizeRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)";
constexpr int kDefaultResizeBorderThicknessClassic = 4;
constexpr int kDefaultResizeBorderThicknessAero = 8;
constexpr int kDefaultCaptionHeight = 23;
constexpr UINT kDefaultResizeBorderThicknessClassic = 4;
constexpr UINT kDefaultResizeBorderThicknessAero = 8;
constexpr UINT kDefaultCaptionHeight = 23;
constexpr WORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37;
constexpr DWORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37;

View File

@ -38,7 +38,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION
//Q_GLOBAL_STATIC(FramelessHelper, framelessHelperUnix)
Q_GLOBAL_STATIC(FramelessHelper, framelessHelperUnix)
#endif
void FramelessWindowsManager::addWindow(QWindow *window)
@ -51,7 +51,7 @@ void FramelessWindowsManager::addWindow(QWindow *window)
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
}
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION
//framelessHelperUnix()->removeWindowFrame(window);
framelessHelperUnix()->removeWindowFrame(window);
#else
FramelessHelperWin::addFramelessWindow(window);
// Work-around a Win32 multi-monitor bug.
@ -62,7 +62,7 @@ void FramelessWindowsManager::addWindow(QWindow *window)
#endif
}
void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value)
void FramelessWindowsManager::setHitTestVisible(QWindow *window, QObject *object, const bool value)
{
Q_ASSERT(window);
Q_ASSERT(object);
@ -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::kHitTestVisibleInChromeFlag));
auto objList = qvariant_cast<QObjectList>(window->property(Constants::kHitTestVisibleFlag));
if (value) {
if (objList.isEmpty() || !objList.contains(object)) {
objList.append(object);
@ -83,7 +83,7 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject
objList.removeAll(object);
}
}
window->setProperty(Constants::kHitTestVisibleInChromeFlag, QVariant::fromValue(objList));
window->setProperty(Constants::kHitTestVisibleFlag, QVariant::fromValue(objList));
}
int FramelessWindowsManager::getResizeBorderThickness(const QWindow *window)
@ -165,7 +165,7 @@ void FramelessWindowsManager::removeWindow(QWindow *window)
return;
}
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION
//framelessHelperUnix()->bringBackWindowFrame(window);
framelessHelperUnix()->bringBackWindowFrame(window);
#else
FramelessHelperWin::removeFramelessWindow(window);
#endif

View File

@ -39,7 +39,7 @@ namespace FramelessWindowsManager
FRAMELESSHELPER_API void addWindow(QWindow *window);
FRAMELESSHELPER_API void removeWindow(QWindow *window);
FRAMELESSHELPER_API bool isWindowFrameless(const QWindow *window);
FRAMELESSHELPER_API void setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value = true);
FRAMELESSHELPER_API void setHitTestVisible(QWindow *window, QObject *object, const bool value = true);
FRAMELESSHELPER_API int getResizeBorderThickness(const QWindow *window);
FRAMELESSHELPER_API void setResizeBorderThickness(QWindow *window, const int value);
FRAMELESSHELPER_API int getTitleBarHeight(const QWindow *window);

View File

@ -49,11 +49,6 @@ QWindow *Utilities::findWindow(const WId winId)
return nullptr;
}
bool Utilities::shouldUseNativeTitleBar()
{
return qEnvironmentVariableIsSet(Constants::kUseNativeTitleBarFlag);
}
bool Utilities::isWindowFixedSize(const QWindow *window)
{
Q_ASSERT(window);
@ -73,13 +68,13 @@ bool Utilities::isWindowFixedSize(const QWindow *window)
return false;
}
bool Utilities::isHitTestVisibleInChrome(const QWindow *window)
bool Utilities::isHitTestVisible(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return false;
}
const auto objs = qvariant_cast<QObjectList>(window->property(Constants::kHitTestVisibleInChromeFlag));
const auto objs = qvariant_cast<QObjectList>(window->property(Constants::kHitTestVisibleFlag));
if (objs.isEmpty()) {
return false;
}

View File

@ -35,9 +35,8 @@ namespace Utilities
FRAMELESSHELPER_API int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue = false);
FRAMELESSHELPER_API QWindow *findWindow(const WId winId);
FRAMELESSHELPER_API bool shouldUseNativeTitleBar();
FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window);
FRAMELESSHELPER_API bool isHitTestVisibleInChrome(const QWindow *window);
FRAMELESSHELPER_API bool isHitTestVisible(const QWindow *window);
FRAMELESSHELPER_API QPointF mapOriginPointToWindow(const QObject *object);
FRAMELESSHELPER_API QColor getColorizationColor();
FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const WId winId);
@ -55,7 +54,6 @@ FRAMELESSHELPER_API bool isDwmCompositionAvailable();
FRAMELESSHELPER_API void triggerFrameChange(const WId winId);
FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset);
FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable);
FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function, const HRESULT hr);
FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function);
#endif // Q_OS_WINDOWS

View File

@ -69,6 +69,39 @@ static inline bool isWin1019H1OrGreater()
return result;
}
static inline QString __getSystemErrorMessage(const QString &function, const DWORD code)
{
Q_ASSERT(!function.isEmpty());
if (function.isEmpty()) {
return {};
}
if (code == ERROR_SUCCESS) {
return {};
}
LPWSTR buf = nullptr;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&buf), 0, nullptr) == 0) {
return {};
}
const QString message = QStringLiteral("Function %1() failed with error code %2: %3.")
.arg(function, QString::number(code), QString::fromWCharArray(buf));
LocalFree(buf);
return message;
}
static inline QString __getSystemErrorMessage(const QString &function, const HRESULT hr)
{
Q_ASSERT(!function.isEmpty());
if (function.isEmpty()) {
return {};
}
if (SUCCEEDED(hr)) {
return {};
}
const DWORD dwError = HRESULT_CODE(hr);
return __getSystemErrorMessage(function, dwError);
}
bool Utilities::isWin8OrGreater()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
@ -110,7 +143,7 @@ bool Utilities::isDwmCompositionAvailable()
if (SUCCEEDED(hr)) {
return (enabled != FALSE);
} else {
qWarning() << getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr);
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr);
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
bool ok = false;
const DWORD value = registry.value(QStringLiteral("Composition"), 0).toUInt(&ok);
@ -204,7 +237,7 @@ void Utilities::updateFrameMargins(const WId winId, const bool reset)
const MARGINS margins = reset ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1};
const HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
if (FAILED(hr)) {
qWarning() << getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr);
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr);
}
}
@ -240,53 +273,29 @@ void Utilities::updateQtFrameMargins(QWindow *window, const bool enable)
#endif
}
QString Utilities::getSystemErrorMessage(const QString &function, const HRESULT hr)
{
Q_ASSERT(!function.isEmpty());
if (function.isEmpty()) {
return {};
}
if (SUCCEEDED(hr)) {
return QStringLiteral("Operation succeeded.");
}
const DWORD dwError = HRESULT_CODE(hr);
LPWSTR buf = nullptr;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, nullptr) == 0) {
return QStringLiteral("Failed to retrieve the error message from system.");
}
const QString message = QStringLiteral("%1 failed with error %2: %3.")
.arg(function, QString::number(dwError), QString::fromWCharArray(buf));
LocalFree(buf);
return message;
}
QString Utilities::getSystemErrorMessage(const QString &function)
{
Q_ASSERT(!function.isEmpty());
if (function.isEmpty()) {
return {};
}
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr)) {
return QStringLiteral("Operation succeeded.");
const DWORD code = GetLastError();
if (code == ERROR_SUCCESS) {
return {};
}
return getSystemErrorMessage(function, hr);
return __getSystemErrorMessage(function, code);
}
QColor Utilities::getColorizationColor()
{
COLORREF color = RGB(0, 0, 0);
DWORD color = 0;
BOOL opaque = FALSE;
const HRESULT hr = DwmGetColorizationColor(&color, &opaque);
if (FAILED(hr)) {
qWarning() << getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr);
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr);
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
bool ok = false;
color = registry.value(QStringLiteral("ColorizationColor"), 0).toUInt(&ok);
if (!ok || (color == 0)) {
color = RGB(128, 128, 128); // Dark gray
}
}
return QColor::fromRgba(color);
}

View File

@ -86,7 +86,11 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
Q_NAMESPACE_EXPORT(FRAMELESSHELPER_API)
#else
Q_NAMESPACE
#endif
namespace Constants
{
@ -95,10 +99,7 @@ constexpr char kFramelessModeFlag[] = "_FRAMELESSHELPER_FRAMELESS_MODE";
constexpr char kResizeBorderThicknessFlag[] = "_FRAMELESSHELPER_RESIZE_BORDER_THICKNESS";
constexpr char kCaptionHeightFlag[] = "_FRAMELESSHELPER_CAPTION_HEIGHT";
constexpr char kTitleBarHeightFlag[] = "_FRAMELESSHELPER_TITLE_BAR_HEIGHT";
constexpr char kHitTestVisibleInChromeFlag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE_IN_CHROME";
constexpr char kUseNativeTitleBarFlag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR";
constexpr char kPreserveNativeFrameFlag[] = "_FRAMELESSHELPER_PRESERVE_NATIVE_WINDOW_FRAME";
constexpr char kForcePreserveNativeFrameFlag[] = "_FRAMELESSHELPER_FORCE_PRESERVE_NATIVE_WINDOW_FRAME";
constexpr char kHitTestVisibleFlag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE";
constexpr char kWindowFixedSizeFlag[] = "_FRAMELESSHELPER_WINDOW_FIXED_SIZE";
}

View File

@ -86,7 +86,7 @@ void FramelessQuickHelper::setHitTestVisibleInChrome(QQuickItem *item, const boo
if (!item) {
return;
}
FramelessWindowsManager::setHitTestVisibleInChrome(window(), item, visible);
FramelessWindowsManager::setHitTestVisible(window(), item, visible);
}
FRAMELESSHELPER_END_NAMESPACE