win: refactor

This commit is contained in:
Yuhang Zhao 2023-08-23 18:04:31 +08:00
parent 644266923b
commit a130fef677
11 changed files with 512 additions and 458 deletions

View File

@ -89,11 +89,6 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 defaultScreenDpi(); [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 defaultScreenDpi();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowAccelerated(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowAccelerated(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowTransparent(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowTransparent(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::MouseButtons queryMouseButtons();
FRAMELESSHELPER_CORE_API void emulateQtMouseEvent(
const QObject *target, const QWindow *window, const Global::ButtonState buttonState,
const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos,
const bool underMouse, const bool hoverEnabled);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
@ -151,7 +146,7 @@ FRAMELESSHELPER_CORE_API void emulateQtMouseEvent(
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint64 getMouseButtonsAndModifiers(const bool async); [[nodiscard]] FRAMELESSHELPER_CORE_API quint64 getKeyState();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowSystemFrameMargins(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowSystemFrameMargins(const WId windowId);

View File

@ -63,7 +63,7 @@ public:
Q_NODISCARD QColor getActiveForegroundColor() const; Q_NODISCARD QColor getActiveForegroundColor() const;
Q_NODISCARD QColor getInactiveForegroundColor() const; Q_NODISCARD QColor getInactiveForegroundColor() const;
Q_NODISCARD bool isActive() const; Q_NODISCARD bool isActive() const;
Q_NODISCARD int iconSize2() const; Q_NODISCARD int glyphSize() const;
void setHoverColor(const QColor &value); void setHoverColor(const QColor &value);
void setPressColor(const QColor &value); void setPressColor(const QColor &value);
@ -71,7 +71,7 @@ public:
void setActiveForegroundColor(const QColor &value); void setActiveForegroundColor(const QColor &value);
void setInactiveForegroundColor(const QColor &value); void setInactiveForegroundColor(const QColor &value);
void setActive(const bool value); void setActive(const bool value);
void setIconSize2(const int value); void setGlyphSize(const int value);
void paintEventHandler(QPaintEvent *event); void paintEventHandler(QPaintEvent *event);
@ -88,7 +88,7 @@ private:
QColor m_activeForegroundColor = {}; QColor m_activeForegroundColor = {};
QColor m_inactiveForegroundColor = {}; QColor m_inactiveForegroundColor = {};
bool m_active = false; bool m_active = false;
std::optional<int> m_iconSize2 = std::nullopt; std::optional<int> m_glyphSize = std::nullopt;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -44,7 +44,7 @@ class FRAMELESSHELPER_WIDGETS_API StandardSystemButton : public QPushButton
Q_PROPERTY(QColor activeForegroundColor READ activeForegroundColor WRITE setActiveForegroundColor NOTIFY activeForegroundColorChanged FINAL) Q_PROPERTY(QColor activeForegroundColor READ activeForegroundColor WRITE setActiveForegroundColor NOTIFY activeForegroundColorChanged FINAL)
Q_PROPERTY(QColor inactiveForegroundColor READ inactiveForegroundColor WRITE setInactiveForegroundColor NOTIFY inactiveForegroundColorChanged FINAL) Q_PROPERTY(QColor inactiveForegroundColor READ inactiveForegroundColor WRITE setInactiveForegroundColor NOTIFY inactiveForegroundColorChanged FINAL)
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged FINAL) Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged FINAL)
Q_PROPERTY(int iconSize2 READ iconSize2 WRITE setIconSize2 NOTIFY iconSize2Changed FINAL) Q_PROPERTY(int glyphSize READ glyphSize WRITE setGlyphSize NOTIFY glyphSizeChanged FINAL)
public: public:
explicit StandardSystemButton(QWidget *parent = nullptr); explicit StandardSystemButton(QWidget *parent = nullptr);
@ -60,7 +60,7 @@ public:
Q_NODISCARD QColor activeForegroundColor() const; Q_NODISCARD QColor activeForegroundColor() const;
Q_NODISCARD QColor inactiveForegroundColor() const; Q_NODISCARD QColor inactiveForegroundColor() const;
Q_NODISCARD bool isActive() const; Q_NODISCARD bool isActive() const;
Q_NODISCARD int iconSize2() const; Q_NODISCARD int glyphSize() const;
public Q_SLOTS: public Q_SLOTS:
void setButtonType(const Global::SystemButtonType value); void setButtonType(const Global::SystemButtonType value);
@ -71,7 +71,7 @@ public Q_SLOTS:
void setActiveForegroundColor(const QColor &value); void setActiveForegroundColor(const QColor &value);
void setInactiveForegroundColor(const QColor &value); void setInactiveForegroundColor(const QColor &value);
void setActive(const bool value); void setActive(const bool value);
void setIconSize2(const int value); void setGlyphSize(const int value);
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
@ -85,7 +85,7 @@ Q_SIGNALS:
void activeForegroundColorChanged(); void activeForegroundColorChanged();
void inactiveForegroundColorChanged(); void inactiveForegroundColorChanged();
void activeChanged(); void activeChanged();
void iconSize2Changed(); void glyphSizeChanged();
private: private:
QScopedPointer<StandardSystemButtonPrivate> d_ptr; QScopedPointer<StandardSystemButtonPrivate> d_ptr;

View File

@ -30,6 +30,7 @@
#include "winverhelper_p.h" #include "winverhelper_p.h"
#include "framelesshelper_windows.h" #include "framelesshelper_windows.h"
#include "framelesshelpercore_global_p.h" #include "framelesshelpercore_global_p.h"
#include "scopeguard_p.h"
#include <optional> #include <optional>
#include <memory> #include <memory>
#include <QtCore/qhash.h> #include <QtCore/qhash.h>
@ -85,10 +86,20 @@ FRAMELESSHELPER_STRING_CONSTANT(DestroyWindow)
FRAMELESSHELPER_STRING_CONSTANT(GetWindowPlacement) FRAMELESSHELPER_STRING_CONSTANT(GetWindowPlacement)
FRAMELESSHELPER_STRING_CONSTANT(SetWindowPlacement) FRAMELESSHELPER_STRING_CONSTANT(SetWindowPlacement)
enum class WindowPart : quint8
{
NotInterested,
ClientArea,
ChromeButton,
ResizeBorder,
FixBorder,
TitleBar
};
struct FramelessWin32HelperData struct FramelessWin32HelperData
{ {
SystemParameters params = {}; SystemParameters params = {};
bool trackingMouse = false; int hitTestResult = HTNOWHERE;
Dpi dpi = {}; Dpi dpi = {};
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
QRect restoreGeometry = {}; QRect restoreGeometry = {};
@ -146,6 +157,36 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
return result; return result;
} }
[[nodiscard]] static inline WindowPart getHittedWindowPart(const LRESULT hitTestResult)
{
switch (hitTestResult) {
case HTCLIENT:
return WindowPart::ClientArea;
case HTCAPTION:
return WindowPart::TitleBar;
case HTSYSMENU:
case HTHELP:
case HTREDUCE:
case HTZOOM:
case HTCLOSE:
return WindowPart::ChromeButton;
case HTLEFT:
case HTRIGHT:
case HTTOP:
case HTTOPLEFT:
case HTTOPRIGHT:
case HTBOTTOM:
case HTBOTTOMLEFT:
case HTBOTTOMRIGHT:
return WindowPart::ResizeBorder;
case HTBORDER:
return WindowPart::FixBorder;
default:
break;
}
return WindowPart::NotInterested;
}
FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {} FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {}
FramelessHelperWin::~FramelessHelperWin() = default; FramelessHelperWin::~FramelessHelperWin() = default;
@ -288,48 +329,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}; };
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
#if 0
const auto releaseButtons = [&data](const std::optional<SystemButtonType> exclude) -> void {
static constexpr const auto defaultButtonState = ButtonState::Normal;
const SystemButtonType button = exclude.value_or(SystemButtonType::Unknown);
if (button != SystemButtonType::WindowIcon) {
data.params.setSystemButtonState(SystemButtonType::WindowIcon, defaultButtonState);
}
if (button != SystemButtonType::Help) {
data.params.setSystemButtonState(SystemButtonType::Help, defaultButtonState);
}
if (button != SystemButtonType::Minimize) {
data.params.setSystemButtonState(SystemButtonType::Minimize, defaultButtonState);
}
if (button != SystemButtonType::Maximize) {
data.params.setSystemButtonState(SystemButtonType::Maximize, defaultButtonState);
}
if (button != SystemButtonType::Restore) {
data.params.setSystemButtonState(SystemButtonType::Restore, defaultButtonState);
}
if (button != SystemButtonType::Close) {
data.params.setSystemButtonState(SystemButtonType::Close, defaultButtonState);
}
};
const auto hoverButton = [&releaseButtons, &data](const SystemButtonType button) -> void {
releaseButtons(button);
data.params.setSystemButtonState(button, ButtonState::Hovered);
};
const auto pressButton = [&releaseButtons, &data](const SystemButtonType button) -> void {
releaseButtons(button);
data.params.setSystemButtonState(button, ButtonState::Pressed);
};
const auto clickButton = [&releaseButtons, &data](const SystemButtonType button) -> void {
releaseButtons(button);
data.params.setSystemButtonState(button, ButtonState::Released);
};
#else
const auto emulateClientAreaMessage = [hWnd, uMsg, wParam, lParam]() -> void { const auto emulateClientAreaMessage = [hWnd, uMsg, wParam, lParam]() -> void {
const auto wparam = [uMsg, wParam]() -> WPARAM { const auto wparam = [uMsg, wParam]() -> WPARAM {
if (uMsg == WM_NCMOUSELEAVE) { if (uMsg == WM_NCMOUSELEAVE) {
return 0; return 0;
} }
const quint64 keyState = Utils::getMouseButtonsAndModifiers(false); const quint64 keyState = Utils::getKeyState();
if ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) { if ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) {
const auto xButtonMask = GET_XBUTTON_WPARAM(wParam); const auto xButtonMask = GET_XBUTTON_WPARAM(wParam);
return MAKEWPARAM(keyState, xButtonMask); return MAKEWPARAM(keyState, xButtonMask);
@ -348,45 +353,51 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} }
return MAKELPARAM(clientPos.x, clientPos.y); return MAKELPARAM(clientPos.x, clientPos.y);
}(); }();
#if 0
# define SEND_MESSAGE ::SendMessageW
#else
# define SEND_MESSAGE ::PostMessageW
#endif
switch (uMsg) { switch (uMsg) {
case WM_NCHITTEST: // Treat hit test messages as mouse move events.
case WM_NCMOUSEMOVE: case WM_NCMOUSEMOVE:
::SendMessageW(hWnd, WM_MOUSEMOVE, wparam, lparam); SEND_MESSAGE(hWnd, WM_MOUSEMOVE, wparam, lparam);
break; break;
case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDOWN:
::SendMessageW(hWnd, WM_LBUTTONDOWN, wparam, lparam); SEND_MESSAGE(hWnd, WM_LBUTTONDOWN, wparam, lparam);
break; break;
case WM_NCLBUTTONUP: case WM_NCLBUTTONUP:
::SendMessageW(hWnd, WM_LBUTTONUP, wparam, lparam); SEND_MESSAGE(hWnd, WM_LBUTTONUP, wparam, lparam);
break; break;
case WM_NCLBUTTONDBLCLK: case WM_NCLBUTTONDBLCLK:
::SendMessageW(hWnd, WM_LBUTTONDBLCLK, wparam, lparam); SEND_MESSAGE(hWnd, WM_LBUTTONDBLCLK, wparam, lparam);
break; break;
case WM_NCRBUTTONDOWN: case WM_NCRBUTTONDOWN:
::SendMessageW(hWnd, WM_RBUTTONDOWN, wparam, lparam); SEND_MESSAGE(hWnd, WM_RBUTTONDOWN, wparam, lparam);
break; break;
case WM_NCRBUTTONUP: case WM_NCRBUTTONUP:
::SendMessageW(hWnd, WM_RBUTTONUP, wparam, lparam); SEND_MESSAGE(hWnd, WM_RBUTTONUP, wparam, lparam);
break; break;
case WM_NCRBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK:
::SendMessageW(hWnd, WM_RBUTTONDBLCLK, wparam, lparam); SEND_MESSAGE(hWnd, WM_RBUTTONDBLCLK, wparam, lparam);
break; break;
case WM_NCMBUTTONDOWN: case WM_NCMBUTTONDOWN:
::SendMessageW(hWnd, WM_MBUTTONDOWN, wparam, lparam); SEND_MESSAGE(hWnd, WM_MBUTTONDOWN, wparam, lparam);
break; break;
case WM_NCMBUTTONUP: case WM_NCMBUTTONUP:
::SendMessageW(hWnd, WM_MBUTTONUP, wparam, lparam); SEND_MESSAGE(hWnd, WM_MBUTTONUP, wparam, lparam);
break; break;
case WM_NCMBUTTONDBLCLK: case WM_NCMBUTTONDBLCLK:
::SendMessageW(hWnd, WM_MBUTTONDBLCLK, wparam, lparam); SEND_MESSAGE(hWnd, WM_MBUTTONDBLCLK, wparam, lparam);
break; break;
case WM_NCXBUTTONDOWN: case WM_NCXBUTTONDOWN:
::SendMessageW(hWnd, WM_XBUTTONDOWN, wparam, lparam); SEND_MESSAGE(hWnd, WM_XBUTTONDOWN, wparam, lparam);
break; break;
case WM_NCXBUTTONUP: case WM_NCXBUTTONUP:
::SendMessageW(hWnd, WM_XBUTTONUP, wparam, lparam); SEND_MESSAGE(hWnd, WM_XBUTTONUP, wparam, lparam);
break; break;
case WM_NCXBUTTONDBLCLK: case WM_NCXBUTTONDBLCLK:
::SendMessageW(hWnd, WM_XBUTTONDBLCLK, wparam, lparam); SEND_MESSAGE(hWnd, WM_XBUTTONDBLCLK, wparam, lparam);
break; break;
#if 0 #if 0
case WM_NCPOINTERUPDATE: case WM_NCPOINTERUPDATE:
@ -395,16 +406,28 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break; break;
#endif #endif
case WM_NCMOUSEHOVER: case WM_NCMOUSEHOVER:
::SendMessageW(hWnd, WM_MOUSEHOVER, wparam, lparam); SEND_MESSAGE(hWnd, WM_MOUSEHOVER, wparam, lparam);
break; break;
case WM_NCMOUSELEAVE: case WM_NCMOUSELEAVE:
::SendMessageW(hWnd, WM_MOUSELEAVE, wparam, lparam); SEND_MESSAGE(hWnd, WM_MOUSELEAVE, wparam, lparam);
break; break;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
}; };
#endif
if (isSnapLayoutEnabled() && (uMsg == WM_MOUSELEAVE)) {
// For some unknown reason, there will be many invalid mouse leave events generated
// when the mouse is hovering above our chrome buttons, which will cause Qt to ignore
// all our mouse move events and thus break the hover state of our controls.
// So we filter out these superfluous mouse leave events here.
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint{ msg->pt.x, msg->pt.y });
SystemButtonType sysButtonType = SystemButtonType::Unknown;
if (data.params.isInsideSystemButtons(qtScenePos, &sysButtonType)) {
*result = FALSE;
return true;
}
}
switch (uMsg) { switch (uMsg) {
#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) // Qt has done this for us since 5.9.0 #if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) // Qt has done this for us since 5.9.0
@ -504,8 +527,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// implement an elaborate client-area preservation technique, and // implement an elaborate client-area preservation technique, and
// simply return 0, which means "preserve the entire old client area // simply return 0, which means "preserve the entire old client area
// and align it with the upper-left corner of our new client area". // and align it with the upper-left corner of our new client area".
const auto clientRect = ((static_cast<BOOL>(wParam) == FALSE) ? const auto clientRect = ((wParam == FALSE) ? reinterpret_cast<LPRECT>(lParam) : &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0]);
reinterpret_cast<LPRECT>(lParam) : &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0]);
if (frameBorderVisible) { if (frameBorderVisible) {
// Store the original top margin before the default window procedure applies the default frame. // Store the original top margin before the default window procedure applies the default frame.
const LONG originalTop = clientRect->top; const LONG originalTop = clientRect->top;
@ -518,7 +540,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// totally OK but since we want to preserve as much original frame as possible, we // totally OK but since we want to preserve as much original frame as possible, we
// can't use that solution. // can't use that solution.
const LRESULT hitTestResult = ::DefWindowProcW(hWnd, WM_NCCALCSIZE, wParam, lParam); const LRESULT hitTestResult = ::DefWindowProcW(hWnd, WM_NCCALCSIZE, wParam, lParam);
if (hitTestResult != FALSE) { if ((hitTestResult != HTERROR) && (hitTestResult != HTNOWHERE)) {
*result = hitTestResult; *result = hitTestResult;
return true; return true;
} }
@ -657,7 +679,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// from Windows 7 to Windows 10. Not tested on Windows 11 yet. Don't know // from Windows 7 to Windows 10. Not tested on Windows 11 yet. Don't know
// whether it exists on Windows XP to Windows Vista or not. // whether it exists on Windows XP to Windows Vista or not.
static const bool needD3DWorkaround = (qEnvironmentVariableIntValue("FRAMELESSHELPER_USE_D3D_WORKAROUND") != 0); static const bool needD3DWorkaround = (qEnvironmentVariableIntValue("FRAMELESSHELPER_USE_D3D_WORKAROUND") != 0);
*result = (((static_cast<BOOL>(wParam) == FALSE) || needD3DWorkaround) ? FALSE : WVR_REDRAW); *result = (((wParam == FALSE) || needD3DWorkaround) ? FALSE : WVR_REDRAW);
return true; return true;
} }
case WM_NCHITTEST: { case WM_NCHITTEST: {
@ -742,6 +764,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// color, our homemade top border can almost have exactly the same // color, our homemade top border can almost have exactly the same
// appearance with the system's one. // appearance with the system's one.
const auto hitTestRecorder = qScopeGuard([&muData, &result](){ muData.hitTestResult = *result; });
const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
POINT nativeLocalPos = nativeGlobalPos; POINT nativeLocalPos = nativeGlobalPos;
if (::ScreenToClient(hWnd, &nativeLocalPos) == FALSE) { if (::ScreenToClient(hWnd, &nativeLocalPos) == FALSE) {
@ -783,7 +807,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const bool full = Utils::isFullScreen(windowId); const bool full = Utils::isFullScreen(windowId);
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
const bool isTop = (nativeLocalPos.y < frameSizeY); const bool isTop = (nativeLocalPos.y < frameSizeY);
const bool leftButtonPressed = (Utils::getMouseButtonsAndModifiers(true) & MK_LBUTTON); const bool leftButtonPressed = (Utils::getKeyState() & MK_LBUTTON);
const bool isTitleBar = (data.params.isInsideTitleBarDraggableArea(qtScenePos) && leftButtonPressed); const bool isTitleBar = (data.params.isInsideTitleBarDraggableArea(qtScenePos) && leftButtonPressed);
const bool isFixedSize = data.params.isWindowFixedSize(); const bool isFixedSize = data.params.isWindowFixedSize();
const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool(); const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool();
@ -843,20 +867,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return true; return true;
} }
if (!isFixedSize) { if (!isFixedSize) {
RECT clientRect = {0, 0, 0, 0}; auto clientRect = RECT{ 0, 0, 0, 0 };
if (::GetClientRect(hWnd, &clientRect) == FALSE) { if (::GetClientRect(hWnd, &clientRect) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kGetClientRect); WARNING << Utils::getSystemErrorMessage(kGetClientRect);
break; break;
} }
const LONG width = clientRect.right; const bool isBottom = (nativeLocalPos.y >= (RECT_HEIGHT(clientRect) - frameSizeY));
const LONG height = clientRect.bottom;
const bool isBottom = (nativeLocalPos.y >= (height - frameSizeY));
// Make the border a little wider to let the user easy to resize on corners. // Make the border a little wider to let the user easy to resize on corners.
const qreal scaleFactor = ((isTop || isBottom) ? 2.0 : 1.0); const auto scaleFactor = ((isTop || isBottom) ? qreal(2) : qreal(1));
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true); const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
const int scaledFrameSizeX = std::round(qreal(frameSizeX) * scaleFactor); const int scaledFrameSizeX = std::round(qreal(frameSizeX) * scaleFactor);
const bool isLeft = (nativeLocalPos.x < scaledFrameSizeX); const bool isLeft = (nativeLocalPos.x < scaledFrameSizeX);
const bool isRight = (nativeLocalPos.x >= (width - scaledFrameSizeX)); const bool isRight = (nativeLocalPos.x >= (RECT_WIDTH(clientRect) - scaledFrameSizeX));
if (dontOverrideCursor && (isTop || isBottom || isLeft || isRight)) { if (dontOverrideCursor && (isTop || isBottom || isLeft || isRight)) {
// Return HTCLIENT instead of HTBORDER here, because the mouse is // Return HTCLIENT instead of HTBORDER here, because the mouse is
// inside the window now, return HTCLIENT to let the controls // inside the window now, return HTCLIENT to let the controls
@ -925,45 +947,23 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
#endif #endif
case WM_NCMOUSEHOVER: case WM_NCMOUSEHOVER:
case WM_NCMOUSELEAVE: { case WM_NCMOUSELEAVE: {
const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult);
const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK));
const WindowPart nowWindowPart = getHittedWindowPart(isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam);
if (uMsg == WM_NCMOUSELEAVE) { if (uMsg == WM_NCMOUSELEAVE) {
muData.trackingMouse = false; if (previousWindowPart == WindowPart::ChromeButton) {
emulateClientAreaMessage(); if (nowWindowPart == WindowPart::ClientArea) {
//*result = FALSE; *result = FALSE;
//return true; return true;
} else {
if ((uMsg == WM_NCMOUSEMOVE) && !data.trackingMouse) {
TRACKMOUSEEVENT tme;
SecureZeroMemory(&tme, sizeof(tme));
tme.cbSize = sizeof(tme);
// TME_NONCLIENT is absolutely critical here. In my experimentation,
// we'd get WM_MOUSELEAVE messages after just a HOVER_DEFAULT
// timeout even though we're not requesting TME_HOVER, which kinda
// ruined the whole point of this.
tme.dwFlags = (TME_LEAVE | TME_NONCLIENT);
tme.hwndTrack = hWnd;
tme.dwHoverTime = HOVER_DEFAULT; // We don't _really_ care about this.
if (::TrackMouseEvent(&tme) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kTrackMouseEvent);
} else { } else {
muData.trackingMouse = true; emulateClientAreaMessage();
} }
} }
const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)); } else {
const auto hitTestResult = (isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam); if (nowWindowPart == WindowPart::ChromeButton) {
switch (hitTestResult) {
case HTSYSMENU:
case HTHELP:
case HTREDUCE:
case HTZOOM:
case HTCLOSE: {
emulateClientAreaMessage(); emulateClientAreaMessage();
//if ((uMsg != WM_NCMOUSEMOVE) && (uMsg != WM_NCMOUSEHOVER)) { *result = (isXButtonMessage ? TRUE : FALSE);
*result = (isXButtonMessage ? TRUE : FALSE); return true;
return true;
//}
}
default:
break;
} }
} }
} break; } break;
@ -1119,7 +1119,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// window activation state change. // window activation state change.
*result = ::DefWindowProcW(hWnd, WM_NCACTIVATE, wParam, -1); *result = ::DefWindowProcW(hWnd, WM_NCACTIVATE, wParam, -1);
} else { } else {
if (static_cast<BOOL>(wParam) == FALSE) { if (wParam == FALSE) {
*result = TRUE; *result = TRUE;
} else { } else {
*result = FALSE; *result = FALSE;

View File

@ -36,7 +36,6 @@
#include <QtGui/qpalette.h> #include <QtGui/qpalette.h>
#include <QtGui/qsurface.h> #include <QtGui/qsurface.h>
#include <QtGui/qsurfaceformat.h> #include <QtGui/qsurfaceformat.h>
#include <QtGui/qevent.h>
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE #ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
# include <QtGui/private/qhighdpiscaling_p.h> # include <QtGui/private/qhighdpiscaling_p.h>
# include <QtGui/private/qwindow_p.h> # include <QtGui/private/qwindow_p.h>
@ -631,157 +630,4 @@ bool Utils::isWindowTransparent(const QWindow *window)
return window->format().hasAlpha(); return window->format().hasAlpha();
} }
void Utils::emulateQtMouseEvent(const QObject *target, const QWindow *window, const ButtonState buttonState,
const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos, const bool underMouse, const bool enableHover)
{
Q_ASSERT(target);
Q_ASSERT(window);
if (!target || !window) {
return;
}
const auto targetObj = const_cast<QObject *>(target);
const auto windowObj = static_cast<QObject *>(const_cast<QWindow *>(window));
const bool isWidget = target->isWidgetType();
static constexpr const char kMouseTrackingProp[] = "mouseTracking";
const bool mouseTrackingEnabled = (isWidget ? target->property(kMouseTrackingProp).toBool() : true);
const bool hoverEnabled = (isWidget ? enableHover : true);
static constexpr const QPoint oldPos = {}; // Not needed.
static constexpr const Qt::MouseButton button = Qt::LeftButton;
const Qt::MouseButtons buttons = QGuiApplication::mouseButtons();
const Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
static constexpr const char kEnteredFlag[] = "__FRAMELESSHELPER_WIDGET_QUICKITEM_ENTERED";
const bool entered = target->property(kEnteredFlag).toBool();
const bool leftButtonPressed = (queryMouseButtons() & Qt::LeftButton);
const auto sendEnterEvent = [&localPos, &scenePos, &globalPos, &modifiers, hoverEnabled](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QEnterEvent enterEvent(localPos, scenePos, globalPos);
#else
QEvent enterEvent(QEvent::Enter);
#endif
QCoreApplication::sendEvent(obj, &enterEvent);
if (hoverEnabled) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
QHoverEvent hoverEnterEvent(QEvent::HoverEnter, scenePos, globalPos, oldPos, modifiers);
#elif (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QHoverEvent hoverEnterEvent(QEvent::HoverEnter, localPos, globalPos, oldPos, modifiers);
#else
QHoverEvent hoverEnterEvent(QEvent::HoverEnter, localPos, oldPos, modifiers);
#endif
QCoreApplication::sendEvent(obj, &hoverEnterEvent);
}
};
const auto sendLeaveEvent = [&localPos, &scenePos, &globalPos, &modifiers, hoverEnabled](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QEvent leaveEvent(QEvent::Leave);
QCoreApplication::sendEvent(obj, &leaveEvent);
if (hoverEnabled) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
Q_UNUSED(localPos);
QHoverEvent hoverLeaveEvent(QEvent::HoverLeave, scenePos, globalPos, oldPos, modifiers);
#elif (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QHoverEvent hoverLeaveEvent(QEvent::HoverLeave, localPos, globalPos, oldPos, modifiers);
#else
QHoverEvent hoverLeaveEvent(QEvent::HoverLeave, localPos, oldPos, modifiers);
#endif
QCoreApplication::sendEvent(obj, &hoverLeaveEvent);
}
};
const auto sendMouseMoveEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers, leftButtonPressed](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
const Qt::MouseButton actualButton = (leftButtonPressed ? button : Qt::NoButton);
QMouseEvent event(QEvent::MouseMove, localPos, scenePos, globalPos, actualButton, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
const auto sendHoverMoveEvent = [&localPos, &scenePos, &globalPos, &modifiers, hoverEnabled](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
if (!hoverEnabled) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
Q_UNUSED(localPos);
QHoverEvent event(QEvent::HoverMove, scenePos, globalPos, oldPos, modifiers);
#elif (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QHoverEvent event(QEvent::HoverMove, localPos, globalPos, oldPos, modifiers);
#else
QHoverEvent event(QEvent::HoverMove, localPos, oldPos, modifiers);
#endif
QCoreApplication::sendEvent(obj, &event);
};
const auto sendMousePressEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QMouseEvent event(QEvent::MouseButtonPress, localPos, scenePos, globalPos, button, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
const auto sendMouseReleaseEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QMouseEvent event(QEvent::MouseButtonRelease, localPos, scenePos, globalPos, button, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
switch (buttonState) {
case ButtonState::Normal: {
targetObj->setProperty(kEnteredFlag, {});
// Send an extra mouse release event to let the control dismiss it's hover state.
// But only when the mouse is not still hovering above the control, otherwise Qt will
// generate a mouse click event, which is not what the user would expect.
if (!underMouse) {
sendMouseReleaseEvent(targetObj);
}
if (isWidget) {
sendLeaveEvent(targetObj);
} else {
sendLeaveEvent(windowObj);
}
} break;
case ButtonState::Hovered: {
if (!entered) {
targetObj->setProperty(kEnteredFlag, true);
if (isWidget) {
sendEnterEvent(targetObj);
} else {
sendEnterEvent(windowObj);
}
}
if (isWidget) {
sendHoverMoveEvent(targetObj);
} else {
sendHoverMoveEvent(windowObj);
}
if (leftButtonPressed || mouseTrackingEnabled) {
if (isWidget) {
sendMouseMoveEvent(targetObj);
} else {
sendMouseMoveEvent(windowObj);
}
}
} break;
case ButtonState::Pressed:
// Sending mouse event to the window has no effect.
sendMousePressEvent(targetObj);
break;
case ButtonState::Released:
// Sending mouse event to the window has no effect.
sendMouseReleaseEvent(targetObj);
break;
}
}
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -992,10 +992,4 @@ bool Utils::setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &
return true; return true;
} }
Qt::MouseButtons Utils::queryMouseButtons()
{
// ### FIXME
return {};
}
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -755,12 +755,6 @@ QColor Utils::getFrameBorderColor(const bool active)
return (active ? getAccentColor() : kDefaultDarkGrayColor); return (active ? getAccentColor() : kDefaultDarkGrayColor);
} }
Qt::MouseButtons Utils::queryMouseButtons()
{
// ### FIXME
return {};
}
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
#include "utils_mac.moc" #include "utils_mac.moc"

View File

@ -36,6 +36,7 @@
#include <QtCore/qhash.h> #include <QtCore/qhash.h>
#include <QtCore/qloggingcategory.h> #include <QtCore/qloggingcategory.h>
#include <QtCore/qabstracteventdispatcher.h> #include <QtCore/qabstracteventdispatcher.h>
#include <QtCore/qtextstream.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE #ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
@ -188,6 +189,7 @@ FRAMELESSHELPER_STRING_CONSTANT(SetActiveWindow)
FRAMELESSHELPER_STRING_CONSTANT(RedrawWindow) FRAMELESSHELPER_STRING_CONSTANT(RedrawWindow)
FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient) FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient)
FRAMELESSHELPER_STRING_CONSTANT(DwmFlush) FRAMELESSHELPER_STRING_CONSTANT(DwmFlush)
FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos)
struct Win32UtilsData struct Win32UtilsData
{ {
@ -203,6 +205,300 @@ struct Win32UtilsInternal
Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData) Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
struct Win32Message
{
UINT Code = 0;
LPCSTR Str = nullptr;
[[nodiscard]] friend inline constexpr bool operator==(const Win32Message &lhs, const Win32Message &rhs) noexcept
{
return (lhs.Code == rhs.Code);
}
[[nodiscard]] friend inline constexpr bool operator!=(const Win32Message &lhs, const Win32Message &rhs) noexcept
{
return !operator==(lhs, rhs);
}
[[nodiscard]] friend inline constexpr bool operator>(const Win32Message &lhs, const Win32Message &rhs) noexcept
{
return (lhs.Code > rhs.Code);
}
[[nodiscard]] friend inline constexpr bool operator>=(const Win32Message &lhs, const Win32Message &rhs) noexcept
{
return (operator>(lhs, rhs) || operator==(lhs, rhs));
}
[[nodiscard]] friend inline constexpr bool operator<(const Win32Message &lhs, const Win32Message &rhs) noexcept
{
return (operator!=(lhs, rhs) && !operator>(lhs, rhs));
}
[[nodiscard]] friend inline constexpr bool operator<=(const Win32Message &lhs, const Win32Message &rhs) noexcept
{
return (operator<(lhs, rhs) || operator==(lhs, rhs));
}
};
#define DEFINE_WIN32_MESSAGE(Message) Win32Message{ Message, #Message },
static constexpr const std::array<Win32Message, 252> g_win32MessageMap =
{
DEFINE_WIN32_MESSAGE(WM_NULL)
DEFINE_WIN32_MESSAGE(WM_CREATE)
DEFINE_WIN32_MESSAGE(WM_DESTROY)
DEFINE_WIN32_MESSAGE(WM_MOVE)
DEFINE_WIN32_MESSAGE(WM_SIZE)
DEFINE_WIN32_MESSAGE(WM_ACTIVATE)
DEFINE_WIN32_MESSAGE(WM_SETFOCUS)
DEFINE_WIN32_MESSAGE(WM_KILLFOCUS)
DEFINE_WIN32_MESSAGE(WM_ENABLE)
DEFINE_WIN32_MESSAGE(WM_SETREDRAW)
DEFINE_WIN32_MESSAGE(WM_SETTEXT)
DEFINE_WIN32_MESSAGE(WM_GETTEXT)
DEFINE_WIN32_MESSAGE(WM_GETTEXTLENGTH)
DEFINE_WIN32_MESSAGE(WM_PAINT)
DEFINE_WIN32_MESSAGE(WM_CLOSE)
DEFINE_WIN32_MESSAGE(WM_QUERYENDSESSION)
DEFINE_WIN32_MESSAGE(WM_QUERYOPEN)
DEFINE_WIN32_MESSAGE(WM_ENDSESSION)
DEFINE_WIN32_MESSAGE(WM_QUIT)
DEFINE_WIN32_MESSAGE(WM_ERASEBKGND)
DEFINE_WIN32_MESSAGE(WM_SYSCOLORCHANGE)
DEFINE_WIN32_MESSAGE(WM_SHOWWINDOW)
DEFINE_WIN32_MESSAGE(WM_SETTINGCHANGE) // WM_WININICHANGE
DEFINE_WIN32_MESSAGE(WM_DEVMODECHANGE)
DEFINE_WIN32_MESSAGE(WM_ACTIVATEAPP)
DEFINE_WIN32_MESSAGE(WM_FONTCHANGE)
DEFINE_WIN32_MESSAGE(WM_TIMECHANGE)
DEFINE_WIN32_MESSAGE(WM_CANCELMODE)
DEFINE_WIN32_MESSAGE(WM_SETCURSOR)
DEFINE_WIN32_MESSAGE(WM_MOUSEACTIVATE)
DEFINE_WIN32_MESSAGE(WM_CHILDACTIVATE)
DEFINE_WIN32_MESSAGE(WM_QUEUESYNC)
DEFINE_WIN32_MESSAGE(WM_GETMINMAXINFO)
DEFINE_WIN32_MESSAGE(WM_PAINTICON)
DEFINE_WIN32_MESSAGE(WM_ICONERASEBKGND)
DEFINE_WIN32_MESSAGE(WM_NEXTDLGCTL)
DEFINE_WIN32_MESSAGE(WM_SPOOLERSTATUS)
DEFINE_WIN32_MESSAGE(WM_DRAWITEM)
DEFINE_WIN32_MESSAGE(WM_MEASUREITEM)
DEFINE_WIN32_MESSAGE(WM_DELETEITEM)
DEFINE_WIN32_MESSAGE(WM_VKEYTOITEM)
DEFINE_WIN32_MESSAGE(WM_CHARTOITEM)
DEFINE_WIN32_MESSAGE(WM_SETFONT)
DEFINE_WIN32_MESSAGE(WM_GETFONT)
DEFINE_WIN32_MESSAGE(WM_SETHOTKEY)
DEFINE_WIN32_MESSAGE(WM_GETHOTKEY)
DEFINE_WIN32_MESSAGE(WM_QUERYDRAGICON)
DEFINE_WIN32_MESSAGE(WM_COMPAREITEM)
DEFINE_WIN32_MESSAGE(WM_GETOBJECT)
DEFINE_WIN32_MESSAGE(WM_COMPACTING)
DEFINE_WIN32_MESSAGE(WM_COMMNOTIFY)
DEFINE_WIN32_MESSAGE(WM_WINDOWPOSCHANGING)
DEFINE_WIN32_MESSAGE(WM_WINDOWPOSCHANGED)
DEFINE_WIN32_MESSAGE(WM_POWER)
DEFINE_WIN32_MESSAGE(WM_COPYDATA)
DEFINE_WIN32_MESSAGE(WM_CANCELJOURNAL)
DEFINE_WIN32_MESSAGE(WM_NOTIFY)
DEFINE_WIN32_MESSAGE(WM_INPUTLANGCHANGEREQUEST)
DEFINE_WIN32_MESSAGE(WM_INPUTLANGCHANGE)
DEFINE_WIN32_MESSAGE(WM_TCARD)
DEFINE_WIN32_MESSAGE(WM_HELP)
DEFINE_WIN32_MESSAGE(WM_USERCHANGED)
DEFINE_WIN32_MESSAGE(WM_NOTIFYFORMAT)
DEFINE_WIN32_MESSAGE(WM_CONTEXTMENU)
DEFINE_WIN32_MESSAGE(WM_STYLECHANGING)
DEFINE_WIN32_MESSAGE(WM_STYLECHANGED)
DEFINE_WIN32_MESSAGE(WM_DISPLAYCHANGE)
DEFINE_WIN32_MESSAGE(WM_GETICON)
DEFINE_WIN32_MESSAGE(WM_SETICON)
DEFINE_WIN32_MESSAGE(WM_NCCREATE)
DEFINE_WIN32_MESSAGE(WM_NCDESTROY)
DEFINE_WIN32_MESSAGE(WM_NCCALCSIZE)
DEFINE_WIN32_MESSAGE(WM_NCHITTEST)
DEFINE_WIN32_MESSAGE(WM_NCPAINT)
DEFINE_WIN32_MESSAGE(WM_NCACTIVATE)
DEFINE_WIN32_MESSAGE(WM_GETDLGCODE)
DEFINE_WIN32_MESSAGE(WM_SYNCPAINT)
DEFINE_WIN32_MESSAGE(WM_NCMOUSEMOVE)
DEFINE_WIN32_MESSAGE(WM_NCLBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_NCLBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_NCLBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_NCRBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_NCRBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_NCRBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_NCMBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_NCMBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_NCMBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_NCXBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_NCXBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_NCXBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_INPUT_DEVICE_CHANGE)
DEFINE_WIN32_MESSAGE(WM_INPUT)
DEFINE_WIN32_MESSAGE(WM_KEYDOWN) // WM_KEYFIRST
DEFINE_WIN32_MESSAGE(WM_KEYUP)
DEFINE_WIN32_MESSAGE(WM_CHAR)
DEFINE_WIN32_MESSAGE(WM_DEADCHAR)
DEFINE_WIN32_MESSAGE(WM_SYSKEYDOWN)
DEFINE_WIN32_MESSAGE(WM_SYSKEYUP)
DEFINE_WIN32_MESSAGE(WM_SYSCHAR)
DEFINE_WIN32_MESSAGE(WM_SYSDEADCHAR)
DEFINE_WIN32_MESSAGE(WM_UNICHAR) // WM_KEYLAST
DEFINE_WIN32_MESSAGE(WM_IME_STARTCOMPOSITION)
DEFINE_WIN32_MESSAGE(WM_IME_ENDCOMPOSITION)
DEFINE_WIN32_MESSAGE(WM_IME_COMPOSITION) // WM_IME_KEYLAST
DEFINE_WIN32_MESSAGE(WM_INITDIALOG)
DEFINE_WIN32_MESSAGE(WM_COMMAND)
DEFINE_WIN32_MESSAGE(WM_SYSCOMMAND)
DEFINE_WIN32_MESSAGE(WM_TIMER)
DEFINE_WIN32_MESSAGE(WM_HSCROLL)
DEFINE_WIN32_MESSAGE(WM_VSCROLL)
DEFINE_WIN32_MESSAGE(WM_INITMENU)
DEFINE_WIN32_MESSAGE(WM_INITMENUPOPUP)
DEFINE_WIN32_MESSAGE(WM_GESTURE)
DEFINE_WIN32_MESSAGE(WM_GESTURENOTIFY)
DEFINE_WIN32_MESSAGE(WM_MENUSELECT)
DEFINE_WIN32_MESSAGE(WM_MENUCHAR)
DEFINE_WIN32_MESSAGE(WM_ENTERIDLE)
DEFINE_WIN32_MESSAGE(WM_MENURBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_MENUDRAG)
DEFINE_WIN32_MESSAGE(WM_MENUGETOBJECT)
DEFINE_WIN32_MESSAGE(WM_UNINITMENUPOPUP)
DEFINE_WIN32_MESSAGE(WM_MENUCOMMAND)
DEFINE_WIN32_MESSAGE(WM_CHANGEUISTATE)
DEFINE_WIN32_MESSAGE(WM_UPDATEUISTATE)
DEFINE_WIN32_MESSAGE(WM_QUERYUISTATE)
DEFINE_WIN32_MESSAGE(WM_CTLCOLORMSGBOX)
DEFINE_WIN32_MESSAGE(WM_CTLCOLOREDIT)
DEFINE_WIN32_MESSAGE(WM_CTLCOLORLISTBOX)
DEFINE_WIN32_MESSAGE(WM_CTLCOLORBTN)
DEFINE_WIN32_MESSAGE(WM_CTLCOLORDLG)
DEFINE_WIN32_MESSAGE(WM_CTLCOLORSCROLLBAR)
DEFINE_WIN32_MESSAGE(WM_CTLCOLORSTATIC)
DEFINE_WIN32_MESSAGE(MN_GETHMENU)
DEFINE_WIN32_MESSAGE(WM_MOUSEMOVE) // WM_MOUSEFIRST
DEFINE_WIN32_MESSAGE(WM_LBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_LBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_LBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_RBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_RBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_RBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_MBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_MBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_MBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_MOUSEWHEEL)
DEFINE_WIN32_MESSAGE(WM_XBUTTONDOWN)
DEFINE_WIN32_MESSAGE(WM_XBUTTONUP)
DEFINE_WIN32_MESSAGE(WM_XBUTTONDBLCLK)
DEFINE_WIN32_MESSAGE(WM_MOUSEHWHEEL) // WM_MOUSELAST
DEFINE_WIN32_MESSAGE(WM_PARENTNOTIFY)
DEFINE_WIN32_MESSAGE(WM_ENTERMENULOOP)
DEFINE_WIN32_MESSAGE(WM_EXITMENULOOP)
DEFINE_WIN32_MESSAGE(WM_NEXTMENU)
DEFINE_WIN32_MESSAGE(WM_SIZING)
DEFINE_WIN32_MESSAGE(WM_CAPTURECHANGED)
DEFINE_WIN32_MESSAGE(WM_MOVING)
DEFINE_WIN32_MESSAGE(WM_POWERBROADCAST)
DEFINE_WIN32_MESSAGE(WM_DEVICECHANGE)
DEFINE_WIN32_MESSAGE(WM_MDICREATE)
DEFINE_WIN32_MESSAGE(WM_MDIDESTROY)
DEFINE_WIN32_MESSAGE(WM_MDIACTIVATE)
DEFINE_WIN32_MESSAGE(WM_MDIRESTORE)
DEFINE_WIN32_MESSAGE(WM_MDINEXT)
DEFINE_WIN32_MESSAGE(WM_MDIMAXIMIZE)
DEFINE_WIN32_MESSAGE(WM_MDITILE)
DEFINE_WIN32_MESSAGE(WM_MDICASCADE)
DEFINE_WIN32_MESSAGE(WM_MDIICONARRANGE)
DEFINE_WIN32_MESSAGE(WM_MDIGETACTIVE)
DEFINE_WIN32_MESSAGE(WM_MDISETMENU)
DEFINE_WIN32_MESSAGE(WM_ENTERSIZEMOVE)
DEFINE_WIN32_MESSAGE(WM_EXITSIZEMOVE)
DEFINE_WIN32_MESSAGE(WM_DROPFILES)
DEFINE_WIN32_MESSAGE(WM_MDIREFRESHMENU)
DEFINE_WIN32_MESSAGE(WM_POINTERDEVICECHANGE)
DEFINE_WIN32_MESSAGE(WM_POINTERDEVICEINRANGE)
DEFINE_WIN32_MESSAGE(WM_POINTERDEVICEOUTOFRANGE)
DEFINE_WIN32_MESSAGE(WM_TOUCH)
DEFINE_WIN32_MESSAGE(WM_NCPOINTERUPDATE)
DEFINE_WIN32_MESSAGE(WM_NCPOINTERDOWN)
DEFINE_WIN32_MESSAGE(WM_NCPOINTERUP)
DEFINE_WIN32_MESSAGE(WM_POINTERUPDATE)
DEFINE_WIN32_MESSAGE(WM_POINTERDOWN)
DEFINE_WIN32_MESSAGE(WM_POINTERUP)
DEFINE_WIN32_MESSAGE(WM_POINTERENTER)
DEFINE_WIN32_MESSAGE(WM_POINTERLEAVE)
DEFINE_WIN32_MESSAGE(WM_POINTERACTIVATE)
DEFINE_WIN32_MESSAGE(WM_POINTERCAPTURECHANGED)
DEFINE_WIN32_MESSAGE(WM_TOUCHHITTESTING)
DEFINE_WIN32_MESSAGE(WM_POINTERWHEEL)
DEFINE_WIN32_MESSAGE(WM_POINTERHWHEEL)
DEFINE_WIN32_MESSAGE(DM_POINTERHITTEST)
DEFINE_WIN32_MESSAGE(WM_POINTERROUTEDTO)
DEFINE_WIN32_MESSAGE(WM_POINTERROUTEDAWAY)
DEFINE_WIN32_MESSAGE(WM_POINTERROUTEDRELEASED)
DEFINE_WIN32_MESSAGE(WM_IME_SETCONTEXT)
DEFINE_WIN32_MESSAGE(WM_IME_NOTIFY)
DEFINE_WIN32_MESSAGE(WM_IME_CONTROL)
DEFINE_WIN32_MESSAGE(WM_IME_COMPOSITIONFULL)
DEFINE_WIN32_MESSAGE(WM_IME_SELECT)
DEFINE_WIN32_MESSAGE(WM_IME_CHAR)
DEFINE_WIN32_MESSAGE(WM_IME_REQUEST)
DEFINE_WIN32_MESSAGE(WM_IME_KEYDOWN)
DEFINE_WIN32_MESSAGE(WM_IME_KEYUP)
DEFINE_WIN32_MESSAGE(WM_MOUSEHOVER)
DEFINE_WIN32_MESSAGE(WM_MOUSELEAVE)
DEFINE_WIN32_MESSAGE(WM_NCMOUSEHOVER)
DEFINE_WIN32_MESSAGE(WM_NCMOUSELEAVE)
DEFINE_WIN32_MESSAGE(WM_WTSSESSION_CHANGE)
DEFINE_WIN32_MESSAGE(WM_TABLET_FIRST)
DEFINE_WIN32_MESSAGE(WM_TABLET_LAST)
DEFINE_WIN32_MESSAGE(WM_DPICHANGED)
DEFINE_WIN32_MESSAGE(WM_DPICHANGED_BEFOREPARENT)
DEFINE_WIN32_MESSAGE(WM_DPICHANGED_AFTERPARENT)
DEFINE_WIN32_MESSAGE(WM_GETDPISCALEDSIZE)
DEFINE_WIN32_MESSAGE(WM_CUT)
DEFINE_WIN32_MESSAGE(WM_COPY)
DEFINE_WIN32_MESSAGE(WM_PASTE)
DEFINE_WIN32_MESSAGE(WM_CLEAR)
DEFINE_WIN32_MESSAGE(WM_UNDO)
DEFINE_WIN32_MESSAGE(WM_RENDERFORMAT)
DEFINE_WIN32_MESSAGE(WM_RENDERALLFORMATS)
DEFINE_WIN32_MESSAGE(WM_DESTROYCLIPBOARD)
DEFINE_WIN32_MESSAGE(WM_DRAWCLIPBOARD)
DEFINE_WIN32_MESSAGE(WM_PAINTCLIPBOARD)
DEFINE_WIN32_MESSAGE(WM_VSCROLLCLIPBOARD)
DEFINE_WIN32_MESSAGE(WM_SIZECLIPBOARD)
DEFINE_WIN32_MESSAGE(WM_ASKCBFORMATNAME)
DEFINE_WIN32_MESSAGE(WM_CHANGECBCHAIN)
DEFINE_WIN32_MESSAGE(WM_HSCROLLCLIPBOARD)
DEFINE_WIN32_MESSAGE(WM_QUERYNEWPALETTE)
DEFINE_WIN32_MESSAGE(WM_PALETTEISCHANGING)
DEFINE_WIN32_MESSAGE(WM_PALETTECHANGED)
DEFINE_WIN32_MESSAGE(WM_HOTKEY)
DEFINE_WIN32_MESSAGE(WM_PRINT)
DEFINE_WIN32_MESSAGE(WM_PRINTCLIENT)
DEFINE_WIN32_MESSAGE(WM_APPCOMMAND)
DEFINE_WIN32_MESSAGE(WM_THEMECHANGED)
DEFINE_WIN32_MESSAGE(WM_CLIPBOARDUPDATE)
DEFINE_WIN32_MESSAGE(WM_DWMCOMPOSITIONCHANGED)
DEFINE_WIN32_MESSAGE(WM_DWMNCRENDERINGCHANGED)
DEFINE_WIN32_MESSAGE(WM_DWMCOLORIZATIONCOLORCHANGED)
DEFINE_WIN32_MESSAGE(WM_DWMWINDOWMAXIMIZEDCHANGE)
DEFINE_WIN32_MESSAGE(WM_DWMSENDICONICTHUMBNAIL)
DEFINE_WIN32_MESSAGE(WM_DWMSENDICONICLIVEPREVIEWBITMAP)
DEFINE_WIN32_MESSAGE(WM_GETTITLEBARINFOEX)
DEFINE_WIN32_MESSAGE(WM_HANDHELDFIRST)
DEFINE_WIN32_MESSAGE(WM_HANDHELDLAST)
DEFINE_WIN32_MESSAGE(WM_AFXFIRST)
DEFINE_WIN32_MESSAGE(WM_AFXLAST)
DEFINE_WIN32_MESSAGE(WM_PENWINFIRST)
DEFINE_WIN32_MESSAGE(WM_PENWINLAST)
DEFINE_WIN32_MESSAGE(WM_APP)
DEFINE_WIN32_MESSAGE(WM_USER)
};
#undef DEFINE_WIN32_MESSAGE
[[nodiscard]] bool operator==(const POINT &lhs, const POINT &rhs) noexcept [[nodiscard]] bool operator==(const POINT &lhs, const POINT &rhs) noexcept
{ {
return ((lhs.x == rhs.x) && (lhs.y == rhs.y)); return ((lhs.x == rhs.x) && (lhs.y == rhs.y));
@ -530,6 +826,12 @@ Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
} }
} }
[[nodiscard]] static inline bool isWin32MessageDebuggingEnabled()
{
static const bool result = (qEnvironmentVariableIntValue("FRAMELESSHELPER_ENABLE_WIN32_MESSAGE_DEBUGGING") != 0);
return result;
}
[[nodiscard]] static inline QByteArray qtNativeEventType() [[nodiscard]] static inline QByteArray qtNativeEventType()
{ {
static const auto result = FRAMELESSHELPER_BYTEARRAY_LITERAL("windows_generic_MSG"); static const auto result = FRAMELESSHELPER_BYTEARRAY_LITERAL("windows_generic_MSG");
@ -556,6 +858,26 @@ Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
return false; return false;
} }
[[nodiscard]] static inline bool isMouseMessage(const UINT message, bool *isNonClient = nullptr)
{
if (((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST))
|| ((message == WM_MOUSEHOVER) || (message == WM_MOUSELEAVE))) {
if (isNonClient) {
*isNonClient = false;
}
return true;
}
if (((message >= WM_NCMOUSEMOVE) && (message <= WM_NCMBUTTONDBLCLK))
|| ((message >= WM_NCXBUTTONDOWN) && (message <= WM_NCXBUTTONDBLCLK))
|| ((message == WM_NCMOUSEHOVER) || (message == WM_NCMOUSELEAVE))) {
if (isNonClient) {
*isNonClient = true;
}
return true;
}
return false;
}
[[nodiscard]] static inline bool usePureQtImplementation() [[nodiscard]] static inline bool usePureQtImplementation()
{ {
static const bool result = FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation); static const bool result = FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
@ -569,6 +891,61 @@ Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
if (!hWnd) { if (!hWnd) {
return 0; return 0;
} }
if (isWin32MessageDebuggingEnabled()) {
const auto it = std::find(g_win32MessageMap.cbegin(), g_win32MessageMap.cend(), Win32Message{ uMsg, nullptr });
if (it != g_win32MessageMap.cend()) {
QString text = {};
QTextStream stream(&text);
stream << "Win32 message received: " << it->Str << " (0x"
<< QString::number(uMsg, 16).toUpper().rightJustified(4, u'0') << ')';
bool isNonClientMouseMessage = false;
if (isMouseMessage(uMsg, &isNonClientMouseMessage)) {
if (isNonClientMouseMessage) {
const auto screenPos = [uMsg, lParam]() -> POINT {
if (uMsg == WM_NCMOUSELEAVE) {
const DWORD dwScreenPos = ::GetMessagePos();
return POINT{ GET_X_LPARAM(dwScreenPos), GET_Y_LPARAM(dwScreenPos) };
} else {
return POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
}
}();
POINT clientPos = screenPos;
if (::ScreenToClient(hWnd, &clientPos) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kScreenToClient);
clientPos = {};
}
stream << ", screen coordinate: POINT(x: " << screenPos.x << ", y: "
<< screenPos.y << "), client coordinate: POINT(x: "
<< clientPos.x << ", y: " << clientPos.y << ')';
} else {
const auto clientPos = [hWnd, uMsg, lParam]() -> POINT {
if (uMsg == WM_MOUSELEAVE) {
const DWORD dwScreenPos = ::GetMessagePos();
const auto screenPos = POINT{ GET_X_LPARAM(dwScreenPos), GET_Y_LPARAM(dwScreenPos) };
POINT clientPos = screenPos;
if (::ScreenToClient(hWnd, &clientPos) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kScreenToClient);
return {};
} else {
return clientPos;
}
} else {
return POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
}
}();
POINT screenPos = clientPos;
if (::ClientToScreen(hWnd, &screenPos) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kClientToScreen);
screenPos = {};
}
stream << ", screen coordinate: POINT(x: " << screenPos.x << ", y: "
<< screenPos.y << "), client coordinate: POINT(x: "
<< clientPos.x << ", y: " << clientPos.y << ')';
}
}
DEBUG.noquote() << text;
}
}
const auto windowId = reinterpret_cast<WId>(hWnd); const auto windowId = reinterpret_cast<WId>(hWnd);
const auto it = g_win32UtilsData()->data.constFind(windowId); const auto it = g_win32UtilsData()->data.constFind(windowId);
if (it == g_win32UtilsData()->data.constEnd()) { if (it == g_win32UtilsData()->data.constEnd()) {
@ -593,9 +970,16 @@ Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
message.wParam = wParam; message.wParam = wParam;
message.lParam = lParam; message.lParam = lParam;
message.time = ::GetMessageTime(); message.time = ::GetMessageTime();
#if 1
const DWORD dwScreenPos = ::GetMessagePos(); const DWORD dwScreenPos = ::GetMessagePos();
message.pt.x = GET_X_LPARAM(dwScreenPos); message.pt.x = GET_X_LPARAM(dwScreenPos);
message.pt.y = GET_Y_LPARAM(dwScreenPos); message.pt.y = GET_Y_LPARAM(dwScreenPos);
#else
if (::GetCursorPos(&message.pt) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kGetCursorPos);
message.pt = {};
}
#endif
if (!isNonClientMessage(uMsg)) { if (!isNonClientMessage(uMsg)) {
if (::ScreenToClient(hWnd, &message.pt) == FALSE) { if (::ScreenToClient(hWnd, &message.pt) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kScreenToClient); WARNING << Utils::getSystemErrorMessage(kScreenToClient);
@ -2649,12 +3033,11 @@ bool Utils::removeMicaWindow(const WId windowId)
return true; return true;
} }
quint64 Utils::getMouseButtonsAndModifiers(const bool async) quint64 Utils::getKeyState()
{ {
quint64 result = 0; quint64 result = 0;
const auto get = [async](const int virtualKey) -> bool { const auto get = [](const int virtualKey) -> bool {
const auto stateCode = (async ? ::GetAsyncKeyState(virtualKey) : ::GetKeyState(virtualKey)); return (::GetAsyncKeyState(virtualKey) < 0);
return (stateCode < 0);
}; };
const bool buttonSwapped = (::GetSystemMetrics(SM_SWAPBUTTON) != FALSE); const bool buttonSwapped = (::GetSystemMetrics(SM_SWAPBUTTON) != FALSE);
if (get(VK_LBUTTON)) { if (get(VK_LBUTTON)) {
@ -2663,12 +3046,6 @@ quint64 Utils::getMouseButtonsAndModifiers(const bool async)
if (get(VK_RBUTTON)) { if (get(VK_RBUTTON)) {
result |= (buttonSwapped ? MK_LBUTTON : MK_RBUTTON); result |= (buttonSwapped ? MK_LBUTTON : MK_RBUTTON);
} }
if (get(VK_SHIFT)) {
result |= MK_SHIFT;
}
if (get(VK_CONTROL)) {
result |= MK_CONTROL;
}
if (get(VK_MBUTTON)) { if (get(VK_MBUTTON)) {
result |= MK_MBUTTON; result |= MK_MBUTTON;
} }
@ -2681,31 +3058,6 @@ quint64 Utils::getMouseButtonsAndModifiers(const bool async)
return result; return result;
} }
Qt::MouseButtons Utils::queryMouseButtons()
{
const quint64 buttonMask = getMouseButtonsAndModifiers(false);
if (buttonMask == 0) {
return {};
}
Qt::MouseButtons buttons = {};
if (buttonMask & MK_LBUTTON) {
buttons |= Qt::LeftButton;
}
if (buttonMask & MK_RBUTTON) {
buttons |= Qt::RightButton;
}
if (buttonMask & MK_MBUTTON) {
buttons |= Qt::MiddleButton;
}
if (buttonMask & MK_XBUTTON1) {
buttons |= Qt::XButton1;
}
if (buttonMask & MK_XBUTTON2) {
buttons |= Qt::XButton2;
}
return buttons;
}
bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel) bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel)
{ {
Q_ASSERT(windowId); Q_ASSERT(windowId);

View File

@ -853,69 +853,8 @@ bool FramelessQuickHelperPrivate::shouldIgnoreMouseEvents(const QPoint &pos) con
void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::SystemButtonType button, void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::SystemButtonType button,
const QuickGlobal::ButtonState state) const QuickGlobal::ButtonState state)
{ {
#ifdef FRAMELESSHELPER_QUICK_NO_PRIVATE
Q_UNUSED(button); Q_UNUSED(button);
Q_UNUSED(state); Q_UNUSED(state);
#else // !FRAMELESSHELPER_QUICK_NO_PRIVATE
Q_ASSERT(button != QuickGlobal::SystemButtonType::Unknown);
if (button == QuickGlobal::SystemButtonType::Unknown) {
return;
}
const FramelessQuickHelperData *data = getWindowData();
if (!data) {
return;
}
QQuickItem *quickButton = nullptr;
switch (button) {
case QuickGlobal::SystemButtonType::WindowIcon:
quickButton = data->windowIconButton;
break;
case QuickGlobal::SystemButtonType::Help:
quickButton = data->contextHelpButton;
break;
case QuickGlobal::SystemButtonType::Minimize:
quickButton = data->minimizeButton;
break;
case QuickGlobal::SystemButtonType::Maximize:
case QuickGlobal::SystemButtonType::Restore:
quickButton = data->maximizeButton;
break;
case QuickGlobal::SystemButtonType::Close:
quickButton = data->closeButton;
break;
case QuickGlobal::SystemButtonType::Unknown:
Q_UNREACHABLE_RETURN(void(0));
}
if (!quickButton) {
return;
}
const auto updateButtonState = [state](QQuickItem *btn) -> void {
Q_ASSERT(btn);
if (!btn) {
return;
}
const QQuickWindow *window = btn->window();
Q_ASSERT(window);
if (!window) {
return;
}
const QScreen *screen = (window->screen() ? window->screen() : QGuiApplication::primaryScreen());
const QPoint globalPos = (screen ? QCursor::pos(screen) : QCursor::pos());
const QPoint localPos = btn->mapFromGlobal(globalPos).toPoint();
const QPoint scenePos = window->mapFromGlobal(globalPos);
const auto underMouse = [btn, &globalPos]() -> bool {
const QPointF originPoint = btn->mapToGlobal(QPointF{ 0, 0 });
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
const QSizeF size = btn->size();
#else
const auto size = QSizeF{ btn->width(), btn->height() };
#endif
return QRectF{ originPoint, size }.contains(globalPos);
}();
Utils::emulateQtMouseEvent(btn, window, FRAMELESSHELPER_ENUM_QUICK_TO_CORE(ButtonState, state), globalPos, scenePos, localPos, underMouse, true);
};
updateButtonState(quickButton);
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
} }
const FramelessQuickHelperData *FramelessQuickHelperPrivate::getWindowData() const const FramelessQuickHelperData *FramelessQuickHelperPrivate::getWindowData() const

View File

@ -803,76 +803,8 @@ bool FramelessWidgetsHelperPrivate::shouldIgnoreMouseEvents(const QPoint &pos) c
void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType button, const ButtonState state) void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType button, const ButtonState state)
{ {
Q_ASSERT(button != SystemButtonType::Unknown); Q_UNUSED(button);
if (button == SystemButtonType::Unknown) { Q_UNUSED(state);
return;
}
const FramelessWidgetsHelperData *data = getWindowData();
if (!data) {
return;
}
QWidget *widgetButton = nullptr;
switch (button) {
case SystemButtonType::WindowIcon:
if (data->windowIconButton) {
widgetButton = data->windowIconButton;
}
break;
case SystemButtonType::Help:
if (data->contextHelpButton) {
widgetButton = data->contextHelpButton;
}
break;
case SystemButtonType::Minimize:
if (data->minimizeButton) {
widgetButton = data->minimizeButton;
}
break;
case SystemButtonType::Maximize:
case SystemButtonType::Restore:
if (data->maximizeButton) {
widgetButton = data->maximizeButton;
}
break;
case SystemButtonType::Close:
if (data->closeButton) {
widgetButton = data->closeButton;
}
break;
case SystemButtonType::Unknown:
Q_UNREACHABLE_RETURN(void(0));
}
if (!widgetButton) {
return;
}
const auto updateButtonState = [state](QWidget *btn) -> void {
Q_ASSERT(btn);
if (!btn) {
return;
}
const QWidget *window = btn->window();
Q_ASSERT(window);
if (!window) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
const QScreen *screen = window->screen();
#else
const QScreen *screen = QGuiApplication::primaryScreen();
#endif
const QPoint globalPos = (screen ? QCursor::pos(screen) : QCursor::pos());
const QPoint localPos = btn->mapFromGlobal(globalPos);
const QPoint scenePos = window->mapFromGlobal(globalPos);
#if 0
const auto underMouse = [btn, &globalPos]() -> bool {
const QPoint originPoint = btn->mapToGlobal(QPoint{ 0, 0 });
return QRect{ originPoint, btn->size() }.contains(globalPos);
}();
#endif
const bool hoverEnabled = btn->testAttribute(Qt::WA_Hover);
Utils::emulateQtMouseEvent(btn, window->windowHandle(), state, globalPos, scenePos, localPos, btn->underMouse(), hoverEnabled);
};
updateButtonState(widgetButton);
} }
void FramelessWidgetsHelperPrivate::moveWindowToDesktopCenter() void FramelessWidgetsHelperPrivate::moveWindowToDesktopCenter()

View File

@ -154,9 +154,9 @@ bool StandardSystemButtonPrivate::isActive() const
return m_active; return m_active;
} }
int StandardSystemButtonPrivate::iconSize2() const int StandardSystemButtonPrivate::glyphSize() const
{ {
return m_iconSize2.value_or(FramelessManagerPrivate::getIconFont().pointSize()); return m_glyphSize.value_or(FramelessManagerPrivate::getIconFont().pointSize());
} }
void StandardSystemButtonPrivate::setHoverColor(const QColor &value) void StandardSystemButtonPrivate::setHoverColor(const QColor &value)
@ -245,19 +245,19 @@ void StandardSystemButtonPrivate::setActive(const bool value)
Q_EMIT q->activeChanged(); Q_EMIT q->activeChanged();
} }
void StandardSystemButtonPrivate::setIconSize2(const int value) void StandardSystemButtonPrivate::setGlyphSize(const int value)
{ {
Q_ASSERT(value > 0); Q_ASSERT(value > 0);
if (value <= 0) { if (value <= 0) {
return; return;
} }
if (iconSize2() == value) { if (glyphSize() == value) {
return; return;
} }
m_iconSize2 = value; m_glyphSize = value;
Q_Q(StandardSystemButton); Q_Q(StandardSystemButton);
q->update(); q->update();
Q_EMIT q->iconSize2Changed(); Q_EMIT q->glyphSizeChanged();
} }
void StandardSystemButtonPrivate::paintEventHandler(QPaintEvent *event) void StandardSystemButtonPrivate::paintEventHandler(QPaintEvent *event)
@ -300,8 +300,8 @@ void StandardSystemButtonPrivate::paintEventHandler(QPaintEvent *event)
}()); }());
painter.setFont([this]() -> QFont { painter.setFont([this]() -> QFont {
QFont font = FramelessManagerPrivate::getIconFont(); QFont font = FramelessManagerPrivate::getIconFont();
if (m_iconSize2.has_value()) { if (m_glyphSize.has_value()) {
font.setPointSize(m_iconSize2.value()); font.setPointSize(m_glyphSize.value());
} }
return font; return font;
}()); }());
@ -316,8 +316,10 @@ void StandardSystemButtonPrivate::initialize()
FramelessManagerPrivate::initializeIconFont(); FramelessManagerPrivate::initializeIconFont();
Q_Q(StandardSystemButton); Q_Q(StandardSystemButton);
q->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); q->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
q->setFixedSize(kDefaultSystemButtonSize); q->setFixedSize(getRecommendedButtonSize());
q->setIconSize(kDefaultSystemButtonIconSize); q->setIconSize(kDefaultSystemButtonIconSize);
q->setMouseTracking(true);
q->setAttribute(Qt::WA_Hover);
} }
StandardSystemButton::StandardSystemButton(QWidget *parent) StandardSystemButton::StandardSystemButton(QWidget *parent)
@ -405,10 +407,10 @@ bool StandardSystemButton::isActive() const
return d->isActive(); return d->isActive();
} }
int StandardSystemButton::iconSize2() const int StandardSystemButton::glyphSize() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->iconSize2(); return d->glyphSize();
} }
void StandardSystemButton::setPressColor(const QColor &value) void StandardSystemButton::setPressColor(const QColor &value)
@ -441,10 +443,10 @@ void StandardSystemButton::setActive(const bool value)
d->setActive(value); d->setActive(value);
} }
void StandardSystemButton::setIconSize2(const int value) void StandardSystemButton::setGlyphSize(const int value)
{ {
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setIconSize2(value); d->setGlyphSize(value);
} }
void StandardSystemButton::paintEvent(QPaintEvent *event) void StandardSystemButton::paintEvent(QPaintEvent *event)