Quality improvements
1. Use native frame color in the MainWindow example, just like the Widget example. Fixes #87 2. Rename setHitTestVisibleInChrome() to setHitTestVisible(): This name was taken from Microsoft's WindowChrome class in WPF. Now they removed the legacy "Chrome" suffix in their new products, so we removed it as well. 3. Fix build with Qt older than 5.15: Q_NAMESPACE_EXPORT was introduced in Qt 5.14 4. Removed code that supports native frame: they are just leftovers of the previous refactoring. 4. Correctly detect SetWindowLongPtrW() and GetWindowLongPtrW() 's operation result: they won't modify the Last Error state on success, so we have to set Last Error state to ERROR_SUCCESS before calling them to make sure we get the correct error code. 5. Remove implicitly conversions, use explicit casts where possible 6. Fixed FormatMessage() usage, correctly retrieve the error message: According to MSDN, we should pass the address of a LPWSTR, not the LPWSTR itself. 7. Removed the special handing of WM_SIZE: It turns out that this handling is not needed at all and it's causing new issues, so just remove it. Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
0bfefb25d0
commit
330669e34a
|
@ -25,6 +25,7 @@
|
|||
#include "mainwindow.h"
|
||||
#include <QtGui/qpainter.h>
|
||||
#include "../../framelesswindowsmanager.h"
|
||||
#include "../../utilities.h"
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
|
@ -86,11 +87,11 @@ void MainWindow::showEvent(QShowEvent *event)
|
|||
const auto win = windowHandle();
|
||||
if (win) {
|
||||
FramelessWindowsManager::addWindow(win);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->iconButton, true);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->minimizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->maximizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->closeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, appMainWindow->menubar, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->iconButton, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->minimizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->maximizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->closeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, appMainWindow->menubar, true);
|
||||
setContentsMargins(1, 1, 1, 1);
|
||||
inited = true;
|
||||
}
|
||||
|
@ -136,7 +137,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::All));
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -36,9 +36,7 @@ Window {
|
|||
title: qsTr("Hello, World!")
|
||||
color: "#f0f0f0"
|
||||
|
||||
property real _flh_margin: ((window.visibility === Window.Maximized)
|
||||
|| (window.visibility
|
||||
=== Window.FullScreen)) ? 0.0 : (1.0 / Screen.devicePixelRatio)
|
||||
property real _flh_margin: ((window.visibility === Window.Maximized) | (window.visibility === Window.FullScreen)) ? 0.0 : (1.0 / Screen.devicePixelRatio)
|
||||
property var _win_prev_state: null
|
||||
|
||||
FramelessHelper {
|
||||
|
@ -83,14 +81,12 @@ Window {
|
|||
MinimizeButton {
|
||||
id: minimizeButton
|
||||
onClicked: window.showMinimized()
|
||||
Component.onCompleted: framelessHelper.setHitTestVisibleInChrome(
|
||||
minimizeButton, true)
|
||||
Component.onCompleted: framelessHelper.setHitTestVisible(minimizeButton, true)
|
||||
}
|
||||
|
||||
MaximizeButton {
|
||||
id: maximizeButton
|
||||
maximized: ((window.visibility === Window.Maximized)
|
||||
|| (window.visibility === Window.FullScreen))
|
||||
maximized: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen))
|
||||
onClicked: {
|
||||
if (maximized) {
|
||||
window.showNormal()
|
||||
|
@ -98,15 +94,13 @@ Window {
|
|||
window.showMaximized()
|
||||
}
|
||||
}
|
||||
Component.onCompleted: framelessHelper.setHitTestVisibleInChrome(
|
||||
maximizeButton, true)
|
||||
Component.onCompleted: framelessHelper.setHitTestVisible(maximizeButton, true)
|
||||
}
|
||||
|
||||
CloseButton {
|
||||
id: closeButton
|
||||
onClicked: window.close()
|
||||
Component.onCompleted: framelessHelper.setHitTestVisibleInChrome(
|
||||
closeButton, true)
|
||||
Component.onCompleted: framelessHelper.setHitTestVisible(closeButton, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,9 +99,9 @@ void Widget::showEvent(QShowEvent *event)
|
|||
return;
|
||||
}
|
||||
FramelessWindowsManager::addWindow(win);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_minimizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_maximizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_closeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, m_minimizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, m_maximizeButton, true);
|
||||
FramelessWindowsManager::setHitTestVisible(win, m_closeButton, true);
|
||||
const int margin = Utilities::getWindowVisibleFrameBorderThickness(winId());
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
|
|||
}
|
||||
return Qt::Edges{};
|
||||
} ();
|
||||
const bool hitTestVisible = Utilities::isHitTestVisibleInChrome(window);
|
||||
const bool hitTestVisible = Utilities::isHitTestVisible(window);
|
||||
bool isInTitlebarArea = false;
|
||||
if ((window->windowState() == Qt::WindowMaximized)
|
||||
|| (window->windowState() == Qt::WindowFullScreen)) {
|
||||
|
|
|
@ -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 @@ namespace Constants
|
|||
[[maybe_unused]] constexpr char kResizeBorderThicknessFlag[] = "_FRAMELESSHELPER_RESIZE_BORDER_THICKNESS";
|
||||
[[maybe_unused]] constexpr char kCaptionHeightFlag[] = "_FRAMELESSHELPER_CAPTION_HEIGHT";
|
||||
[[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 kHitTestVisibleFlag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE";
|
||||
[[maybe_unused]] constexpr char kWindowFixedSizeFlag[] = "_FRAMELESSHELPER_WINDOW_FIXED_SIZE";
|
||||
|
||||
}
|
||||
|
|
|
@ -32,28 +32,6 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
[[nodiscard]] 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
|
||||
{
|
||||
[[nodiscard]] 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
|
||||
|
@ -283,11 +243,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// a window when it's maximized unless you restore it).
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
[[maybe_unused]] constexpr int kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels
|
||||
[[maybe_unused]] constexpr UINT kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels
|
||||
|
||||
[[maybe_unused]] constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)";
|
||||
[[maybe_unused]] constexpr char kPersonalizeRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)";
|
||||
|
||||
[[maybe_unused]] constexpr int kDefaultResizeBorderThicknessClassic = 4;
|
||||
[[maybe_unused]] constexpr int kDefaultResizeBorderThicknessAero = 8;
|
||||
[[maybe_unused]] constexpr int kDefaultCaptionHeight = 23;
|
||||
[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessClassic = 4;
|
||||
[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessAero = 8;
|
||||
[[maybe_unused]] constexpr UINT kDefaultCaptionHeight = 23;
|
||||
|
||||
[[maybe_unused]] constexpr WORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37;
|
||||
[[maybe_unused]] constexpr DWORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37;
|
||||
|
|
|
@ -80,13 +80,13 @@ bool FramelessQuickHelper::isWindowFrameless() const
|
|||
return FramelessWindowsManager::isWindowFrameless(window());
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setHitTestVisibleInChrome(QQuickItem *item, const bool visible)
|
||||
void FramelessQuickHelper::setHitTestVisible(QQuickItem *item, const bool visible)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
FramelessWindowsManager::setHitTestVisibleInChrome(window(), item, visible);
|
||||
FramelessWindowsManager::setHitTestVisible(window(), item, visible);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -57,7 +57,7 @@ public Q_SLOTS:
|
|||
void removeWindowFrame();
|
||||
void bringBackWindowFrame();
|
||||
Q_NODISCARD bool isWindowFrameless() const;
|
||||
void setHitTestVisibleInChrome(QQuickItem *item, const bool visible);
|
||||
void setHitTestVisible(QQuickItem *item, const bool visible);
|
||||
|
||||
Q_SIGNALS:
|
||||
void resizeBorderThicknessChanged(qreal);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace FramelessWindowsManager
|
|||
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);
|
||||
FRAMELESSHELPER_API void setHitTestVisible(QWindow *window, QObject *object, const bool value = true);
|
||||
[[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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -34,9 +34,8 @@ namespace Utilities
|
|||
|
||||
[[nodiscard]] FRAMELESSHELPER_API int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue = false);
|
||||
[[nodiscard]] FRAMELESSHELPER_API QWindow *findWindow(const WId winId);
|
||||
[[nodiscard]] FRAMELESSHELPER_API bool shouldUseNativeTitleBar();
|
||||
[[nodiscard]] FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window);
|
||||
[[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisibleInChrome(const QWindow *window);
|
||||
[[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisible(const QWindow *window);
|
||||
[[nodiscard]] FRAMELESSHELPER_API QPointF mapOriginPointToWindow(const QObject *object);
|
||||
[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor();
|
||||
[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const WId winId);
|
||||
|
@ -54,7 +53,6 @@ namespace Utilities
|
|||
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);
|
||||
[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function, const HRESULT hr);
|
||||
[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -69,6 +69,39 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] 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;
|
||||
}
|
||||
|
||||
[[nodiscard]] 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);
|
||||
|
@ -219,7 +252,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,53 +288,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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue