add the Options feature to control some details

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-03-20 15:51:05 +08:00
parent 09acbfaf02
commit 12988f2ddf
15 changed files with 170 additions and 94 deletions

View File

@ -29,7 +29,7 @@
FRAMELESSHELPER_USE_NAMESPACE
MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : FramelessMainWindow(parent, flags)
MainWindow::MainWindow(QWidget *parent, const Qt::WindowFlags flags) : FramelessMainWindow(parent, flags)
{
setupUi();
}

View File

@ -38,7 +38,7 @@ class MainWindow : public FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessMainWindow)
Q_DISABLE_COPY_MOVE(MainWindow)
public:
explicit MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {});
explicit MainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {});
~MainWindow() override;
protected:

View File

@ -30,7 +30,7 @@
FRAMELESSHELPER_USE_NAMESPACE
Widget::Widget(QWidget *parent) : FramelessWidget(parent, WindowLayout::Standard)
Widget::Widget(QWidget *parent) : FramelessWidget(parent, {Option::UseStandardWindowLayout})
{
setupUi();
startTimer(500);

View File

@ -26,6 +26,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
#include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/qwindow.h>
#include "framelesswindowsmanager.h"
@ -76,11 +77,16 @@ void FramelessHelperWin::addWindow(QWindow *window)
qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.data());
}
g_win32Helper()->mutex.unlock();
Utils::fixupQtInternals(winId);
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if (!(options & Option::DontModifyQtInternals)) {
Utils::fixupQtInternals(winId);
}
Utils::updateInternalWindowFrameMargins(window, true);
Utils::updateWindowFrameMargins(winId, false);
const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(winId, dark);
if (!(options & Option::DontModifyWindowFrameBorderColor)) {
const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(winId, dark);
}
}
void FramelessHelperWin::removeWindow(QWindow *window)
@ -119,7 +125,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
#endif
if (!msg->hwnd) {
// Why sometimes the window handle is null? Is it designed to be like this?
// Anyway, we should skip the entire function in this case.
// Anyway, we should skip the entire processing in this case.
return false;
}
const WId winId = reinterpret_cast<WId>(msg->hwnd);
@ -134,6 +140,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (!window) {
return false;
}
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);
window->setProperty(kInternalOptionsFlag, QVariant::fromValue(options));
}
const bool frameBorderVisible = [options]() -> bool {
if (options & Option::ForceShowWindowFrameBorder) {
return true;
}
if (options & Option::ForceHideWindowFrameBorder) {
return false;
}
return Utils::isWindowFrameBorderVisible();
}();
switch (msg->message) {
case WM_NCCALCSIZE: {
// Windows是根据这个消息的返回值来设置窗口的客户区窗口中真正显示的内容
@ -226,7 +248,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const auto clientRect = ((static_cast<BOOL>(msg->wParam) == FALSE)
? reinterpret_cast<LPRECT>(msg->lParam)
: &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam))->rgrc[0]);
if (Utils::isWindowFrameBorderVisible()) {
if (frameBorderVisible) {
// Store the original top before the default window proc applies the default frame.
const LONG originalTop = clientRect->top;
// Apply the default frame.
@ -252,7 +274,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// a window when it's maximized unless you restore it).
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
clientRect->top += frameSizeY;
if (!Utils::isWindowFrameBorderVisible()) {
if (!frameBorderVisible) {
clientRect->bottom -= frameSizeY;
const int frameSizeX = Utils::getResizeBorderThickness(winId, true, true);
clientRect->left += frameSizeX;
@ -466,7 +488,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const int frameSizeY = Utils::getResizeBorderThickness(winId, false, true);
const bool isTop = (localPos.y < frameSizeY);
static constexpr const bool isTitleBar = false;
if (Utils::isWindowFrameBorderVisible()) {
if (frameBorderVisible) {
// This will handle the left, right and bottom parts of the frame
// because we didn't change them.
const LRESULT originalRet = DefWindowProcW(msg->hwnd, WM_NCHITTEST, 0, msg->lParam);
@ -579,7 +601,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
default:
break;
}
if (!Utils::isWindowFrameBorderVisible()) {
if (!frameBorderVisible) {
switch (msg->message) {
case WM_NCUAHDRAWCAPTION:
case WM_NCUAHDRAWFRAME: {
@ -665,8 +687,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return false;
}();
if (themeSettingChanged) {
const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(winId, dark);
if (!(options & Option::DontModifyWindowFrameBorderColor)) {
const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(winId, dark);
}
}
if (themeSettingChanged || (msg->message == WM_THEMECHANGED)
|| (msg->message == WM_DWMCOLORIZATIONCOLORCHANGED)) {

View File

@ -108,11 +108,29 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
[[maybe_unused]] static constexpr const QSize kDefaultSystemButtonSize = {int(qRound(qreal(kDefaultTitleBarHeight) * 1.5)), kDefaultTitleBarHeight};
[[maybe_unused]] static constexpr const QSize kDefaultSystemButtonIconSize = {16, 16};
enum class WindowLayout : int
[[maybe_unused]] static constexpr const char kInternalOptionsFlag[] = "FRAMELESSHELPER_INTERNAL_OPTIONS";
enum class Option : int
{
Standard = 0,
Custom = 1
Default = 0x00000000, // Default placeholder, have no effect.
ForceHideWindowFrameBorder = 0x00000001, // Windows only, force hide the window frame border even on Windows 10 and onwards.
ForceShowWindowFrameBorder = 0x00000002, // Windows only, force show the window frame border even on Windows 7 (~ 8.1).
DontDrawTopWindowFrameBorder = 0x00000004, // Windows only, don't draw the top window frame border even if the window frame border is visible.
EnableRoundedWindowCorners = 0x00000008, // Not implemented yet.
TransparentWindowBackground = 0x00000010, // Not implemented yet.
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.
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.
DontModifyWindowFrameBorderColor = 0x00000200, // Windows only, don't touch the window frame border color.
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.
NoDoubleClickMaximizeToggle = 0x00001000 // Don't toggle the maximize state when double clicks the titlebar.
};
Q_ENUM_NS(WindowLayout)
Q_FLAG_NS(Option)
Q_DECLARE_FLAGS(Options, Option)
Q_DECLARE_OPERATORS_FOR_FLAGS(Options)
FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Options))

View File

@ -24,6 +24,7 @@
#include "framelesswindowsmanager.h"
#include "framelesswindowsmanager_p.h"
#include <QtCore/qvariant.h>
#include <QtGui/qscreen.h>
#include <QtGui/qwindow.h>
#include "framelesshelper_qt.h"
@ -182,7 +183,10 @@ void FramelessWindowsManager::addWindow(QWindow *window)
if (!pureQt) {
FramelessHelperWin::addWindow(window);
}
Utils::installSystemMenuHook(winId);
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if (!(options & Option::DontInstallSystemMenuHook)) {
Utils::installSystemMenuHook(winId);
}
#endif
}
@ -208,7 +212,10 @@ void FramelessWindowsManager::removeWindow(QWindow *window)
disconnect(d->win32WorkaroundConnections.value(uuid));
d->win32WorkaroundConnections.remove(uuid);
}
Utils::uninstallSystemMenuHook(winId);
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if (!(options & Option::DontInstallSystemMenuHook)) {
Utils::uninstallSystemMenuHook(winId);
}
#endif
static const bool pureQt = d->usePureQtImplementation();
if (pureQt) {

View File

@ -77,6 +77,7 @@ FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFixedSize(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API QVariant getSystemButtonIconResource
(const SystemButtonType button, const SystemTheme theme, const ResourceType type);
FRAMELESSHELPER_CORE_API void sendMouseReleaseEvent();
#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin8OrGreater();
@ -111,6 +112,7 @@ FRAMELESSHELPER_CORE_API void fixupQtInternals(const WId winId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized();
FRAMELESSHELPER_CORE_API void installSystemMenuHook(const WId winId);
FRAMELESSHELPER_CORE_API void uninstallSystemMenuHook(const WId winId);
FRAMELESSHELPER_CORE_API void tryToBeCompatibleWithQtFramelessWindowHint(QWindow *window, const bool enable);
#endif // Q_OS_WINDOWS
} // namespace Utils

View File

@ -913,7 +913,9 @@ void Utils::fixupQtInternals(const WId winId)
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast<LONG_PTR>(newWindowStyle)) == 0) {
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
return;
}
triggerFrameChange(winId);
}
void Utils::startSystemMove(QWindow *window)
@ -925,10 +927,7 @@ void Utils::startSystemMove(QWindow *window)
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
window->startSystemMove();
#else
if (ReleaseCapture() == FALSE) {
qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture"));
return;
}
sendMouseReleaseEvent();
const auto hwnd = reinterpret_cast<HWND>(window->winId());
if (PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) {
qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW"));
@ -948,10 +947,7 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges)
if (edges == Qt::Edges{}) {
return;
}
if (ReleaseCapture() == FALSE) {
qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture"));
return;
}
sendMouseReleaseEvent();
const auto hwnd = reinterpret_cast<HWND>(window->winId());
if (PostMessageW(hwnd, WM_SYSCOMMAND, qtEdgesToWin32Orientation(edges), 0) == FALSE) {
qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW"));
@ -1024,6 +1020,7 @@ void Utils::installSystemMenuHook(const WId winId)
return;
}
g_utilsHelper()->qtWindowProcs.insert(hwnd, originalWindowProc);
//triggerFrameChange(winId);
}
void Utils::uninstallSystemMenuHook(const WId winId)
@ -1048,6 +1045,40 @@ void Utils::uninstallSystemMenuHook(const WId winId)
return;
}
g_utilsHelper()->qtWindowProcs.remove(hwnd);
//triggerFrameChange(winId);
}
void Utils::sendMouseReleaseEvent()
{
if (ReleaseCapture() == FALSE) {
qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture"));
}
}
void Utils::tryToBeCompatibleWithQtFramelessWindowHint(QWindow *window, const bool enable)
{
Q_ASSERT(window);
if (!window) {
return;
}
const WId winId = window->winId();
const auto hwnd = reinterpret_cast<HWND>(winId);
SetLastError(ERROR_SUCCESS);
const LONG_PTR originalWindowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
if (originalWindowStyle == 0) {
qWarning() << getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW"));
return;
}
const Qt::WindowFlags originalWindowFlags = window->flags();
const Qt::WindowFlags newWindowFlags = (enable ? (originalWindowFlags | Qt::FramelessWindowHint)
: (originalWindowFlags & ~Qt::FramelessWindowHint));
window->setFlags(newWindowFlags);
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(hwnd, GWL_STYLE, originalWindowStyle) == 0) {
qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"));
return;
}
triggerFrameChange(winId);
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -208,6 +208,7 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return false;
}
const bool titleBar = isInTitleBarDraggableArea(window, scenePos);
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
switch (eventType) {
case QEvent::MouseButtonPress: {
if (button != Qt::LeftButton) {
@ -220,6 +221,9 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return true;
}
case QEvent::MouseButtonRelease: {
if (options & Option::DisableSystemMenu) {
return false;
}
if (button != Qt::RightButton) {
return false;
}
@ -236,6 +240,9 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
return true;
}
case QEvent::MouseButtonDblClick: {
if (options & Option::NoDoubleClickMaximizeToggle) {
return false;
}
if (button != Qt::LeftButton) {
return false;
}

View File

@ -27,9 +27,9 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
FramelessMainWindow::FramelessMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags)
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags, const Options options) : QMainWindow(parent, flags)
{
m_helper.reset(new FramelessWidgetsHelper(this, WindowLayout::Custom));
m_helper.reset(new FramelessWidgetsHelper(this, options));
}
FramelessMainWindow::~FramelessMainWindow() = default;
@ -64,12 +64,6 @@ void FramelessMainWindow::toggleMaximized()
m_helper->toggleMaximized();
}
void FramelessMainWindow::showEvent(QShowEvent *event)
{
QMainWindow::showEvent(event);
m_helper->showEventHandler(event);
}
void FramelessMainWindow::changeEvent(QEvent *event)
{
QMainWindow::changeEvent(event);

View File

@ -38,7 +38,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
Q_PROPERTY(QWidget* titleBarWidget READ titleBarWidget WRITE setTitleBarWidget NOTIFY titleBarWidgetChanged FINAL)
public:
explicit FramelessMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {});
explicit FramelessMainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {}, const Options options = {});
~FramelessMainWindow() override;
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
@ -52,7 +52,6 @@ public:
Q_INVOKABLE void toggleMaximized();
protected:
void showEvent(QShowEvent *event) override;
void changeEvent(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;

View File

@ -27,9 +27,9 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
FramelessWidget::FramelessWidget(QWidget *parent, const WindowLayout wl) : QWidget(parent)
FramelessWidget::FramelessWidget(QWidget *parent, const Options options) : QWidget(parent)
{
m_helper.reset(new FramelessWidgetsHelper(this, wl));
m_helper.reset(new FramelessWidgetsHelper(this, options));
}
FramelessWidget::~FramelessWidget() = default;
@ -74,12 +74,6 @@ void FramelessWidget::toggleMaximized()
m_helper->toggleMaximized();
}
void FramelessWidget::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
m_helper->showEventHandler(event);
}
void FramelessWidget::changeEvent(QEvent *event)
{
QWidget::changeEvent(event);

View File

@ -39,7 +39,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget
Q_PROPERTY(QWidget* contentWidget READ contentWidget WRITE setContentWidget NOTIFY contentWidgetChanged FINAL)
public:
explicit FramelessWidget(QWidget *parent = nullptr, const WindowLayout wl = WindowLayout::Standard);
explicit FramelessWidget(QWidget *parent = nullptr, const Options options = {});
~FramelessWidget() override;
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
@ -56,7 +56,6 @@ public:
Q_INVOKABLE void toggleMaximized();
protected:
void showEvent(QShowEvent *event) override;
void changeEvent(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;

View File

@ -23,8 +23,10 @@
*/
#include "framelesswidgetshelper.h"
#include <QtCore/qdebug.h>
#include <QtGui/qpainter.h>
#include <QtGui/qevent.h>
#include <QtGui/qwindow.h>
#include <QtWidgets/qboxlayout.h>
#include <QtWidgets/qlabel.h>
#include <QtWidgets/qpushbutton.h>
@ -49,12 +51,12 @@ QPushButton:pressed {
}
)");
FramelessWidgetsHelper::FramelessWidgetsHelper(QWidget *q, const WindowLayout wl) : QObject(q)
FramelessWidgetsHelper::FramelessWidgetsHelper(QWidget *q, const Options options) : QObject(q)
{
Q_ASSERT(q);
if (q) {
this->q = q;
m_windowLayout = wl;
m_options = options;
initialize();
}
}
@ -80,7 +82,7 @@ void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
if (m_userTitleBarWidget == widget) {
return;
}
if (isStandardLayout()) {
if (m_options & Option::UseStandardWindowLayout) {
if (m_systemTitleBarWidget && m_systemTitleBarWidget->isVisible()) {
m_mainLayout->removeWidget(m_systemTitleBarWidget);
m_systemTitleBarWidget->hide();
@ -108,7 +110,7 @@ void FramelessWidgetsHelper::setContentWidget(QWidget *widget)
if (!widget) {
return;
}
if (isCustomLayout()) {
if (!(m_options & Option::UseStandardWindowLayout)) {
return;
}
if (m_userContentWidget == widget) {
@ -143,15 +145,6 @@ void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visib
}
}
void FramelessWidgetsHelper::showEventHandler(QShowEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
setupFramelessHelperOnce();
}
void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
{
Q_ASSERT(event);
@ -162,8 +155,9 @@ void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
if ((type != QEvent::WindowStateChange) && (type != QEvent::ActivationChange)) {
return;
}
const bool standardLayout = (m_options & Option::UseStandardWindowLayout);
if (type == QEvent::WindowStateChange) {
if (isStandardLayout()) {
if (standardLayout) {
if (isZoomed()) {
m_systemMaximizeButton->setToolTip(tr("Restore"));
} else {
@ -173,7 +167,7 @@ void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
}
updateContentsMargins();
}
if (isStandardLayout()) {
if (standardLayout) {
updateSystemTitleBarStyleSheet();
}
q->update();
@ -227,6 +221,9 @@ void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
if (!event) {
return;
}
if (m_options & Option::DisableSystemMenu) {
return;
}
if (event->button() != Qt::RightButton) {
return;
}
@ -258,6 +255,9 @@ void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event)
if (!event) {
return;
}
if (m_options & Option::NoDoubleClickMaximizeToggle) {
return;
}
if (event->button() != Qt::LeftButton) {
return;
}
@ -281,21 +281,35 @@ void FramelessWidgetsHelper::initialize()
return;
}
m_initialized = true;
// Without this flag, Qt will always create an invisible native parent window
// for any native widgets which will intercept some win32 messages and confuse
// our own native event filter, so to prevent some weired bugs from happening,
// just disable this feature.
q->setAttribute(Qt::WA_DontCreateNativeAncestors);
// Force the widget become a native window now so that we can deal with its
// win32 events as soon as possible.
q->createWinId();
setupInitialUi();
}
void FramelessWidgetsHelper::setupFramelessHelperOnce()
{
if (m_framelessHelperSetup) {
QWindow * const window = q->windowHandle();
Q_ASSERT(window);
if (!window) {
return;
}
m_framelessHelperSetup = true;
window->setProperty(kInternalOptionsFlag, QVariant::fromValue(m_options));
if (m_options & Option::UseStandardWindowLayout) {
if (q->inherits("QMainWindow")) {
m_options &= ~Options(Option::UseStandardWindowLayout);
qWarning() << "\"Option::UseStandardWindowLayout\" is not compatible with QMainWindow and it's subclasses."
" Enabling this option will mess up with your main window's layout.";
}
}
if (m_options & Option::BeCompatibleWithQtFramelessWindowHint) {
Utils::tryToBeCompatibleWithQtFramelessWindowHint(window, true);
Q_ASSERT(window->flags() & Qt::FramelessWindowHint);
}
FramelessWindowsManager *manager = FramelessWindowsManager::instance();
manager->addWindow(q->windowHandle());
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this](){
if (isStandardLayout()) {
if (m_options & Option::UseStandardWindowLayout) {
updateSystemTitleBarStyleSheet();
updateSystemButtonsIcon();
q->update();
@ -305,11 +319,12 @@ void FramelessWidgetsHelper::setupFramelessHelperOnce()
connect(manager, &FramelessWindowsManager::systemMenuRequested, this, [this](const QPointF &pos){
QMetaObject::invokeMethod(q, "systemMenuRequested", Q_ARG(QPointF, pos));
});
setupInitialUi();
}
void FramelessWidgetsHelper::createSystemTitleBar()
{
if (isCustomLayout()) {
if (!(m_options & Option::UseStandardWindowLayout)) {
return;
}
m_systemTitleBarWidget = new QWidget(q);
@ -352,7 +367,7 @@ void FramelessWidgetsHelper::createSystemTitleBar()
void FramelessWidgetsHelper::createUserContentContainer()
{
if (isCustomLayout()) {
if (!(m_options & Option::UseStandardWindowLayout)) {
return;
}
m_userContentContainerWidget = new QWidget(q);
@ -365,7 +380,7 @@ void FramelessWidgetsHelper::createUserContentContainer()
void FramelessWidgetsHelper::setupInitialUi()
{
if (isStandardLayout()) {
if (m_options & Option::UseStandardWindowLayout) {
createSystemTitleBar();
createUserContentContainer();
m_mainLayout = new QVBoxLayout(q);
@ -402,7 +417,7 @@ bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const
}
return region;
}
if (isStandardLayout()) {
if (m_options & Option::UseStandardWindowLayout) {
QRegion region = mapGeometryToScene(m_systemTitleBarWidget);
region -= mapGeometryToScene(m_systemMinimizeButton);
region -= mapGeometryToScene(m_systemMaximizeButton);
@ -417,22 +432,13 @@ bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const
bool FramelessWidgetsHelper::shouldDrawFrameBorder() const
{
#ifdef Q_OS_WINDOWS
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater() && isNormal());
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater()
&& isNormal() && !(m_options & Option::DontDrawTopWindowFrameBorder));
#else
return false;
#endif
}
bool FramelessWidgetsHelper::isStandardLayout() const
{
return (m_windowLayout == WindowLayout::Standard);
}
bool FramelessWidgetsHelper::isCustomLayout() const
{
return (m_windowLayout == WindowLayout::Custom);
}
bool FramelessWidgetsHelper::shouldIgnoreMouseEvents(const QPoint &pos) const
{
return (isNormal() && ((pos.x() < kDefaultResizeBorderThickness)
@ -449,7 +455,7 @@ void FramelessWidgetsHelper::updateContentsMargins()
void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
{
if (isCustomLayout()) {
if (!(m_options & Option::UseStandardWindowLayout)) {
return;
}
const bool active = q->isActiveWindow();
@ -484,7 +490,7 @@ void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
void FramelessWidgetsHelper::updateSystemButtonsIcon()
{
if (isCustomLayout()) {
if (!(m_options & Option::UseStandardWindowLayout)) {
return;
}
const SystemTheme theme = ((Utils::shouldAppsUseDarkMode() || Utils::isTitleBarColorized()) ? SystemTheme::Dark : SystemTheme::Light);

View File

@ -45,7 +45,7 @@ class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
Q_DISABLE_COPY_MOVE(FramelessWidgetsHelper)
public:
explicit FramelessWidgetsHelper(QWidget *q, const WindowLayout wl);
explicit FramelessWidgetsHelper(QWidget *q, const Options options = {});
~FramelessWidgetsHelper() override;
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
@ -61,7 +61,6 @@ public:
Q_INVOKABLE void toggleMaximized();
Q_INVOKABLE void showEventHandler(QShowEvent *event);
Q_INVOKABLE void changeEventHandler(QEvent *event);
Q_INVOKABLE void paintEventHandler(QPaintEvent *event);
Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event);
@ -70,14 +69,11 @@ public:
private:
void initialize();
void setupFramelessHelperOnce();
void createSystemTitleBar();
void createUserContentContainer();
void setupInitialUi();
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
Q_NODISCARD bool shouldDrawFrameBorder() const;
Q_NODISCARD bool isStandardLayout() const;
Q_NODISCARD bool isCustomLayout() const;
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
private Q_SLOTS:
@ -88,8 +84,7 @@ private Q_SLOTS:
private:
QWidget *q = nullptr;
bool m_initialized = false;
bool m_framelessHelperSetup = false;
WindowLayout m_windowLayout = WindowLayout::Standard;
Options m_options = {};
QWidget *m_systemTitleBarWidget = nullptr;
QLabel *m_systemWindowTitleLabel = nullptr;
QPushButton *m_systemMinimizeButton = nullptr;