Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-03-21 13:08:27 +08:00
parent 12988f2ddf
commit 6676a3c1f9
14 changed files with 98 additions and 71 deletions

View File

@ -34,6 +34,7 @@ struct QtHelper
{ {
QMutex mutex = {}; QMutex mutex = {};
QHash<QWindow *, FramelessHelperQt *> qtFramelessHelpers = {}; QHash<QWindow *, FramelessHelperQt *> qtFramelessHelpers = {};
QHash<QWindow *, Options> options = {};
explicit QtHelper() = default; explicit QtHelper() = default;
~QtHelper() = default; ~QtHelper() = default;
@ -59,6 +60,8 @@ void FramelessHelperQt::addWindow(QWindow *window)
g_qtHelper()->mutex.unlock(); g_qtHelper()->mutex.unlock();
return; return;
} }
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
g_qtHelper()->options.insert(window, options);
// Give it a parent so that it can be deleted even if we forget to do so. // Give it a parent so that it can be deleted even if we forget to do so.
const auto qtFramelessHelper = new FramelessHelperQt(window); const auto qtFramelessHelper = new FramelessHelperQt(window);
g_qtHelper()->qtFramelessHelpers.insert(window, qtFramelessHelper); g_qtHelper()->qtFramelessHelpers.insert(window, qtFramelessHelper);
@ -78,6 +81,7 @@ void FramelessHelperQt::removeWindow(QWindow *window)
g_qtHelper()->mutex.unlock(); g_qtHelper()->mutex.unlock();
return; return;
} }
g_qtHelper()->options.remove(window);
FramelessHelperQt *qtFramelessHelper = g_qtHelper()->qtFramelessHelpers.value(window); FramelessHelperQt *qtFramelessHelper = g_qtHelper()->qtFramelessHelpers.value(window);
g_qtHelper()->qtFramelessHelpers.remove(window); g_qtHelper()->qtFramelessHelpers.remove(window);
g_qtHelper()->mutex.unlock(); g_qtHelper()->mutex.unlock();
@ -109,18 +113,22 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
g_qtHelper()->mutex.unlock(); g_qtHelper()->mutex.unlock();
return false; return false;
} }
const Options options = g_qtHelper()->options.value(window);
g_qtHelper()->mutex.unlock(); g_qtHelper()->mutex.unlock();
if (Utils::isWindowFixedSize(window)) { if (Utils::isWindowFixedSize(window) || (options & Option::DisableResizing)) {
return false; return false;
} }
const auto mouseEvent = static_cast<QMouseEvent *>(event); const auto mouseEvent = static_cast<QMouseEvent *>(event);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPointF scenePos = mouseEvent->scenePosition(); const QPoint scenePos = mouseEvent->scenePosition().toPoint();
#else #else
const QPointF scenePos = mouseEvent->windowPos(); const QPoint scenePos = mouseEvent->windowPos().toPoint();
#endif #endif
switch (type) { switch (type) {
case QEvent::MouseMove: { case QEvent::MouseMove: {
if (options & Option::DontTouchCursorShape) {
return false;
}
const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos); const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos);
if (cs == Qt::ArrowCursor) { if (cs == Qt::ArrowCursor) {
window->unsetCursor(); window->unsetCursor();

View File

@ -39,7 +39,7 @@ struct Win32Helper
{ {
QMutex mutex = {}; QMutex mutex = {};
QScopedPointer<FramelessHelperWin> nativeEventFilter; QScopedPointer<FramelessHelperWin> nativeEventFilter;
QWindowList framelessWindows = {}; QHash<QWindow *, Options> options = {};
QHash<WId, QWindow *> windowMapping = {}; QHash<WId, QWindow *> windowMapping = {};
explicit Win32Helper() = default; explicit Win32Helper() = default;
@ -65,11 +65,17 @@ void FramelessHelperWin::addWindow(QWindow *window)
return; return;
} }
g_win32Helper()->mutex.lock(); g_win32Helper()->mutex.lock();
if (g_win32Helper()->framelessWindows.contains(window)) { if (g_win32Helper()->options.contains(window)) {
g_win32Helper()->mutex.unlock(); g_win32Helper()->mutex.unlock();
return; return;
} }
g_win32Helper()->framelessWindows.append(window); auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if ((options & Option::ForceHideWindowFrameBorder) && (options & Option::ForceShowWindowFrameBorder)) {
qWarning() << "You can't use both \"Option::ForceHideWindowFrameBorder\" and "
"\"Option::ForceShowWindowFrameBorder\" at the same time.";
options &= ~(Option::ForceHideWindowFrameBorder | Option::ForceShowWindowFrameBorder);
}
g_win32Helper()->options.insert(window, options);
const WId winId = window->winId(); const WId winId = window->winId();
g_win32Helper()->windowMapping.insert(winId, window); g_win32Helper()->windowMapping.insert(winId, window);
if (g_win32Helper()->nativeEventFilter.isNull()) { if (g_win32Helper()->nativeEventFilter.isNull()) {
@ -77,13 +83,15 @@ void FramelessHelperWin::addWindow(QWindow *window)
qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.data()); qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.data());
} }
g_win32Helper()->mutex.unlock(); g_win32Helper()->mutex.unlock();
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag)); if (!(options & Option::DontTouchQtInternals)) {
if (!(options & Option::DontModifyQtInternals)) {
Utils::fixupQtInternals(winId); Utils::fixupQtInternals(winId);
} }
if (!(options & Option::DontTweakDpiAwarenessLevel)) {
Utils::tryToEnableHighestDpiAwarenessLevel(winId);
}
Utils::updateInternalWindowFrameMargins(window, true); Utils::updateInternalWindowFrameMargins(window, true);
Utils::updateWindowFrameMargins(winId, false); Utils::updateWindowFrameMargins(winId, false);
if (!(options & Option::DontModifyWindowFrameBorderColor)) { if (!(options & Option::DontTouchWindowFrameBorderColor)) {
const bool dark = Utils::shouldAppsUseDarkMode(); const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(winId, dark); Utils::updateWindowFrameBorderColor(winId, dark);
} }
@ -96,11 +104,11 @@ void FramelessHelperWin::removeWindow(QWindow *window)
return; return;
} }
g_win32Helper()->mutex.lock(); g_win32Helper()->mutex.lock();
if (!g_win32Helper()->framelessWindows.contains(window)) { if (!g_win32Helper()->options.contains(window)) {
g_win32Helper()->mutex.unlock(); g_win32Helper()->mutex.unlock();
return; return;
} }
g_win32Helper()->framelessWindows.removeAll(window); g_win32Helper()->options.remove(window);
const WId winId = window->winId(); const WId winId = window->winId();
g_win32Helper()->windowMapping.remove(winId); g_win32Helper()->windowMapping.remove(winId);
g_win32Helper()->mutex.unlock(); g_win32Helper()->mutex.unlock();
@ -135,18 +143,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return false; return false;
} }
QWindow * const window = g_win32Helper()->windowMapping.value(winId); QWindow * const window = g_win32Helper()->windowMapping.value(winId);
g_win32Helper()->mutex.unlock();
Q_ASSERT(window); Q_ASSERT(window);
if (!window) { if (!window) {
g_win32Helper()->mutex.unlock();
return false; return false;
} }
auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag)); const Options options = g_win32Helper()->options.value(window);
if ((options & Option::ForceHideWindowFrameBorder) && (options & Option::ForceShowWindowFrameBorder)) { g_win32Helper()->mutex.unlock();
qWarning() << "You can't use both \"Option::ForceHideWindowFrameBorder\" and "
"\"Option::ForceShowWindowFrameBorder\" at the same time.";
options &= ~(Option::ForceHideWindowFrameBorder | Option::ForceShowWindowFrameBorder);
window->setProperty(kInternalOptionsFlag, QVariant::fromValue(options));
}
const bool frameBorderVisible = [options]() -> bool { const bool frameBorderVisible = [options]() -> bool {
if (options & Option::ForceShowWindowFrameBorder) { if (options & Option::ForceShowWindowFrameBorder) {
return true; return true;
@ -473,7 +476,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// another branch, if you are interested in it, you can give it a // another branch, if you are interested in it, you can give it a
// try. // try.
if (Utils::isWindowFixedSize(window)) { if (Utils::isWindowFixedSize(window) || (options & Option::DisableResizing)) {
*result = HTCLIENT; *result = HTCLIENT;
return true; return true;
} }
@ -487,7 +490,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const bool full = Utils::isFullScreen(winId); const bool full = Utils::isFullScreen(winId);
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true); const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
const bool isTop = (localPos.y < frameSizeY); const bool isTop = (localPos.y < frameSizeY);
static constexpr const bool isTitleBar = false; const bool isTitleBar = (false || (options & Option::DisableDragging));
if (frameBorderVisible) { if (frameBorderVisible) {
// This will handle the left, right and bottom parts of the frame // This will handle the left, right and bottom parts of the frame
// because we didn't change them. // because we didn't change them.
@ -687,7 +690,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return false; return false;
}(); }();
if (themeSettingChanged) { if (themeSettingChanged) {
if (!(options & Option::DontModifyWindowFrameBorderColor)) { if (!(options & Option::DontTouchWindowFrameBorderColor)) {
const bool dark = Utils::shouldAppsUseDarkMode(); const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(winId, dark); Utils::updateWindowFrameBorderColor(winId, dark);
} }

View File

@ -109,6 +109,9 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
[[maybe_unused]] static constexpr const QSize kDefaultSystemButtonIconSize = {16, 16}; [[maybe_unused]] static constexpr const QSize kDefaultSystemButtonIconSize = {16, 16};
[[maybe_unused]] static constexpr const char kInternalOptionsFlag[] = "FRAMELESSHELPER_INTERNAL_OPTIONS"; [[maybe_unused]] static constexpr const char kInternalOptionsFlag[] = "FRAMELESSHELPER_INTERNAL_OPTIONS";
[[maybe_unused]] static constexpr const char kUsePureQtImplFlag[] = "FRAMELESSHELPER_PURE_QT_IMPLEMENTATION";
[[maybe_unused]] static constexpr const char kForceHideFrameBorderFlag[] = "FRAMELESSHELPER_FORCE_HIDE_FRAME_BORDER";
[[maybe_unused]] static constexpr const char kForceShowFrameBorderFlag[] = "FRAMELESSHELPER_FORCE_SHOW_FRAME_BORDER";
enum class Option : int enum class Option : int
{ {
@ -121,16 +124,18 @@ enum class Option : int
MaximizeButtonDocking = 0x00000020, // Windows only, enable the window docking feature introduced in Windows 11. MaximizeButtonDocking = 0x00000020, // Windows only, enable the window docking feature introduced in Windows 11.
UseStandardWindowLayout = 0x00000040, // The standard window layout is a titlebar always on top and fill the window width. UseStandardWindowLayout = 0x00000040, // The standard window layout is a titlebar always on top and fill the window width.
BeCompatibleWithQtFramelessWindowHint = 0x00000080, // Windows only, make the code compatible with Qt::FramelessWindowHint. Don't use this option unless you really need that flag. BeCompatibleWithQtFramelessWindowHint = 0x00000080, // Windows only, make the code compatible with Qt::FramelessWindowHint. Don't use this option unless you really need that flag.
DontModifyQtInternals = 0x00000100, // Windows only, don't touch Qt's internal data. DontTouchQtInternals = 0x00000100, // Windows only, don't modify Qt's internal data.
DontModifyWindowFrameBorderColor = 0x00000200, // Windows only, don't touch the window frame border color. DontTouchWindowFrameBorderColor = 0x00000200, // Windows only, don't change the window frame border color.
DontInstallSystemMenuHook = 0x00000400, // Windows only, don't install the system menu hook. DontInstallSystemMenuHook = 0x00000400, // Windows only, don't install the system menu hook.
DisableSystemMenu = 0x00000800, // Windows only, don't open the system menu when right clicks the titlebar. DisableSystemMenu = 0x00000800, // Windows only, don't open the system menu when right clicks the titlebar.
NoDoubleClickMaximizeToggle = 0x00001000 // Don't toggle the maximize state when double clicks the titlebar. NoDoubleClickMaximizeToggle = 0x00001000, // Don't toggle the maximize state when double clicks the titlebar.
DisableResizing = 0x00002000, // Disable resizing of the window.
DisableDragging = 0x00004000, // Disable dragging through the titlebar of the window.
DontTouchCursorShape = 0x00008000, // Don't change the cursor shape while the mouse is hovering above the window.
DontTweakDpiAwarenessLevel = 0x00010000 // Windows only, don't tweak the DPI awareness level of the window / process.
}; };
Q_FLAG_NS(Option)
Q_DECLARE_FLAGS(Options, Option) Q_DECLARE_FLAGS(Options, Option)
Q_FLAG_NS(Options)
Q_DECLARE_OPERATORS_FOR_FLAGS(Options) Q_DECLARE_OPERATORS_FOR_FLAGS(Options)
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Options))

View File

@ -59,7 +59,7 @@ FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(FramelessWin
bool FramelessWindowsManagerPrivate::usePureQtImplementation() const bool FramelessWindowsManagerPrivate::usePureQtImplementation() const
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
static const bool result = (qEnvironmentVariableIntValue("FRAMELESSHELPER_PURE_QT_IMPL") != 0); static const bool result = (qEnvironmentVariableIntValue(kUsePureQtImplFlag) != 0);
#else #else
static constexpr const bool result = true; static constexpr const bool result = true;
#endif #endif

View File

@ -52,7 +52,6 @@ public:
Q_SIGNALS: Q_SIGNALS:
void systemThemeChanged(); void systemThemeChanged();
void systemMenuRequested(const QPointF &);
private: private:
QScopedPointer<FramelessWindowsManagerPrivate> d_ptr; QScopedPointer<FramelessWindowsManagerPrivate> d_ptr;

View File

@ -39,7 +39,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
static const QString kImageResourcePrefix = QStringLiteral(":/org.wangwenx190.FramelessHelper/images"); static const QString kImageResourcePrefix = QStringLiteral(":/org.wangwenx190.FramelessHelper/images");
Qt::CursorShape Utils::calculateCursorShape(const QWindow *window, const QPointF &pos) Qt::CursorShape Utils::calculateCursorShape(const QWindow *window, const QPoint &pos)
{ {
Q_ASSERT(window); Q_ASSERT(window);
if (!window) { if (!window) {
@ -65,7 +65,7 @@ Qt::CursorShape Utils::calculateCursorShape(const QWindow *window, const QPointF
return Qt::ArrowCursor; return Qt::ArrowCursor;
} }
Qt::Edges Utils::calculateWindowEdges(const QWindow *window, const QPointF &pos) Qt::Edges Utils::calculateWindowEdges(const QWindow *window, const QPoint &pos)
{ {
Q_ASSERT(window); Q_ASSERT(window);
if (!window) { if (!window) {

View File

@ -70,8 +70,8 @@ Q_ENUM_NS(DwmColorizationArea)
namespace Utils namespace Utils
{ {
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::CursorShape calculateCursorShape(const QWindow *window, const QPointF &pos); [[nodiscard]] FRAMELESSHELPER_CORE_API Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window, const QPointF &pos); [[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos);
FRAMELESSHELPER_CORE_API void startSystemMove(QWindow *window); FRAMELESSHELPER_CORE_API void startSystemMove(QWindow *window);
FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges edges); FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges edges);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFixedSize(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFixedSize(const QWindow *window);
@ -93,7 +93,7 @@ FRAMELESSHELPER_CORE_API void updateInternalWindowFrameMargins(QWindow *window,
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId winId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId winId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId winId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId winId);
FRAMELESSHELPER_CORE_API void syncWmPaintWithDwm(); FRAMELESSHELPER_CORE_API void syncWmPaintWithDwm();
FRAMELESSHELPER_CORE_API void showSystemMenu(const WId winId, const QPointF &pos); FRAMELESSHELPER_CORE_API void showSystemMenu(const WId winId, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor(); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode();
[[nodiscard]] FRAMELESSHELPER_CORE_API DwmColorizationArea getDwmColorizationArea(); [[nodiscard]] FRAMELESSHELPER_CORE_API DwmColorizationArea getDwmColorizationArea();
@ -113,6 +113,7 @@ FRAMELESSHELPER_CORE_API void fixupQtInternals(const WId winId);
FRAMELESSHELPER_CORE_API void installSystemMenuHook(const WId winId); FRAMELESSHELPER_CORE_API void installSystemMenuHook(const WId winId);
FRAMELESSHELPER_CORE_API void uninstallSystemMenuHook(const WId winId); FRAMELESSHELPER_CORE_API void uninstallSystemMenuHook(const WId winId);
FRAMELESSHELPER_CORE_API void tryToBeCompatibleWithQtFramelessWindowHint(QWindow *window, const bool enable); FRAMELESSHELPER_CORE_API void tryToBeCompatibleWithQtFramelessWindowHint(QWindow *window, const bool enable);
FRAMELESSHELPER_CORE_API void tryToEnableHighestDpiAwarenessLevel(const WId winId);
#endif // Q_OS_WINDOWS #endif // Q_OS_WINDOWS
} // namespace Utils } // namespace Utils

View File

@ -182,10 +182,10 @@ static const QString successErrorText = QStringLiteral("The operation completed
} }
g_utilsHelper()->mutex.unlock(); g_utilsHelper()->mutex.unlock();
const auto winId = reinterpret_cast<WId>(hWnd); const auto winId = reinterpret_cast<WId>(hWnd);
const auto getGlobalPosFromMouse = [lParam]() -> QPointF { const auto getGlobalPosFromMouse = [lParam]() -> QPoint {
return {qreal(GET_X_LPARAM(lParam)), qreal(GET_Y_LPARAM(lParam))}; return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
}; };
const auto getGlobalPosFromKeyboard = [hWnd, winId]() -> QPointF { const auto getGlobalPosFromKeyboard = [hWnd, winId]() -> QPoint {
RECT windowPos = {}; RECT windowPos = {};
if (GetWindowRect(hWnd, &windowPos) == FALSE) { if (GetWindowRect(hWnd, &windowPos) == FALSE) {
qWarning() << Utils::getSystemErrorMessage(QStringLiteral("GetWindowRect")); qWarning() << Utils::getSystemErrorMessage(QStringLiteral("GetWindowRect"));
@ -212,10 +212,10 @@ static const QString successErrorText = QStringLiteral("The operation completed
} }
return (titleBarHeight - frameSizeY); return (titleBarHeight - frameSizeY);
}(); }();
return {qreal(windowPos.left + horizontalOffset), qreal(windowPos.top + verticalOffset)}; return {windowPos.left + horizontalOffset, windowPos.top + verticalOffset};
}; };
bool shouldShowSystemMenu = false; bool shouldShowSystemMenu = false;
QPointF globalPos = {}; QPoint globalPos = {};
if (uMsg == WM_NCRBUTTONUP) { if (uMsg == WM_NCRBUTTONUP) {
if (wParam == HTCAPTION) { if (wParam == HTCAPTION) {
shouldShowSystemMenu = true; shouldShowSystemMenu = true;
@ -486,7 +486,7 @@ DwmColorizationArea Utils::getDwmColorizationArea()
return DwmColorizationArea::None; return DwmColorizationArea::None;
} }
void Utils::showSystemMenu(const WId winId, const QPointF &pos) void Utils::showSystemMenu(const WId winId, const QPoint &pos)
{ {
Q_ASSERT(winId); Q_ASSERT(winId);
if (!winId) { if (!winId) {
@ -535,9 +535,8 @@ void Utils::showSystemMenu(const WId winId, const QPointF &pos)
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuDefaultItem")); qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuDefaultItem"));
return; return;
} }
const QPoint roundedPos = pos.toPoint();
const int ret = TrackPopupMenu(menu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() const int ret = TrackPopupMenu(menu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft()
? TPM_RIGHTALIGN : TPM_LEFTALIGN)), roundedPos.x(), roundedPos.y(), 0, hWnd, nullptr); ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), pos.x(), pos.y(), 0, hWnd, nullptr);
if (ret != 0) { if (ret != 0) {
if (PostMessageW(hWnd, WM_SYSCOMMAND, ret, 0) == FALSE) { if (PostMessageW(hWnd, WM_SYSCOMMAND, ret, 0) == FALSE) {
qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW")); qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW"));
@ -663,7 +662,7 @@ void Utils::syncWmPaintWithDwm()
m = dt - (period * w); m = dt - (period * w);
Q_ASSERT(m >= 0); Q_ASSERT(m >= 0);
Q_ASSERT(m < period); Q_ASSERT(m < period);
const qreal m_ms = 1000.0 * static_cast<qreal>(m) / static_cast<qreal>(freq.QuadPart); const qreal m_ms = (1000.0 * qreal(m) / qreal(freq.QuadPart));
Sleep(static_cast<DWORD>(qRound(m_ms))); Sleep(static_cast<DWORD>(qRound(m_ms)));
if (ptimeEndPeriod(ms_granularity) != TIMERR_NOERROR) { if (ptimeEndPeriod(ms_granularity) != TIMERR_NOERROR) {
qWarning() << "timeEndPeriod() failed."; qWarning() << "timeEndPeriod() failed.";
@ -973,10 +972,10 @@ bool Utils::isWindowFrameBorderVisible()
// the window will look rather ugly and I guess no one would like to see // the window will look rather ugly and I guess no one would like to see
// such weired windows. But for the ones who really want to see what the // such weired windows. But for the ones who really want to see what the
// window look like, I still provide a way to enter such scenarios. // window look like, I still provide a way to enter such scenarios.
if (qEnvironmentVariableIntValue("FRAMELESSHELPER_FORCE_SHOW_FRAME_BORDER") != 0) { if (qEnvironmentVariableIntValue(kForceShowFrameBorderFlag) != 0) {
return true; return true;
} }
return (isWin10OrGreater() && !qEnvironmentVariableIsSet("FRAMELESSHELPER_HIDE_FRAME_BORDER")); return (isWin10OrGreater() && !qEnvironmentVariableIsSet(kForceHideFrameBorderFlag));
}(); }();
return result; return result;
} }
@ -1081,4 +1080,12 @@ void Utils::tryToBeCompatibleWithQtFramelessWindowHint(QWindow *window, const bo
triggerFrameChange(winId); triggerFrameChange(winId);
} }
void Utils::tryToEnableHighestDpiAwarenessLevel(const WId winId)
{
Q_ASSERT(winId);
if (!winId) {
return;
}
}
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -38,6 +38,7 @@ struct EventFilterDataInternal
FramelessQuickEventFilter *eventFilter = nullptr; FramelessQuickEventFilter *eventFilter = nullptr;
QQuickItem *titleBarItem = nullptr; QQuickItem *titleBarItem = nullptr;
QList<QQuickItem *> hitTestVisibleItems = {}; QList<QQuickItem *> hitTestVisibleItems = {};
Options options = {};
}; };
struct EventFilterData struct EventFilterData
@ -54,7 +55,7 @@ private:
Q_GLOBAL_STATIC(EventFilterData, g_data) Q_GLOBAL_STATIC(EventFilterData, g_data)
[[nodiscard]] static inline bool isInTitleBarDraggableArea(QQuickWindow *window, const QPointF &pos) [[nodiscard]] static inline bool isInTitleBarDraggableArea(QQuickWindow *window, const QPoint &pos)
{ {
Q_ASSERT(window); Q_ASSERT(window);
if (!window) { if (!window) {
@ -70,23 +71,23 @@ Q_GLOBAL_STATIC(EventFilterData, g_data)
if (!data.titleBarItem) { if (!data.titleBarItem) {
return false; return false;
} }
const auto mapGeometryToScene = [](const QQuickItem * const item) -> QRectF { const auto mapGeometryToScene = [](const QQuickItem * const item) -> QRect {
Q_ASSERT(item); Q_ASSERT(item);
if (!item) { if (!item) {
return {}; return {};
} }
return QRectF(item->mapToScene(QPointF(0.0, 0.0)), item->size()); return QRect(item->mapToScene(QPointF(0.0, 0.0)).toPoint(), item->size().toSize());
}; };
QRegion region = mapGeometryToScene(data.titleBarItem).toRect(); QRegion region = mapGeometryToScene(data.titleBarItem);
if (!data.hitTestVisibleItems.isEmpty()) { if (!data.hitTestVisibleItems.isEmpty()) {
for (auto &&item : qAsConst(data.hitTestVisibleItems)) { for (auto &&item : qAsConst(data.hitTestVisibleItems)) {
Q_ASSERT(item); Q_ASSERT(item);
if (item) { if (item) {
region -= mapGeometryToScene(item).toRect(); region -= mapGeometryToScene(item);
} }
} }
} }
return region.contains(pos.toPoint()); return region.contains(pos);
} }
FramelessQuickEventFilter::FramelessQuickEventFilter(QObject *parent) : QObject(parent) {} FramelessQuickEventFilter::FramelessQuickEventFilter(QObject *parent) : QObject(parent) {}
@ -106,6 +107,8 @@ void FramelessQuickEventFilter::addWindow(QQuickWindow *window)
} }
auto data = EventFilterDataInternal{}; auto data = EventFilterDataInternal{};
data.window = window; data.window = window;
data.options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
// Give it a parent so that it can be deleted even if we forget to do so.
data.eventFilter = new FramelessQuickEventFilter(window); data.eventFilter = new FramelessQuickEventFilter(window);
g_data()->data.insert(window, data); g_data()->data.insert(window, data);
g_data()->mutex.unlock(); g_data()->mutex.unlock();
@ -184,6 +187,7 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
g_data()->mutex.unlock(); g_data()->mutex.unlock();
return false; return false;
} }
const Options options = g_data()->data.value(window).options;
g_data()->mutex.unlock(); g_data()->mutex.unlock();
const QEvent::Type eventType = event->type(); const QEvent::Type eventType = event->type();
if ((eventType != QEvent::MouseButtonPress) if ((eventType != QEvent::MouseButtonPress)
@ -196,9 +200,9 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return false; return false;
} }
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPointF scenePos = mouseEvent->scenePosition(); const QPoint scenePos = mouseEvent->scenePosition().toPoint();
#else #else
const QPointF scenePos = mouseEvent->windowPos(); const QPoint scenePos = mouseEvent->windowPos().toPoint();
#endif #endif
const QQuickWindow::Visibility visibility = window->visibility(); const QQuickWindow::Visibility visibility = window->visibility();
if ((visibility == QQuickWindow::Windowed) if ((visibility == QQuickWindow::Windowed)
@ -208,9 +212,11 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return false; return false;
} }
const bool titleBar = isInTitleBarDraggableArea(window, scenePos); const bool titleBar = isInTitleBarDraggableArea(window, scenePos);
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
switch (eventType) { switch (eventType) {
case QEvent::MouseButtonPress: { case QEvent::MouseButtonPress: {
if (options & Option::DisableDragging) {
return false;
}
if (button != Qt::LeftButton) { if (button != Qt::LeftButton) {
return false; return false;
} }
@ -231,11 +237,11 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return false; return false;
} }
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPointF globalPos = mouseEvent->globalPosition(); const QPoint globalPos = mouseEvent->globalPosition().toPoint();
#else #else
const QPointF globalPos = mouseEvent->globalPos(); const QPoint globalPos = mouseEvent->globalPos().toPoint();
#endif #endif
const QPointF nativePos = QPointF(globalPos * window->effectiveDevicePixelRatio()); const QPoint nativePos = QPointF(QPointF(globalPos) * window->effectiveDevicePixelRatio()).toPoint();
Utils::showSystemMenu(window->winId(), nativePos); Utils::showSystemMenu(window->winId(), nativePos);
return true; return true;
} }

View File

@ -137,7 +137,7 @@ void FramelessQuickUtils::showMinimized2(QQuickWindow *window)
#endif #endif
} }
void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPointF &pos) void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPoint &pos)
{ {
Q_ASSERT(window); Q_ASSERT(window);
if (!window) { if (!window) {
@ -145,11 +145,11 @@ void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPointF &po
} }
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) # if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPointF globalPos = window->mapToGlobal(pos); const QPoint globalPos = window->mapToGlobal(pos);
# else # else
const QPointF globalPos = window->mapToGlobal(pos.toPoint()); const QPoint globalPos = window->mapToGlobal(pos.toPoint());
# endif # endif
const QPointF nativePos = QPointF(globalPos * window->effectiveDevicePixelRatio()); const QPoint nativePos = QPointF(QPointF(globalPos) * window->effectiveDevicePixelRatio()).toPoint();
Utils::showSystemMenu(window->winId(), nativePos); Utils::showSystemMenu(window->winId(), nativePos);
#endif #endif
} }

