Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
quick module: minor improvements
Browse files Browse the repository at this point in the history
Signed-off-by: Yuhang Zhao <[email protected]>
  • Loading branch information
wangwenx190 committed Apr 22, 2022
1 parent 201f54e commit 8460995
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 28 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
49 changes: 47 additions & 2 deletions include/FramelessHelper/Quick/framelesshelperquick_global.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -128,7 +172,8 @@ struct FRAMELESSHELPER_QUICK_API QuickGlobal
#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
5 changes: 5 additions & 0 deletions include/FramelessHelper/Quick/framelessquickwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {});
Expand All @@ -63,6 +64,9 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow

Q_NODISCARD QColor frameBorderColor() const;

Q_NODISCARD QuickGlobal::Options options() const;
void setOptions(const QuickGlobal::Options value);

public Q_SLOTS:
void showMinimized2();
void toggleMaximized();
Expand All @@ -85,6 +89,7 @@ public Q_SLOTS:
void fixedSizeChanged();
void frameBorderColorChanged();
void systemButtonStateChanged(const QuickGlobal::SystemButtonType, const QuickGlobal::ButtonState);
void optionsChanged();

private:
QScopedPointer<FramelessQuickWindowPrivate> d_ptr;
Expand Down
1 change: 1 addition & 0 deletions src/quick/framelessquickhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down
138 changes: 114 additions & 24 deletions src/quick/framelessquickwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -439,49 +508,37 @@ 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();
Q_EMIT q->zoomedChanged();
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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -711,16 +778,27 @@ 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
}

void FramelessQuickWindowPrivate::updateTopBorderHeight()
{
#ifdef Q_OS_WINDOWS
if (!shouldDrawFrameBorder()) {
return;
}
const qreal newHeight = (isNormal() ? 1.0 : 0.0);
m_topBorderRectangle->setHeight(newHeight);
#endif
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/quick/framelessquickwindow_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject
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();
Expand All @@ -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;
Expand All @@ -95,6 +98,7 @@ public Q_SLOTS:
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();
Expand All @@ -111,6 +115,7 @@ private Q_SLOTS:
bool m_windowExposed = false;
QPointer<QQuickItem> m_titleBarItem = nullptr;
QList<QQuickItem *> m_hitTestVisibleItems = {};
QuickGlobal::Options m_quickOptions = {};
};

FRAMELESSHELPER_END_NAMESPACE

0 comments on commit 8460995

Please sign in to comment.