Commit c812ffbe authored by Kevin Ottens's avatar Kevin Ottens Committed by Kevin Ottens
Browse files

Move basic activities support from X11Client to AbstractClient

We're now sharing most of the X11Client activity behavior accross all
clients. This allows to cleanup some of the existing virtuals and remove
quite a bit of code overalls.

Has to introduce an extra platform specific hook since X11Client
serializes the activity information in an atom and we will probably need
to do something similar on the Wayland platform at some point.

This allows us to start interacting with the activities with kwin
wayland. They are not restored properly accross sessions though since
nothing is really persisted and the session management still seems to
be amiss.
parent da0aed54
......@@ -511,6 +511,11 @@ void AbstractClient::doSetDesktop()
{
}
void AbstractClient::doSetOnActivities(const QStringList &activityList)
{
Q_UNUSED(activityList);
}
void AbstractClient::enterDesktop(VirtualDesktop *virtualDesktop)
{
if (m_desktops.contains(virtualDesktop)) {
......@@ -2792,9 +2797,14 @@ void AbstractClient::evaluateWindowRules()
applyWindowRules();
}
void AbstractClient::setOnActivities(const QStringList &newActivitiesList)
/**
* Returns the list of activities the client window is on.
* if it's on all activities, the list will be empty.
* Don't use this, use isOnActivity() and friends (from class Toplevel)
*/
QStringList AbstractClient::activities() const
{
Q_UNUSED(newActivitiesList)
return m_activityList;
}
/**
......@@ -2832,6 +2842,95 @@ void AbstractClient::setOnActivity(const QString &activity, bool enable)
#endif
}
/**
* set exactly which activities this client is on
*/
void AbstractClient::setOnActivities(const QStringList &newActivitiesList)
{
#ifdef KWIN_BUILD_ACTIVITIES
if (!Activities::self()) {
return;
}
const auto allActivities = Activities::self()->all();
const auto activityList = [&] {
auto result = rules()->checkActivity(newActivitiesList);
const auto it = std::remove_if(result.begin(), result.end(), [=](const QString &activity) {
return !allActivities.contains(activity);
});
result.erase(it, result.end());
return result;
}();
const auto allActivityExplicitlyRequested = activityList.isEmpty() || activityList.contains(Activities::nullUuid());
const auto allActivitiesCovered = activityList.size() > 1 && activityList.size() == allActivities.size();
if (allActivityExplicitlyRequested || allActivitiesCovered) {
if (!m_activityList.isEmpty()) {
m_activityList.clear();
doSetOnActivities(m_activityList);
}
} else {
if (m_activityList != activityList) {
m_activityList = activityList;
doSetOnActivities(m_activityList);
}
}
updateActivities(false);
#else
Q_UNUSED(newActivitiesList)
#endif
}
/**
* if @p all is true, sets on all activities.
* if it's false, sets it to only be on the current activity
*/
void AbstractClient::setOnAllActivities(bool all)
{
#ifdef KWIN_BUILD_ACTIVITIES
if (all == isOnAllActivities()) {
return;
}
if (all) {
setOnActivities(QStringList());
} else {
setOnActivity(Activities::self()->current(), true);
}
#else
Q_UNUSED(on)
#endif
}
/**
* update after activities changed
*/
void AbstractClient::updateActivities(bool includeTransients)
{
if (m_activityUpdatesBlocked) {
m_blockedActivityUpdatesRequireTransients |= includeTransients;
return;
}
emit activitiesChanged(this);
m_blockedActivityUpdatesRequireTransients = false; // reset
FocusChain::self()->update(this, FocusChain::MakeFirst);
updateWindowRules(Rules::Activity);
}
void AbstractClient::blockActivityUpdates(bool b)
{
if (b) {
++m_activityUpdatesBlocked;
} else {
Q_ASSERT(m_activityUpdatesBlocked);
--m_activityUpdatesBlocked;
if (!m_activityUpdatesBlocked) {
updateActivities(m_blockedActivityUpdatesRequireTransients);
}
}
}
void AbstractClient::checkNoBorder()
{
setNoBorder(false);
......
......@@ -501,7 +501,6 @@ public:
Q_INVOKABLE void setMaximize(bool vertically, bool horizontally);
virtual bool noBorder() const;
virtual void setNoBorder(bool set);
virtual void blockActivityUpdates(bool b = true) = 0;
QPalette palette() const;
const Decoration::DecorationPalette *decorationPalette() const;
/**
......@@ -537,9 +536,14 @@ public:
virtual bool userCanSetFullScreen() const;
virtual bool userCanSetNoBorder() const;
virtual void checkNoBorder();
virtual void setOnActivities(const QStringList &newActivitiesList);
virtual void setOnAllActivities(bool set) = 0;
QStringList activities() const override;
void setOnActivity(const QString &activity, bool enable);
void setOnActivities(const QStringList &newActivitiesList);
void setOnAllActivities(bool all);
virtual void updateActivities(bool includeTransients);
void blockActivityUpdates(bool b = true);
const WindowRules* rules() const {
return &m_rules;
}
......@@ -970,6 +974,15 @@ protected:
* Default implementation does nothing.
*/
virtual void doSetDesktop();
/**
* Called from @ref setOnActivities just after the activity list member has been updated, but before
* @ref updateActivities is called.
*
* @param activityList the new list of activities set on that client
*
* Default implementation does nothing
*/
virtual void doSetOnActivities(const QStringList &activityList);
/**
* Called from @ref minimize and @ref unminimize once the minimized value got updated, but before the
* changed signal is emitted.
......@@ -1255,6 +1268,10 @@ private:
ShadeMode m_shadeMode = ShadeNone;
QVector <VirtualDesktop *> m_desktops;
QStringList m_activityList;
int m_activityUpdatesBlocked = 0;
bool m_blockedActivityUpdatesRequireTransients = false;
QString m_colorScheme;
std::shared_ptr<Decoration::DecorationPalette> m_palette;
static QHash<QString, std::weak_ptr<Decoration::DecorationPalette>> s_palettes;
......
......@@ -90,18 +90,6 @@ QRect InternalClient::bufferGeometry() const
return m_clientGeometry;
}
QStringList InternalClient::activities() const
{
return QStringList();
}
void InternalClient::blockActivityUpdates(bool b)
{
Q_UNUSED(b)
// Internal clients do not support activities.
}
qreal InternalClient::bufferScale() const
{
if (m_internalWindow) {
......@@ -298,13 +286,6 @@ AbstractClient *InternalClient::findModal(bool allow_itself)
return nullptr;
}
void InternalClient::setOnAllActivities(bool set)
{
Q_UNUSED(set)
// Internal clients do not support activities.
}
bool InternalClient::takeFocus()
{
return false;
......
......@@ -25,8 +25,6 @@ public:
bool eventFilter(QObject *watched, QEvent *event) override;
QRect bufferGeometry() const override;
QStringList activities() const override;
void blockActivityUpdates(bool b = true) override;
qreal bufferScale() const override;
QString captionNormal() const override;
QString captionSuffix() const override;
......@@ -56,7 +54,6 @@ public:
void resizeWithChecks(const QSize &size, ForceGeometry_t force = NormalGeometrySet) override;
void setFrameGeometry(const QRect &rect, ForceGeometry_t force = NormalGeometrySet) override;
AbstractClient *findModal(bool allow_itself = false) override;
void setOnAllActivities(bool set) override;
bool takeFocus() override;
void setNoBorder(bool set) override;
void updateDecoration(bool check_workspace_pos, bool force = false) override;
......
......@@ -67,21 +67,6 @@ QString WaylandClient::captionSuffix() const
return m_captionSuffix;
}
QStringList WaylandClient::activities() const
{
return QStringList();
}
void WaylandClient::setOnAllActivities(bool set)
{
Q_UNUSED(set)
}
void WaylandClient::blockActivityUpdates(bool b)
{
Q_UNUSED(b)
}
QPoint WaylandClient::clientContentPos() const
{
return -clientPos();
......
......@@ -26,9 +26,6 @@ public:
QRect bufferGeometry() const override;
QString captionNormal() const override;
QString captionSuffix() const override;
QStringList activities() const override;
void setOnAllActivities(bool set) override;
void blockActivityUpdates(bool b = true) override;
QPoint clientContentPos() const override;
QRect transparentRect() const override;
pid_t pid() const override;
......
......@@ -1878,75 +1878,27 @@ void X11Client::doSetDemandsAttention()
info->setState(isDemandingAttention() ? NET::DemandsAttention : NET::States(), NET::DemandsAttention);
}
/**
* set exactly which activities this client is on
*/
void X11Client::setOnActivities(const QStringList &newActivitiesList)
void X11Client::doSetOnActivities(const QStringList &activityList)
{
#ifdef KWIN_BUILD_ACTIVITIES
if (!Activities::self()) {
return;
}
auto activitiesList = rules()->checkActivity(newActivitiesList);
QStringList allActivities = Activities::self()->all();
auto it = activitiesList.begin();
while (it != activitiesList.end()) {
if (! allActivities.contains(*it)) {
it = activitiesList.erase(it);
} else {
it++;
}
}
if (// If we got the request to be on all activities explicitly
activitiesList.isEmpty() || activitiesList.contains(Activities::nullUuid()) ||
// If we got a list of activities that covers all activities
(activitiesList.count() > 1 && activitiesList.count() == allActivities.count())) {
activityList.clear();
if (activityList.isEmpty()) {
const QByteArray nullUuid = Activities::nullUuid().toUtf8();
m_client.changeProperty(atoms->activities, XCB_ATOM_STRING, 8, nullUuid.length(), nullUuid.constData());
} else {
QByteArray joined = activitiesList.join(QStringLiteral(",")).toLatin1();
activityList = activitiesList;
QByteArray joined = activityList.join(QStringLiteral(",")).toLatin1();
m_client.changeProperty(atoms->activities, XCB_ATOM_STRING, 8, joined.length(), joined.constData());
}
updateActivities(false);
#else
Q_UNUSED(newActivitiesList)
#endif
}
void X11Client::blockActivityUpdates(bool b)
{
if (b) {
++m_activityUpdatesBlocked;
} else {
Q_ASSERT(m_activityUpdatesBlocked);
--m_activityUpdatesBlocked;
if (!m_activityUpdatesBlocked)
updateActivities(m_blockedActivityUpdatesRequireTransients);
}
}
/**
* update after activities changed
*/
void X11Client::updateActivities(bool includeTransients)
{
if (m_activityUpdatesBlocked) {
m_blockedActivityUpdatesRequireTransients |= includeTransients;
return;
AbstractClient::updateActivities(includeTransients);
if (!m_activityUpdatesBlocked) {
updateVisibility();
}
emit activitiesChanged(this);
m_blockedActivityUpdatesRequireTransients = false; // reset
FocusChain::self()->update(this, FocusChain::MakeFirst);
updateVisibility();
updateWindowRules(Rules::Activity);
}
/**
......@@ -1959,27 +1911,7 @@ QStringList X11Client::activities() const
if (sessionActivityOverride) {
return QStringList();
}
return activityList;
}
/**
* if @p on is true, sets on all activities.
* if it's false, sets it to only be on the current activity
*/
void X11Client::setOnAllActivities(bool on)
{
#ifdef KWIN_BUILD_ACTIVITIES
if (on == isOnAllActivities())
return;
if (on) {
setOnActivities(QStringList());
} else {
setOnActivity(Activities::self()->current(), true);
}
#else
Q_UNUSED(on)
#endif
return AbstractClient::activities();
}
/**
......
......@@ -122,10 +122,8 @@ public:
void destroyClient() override;
QStringList activities() const override;
void setOnAllActivities(bool set) override;
void setOnActivities(const QStringList &newActivitiesList) override;
void updateActivities(bool includeTransients);
void blockActivityUpdates(bool b = true) override;
void doSetOnActivities(const QStringList &newActivitiesList) override;
void updateActivities(bool includeTransients) override;
/// Is not minimized and not hidden. I.e. normally visible on some virtual desktop.
bool isShown(bool shaded_is_shown) const override;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment