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 "mainwindow.h"
|
||||||
#include <QtGui/qpainter.h>
|
#include <QtGui/qpainter.h>
|
||||||
#include "../../framelesswindowsmanager.h"
|
#include "../../framelesswindowsmanager.h"
|
||||||
|
#include "../../utilities.h"
|
||||||
|
|
||||||
FRAMELESSHELPER_USE_NAMESPACE
|
FRAMELESSHELPER_USE_NAMESPACE
|
||||||
|
|
||||||
|
@ -86,11 +87,11 @@ void MainWindow::showEvent(QShowEvent *event)
|
||||||
const auto win = windowHandle();
|
const auto win = windowHandle();
|
||||||
if (win) {
|
if (win) {
|
||||||
FramelessWindowsManager::addWindow(win);
|
FramelessWindowsManager::addWindow(win);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->iconButton, true);
|
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->iconButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->minimizeButton, true);
|
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->minimizeButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->maximizeButton, true);
|
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->maximizeButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->closeButton, true);
|
FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->closeButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, appMainWindow->menubar, true);
|
FramelessWindowsManager::setHitTestVisible(win, appMainWindow->menubar, true);
|
||||||
setContentsMargins(1, 1, 1, 1);
|
setContentsMargins(1, 1, 1, 1);
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +137,12 @@ void MainWindow::paintEvent(QPaintEvent *event)
|
||||||
{0, h, 0, 0}
|
{0, h, 0, 0}
|
||||||
};
|
};
|
||||||
painter.save();
|
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.drawLines(lines);
|
||||||
painter.restore();
|
painter.restore();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,7 @@ Window {
|
||||||
title: qsTr("Hello, World!")
|
title: qsTr("Hello, World!")
|
||||||
color: "#f0f0f0"
|
color: "#f0f0f0"
|
||||||
|
|
||||||
property real _flh_margin: ((window.visibility === Window.Maximized)
|
property real _flh_margin: ((window.visibility === Window.Maximized) | (window.visibility === Window.FullScreen)) ? 0.0 : (1.0 / Screen.devicePixelRatio)
|
||||||
|| (window.visibility
|
|
||||||
=== Window.FullScreen)) ? 0.0 : (1.0 / Screen.devicePixelRatio)
|
|
||||||
property var _win_prev_state: null
|
property var _win_prev_state: null
|
||||||
|
|
||||||
FramelessHelper {
|
FramelessHelper {
|
||||||
|
@ -83,14 +81,12 @@ Window {
|
||||||
MinimizeButton {
|
MinimizeButton {
|
||||||
id: minimizeButton
|
id: minimizeButton
|
||||||
onClicked: window.showMinimized()
|
onClicked: window.showMinimized()
|
||||||
Component.onCompleted: framelessHelper.setHitTestVisibleInChrome(
|
Component.onCompleted: framelessHelper.setHitTestVisible(minimizeButton, true)
|
||||||
minimizeButton, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MaximizeButton {
|
MaximizeButton {
|
||||||
id: maximizeButton
|
id: maximizeButton
|
||||||
maximized: ((window.visibility === Window.Maximized)
|
maximized: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen))
|
||||||
|| (window.visibility === Window.FullScreen))
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (maximized) {
|
if (maximized) {
|
||||||
window.showNormal()
|
window.showNormal()
|
||||||
|
@ -98,15 +94,13 @@ Window {
|
||||||
window.showMaximized()
|
window.showMaximized()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component.onCompleted: framelessHelper.setHitTestVisibleInChrome(
|
Component.onCompleted: framelessHelper.setHitTestVisible(maximizeButton, true)
|
||||||
maximizeButton, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseButton {
|
CloseButton {
|
||||||
id: closeButton
|
id: closeButton
|
||||||
onClicked: window.close()
|
onClicked: window.close()
|
||||||
Component.onCompleted: framelessHelper.setHitTestVisibleInChrome(
|
Component.onCompleted: framelessHelper.setHitTestVisible(closeButton, true)
|
||||||
closeButton, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,9 +99,9 @@ void Widget::showEvent(QShowEvent *event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FramelessWindowsManager::addWindow(win);
|
FramelessWindowsManager::addWindow(win);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_minimizeButton, true);
|
FramelessWindowsManager::setHitTestVisible(win, m_minimizeButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_maximizeButton, true);
|
FramelessWindowsManager::setHitTestVisible(win, m_maximizeButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_closeButton, true);
|
FramelessWindowsManager::setHitTestVisible(win, m_closeButton, true);
|
||||||
const int margin = Utilities::getWindowVisibleFrameBorderThickness(winId());
|
const int margin = Utilities::getWindowVisibleFrameBorderThickness(winId());
|
||||||
setContentsMargins(margin, margin, margin, margin);
|
setContentsMargins(margin, margin, margin, margin);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
|
||||||
}
|
}
|
||||||
return Qt::Edges{};
|
return Qt::Edges{};
|
||||||
} ();
|
} ();
|
||||||
const bool hitTestVisible = Utilities::isHitTestVisibleInChrome(window);
|
const bool hitTestVisible = Utilities::isHitTestVisible(window);
|
||||||
bool isInTitlebarArea = false;
|
bool isInTitlebarArea = false;
|
||||||
if ((window->windowState() == Qt::WindowMaximized)
|
if ((window->windowState() == Qt::WindowMaximized)
|
||||||
|| (window->windowState() == Qt::WindowFullScreen)) {
|
|| (window->windowState() == Qt::WindowFullScreen)) {
|
||||||
|
|
|
@ -86,7 +86,11 @@
|
||||||
|
|
||||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||||
Q_NAMESPACE_EXPORT(FRAMELESSHELPER_API)
|
Q_NAMESPACE_EXPORT(FRAMELESSHELPER_API)
|
||||||
|
#else
|
||||||
|
Q_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Constants
|
namespace Constants
|
||||||
{
|
{
|
||||||
|
@ -95,10 +99,7 @@ namespace Constants
|
||||||
[[maybe_unused]] constexpr char kResizeBorderThicknessFlag[] = "_FRAMELESSHELPER_RESIZE_BORDER_THICKNESS";
|
[[maybe_unused]] constexpr char kResizeBorderThicknessFlag[] = "_FRAMELESSHELPER_RESIZE_BORDER_THICKNESS";
|
||||||
[[maybe_unused]] constexpr char kCaptionHeightFlag[] = "_FRAMELESSHELPER_CAPTION_HEIGHT";
|
[[maybe_unused]] constexpr char kCaptionHeightFlag[] = "_FRAMELESSHELPER_CAPTION_HEIGHT";
|
||||||
[[maybe_unused]] constexpr char kTitleBarHeightFlag[] = "_FRAMELESSHELPER_TITLE_BAR_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 kHitTestVisibleFlag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE";
|
||||||
[[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";
|
[[maybe_unused]] constexpr char kWindowFixedSizeFlag[] = "_FRAMELESSHELPER_WINDOW_FIXED_SIZE";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,28 +32,6 @@
|
||||||
|
|
||||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
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
|
struct FramelessHelperWinData
|
||||||
{
|
{
|
||||||
[[nodiscard]] bool create() {
|
[[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
|
// preserve the four window borders. So we just remove the whole
|
||||||
// window frame, otherwise the code will become much more complex.
|
// window frame, otherwise the code will become much more complex.
|
||||||
|
|
||||||
if (Utilities::shouldUseNativeTitleBar()) {
|
if (static_cast<BOOL>(msg->wParam) == FALSE) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->wParam == FALSE) {
|
|
||||||
*result = 0;
|
*result = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto clientRect = &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0]);
|
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;
|
bool nonClientAreaExists = false;
|
||||||
// We don't need this correction when we're fullscreen. We will
|
// We don't need this correction when we're fullscreen. We will
|
||||||
// have the WS_POPUP size, so we don't have to worry about
|
// have the WS_POPUP size, so we don't have to worry about
|
||||||
|
@ -283,11 +243,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
// a window when it's maximized unless you restore it).
|
// a window when it's maximized unless you restore it).
|
||||||
const int resizeBorderThickness = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true);
|
const int resizeBorderThickness = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true);
|
||||||
clientRect->top += resizeBorderThickness;
|
clientRect->top += resizeBorderThickness;
|
||||||
if (!shouldHaveWindowFrame()) {
|
clientRect->bottom -= resizeBorderThickness;
|
||||||
clientRect->bottom -= resizeBorderThickness;
|
clientRect->left += resizeBorderThickness;
|
||||||
clientRect->left += resizeBorderThickness;
|
clientRect->right -= resizeBorderThickness;
|
||||||
clientRect->right -= resizeBorderThickness;
|
|
||||||
}
|
|
||||||
nonClientAreaExists = true;
|
nonClientAreaExists = true;
|
||||||
}
|
}
|
||||||
// Attempt to detect if there's an autohide taskbar, and if
|
// Attempt to detect if there's an autohide taskbar, and if
|
||||||
|
@ -427,17 +385,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
// area.
|
// area.
|
||||||
case WM_NCUAHDRAWCAPTION:
|
case WM_NCUAHDRAWCAPTION:
|
||||||
case WM_NCUAHDRAWFRAME: {
|
case WM_NCUAHDRAWFRAME: {
|
||||||
if (shouldHaveWindowFrame()) {
|
*result = 0;
|
||||||
break;
|
return true;
|
||||||
} else {
|
|
||||||
*result = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case WM_NCPAINT: {
|
case WM_NCPAINT: {
|
||||||
// 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失
|
// 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失
|
||||||
|
|
||||||
if (!Utilities::isDwmCompositionAvailable() && !shouldHaveWindowFrame()) {
|
if (!Utilities::isDwmCompositionAvailable()) {
|
||||||
// Only block WM_NCPAINT when DWM composition is disabled. If
|
// Only block WM_NCPAINT when DWM composition is disabled. If
|
||||||
// it's blocked when DWM composition is enabled, the frame
|
// it's blocked when DWM composition is enabled, the frame
|
||||||
// shadow won't be drawn.
|
// shadow won't be drawn.
|
||||||
|
@ -448,26 +402,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case WM_NCACTIVATE: {
|
case WM_NCACTIVATE: {
|
||||||
if (shouldHaveWindowFrame()) {
|
if (Utilities::isDwmCompositionAvailable()) {
|
||||||
break;
|
// 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 {
|
} else {
|
||||||
if (Utilities::isDwmCompositionAvailable()) {
|
if (static_cast<BOOL>(msg->wParam) == FALSE) {
|
||||||
// DefWindowProc won't repaint the window border if lParam
|
*result = TRUE;
|
||||||
// (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 {
|
} else {
|
||||||
if (msg->wParam == FALSE) {
|
*result = FALSE;
|
||||||
*result = TRUE;
|
|
||||||
} else {
|
|
||||||
*result = FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
case WM_NCHITTEST: {
|
case WM_NCHITTEST: {
|
||||||
// 原生Win32窗口只有顶边是在窗口内部resize的,其余三边都是在窗口
|
// 原生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
|
// another branch, if you are interested in it, you can give it a
|
||||||
// try.
|
// try.
|
||||||
|
|
||||||
if (Utilities::shouldUseNativeTitleBar()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
|
POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
|
||||||
if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) {
|
if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) {
|
||||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("ScreenToClient"));
|
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)) {
|
if (IsMaximized(msg->hwnd) || (window->windowState() == Qt::WindowFullScreen)) {
|
||||||
isTitleBar = (localMouse.y() >= 0) && (localMouse.y() <= titleBarHeight)
|
isTitleBar = (localMouse.y() >= 0) && (localMouse.y() <= titleBarHeight)
|
||||||
&& (localMouse.x() >= 0) && (localMouse.x() <= windowWidth)
|
&& (localMouse.x() >= 0) && (localMouse.x() <= windowWidth)
|
||||||
&& !Utilities::isHitTestVisibleInChrome(window);
|
&& !Utilities::isHitTestVisible(window);
|
||||||
}
|
}
|
||||||
if (window->windowState() == Qt::WindowNoState) {
|
if (window->windowState() == Qt::WindowNoState) {
|
||||||
isTitleBar = (localMouse.y() > resizeBorderThickness) && (localMouse.y() <= titleBarHeight)
|
isTitleBar = (localMouse.y() > resizeBorderThickness) && (localMouse.y() <= titleBarHeight)
|
||||||
&& (localMouse.x() > resizeBorderThickness) && (localMouse.x() < (windowWidth - resizeBorderThickness))
|
&& (localMouse.x() > resizeBorderThickness) && (localMouse.x() < (windowWidth - resizeBorderThickness))
|
||||||
&& !Utilities::isHitTestVisibleInChrome(window);
|
&& !Utilities::isHitTestVisible(window);
|
||||||
}
|
}
|
||||||
const bool isTop = localMouse.y() <= resizeBorderThickness;
|
const bool isTop = localMouse.y() <= resizeBorderThickness;
|
||||||
if (shouldHaveWindowFrame()) {
|
const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, resizeBorderThickness, windowWidth, isTop, window]{
|
||||||
// This will handle the left, right and bottom parts of the frame
|
if (IsMaximized(msg->hwnd)) {
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
if (isTitleBar) {
|
if (isTitleBar) {
|
||||||
return HTCAPTION;
|
return HTCAPTION;
|
||||||
}
|
}
|
||||||
return HTCLIENT;
|
return HTCLIENT;
|
||||||
}();
|
}
|
||||||
*result = hitTestResult;
|
const LONG windowHeight = clientRect.bottom;
|
||||||
return true;
|
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_SETICON:
|
||||||
case WM_SETTEXT: {
|
case WM_SETTEXT: {
|
||||||
if (Utilities::shouldUseNativeTitleBar()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable painting while these messages are handled to prevent them
|
// Disable painting while these messages are handled to prevent them
|
||||||
// from drawing a window caption over the client area.
|
// from drawing a window caption over the client area.
|
||||||
|
SetLastError(ERROR_SUCCESS);
|
||||||
const LONG_PTR oldStyle = GetWindowLongPtrW(msg->hwnd, GWL_STYLE);
|
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
|
// Prevent Windows from drawing the default title bar by temporarily
|
||||||
// toggling the WS_VISIBLE style.
|
// toggling the WS_VISIBLE style.
|
||||||
|
SetLastError(ERROR_SUCCESS);
|
||||||
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle & ~WS_VISIBLE)) == 0) {
|
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle & ~WS_VISIBLE)) == 0) {
|
||||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||||
break;
|
break;
|
||||||
|
@ -657,6 +580,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
const auto winId = reinterpret_cast<WId>(msg->hwnd);
|
const auto winId = reinterpret_cast<WId>(msg->hwnd);
|
||||||
Utilities::triggerFrameChange(winId);
|
Utilities::triggerFrameChange(winId);
|
||||||
const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
|
const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
|
||||||
|
SetLastError(ERROR_SUCCESS);
|
||||||
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) {
|
if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) {
|
||||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
|
||||||
break;
|
break;
|
||||||
|
@ -665,15 +589,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
*result = ret;
|
*result = ret;
|
||||||
return true;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,11 +90,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GET_X_LPARAM
|
#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
|
#endif
|
||||||
|
|
||||||
#ifndef GET_Y_LPARAM
|
#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
|
#endif
|
||||||
|
|
||||||
#ifndef IsMinimized
|
#ifndef IsMinimized
|
||||||
|
@ -105,13 +105,13 @@
|
||||||
#define IsMaximized(window) (IsZoomed(window) != FALSE)
|
#define IsMaximized(window) (IsZoomed(window) != FALSE)
|
||||||
#endif
|
#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 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 char kPersonalizeRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)";
|
||||||
|
|
||||||
[[maybe_unused]] constexpr int kDefaultResizeBorderThicknessClassic = 4;
|
[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessClassic = 4;
|
||||||
[[maybe_unused]] constexpr int kDefaultResizeBorderThicknessAero = 8;
|
[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessAero = 8;
|
||||||
[[maybe_unused]] constexpr int kDefaultCaptionHeight = 23;
|
[[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());
|
return FramelessWindowsManager::isWindowFrameless(window());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessQuickHelper::setHitTestVisibleInChrome(QQuickItem *item, const bool visible)
|
void FramelessQuickHelper::setHitTestVisible(QQuickItem *item, const bool visible)
|
||||||
{
|
{
|
||||||
Q_ASSERT(item);
|
Q_ASSERT(item);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(window(), item, visible);
|
FramelessWindowsManager::setHitTestVisible(window(), item, visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
FRAMELESSHELPER_END_NAMESPACE
|
FRAMELESSHELPER_END_NAMESPACE
|
||||||
|
|
|
@ -57,7 +57,7 @@ public Q_SLOTS:
|
||||||
void removeWindowFrame();
|
void removeWindowFrame();
|
||||||
void bringBackWindowFrame();
|
void bringBackWindowFrame();
|
||||||
Q_NODISCARD bool isWindowFrameless() const;
|
Q_NODISCARD bool isWindowFrameless() const;
|
||||||
void setHitTestVisibleInChrome(QQuickItem *item, const bool visible);
|
void setHitTestVisible(QQuickItem *item, const bool visible);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void resizeBorderThicknessChanged(qreal);
|
void resizeBorderThicknessChanged(qreal);
|
||||||
|
|
|
@ -62,7 +62,7 @@ void FramelessWindowsManager::addWindow(QWindow *window)
|
||||||
#endif
|
#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(window);
|
||||||
Q_ASSERT(object);
|
Q_ASSERT(object);
|
||||||
|
@ -73,7 +73,7 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject
|
||||||
qWarning() << object << "is not a QWidget or QQuickItem.";
|
qWarning() << object << "is not a QWidget or QQuickItem.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto objList = qvariant_cast<QObjectList>(window->property(Constants::kHitTestVisibleInChromeFlag));
|
auto objList = qvariant_cast<QObjectList>(window->property(Constants::kHitTestVisibleFlag));
|
||||||
if (value) {
|
if (value) {
|
||||||
if (objList.isEmpty() || !objList.contains(object)) {
|
if (objList.isEmpty() || !objList.contains(object)) {
|
||||||
objList.append(object);
|
objList.append(object);
|
||||||
|
@ -83,7 +83,7 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject
|
||||||
objList.removeAll(object);
|
objList.removeAll(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window->setProperty(Constants::kHitTestVisibleInChromeFlag, QVariant::fromValue(objList));
|
window->setProperty(Constants::kHitTestVisibleFlag, QVariant::fromValue(objList));
|
||||||
}
|
}
|
||||||
|
|
||||||
int FramelessWindowsManager::getResizeBorderThickness(const QWindow *window)
|
int FramelessWindowsManager::getResizeBorderThickness(const QWindow *window)
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace FramelessWindowsManager
|
||||||
FRAMELESSHELPER_API void addWindow(QWindow *window);
|
FRAMELESSHELPER_API void addWindow(QWindow *window);
|
||||||
FRAMELESSHELPER_API void removeWindow(QWindow *window);
|
FRAMELESSHELPER_API void removeWindow(QWindow *window);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool isWindowFrameless(const QWindow *window);
|
[[nodiscard]] FRAMELESSHELPER_API bool isWindowFrameless(const QWindow *window);
|
||||||
FRAMELESSHELPER_API void setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value = true);
|
FRAMELESSHELPER_API void setHitTestVisible(QWindow *window, QObject *object, const bool value = true);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API int getResizeBorderThickness(const QWindow *window);
|
[[nodiscard]] FRAMELESSHELPER_API int getResizeBorderThickness(const QWindow *window);
|
||||||
FRAMELESSHELPER_API void setResizeBorderThickness(QWindow *window, const int value);
|
FRAMELESSHELPER_API void setResizeBorderThickness(QWindow *window, const int value);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API int getTitleBarHeight(const QWindow *window);
|
[[nodiscard]] FRAMELESSHELPER_API int getTitleBarHeight(const QWindow *window);
|
||||||
|
|
|
@ -49,11 +49,6 @@ QWindow *Utilities::findWindow(const WId winId)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Utilities::shouldUseNativeTitleBar()
|
|
||||||
{
|
|
||||||
return qEnvironmentVariableIsSet(Constants::kUseNativeTitleBarFlag);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Utilities::isWindowFixedSize(const QWindow *window)
|
bool Utilities::isWindowFixedSize(const QWindow *window)
|
||||||
{
|
{
|
||||||
Q_ASSERT(window);
|
Q_ASSERT(window);
|
||||||
|
@ -73,13 +68,13 @@ bool Utilities::isWindowFixedSize(const QWindow *window)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Utilities::isHitTestVisibleInChrome(const QWindow *window)
|
bool Utilities::isHitTestVisible(const QWindow *window)
|
||||||
{
|
{
|
||||||
Q_ASSERT(window);
|
Q_ASSERT(window);
|
||||||
if (!window) {
|
if (!window) {
|
||||||
return false;
|
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()) {
|
if (objs.isEmpty()) {
|
||||||
return false;
|
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 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 QWindow *findWindow(const WId winId);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool shouldUseNativeTitleBar();
|
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window);
|
[[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 QPointF mapOriginPointToWindow(const QObject *object);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor();
|
[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor();
|
||||||
[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const WId winId);
|
[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const WId winId);
|
||||||
|
@ -54,7 +53,6 @@ namespace Utilities
|
||||||
FRAMELESSHELPER_API void triggerFrameChange(const WId winId);
|
FRAMELESSHELPER_API void triggerFrameChange(const WId winId);
|
||||||
FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset);
|
FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset);
|
||||||
FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable);
|
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);
|
[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,39 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
return result;
|
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()
|
bool Utilities::isWin8OrGreater()
|
||||||
{
|
{
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||||
|
@ -110,7 +143,7 @@ bool Utilities::isDwmCompositionAvailable()
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
return (enabled != FALSE);
|
return (enabled != FALSE);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr);
|
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr);
|
||||||
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
|
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
const DWORD value = registry.value(QStringLiteral("Composition"), 0).toUInt(&ok);
|
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 MARGINS margins = reset ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1};
|
||||||
const HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
|
const HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
|
||||||
if (FAILED(hr)) {
|
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
|
#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)
|
QString Utilities::getSystemErrorMessage(const QString &function)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!function.isEmpty());
|
Q_ASSERT(!function.isEmpty());
|
||||||
if (function.isEmpty()) {
|
if (function.isEmpty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
const DWORD code = GetLastError();
|
||||||
if (SUCCEEDED(hr)) {
|
if (code == ERROR_SUCCESS) {
|
||||||
return QStringLiteral("Operation succeeded.");
|
return {};
|
||||||
}
|
}
|
||||||
return getSystemErrorMessage(function, hr);
|
return __getSystemErrorMessage(function, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor Utilities::getColorizationColor()
|
QColor Utilities::getColorizationColor()
|
||||||
{
|
{
|
||||||
COLORREF color = RGB(0, 0, 0);
|
DWORD color = 0;
|
||||||
BOOL opaque = FALSE;
|
BOOL opaque = FALSE;
|
||||||
const HRESULT hr = DwmGetColorizationColor(&color, &opaque);
|
const HRESULT hr = DwmGetColorizationColor(&color, &opaque);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning() << getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr);
|
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr);
|
||||||
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
|
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
color = registry.value(QStringLiteral("ColorizationColor"), 0).toUInt(&ok);
|
color = registry.value(QStringLiteral("ColorizationColor"), 0).toUInt(&ok);
|
||||||
if (!ok || (color == 0)) {
|
|
||||||
color = RGB(128, 128, 128); // Dark gray
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return QColor::fromRgba(color);
|
return QColor::fromRgba(color);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue