diff --git a/autotests/mockclient.h b/autotests/mockclient.h --- a/autotests/mockclient.h +++ b/autotests/mockclient.h @@ -52,12 +52,15 @@ bool isShadeable() const override; bool isShaded() const override; QPalette palette() const override; + bool hasApplicationMenu() const override; + bool isApplicationMenuActive() const override; bool providesContextHelp() const override; void requestClose() override; void requestContextHelp() override; void requestToggleMaximization(Qt::MouseButtons buttons) override; void requestMinimize() override; void requestShowWindowMenu() override; + void requestShowApplicationMenu(const QRect &rect, int actionId) override; void requestToggleKeepAbove() override; void requestToggleKeepBelow() override; void requestToggleOnAllDesktops() override; @@ -65,6 +68,8 @@ int width() const override; WId windowId() const override; + void showApplicationMenu(int actionId) override; + void setCloseable(bool set); void setMinimizable(bool set); void setProvidesContextHelp(bool set); @@ -79,6 +84,7 @@ void minimizeRequested(); void quickHelpRequested(); void menuRequested(); + void applicationMenuRequested(); private: bool m_closeable = false; diff --git a/autotests/mockclient.cpp b/autotests/mockclient.cpp --- a/autotests/mockclient.cpp +++ b/autotests/mockclient.cpp @@ -138,6 +138,16 @@ return QPalette(); } +bool MockClient::hasApplicationMenu() const +{ + return false; // FIXME TODO +} + +bool MockClient::isApplicationMenuActive() const +{ + return false; +} + bool MockClient::providesContextHelp() const { return m_contextHelp; @@ -191,6 +201,13 @@ emit menuRequested(); } +void MockClient::requestShowApplicationMenu(const QRect &rect, int actionId) +{ + Q_UNUSED(rect); + Q_UNUSED(actionId); + emit applicationMenuRequested(); // FIXME TODO pass geometry +} + void MockClient::requestToggleKeepAbove() { m_keepAbove = !m_keepAbove; @@ -266,3 +283,8 @@ m_height = h; emit client()->heightChanged(h); } + +void MockClient::showApplicationMenu(int actionId) +{ + Q_UNUSED(actionId) +} diff --git a/src/decoratedclient.h b/src/decoratedclient.h --- a/src/decoratedclient.h +++ b/src/decoratedclient.h @@ -168,6 +168,12 @@ **/ Q_PROPERTY(Qt::Edges adjacentScreenEdges READ adjacentScreenEdges NOTIFY adjacentScreenEdgesChanged) + // FIXME TODO docs @since + Q_PROPERTY(bool hasApplicationMenu READ hasApplicationMenu NOTIFY hasApplicationMenuChanged) + + // FIXME TODO docs @since + Q_PROPERTY(bool applicationMenuActive READ isApplicationMenuActive NOTIFY applicationMenuActiveChanged) + // TODO: properties for windowId and decorationId? public: @@ -221,6 +227,24 @@ **/ QColor color(ColorGroup group, ColorRole role) const; + /** + * Whether the DecoratedClient has an application menu + * + * @since 5.9 + */ + bool hasApplicationMenu() const; + /** + * Whether the application menu of this DecoratedClient is currently shown to the user + * @since 5.9 + */ + bool isApplicationMenuActive() const; + + /** + * Request the application menu to be shown to the user + * @param actionId The DBus menu ID of the action that should be highlighted, 0 for none. + */ + void showApplicationMenu(int actionId); + Q_SIGNALS: void activeChanged(bool); void captionChanged(QString); @@ -247,6 +271,9 @@ void paletteChanged(const QPalette &palette); void adjacentScreenEdgesChanged(Qt::Edges edges); + void hasApplicationMenuChanged(bool); + void applicationMenuActiveChanged(bool); + private: friend class Decoration; DecoratedClient(Decoration *parent, DecorationBridge *bridge); diff --git a/src/decoratedclient.cpp b/src/decoratedclient.cpp --- a/src/decoratedclient.cpp +++ b/src/decoratedclient.cpp @@ -66,6 +66,8 @@ DELEGATE(int, height) DELEGATE(QPalette, palette) DELEGATE(Qt::Edges, adjacentScreenEdges) +DELEGATE(bool, hasApplicationMenu) +DELEGATE(bool, isApplicationMenuActive) #undef DELEGATE @@ -84,4 +86,9 @@ return d->color(group, role); } +void DecoratedClient::showApplicationMenu(int actionId) +{ + d->showApplicationMenu(actionId); +} + } // namespace diff --git a/src/decoration.h b/src/decoration.h --- a/src/decoration.h +++ b/src/decoration.h @@ -177,6 +177,9 @@ void requestToggleKeepBelow(); void requestShowWindowMenu(); + void showApplicationMenu(int actionId); + void requestShowApplicationMenu(const QRect &rect, int actionId); + void update(const QRect &rect); void update(); diff --git a/src/decoration.cpp b/src/decoration.cpp --- a/src/decoration.cpp +++ b/src/decoration.cpp @@ -185,6 +185,22 @@ d->client->d->requestToggleMaximization(buttons); } +void Decoration::showApplicationMenu(int actionId) +{ + auto it = std::find_if(d->buttons.constBegin(), d->buttons.constEnd(), [](DecorationButton *button) { + return button->type() == DecorationButtonType::ApplicationMenu; + }); + + if (it != d->buttons.constEnd()) { + requestShowApplicationMenu((*it)->geometry().toRect(), actionId); + } +} + +void Decoration::requestShowApplicationMenu(const QRect &rect, int actionId) +{ + d->client->d->requestShowApplicationMenu(rect, actionId); +} + #define DELEGATE(name, variableName, type, emitValue) \ void Decoration::name(type a) \ { \ diff --git a/src/decorationbutton.cpp b/src/decorationbutton.cpp --- a/src/decorationbutton.cpp +++ b/src/decorationbutton.cpp @@ -77,6 +77,16 @@ setPressAndHold(settings->isCloseOnDoubleClickOnMenu()); setAcceptedButtons(Qt::LeftButton | Qt::RightButton); break; + case DecorationButtonType::ApplicationMenu: + setVisible(c->hasApplicationMenu()); + setCheckable(true); // will be "checked" whilst the menu is opened + // FIXME TODO connect directly and figure out the button geometry/offset stuff + QObject::connect(q, &DecorationButton::clicked, decoration.data(), [this] { + decoration->requestShowApplicationMenu(q->geometry().toRect(), 0 /* actionId */); + }, Qt::QueuedConnection); //&Decoration::requestShowApplicationMenu, Qt::QueuedConnection); + QObject::connect(c, &DecoratedClient::hasApplicationMenuChanged, q, &DecorationButton::setVisible); + QObject::connect(c, &DecoratedClient::applicationMenuActiveChanged, q, &DecorationButton::setChecked); + break; case DecorationButtonType::OnAllDesktops: setVisible(settings->isOnAllDesktopsAvailable()); setCheckable(true); diff --git a/src/private/decoratedclientprivate.h b/src/private/decoratedclientprivate.h --- a/src/private/decoratedclientprivate.h +++ b/src/private/decoratedclientprivate.h @@ -76,6 +76,9 @@ virtual QPalette palette() const = 0; virtual Qt::Edges adjacentScreenEdges() const = 0; + virtual bool hasApplicationMenu() const = 0; + virtual bool isApplicationMenuActive() const = 0; + virtual void requestClose() = 0; virtual void requestToggleMaximization(Qt::MouseButtons buttons) = 0; virtual void requestMinimize() = 0; @@ -86,6 +89,9 @@ virtual void requestToggleKeepBelow() = 0; virtual void requestShowWindowMenu() = 0; + virtual void showApplicationMenu(int actionId) = 0; + virtual void requestShowApplicationMenu(const QRect &rect, int actionId) = 0; + Decoration *decoration(); Decoration *decoration() const;