From 10c07080bbe7dd58ad82943ab64af8c3cfc0e526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 30 Jan 2013 13:07:59 +0100 Subject: [PATCH] Notify effects when the screen gets locked EffectsHandlerImpl starts to monitor DBus for the screen being locked and provides this information to the Effect system by allowing them to ask whether the screen is currently locked and by emitting a signal when the screen gets locked/unlocked. This information is needed to ensure that no private data is shown on the screen. The following effects are adjusted: * taskbar thumbnails * thumbnail aside * mouse mark * screen shot BUG: 255712 FIXED-IN: 4.11 REVIEW: 108670 --- CMakeLists.txt | 2 + effects.cpp | 103 ++++++++++++++++++ effects.h | 30 ++++- effects/mousemark/mousemark.cpp | 16 ++- effects/mousemark/mousemark.h | 1 + effects/screenshot/screenshot.cpp | 2 +- effects/taskbarthumbnail/taskbarthumbnail.cpp | 10 +- effects/taskbarthumbnail/taskbarthumbnail.h | 1 + effects/thumbnailaside/thumbnailaside.cpp | 3 +- effects/thumbnailaside/thumbnailaside.h | 2 +- libkwineffects/kwineffects.h | 18 +++ 11 files changed, 182 insertions(+), 6 deletions(-) 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