• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kde-workspace API Reference
  • KDE Home
  • Contact Us
 

KWin

  • kde-4.x
  • kde-workspace
  • kwin
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 Copyright (C) 2013 Martin Gräßlin <[email protected]>
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include "activities.h"
21 // KWin
22 #include "client.h"
23 #include "workspace.h"
24 // KDE
25 #include <KConfigGroup>
26 #include <kactivities/controller.h>
27 // Qt
28 #include <QtConcurrentRun>
29 #include <QDBusInterface>
30 #include <QDBusPendingCall>
31 #include <QFutureWatcher>
32 
33 namespace KWin
34 {
35 
36 KWIN_SINGLETON_FACTORY(Activities)
37 
38 Activities::Activities(QObject *parent)
39  : QObject(parent)
40  , m_controller(new KActivities::Controller(this))
41 {
42  connect(m_controller, &KActivities::Controller::activityRemoved, this, &Activities::slotRemoved);
43  connect(m_controller, &KActivities::Controller::activityRemoved, this, &Activities::removed);
44  connect(m_controller, &KActivities::Controller::activityAdded, this, &Activities::slotAdded);
45  connect(m_controller, &KActivities::Controller::activityAdded, this, &Activities::added);
46  connect(m_controller, &KActivities::Controller::currentActivityChanged, this, &Activities::slotCurrentChanged);
47 }
48 
49 Activities::~Activities()
50 {
51  s_self = NULL;
52 }
53 
54 void Activities::setCurrent(const QString &activity)
55 {
56  m_controller->setCurrentActivity(activity);
57 }
58 
59 void Activities::slotCurrentChanged(const QString &newActivity)
60 {
61  if (m_current == newActivity) {
62  return;
63  }
64  m_previous = m_current;
65  m_current = newActivity;
66  emit currentChanged(newActivity);
67 }
68 
69 void Activities::slotAdded(const QString &activity)
70 {
71  m_all << activity;
72 }
73 
74 void Activities::slotRemoved(const QString &activity)
75 {
76  m_all.removeOne(activity);
77  foreach (Client * client, Workspace::self()->clientList()) {
78  client->setOnActivity(activity, false);
79  }
80  //toss out any session data for it
81  KConfigGroup cg(KSharedConfig::openConfig(), QString("SubSession: ") + activity);
82  cg.deleteGroup();
83 }
84 
85 void Activities::toggleClientOnActivity(Client* c, const QString &activity, bool dont_activate)
86 {
87  //int old_desktop = c->desktop();
88  bool was_on_activity = c->isOnActivity(activity);
89  bool was_on_all = c->isOnAllActivities();
90  //note: all activities === no activities
91  bool enable = was_on_all || !was_on_activity;
92  c->setOnActivity(activity, enable);
93  if (c->isOnActivity(activity) == was_on_activity && c->isOnAllActivities() == was_on_all) // No change
94  return;
95 
96  Workspace *ws = Workspace::self();
97  if (c->isOnCurrentActivity()) {
98  if (c->wantsTabFocus() && options->focusPolicyIsReasonable() &&
99  !was_on_activity && // for stickyness changes
100  //FIXME not sure if the line above refers to the correct activity
101  !dont_activate)
102  ws->requestFocus(c);
103  else
104  ws->restackClientUnderActive(c);
105  } else
106  ws->raiseClient(c);
107 
108  //notifyWindowDesktopChanged( c, old_desktop );
109 
110  ClientList transients_stacking_order = ws->ensureStackingOrder(c->transients());
111  for (ClientList::ConstIterator it = transients_stacking_order.constBegin();
112  it != transients_stacking_order.constEnd();
113  ++it)
114  toggleClientOnActivity(*it, activity, dont_activate);
115  ws->updateClientArea();
116 }
117 
118 bool Activities::start(const QString &id)
119 {
120  Workspace *ws = Workspace::self();
121  if (ws->sessionSaving()) {
122  return false; //ksmserver doesn't queue requests (yet)
123  }
124 
125  if (!m_all.contains(id)) {
126  return false; //bogus id
127  }
128 
129  ws->loadSubSessionInfo(id);
130 
131  QDBusInterface ksmserver("org.kde.ksmserver", "/KSMServer", "org.kde.KSMServerInterface");
132  if (ksmserver.isValid()) {
133  ksmserver.asyncCall("restoreSubSession", id);
134  } else {
135  qDebug() << "couldn't get ksmserver interface";
136  return false;
137  }
138  return true;
139 }
140 
141 bool Activities::stop(const QString &id)
142 {
143  if (Workspace::self()->sessionSaving()) {
144  return false; //ksmserver doesn't queue requests (yet)
145  //FIXME what about session *loading*?
146  }
147 
148  //ugly hack to avoid dbus deadlocks
149  update(true, false);
150  QMetaObject::invokeMethod(this, "reallyStop", Qt::QueuedConnection, Q_ARG(QString, id));
151  //then lie and assume it worked.
152  return true;
153 }
154 
155 void Activities::reallyStop(const QString &id)
156 {
157  Workspace *ws = Workspace::self();
158  if (ws->sessionSaving())
159  return; //ksmserver doesn't queue requests (yet)
160 
161  qDebug() << id;
162 
163  QSet<QByteArray> saveSessionIds;
164  QSet<QByteArray> dontCloseSessionIds;
165  const ClientList &clients = ws->clientList();
166  for (ClientList::const_iterator it = clients.constBegin(); it != clients.constEnd(); ++it) {
167  const Client* c = (*it);
168  const QByteArray sessionId = c->sessionId();
169  if (sessionId.isEmpty()) {
170  continue; //TODO support old wm_command apps too?
171  }
172 
173  //qDebug() << sessionId;
174 
175  //if it's on the activity that's closing, it needs saving
176  //but if a process is on some other open activity, I don't wanna close it yet
177  //this is, of course, complicated by a process having many windows.
178  if (c->isOnAllActivities()) {
179  dontCloseSessionIds << sessionId;
180  continue;
181  }
182 
183  const QStringList activities = c->activities();
184  foreach (const QString & activityId, activities) {
185  if (activityId == id) {
186  saveSessionIds << sessionId;
187  } else if (m_running.contains(activityId)) {
188  dontCloseSessionIds << sessionId;
189  }
190  }
191  }
192 
193  ws->storeSubSession(id, saveSessionIds);
194 
195  QStringList saveAndClose;
196  QStringList saveOnly;
197  foreach (const QByteArray & sessionId, saveSessionIds) {
198  if (dontCloseSessionIds.contains(sessionId)) {
199  saveOnly << sessionId;
200  } else {
201  saveAndClose << sessionId;
202  }
203  }
204 
205  qDebug() << "saveActivity" << id << saveAndClose << saveOnly;
206 
207  //pass off to ksmserver
208  QDBusInterface ksmserver("org.kde.ksmserver", "/KSMServer", "org.kde.KSMServerInterface");
209  if (ksmserver.isValid()) {
210  ksmserver.asyncCall("saveSubSession", id, saveAndClose, saveOnly);
211  } else {
212  qDebug() << "couldn't get ksmserver interface";
213  }
214 }
215 
216 //BEGIN threaded activity list fetching
217 typedef QPair<QStringList*, QStringList> AssignedList;
218 typedef QPair<QString, QStringList> CurrentAndList;
219 
220 static AssignedList
221 fetchActivityList(KActivities::Controller *controller, QStringList *target, bool running) // could be member function, but actually it's much simpler this way
222 {
223  return AssignedList(target, running ? controller->activities(KActivities::Info::Running) :
224  controller->activities());
225 }
226 
227 static CurrentAndList
228 fetchActivityListAndCurrent(KActivities::Controller *controller)
229 {
230  QStringList l = controller->activities();
231  QString c = controller->currentActivity();
232  return CurrentAndList(c, l);
233 }
234 
235 void Activities::update(bool running, bool updateCurrent, QObject *target, QString slot)
236 {
237  if (updateCurrent) {
238  QFutureWatcher<CurrentAndList>* watcher = new QFutureWatcher<CurrentAndList>;
239  connect( watcher, SIGNAL(finished()), SLOT(handleReply()) );
240  if (!slot.isEmpty()) {
241  watcher->setProperty("activityControllerCallback", slot); // "activity reply trigger"
242  watcher->setProperty("activityControllerCallbackTarget", qVariantFromValue((void*)target));
243  }
244  watcher->setFuture(QtConcurrent::run(fetchActivityListAndCurrent, m_controller));
245  } else {
246  QFutureWatcher<AssignedList>* watcher = new QFutureWatcher<AssignedList>;
247  connect(watcher, SIGNAL(finished()), SLOT(handleReply()));
248  if (!slot.isEmpty()) {
249  watcher->setProperty("activityControllerCallback", slot); // "activity reply trigger"
250  watcher->setProperty("activityControllerCallbackTarget", qVariantFromValue((void*)target));
251  }
252  QStringList *target = running ? &m_running : &m_all;
253  watcher->setFuture(QtConcurrent::run(fetchActivityList, m_controller, target, running));
254  }
255 }
256 
257 void Activities::handleReply()
258 {
259  QObject *watcherObject = 0;
260  if (QFutureWatcher<AssignedList>* watcher = dynamic_cast< QFutureWatcher<AssignedList>* >(sender())) {
261  // we carry over the to-be-updated StringList member as pointer in the threaded return
262  *(watcher->result().first) = watcher->result().second;
263  watcherObject = watcher;
264  }
265 
266  if (!watcherObject) {
267  if (QFutureWatcher<CurrentAndList>* watcher = dynamic_cast< QFutureWatcher<CurrentAndList>* >(sender())) {
268  m_all = watcher->result().second;
269  slotCurrentChanged(watcher->result().first);
270  watcherObject = watcher;
271  }
272  }
273 
274  if (watcherObject) {
275  QString slot = watcherObject->property("activityControllerCallback").toString();
276  QObject *target = static_cast<QObject*>(watcherObject->property("activityControllerCallbackTarget").value<void*>());
277  watcherObject->deleteLater(); // has done it's job
278  if (!slot.isEmpty())
279  QMetaObject::invokeMethod(target, slot.toAscii().data(), Qt::DirectConnection);
280  }
281 }
282 //END threaded activity list fetching
283 
284 } // namespace
KWin::Workspace::updateClientArea
void updateClientArea()
Definition: geometry.cpp:251
QDBusAbstractInterface::isValid
bool isValid() const
QByteArray
QObject::sender
QObject * sender() const
KWin::Toplevel::isOnActivity
bool isOnActivity(const QString &activity) const
Definition: toplevel.h:640
KWin::options
Options * options
Definition: main.cpp:67
KWin::Activities::removed
void removed(const QString &id)
This signal is emitted when the activity is removed.
KWin::Workspace::storeSubSession
void storeSubSession(const QString &name, QSet< QByteArray > sessionIds)
Definition: sm.cpp:163
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
QByteArray::isEmpty
bool isEmpty() const
KWin::Activities::added
void added(const QString &id)
This signal is emitted when a new activity is added.
KWin::Workspace
Definition: workspace.h:60
QVariant::value
T value() const
KWin::CurrentAndList
QPair< QString, QStringList > CurrentAndList
Definition: activities.cpp:218
KWin::Workspace::restackClientUnderActive
void restackClientUnderActive(Client *)
Definition: layers.cpp:462
KWin::Activities::~Activities
~Activities()
Definition: activities.cpp:49
QList::const_iterator
KWin::Client::wantsTabFocus
bool wantsTabFocus() const
Definition: client.cpp:2252
KWin::Toplevel::isOnAllActivities
bool isOnAllActivities() const
Definition: toplevel.h:630
KWin::Workspace::clientList
const ClientList & clientList() const
Definition: workspace.h:192
KWin::Workspace::sessionSaving
bool sessionSaving() const
Definition: workspace.h:664
KWin::Activities::currentChanged
void currentChanged(const QString &id)
This signal is emitted when the global activity is changed.
workspace.h
QObject::property
QVariant property(const char *name) const
KWin::AssignedList
QPair< QStringList *, QStringList > AssignedList
Definition: activities.cpp:217
KWin::Workspace::loadSubSessionInfo
void loadSubSessionInfo(const QString &name)
Definition: sm.cpp:246
QObject
KWin::Activities::start
bool start(const QString &id)
Definition: activities.cpp:118
QString::isEmpty
bool isEmpty() const
KWin::Workspace::raiseClient
void raiseClient(Client *c, bool nogroup=false)
Definition: layers.cpp:364
QtConcurrent::run
QFuture< T > run(Function function,...)
KWin::Activities::update
void update(bool running, bool updateCurrent, QObject *target=NULL, QString slot=QString())
Definition: activities.cpp:235
QSet
QObject::deleteLater
void deleteLater()
KWin::Workspace::self
static Workspace * self()
Definition: workspace.h:67
QString
QList
KWin::Activities::stop
bool stop(const QString &id)
Definition: activities.cpp:141
KWin::Toplevel::isOnCurrentActivity
bool isOnCurrentActivity() const
Definition: toplevel.cpp:441
activities.h
QFutureWatcher::setFuture
void setFuture(const QFuture< T > &future)
KWin::fetchActivityListAndCurrent
static CurrentAndList fetchActivityListAndCurrent(KActivities::Controller *controller)
Definition: activities.cpp:228
QStringList
QPair
QDBusInterface
KWin::Toplevel::sessionId
QByteArray sessionId() const
Definition: toplevel.cpp:194
QMetaObject::invokeMethod
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
QSet::contains
bool contains(const T &value) const
KWin::Options::focusPolicyIsReasonable
bool focusPolicyIsReasonable
Definition: options.h:90
KWin::Activities::setCurrent
void setCurrent(const QString &activity)
Definition: activities.cpp:54
KWin::Client::transients
const ClientList & transients() const
Definition: client.h:1080
QList::ConstIterator
typedef ConstIterator
KWin::fetchActivityList
static AssignedList fetchActivityList(KActivities::Controller *controller, QStringList *target, bool running)
Definition: activities.cpp:221
KWin::Activities::toggleClientOnActivity
void toggleClientOnActivity(Client *c, const QString &activity, bool dont_activate)
Adds/removes client c to/from activity.
Definition: activities.cpp:85
KWin::Workspace::requestFocus
void requestFocus(Client *c, bool force=false)
Definition: activation.cpp:336
QFutureWatcher
Definition: client_machine.h:29
QByteArray::data
char * data()
QObject::setProperty
bool setProperty(const char *name, const QVariant &value)
client.h
QList::constEnd
const_iterator constEnd() const
KWin::Client
The Client class encapsulates a window decoration frame.
Definition: client.h:71
QList::constBegin
const_iterator constBegin() const
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QDBusAbstractInterface::asyncCall
QDBusPendingCall asyncCall(const QString &method, const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8)
QVariant::toString
QString toString() const
QList::removeOne
bool removeOne(const T &value)
KWin::Client::activities
virtual QStringList activities() const
Returns the list of activities the client window is on.
Definition: client.cpp:1692
KWin::Client::setOnActivity
void setOnActivity(const QString &activity, bool enable)
Sets whether the client is on activity.
Definition: client.cpp:1591
KWin::Workspace::ensureStackingOrder
ClientList ensureStackingOrder(const ClientList &clients) const
Definition: layers.cpp:624
QString::toAscii
QByteArray toAscii() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Thu Dec 5 2019 03:47:05 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KWin

Skip menu "KWin"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kde-workspace API Reference

Skip menu "kde-workspace API Reference"
  • KWin
  •   KWin Decoration Library
  •   KWin Effects Library
  • Plasma
  • Plasma
  •   Applets
  •   Engines
  •   libkworkspace
  •   libtaskmanager
  • System Settings
  •   SystemSettingsView

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal