diff --git a/CMakeLists.txt b/CMakeLists.txt
index b432c0fb59..1fbaa3ee27 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -176,6 +176,8 @@ qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.Effects.xml effects.h KWin:
qt4_add_dbus_interface( kwin_KDEINIT_SRCS
${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/org.kde.KSMServerInterface.xml ksmserver_interface)
+qt4_add_dbus_interface( kwin_KDEINIT_SRCS
+ ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/dbus/org.freedesktop.ScreenSaver.xml screenlocker_interface)
qt4_add_resources( kwin_KDEINIT_SRCS resources.qrc )
diff --git a/effects.cpp b/effects.cpp
index b6eba83cc0..1d5ef69b7a 100644
--- a/effects.cpp
+++ b/effects.cpp
@@ -45,6 +45,8 @@ along with this program. If not, see .
#include
#include
#include
+#include
+#include
#include "kdebug.h"
#include "klibrary.h"
@@ -60,10 +62,104 @@ along with this program. If not, see .
#include "composite.h"
#include "xcbutils.h"
+// dbus generated
+#include "screenlocker_interface.h"
+
namespace KWin
{
+static const QString SCREEN_LOCKER_SERVICE_NAME = QString("org.freedesktop.ScreenSaver");
+
+ScreenLockerWatcher::ScreenLockerWatcher(QObject *parent)
+ : QObject(parent)
+ , m_interface(NULL)
+ , m_serviceWatcher(new QDBusServiceWatcher(this))
+ , m_locked(false)
+{
+ connect(m_serviceWatcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(serviceOwnerChanged(QString,QString,QString)));
+ m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForOwnerChange);
+ m_serviceWatcher->addWatchedService(SCREEN_LOCKER_SERVICE_NAME);
+ // check whether service is registered
+ QFutureWatcher > *watcher = new QFutureWatcher >(this);
+ connect(watcher, SIGNAL(finished()), SLOT(serviceRegisteredQueried()));
+ connect(watcher, SIGNAL(canceled()), watcher, SLOT(deleteLater()));
+ watcher->setFuture(QtConcurrent::run(QDBusConnection::sessionBus().interface(),
+ &QDBusConnectionInterface::isServiceRegistered,
+ SCREEN_LOCKER_SERVICE_NAME));
+}
+
+ScreenLockerWatcher::~ScreenLockerWatcher()
+{
+}
+
+void ScreenLockerWatcher::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
+{
+ Q_UNUSED(oldOwner)
+ if (serviceName != SCREEN_LOCKER_SERVICE_NAME) {
+ return;
+ }
+ delete m_interface;
+ m_interface = NULL;
+ m_locked = false;
+ if (!newOwner.isEmpty()) {
+ m_interface = new OrgFreedesktopScreenSaverInterface(newOwner, QString(), QDBusConnection::sessionBus(), this);
+ connect(m_interface, SIGNAL(ActiveChanged(bool)), SLOT(setLocked(bool)));
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_interface->GetActive(), this);
+ connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(activeQueried(QDBusPendingCallWatcher*)));
+ }
+}
+
+void ScreenLockerWatcher::serviceRegisteredQueried()
+{
+ QFutureWatcher > *watcher = dynamic_cast > *>(sender());
+ if (!watcher) {
+ return;
+ }
+ const QDBusReply &reply = watcher->result();
+ if (reply.isValid() && reply.value()) {
+ QFutureWatcher > *ownerWatcher = new QFutureWatcher >(this);
+ connect(ownerWatcher, SIGNAL(finished()), SLOT(serviceOwnerQueried()));
+ connect(ownerWatcher, SIGNAL(canceled()), ownerWatcher, SLOT(deleteLater()));
+ ownerWatcher->setFuture(QtConcurrent::run(QDBusConnection::sessionBus().interface(),
+ &QDBusConnectionInterface::serviceOwner,
+ SCREEN_LOCKER_SERVICE_NAME));
+ }
+ watcher->deleteLater();
+}
+
+void ScreenLockerWatcher::serviceOwnerQueried()
+{
+ QFutureWatcher > *watcher = dynamic_cast > *>(sender());
+ if (!watcher) {
+ return;
+ }
+ const QDBusReply reply = watcher->result();
+ if (reply.isValid()) {
+ serviceOwnerChanged(SCREEN_LOCKER_SERVICE_NAME, QString(), reply.value());
+ }
+
+ watcher->deleteLater();
+}
+
+void ScreenLockerWatcher::activeQueried(QDBusPendingCallWatcher *watcher)
+{
+ QDBusPendingReply reply = *watcher;
+ if (!reply.isError()) {
+ setLocked(reply.value());
+ }
+ watcher->deleteLater();
+}
+
+void ScreenLockerWatcher::setLocked(bool activated)
+{
+ if (m_locked == activated) {
+ return;
+ }
+ m_locked = activated;
+ emit locked(m_locked);
+}
+
//---------------------
// Static
@@ -112,6 +208,7 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
, mouse_poll_ref_count(0)
, m_compositor(compositor)
, m_scene(scene)
+ , m_screenLockerWatcher(new ScreenLockerWatcher(this))
{
new EffectsAdaptor(this);
QDBusConnection dbus = QDBusConnection::sessionBus();
@@ -144,6 +241,7 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
#ifdef KWIN_BUILD_SCREENEDGES
connect(ScreenEdges::self(), SIGNAL(approaching(ElectricBorder,qreal,QRect)), SIGNAL(screenEdgeApproaching(ElectricBorder,qreal,QRect)));
#endif
+ connect(m_screenLockerWatcher, SIGNAL(locked(bool)), SIGNAL(screenLockingChanged(bool)));
// connect all clients
foreach (Client *c, ws->clientList()) {
setupClientConnections(c);
@@ -1536,6 +1634,11 @@ QString EffectsHandlerImpl::supportInformation(const QString &name) const
return QString();
}
+bool EffectsHandlerImpl::isScreenLocked() const
+{
+ return m_screenLockerWatcher->isLocked();
+}
+
//****************************************
// EffectWindowImpl
//****************************************
diff --git a/effects.h b/effects.h
index 43724397c9..80a2915cac 100644
--- a/effects.h
+++ b/effects.h
@@ -30,8 +30,10 @@ along with this program. If not, see .
#include
#include
-
+class QDBusPendingCallWatcher;
+class QDBusServiceWatcher;
class KService;
+class OrgFreedesktopScreenSaverInterface;
namespace KWin
@@ -44,6 +46,7 @@ class Client;
class Compositor;
class Deleted;
class Unmanaged;
+class ScreenLockerWatcher;
class EffectsHandlerImpl : public EffectsHandler
{
@@ -160,6 +163,7 @@ public:
virtual EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize, const QPoint& position, Qt::Alignment alignment) const;
virtual QVariant kwinOption(KWinOption kwopt);
+ virtual bool isScreenLocked() const;
// internal (used by kwin core or compositing code)
void startPaint();
@@ -241,6 +245,7 @@ private:
Compositor *m_compositor;
Scene *m_scene;
QList< InputWindowPair > input_windows;
+ ScreenLockerWatcher *m_screenLockerWatcher;
};
class EffectWindowImpl : public EffectWindow
@@ -386,6 +391,29 @@ private:
GLShader* m_shader;
};
+class ScreenLockerWatcher : public QObject
+{
+ Q_OBJECT
+public:
+ explicit ScreenLockerWatcher(QObject *parent = 0);
+ virtual ~ScreenLockerWatcher();
+ bool isLocked() const {
+ return m_locked;
+ }
+Q_SIGNALS:
+ void locked(bool locked);
+private Q_SLOTS:
+ void setLocked(bool activated);
+ void activeQueried(QDBusPendingCallWatcher *watcher);
+ void serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner);
+ void serviceRegisteredQueried();
+ void serviceOwnerQueried();
+private:
+ OrgFreedesktopScreenSaverInterface *m_interface;
+ QDBusServiceWatcher *m_serviceWatcher;
+ bool m_locked;
+};
+
inline
QList EffectsHandlerImpl::elevatedWindows() const
{
diff --git a/effects/mousemark/mousemark.cpp b/effects/mousemark/mousemark.cpp
index 5a0c8351bc..dc53015a30 100644
--- a/effects/mousemark/mousemark.cpp
+++ b/effects/mousemark/mousemark.cpp
@@ -59,6 +59,7 @@ MouseMarkEffect::MouseMarkEffect()
connect(a, SIGNAL(triggered(bool)), this, SLOT(clearLast()));
connect(effects, SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)),
this, SLOT(slotMouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)));
+ connect(effects, SIGNAL(screenLockingChanged(bool)), SLOT(screenLockingChanged(bool)));
reconfigure(ReconfigureAll);
arrow_start = NULL_POINT;
effects->startMousePolling(); // We require it to detect activation as well
@@ -239,9 +240,22 @@ MouseMarkEffect::Mark MouseMarkEffect::createArrow(QPoint arrow_start, QPoint ar
return ret;
}
+void MouseMarkEffect::screenLockingChanged(bool locked)
+{
+ if (!marks.isEmpty() || !drawing.isEmpty()) {
+ effects->addRepaintFull();
+ }
+ // disable mouse polling while screen is locked.
+ if (locked) {
+ effects->stopMousePolling();
+ } else {
+ effects->startMousePolling();
+ }
+}
+
bool MouseMarkEffect::isActive() const
{
- return !marks.isEmpty() || !drawing.isEmpty();
+ return (!marks.isEmpty() || !drawing.isEmpty()) && !effects->isScreenLocked();
}
diff --git a/effects/mousemark/mousemark.h b/effects/mousemark/mousemark.h
index e4bcf13b81..45e9f8dd41 100644
--- a/effects/mousemark/mousemark.h
+++ b/effects/mousemark/mousemark.h
@@ -56,6 +56,7 @@ private slots:
void slotMouseChanged(const QPoint& pos, const QPoint& old,
Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons,
Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers);
+ void screenLockingChanged(bool locked);
private:
typedef QVector< QPoint > Mark;
static Mark createArrow(QPoint arrow_start, QPoint arrow_end);
diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp
index dfbb2c72bc..af62a706db 100644
--- a/effects/screenshot/screenshot.cpp
+++ b/effects/screenshot/screenshot.cpp
@@ -353,7 +353,7 @@ void ScreenShotEffect::convertFromGLImage(QImage &img, int w, int h)
bool ScreenShotEffect::isActive() const
{
- return m_scheduledScreenshot != NULL;
+ return m_scheduledScreenshot != NULL && !effects->isScreenLocked();
}
void ScreenShotEffect::windowClosed( EffectWindow* w )
diff --git a/effects/taskbarthumbnail/taskbarthumbnail.cpp b/effects/taskbarthumbnail/taskbarthumbnail.cpp
index 056796eaad..7319a93644 100644
--- a/effects/taskbarthumbnail/taskbarthumbnail.cpp
+++ b/effects/taskbarthumbnail/taskbarthumbnail.cpp
@@ -41,6 +41,7 @@ TaskbarThumbnailEffect::TaskbarThumbnailEffect()
connect(effects, SIGNAL(windowDeleted(KWin::EffectWindow*)), this, SLOT(slotWindowDeleted(KWin::EffectWindow*)));
connect(effects, SIGNAL(windowDamaged(KWin::EffectWindow*,QRect)), this, SLOT(slotWindowDamaged(KWin::EffectWindow*,QRect)));
connect(effects, SIGNAL(propertyNotify(KWin::EffectWindow*,long)), this, SLOT(slotPropertyNotify(KWin::EffectWindow*,long)));
+ connect(effects, SIGNAL(screenLockingChanged(bool)), SLOT(screenLockingChanged()));
}
TaskbarThumbnailEffect::~TaskbarThumbnailEffect()
@@ -147,9 +148,16 @@ void TaskbarThumbnailEffect::slotPropertyNotify(EffectWindow* w, long a)
}
}
+void TaskbarThumbnailEffect::screenLockingChanged()
+{
+ foreach (EffectWindow *window, thumbnails.uniqueKeys()) {
+ window->addRepaintFull();
+ }
+}
+
bool TaskbarThumbnailEffect::isActive() const
{
- return !thumbnails.isEmpty();
+ return !thumbnails.isEmpty() && !effects->isScreenLocked();
}
} // namespace
diff --git a/effects/taskbarthumbnail/taskbarthumbnail.h b/effects/taskbarthumbnail/taskbarthumbnail.h
index 2fb6e39d98..50f70401fd 100644
--- a/effects/taskbarthumbnail/taskbarthumbnail.h
+++ b/effects/taskbarthumbnail/taskbarthumbnail.h
@@ -45,6 +45,7 @@ public Q_SLOTS:
void slotWindowDeleted(KWin::EffectWindow *w);
void slotWindowDamaged(KWin::EffectWindow* w, const QRect& damage);
void slotPropertyNotify(KWin::EffectWindow *w, long atom);
+ void screenLockingChanged();
private:
struct Data {
Window window; // thumbnail of this window
diff --git a/effects/thumbnailaside/thumbnailaside.cpp b/effects/thumbnailaside/thumbnailaside.cpp
index 2a1f557374..29687c0691 100644
--- a/effects/thumbnailaside/thumbnailaside.cpp
+++ b/effects/thumbnailaside/thumbnailaside.cpp
@@ -42,6 +42,7 @@ ThumbnailAsideEffect::ThumbnailAsideEffect()
connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*)));
connect(effects, SIGNAL(windowGeometryShapeChanged(KWin::EffectWindow*,QRect)), this, SLOT(slotWindowGeometryShapeChanged(KWin::EffectWindow*,QRect)));
connect(effects, SIGNAL(windowDamaged(KWin::EffectWindow*,QRect)), this, SLOT(slotWindowDamaged(KWin::EffectWindow*,QRect)));
+ connect(effects, SIGNAL(screenLockingChanged(bool)), SLOT(repaintAll()));
reconfigure(ReconfigureAll);
}
@@ -182,7 +183,7 @@ void ThumbnailAsideEffect::repaintAll()
bool ThumbnailAsideEffect::isActive() const
{
- return !windows.isEmpty();
+ return !windows.isEmpty() && !effects->isScreenLocked();
}
} // namespace
diff --git a/effects/thumbnailaside/thumbnailaside.h b/effects/thumbnailaside/thumbnailaside.h
index 98f65447b2..2c3cb05578 100644
--- a/effects/thumbnailaside/thumbnailaside.h
+++ b/effects/thumbnailaside/thumbnailaside.h
@@ -68,11 +68,11 @@ private slots:
void slotWindowGeometryShapeChanged(KWin::EffectWindow *w, const QRect &old);
void slotWindowDamaged(KWin::EffectWindow* w, const QRect& damage);
virtual bool isActive() const;
+ void repaintAll();
private:
void addThumbnail(EffectWindow* w);
void removeThumbnail(EffectWindow* w);
void arrange();
- void repaintAll();
struct Data {
EffectWindow* window; // the same like the key in the hash (makes code simpler)
int index;
diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h
index 7f0e790947..08be2e4f3a 100644
--- a/libkwineffects/kwineffects.h
+++ b/libkwineffects/kwineffects.h
@@ -875,6 +875,18 @@ public:
**/
virtual void reloadEffect(Effect *effect) = 0;
+ /**
+ * Whether the screen is currently considered as locked.
+ * Note for technical reasons this is not always possible to detect. The screen will only
+ * be considered as locked if the screen locking process implements the
+ * org.freedesktop.ScreenSaver interface.
+ *
+ * @returns @c true if the screen is currently locked, @c false otherwise
+ * @see screenLockingChanged
+ * @since 4.11
+ **/
+ virtual bool isScreenLocked() const = 0;
+
/**
* Sends message over DCOP to reload given effect.
* @param effectname effect's name without "kwin4_effect_" prefix.
@@ -1155,6 +1167,12 @@ Q_SIGNALS:
* @since 4.9
*/
void activityRemoved(const QString &id);
+ /**
+ * This signal is emitted when the screen got locked or unlocked.
+ * @param locked @c true if the screen is now locked, @c false if it is now unlocked
+ * @since 4.11
+ **/
+ void screenLockingChanged(bool locked);
/**
* This signels is emitted when ever the stacking order is change, ie. a window is risen