quick module: minor improvements

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-04-22 15:49:00 +08:00
parent 201f54e7a5
commit 8460995d7f
6 changed files with 179 additions and 28 deletions

View File

@ -20,8 +20,13 @@ TODO
## Roadmap
- [ ] Windows: Maximize button docking feature introduced in Windows 11
- [ ] All: Add cross-platform system menu. Support both light and dark theme. Can be triggered by right-click on the title bar area.
- 2.1
- [ ] All: Add cross-platform system menu for both Qt Widgets and Qt Quick. Support both light and dark theme. Can be triggered by right-clicking on the title bar area or pressing the system menu shortcut (ALT + SPACE).
- [ ] All: Add QtWebEngine demo applications for both Qt Widgets and Qt Quick.
- [ ] All: Make more settings and options configurable through environment variables and configuration files.
- Future versions
- [ ] Windows: Maximize button docking feature introduced in Windows 11
- [ ] More feature requests are welcome!
## Feedback

View File

@ -56,12 +56,56 @@
static_cast<FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::Enum>(static_cast<int>(Value))
#endif
#ifndef FRAMELESSHELPER_FLAGS_CORE_TO_QUICK
# define FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Enum, Value, In, Out) \
if (In & FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::Enum::Value) { \
Out |= FRAMELESSHELPER_PREPEND_NAMESPACE(QuickGlobal)::Enum::Value; \
}
#endif
#ifndef FRAMELESSHELPER_FLAGS_QUICK_TO_CORE
# define FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Enum, Value, In, Out) \
if (In & FRAMELESSHELPER_PREPEND_NAMESPACE(QuickGlobal)::Enum::Value) { \
Out |= FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::Enum::Value; \
}
#endif
FRAMELESSHELPER_BEGIN_NAMESPACE
[[maybe_unused]] static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
struct FRAMELESSHELPER_QUICK_API QuickGlobal
{
enum class Option
{
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, ForceHideWindowFrameBorder)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, ForceShowWindowFrameBorder)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontDrawTopWindowFrameBorder)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, EnableRoundedWindowCorners)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, TransparentWindowBackground)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, MaximizeButtonDocking)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, CreateStandardWindowLayout)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, BeCompatibleWithQtFramelessWindowHint)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontTouchQtInternals)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontTouchWindowFrameBorderColor)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontInstallSystemMenuHook)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DisableSystemMenu)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, NoDoubleClickMaximizeToggle)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DisableResizing)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DisableDragging)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontTouchCursorShape)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontMoveWindowToDesktopCenter)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontTreatFullScreenAsZoomed)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontTouchHighDpiScalingPolicy)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontTouchScaleFactorRoundingPolicy)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontTouchProcessDpiAwarenessLevel)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, DontEnsureNonNativeWidgetSiblings)
FRAMELESSHELPER_QUICK_ENUM_VALUE(Option, SyncNativeControlsThemeWithSystem)
};
Q_ENUM(Option)
Q_DECLARE_FLAGS(Options, Option)
Q_FLAG(Options)
enum class SystemTheme
{
FRAMELESSHELPER_QUICK_ENUM_VALUE(SystemTheme, Unknown)
@ -93,7 +137,7 @@ struct FRAMELESSHELPER_QUICK_API QuickGlobal
enum class DwmColorizationArea
{
FRAMELESSHELPER_QUICK_ENUM_VALUE(DwmColorizationArea, None_) // Avoid name conflicts with X11 headers.
FRAMELESSHELPER_QUICK_ENUM_VALUE(DwmColorizationArea, None_)
FRAMELESSHELPER_QUICK_ENUM_VALUE(DwmColorizationArea, StartMenu_TaskBar_ActionCenter)
FRAMELESSHELPER_QUICK_ENUM_VALUE(DwmColorizationArea, TitleBar_WindowBorder)
FRAMELESSHELPER_QUICK_ENUM_VALUE(DwmColorizationArea, All)
@ -128,7 +172,8 @@ private:
#ifdef QML_UNCREATABLE
QML_UNCREATABLE("The FramelessHelper namespace is not creatable, you can only use it to access it's enums.")
#endif
Q_DISABLE_COPY_MOVE(QuickGlobal)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QuickGlobal::Options)
FRAMELESSHELPER_END_NAMESPACE

View File

@ -47,6 +47,7 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow
Q_PROPERTY(bool fullScreen READ isFullScreen NOTIFY fullScreenChanged FINAL)
Q_PROPERTY(bool fixedSize READ fixedSize WRITE setFixedSize NOTIFY fixedSizeChanged FINAL)
Q_PROPERTY(QColor frameBorderColor READ frameBorderColor NOTIFY frameBorderColorChanged FINAL)
Q_PROPERTY(QuickGlobal::Options options READ options WRITE setOptions NOTIFY optionsChanged FINAL)
public:
explicit FramelessQuickWindow(QWindow *parent = nullptr, const Global::UserSettings &settings = {});
@ -63,6 +64,9 @@ public:
Q_NODISCARD QColor frameBorderColor() const;
Q_NODISCARD QuickGlobal::Options options() const;
void setOptions(const QuickGlobal::Options value);
public Q_SLOTS:
void showMinimized2();
void toggleMaximized();
@ -85,6 +89,7 @@ Q_SIGNALS:
void fixedSizeChanged();
void frameBorderColorChanged();
void systemButtonStateChanged(const QuickGlobal::SystemButtonType, const QuickGlobal::ButtonState);
void optionsChanged();
private:
QScopedPointer<FramelessQuickWindowPrivate> d_ptr;

View File

@ -57,6 +57,7 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
return;
}
inited = true;
qRegisterMetaType<QuickGlobal::Options>();
qRegisterMetaType<QuickGlobal::SystemTheme>();
qRegisterMetaType<QuickGlobal::SystemButtonType>();
qRegisterMetaType<QuickGlobal::ResourceType>();

View File

@ -36,6 +36,64 @@ using namespace Global;
static constexpr const char QT_QUICKITEM_CLASS_NAME[] = "QQuickItem";
[[nodiscard]] static inline QuickGlobal::Options optionsCoreToQuick(const Options value)
{
QuickGlobal::Options result = {};
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, ForceHideWindowFrameBorder, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, ForceShowWindowFrameBorder, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontDrawTopWindowFrameBorder, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, EnableRoundedWindowCorners, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, TransparentWindowBackground, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, MaximizeButtonDocking, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, CreateStandardWindowLayout, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, BeCompatibleWithQtFramelessWindowHint, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontTouchQtInternals, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontTouchWindowFrameBorderColor, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontInstallSystemMenuHook, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DisableSystemMenu, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, NoDoubleClickMaximizeToggle, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DisableResizing, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DisableDragging, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontTouchCursorShape, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontMoveWindowToDesktopCenter, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontTreatFullScreenAsZoomed, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontTouchHighDpiScalingPolicy, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontTouchScaleFactorRoundingPolicy, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontTouchProcessDpiAwarenessLevel, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, DontEnsureNonNativeWidgetSiblings, value, result)
FRAMELESSHELPER_FLAGS_CORE_TO_QUICK(Option, SyncNativeControlsThemeWithSystem, value, result)
return result;
}
[[nodiscard]] static inline Options optionsQuickToCore(const QuickGlobal::Options value)
{
Options result = {};
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, ForceHideWindowFrameBorder, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, ForceShowWindowFrameBorder, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontDrawTopWindowFrameBorder, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, EnableRoundedWindowCorners, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, TransparentWindowBackground, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, MaximizeButtonDocking, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, CreateStandardWindowLayout, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, BeCompatibleWithQtFramelessWindowHint, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontTouchQtInternals, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontTouchWindowFrameBorderColor, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontInstallSystemMenuHook, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DisableSystemMenu, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, NoDoubleClickMaximizeToggle, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DisableResizing, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DisableDragging, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontTouchCursorShape, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontMoveWindowToDesktopCenter, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontTreatFullScreenAsZoomed, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontTouchHighDpiScalingPolicy, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontTouchScaleFactorRoundingPolicy, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontTouchProcessDpiAwarenessLevel, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, DontEnsureNonNativeWidgetSiblings, value, result)
FRAMELESSHELPER_FLAGS_QUICK_TO_CORE(Option, SyncNativeControlsThemeWithSystem, value, result)
return result;
}
FramelessQuickWindowPrivate::FramelessQuickWindowPrivate(FramelessQuickWindow *q, const UserSettings &settings) : QObject(q)
{
Q_ASSERT(q);
@ -278,6 +336,17 @@ void FramelessQuickWindowPrivate::snapToTopBorder(QQuickItem *item, const QuickG
}
}
void FramelessQuickWindowPrivate::setOptions(const QuickGlobal::Options value)
{
Q_Q(FramelessQuickWindow);
if (m_quickOptions == value) {
return;
}
m_quickOptions = value;
m_settings.options = optionsQuickToCore(m_quickOptions);
Q_EMIT q->optionsChanged();
}
bool FramelessQuickWindowPrivate::eventFilter(QObject *object, QEvent *event)
{
Q_ASSERT(object);
@ -439,32 +508,26 @@ void FramelessQuickWindowPrivate::initialize()
if (m_settings.options & Option::TransparentWindowBackground) {
q->setColor(kDefaultTransparentColor);
}
m_quickOptions = optionsCoreToQuick(m_settings.options);
FramelessWindowsManager * const manager = FramelessWindowsManager::instance();
manager->addWindow(m_settings, m_params);
q->installEventFilter(this);
QQuickItem * const rootItem = q->contentItem();
const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem);
m_topBorderRectangle.reset(new QQuickRectangle(rootItem));
m_topBorderRectangle->setColor(kDefaultTransparentColor);
m_topBorderRectangle->setHeight(0.0);
QQuickPen * const _border = m_topBorderRectangle->border();
_border->setWidth(0.0);
_border->setColor(kDefaultTransparentColor);
const bool frameBorderVisible = [this]() -> bool {
#ifdef Q_OS_WINDOWS
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater()
&& !(m_settings.options & Option::DontDrawTopWindowFrameBorder));
#else
Q_UNUSED(this);
return false;
#endif
}();
if (frameBorderVisible) {
updateTopBorderHeight();
updateTopBorderColor();
m_topBorderAnchors.reset(new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data()));
m_topBorderAnchors->setTop(rootItemPrivate->top());
m_topBorderAnchors->setLeft(rootItemPrivate->left());
m_topBorderAnchors->setRight(rootItemPrivate->right());
connect(q, &FramelessQuickWindow::visibilityChanged, this, [this, q](){
updateTopBorderHeight();
updateTopBorderColor();
}
connect(q, &FramelessQuickWindow::visibilityChanged, this, [this, q, frameBorderVisible](){
if (frameBorderVisible) {
updateTopBorderHeight();
}
Q_EMIT q->hiddenChanged();
Q_EMIT q->normalChanged();
Q_EMIT q->minimizedChanged();
@ -472,16 +535,10 @@ void FramelessQuickWindowPrivate::initialize()
Q_EMIT q->fullScreenChanged();
});
connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this, q, frameBorderVisible](){
if (frameBorderVisible) {
updateTopBorderColor();
}
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this, q](){
updateTopBorderColor();
Q_EMIT q->frameBorderColorChanged();
});
m_topBorderAnchors.reset(new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data()));
m_topBorderAnchors->setTop(rootItemPrivate->top());
m_topBorderAnchors->setLeft(rootItemPrivate->left());
m_topBorderAnchors->setRight(rootItemPrivate->right());
}
QRect FramelessQuickWindowPrivate::mapItemGeometryToScene(const QQuickItem * const item) const
@ -608,6 +665,16 @@ void FramelessQuickWindowPrivate::doStartSystemMove2(QMouseEvent *event)
startSystemMove2(globalPos);
}
bool FramelessQuickWindowPrivate::shouldDrawFrameBorder() const
{
#ifdef Q_OS_WINDOWS
return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater()
&& !(m_settings.options & Option::DontDrawTopWindowFrameBorder));
#else
return false;
#endif
}
void FramelessQuickWindowPrivate::showEventHandler(QShowEvent *event)
{
Q_ASSERT(event);
@ -711,9 +778,17 @@ void FramelessQuickWindowPrivate::mouseDoubleClickEventHandler(QMouseEvent *even
toggleMaximized();
}
QuickGlobal::Options FramelessQuickWindowPrivate::getOptions() const
{
return m_quickOptions;
}
void FramelessQuickWindowPrivate::updateTopBorderColor()
{
#ifdef Q_OS_WINDOWS
if (!shouldDrawFrameBorder()) {
return;
}
m_topBorderRectangle->setColor(getFrameBorderColor());
#endif
}
@ -721,6 +796,9 @@ void FramelessQuickWindowPrivate::updateTopBorderColor()
void FramelessQuickWindowPrivate::updateTopBorderHeight()
{
#ifdef Q_OS_WINDOWS
if (!shouldDrawFrameBorder()) {
return;
}
const qreal newHeight = (isNormal() ? 1.0 : 0.0);
m_topBorderRectangle->setHeight(newHeight);
#endif
@ -781,6 +859,18 @@ QColor FramelessQuickWindow::frameBorderColor() const
return d->getFrameBorderColor();
}
QuickGlobal::Options FramelessQuickWindow::options() const
{
Q_D(const FramelessQuickWindow);
return d->getOptions();
}
void FramelessQuickWindow::setOptions(const QuickGlobal::Options value)
{
Q_D(FramelessQuickWindow);
d->setOptions(value);
}
void FramelessQuickWindow::setTitleBarItem(QQuickItem *item)
{
Q_ASSERT(item);

View File

@ -71,6 +71,8 @@ public:
Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event);
Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event);
Q_INVOKABLE Q_NODISCARD QuickGlobal::Options getOptions() const;
public Q_SLOTS:
void showMinimized2();
void toggleMaximized();
@ -84,6 +86,7 @@ public Q_SLOTS:
void setFixedSize(const bool value, const bool force = false);
void bringToFront();
void snapToTopBorder(QQuickItem *item, const QuickGlobal::Anchor itemAnchor, const QuickGlobal::Anchor topBorderAnchor);
void setOptions(const QuickGlobal::Options value);
protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
@ -95,6 +98,7 @@ private:
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
void doStartSystemMove2(QMouseEvent *event);
Q_NODISCARD bool shouldDrawFrameBorder() const;
private Q_SLOTS:
void updateTopBorderColor();
@ -111,6 +115,7 @@ private:
bool m_windowExposed = false;
QPointer<QQuickItem> m_titleBarItem = nullptr;
QList<QQuickItem *> m_hitTestVisibleItems = {};
QuickGlobal::Options m_quickOptions = {};
};
FRAMELESSHELPER_END_NAMESPACE