KWin
Loading...
Searching...
No Matches
activities.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "activities.h"
10// KWin
11#include "workspace.h"
12#include "x11window.h"
13// KDE
14#include <KConfigGroup>
15// Qt
16#include <QDBusInterface>
17#include <QDBusPendingCall>
18#include <QFutureWatcher>
19#include <QtConcurrentRun>
20
21namespace KWin
22{
23
25 : m_controller(new KActivities::Controller(this))
26{
27 connect(m_controller, &KActivities::Controller::activityRemoved, this, &Activities::slotRemoved);
28 connect(m_controller, &KActivities::Controller::activityRemoved, this, &Activities::removed);
29 connect(m_controller, &KActivities::Controller::activityAdded, this, &Activities::added);
30 connect(m_controller, &KActivities::Controller::currentActivityChanged, this, &Activities::slotCurrentChanged);
31 connect(m_controller, &KActivities::Controller::serviceStatusChanged, this, &Activities::slotServiceStatusChanged);
32}
33
34KActivities::Consumer::ServiceStatus Activities::serviceStatus() const
35{
36 return m_controller->serviceStatus();
37}
38
39void Activities::slotServiceStatusChanged()
40{
41 if (m_controller->serviceStatus() != KActivities::Consumer::Running) {
42 return;
43 }
44 const auto windows = Workspace::self()->windows();
45 for (auto *const window : windows) {
46 if (!window->isClient()) {
47 continue;
48 }
49 if (window->isDesktop()) {
50 continue;
51 }
52 window->checkActivities();
53 }
54}
55
56void Activities::setCurrent(const QString &activity)
57{
58 m_controller->setCurrentActivity(activity);
59}
60
61void Activities::slotCurrentChanged(const QString &newActivity)
62{
63 if (m_current == newActivity) {
64 return;
65 }
66 m_previous = m_current;
67 m_current = newActivity;
68 Q_EMIT currentChanged(newActivity);
69}
70
71void Activities::slotRemoved(const QString &activity)
72{
73 const auto windows = Workspace::self()->windows();
74 for (auto *const window : windows) {
75 if (!window->isClient()) {
76 continue;
77 }
78 if (window->isDesktop()) {
79 continue;
80 }
81 window->setOnActivity(activity, false);
82 }
83 // toss out any session data for it
84 KConfigGroup cg(KSharedConfig::openConfig(), QLatin1String("SubSession: ") + activity);
85 cg.deleteGroup();
86}
87
88void Activities::toggleWindowOnActivity(Window *window, const QString &activity, bool dont_activate)
89{
90 // int old_desktop = window->desktop();
91 bool was_on_activity = window->isOnActivity(activity);
92 bool was_on_all = window->isOnAllActivities();
93 // note: all activities === no activities
94 bool enable = was_on_all || !was_on_activity;
95 window->setOnActivity(activity, enable);
96 if (window->isOnActivity(activity) == was_on_activity && window->isOnAllActivities() == was_on_all) { // No change
97 return;
98 }
99
101 if (window->isOnCurrentActivity()) {
102 if (window->wantsTabFocus() && options->focusPolicyIsReasonable() && !was_on_activity && // for stickyness changes
103 // FIXME not sure if the line above refers to the correct activity
104 !dont_activate) {
105 ws->requestFocus(window);
106 } else {
107 ws->restackWindowUnderActive(window);
108 }
109 } else {
110 ws->raiseWindow(window);
111 }
112
113 // notifyWindowDesktopChanged( c, old_desktop );
114
115 const auto transients_stacking_order = ws->ensureStackingOrder(window->transients());
116 for (auto *const window : transients_stacking_order) {
117 if (!window) {
118 continue;
119 }
120 toggleWindowOnActivity(window, activity, dont_activate);
121 }
122 ws->updateClientArea();
123}
124
125bool Activities::start(const QString &id)
126{
128 if (ws->sessionManager()->state() == SessionState::Saving) {
129 return false; // ksmserver doesn't queue requests (yet)
130 }
131
132 if (!all().contains(id)) {
133 return false; // bogus id
134 }
135
137
138 QDBusInterface ksmserver("org.kde.ksmserver", "/KSMServer", "org.kde.KSMServerInterface");
139 if (ksmserver.isValid()) {
140 ksmserver.asyncCall("restoreSubSession", id);
141 } else {
142 qCDebug(KWIN_CORE) << "couldn't get ksmserver interface";
143 return false;
144 }
145 return true;
146}
147
148bool Activities::stop(const QString &id)
149{
150 if (Workspace::self()->sessionManager()->state() == SessionState::Saving) {
151 return false; // ksmserver doesn't queue requests (yet)
152 // FIXME what about session *loading*?
153 }
154
155 // ugly hack to avoid dbus deadlocks
156 QMetaObject::invokeMethod(
157 this, [this, id] {
158 reallyStop(id);
159 },
160 Qt::QueuedConnection);
161 // then lie and assume it worked.
162 return true;
163}
164
165void Activities::reallyStop(const QString &id)
166{
168 if (ws->sessionManager()->state() == SessionState::Saving) {
169 return; // ksmserver doesn't queue requests (yet)
170 }
171
172 qCDebug(KWIN_CORE) << id;
173
174 QSet<QByteArray> saveSessionIds;
175 QSet<QByteArray> dontCloseSessionIds;
176 const auto windows = ws->windows();
177 for (auto *const window : windows) {
178 auto x11Window = qobject_cast<X11Window *>(window);
179 if (!x11Window || window->isUnmanaged()) {
180 continue;
181 }
182 if (window->isDesktop()) {
183 continue;
184 }
185 const QByteArray sessionId = x11Window->sessionId();
186 if (sessionId.isEmpty()) {
187 continue; // TODO support old wm_command apps too?
188 }
189
190 // qDebug() << sessionId;
191
192 // if it's on the activity that's closing, it needs saving
193 // but if a process is on some other open activity, I don't wanna close it yet
194 // this is, of course, complicated by a process having many windows.
195 if (window->isOnAllActivities()) {
196 dontCloseSessionIds << sessionId;
197 continue;
198 }
199
200 const QStringList activities = window->activities();
201 for (const QString &activityId : activities) {
202 if (activityId == id) {
203 saveSessionIds << sessionId;
204 } else if (running().contains(activityId)) {
205 dontCloseSessionIds << sessionId;
206 }
207 }
208 }
209
210 ws->sessionManager()->storeSubSession(id, saveSessionIds);
211
212 QStringList saveAndClose;
213 QStringList saveOnly;
214 for (const QByteArray &sessionId : std::as_const(saveSessionIds)) {
215 if (dontCloseSessionIds.contains(sessionId)) {
216 saveOnly << sessionId;
217 } else {
218 saveAndClose << sessionId;
219 }
220 }
221
222 qCDebug(KWIN_CORE) << "saveActivity" << id << saveAndClose << saveOnly;
223
224 // pass off to ksmserver
225 QDBusInterface ksmserver("org.kde.ksmserver", "/KSMServer", "org.kde.KSMServerInterface");
226 if (ksmserver.isValid()) {
227 ksmserver.asyncCall("saveSubSession", id, saveAndClose, saveOnly);
228 } else {
229 qCDebug(KWIN_CORE) << "couldn't get ksmserver interface";
230 }
231}
232
233} // namespace
234
235#include "moc_activities.cpp"
void toggleWindowOnActivity(Window *window, const QString &activity, bool dont_activate)
void added(const QString &id)
QStringList all() const
Definition activities.h:83
KActivities::Controller::ServiceStatus serviceStatus() const
QStringList running() const
Definition activities.h:98
bool start(const QString &id)
bool stop(const QString &id)
void setCurrent(const QString &activity)
void currentChanged(const QString &id)
void removed(const QString &id)
bool focusPolicyIsReasonable
Definition options.h:113
void loadSubSessionInfo(const QString &name)
Definition sm.cpp:274
SessionState state() const
Definition sm.cpp:361
void storeSubSession(const QString &name, QSet< QByteArray > sessionIds)
Definition sm.cpp:182
bool isOnActivity(const QString &activity) const
Definition window.h:2042
bool wantsTabFocus() const
Definition window.cpp:697
bool isOnCurrentActivity() const
Definition window.cpp:3097
void setOnActivity(const QString &activity, bool enable)
Definition window.cpp:3116
const QList< Window * > & transients() const
Definition window.h:2088
bool isOnAllActivities() const
Definition window.h:2037
void updateClientArea()
void raiseWindow(Window *window, bool nogroup=false)
Definition layers.cpp:354
static Workspace * self()
Definition workspace.h:91
const QList< Window * > windows() const
Definition workspace.h:248
bool requestFocus(Window *window, bool force=false)
SessionManager * sessionManager() const
Definition workspace.h:799
void restackWindowUnderActive(Window *window)
Definition layers.cpp:464
QList< X11Window * > ensureStackingOrder(const QList< X11Window * > &windows) const
Definition layers.cpp:639
Options * options
Definition main.cpp:73