View File

@ -67,7 +67,7 @@ public:
Q_NODISCARD static bool titleBarColorVisible(); Q_NODISCARD static bool titleBarColorVisible();
Q_INVOKABLE static void showMinimized2(QQuickWindow *window); Q_INVOKABLE static void showMinimized2(QQuickWindow *window);
Q_INVOKABLE static void showSystemMenu(QQuickWindow *window, const QPointF &pos); Q_INVOKABLE static void showSystemMenu(QQuickWindow *window, const QPoint &pos);
Q_INVOKABLE static void startSystemMove2(QQuickWindow *window); Q_INVOKABLE static void startSystemMove2(QQuickWindow *window);
Q_INVOKABLE static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges); Q_INVOKABLE static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges);

View File

@ -61,7 +61,6 @@ protected:
Q_SIGNALS: Q_SIGNALS:
void titleBarWidgetChanged(); void titleBarWidgetChanged();
void systemThemeChanged(); void systemThemeChanged();
void systemMenuRequested(const QPointF &);
private: private:
QScopedPointer<FramelessWidgetsHelper> m_helper; QScopedPointer<FramelessWidgetsHelper> m_helper;

View File

@ -66,7 +66,6 @@ Q_SIGNALS:
void titleBarWidgetChanged(); void titleBarWidgetChanged();
void contentWidgetChanged(); void contentWidgetChanged();
void systemThemeChanged(); void systemThemeChanged();
void systemMenuRequested(const QPointF &);
private: private:
QScopedPointer<FramelessWidgetsHelper> m_helper; QScopedPointer<FramelessWidgetsHelper> m_helper;

View File

@ -198,6 +198,9 @@ void FramelessWidgetsHelper::mousePressEventHandler(QMouseEvent *event)
if (!event) { if (!event) {
return; return;
} }
if (m_options & Option::DisableDragging) {
return;
}
if (event->button() != Qt::LeftButton) { if (event->button() != Qt::LeftButton) {
return; return;
} }
@ -240,11 +243,11 @@ void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
} }
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) # if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPointF globalPos = event->globalPosition(); const QPoint globalPos = event->globalPosition().toPoint();
# else # else
const QPointF globalPos = event->globalPos(); const QPoint globalPos = event->globalPos().toPoint();
# endif # endif
const QPointF nativePos = QPointF(globalPos * q->devicePixelRatioF()); const QPoint nativePos = QPointF(QPointF(globalPos) * q->devicePixelRatioF()).toPoint();
Utils::showSystemMenu(q->winId(), nativePos); Utils::showSystemMenu(q->winId(), nativePos);
#endif #endif
} }
@ -316,9 +319,6 @@ void FramelessWidgetsHelper::initialize()
} }
QMetaObject::invokeMethod(q, "systemThemeChanged"); QMetaObject::invokeMethod(q, "systemThemeChanged");
}); });
connect(manager, &FramelessWindowsManager::systemMenuRequested, this, [this](const QPointF &pos){
QMetaObject::invokeMethod(q, "systemMenuRequested", Q_ARG(QPointF, pos));
});
setupInitialUi(); setupInitialUi();
} }