wip
This commit is contained in:
parent
ae9c4ae5c8
commit
099da347e8
|
@ -86,6 +86,46 @@
|
|||
|
||||
#include <FramelessHelper/Core/framelesshelpercore_global.h>
|
||||
|
||||
#ifndef SC_SIZE
|
||||
# define SC_SIZE (0xF000)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZELEFT
|
||||
# define SC_SIZELEFT (0xF001)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZERIGHT
|
||||
# define SC_SIZERIGHT (0xF002)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZETOP
|
||||
# define SC_SIZETOP (0xF003)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZETOPLEFT
|
||||
# define SC_SIZETOPLEFT (0xF004)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZETOPRIGHT
|
||||
# define SC_SIZETOPRIGHT (0xF005)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZEBOTTOM
|
||||
# define SC_SIZEBOTTOM (0xF006)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZEBOTTOMLEFT
|
||||
# define SC_SIZEBOTTOMLEFT (0xF007)
|
||||
#endif
|
||||
|
||||
#ifndef SC_SIZEBOTTOMRIGHT
|
||||
# define SC_SIZEBOTTOMRIGHT (0xF008)
|
||||
#endif
|
||||
|
||||
#ifndef SC_DRAGMOVE
|
||||
# define SC_DRAGMOVE (0xF012)
|
||||
#endif
|
||||
|
||||
#ifndef WM_SIZEWAIT
|
||||
# define WM_SIZEWAIT (0x0004)
|
||||
#endif
|
||||
|
@ -1166,3 +1206,39 @@ EXTERN_C_END
|
|||
{
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr QPoint point2qpoint(const POINT &point)
|
||||
{
|
||||
return QPoint{ int(point.x), int(point.y) };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr POINT qpoint2point(const QPoint &point)
|
||||
{
|
||||
return POINT{ LONG(point.x()), LONG(point.y()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr QSize size2qsize(const SIZE &size)
|
||||
{
|
||||
return QSize{ int(size.cx), int(size.cy) };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr SIZE qsize2size(const QSize &size)
|
||||
{
|
||||
return SIZE{ LONG(size.width()), LONG(size.height()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr QRect rect2qrect(const RECT &rect)
|
||||
{
|
||||
return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr RECT qrect2rect(const QRect &qrect)
|
||||
{
|
||||
return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline /*constexpr*/ QString hwnd2str(const HWND hwnd)
|
||||
{
|
||||
// NULL handle is allowed here.
|
||||
return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast<WId>(hwnd), 16).toUpper().rightJustified(8, u'0');
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
|
|||
|
||||
enum class Option : quint8
|
||||
{
|
||||
UseCrossPlatformQtImplementation,
|
||||
//UseCrossPlatformQtImplementation,
|
||||
ForceHideWindowFrameBorder,
|
||||
ForceShowWindowFrameBorder,
|
||||
DisableWindowsSnapLayout,
|
||||
|
|
|
@ -96,26 +96,33 @@ struct FramelessCallbacks
|
|||
ForceChildrenRepaintCallback forceChildrenRepaint = nullptr;
|
||||
ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr;
|
||||
|
||||
using PtrType = std::shared_ptr<FramelessCallbacks>;
|
||||
[[nodiscard]] static PtrType create();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY_MOVE(FramelessCallbacks)
|
||||
};
|
||||
using FramelessCallbacksPtr = std::shared_ptr<FramelessCallbacks>;
|
||||
#define CreateFramelessCallbacks(...) std::make_shared<FramelessCallbacks>(__VA_ARGS__)
|
||||
|
||||
struct FramelessData;
|
||||
using FramelessDataPtr = std::shared_ptr<FramelessData>;
|
||||
#define CreateFramelessData(...) std::make_shared<FramelessData>(__VA_ARGS__)
|
||||
using FramelessCallbacksPtr = FramelessCallbacks::PtrType;
|
||||
|
||||
struct FramelessData
|
||||
{
|
||||
bool frameless = false;
|
||||
FramelessCallbacksPtr callbacks = nullptr;
|
||||
struct {
|
||||
void *ptr = nullptr;
|
||||
using DeleterFunctionPrototype = void(*)(void*);
|
||||
DeleterFunctionPrototype deleter = nullptr;
|
||||
} extraData = {};
|
||||
|
||||
[[nodiscard]] static FramelessDataPtr create();
|
||||
using PtrType = std::shared_ptr<FramelessData>;
|
||||
[[nodiscard]] static PtrType create();
|
||||
|
||||
~FramelessData();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY_MOVE(FramelessData)
|
||||
};
|
||||
using FramelessDataPtr = FramelessData::PtrType;
|
||||
|
||||
using FramelessDataHash = QHash<const QWindow *, FramelessDataPtr>;
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
void doNotifyWallpaperHasChangedOrNot();
|
||||
|
||||
Q_NODISCARD static FramelessDataPtr getData(const QWindow *window);
|
||||
static void removeData(const QWindow *window);
|
||||
|
||||
FramelessManager *q_ptr = nullptr;
|
||||
Global::SystemTheme systemTheme = Global::SystemTheme::Unknown;
|
||||
|
|
|
@ -114,28 +114,16 @@ struct FramelessDataWin : public FramelessData
|
|||
QRect restoreGeometry = {};
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
};
|
||||
#define CreateFramelessDataWin(...) std::make_shared<FramelessDataWin>(__VA_ARGS__)
|
||||
|
||||
#define GetFramelessDataWin(Window) std::dynamic_pointer_cast<FramelessDataWin>(FramelessManagerPrivate::getData(Window))
|
||||
|
||||
[[nodiscard]] FramelessDataPtr FramelessData::create()
|
||||
{
|
||||
return CreateFramelessDataWin();
|
||||
return std::make_shared<FramelessDataWin>();
|
||||
}
|
||||
|
||||
static std::unique_ptr<FramelessHelperWin> g_framelessHelperWin = nullptr;
|
||||
|
||||
[[nodiscard]] extern QPoint point2qpoint(const POINT &point);
|
||||
[[nodiscard]] extern POINT qpoint2point(const QPoint &point);
|
||||
|
||||
[[nodiscard]] extern QSize size2qsize(const SIZE &size);
|
||||
[[nodiscard]] extern SIZE qsize2size(const QSize &size);
|
||||
|
||||
[[nodiscard]] extern QRect rect2qrect(const RECT &rect);
|
||||
[[nodiscard]] extern RECT qrect2rect(const QRect &qrect);
|
||||
|
||||
[[nodiscard]] extern QString hwnd2str(const HWND hwnd);
|
||||
|
||||
[[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd);
|
||||
|
||||
[[nodiscard]] static inline QByteArray qtNativeEventType()
|
||||
|
@ -218,11 +206,7 @@ void FramelessHelperWin::addWindow(const QWindow *window)
|
|||
}
|
||||
data->frameless = true;
|
||||
data->dpi = Dpi{ Utils::getWindowDpi(window, true), Utils::getWindowDpi(window, false) };
|
||||
if (!g_framelessHelperWin) {
|
||||
g_framelessHelperWin = std::make_unique<FramelessHelperWin>();
|
||||
qApp->installNativeEventFilter(g_framelessHelperWin.get());
|
||||
}
|
||||
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data->dpi;
|
||||
DEBUG.noquote() << "The DPI of window" << hwnd2str(qWindowId<HWND>(window)) << "is" << data->dpi;
|
||||
// Remove the bad window styles added by Qt (it's not that "bad" though).
|
||||
std::ignore = Utils::maybeFixupQtInternals(window);
|
||||
#if 0
|
||||
|
@ -267,19 +251,15 @@ void FramelessHelperWin::addWindow(const QWindow *window)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!g_framelessHelperWin) {
|
||||
g_framelessHelperWin = std::make_unique<FramelessHelperWin>();
|
||||
qApp->installNativeEventFilter(g_framelessHelperWin.get());
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessHelperWin::removeWindow(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const auto data = GetFramelessDataWin(window);
|
||||
if (!data || !data->frameless) {
|
||||
return;
|
||||
}
|
||||
data->frameless = false;
|
||||
Q_UNUSED(window);
|
||||
}
|
||||
|
||||
bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result)
|
||||
|
@ -301,16 +281,23 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// Anyway, we should skip the entire processing in this case.
|
||||
return false;
|
||||
}
|
||||
|
||||
const QWindow *window = Utils::findWindow(reinterpret_cast<WId>(hWnd));
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let's be extra safe.
|
||||
if (!Utils::isValidWindow(window, false, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto data = GetFramelessDataWin(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data || !data->frameless) {
|
||||
return false;
|
||||
}
|
||||
// Let's be extra safe.
|
||||
if (!Utils::isValidWindow(window, false, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const UINT uMsg = msg->message;
|
||||
|
||||
// We should skip these messages otherwise we will get crashes.
|
||||
|
@ -332,7 +319,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const LPARAM lParam = msg->lParam;
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
const auto updateRestoreGeometry = [window](const bool ignoreWindowState) -> void {
|
||||
const auto updateRestoreGeometry = [window, &data](const bool ignoreWindowState) -> void {
|
||||
if (!ignoreWindowState && !Utils::isWindowNoState(window)) {
|
||||
return;
|
||||
}
|
||||
|
@ -341,10 +328,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
WARNING << "The calculated restore geometry is invalid.";
|
||||
return;
|
||||
}
|
||||
if (Utils::isValidGeometry(data.restoreGeometry) && (data.restoreGeometry == rect)) {
|
||||
if (Utils::isValidGeometry(data->restoreGeometry) && (data->restoreGeometry == rect)) {
|
||||
return;
|
||||
}
|
||||
muData.restoreGeometry = rect;
|
||||
data->restoreGeometry = rect;
|
||||
};
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
|
||||
|
@ -447,13 +434,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// So we filter out these superfluous mouse leave events here to avoid this issue.
|
||||
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint{ msg->pt.x, msg->pt.y });
|
||||
SystemButtonType dummy = SystemButtonType::Unknown;
|
||||
if (data.params.isInsideSystemButtons(qtScenePos, &dummy)) {
|
||||
muData.mouseLeaveBlocked = true;
|
||||
if (data->callbacks->isInsideSystemButtons(qtScenePos, &dummy)) {
|
||||
data->mouseLeaveBlocked = true;
|
||||
*result = FALSE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
muData.mouseLeaveBlocked = false;
|
||||
data->mouseLeaveBlocked = false;
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
|
@ -465,7 +452,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// If we are using the PMv2 DPI awareness mode, the non-client area
|
||||
// of the window will be scaled by the OS automatically, so there will
|
||||
// be no need to do this in that case.
|
||||
Utils::enableNonClientAreaDpiScalingForWindow(windowId);
|
||||
Utils::enableNonClientAreaDpiScalingForWindow(window);
|
||||
} break;
|
||||
#endif
|
||||
case WM_NCCALCSIZE: {
|
||||
|
@ -581,7 +568,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
clientRect->top = originalTop;
|
||||
}
|
||||
const bool max = IsMaximized(hWnd);
|
||||
const bool full = Utils::isFullScreen(windowId);
|
||||
const bool full = Utils::isFullScreen(window);
|
||||
// We don't need this correction when we're fullscreen. We will
|
||||
// have the WS_POPUP size, so we don't have to worry about
|
||||
// borders, and the default frame will be fine.
|
||||
|
@ -592,11 +579,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// then the window is clipped to the monitor so that the resize handle
|
||||
// do not appear because you don't need them (because you can't resize
|
||||
// a window when it's maximized unless you restore it).
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(window, false, true);
|
||||
clientRect->top += frameSizeY;
|
||||
if (!frameBorderVisible) {
|
||||
clientRect->bottom -= frameSizeY;
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(window, true, true);
|
||||
clientRect->left += frameSizeX;
|
||||
clientRect->right -= frameSizeX;
|
||||
}
|
||||
|
@ -791,8 +778,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// color, our homemade top border can almost have exactly the same
|
||||
// appearance with the system's one.
|
||||
|
||||
const auto hitTestRecorder = qScopeGuard([&muData, &result](){
|
||||
muData.lastHitTestResult = getHittedWindowPart(*result);
|
||||
const auto hitTestRecorder = qScopeGuard([&data, &result](){
|
||||
data->lastHitTestResult = getHittedWindowPart(*result);
|
||||
});
|
||||
|
||||
const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||
|
@ -812,7 +799,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
|
||||
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y));
|
||||
SystemButtonType sysButtonType = SystemButtonType::Unknown;
|
||||
if (data.params.isInsideSystemButtons(qtScenePos, &sysButtonType)) {
|
||||
if (data->callbacks->isInsideSystemButtons(qtScenePos, &sysButtonType)) {
|
||||
// Even if the mouse is inside the chrome button area now, we should still allow the user
|
||||
// to be able to resize the window with the top or right window border, this is also the
|
||||
// normal behavior of a native Win32 window.
|
||||
|
@ -858,13 +845,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// are we hitting.
|
||||
|
||||
const bool max = IsMaximized(hWnd);
|
||||
const bool full = Utils::isFullScreen(windowId);
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
|
||||
const bool full = Utils::isFullScreen(window);
|
||||
const int frameSizeY = Utils::getResizeBorderThickness(window, false, true);
|
||||
const bool isTop = (nativeLocalPos.y < frameSizeY);
|
||||
const bool isTitleBar = data.params.isInsideTitleBarDraggableArea(qtScenePos);
|
||||
const bool isFixedSize = data.params.isWindowFixedSize();
|
||||
const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool();
|
||||
const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool();
|
||||
const bool isTitleBar = data->callbacks->isInsideTitleBarDraggableArea(qtScenePos);
|
||||
const bool isFixedSize = data->callbacks->isWindowFixedSize();
|
||||
const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool();
|
||||
const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool();
|
||||
|
||||
if (dontToggleMaximize) {
|
||||
static bool once = false;
|
||||
|
@ -922,7 +909,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const bool isBottom = (nativeLocalPos.y >= (clientHeight - frameSizeY));
|
||||
// Make the border a little wider to let the user easy to resize on corners.
|
||||
const auto scaleFactor = ((isTop || isBottom) ? qreal(2) : qreal(1));
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
|
||||
const int frameSizeX = Utils::getResizeBorderThickness(window, true, true);
|
||||
const int scaledFrameSizeX = std::round(qreal(frameSizeX) * scaleFactor);
|
||||
const bool isLeft = (nativeLocalPos.x < scaledFrameSizeX);
|
||||
const bool isRight = (nativeLocalPos.x >= (clientWidth - scaledFrameSizeX));
|
||||
|
@ -975,8 +962,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
return true;
|
||||
}
|
||||
case WM_MOUSEMOVE:
|
||||
if ((data.lastHitTestResult != WindowPart::ChromeButton) && data.mouseLeaveBlocked) {
|
||||
muData.mouseLeaveBlocked = false;
|
||||
if ((data->lastHitTestResult != WindowPart::ChromeButton) && data->mouseLeaveBlocked) {
|
||||
data->mouseLeaveBlocked = false;
|
||||
std::ignore = requestForMouseLeaveMessage(hWnd, false);
|
||||
}
|
||||
break;
|
||||
|
@ -999,11 +986,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
case WM_NCPOINTERUP:
|
||||
#endif
|
||||
case WM_NCMOUSEHOVER: {
|
||||
const WindowPart currentWindowPart = data.lastHitTestResult;
|
||||
const WindowPart currentWindowPart = data->lastHitTestResult;
|
||||
if (uMsg == WM_NCMOUSEMOVE) {
|
||||
if (currentWindowPart != WindowPart::ChromeButton) {
|
||||
std::ignore = data.params.resetQtGrabbedControl();
|
||||
if (muData.mouseLeaveBlocked) {
|
||||
std::ignore = data->callbacks->resetQtGrabbedControl();
|
||||
if (data->mouseLeaveBlocked) {
|
||||
emulateClientAreaMessage(WM_NCMOUSELEAVE);
|
||||
}
|
||||
}
|
||||
|
@ -1014,12 +1001,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// If the mouse is entering the client area, there must be a WM_NCHITTEST setting
|
||||
// it to `Client` before the WM_NCMOUSELEAVE comes;
|
||||
// If the mouse is leaving the window, current window part remains as `Outside`.
|
||||
muData.lastHitTestResult = WindowPart::Outside;
|
||||
data->lastHitTestResult = WindowPart::Outside;
|
||||
}
|
||||
|
||||
if (currentWindowPart == WindowPart::ChromeButton) {
|
||||
emulateClientAreaMessage();
|
||||
if (uMsg == WM_NCMOUSEMOVE) {
|
||||
// ### FIXME: Calling DefWindowProc() here is really dangerous, investigate how
|
||||
// to avoid doing this.
|
||||
*result = ::DefWindowProcW(hWnd, WM_NCMOUSEMOVE, wParam, lParam);
|
||||
} else {
|
||||
*result = (((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) ? TRUE : FALSE);
|
||||
|
@ -1028,18 +1017,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
}
|
||||
} break;
|
||||
case WM_NCMOUSELEAVE: {
|
||||
const WindowPart currentWindowPart = data.lastHitTestResult;
|
||||
const WindowPart currentWindowPart = data->lastHitTestResult;
|
||||
if (currentWindowPart == WindowPart::ChromeButton) {
|
||||
// If we press on the chrome button and move mouse, Windows will take the pressing area
|
||||
// as HTCLIENT which maybe because of our former retransmission of WM_NCLBUTTONDOWN, as
|
||||
// a result, a WM_NCMOUSELEAVE will come immediately and a lot of WM_MOUSEMOVE will come
|
||||
// if we move the mouse, we should track the mouse in advance.
|
||||
if (muData.mouseLeaveBlocked) {
|
||||
muData.mouseLeaveBlocked = false;
|
||||
if (data->mouseLeaveBlocked) {
|
||||
data->mouseLeaveBlocked = false;
|
||||
std::ignore = requestForMouseLeaveMessage(hWnd, false);
|
||||
}
|
||||
} else {
|
||||
if (data.mouseLeaveBlocked) {
|
||||
if (data->mouseLeaveBlocked) {
|
||||
// The mouse is moving from the chrome button to other non-client area, we should
|
||||
// emulate a WM_MOUSELEAVE message to reset the button state.
|
||||
emulateClientAreaMessage(WM_NCMOUSELEAVE);
|
||||
|
@ -1051,7 +1040,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// the mouse leaves window from client area and enters window from non-client area,
|
||||
// but it has no bad effect.
|
||||
|
||||
std::ignore = data.params.resetQtGrabbedControl();
|
||||
std::ignore = data->callbacks->resetQtGrabbedControl();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -1065,7 +1054,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// of the application a lot.
|
||||
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
|
||||
const QRect suggestedFrameGeometry{ windowPos->x, windowPos->y, windowPos->cx, windowPos->cy };
|
||||
const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(windowId) + Utils::getWindowCustomFrameMargins(window));
|
||||
const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(window) + Utils::getWindowCustomFrameMargins(window));
|
||||
const QRect suggestedGeometry = (suggestedFrameGeometry - frameMargins);
|
||||
if (Utils::toNativePixels(window, window->size()) != suggestedGeometry.size()) {
|
||||
windowPos->flags |= SWP_NOCOPYBITS;
|
||||
|
@ -1107,7 +1096,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
}
|
||||
#endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
|
||||
case WM_DPICHANGED: {
|
||||
const Dpi oldDpi = data.dpi;
|
||||
const Dpi oldDpi = data->dpi;
|
||||
const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
|
||||
if (Q_UNLIKELY(newDpi == oldDpi)) {
|
||||
WARNING << "Wrong WM_DPICHANGED received: same DPI.";
|
||||
|
@ -1115,18 +1104,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
}
|
||||
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd)
|
||||
<< "is" << newDpi << "(was" << oldDpi << ").";
|
||||
muData.dpi = newDpi;
|
||||
data->dpi = newDpi;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
if (Utils::isValidGeometry(data.restoreGeometry)) {
|
||||
if (Utils::isValidGeometry(data->restoreGeometry)) {
|
||||
// Update the window size only. The position should not be changed.
|
||||
muData.restoreGeometry.setSize(Utils::rescaleSize(data.restoreGeometry.size(), oldDpi.x, newDpi.x));
|
||||
muData.restoreGeometry.setSize(Utils::rescaleSize(data->restoreGeometry.size(), oldDpi.x, newDpi.x));
|
||||
}
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
data.params.forceChildrenRepaint(500);
|
||||
data->callbacks->forceChildrenRepaint(500);
|
||||
} break;
|
||||
case WM_DWMCOMPOSITIONCHANGED:
|
||||
// Re-apply the custom window frame if recovered from the basic theme.
|
||||
std::ignore = Utils::updateWindowFrameMargins(windowId, false);
|
||||
std::ignore = Utils::updateWindowFrameMargins(window, false);
|
||||
break;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
case WM_ENTERSIZEMOVE: // Sent to a window when the user drags the title bar or the resize border.
|
||||
|
@ -1137,7 +1126,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
if (wParam != SIZE_MAXIMIZED) {
|
||||
break;
|
||||
}
|
||||
if (!Utils::isValidGeometry(data.restoreGeometry)) {
|
||||
if (!Utils::isValidGeometry(data->restoreGeometry)) {
|
||||
updateRestoreGeometry(true);
|
||||
break;
|
||||
}
|
||||
|
@ -1149,11 +1138,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
break;
|
||||
}
|
||||
// The restore geometry is correct, no need to bother.
|
||||
if (rect2qrect(wp.rcNormalPosition) == data.restoreGeometry) {
|
||||
if (rect2qrect(wp.rcNormalPosition) == data->restoreGeometry) {
|
||||
break;
|
||||
}
|
||||
// OK, the restore geometry is wrong, let's correct it then :)
|
||||
wp.rcNormalPosition = qrect2rect(data.restoreGeometry);
|
||||
wp.rcNormalPosition = qrect2rect(data->restoreGeometry);
|
||||
if (::SetWindowPlacement(hWnd, &wp) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kSetWindowPlacement);
|
||||
}
|
||||
|
@ -1165,7 +1154,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// down the monitor (only a suggestion to the OS, the OS can still ignore
|
||||
// our request).
|
||||
if ((filteredWParam == SC_SCREENSAVE) || (filteredWParam == SC_MONITORPOWER)) {
|
||||
if (Utils::isFullScreen(windowId)) {
|
||||
if (Utils::isFullScreen(window)) {
|
||||
*result = FALSE;
|
||||
return true;
|
||||
}
|
||||
|
@ -1233,14 +1222,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
break;
|
||||
}
|
||||
std::ignore = Utils::triggerFrameChange(windowId);
|
||||
std::ignore = Utils::triggerFrameChange(window);
|
||||
const LRESULT originalResult = ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
if (::SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle)) == 0) {
|
||||
WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
break;
|
||||
}
|
||||
std::ignore = Utils::triggerFrameChange(windowId);
|
||||
std::ignore = Utils::triggerFrameChange(window);
|
||||
*result = originalResult;
|
||||
return true;
|
||||
}
|
||||
|
@ -1251,7 +1240,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
|
||||
if ((uMsg == WM_DWMCOMPOSITIONCHANGED) || (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)) {
|
||||
if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) {
|
||||
std::ignore = Utils::updateFramebufferTransparency(windowId);
|
||||
std::ignore = Utils::updateFramebufferTransparency(window);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1266,14 +1255,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
if (WindowsVersionHelper::isWin10RS5OrGreater()) {
|
||||
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
|
||||
const auto isWidget = [&data]() -> bool {
|
||||
const auto widget = data.params.getWidgetHandle();
|
||||
const auto widget = data->callbacks->getWidgetHandle();
|
||||
return (widget && widget->isWidgetType());
|
||||
}();
|
||||
if (!isWidget) {
|
||||
// Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications.
|
||||
std::ignore = Utils::updateGlobalWin32ControlsTheme(windowId, dark);
|
||||
std::ignore = Utils::updateGlobalWin32ControlsTheme(window, dark);
|
||||
}
|
||||
std::ignore = Utils::refreshWin32ThemeResources(windowId, dark);
|
||||
std::ignore = Utils::refreshWin32ThemeResources(window, dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,23 @@ using namespace Global;
|
|||
static_assert(std::size(WindowsVersions) == (static_cast<int>(WindowsVersion::Latest) + 1));
|
||||
#endif
|
||||
|
||||
FramelessCallbacksPtr FramelessCallbacks::create()
|
||||
{
|
||||
return std::make_shared<FramelessCallbacks>();
|
||||
}
|
||||
|
||||
FramelessData::~FramelessData()
|
||||
{
|
||||
if (extraData.ptr) {
|
||||
Q_ASSERT(extraData.deleter);
|
||||
if (extraData.deleter) {
|
||||
extraData.deleter(extraData.ptr);
|
||||
extraData.deleter = nullptr;
|
||||
}
|
||||
extraData.ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessHelperCoreInitialize()
|
||||
{
|
||||
static bool inited = false;
|
||||
|
|
|
@ -81,18 +81,6 @@ static constexpr const int kEventDelayInterval = 1000;
|
|||
}
|
||||
#endif
|
||||
|
||||
[[nodiscard]] static inline bool usePureQtImplementation()
|
||||
{
|
||||
static const auto result = []() -> bool {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
FramelessManagerPrivate::FramelessManagerPrivate(FramelessManager *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
|
@ -240,6 +228,19 @@ FramelessDataPtr FramelessManagerPrivate::getData(const QWindow *window)
|
|||
return it.value();
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::removeData(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const auto it = g_internalData()->constFind(window);
|
||||
if (it == g_internalData()->constEnd()) {
|
||||
return;
|
||||
}
|
||||
g_internalData()->erase(it);
|
||||
}
|
||||
|
||||
bool FramelessManagerPrivate::isThemeOverrided() const
|
||||
{
|
||||
return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown);
|
||||
|
@ -316,7 +317,7 @@ bool FramelessManager::isFramelessWindow(const QWindow *window) const
|
|||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
return FramelessManagerPrivate::getData(window)->isFrameless;
|
||||
return FramelessManagerPrivate::getData(window)->frameless;
|
||||
}
|
||||
|
||||
SystemTheme FramelessManager::systemTheme() const
|
||||
|
@ -369,19 +370,20 @@ bool FramelessManager::addWindow(const QWindow *window)
|
|||
return false;
|
||||
}
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
if (data->isFrameless) {
|
||||
Q_ASSERT(data);
|
||||
if (!data || data->frameless) {
|
||||
return false;
|
||||
}
|
||||
data->isFrameless = true;
|
||||
const bool pureQt = usePureQtImplementation();
|
||||
if (pureQt) {
|
||||
FramelessHelperQt::addWindow(window);
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (!pureQt) {
|
||||
FramelessHelperWin::addWindow(window);
|
||||
}
|
||||
#if FRAMELESSHELPER_CONFIG(native_impl)
|
||||
# ifdef Q_OS_WINDOWS
|
||||
std::ignore = Utils::installWindowProcHook(window);
|
||||
FramelessHelperWin::addWindow(window);
|
||||
# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
# elif defined(Q_OS_MACOS)
|
||||
# else
|
||||
# endif
|
||||
#else
|
||||
FramelessHelperQt::addWindow(window);
|
||||
#endif
|
||||
connect(window, &QWindow::destroyed, FramelessManager::instance(), [this, window](){ std::ignore = removeWindow(window); });
|
||||
return true;
|
||||
|
@ -394,19 +396,20 @@ bool FramelessManager::removeWindow(const QWindow *window)
|
|||
return false;
|
||||
}
|
||||
const auto it = g_internalData()->constFind(window);
|
||||
if ((it == g_internalData()->constEnd()) || !it.value()->isFrameless) {
|
||||
if (it == g_internalData()->constEnd()) {
|
||||
return false;
|
||||
}
|
||||
const bool pureQt = usePureQtImplementation();
|
||||
if (pureQt) {
|
||||
FramelessHelperQt::removeWindow(window);
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (!pureQt) {
|
||||
FramelessHelperWin::removeWindow(window);
|
||||
}
|
||||
#if FRAMELESSHELPER_CONFIG(native_impl)
|
||||
# ifdef Q_OS_WINDOWS
|
||||
FramelessHelperWin::removeWindow(window);
|
||||
std::ignore = Utils::uninstallWindowProcHook(window);
|
||||
std::ignore = Utils::removeMicaWindow(window);
|
||||
# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
# elif defined(Q_OS_MACOS)
|
||||
# else
|
||||
# endif
|
||||
#else
|
||||
FramelessHelperQt::removeWindow(window);
|
||||
#endif
|
||||
g_internalData()->erase(it);
|
||||
return true;
|
||||
|
|
|
@ -50,11 +50,11 @@ _GetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD
|
|||
Q_ASSERT(hWnd);
|
||||
Q_ASSERT(pvData);
|
||||
if (!hWnd || !pvData) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if (!API_USER_AVAILABLE(GetWindowCompositionAttribute)) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return API_CALL_FUNCTION4(user32, GetWindowCompositionAttribute, hWnd, pvData);
|
||||
|
@ -66,11 +66,11 @@ _SetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD
|
|||
Q_ASSERT(hWnd);
|
||||
Q_ASSERT(pvData);
|
||||
if (!hWnd || !pvData) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if (!API_USER_AVAILABLE(SetWindowCompositionAttribute)) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return API_CALL_FUNCTION4(user32, SetWindowCompositionAttribute, hWnd, pvData);
|
||||
|
@ -111,14 +111,14 @@ _ShouldAppsUseDarkMode(VOID)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
static const auto pShouldAppsUseDarkMode
|
||||
= reinterpret_cast<ShouldAppsUseDarkModePtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(132)));
|
||||
if (!pShouldAppsUseDarkMode) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pShouldAppsUseDarkMode();
|
||||
|
@ -129,19 +129,19 @@ _AllowDarkModeForWindow(const HWND hWnd, const BOOL bAllow)
|
|||
{
|
||||
Q_ASSERT(hWnd);
|
||||
if (!hWnd) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
static const auto pAllowDarkModeForWindow
|
||||
= reinterpret_cast<AllowDarkModeForWindowPtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(133)));
|
||||
if (!pAllowDarkModeForWindow) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pAllowDarkModeForWindow(hWnd, bAllow);
|
||||
|
@ -152,14 +152,14 @@ _AllowDarkModeForApp(const BOOL bAllow)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
static const auto pAllowDarkModeForApp
|
||||
= reinterpret_cast<AllowDarkModeForAppPtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
|
||||
if (!pAllowDarkModeForApp) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pAllowDarkModeForApp(bAllow);
|
||||
|
@ -170,14 +170,14 @@ _FlushMenuThemes(VOID)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
static const auto pFlushMenuThemes
|
||||
= reinterpret_cast<FlushMenuThemesPtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(136)));
|
||||
if (!pFlushMenuThemes) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
pFlushMenuThemes();
|
||||
|
@ -188,14 +188,14 @@ _RefreshImmersiveColorPolicyState(VOID)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
static const auto pRefreshImmersiveColorPolicyState
|
||||
= reinterpret_cast<RefreshImmersiveColorPolicyStatePtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(104)));
|
||||
if (!pRefreshImmersiveColorPolicyState) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
pRefreshImmersiveColorPolicyState();
|
||||
|
@ -206,19 +206,19 @@ _IsDarkModeAllowedForWindow(const HWND hWnd)
|
|||
{
|
||||
Q_ASSERT(hWnd);
|
||||
if (!hWnd) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
static const auto pIsDarkModeAllowedForWindow
|
||||
= reinterpret_cast<IsDarkModeAllowedForWindowPtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(137)));
|
||||
if (!pIsDarkModeAllowedForWindow) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pIsDarkModeAllowedForWindow(hWnd);
|
||||
|
@ -229,14 +229,14 @@ _GetIsImmersiveColorUsingHighContrast(const IMMERSIVE_HC_CACHE_MODE mode)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
static const auto pGetIsImmersiveColorUsingHighContrast
|
||||
= reinterpret_cast<GetIsImmersiveColorUsingHighContrastPtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(106)));
|
||||
if (!pGetIsImmersiveColorUsingHighContrast) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pGetIsImmersiveColorUsingHighContrast(mode);
|
||||
|
@ -248,19 +248,19 @@ _OpenNcThemeData(const HWND hWnd, LPCWSTR pszClassList)
|
|||
Q_ASSERT(hWnd);
|
||||
Q_ASSERT(pszClassList);
|
||||
if (!hWnd || !pszClassList) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return nullptr;
|
||||
}
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
}
|
||||
static const auto pOpenNcThemeData
|
||||
= reinterpret_cast<OpenNcThemeDataPtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(49)));
|
||||
if (!pOpenNcThemeData) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
}
|
||||
return pOpenNcThemeData(hWnd, pszClassList);
|
||||
|
@ -271,14 +271,14 @@ _ShouldSystemUseDarkMode(VOID)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
static const auto pShouldSystemUseDarkMode
|
||||
= reinterpret_cast<ShouldSystemUseDarkModePtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(138)));
|
||||
if (!pShouldSystemUseDarkMode) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pShouldSystemUseDarkMode();
|
||||
|
@ -289,14 +289,14 @@ _SetPreferredAppMode(const PREFERRED_APP_MODE mode)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return PAM_MAX;
|
||||
}
|
||||
static const auto pSetPreferredAppMode
|
||||
= reinterpret_cast<SetPreferredAppModePtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
|
||||
if (!pSetPreferredAppMode) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return PAM_MAX;
|
||||
}
|
||||
return pSetPreferredAppMode(mode);
|
||||
|
@ -307,14 +307,14 @@ _IsDarkModeAllowedForApp(VOID)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
static const auto pIsDarkModeAllowedForApp
|
||||
= reinterpret_cast<IsDarkModeAllowedForAppPtr>(
|
||||
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(139)));
|
||||
if (!pIsDarkModeAllowedForApp) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pIsDarkModeAllowedForApp();
|
||||
|
@ -325,12 +325,12 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable)
|
|||
{
|
||||
Q_ASSERT(hWnd);
|
||||
if (!hWnd) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
using EnableChildWindowDpiMessagePtr = decltype(&::_EnableChildWindowDpiMessage);
|
||||
|
@ -355,7 +355,7 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable)
|
|||
return nullptr;
|
||||
}();
|
||||
if (!pEnableChildWindowDpiMessage) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pEnableChildWindowDpiMessage(hWnd, fEnable);
|
||||
|
@ -366,7 +366,7 @@ _EnablePerMonitorDialogScaling2(VOID)
|
|||
{
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
using EnablePerMonitorDialogScalingPtr = decltype(&::_EnablePerMonitorDialogScaling);
|
||||
|
@ -385,7 +385,7 @@ _EnablePerMonitorDialogScaling2(VOID)
|
|||
return nullptr;
|
||||
}();
|
||||
if (!pEnablePerMonitorDialogScaling) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pEnablePerMonitorDialogScaling();
|
||||
|
@ -396,12 +396,12 @@ _GetDpiForWindow2(const HWND hWnd)
|
|||
{
|
||||
Q_ASSERT(hWnd);
|
||||
if (!hWnd) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
using GetDpiForWindowPtr = decltype(&::_GetDpiForWindow);
|
||||
|
@ -424,7 +424,7 @@ _GetDpiForWindow2(const HWND hWnd)
|
|||
return nullptr;
|
||||
}();
|
||||
if (!pGetDpiForWindow) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
return pGetDpiForWindow(hWnd);
|
||||
|
@ -436,12 +436,12 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi)
|
|||
Q_ASSERT(nIndex >= 0);
|
||||
Q_ASSERT(dpi != 0);
|
||||
if ((nIndex < 0) || (dpi == 0)) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
using GetSystemMetricsForDpiPtr = decltype(&::_GetSystemMetricsForDpi);
|
||||
|
@ -460,7 +460,7 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi)
|
|||
return nullptr;
|
||||
}();
|
||||
if (!pGetSystemMetricsForDpi) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
return pGetSystemMetricsForDpi(nIndex, dpi);
|
||||
|
@ -473,12 +473,12 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle,
|
|||
Q_ASSERT(lpRect);
|
||||
Q_ASSERT(dpi != 0);
|
||||
if (!lpRect || (dpi == 0)) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
using AdjustWindowRectExForDpiPtr = decltype(&::_AdjustWindowRectExForDpi);
|
||||
|
@ -496,7 +496,7 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle,
|
|||
return nullptr;
|
||||
}();
|
||||
if (!pAdjustWindowRectExForDpi) {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
return pAdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle, dpi);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "framelesshelper_windows.h"
|
||||
#include "framelessmanager.h"
|
||||
#include "framelessmanager_p.h"
|
||||
#include "framelessconfig_p.h"
|
||||
#include "sysapiloader_p.h"
|
||||
#include "registrykey_p.h"
|
||||
|
@ -193,12 +194,20 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient)
|
|||
FRAMELESSHELPER_STRING_CONSTANT(DwmFlush)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos)
|
||||
|
||||
struct Win32UtilsInternal
|
||||
struct FramelessDataExtra
|
||||
{
|
||||
WNDPROC qtWindowProc = nullptr;
|
||||
bool windowProcHooked = false;
|
||||
bool mica = false;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
|
||||
static inline void FramelessDataExtraDeleter(void *data)
|
||||
{
|
||||
Q_ASSERT(data);
|
||||
if (data) {
|
||||
delete static_cast<FramelessDataExtra *>(data);
|
||||
}
|
||||
}
|
||||
|
||||
struct Win32Message
|
||||
{
|
||||
|
@ -576,42 +585,6 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
};
|
||||
#undef DEFINE_WIN32_MESSAGE
|
||||
|
||||
[[nodiscard]] QPoint point2qpoint(const POINT &point)
|
||||
{
|
||||
return QPoint{ int(point.x), int(point.y) };
|
||||
}
|
||||
|
||||
[[nodiscard]] POINT qpoint2point(const QPoint &point)
|
||||
{
|
||||
return POINT{ LONG(point.x()), LONG(point.y()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] QSize size2qsize(const SIZE &size)
|
||||
{
|
||||
return QSize{ int(size.cx), int(size.cy) };
|
||||
}
|
||||
|
||||
[[nodiscard]] SIZE qsize2size(const QSize &size)
|
||||
{
|
||||
return SIZE{ LONG(size.width()), LONG(size.height()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] QRect rect2qrect(const RECT &rect)
|
||||
{
|
||||
return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } };
|
||||
}
|
||||
|
||||
[[nodiscard]] RECT qrect2rect(const QRect &qrect)
|
||||
{
|
||||
return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] QString hwnd2str(const HWND hwnd)
|
||||
{
|
||||
// NULL handle is allowed here.
|
||||
return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast<WId>(hwnd), 16).toUpper().rightJustified(8, u'0');
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd)
|
||||
{
|
||||
Q_ASSERT(hwnd);
|
||||
|
@ -814,29 +787,29 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
return std::round(qreal(::GetSystemMetrics(index)) / dpr);
|
||||
}
|
||||
|
||||
[[maybe_unused]] [[nodiscard]] static inline
|
||||
[[maybe_unused]] [[nodiscard]] static inline constexpr
|
||||
DWORD qtEdgesToWin32Orientation(const Qt::Edges edges)
|
||||
{
|
||||
if (edges == Qt::Edges{}) {
|
||||
return 0;
|
||||
} else if (edges == (Qt::LeftEdge)) {
|
||||
return 0xF001; // SC_SIZELEFT
|
||||
return SC_SIZELEFT;
|
||||
} else if (edges == (Qt::RightEdge)) {
|
||||
return 0xF002; // SC_SIZERIGHT
|
||||
return SC_SIZERIGHT;
|
||||
} else if (edges == (Qt::TopEdge)) {
|
||||
return 0xF003; // SC_SIZETOP
|
||||
return SC_SIZETOP;
|
||||
} else if (edges == (Qt::TopEdge | Qt::LeftEdge)) {
|
||||
return 0xF004; // SC_SIZETOPLEFT
|
||||
return SC_SIZETOPLEFT;
|
||||
} else if (edges == (Qt::TopEdge | Qt::RightEdge)) {
|
||||
return 0xF005; // SC_SIZETOPRIGHT
|
||||
return SC_SIZETOPRIGHT;
|
||||
} else if (edges == (Qt::BottomEdge)) {
|
||||
return 0xF006; // SC_SIZEBOTTOM
|
||||
return SC_SIZEBOTTOM;
|
||||
} else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) {
|
||||
return 0xF007; // SC_SIZEBOTTOMLEFT
|
||||
return SC_SIZEBOTTOMLEFT;
|
||||
} else if (edges == (Qt::BottomEdge | Qt::RightEdge)) {
|
||||
return 0xF008; // SC_SIZEBOTTOMRIGHT
|
||||
return SC_SIZEBOTTOMRIGHT;
|
||||
} else {
|
||||
return 0xF000; // SC_SIZE
|
||||
return SC_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -854,7 +827,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool isNonClientMessage(const UINT message)
|
||||
[[nodiscard]] static inline constexpr bool isNonClientMessage(const UINT message)
|
||||
{
|
||||
if (((message >= WM_NCCREATE) && (message <= WM_NCACTIVATE))
|
||||
|| ((message >= WM_NCMOUSEMOVE) && (message <= WM_NCMBUTTONDBLCLK))
|
||||
|
@ -867,7 +840,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool isMouseMessage(const UINT message, bool *isNonClient = nullptr)
|
||||
[[nodiscard]] static inline constexpr bool isMouseMessage(const UINT message, bool *isNonClient = nullptr)
|
||||
{
|
||||
if (((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST))
|
||||
|| ((message == WM_MOUSEHOVER) || (message == WM_MOUSELEAVE))) {
|
||||
|
@ -887,18 +860,12 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool usePureQtImplementation()
|
||||
{
|
||||
static const bool result = FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline LRESULT CALLBACK FramelessHelperHookWindowProc
|
||||
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
|
||||
{
|
||||
Q_ASSERT(hWnd);
|
||||
if (!hWnd) {
|
||||
return 0;
|
||||
return FALSE;
|
||||
}
|
||||
#if FRAMELESSHELPER_CONFIG(debug_output)
|
||||
if (isWin32MessageDebuggingEnabled()) {
|
||||
|
@ -913,14 +880,20 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
}
|
||||
#endif
|
||||
const QWindow *window = Utils::findWindow(reinterpret_cast<WId>(hWnd));
|
||||
Q_ASSERT(window);
|
||||
if (!window || !FramelessManager::instance()->isFramelessWindow(window)) {
|
||||
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
const FramelessDataPtr data = FramelessHelperExtractData(window);
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data) {
|
||||
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
|
||||
Q_ASSERT(extraData);
|
||||
if (!extraData) {
|
||||
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
// https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025
|
||||
// We can see from the source code that Qt will filter out some messages first and then send the unfiltered
|
||||
// messages to the event dispatcher. To activate the Snap Layout feature on Windows 11, we must process
|
||||
|
@ -939,7 +912,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
// (and correct client area size, especially when the window is maximized/fullscreen). So we still go through
|
||||
// the normal code path of the original qWindowsWndProc() function, but only for this specific message. It should
|
||||
// be OK because Qt won't prevent us from handling WM_NCCALCSIZE.
|
||||
if (!usePureQtImplementation() && (uMsg != WM_NCCALCSIZE)) {
|
||||
if ((uMsg != WM_NCCALCSIZE)) {
|
||||
MSG message;
|
||||
SecureZeroMemory(&message, sizeof(message));
|
||||
message.hwnd = hWnd;
|
||||
|
@ -1008,7 +981,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
case WM_RBUTTONUP: {
|
||||
const QPoint nativeLocalPos = getNativePosFromMouse();
|
||||
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, nativeLocalPos);
|
||||
if (data->callbacks.isInsideTitleBarDraggableArea(qtScenePos)) {
|
||||
if (data->callbacks->isInsideTitleBarDraggableArea(qtScenePos)) {
|
||||
POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()};
|
||||
if (::ClientToScreen(hWnd, &pos) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kClientToScreen);
|
||||
|
@ -1051,13 +1024,13 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
|
|||
// behavior is not what we would want to see because it doesn't know our
|
||||
// window doesn't have any window frame now, so return early here to avoid
|
||||
// entering Qt's own handling logic.
|
||||
return 0; // Return 0 means we have handled this event.
|
||||
return FALSE; // Return 0 means we have handled this event.
|
||||
}
|
||||
Q_ASSERT(g_win32UtilsData()->qtWindowProc);
|
||||
if (g_win32UtilsData()->qtWindowProc) {
|
||||
Q_ASSERT(extraData->qtWindowProc);
|
||||
if (extraData->qtWindowProc) {
|
||||
// Hand over to Qt's original window proc function for events we are not
|
||||
// interested in.
|
||||
return ::CallWindowProcW(g_win32UtilsData()->qtWindowProc, hWnd, uMsg, wParam, lParam);
|
||||
return ::CallWindowProcW(extraData->qtWindowProc, hWnd, uMsg, wParam, lParam);
|
||||
} else {
|
||||
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
@ -1123,20 +1096,28 @@ bool Utils::updateWindowFrameMargins(const QWindow *window, const bool reset)
|
|||
if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) {
|
||||
return false;
|
||||
}
|
||||
// We can't extend the window frame when DWM composition is disabled.
|
||||
// We can't extend the window frame when DWM composition is disabled anyway.
|
||||
// No need to try further in this case.
|
||||
if (!isDwmCompositionEnabled()) {
|
||||
return false;
|
||||
}
|
||||
const FramelessDataPtr data = FramelessHelperExtractData(window);
|
||||
const bool micaEnabled = (data && data->micaEnabled);
|
||||
const auto margins = [micaEnabled, reset]() -> MARGINS {
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
|
||||
Q_ASSERT(extraData);
|
||||
if (!extraData) {
|
||||
return false;
|
||||
}
|
||||
const auto margins = [extraData, reset]() -> MARGINS {
|
||||
// To make Mica/Mica Alt work for normal Win32 windows, we have to
|
||||
// let the window frame extend to the whole window (or disable the
|
||||
// redirection surface, but this will break GDI's rendering, so we
|
||||
// can't do this, unfortunately), so we can't change the window frame
|
||||
// margins in this case, otherwise Mica/Mica Alt will be broken.
|
||||
if (micaEnabled) {
|
||||
if (extraData->mica) {
|
||||
return {-1, -1, -1, -1};
|
||||
}
|
||||
if (reset || isWindowFrameBorderVisible()) {
|
||||
|
@ -1282,7 +1263,7 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool
|
|||
if (!FramelessManager::instance()->isFramelessWindow(window)) {
|
||||
return false;
|
||||
}
|
||||
const FramelessDataPtr data = FramelessHelperExtractData(window);
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data) {
|
||||
return false;
|
||||
|
@ -1298,11 +1279,11 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool
|
|||
}
|
||||
|
||||
// Tweak the menu items according to the current window status and user settings.
|
||||
const bool disableRestore = data->callbacks.getProperty(kSysMenuDisableRestoreVar, false).toBool();
|
||||
const bool disableMinimize = data->callbacks.getProperty(kSysMenuDisableMinimizeVar, false).toBool();
|
||||
const bool disableMaximize = data->callbacks.getProperty(kSysMenuDisableMaximizeVar, false).toBool();
|
||||
const bool disableRestore = data->callbacks->getProperty(kSysMenuDisableRestoreVar, false).toBool();
|
||||
const bool disableMinimize = data->callbacks->getProperty(kSysMenuDisableMinimizeVar, false).toBool();
|
||||
const bool disableMaximize = data->callbacks->getProperty(kSysMenuDisableMaximizeVar, false).toBool();
|
||||
const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(window));
|
||||
const bool fixedSize = data->callbacks.isWindowFixedSize();
|
||||
const bool fixedSize = data->callbacks->isWindowFixedSize();
|
||||
::EnableMenuItem(hMenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize && !disableRestore) ? MFS_ENABLED : MFS_DISABLED)));
|
||||
// The first menu item should be selected by default if the menu is brought
|
||||
// up by keyboard. I don't know how to pre-select a menu item but it seems
|
||||
|
@ -1342,7 +1323,7 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool
|
|||
// highlighting until we unhighlight it manually.
|
||||
::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE));
|
||||
|
||||
if (result == 0) {
|
||||
if (result == FALSE) {
|
||||
// The user canceled the menu, no need to continue.
|
||||
return true;
|
||||
}
|
||||
|
@ -1877,7 +1858,7 @@ bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
|
|||
return false;
|
||||
}
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
if (::PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) {
|
||||
if (::PostMessageW(hwnd, WM_SYSCOMMAND, SC_DRAGMOVE, 0) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kPostMessageW);
|
||||
return false;
|
||||
}
|
||||
|
@ -1914,10 +1895,8 @@ bool Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
|
|||
bool Utils::isWindowFrameBorderVisible()
|
||||
{
|
||||
static const auto result = []() -> bool {
|
||||
#if FRAMELESSHELPER_CONFIG(native_impl)
|
||||
const FramelessConfig * const config = FramelessConfig::instance();
|
||||
if (config->isSet(Option::UseCrossPlatformQtImplementation)) {
|
||||
return false;
|
||||
}
|
||||
if (config->isSet(Option::ForceShowWindowFrameBorder)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1925,6 +1904,9 @@ bool Utils::isWindowFrameBorderVisible()
|
|||
return false;
|
||||
}
|
||||
return WindowsVersionHelper::isWin10OrGreater();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
@ -1950,8 +1932,20 @@ bool Utils::installWindowProcHook(const QWindow *window)
|
|||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
if (!data->extraData.ptr) {
|
||||
data->extraData.ptr = new FramelessDataExtra();
|
||||
}
|
||||
if (!data->extraData.deleter) {
|
||||
data->extraData.deleter = FramelessDataExtraDeleter;
|
||||
}
|
||||
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
if (!g_win32UtilsData()->qtWindowProc) {
|
||||
if (!extraData->qtWindowProc) {
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
const auto qtWindowProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC));
|
||||
Q_ASSERT(qtWindowProc);
|
||||
|
@ -1959,53 +1953,56 @@ bool Utils::installWindowProcHook(const QWindow *window)
|
|||
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
return false;
|
||||
}
|
||||
g_win32UtilsData()->qtWindowProc = qtWindowProc;
|
||||
extraData->qtWindowProc = qtWindowProc;
|
||||
}
|
||||
FramelessDataPtr data = FramelessHelperExtractData(window);
|
||||
if (!data) {
|
||||
data.reset(new FramelessData);
|
||||
FramelessHelperSetData(const_cast<QWindow *>(window), data);
|
||||
}
|
||||
if (!data->windowProcHooked) {
|
||||
if (!extraData->windowProcHooked) {
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(FramelessHelperHookWindowProc)) == 0) {
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return false;
|
||||
}
|
||||
data->windowProcHooked = true;
|
||||
extraData->windowProcHooked = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Utils::uninstallWindowProcHook(const WId windowId)
|
||||
bool Utils::uninstallWindowProcHook(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const auto it = g_win32UtilsData()->data.constFind(windowId);
|
||||
if (it != g_win32UtilsData()->data.constEnd()) {
|
||||
g_win32UtilsData()->data.erase(it);
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
if (g_win32UtilsData()->data.isEmpty() && g_win32UtilsData()->qtWindowProc) {
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(g_win32UtilsData()->qtWindowProc)) == 0) {
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return false;
|
||||
}
|
||||
g_win32UtilsData()->qtWindowProc = nullptr;
|
||||
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
|
||||
if (!extraData || !extraData->windowProcHooked) {
|
||||
return false;
|
||||
}
|
||||
Q_ASSERT(extraData->qtWindowProc);
|
||||
if (!extraData->qtWindowProc) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(extraData->qtWindowProc)) == 0) {
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return false;
|
||||
}
|
||||
extraData->qtWindowProc = nullptr;
|
||||
extraData->windowProcHooked = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Utils::setAeroSnappingEnabled(const WId windowId, const bool enable)
|
||||
bool Utils::setAeroSnappingEnabled(const QWindow *window, const bool enable)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
const auto oldWindowStyle = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE));
|
||||
if (oldWindowStyle == 0) {
|
||||
|
@ -2027,7 +2024,7 @@ bool Utils::setAeroSnappingEnabled(const WId windowId, const bool enable)
|
|||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return false;
|
||||
}
|
||||
return triggerFrameChange(windowId);
|
||||
return triggerFrameChange(window);
|
||||
}
|
||||
|
||||
bool Utils::tryToEnableHighestDpiAwarenessLevel()
|
||||
|
@ -2138,10 +2135,10 @@ bool Utils::tryToEnableHighestDpiAwarenessLevel()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
|
||||
bool Utils::updateGlobalWin32ControlsTheme(const QWindow *window, const bool dark)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
// There's no global dark theme for common Win32 controls before Win10 1809.
|
||||
|
@ -2151,7 +2148,7 @@ bool Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
|
|||
if (!API_THEME_AVAILABLE(SetWindowTheme)) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
const HRESULT hr = API_CALL_FUNCTION(uxtheme, SetWindowTheme, hwnd,
|
||||
(dark ? kSystemDarkThemeResourceName : kSystemLightThemeResourceName), nullptr);
|
||||
if (FAILED(hr)) {
|
||||
|
@ -2209,10 +2206,10 @@ bool Utils::shouldAppsUseDarkMode_windows()
|
|||
return resultFromRegistry();
|
||||
}
|
||||
|
||||
bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle style)
|
||||
bool Utils::setCornerStyleForWindow(const QWindow *window, const WindowCornerStyle style)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
// We cannot change the window corner style until Windows 11.
|
||||
|
@ -2222,7 +2219,7 @@ bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle
|
|||
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
const auto wcp = [style]() -> _DWM_WINDOW_CORNER_PREFERENCE {
|
||||
switch (style) {
|
||||
case WindowCornerStyle::Default:
|
||||
|
@ -2246,22 +2243,32 @@ bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode, const QColor &color)
|
||||
bool Utils::setBlurBehindWindowEnabled(const QWindow *window, const BlurMode mode, const QColor &color)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
|
||||
Q_ASSERT(extraData);
|
||||
if (!extraData) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
if (WindowsVersionHelper::isWin8OrGreater()) {
|
||||
if (!(API_DWM_AVAILABLE(DwmSetWindowAttribute)
|
||||
&& API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea))) {
|
||||
WARNING << "Blur behind window is not available on current platform.";
|
||||
return false;
|
||||
}
|
||||
const auto restoreWindowFrameMargins = [windowId]() -> void {
|
||||
g_win32UtilsData()->micaWindowIds.removeAll(windowId);
|
||||
std::ignore = updateWindowFrameMargins(windowId, false);
|
||||
const auto restoreWindowFrameMargins = [window, extraData]() -> void {
|
||||
extraData->mica = false;
|
||||
std::ignore = updateWindowFrameMargins(window, false);
|
||||
};
|
||||
static const bool preferMicaAlt = (qEnvironmentVariableIntValue("FRAMELESSHELPER_PREFER_MICA_ALT") != 0);
|
||||
const auto blurMode = [mode]() -> BlurMode {
|
||||
|
@ -2334,7 +2341,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return result;
|
||||
} else {
|
||||
if ((blurMode == BlurMode::Windows_Mica) || (blurMode == BlurMode::Windows_MicaAlt)) {
|
||||
g_win32UtilsData()->micaWindowIds.append(windowId);
|
||||
extraData->mica = true;
|
||||
// By giving a negative value, DWM will extend the window frame into the whole
|
||||
// client area. We need this step because the Mica material can only be applied
|
||||
// to the non-client area of a window. Without this step, you'll get a window
|
||||
|
@ -2531,13 +2538,13 @@ bool Utils::isBlurBehindWindowSupported()
|
|||
return result;
|
||||
}
|
||||
|
||||
bool Utils::hideOriginalTitleBarElements(const WId windowId, const bool disable)
|
||||
bool Utils::hideOriginalTitleBarElements(const QWindow *window, const bool disable)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
static constexpr const DWORD validBits = (WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON | WTNCA_NOSYSMENU);
|
||||
const DWORD mask = (disable ? validBits : 0);
|
||||
const HRESULT hr = _SetWindowThemeNonClientAttributes(hwnd, mask, mask);
|
||||
|
@ -2575,9 +2582,9 @@ bool Utils::setQtDarkModeAwareEnabled(const bool enable)
|
|||
// flag has no effect for pure Qt Quick applications.
|
||||
return {App::DarkModeWindowFrames | App::DarkModeStyle};
|
||||
# else // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) \
|
||||
// Don't try to use the broken dark theme for Qt Widgets applications. \
|
||||
// For Qt Quick applications this is also enough. There's no global dark \
|
||||
// theme for them anyway.
|
||||
// Don't try to use the broken dark theme for Qt Widgets applications. \
|
||||
// For Qt Quick applications this is also enough. There's no global dark \
|
||||
// theme for them anyway.
|
||||
return {App::DarkModeWindowFrames};
|
||||
# endif // (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||
}());
|
||||
|
@ -2604,13 +2611,13 @@ bool Utils::registerThemeChangeNotification()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
|
||||
bool Utils::refreshWin32ThemeResources(const QWindow *window, const bool dark)
|
||||
{
|
||||
// Code learned from the following repositories. Thank very much for their great effort!
|
||||
// https://github.com/ysc3839/win32-darkmode/blob/master/win32-darkmode/DarkMode.h
|
||||
// https://github.com/TortoiseGit/TortoiseGit/blob/master/src/TortoiseGitBlame/MainFrm.cpp
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
// We have no way to adjust such things until Win10 1809.
|
||||
|
@ -2620,7 +2627,7 @@ bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
|
|||
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
|
||||
return false;
|
||||
}
|
||||
const auto hWnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hWnd = qWindowId<HWND>(window);
|
||||
const DWORD borderFlag = (WindowsVersionHelper::isWin1020H1OrGreater()
|
||||
? _DWMWA_USE_IMMERSIVE_DARK_MODE : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1);
|
||||
const BOOL darkFlag = (dark ? TRUE : FALSE);
|
||||
|
@ -2689,10 +2696,10 @@ bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Utils::enableNonClientAreaDpiScalingForWindow(const WId windowId)
|
||||
bool Utils::enableNonClientAreaDpiScalingForWindow(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
if (!API_USER_AVAILABLE(EnableNonClientDpiScaling)) {
|
||||
|
@ -2702,7 +2709,7 @@ bool Utils::enableNonClientAreaDpiScalingForWindow(const WId windowId)
|
|||
if (getDpiAwarenessForCurrentProcess() == DpiAwareness::PerMonitorVersion2) {
|
||||
return true;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
if (API_CALL_FUNCTION4(user32, EnableNonClientDpiScaling, hwnd) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kEnableNonClientDpiScaling);
|
||||
return false;
|
||||
|
@ -2816,10 +2823,10 @@ DpiAwareness Utils::getDpiAwarenessForCurrentProcess(bool *highest)
|
|||
return DpiAwareness::Unknown;
|
||||
}
|
||||
|
||||
bool Utils::fixupChildWindowsDpiMessage(const WId windowId)
|
||||
bool Utils::fixupChildWindowsDpiMessage(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
// This hack is only available on Windows 10 and newer, and starting from
|
||||
|
@ -2830,7 +2837,7 @@ bool Utils::fixupChildWindowsDpiMessage(const WId windowId)
|
|||
&& (getDpiAwarenessForCurrentProcess() == DpiAwareness::PerMonitorVersion2))) {
|
||||
return true;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
if (_EnableChildWindowDpiMessage2(hwnd, TRUE) != FALSE) {
|
||||
return true;
|
||||
}
|
||||
|
@ -2884,13 +2891,13 @@ bool Utils::setDarkModeAllowedForApp(const bool allow)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Utils::bringWindowToFront(const WId windowId)
|
||||
bool Utils::bringWindowToFront(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
const HWND oldForegroundWindow = ::GetForegroundWindow();
|
||||
if (!oldForegroundWindow) {
|
||||
// The foreground window can be NULL, it's not an API error.
|
||||
|
@ -2956,13 +2963,13 @@ bool Utils::bringWindowToFront(const WId windowId)
|
|||
return moveWindowToMonitor(hwnd, activeMonitor.value());
|
||||
}
|
||||
|
||||
QPoint Utils::getWindowPlacementOffset(const WId windowId)
|
||||
QPoint Utils::getWindowPlacementOffset(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return {};
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
const auto exStyle = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
|
||||
if (exStyle == 0) {
|
||||
|
@ -2983,13 +2990,13 @@ QPoint Utils::getWindowPlacementOffset(const WId windowId)
|
|||
return {work.left - total.left, work.top - total.top};
|
||||
}
|
||||
|
||||
QRect Utils::getWindowRestoreGeometry(const WId windowId)
|
||||
QRect Utils::getWindowRestoreGeometry(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return {};
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
WINDOWPLACEMENT wp;
|
||||
SecureZeroMemory(&wp, sizeof(wp));
|
||||
wp.length = sizeof(wp);
|
||||
|
@ -2997,16 +3004,25 @@ QRect Utils::getWindowRestoreGeometry(const WId windowId)
|
|||
WARNING << getSystemErrorMessage(kGetWindowPlacement);
|
||||
return {};
|
||||
}
|
||||
return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(windowId));
|
||||
return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(window));
|
||||
}
|
||||
|
||||
bool Utils::removeMicaWindow(const WId windowId)
|
||||
bool Utils::removeMicaWindow(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
g_win32UtilsData()->micaWindowIds.removeAll(windowId);
|
||||
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
|
||||
Q_ASSERT(data);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
|
||||
if (!extraData || !extraData->mica) {
|
||||
return false;
|
||||
}
|
||||
extraData->mica = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3041,13 +3057,13 @@ quint64 Utils::getKeyState()
|
|||
return result;
|
||||
}
|
||||
|
||||
bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel)
|
||||
bool Utils::isValidWindow(const QWindow *window, const bool checkVisible, const bool checkTopLevel)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
if (::IsWindow(hwnd) == FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3056,7 +3072,7 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
|
|||
return false;
|
||||
}
|
||||
const LONG_PTR exStyles = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
|
||||
if ((exStyles != 0) && (exStyles & WS_EX_TOOLWINDOW)) {
|
||||
if ((exStyles == 0) || (exStyles & WS_EX_TOOLWINDOW)) {
|
||||
return false;
|
||||
}
|
||||
RECT rect = { 0, 0, 0, 0 };
|
||||
|
@ -3079,10 +3095,10 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Utils::updateFramebufferTransparency(const WId windowId)
|
||||
bool Utils::updateFramebufferTransparency(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
if (!API_DWM_AVAILABLE(DwmEnableBlurBehindWindow)) {
|
||||
|
@ -3093,7 +3109,7 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
|
|||
if (!isDwmCompositionEnabled()) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const auto hwnd = qWindowId<HWND>(window);
|
||||
bool opaque = false;
|
||||
bool ok = false;
|
||||
std::ignore = getDwmColorizationColor(&opaque, &ok);
|
||||
|
@ -3102,11 +3118,11 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
|
|||
DWM_BLURBEHIND bb;
|
||||
SecureZeroMemory(&bb, sizeof(bb));
|
||||
bb.dwFlags = (DWM_BB_ENABLE | DWM_BB_BLURREGION);
|
||||
bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
|
||||
bb.hRgnBlur = ::CreateRectRgn(0, 0, -1, -1);
|
||||
bb.fEnable = TRUE;
|
||||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmEnableBlurBehindWindow, hwnd, &bb);
|
||||
if (bb.hRgnBlur) {
|
||||
if (DeleteObject(bb.hRgnBlur) == FALSE) {
|
||||
if (::DeleteObject(bb.hRgnBlur) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kDeleteObject);
|
||||
}
|
||||
}
|
||||
|
@ -3133,14 +3149,14 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
|
|||
return true;
|
||||
}
|
||||
|
||||
QMargins Utils::getWindowSystemFrameMargins(const WId windowId)
|
||||
QMargins Utils::getWindowSystemFrameMargins(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return {};
|
||||
}
|
||||
const auto horizontalMargin = int(getResizeBorderThickness(windowId, true, true));
|
||||
const auto verticalMargin = int(getResizeBorderThickness(windowId, false, true));
|
||||
const auto horizontalMargin = int(getResizeBorderThickness(window, true, true));
|
||||
const auto verticalMargin = int(getResizeBorderThickness(window, false, true));
|
||||
return QMargins{ horizontalMargin, verticalMargin, horizontalMargin, verticalMargin };
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue