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