diff --git a/kwin/CMakeLists.txt b/kwin/CMakeLists.txt
index 45651c1..1405aa6 100644
--- a/kwin/CMakeLists.txt
+++ b/kwin/CMakeLists.txt
@@ -46,21 +46,29 @@ OPTION(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON)
OPTION(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON)
OPTION(KWIN_MOBILE_EFFECTS "Only build effects relevant for mobile devices" OFF)
+# screensaver/locking stuff:
+macro_bool_to_01(X11_Xscreensaver_FOUND HAVE_XSCREENSAVER)
+macro_log_feature(HAVE_XSCREENSAVER "libxss" "XScreenSaver Library" "http://www.x.org/" FALSE "" "Needed to enable screensaver status check")
+
# for things that are also used by kwin libraries
configure_file(libkwineffects/kwinconfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/libkwineffects/kwinconfig.h )
# for kwin internal things
configure_file(config-kwin.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwin.h )
-
+# for screensaver/locking
+configure_file(screenlocker/config-xautolock.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/screenlocker/config-xautolock.h)
########### global ###############
include_directories(
${CMAKE_CURRENT_BINARY_DIR}/libkwineffects
${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/screenlocker
${CMAKE_CURRENT_SOURCE_DIR}/libkwineffects
${CMAKE_CURRENT_SOURCE_DIR}/libkdecorations
${CMAKE_CURRENT_SOURCE_DIR}/effects
${CMAKE_CURRENT_SOURCE_DIR}/tabbox
+ ${CMAKE_CURRENT_SOURCE_DIR}/screenlocker/
+ ${CMAKE_CURRENT_SOURCE_DIR}/screenlocker/screensaver
${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kephal
${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kworkspace
)
@@ -159,8 +167,23 @@ set(kwin_KDEINIT_SRCS
# floating
tilinglayouts/floating/floating.cpp
+
+ # screensaver activation
+ screenlocker/screenlocker.cpp
+ screenlocker/screensaver/saverengine.cpp
+ screenlocker/screensaver/xautolock.cpp
+ screenlocker/screensaver/xautolock_diy.c
+ screenlocker/screensaver/xautolock_engine.c
)
+set(screensaver_dbusXML screenlocker/dbus/org.freedesktop.ScreenSaver.xml)
+set(kscreensaver_dbusXML screenlocker/dbus/org.kde.screensaver.xml)
+
+kde4_add_kcfg_files( kwin_KDEINIT_SRCS screenlocker/kcfg/kscreensaversettings.kcfgc )
+
+qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS ${screensaver_dbusXML} saverengine.h SaverEngine)
+qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS ${kscreensaver_dbusXML} saverengine.h SaverEngine kscreensaveradaptor KScreenSaverAdaptor)
+
qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWin::Workspace )
qt4_add_dbus_interface( kwin_KDEINIT_SRCS
@@ -172,6 +195,10 @@ kde4_add_kdeinit_executable( kwin ${kwin_KDEINIT_SRCS})
target_link_libraries(kdeinit_kwin ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTXML_LIBRARY} ${QT_QTSCRIPT_LIBRARY} kephal kworkspace kdecorations kwineffects ${X11_LIBRARIES})
+if(X11_Xscreensaver_FOUND)
+ target_link_libraries(kdeinit_kwin ${kwinLibs} ${X11_Xscreensaver_LIB})
+endif(X11_Xscreensaver_FOUND)
+
if(OPENGL_FOUND AND NOT KWIN_HAVE_OPENGLES_COMPOSITING)
add_subdirectory(opengltest)
target_link_libraries(kdeinit_kwin ${OPENGL_gl_LIBRARY})
@@ -224,6 +251,8 @@ install(TARGETS kwinnvidiahack ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_
install( FILES kwin.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
install( FILES kwin.notifyrc DESTINATION ${DATA_INSTALL_DIR}/kwin )
install( FILES org.kde.KWin.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
+install( FILES ${screensaver_dbusXML} DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
+install( FILES ${kscreensaver_dbusXML} DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
install( FILES tabbox/DefaultTabBoxLayouts.xml DESTINATION ${DATA_INSTALL_DIR}/kwin )
kde4_install_icons( ${ICON_INSTALL_DIR} )
diff --git a/kwin/effects.cpp b/kwin/effects.cpp
index f5863fc0..d537fa5 100644
--- a/kwin/effects.cpp
+++ b/kwin/effects.cpp
@@ -30,6 +30,7 @@ along with this program. If not, see .
#include "tabbox.h"
#include "workspace.h"
#include "kwinglutils.h"
+#include "screenlocker/screenlocker.h"
#include
@@ -96,6 +97,7 @@ EffectsHandlerImpl::EffectsHandlerImpl(CompositingType type)
, next_window_quad_type(EFFECT_QUAD_TYPE_START)
, mouse_poll_ref_count(0)
, current_paint_effectframe(0)
+ , m_activeScreenLockEffect(NULL)
{
Workspace *ws = Workspace::self();
connect(ws, SIGNAL(currentDesktopChanged(int)), this, SLOT(slotDesktopChanged(int)));
@@ -1189,6 +1191,17 @@ EffectFrame* EffectsHandlerImpl::effectFrame(EffectFrameStyle style, bool static
return new EffectFrameImpl(style, staticSize, position, alignment);
}
+
+QVariant EffectsHandlerImpl::kwinOption(KWinOption kwopt)
+{
+ switch (kwopt)
+ {
+ case CloseButtonCorner:
+ return Workspace::self()->decorationCloseButtonCorner();
+ }
+ return QVariant(); // an invalid one
+}
+
void EffectsHandlerImpl::slotShowOutline(const QRect& geometry)
{
emit showOutline(geometry);
@@ -1199,6 +1212,37 @@ void EffectsHandlerImpl::slotHideOutline()
emit hideOutline();
}
+static bool s_prepareLock = false;
+bool EffectsHandlerImpl::lockScreen()
+{
+ s_prepareLock = true;
+ emit requestScreenLock();
+ s_prepareLock = false;
+ return isScreenLockerReferenced();
+}
+
+void EffectsHandlerImpl::refScreenLocker(Effect* lockEffect)
+{
+ if (m_activeScreenLockEffect || !s_prepareLock) {
+ return;
+ }
+ m_activeScreenLockEffect = lockEffect;
+}
+
+void EffectsHandlerImpl::unrefScreenLocker(Effect* lockEffect)
+{
+ if (m_activeScreenLockEffect != lockEffect) {
+ return;
+ }
+ m_activeScreenLockEffect = NULL;
+ Workspace::self()->screenLocker()->unlock();
+}
+
+bool EffectsHandlerImpl::isScreenLockerReferenced() const
+{
+ return m_activeScreenLockEffect != NULL;
+}
+
//****************************************
// EffectWindowImpl
//****************************************
diff --git a/kwin/effects.h b/kwin/effects.h
index abff777..3a626b1 100644
--- a/kwin/effects.h
+++ b/kwin/effects.h
@@ -151,6 +151,12 @@ public:
virtual EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize, const QPoint& position, Qt::Alignment alignment) const;
+ virtual QVariant kwinOption(KWinOption kwopt);
+
+ virtual void refScreenLocker(Effect *lockEffect);
+ virtual void unrefScreenLocker(Effect *lockEffect);
+ virtual bool isScreenLockerReferenced() const;
+
// internal (used by kwin core or compositing code)
void startPaint();
bool borderActivated(ElectricBorder border);
@@ -167,6 +173,13 @@ public:
QList elevatedWindows() const;
+ /**
+ * Passes the request to lock the screen to the effects and returns whether an effect
+ * will handle the screen locking.
+ * @returns @c true in case an effect handles the screen locking, @c false otherwise.
+ **/
+ bool lockScreen();
+
public Q_SLOTS:
void slotClientGroupItemSwitched(EffectWindow* from, EffectWindow* to);
void slotClientGroupItemAdded(EffectWindow* from, EffectWindow* to);
@@ -209,6 +222,15 @@ protected:
int next_window_quad_type;
int mouse_poll_ref_count;
int current_paint_effectframe;
+
+private:
+ QList< Effect* > m_activeEffects;
+ QList< Effect* >::iterator m_currentDrawWindowIterator;
+ QList< Effect* >::iterator m_currentPaintWindowIterator;
+ QList< Effect* >::iterator m_currentPaintEffectFrameIterator;
+ QList< Effect* >::iterator m_currentPaintScreenIterator;
+ QList< Effect* >::iterator m_currentBuildQuadsIterator;
+ Effect *m_activeScreenLockEffect;
};
class EffectWindowImpl : public EffectWindow
diff --git a/kwin/effects/CMakeLists.txt b/kwin/effects/CMakeLists.txt
index 0312ac2..fa47082 100644
--- a/kwin/effects/CMakeLists.txt
+++ b/kwin/effects/CMakeLists.txt
@@ -7,7 +7,7 @@ kde4_no_enable_final(kwineffects)
# Adds effect plugin with given name. Sources are given after the name
macro( KWIN4_ADD_EFFECT name )
kde4_add_plugin( kwin4_effect_${name} ${ARGN} )
- target_link_libraries( kwin4_effect_${name} kwineffects ${KDE4_KDEUI_LIBS} kephal ${KDE4_PLASMA_LIBS} ${X11_Xfixes_LIB} ${X11_Xcursor_LIB})
+ target_link_libraries( kwin4_effect_${name} kwineffects ${KDE4_KDEUI_LIBS} kephal ${KDE4_PLASMA_LIBS} ${X11_Xfixes_LIB} ${X11_Xcursor_LIB} ${QT_QTDECLARATIVE_LIBRARY} kdeclarative)
if (X11_Xfixes_FOUND)
target_link_libraries(kwin4_effect_${name} ${X11_Xfixes_LIB})
endif (X11_Xfixes_FOUND)
@@ -62,6 +62,7 @@ include( fade/CMakeLists.txt )
include( login/CMakeLists.txt )
include( outline/CMakeLists.txt )
include( presentwindows/CMakeLists.txt )
+include( screenlocker/CMakeLists.txt )
include( slidingpopups/CMakeLists.txt )
include( taskbarthumbnail/CMakeLists.txt )
diff --git a/kwin/effects/presentwindows/presentwindows.cpp b/kwin/effects/presentwindows/presentwindows.cpp
index a0e8306..bea897b 100755
--- a/kwin/effects/presentwindows/presentwindows.cpp
+++ b/kwin/effects/presentwindows/presentwindows.cpp
@@ -295,9 +295,12 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
} else if (winData->opacity != 1.0)
data.setTranslucent();
+ const bool isInMotion = m_motionManager.isManaging(w);
// Calculate window's brightness
if (w == m_highlightedWindow || w == m_closeWindow || !m_activated)
winData->highlight = qMin(1.0, winData->highlight + time / m_fadeDuration);
+ else if (!isInMotion && w->isDesktop())
+ winData->highlight = 0.3;
else
winData->highlight = qMax(0.0, winData->highlight - time / m_fadeDuration);
@@ -317,7 +320,7 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
if (w->isDesktop() && !w->isOnCurrentDesktop())
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
- if (m_motionManager.isManaging(w))
+ if (isInMotion)
data.setTransformed(); // We will be moving this window
}
effects->prePaintWindow(w, data, time);
@@ -333,15 +336,50 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
return;
}
+ mask |= PAINT_WINDOW_LANCZOS;
// Apply opacity and brightness
data.opacity *= winData->opacity;
- data.brightness *= interpolate(0.7, 1.0, winData->highlight);
+ data.brightness *= interpolate(0.40, 1.0, winData->highlight);
if (m_motionManager.isManaging(w)) {
+ if (w->isDesktop())
+ effects->paintWindow(w, mask, region, data);
m_motionManager.apply(w, data);
+ QRect rect = m_motionManager.transformedGeometry(w).toRect();
+
+ if (winData->highlight > 0.0) {
+ // scale the window (interpolated by the highlight level) to at least 105% or to cover 1/16 of the screen size - yet keep it in screen bounds
+ QRect area = effects->clientArea(FullScreenArea, w);
+ QSizeF effSize(w->width()*data.xScale, w->height()*data.yScale);
+ float tScale = sqrt((area.width()*area.height()) / (16.0*effSize.width()*effSize.height()));
+ if (tScale < 1.05)
+ tScale = 1.05;
+ if (effSize.width()*tScale > area.width())
+ tScale = area.width() / effSize.width();
+ if (effSize.height()*tScale > area.height())
+ tScale = area.height() / effSize.height();
+ const float scale = interpolate(1.0, tScale, winData->highlight);
+ if (scale > 1.0) {
+ if (scale < tScale) // don't use lanczos during transition
+ mask &= ~PAINT_WINDOW_LANCZOS;
+
+ const QPoint ac = area.center();
+ const QPoint wc = rect.center();
+
+ data.xScale *= scale;
+ data.yScale *= scale;
+ const int tx = -w->width()*data.xScale*(scale-1.0)*(0.5+(wc.x() - ac.x())/area.width());
+ const int ty = -w->height()*data.yScale*(scale-1.0)*(0.5+(wc.y() - ac.y())/area.height());
+ rect.translate(tx,ty);
+ rect.setWidth(rect.width()*scale);
+ rect.setHeight(rect.height()*scale);
+ data.xTranslate += tx;
+ data.yTranslate += ty;
+ }
+ }
- if (!m_motionManager.areWindowsMoving()) {
- mask |= PAINT_WINDOW_LANCZOS;
+ if (m_motionManager.areWindowsMoving()) {
+ mask &= ~PAINT_WINDOW_LANCZOS;
}
if (m_dragInProgress && m_dragWindow == w) {
QPoint diff = cursorPos() - m_dragStart;
@@ -350,7 +388,7 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
}
effects->paintWindow(w, mask, region, data);
- QRect rect = m_motionManager.transformedGeometry(w).toRect();
+
if (m_showIcons) {
QPoint point(rect.x() + rect.width() * 0.95,
rect.y() + rect.height() * 0.95);
@@ -484,7 +522,7 @@ void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e)
}
if (m_closeView->isVisible()) {
const QPoint widgetPos = m_closeView->mapFromGlobal(me->pos());
- const QPointF scenePos = m_closeView->mapToScene(widgetPos);
+// const QPointF scenePos = m_closeView->mapToScene(widgetPos);
QMouseEvent event(me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers());
m_closeView->windowInputMouseEvent(&event);
return;
@@ -1546,6 +1584,7 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
}
m_activated = active;
if (m_activated) {
+ m_closeButtonCorner = (Qt::Corner)effects->kwinOption(KWin::CloseButtonCorner).toInt();
m_decalOpacity = 0.0;
m_highlightedWindow = NULL;
m_windowFilter.clear();
@@ -1648,6 +1687,8 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
}
}
} else {
+ if (m_highlightedWindow)
+ effects->setElevatedWindow(m_highlightedWindow, false);
// Fade in/out all windows
EffectWindow *activeWindow = effects->activeWindow();
if (m_tabBoxEnabled)
@@ -1752,32 +1793,65 @@ void PresentWindowsEffect::setHighlightedWindow(EffectWindow *w)
return;
m_closeView->hide();
- if (m_highlightedWindow)
+ if (m_highlightedWindow) {
+ effects->setElevatedWindow(m_highlightedWindow, false);
m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
+ }
m_highlightedWindow = w;
- if (m_highlightedWindow)
+ if (m_highlightedWindow) {
+ effects->setElevatedWindow(m_highlightedWindow, true);
m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
+ }
if (m_tabBoxEnabled && m_highlightedWindow)
effects->setTabBoxWindow(w);
updateCloseWindow();
}
+void PresentWindowsEffect::elevateCloseWindow()
+{
+ if (EffectWindow *cw = effects->findWindow(m_closeView->winId()))
+ effects->setElevatedWindow(cw, true);
+}
+
void PresentWindowsEffect::updateCloseWindow()
{
if (m_doNotCloseWindows)
return;
+ if (!m_highlightedWindow || m_highlightedWindow->isDesktop()) {
+ m_closeView->hide();
+ return;
+ }
if (m_closeView->isVisible())
return;
- if (!m_highlightedWindow) {
+
+ const QRectF rect(m_motionManager.targetGeometry(m_highlightedWindow));
+ if (2*m_closeView->sceneRect().width() > rect.width() && 2*m_closeView->sceneRect().height() > rect.height()) {
+ // not for tiny windows (eg. with many windows) - they might become unselectable
m_closeView->hide();
return;
}
- const QRectF rect = m_motionManager.targetGeometry(m_highlightedWindow);
- m_closeView->setGeometry(rect.x() + rect.width() - m_closeView->sceneRect().width(), rect.y(),
- m_closeView->sceneRect().width(), m_closeView->sceneRect().height());
- if (rect.contains(effects->cursorPos()))
- m_closeView->delayedShow();
+ QRect cvr(QPoint(0,0), m_closeView->sceneRect().size().toSize());
+ switch (m_closeButtonCorner)
+ {
+ case Qt::TopLeftCorner:
+ default:
+ cvr.moveTopLeft(rect.topLeft().toPoint()); break;
+ case Qt::TopRightCorner:
+ cvr.moveTopRight(rect.topRight().toPoint()); break;
+ case Qt::BottomLeftCorner:
+ cvr.moveBottomLeft(rect.bottomLeft().toPoint()); break;
+ case Qt::BottomRightCorner:
+ cvr.moveBottomRight(rect.bottomRight().toPoint()); break;
+ }
+ m_closeView->setGeometry(cvr);
+ if (rect.contains(effects->cursorPos())) {
+ m_closeView->show();
+ m_closeView->disarm();
+ // to wait for the next event cycle (or more if the show takes more time)
+ // TODO: make the closeWindow a graphicsviewitem? why should there be an extra scene to be used in an exiting scene??
+ QTimer::singleShot(50, this, SLOT(elevateCloseWindow()));
+ }
else
m_closeView->hide();
}
@@ -1972,7 +2046,7 @@ void PresentWindowsEffect::globalShortcutChangedClass(const QKeySequence& seq)
************************************************/
CloseWindowView::CloseWindowView(QWidget* parent)
: QGraphicsView(parent)
- , m_delayedShowTimer(new QTimer(this))
+ , m_armTimer(new QTimer(this))
{
setWindowFlags(Qt::X11BypassWindowManagerHint);
setAttribute(Qt::WA_TranslucentBackground);
@@ -2013,15 +2087,15 @@ CloseWindowView::CloseWindowView(QWidget* parent)
scene->setSceneRect(QRectF(QPointF(0, 0), QSizeF(width, height)));
setScene(scene);
- // setup the timer
- m_delayedShowTimer->setSingleShot(true);
- m_delayedShowTimer->setInterval(500);
- connect(m_delayedShowTimer, SIGNAL(timeout()), SLOT(show()));
+ // setup the timer - attempt to prevent accidental clicks
+ m_armTimer->setSingleShot(true);
+ m_armTimer->setInterval(350); // 50ms until the window is elevated (seen!) and 300ms more to be "realized" by the user.
+ connect(m_armTimer, SIGNAL(timeout()), SLOT(arm()));
}
void CloseWindowView::windowInputMouseEvent(QMouseEvent* e)
{
- if (m_delayedShowTimer->isActive())
+ if (!isEnabled())
return;
if (e->type() == QEvent::MouseMove) {
mouseMoveEvent(e);
@@ -2041,17 +2115,15 @@ void CloseWindowView::drawBackground(QPainter* painter, const QRectF& rect)
m_frame->paintFrame(painter);
}
-void CloseWindowView::hide()
+void CloseWindowView::arm()
{
- m_delayedShowTimer->stop();
- QWidget::hide();
+ setEnabled(true);
}
-void CloseWindowView::delayedShow()
+void CloseWindowView::disarm()
{
- if (isVisible() || m_delayedShowTimer->isActive())
- return;
- m_delayedShowTimer->start();
+ setEnabled(false);
+ m_armTimer->start();
}
diff --git a/kwin/effects/presentwindows/presentwindows.h b/kwin/effects/presentwindows/presentwindows.h
index 58c5266..e0c982e 100644
--- a/kwin/effects/presentwindows/presentwindows.h
+++ b/kwin/effects/presentwindows/presentwindows.h
@@ -46,8 +46,9 @@ public:
void windowInputMouseEvent(QMouseEvent* e);
virtual void drawBackground(QPainter* painter, const QRectF& rect);
- void delayedShow();
- void hide();
+ void disarm();
+public slots:
+ void arm();
Q_SIGNALS:
void close();
@@ -55,7 +56,7 @@ Q_SIGNALS:
private:
Plasma::PushButton* m_closeButton;
Plasma::FrameSvg* m_frame;
- QTimer* m_delayedShowTimer;
+ QTimer* m_armTimer;
};
/**
@@ -160,6 +161,7 @@ public slots:
private slots:
void closeWindow();
+ void elevateCloseWindow();
protected:
// Window rearranging
@@ -265,6 +267,7 @@ private:
CloseWindowView* m_closeView;
EffectWindow* m_closeWindow;
+ Qt::Corner m_closeButtonCorner;
// drag to close
QPoint m_dragStart;
diff --git a/kwin/effects/screenlocker/CMakeLists.txt b/kwin/effects/screenlocker/CMakeLists.txt
new file mode 100644
index 0000000..21d9284
--- /dev/null
+++ b/kwin/effects/screenlocker/CMakeLists.txt
@@ -0,0 +1,13 @@
+#######################################
+# Effect
+
+# Source files
+set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
+ screenlocker/screenlocker.cpp
+ )
+
+# .desktop files
+install( FILES
+ screenlocker/screenlocker.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
+
diff --git a/kwin/effects/screenlocker/qml/main.qml b/kwin/effects/screenlocker/qml/main.qml
new file mode 100644
index 0000000..36be712
--- /dev/null
+++ b/kwin/effects/screenlocker/qml/main.qml
@@ -0,0 +1,151 @@
+/***************************************************************************
+ * Copyright 2011 Artur Duque de Souza *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
+ ***************************************************************************/
+
+import QtQuick 1.0
+import org.kde.plasma.core 0.1 as PlasmaCore
+import org.kde.qtextracomponents 0.1
+
+
+Rectangle {
+ id: lockScreen
+ width: 800
+ height: 600
+ color: Qt.rgba(0, 0, 0, 0.8)
+
+ signal unlockRequested()
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: mouse.accepted = true
+ }
+
+ PlasmaCore.Theme {
+ id: theme
+ }
+
+ Behavior on opacity {
+ NumberAnimation {duration: 250}
+ }
+
+ Item {
+ id: lockArea
+ anchors {
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ }
+ height: 120
+ }
+
+ Item {
+ id: unlockArea
+ anchors {
+ top: parent.top
+ bottom: lockArea.top
+ left: parent.left
+ right: parent.right
+ }
+
+
+ Text {
+ id: unlockText
+ text: i18n("Drag here to unlock")
+ color: "white"
+ anchors.centerIn: parent
+ font.pixelSize: 36
+ font.family: theme.font.family
+ font.bold: theme.font.bold
+ font.capitalization: theme.font.capitalization
+ font.italic: theme.font.italic
+ font.weight: theme.font.weight
+ font.underline: theme.font.underline
+ font.wordSpacing: theme.font.wordSpacing
+ opacity: 0
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+ }
+
+ }
+
+
+ Image {
+ id: lockerImage
+ width: 64
+ height: 64
+ source: "unlock-normal.png"
+ state: "default"
+
+ anchors {
+ bottom: lockScreen.bottom
+ topMargin: 10
+ horizontalCenter: lockScreen.horizontalCenter
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ drag.target: parent
+ onPressed: {
+ lockerImage.state = "drag"
+ }
+
+ onReleased: {
+ var pos = (lockerImage.x > unlockArea.x && lockerImage.y > unlockArea.y);
+ var size = (lockerImage.x < unlockArea.width && lockerImage.y < unlockArea.height);
+
+ if (pos && size) {
+ lockScreen.unlockRequested()
+ }
+
+ lockerImage.state = "default"
+ }
+ }
+
+ states: [
+ State {
+ name: "drag"
+ PropertyChanges {
+ target: lockerImage
+ anchors.bottom: undefined
+ anchors.horizontalCenter: undefined
+ source: "unlock-pressed.png"
+ }
+ PropertyChanges {
+ target: unlockText
+ opacity: 0.6
+ }
+ },
+ State {
+ name: "default"
+ PropertyChanges {
+ target: lockerImage
+ anchors.bottom: lockScreen.bottom
+ anchors.horizontalCenter: lockScreen.horizontalCenter
+ source: "unlock-normal.png"
+ }
+ PropertyChanges {
+ target: unlockText
+ opacity: 0
+ }
+ }
+ ]
+ }
+}
+
diff --git a/kwin/effects/screenlocker/qml/unlock-normal.png b/kwin/effects/screenlocker/qml/unlock-normal.png
new file mode 100644
index 0000000..e67472e
Binary files /dev/null and b/kwin/effects/screenlocker/qml/unlock-normal.png differ
diff --git a/kwin/effects/screenlocker/qml/unlock-pressed.png b/kwin/effects/screenlocker/qml/unlock-pressed.png
new file mode 100644
index 0000000..cd8e0cf
Binary files /dev/null and b/kwin/effects/screenlocker/qml/unlock-pressed.png differ
diff --git a/kwin/effects/screenlocker/screenlocker.cpp b/kwin/effects/screenlocker/screenlocker.cpp
new file mode 100644
index 0000000..df20014
--- /dev/null
+++ b/kwin/effects/screenlocker/screenlocker.cpp
@@ -0,0 +1,234 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2011 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#include "screenlocker.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef KWIN_HAVE_OPENGL
+#include
+#endif
+#ifdef KWIN_HAVE_XRENDER_COMPOSITING
+#include
+#endif
+#include
+
+namespace KWin
+{
+
+KWIN_EFFECT(screenlocker, ScreenLockerEffect)
+
+class EffectDeclarativeView : public QDeclarativeView
+{
+public:
+ void windowInputMouseEvent(QEvent *e)
+ {
+ QMouseEvent *ev = static_cast(e);
+
+ if (e->type() == QEvent::MouseMove) {
+ mouseMoveEvent(ev);
+ } else if (e->type() == QEvent::MouseButtonPress) {
+ mousePressEvent(ev);
+ } else if (e->type() == QEvent::MouseButtonDblClick) {
+ mouseDoubleClickEvent(ev);
+ } else if (e->type() == QEvent::MouseButtonRelease) {
+ mouseReleaseEvent(ev);
+ }
+ }
+};
+
+ScreenLockerEffect::ScreenLockerEffect()
+ : Effect()
+ , m_locked(false)
+ , m_inputWindow(0)
+{
+ connect(effects, SIGNAL(requestScreenLock()), SLOT(slotRequestLock()));
+ m_declarativeView = new EffectDeclarativeView;
+ foreach(const QString &importPath, KGlobal::dirs()->findDirs("module", "imports")) {
+ m_declarativeView->engine()->addImportPath(importPath);
+ }
+ KDeclarative kdeclarative;
+ kdeclarative.setDeclarativeEngine(m_declarativeView->engine());
+ kdeclarative.initialize();
+ //binds things like kconfig and icons
+ kdeclarative.setupBindings();
+ m_declarativeView->setSource(QUrl(KStandardDirs::locate("data", "kwin/lockscreen/main.qml")));
+ m_declarativeView->setResizeMode(QDeclarativeView::SizeRootObjectToView);
+ m_declarativeView->setWindowFlags(Qt::X11BypassWindowManagerHint);
+ m_declarativeView->setAttribute(Qt::WA_TranslucentBackground);
+ m_declarativeView->setFrameShape(QFrame::NoFrame);
+
+ connect(m_declarativeView->rootObject(), SIGNAL(unlockRequested()), this, SLOT(slotRequestUnlock()));
+ //m_declarativeView->hide();
+}
+
+ScreenLockerEffect::~ScreenLockerEffect()
+{
+ delete m_declarativeView;
+}
+
+void ScreenLockerEffect::paintScreen(int mask, QRegion region, ScreenPaintData &data)
+{
+ effects->paintScreen(mask, region, data);
+ if (m_locked) {
+ // TODO: do our screen locking
+ }
+}
+
+void ScreenLockerEffect::postPaintScreen()
+{
+ if (m_locked) {
+ // paint screen black
+ // TODO: add cross fading
+ if (effects->compositingType() == OpenGLCompositing) {
+ paintGL();
+ } else if (effects->compositingType() == XRenderCompositing) {
+ paintXrender();
+ }
+ EffectWindow *w = effects->findWindow(m_declarativeView->winId());
+ if (w) {
+ WindowPaintData d(w);
+ effects->drawWindow(w, PAINT_WINDOW_OPAQUE, infiniteRegion(), d);
+ }
+ }
+}
+
+void ScreenLockerEffect::paintGL()
+{
+#ifdef KWIN_HAVE_OPENGL
+ GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
+ vbo->reset();
+ vbo->setUseColor(true);
+ if (ShaderManager::instance()->isValid()) {
+ ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
+ }
+ vbo->setColor(Qt::black);
+ QVector verts;
+ const QRect r(0, 0, displayWidth(), displayHeight());
+ verts.reserve(12);
+ verts << r.x() + r.width() << r.y();
+ verts << r.x() << r.y();
+ verts << r.x() << r.y() + r.height();
+ verts << r.x() << r.y() + r.height();
+ verts << r.x() + r.width() << r.y() + r.height();
+ verts << r.x() + r.width() << r.y();
+ vbo->setData(6, 2, verts.data(), NULL);
+ vbo->render(GL_TRIANGLES);
+ if (ShaderManager::instance()->isValid()) {
+ ShaderManager::instance()->popShader();
+ }
+#endif
+}
+
+void ScreenLockerEffect::paintXrender()
+{
+#ifdef KWIN_HAVE_XRENDER_COMPOSITING
+ XRenderColor col;
+ col.alpha = 1;
+ col.red = 0;
+ col.green = 0;
+ col.blue = 0;
+ XRenderFillRectangle(display(), PictOpOver, effects->xrenderBufferPicture(),
+ &col, 0, 0, displayWidth(), displayHeight());
+#endif
+}
+
+void ScreenLockerEffect::slotRequestLock()
+{
+ if (!effects->isScreenLockerReferenced()) {
+ m_declarativeView->setGeometry(effects->clientArea(FullScreenArea, effects->activeScreen(), effects->currentDesktop()));
+ m_declarativeView->show();
+ // create input window and grab mouse
+ Window w = effects->createFullScreenInputWindow(this, Qt::PointingHandCursor);
+ if (!w) {
+ return;
+ }
+ if (!effects->grabKeyboard(this)) {
+ effects->destroyInputWindow(w);
+ return;
+ }
+ effects->refScreenLocker(this);
+ effects->setActiveFullScreenEffect(this);
+ m_locked = true;
+ m_inputWindow = w;
+
+ effects->addRepaintFull();
+ }
+}
+
+void ScreenLockerEffect::grabbedKeyboardEvent(QKeyEvent *e)
+{
+ if (!m_locked) {
+ return;
+ }
+ // TODO: implement a proper unlock behavior
+ if (e->key() == Qt::Key_Space) {
+ // magic key for testing
+ doUnlock();
+ }
+}
+
+void ScreenLockerEffect::slotRequestUnlock()
+{
+ doUnlock();
+}
+
+void ScreenLockerEffect::windowInputMouseEvent(Window w, QEvent *e)
+{
+ Q_UNUSED(w)
+ Q_UNUSED(e)
+ if (!m_locked) {
+ return;
+ }
+
+ QMouseEvent* me = static_cast< QMouseEvent* >(e);
+ QMouseEvent event(me->type(), me->pos(), me->pos(), me->button(), me->buttons(), me->modifiers());
+ m_declarativeView->windowInputMouseEvent(&event);
+ // TODO: implement proper behavior by triggering the unlock screen
+}
+
+void ScreenLockerEffect::doUnlock()
+{
+ m_locked = false;
+ effects->destroyInputWindow(m_inputWindow);
+ m_inputWindow = 0;
+ effects->setActiveFullScreenEffect(NULL);
+ effects->ungrabKeyboard();
+ effects->unrefScreenLocker(this);
+ m_declarativeView->hide();
+ effects->addRepaintFull();
+}
+
+bool ScreenLockerEffect::isActive() const
+{
+ return m_locked;
+}
+
+bool ScreenLockerEffect::provides(Effect::Feature feature)
+{
+ if (feature == ScreenLocking) {
+ return true;
+ }
+ return false;
+}
+
+} //namespace
diff --git a/kwin/effects/screenlocker/screenlocker.desktop b/kwin/effects/screenlocker/screenlocker.desktop
new file mode 100644
index 0000000..3631f35
--- /dev/null
+++ b/kwin/effects/screenlocker/screenlocker.desktop
@@ -0,0 +1,17 @@
+[Desktop Entry]
+Name=Screen Locker
+Icon=preferences-system-windows-effect-screenlocker
+Comment=Internal Helper Effect to perform screen locking
+
+Type=Service
+X-KDE-ServiceTypes=KWin/Effect
+X-KDE-PluginInfo-Author=Martin Gräßlin
+X-KDE-PluginInfo-Email=mgraesslin@kde.org
+X-KDE-PluginInfo-Name=kwin4_effect_screenlocker
+X-KDE-PluginInfo-Version=0.1.0
+X-KDE-PluginInfo-Category=Window Management
+X-KDE-PluginInfo-Depends=
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=true
+X-KDE-Library=kwin4_effect_builtins
+X-KDE-Ordering=99
\ No newline at end of file
diff --git a/kwin/effects/screenlocker/screenlocker.h b/kwin/effects/screenlocker/screenlocker.h
new file mode 100644
index 0000000..7a21a80
--- /dev/null
+++ b/kwin/effects/screenlocker/screenlocker.h
@@ -0,0 +1,57 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2011 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#ifndef KWIN_SCREENLOCKER_EFFECT_H
+#define KWIN_SCREENLOCKER_EFFECT_H
+#include
+
+
+namespace KWin
+{
+
+class EffectDeclarativeView;
+
+class ScreenLockerEffect : public Effect
+{
+ Q_OBJECT
+public:
+ ScreenLockerEffect();
+ virtual ~ScreenLockerEffect();
+ virtual void paintScreen(int mask, QRegion region, ScreenPaintData &data);
+ virtual void postPaintScreen();
+ virtual bool provides(Feature feature);
+ virtual bool isActive() const;
+
+ virtual void windowInputMouseEvent(Window w, QEvent *e);
+ virtual void grabbedKeyboardEvent(QKeyEvent *e);
+
+public Q_SLOTS:
+ void slotRequestLock();
+ void slotRequestUnlock();
+
+private:
+ void doUnlock();
+ void paintGL();
+ void paintXrender();
+ bool m_locked;
+ Window m_inputWindow;
+ EffectDeclarativeView *m_declarativeView;
+};
+} // namespace
+#endif
diff --git a/kwin/libkdecorations/kdecorationfactory.cpp b/kwin/libkdecorations/kdecorationfactory.cpp
index 05b33cf..142add7 100644
--- a/kwin/libkdecorations/kdecorationfactory.cpp
+++ b/kwin/libkdecorations/kdecorationfactory.cpp
@@ -28,12 +28,21 @@ DEALINGS IN THE SOFTWARE.
#include "kdecorationbridge.h"
-KDecorationFactory::KDecorationFactory()
+class KDecorationFactoryPrivate {
+public:
+ KDecorationFactoryPrivate() {
+ closeButtonCorner = (Qt::Corner)0;
+ }
+ Qt::Corner closeButtonCorner;
+};
+
+KDecorationFactory::KDecorationFactory() : d(new KDecorationFactoryPrivate)
{
}
KDecorationFactory::~KDecorationFactory()
{
+ delete d;
assert(_decorations.count() == 0);
}
@@ -56,6 +65,18 @@ bool KDecorationFactory::exists(const KDecoration* deco) const
return _decorations.contains(const_cast< KDecoration* >(deco));
}
+Qt::Corner KDecorationFactory::closeButtonCorner()
+{
+ if (d->closeButtonCorner)
+ return d->closeButtonCorner;
+ return options()->titleButtonsLeft().contains('X') ? Qt::TopLeftCorner : Qt::TopRightCorner;
+}
+
+void KDecorationFactory::setCloseButtonCorner(Qt::Corner cnr)
+{
+ d->closeButtonCorner = cnr;
+}
+
void KDecorationFactory::addDecoration(KDecoration* deco)
{
_decorations.append(deco);
diff --git a/kwin/libkdecorations/kdecorationfactory.h b/kwin/libkdecorations/kdecorationfactory.h
index 978d4b2..44a5b7d 100644
--- a/kwin/libkdecorations/kdecorationfactory.h
+++ b/kwin/libkdecorations/kdecorationfactory.h
@@ -88,6 +88,21 @@ public:
* after such actions.
*/
bool exists(const KDecoration* deco) const;
+
+ /**
+ * Set & get the position of the close button - most decorations don't have to call this ever.
+ *
+ * By default, the legacy position indicated by the options (top left or top right) will be
+ * returned.
+ * Only if you need to provide a bottom corner or your decoration does not respect those
+ * settings you will have to specify the exact corner (eg. used by the "present windows"
+ * closer)
+ *
+ * @since 4.8
+ */
+ Qt::Corner closeButtonCorner();
+ void setCloseButtonCorner(Qt::Corner cnr);
+
/**
* @internal
*/
diff --git a/kwin/libkwineffects/kwineffects.h b/kwin/libkwineffects/kwineffects.h
index 87a676d..6f32068 100644
--- a/kwin/libkwineffects/kwineffects.h
+++ b/kwin/libkwineffects/kwineffects.h
@@ -166,7 +166,7 @@ X-KDE-Library=kwin4_effect_cooleffect
#define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor ))
#define KWIN_EFFECT_API_VERSION_MAJOR 0
-#define KWIN_EFFECT_API_VERSION_MINOR 180
+#define KWIN_EFFECT_API_VERSION_MINOR 181
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR )
@@ -331,7 +331,8 @@ public:
enum Feature {
Nothing = 0, Resize, GeometryTip,
- Outline
+ Outline,
+ ScreenLocking
};
/**
@@ -580,6 +581,7 @@ public:
virtual void paintEffectFrame(EffectFrame* frame, QRegion region, double opacity, double frameOpacity) = 0;
virtual void drawWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) = 0;
virtual void buildQuads(EffectWindow* w, WindowQuadList& quadList) = 0;
+ virtual QVariant kwinOption(KWinOption kwopt) = 0;
// Functions for handling input - e.g. when an Expose-like effect is shown, an input window
// covering the whole screen is created and all mouse events will be intercepted by it.
// The effect's windowInputMouseEvent() will get called with such events.
@@ -780,6 +782,42 @@ public:
virtual EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize = true,
const QPoint& position = QPoint(-1, -1), Qt::Alignment alignment = Qt::AlignCenter) const = 0;
+
+ /**
+ * Allows effects to indicate that they are responsible for handling screen locking.
+ * Only one effect at a time should reference the Screen Locker. It is assumed that
+ * all effects want to collaborate and will check @link isScreenLockerReferenced before
+ * trying to reference the screen locker.
+ * When the effect gets into a state that it wants to indicate that the screen got unlocked
+ * it should use @link unrefScreenLocker to remove the reference on the screen locker and
+ * to indicate that the screen got unlocked.
+ *
+ * An Effect may only call this method in a slot connected on the @link requestScreenLock signal.
+ * Calling this method outside the handling of that signal will not do anything.
+ *
+ * @param lockEffect The Effect which implements the lock.
+ * @since 4.8
+ * @see unrefScreenLocker
+ * @see isScreenLockerReferenced
+ **/
+ virtual void refScreenLocker(Effect *lockEffect) = 0;
+ /**
+ * Method to unlock the screen for an Effect which handles Screen Locking through
+ * @link refScreenLocker.
+ * If the Effect had not referenced the Screen Locker this method will not unlock the screen.
+ * @param lockEffect The Effect which implements the lock.
+ * @since 4.8
+ * @see refScreenLocker
+ **/
+ virtual void unrefScreenLocker(Effect *lockEffect) = 0;
+ /**
+ * @returns Whether an Effect referenced the Screen Lock.
+ * @since 4.8
+ * @see refScreenLocker
+ * @see unrefScreenLocker
+ **/
+ virtual bool isScreenLockerReferenced() const = 0;
+
/**
* Sends message over DCOP to reload given effect.
* @param effectname effect's name without "kwin4_effect_" prefix.
@@ -1017,6 +1055,14 @@ Q_SIGNALS:
* @since 4.7
**/
void hideOutline();
+ /**
+ * Signal emitted when the screen is about to be locked. An effect implementing a screen lock
+ * may connect to this signal and call @link refScreenLocker in the slot handling the signal.
+ * @since 4.8
+ * @see refScreenLocker
+ * @see isScreenLockerReferenced
+ **/
+ void requestScreenLock();
protected:
QVector< EffectPair > loaded_effects;
diff --git a/kwin/libkwineffects/kwinglobals.h b/kwin/libkwineffects/kwinglobals.h
index 2a4ea71..b33d3df 100644
--- a/kwin/libkwineffects/kwinglobals.h
+++ b/kwin/libkwineffects/kwinglobals.h
@@ -105,6 +105,10 @@ enum TabBoxMode {
TabBoxWindowsAlternativeMode // Secondary window switching mode
};
+enum KWinOption {
+ CloseButtonCorner
+};
+
inline
KWIN_EXPORT Display* display()
{
diff --git a/kwin/screenlocker/config-xautolock.h.cmake b/kwin/screenlocker/config-xautolock.h.cmake
new file mode 100644
index 0000000..eadb0a6
--- /dev/null
+++ b/kwin/screenlocker/config-xautolock.h.cmake
@@ -0,0 +1,2 @@
+/* Define if you have the XScreenSaver extension */
+#cmakedefine HAVE_XSCREENSAVER 1
diff --git a/kwin/screenlocker/dbus/org.freedesktop.ScreenSaver.xml b/kwin/screenlocker/dbus/org.freedesktop.ScreenSaver.xml
new file mode 100644
index 0000000..5efd943
--- /dev/null
+++ b/kwin/screenlocker/dbus/org.freedesktop.ScreenSaver.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kwin/screenlocker/dbus/org.kde.screensaver.xml b/kwin/screenlocker/dbus/org.kde.screensaver.xml
new file mode 100644
index 0000000..e700b88
--- /dev/null
+++ b/kwin/screenlocker/dbus/org.kde.screensaver.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kwin/screenlocker/kcfg/kscreensaversettings.kcfg b/kwin/screenlocker/kcfg/kscreensaversettings.kcfg
new file mode 100644
index 0000000..c8f76f3
--- /dev/null
+++ b/kwin/screenlocker/kcfg/kscreensaversettings.kcfg
@@ -0,0 +1,92 @@
+
+
+ kglobalsettings.h
+
+
+
+ false
+
+ Enables the screen saver.
+
+
+ 300
+
+ Sets the seconds after which the screen saver is started.
+
+
+ true
+
+ Usually the screen saver is suspended when display power saving kicks in,
+ as nothing can be seen on the screen anyway, obviously. However, some screen savers
+ actually perform useful computations, so it is not desirable to suspend them.
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+ false
+
+
+
+
+ 5000
+
+
+
+
+ false
+
+
+
+
+ 600
+
+
+
+
+ 19
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
diff --git a/kwin/screenlocker/kcfg/kscreensaversettings.kcfgc b/kwin/screenlocker/kcfg/kscreensaversettings.kcfgc
new file mode 100644
index 0000000..af9133d
--- /dev/null
+++ b/kwin/screenlocker/kcfg/kscreensaversettings.kcfgc
@@ -0,0 +1,4 @@
+File=kscreensaversettings.kcfg
+ClassName=KScreenSaverSettings
+Singleton=true
+Mutators=true
diff --git a/kwin/screenlocker/lock/CMakeLists.txt b/kwin/screenlocker/lock/CMakeLists.txt
new file mode 100644
index 0000000..76319be
--- /dev/null
+++ b/kwin/screenlocker/lock/CMakeLists.txt
@@ -0,0 +1,62 @@
+include_directories( ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/screenlocker ${KDEBASE_WORKSPACE_SOURCE_DIR}/kcheckpass ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kdm )
+
+########### next target ###############
+
+check_library_exists(Xxf86misc XF86MiscSetGrabKeysState "" HAVE_XF86MISCSETGRABKEYSSTATE)
+if(WITH_OpenGL)
+check_library_exists(GL glXChooseVisual "" HAVE_GLXCHOOSEVISUAL)
+endif(WITH_OpenGL)
+
+configure_file(config-krunner-lock.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-krunner-lock.h)
+
+set(kscreenlocker_SRCS
+ lockprocess.cc
+ lockdlg.cc
+ autologout.cc
+ main.cc )
+
+set(plasmaapp_dbusXML ../../../plasma/screensaver/shell/org.kde.plasma-overlay.App.xml)
+qt4_add_dbus_interface(kscreenlocker_SRCS ${plasmaapp_dbusXML} plasmaapp_interface)
+
+set(lockprocess_dbusXML org.kde.screenlocker.LockProcess.xml)
+qt4_generate_dbus_interface(lockprocess.h ${lockprocess_dbusXML} OPTIONS -m)
+qt4_add_dbus_adaptor(kscreenlocker_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${lockprocess_dbusXML} lockprocess.h LockProcess)
+
+set(ksmserver_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/org.kde.KSMServerInterface.xml)
+QT4_ADD_DBUS_INTERFACE(kscreenlocker_SRCS ${ksmserver_xml} ksmserver_interface)
+set(kscreensaver_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/screenlocker/dbus/org.kde.screensaver.xml)
+QT4_ADD_DBUS_INTERFACE(kscreenlocker_SRCS ${kscreensaver_xml} kscreensaver_interface)
+
+
+
+kde4_add_kcfg_files(kscreenlocker_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/../kcfg/kscreensaversettings.kcfgc)
+
+
+
+kde4_add_executable(kscreenlocker ${kscreenlocker_SRCS})
+
+target_link_libraries(kscreenlocker kephal ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES})
+
+find_library(DL_LIBRARY dl)
+if (DL_LIBRARY)
+ target_link_libraries(kscreenlocker ${DL_LIBRARY})
+endif(DL_LIBRARY)
+
+if (HAVE_XF86MISC)
+ target_link_libraries(kscreenlocker ${X11_Xxf86misc_LIB})
+endif (HAVE_XF86MISC)
+
+if(HAVE_GLXCHOOSEVISUAL)
+ target_link_libraries(kscreenlocker ${OPENGL_gl_LIBRARY})
+endif(HAVE_GLXCHOOSEVISUAL)
+
+install(TARGETS kscreenlocker DESTINATION ${LIBEXEC_INSTALL_DIR})
+
+install_pam_service(kscreensaver)
+
+
+########### install files ###############
+
+
+install( FILES kscreenlocker.notifyrc DESTINATION ${DATA_INSTALL_DIR}/kscreenlocker )
+
diff --git a/kwin/screenlocker/lock/autologout.cc b/kwin/screenlocker/lock/autologout.cc
new file mode 100644
index 0000000..c86e29a
--- /dev/null
+++ b/kwin/screenlocker/lock/autologout.cc
@@ -0,0 +1,118 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 2004 Chris Howells
+
+#include "lockprocess.h"
+#include "autologout.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define COUNTDOWN 30
+
+AutoLogout::AutoLogout(LockProcess *parent) : QDialog(parent, Qt::X11BypassWindowManagerHint)
+{
+ QLabel *pixLabel = new QLabel( this );
+ pixLabel->setObjectName( QLatin1String( "pixlabel" ) );
+ pixLabel->setPixmap(DesktopIcon(QLatin1String( "application-exit" )));
+
+ QLabel *greetLabel = new QLabel(i18n("Automatic Log Out"), this);
+ QLabel *infoLabel = new QLabel(i18n("To prevent being logged out, resume using this session by moving the mouse or pressing a key."), this);
+
+ mStatusLabel = new QLabel(QLatin1String( " " ), this);
+ mStatusLabel->setAlignment(Qt::AlignCenter);
+
+ QLabel *mProgressLabel = new QLabel(i18n("Time Remaining:"), this);
+ mProgressRemaining = new QProgressBar(this);
+ mProgressRemaining->setTextVisible(false);
+
+ frameLayout = new QGridLayout(this);
+ frameLayout->setSpacing(KDialog::spacingHint());
+ frameLayout->setMargin(KDialog::marginHint() * 2);
+ frameLayout->addWidget(pixLabel, 0, 0, 3, 1, Qt::AlignCenter | Qt::AlignTop);
+ frameLayout->addWidget(greetLabel, 0, 1);
+ frameLayout->addWidget(mStatusLabel, 1, 1);
+ frameLayout->addWidget(infoLabel, 2, 1);
+ frameLayout->addWidget(mProgressLabel, 3, 1);
+ frameLayout->addWidget(mProgressRemaining, 4, 1);
+
+ // get the time remaining in seconds for the status label
+ mRemaining = COUNTDOWN * 25;
+
+ mProgressRemaining->setMaximum(COUNTDOWN * 25);
+
+ updateInfo(mRemaining);
+
+ mCountdownTimerId = startTimer(1000/25);
+
+ connect(qApp, SIGNAL(activity()), SLOT(slotActivity()));
+}
+
+AutoLogout::~AutoLogout()
+{
+ hide();
+}
+
+void AutoLogout::updateInfo(int timeout)
+{
+ mStatusLabel->setText(i18np("You will be automatically logged out in 1 second",
+ "You will be automatically logged out in %1 seconds",
+ timeout / 25) );
+ mProgressRemaining->setValue(timeout);
+}
+
+void AutoLogout::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == mCountdownTimerId)
+ {
+ updateInfo(mRemaining);
+ --mRemaining;
+ if (mRemaining < 0)
+ {
+ killTimer(mCountdownTimerId);
+ logout();
+ }
+ }
+}
+
+void AutoLogout::slotActivity()
+{
+ if (mRemaining >= 0)
+ accept();
+}
+
+void AutoLogout::logout()
+{
+ QAbstractEventDispatcher::instance()->unregisterTimers(this);
+ org::kde::KSMServerInterface ksmserver(QLatin1String( "org.kde.ksmserver" ), QLatin1String( "/KSMServer" ), QDBusConnection::sessionBus());
+ ksmserver.logout( 0, 0, 0 );
+}
+
+void AutoLogout::setVisible(bool visible)
+{
+ QDialog::setVisible(visible);
+
+ if (visible)
+ QApplication::flush();
+}
+
+#include "autologout.moc"
diff --git a/kwin/screenlocker/lock/autologout.h b/kwin/screenlocker/lock/autologout.h
new file mode 100644
index 0000000..0c44405
--- /dev/null
+++ b/kwin/screenlocker/lock/autologout.h
@@ -0,0 +1,46 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 1999 Martin R. Jones
+// Copyright 2003 Oswald Buddenhagen
+// Copyright 2004 Chris Howells
+
+#ifndef AUTOLOGOUT_H
+#define AUTOLOGOUT_H
+
+#include
+
+class LockProcess;
+class QGridLayout;
+class QLabel;
+class QDialog;
+class QProgressBar;
+
+class AutoLogout : public QDialog
+{
+ Q_OBJECT
+
+public:
+ AutoLogout(LockProcess *parent);
+ ~AutoLogout();
+ virtual void setVisible(bool visible);
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+
+private Q_SLOTS:
+ void slotActivity();
+
+private:
+ void updateInfo(int);
+ QGridLayout *frameLayout;
+ QLabel *mStatusLabel;
+ int mCountdownTimerId;
+ int mRemaining;
+ QTimer countDownTimer;
+ QProgressBar *mProgressRemaining;
+ void logout();
+};
+
+#endif // AUTOLOGOUT_H
diff --git a/kwin/screenlocker/lock/config-krunner-lock.h.cmake b/kwin/screenlocker/lock/config-krunner-lock.h.cmake
new file mode 100644
index 0000000..7bfdfd6
--- /dev/null
+++ b/kwin/screenlocker/lock/config-krunner-lock.h.cmake
@@ -0,0 +1,2 @@
+#cmakedefine HAVE_GLXCHOOSEVISUAL 1
+#cmakedefine HAVE_XF86MISCSETGRABKEYSSTATE 1
diff --git a/kwin/screenlocker/lock/kscreenlocker.notifyrc b/kwin/screenlocker/lock/kscreenlocker.notifyrc
new file mode 100644
index 0000000..9a9bce8
--- /dev/null
+++ b/kwin/screenlocker/lock/kscreenlocker.notifyrc
@@ -0,0 +1,740 @@
+[Global]
+IconName=system-lock-screen
+Comment=Screen Saver
+Comment[ar]=حافظة الشاشة
+Comment[ast]=Curiapantalles
+Comment[bg]=Екранен предпазител
+Comment[bs]=Čuvar ekrana
+Comment[ca]=Estalvi de pantalla
+Comment[ca@valencia]=Estalvi de pantalla
+Comment[cs]=Šetřič obrazovky
+Comment[da]=Pauseskærm
+Comment[de]=Bildschirmschoner
+Comment[el]=Προφύλαξη οθόνης
+Comment[en_GB]=Screen Saver
+Comment[es]=Salvapantallas
+Comment[et]=Ekraanisäästja
+Comment[eu]=Pantaila babeslea
+Comment[fi]=Näytönsäästäjä
+Comment[fr]=Écran de veille
+Comment[ga]=Spárálaí Scáileáin
+Comment[gu]=સ્ક્રીનક્રિન સેવર
+Comment[he]=שומר מסך
+Comment[hi]=स्क्रीन सेवर
+Comment[hr]=Čuvar zaslona
+Comment[hu]=Képernyővédő
+Comment[ia]=Salvator de schermo
+Comment[id]=Penyimpan Layar
+Comment[is]=Skjáhvíla
+Comment[it]=Salvaschermo
+Comment[ja]=スクリーンセーバー
+Comment[kk]=Экран сақтағышы
+Comment[km]=ធាតុរក្សាអេក្រង់
+Comment[kn]=ತೆರೆ ರಕ್ಷಕ
+Comment[ko]=화면 보호기
+Comment[lt]=Ekrano užsklanda
+Comment[lv]=Ekrānsaudzētājs
+Comment[nb]=Pauseskjerm
+Comment[nds]=Pausschirm
+Comment[nl]=Schermbeveiliging
+Comment[nn]=Pauseskjerm
+Comment[pa]=ਸਕਰੀਨ ਸੇਵਰ
+Comment[pl]=Wygaszacz ekranu
+Comment[pt]=Protector de Ecrã
+Comment[pt_BR]=Protetor de tela
+Comment[ro]=Protecție de ecran
+Comment[ru]=Хранитель экрана
+Comment[si]=තිර සුරැකුම
+Comment[sk]=Šetrič obrazovky
+Comment[sl]=Ohranjevalnik zaslona
+Comment[sr]=Чувар екрана
+Comment[sr@ijekavian]=Чувар екрана
+Comment[sr@ijekavianlatin]=Čuvar ekrana
+Comment[sr@latin]=Čuvar ekrana
+Comment[sv]=Skärmsläckare
+Comment[tg]=Пардаи экран
+Comment[th]=โปรแกรมรักษาจอภาพ
+Comment[tr]=Ekran Koruyucu
+Comment[ug]=ئېكران قوغدىغۇچ
+Comment[uk]=Зберігач екрана
+Comment[wa]=Sipårgneu di waitroûle
+Comment[x-test]=xxScreen Saverxx
+Comment[zh_CN]=屏幕保护程序
+Comment[zh_TW]=螢幕保護程式
+
+[Event/savingstarted]
+Name=Screen saver started
+Name[ar]=بدأت حافظة الشاشة
+Name[ast]=Curiapantalles aniciáu
+Name[bg]=Зареден е екранен предпазител
+Name[bs]=Čuvar ekrana pokrenut
+Name[ca]=S'ha iniciat l'estalvi de pantalla
+Name[ca@valencia]=S'ha iniciat l'estalvi de pantalla
+Name[cs]=Šetřič obrazovky spuštěn
+Name[csb]=Zrëszony wëgaszôcz ekranu
+Name[da]=Pauseskærm startet
+Name[de]=Der Bildschirmschoner wurde gestartet.
+Name[el]=Η προφύλαξη οθόνης ξεκίνησε
+Name[en_GB]=Screen saver started
+Name[eo]=Ekrankurtenon ŝaltis
+Name[es]=Salvapantallas iniciado
+Name[et]=Ekraanisäästja alustas tööd
+Name[eu]=Pantaila babeslea abiarazita
+Name[fi]=Näytönsäästäjä käynnistyi
+Name[fr]=Écran de veille démarré
+Name[fy]=Skermbefeiliging úteinsetten
+Name[ga]=Tosaíodh an spárálaí scáileáin
+Name[gl]=Iniciouse o protector de pantalla
+Name[gu]=સ્ક્રિન સેવર શરૂ થયું
+Name[he]=שומר המסך התחיל
+Name[hi]=स्क्रीन सेवर चालू
+Name[hr]=Zaštita zaslona pokrenuta
+Name[hu]=A képernyővédő elindult
+Name[ia]=Salvator de schermo startate
+Name[id]=Penyimpan layar dijalankan
+Name[is]=Skjásvæfa ræst
+Name[it]=Salvaschermo avviato
+Name[ja]=スクリーンセーバー開始
+Name[kk]=Экран сақтағышы ісін бастады
+Name[km]=បានចាប់ផ្ដើមធាតុរក្សាអេក្រង់
+Name[kn]=ಸ್ಕ್ರೀನ್ ಸೇವರ್ ಪ್ರಾರಂಭಗೊಂಡಿದೆ
+Name[ko]=화면 보호기 시작됨
+Name[lt]=Ekrano užsklanda paleista
+Name[lv]=Ekrāna saudzētājs palaists
+Name[mk]=Чуварот на екранот е стартуван
+Name[ml]=സ്ക്രീന് സേവര് തുടങ്ങി
+Name[nb]=Pauseskjerm startet
+Name[nds]=Pausschirm opropen
+Name[nl]=Schermbeveiliging gestart
+Name[nn]=Pauseskjermen er starta
+Name[pa]=ਸਕਰੀਨ-ਸੇਵਰ ਸ਼ੁਰੂ ਹੋਏ
+Name[pl]=Wygaszacz ekranu uruchomiony
+Name[pt]=O protector de ecrã foi iniciado
+Name[pt_BR]=O protetor de tela foi iniciado
+Name[ro]=Protecție de ecran pornită
+Name[ru]=Хранитель экрана запущен
+Name[si]=තිර සුරැකුම ආරම්ණ කරන ලදි
+Name[sk]=Šetrič obrazovky spustený
+Name[sl]=Zagon ohranjevalnika zaslona
+Name[sr]=Чувар екрана покренут
+Name[sr@ijekavian]=Чувар екрана покренут
+Name[sr@ijekavianlatin]=Čuvar ekrana pokrenut
+Name[sr@latin]=Čuvar ekrana pokrenut
+Name[sv]=Skärmsläckare startad
+Name[tg]=Пардаи экран сар шуд
+Name[th]=โปรแกรมรักษาจอภาพเริ่มทำงานแล้ว
+Name[tr]=Ekran koruyucu başlatıldı
+Name[ug]=ئېكران قوغدىغۇچ باشلاندى
+Name[uk]=Запущено зберігач екрана
+Name[wa]=Sipårgneu di waitroûle enondé
+Name[x-test]=xxScreen saver startedxx
+Name[zh_CN]=屏幕保护程序已启动
+Name[zh_TW]=螢幕保護程式已啟動
+Comment=The screen saver has been started
+Comment[ar]=بدأت حافظة الشاشة
+Comment[ast]=Entamóse'l curiapantalles
+Comment[bg]=Зареден е екранен предпазител
+Comment[bs]=Pokrenut je čuvar ekrana
+Comment[ca]=S'ha iniciat l'estalvi de pantalla
+Comment[ca@valencia]=S'ha iniciat l'estalvi de pantalla
+Comment[cs]=Šetřič obrazovky byl spuštěn
+Comment[csb]=Wëgaszôcz ekranu òstôł zrëszony
+Comment[da]=Pauseskærmen er blevet startet
+Comment[de]=Der Bildschirmschoner wurde gestartet.
+Comment[el]=Η προφύλαξη οθόνης έχει ξεκινήσει
+Comment[en_GB]=The screen saver has been started
+Comment[eo]=la Ekrankurteno lanĉiĝas
+Comment[es]=Se ha iniciado el salvapantallas
+Comment[et]=Ekraanisäästja alustas tööd
+Comment[eu]=Pantaila babeslea abiarazi da
+Comment[fi]=Näytönsäästäjä on käynnistynyt
+Comment[fr]=L'écran de veille a été démarré
+Comment[fy]=De skermbefeiliging is úteinsetten
+Comment[ga]=Tosaíodh an spárálaí scáileáin
+Comment[gl]=Iniciouse o protector de pantalla
+Comment[gu]=સ્ક્રિન સેવર શરૂ કરાયેલ છે
+Comment[he]=שומר מסך הופעל
+Comment[hr]=Zaštita zaslona je pokrenuta
+Comment[hu]=A képernyővédő elindult
+Comment[ia]=Le salvator de schermo ha essite startate
+Comment[id]=Penyimpan layar telah dijalankan
+Comment[is]=Skjáhvílan hefur verið ræst
+Comment[it]=Il salvaschermo è stato avviato
+Comment[ja]=スクリーンセーバーが開始されました
+Comment[kk]=Экран сақтағышы ісін бастады
+Comment[km]=ធាតុរក្សាអេក្រង់ត្រូវបានចាប់ផ្ដើម
+Comment[kn]=ಸ್ಕ್ರೀನ್ ಸೇವರನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗಿದೆ
+Comment[ko]=화면 보호기 시작됨
+Comment[lt]=Ekrano užsklanda buvo paleista
+Comment[lv]=Ekrāna saudzētājs tika palaists
+Comment[mk]=Чуварот на екранот беше стартуван
+Comment[ml]=സ്ക്രീന് സേവര് തുടങ്ങിയിരിയ്ക്കുന്നു
+Comment[nb]=Pauseskjermen er startet
+Comment[nds]=De Pausschirm wöör opropen
+Comment[nl]=De schermbeveiliging is gestart
+Comment[nn]=Pauseskjermen er starta
+Comment[pa]=ਸਕਰੀਨਸੇਵਰ ਸ਼ੁਰੂ ਕੀਤਾ ਜਾ ਚੁੱਕਿਆ ਹੈ
+Comment[pl]=Wygaszacz ekranu został uruchomiony
+Comment[pt]=O protector de ecrã foi iniciado
+Comment[pt_BR]=O protetor de tela foi iniciado
+Comment[ro]=Protecția de ecran a fost pornită
+Comment[ru]=Хранитель экрана запущен
+Comment[si]=තිර සුරැකුම ආරම්භ කර ඇත
+Comment[sk]=Šetrič obrazovky bol spustený
+Comment[sl]=Ohranjevalnik zaslona se je zagnal
+Comment[sr]=Покренут је чувар екрана
+Comment[sr@ijekavian]=Покренут је чувар екрана
+Comment[sr@ijekavianlatin]=Pokrenut je čuvar ekrana
+Comment[sr@latin]=Pokrenut je čuvar ekrana
+Comment[sv]=Skärmsläckaren har startats
+Comment[tg]=Ахлотдон холӣ карда шуд
+Comment[th]=โปรแกรมรักษาจอภาพเริ่มการทำงานแล้ว
+Comment[tr]=Ekran koruyucu başlatıldı
+Comment[ug]=ئېكران قوغدىغۇچ باشلاندى
+Comment[uk]=Запущено зберігач екрана
+Comment[wa]=Li spårgneu di waitroûle a stî enondé
+Comment[x-test]=xxThe screen saver has been startedxx
+Comment[zh_CN]=屏幕保护程序已经启动
+Comment[zh_TW]=螢幕保護程式已被啟動
+Action=None
+
+[Event/locked]
+Name=Screen locked
+Name[ar]=قُقلت الشاشة
+Name[ast]=Pantalla bloquiada
+Name[bg]=Екранът е заключен
+Name[bs]=Ekran zaključan
+Name[ca]=S'ha bloquejat la pantalla
+Name[ca@valencia]=S'ha bloquejat la pantalla
+Name[cs]=Obrazovka uzamčena
+Name[csb]=Zablokòwóny ekranu
+Name[da]=Skærmen er låst
+Name[de]=Bildschirm gesperrt
+Name[el]=Οθόνη κλειδώθηκε
+Name[en_GB]=Screen locked
+Name[eo]=Ekranŝloso
+Name[es]=Pantalla bloqueada
+Name[et]=Ekraan on lukustatud
+Name[eu]=Pantaila giltzatuta
+Name[fi]=Näyttö lukittu
+Name[fr]=Écran verrouillé
+Name[fy]=Skerm beskoattele
+Name[ga]=Tá an scáileán faoi ghlas
+Name[gl]=A pantalla está trancada
+Name[gu]=સ્ક્રિન તાળું મારેલ છે
+Name[he]=מסך נעול
+Name[hi]=स्क्रीन तालाबंद
+Name[hr]=Zaslon zaključan
+Name[hu]=A képernyő zárolt
+Name[ia]=Schermo blocate
+Name[id]=Layar dikunci
+Name[is]=Skjár læstur
+Name[it]=Schermo bloccato
+Name[ja]=スクリーンロック
+Name[kk]=Экран бұғатталды
+Name[km]=បានចាក់សោអេក្រង់
+Name[kn]=ತೆರೆ ಲಾಕ್ ಆಗಿದೆ
+Name[ko]=화면 잠김
+Name[lt]=Ekranas užrakintas
+Name[lv]=Ekrāns slēgts
+Name[mk]=Екранот е заклучен
+Name[ml]=സ്ക്രീന് പൂട്ടി
+Name[nb]=Skjermen låst
+Name[nds]=Schirm afslaten
+Name[nl]=Scherm vergrendeld
+Name[nn]=Skjermen er låst
+Name[pa]=ਸਕਰੀਨ ਲਾਕ ਹੈ
+Name[pl]=Ekran zablokowany
+Name[pt]=Ecrã bloqueado
+Name[pt_BR]=Tela bloqueada
+Name[ro]=Ecran blocat
+Name[ru]=Экран заблокирован
+Name[si]=තිරය අගුලු දමන ලදි
+Name[sk]=Obrazovka zamknutá
+Name[sl]=Zaklep zaslona
+Name[sr]=Екран закључан
+Name[sr@ijekavian]=Екран закључан
+Name[sr@ijekavianlatin]=Ekran zaključan
+Name[sr@latin]=Ekran zaključan
+Name[sv]=Skärm låst
+Name[tg]=Пардаи экран қулф шуд
+Name[th]=หน้าจอถูกล็อคอยู่
+Name[tr]=Ekran kilitlendi
+Name[ug]=ئېكران قۇلۇپلاندى
+Name[uk]=Екран заблоковано
+Name[wa]=Waitroûle eclawêye
+Name[x-test]=xxScreen lockedxx
+Name[zh_CN]=屏幕已锁定
+Name[zh_TW]=螢幕已鎖定
+Comment=The screen has been locked
+Comment[ar]=تمّ قفل الشاشة
+Comment[ast]=Bloquióse la pantalla
+Comment[bg]=Екранът е заключен
+Comment[bs]=Ekran je upravo zaključan
+Comment[ca]=S'ha bloquejat la pantalla
+Comment[ca@valencia]=S'ha bloquejat la pantalla
+Comment[cs]=Obrazovka byla uzamčena
+Comment[csb]=Ekran òstôł zablokòwóny
+Comment[da]=Skærmen er blevet låst
+Comment[de]=Der Bildschirm wurde gesperrt.
+Comment[el]=Η οθόνη έχει κλειδωθεί
+Comment[en_GB]=The screen has been locked
+Comment[eo]=La ekrano ŝlosiĝis
+Comment[es]=Se ha bloqueado la pantalla
+Comment[et]=Ekraan on lukustatud
+Comment[eu]=Pantaila giltzatu egin da
+Comment[fi]=Näyttö on lukittunut
+Comment[fr]=L'écran a été verrouillé
+Comment[fy]=It skerm is beskoattele
+Comment[ga]=Cuireadh an scáileán faoi ghlas
+Comment[gl]=A pantalla trancouse
+Comment[gu]=સ્ક્રિનને તાળું મારવામાં આવ્યું છે
+Comment[he]=המסך ננעל
+Comment[hi]=स्क्रीन तालाबंद कर दिया गया है
+Comment[hr]=Zaslon je zaključan
+Comment[hu]=A képernyő zárolt
+Comment[ia]=Le schermo ha essite blocate
+Comment[id]=Layar telah dikunci
+Comment[is]=Skjánum hefur verið læst
+Comment[it]=Lo schermo è stato bloccato
+Comment[ja]=スクリーンがロックされました
+Comment[kk]=Экран бұғатталған
+Comment[km]=អេក្រង់ត្រូវបានចាក់សោ
+Comment[kn]=ಒಂದು ತೆರೆಯನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ
+Comment[ko]=화면 잠김
+Comment[lt]=Ekranas buvo užrakintas
+Comment[lv]=Ekrāns tika slēgts
+Comment[mk]=Екранот беше заклучен
+Comment[ml]=സ്ക്രീന് പൂട്ടിയിരിയ്ക്കുന്നു
+Comment[nb]=Skjermen er nå låst
+Comment[nds]=De Schirm wöör afslaten
+Comment[nl]=Het scherm is vergrendeld
+Comment[nn]=Skjermen er låst
+Comment[pa]=ਸਕਰੀਨ ਨੂੰ ਲਾਕ ਕੀਤਾ ਗਿਆ ਹੈ
+Comment[pl]=Ekran został zablokowany
+Comment[pt]=O ecrã foi bloqueado
+Comment[pt_BR]=A tela foi bloqueada
+Comment[ro]=Ecranul a fost blocat
+Comment[ru]=Экран заблокирован
+Comment[si]=තිරය අගුළු දමා ඇත
+Comment[sk]=Obrazovka bola zamknutá
+Comment[sl]=Zaslon je bil zaklenjen
+Comment[sr]=Екран је управо закључан
+Comment[sr@ijekavian]=Екран је управо закључан
+Comment[sr@ijekavianlatin]=Ekran je upravo zaključan
+Comment[sr@latin]=Ekran je upravo zaključan
+Comment[sv]=Skärmen har låsts
+Comment[tg]=Клавиша модификатора зафиксирована
+Comment[th]=หน้าจอถูกล็อคอยู่
+Comment[tr]=Ekran kilitlendi
+Comment[ug]=ئېكران قۇلۇپلانغان
+Comment[uk]=Екран було заблоковано
+Comment[wa]=Li waitroûle a stî eclawêye
+Comment[x-test]=xxThe screen has been lockedxx
+Comment[zh_CN]=屏幕已经被锁定
+Comment[zh_TW]=螢幕已被鎖定
+Action=None
+
+[Event/savingstopped]
+Name=Screen saver exited
+Name[ar]=خرجت حافظة الشاشة
+Name[ast]=Finó'l curiapantalles
+Name[bg]=Екранният предпазител е спрян
+Name[bs]=Čuvar ekrana napušten
+Name[ca]=S'ha sortit de l'estalvi de pantalla
+Name[ca@valencia]=S'ha eixit de l'estalvi de pantalla
+Name[cs]=Šetřič obrazovky ukončen
+Name[csb]=Wëgaszôcz ekranu òstôł zakùńczony
+Name[da]=Pauseskærm afslutter
+Name[de]=Der Bildschirmschoner wurde beendet.
+Name[el]=Η προφύλαξη οθόνης τερμάτισε
+Name[en_GB]=Screen saver exited
+Name[eo]=Ekrankurteno finiĝis
+Name[es]=El salvapantallas ha terminado
+Name[et]=Ekraanisäästja lõpetas töö
+Name[eu]=Pantaila babeslea amaituta
+Name[fi]=Näytönsäästäjä sulkeutui
+Name[fr]=Écran de veille terminé
+Name[fy]=Skermbefeiliging is der útgong
+Name[ga]=Scoireadh ón spárálaí scáileáin
+Name[gl]=O protector de pantalla saíu
+Name[he]=שומר המסך הפסיק
+Name[hi]=स्क्रीन सेवर बंद
+Name[hr]=Zaštita zaslona završila
+Name[hu]=A képernyővédő kilépett
+Name[ia]=Salvator de schermo exite
+Name[id]=Penyimpan layar keluar
+Name[is]=Hætt í skjásvæfu
+Name[it]=Salvaschermo terminato
+Name[ja]=スクリーンセーバー終了
+Name[kk]=Экран қорғаушысы тоқтады
+Name[km]=បានចេញពីធាតុរក្សាអេក្រង់
+Name[kn]=ಸ್ಕ್ರೀನ್ ಸೇವರ್ ನಿರ್ಗಮಿಸಿದೆ
+Name[ko]=화면 보호기 종료됨
+Name[lt]=Ekrano užsklanda išsijungė
+Name[lv]=Ekrāna saudzētājs apturēts
+Name[mk]=Чуварот на екранот излезе
+Name[ml]=സ്ക്രീന് സേവറില് നിന്നും പുറത്തു് കടന്നിരിയ്ക്കുന്നു
+Name[nb]=Pauseskjermen avsluttet
+Name[nds]=Pausschirm utmaakt
+Name[nl]=Schermbeveiliger geëindigd
+Name[nn]=Pauseskjermen er avslutta
+Name[pa]=ਸਕਰੀਨ ਸੇਵਰ ਬੰਦ
+Name[pl]=Wygaszacz ekranu zakończył się
+Name[pt]=O protector de ecrã terminou
+Name[pt_BR]=O protetor de tela terminou
+Name[ro]=Protecția de ecran a s-a terminat
+Name[ru]=Хранитель экрана завершил работу
+Name[si]=තිර සුරැකුම ඉවත් විය
+Name[sk]=Šetrič obrazovky skončil
+Name[sl]=Izhod iz ohranjevalnika zaslona
+Name[sr]=Чувар екрана напуштен
+Name[sr@ijekavian]=Чувар екрана напуштен
+Name[sr@ijekavianlatin]=Čuvar ekrana napušten
+Name[sr@latin]=Čuvar ekrana napušten
+Name[sv]=Skärmsläckare avslutades
+Name[tg]=Пардаи экран хомӯш шуд
+Name[th]=โปรแกรมรักษาจอภาพจบการทำงานแล้ว
+Name[tr]=Ekran koruyucudan çıkıldı
+Name[ug]=ئېكران قوغدىغۇچ ئاخىرلاشتى
+Name[uk]=Завершено роботу зберігача екрана
+Name[wa]=Sipårgneu di waitroûle a cwité
+Name[x-test]=xxScreen saver exitedxx
+Name[zh_CN]=屏幕保护程序已退出
+Name[zh_TW]=螢幕保護程式已離開
+Comment=The screen saver has finished
+Comment[ar]=حافظة الشاشة انتهت
+Comment[ast]=Finó'l curiapantalles
+Comment[bg]=Екранният предпазител е спрян
+Comment[bs]=Čuvar ekrana se upravo okončao
+Comment[ca]=L'estalvi de pantalla ha finalitzat
+Comment[ca@valencia]=L'estalvi de pantalla ha finalitzat
+Comment[cs]=Šetřič obrazovky byl ukončen
+Comment[csb]=Wëgaszôcz ekranu òstôł zakùńczony
+Comment[da]=Pauseskærmen er afsluttet
+Comment[de]=Der Bildschirmschoner wurde beendet.
+Comment[el]=Η προφύλαξη οθόνης έχει τελειώσει
+Comment[en_GB]=The screen saver has finished
+Comment[eo]=La ekrankurteno finiĝis
+Comment[es]=El salvapantallas ha terminado
+Comment[et]=Ekraanisäästja lõpetas töö
+Comment[eu]=Pantaila babeslea amaitu da
+Comment[fi]=Näytönsäästäjä on päättynyt
+Comment[fr]=L'écran de veille a terminé
+Comment[fy]=De skermbefeiliging is foltôge
+Comment[ga]=Tá an spárálaí scáileán críochnaithe
+Comment[gl]=O protector de pantalla rematou
+Comment[gu]=સ્ક્રિન સેવર પૂર્ણ થયું છે
+Comment[he]=שומר המסך הפסיק
+Comment[hi]=स्क्रीन सेवर समाप्त हुआ
+Comment[hr]=Zaštita zaslona je završila
+Comment[hu]=A képernyővédő befejeződött
+Comment[ia]=Le salvator de schermo ha finite
+Comment[id]=Penyimpan layar telah selesai
+Comment[is]=Skjáhvílan hefur lokið sér af
+Comment[it]=Il salvaschermo si è concluso
+Comment[ja]=スクリーンセーバーが終了しました
+Comment[kk]=Экран қорғаушысы жұмысын тоқтатты
+Comment[km]=បានបញ្ចប់ធាតុរក្សាអេក្រង់
+Comment[kn]=ತೆರೆ ರಕ್ಷಕ (ಸ್ಕ್ರೀನ್ ಸೇವರ್) ಅಂತ್ಯಗೊಂಡಿದೆ
+Comment[ko]=화면 보호기 종료됨
+Comment[lt]=Ekrano užsklanda baigė darbą
+Comment[lv]=Ekrāna saudzētājs tika apturēts
+Comment[mk]=Чуварот на екранот заврши
+Comment[ml]=സ്ക്രീന് സേവര് അവസാനിച്ചു
+Comment[nb]=Pauseskjermen er ferdig
+Comment[nds]=De Pausschirm wöör utmaakt
+Comment[nl]=De schermbeveiliging is geëindigd
+Comment[nn]=Pauseskjermen er ferdig
+Comment[pa]=ਸਕਰੀਨ ਸੇਵਰ ਮੁਕੰਮਲ
+Comment[pl]=Wygaszacz ekranu zakończył działanie
+Comment[pt]=O protector de ecrã terminou
+Comment[pt_BR]=O protetor de tela terminou
+Comment[ro]=Protecția de ecran s-a încheiat
+Comment[ru]=Хранитель экрана завершил работу
+Comment[si]=තිරසුරැකුම අවසන් විය
+Comment[sk]=Šetrič obrazovky bol ukončený
+Comment[sl]=Ohranjevalnik zaslona se je zaključil
+Comment[sr]=Чувар екрана се управо окончао
+Comment[sr@ijekavian]=Чувар екрана се управо окончао
+Comment[sr@ijekavianlatin]=Čuvar ekrana se upravo okončao
+Comment[sr@latin]=Čuvar ekrana se upravo okončao
+Comment[sv]=Skärmsläckaren har avslutats
+Comment[th]=โปรแกรมรักษาจอภาพทำงานเสร็จสิ้นแล้ว
+Comment[tr]=Ekran koruyucu bitti
+Comment[ug]=ئېكران قوغدىغۇچ ئاخىرلاشتى
+Comment[uk]=Роботу зберігача екрана завершено
+Comment[wa]=Li spårgneu di waitroûle a cwité
+Comment[x-test]=xxThe screen saver has finishedxx
+Comment[zh_CN]=屏幕保护程序已运行完成
+Comment[zh_TW]=螢幕保護程式已完成
+Action=None
+
+[Event/unlocked]
+Name=Screen unlocked
+Name[ar]=فُكًَ قفل الشاشة
+Name[ast]=Pantalla desbloquiada
+Name[bg]=Екранът е отключен
+Name[bs]=Ekran otključan
+Name[ca]=Pantalla desbloquejada
+Name[ca@valencia]=Pantalla desbloquejada
+Name[cs]=Obrazovka odemknuta
+Name[csb]=Ekran òdblokòwóny
+Name[da]=Skærmen er låst op
+Name[de]=Bildschirm freigegeben
+Name[el]=Οθόνη ξεκλείδωτη
+Name[en_GB]=Screen unlocked
+Name[eo]=Ekrano malŝlosita
+Name[es]=Pantalla desbloqueada
+Name[et]=Ekraan on lahtilukustatud
+Name[eu]=Pantaila desblokeatuta
+Name[fi]=Näytön lukitus aukeni
+Name[fr]=Écran déverrouillé
+Name[fy]=Skerm ûntskoattele
+Name[ga]=Scáileán díghlasáilte
+Name[gl]=A pantalla desatrancouse
+Name[gu]=સ્ક્રિનનું તાળું ખૂલેલ છે
+Name[he]=המסך שוחרר
+Name[hi]=स्क्रीन तालाबंद
+Name[hr]=Zaslon otključan
+Name[hu]=A képernyő feloldva
+Name[ia]=Schermo disblocate
+Name[id]=Layar tidak dikunci
+Name[is]=Skjár aflæstur
+Name[it]=Schermo sbloccato
+Name[ja]=スクリーンロック解除
+Name[kk]=Экран бұғаты шешілді
+Name[km]=បានដោះសោអេក្រង់
+Name[kn]=ತೆರೆಯನ್ನು ಅನ್ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ
+Name[ko]=화면 잠금 풀림
+Name[lt]=Ekranas atrakintas
+Name[lv]=Ekrāns atslēgts
+Name[mk]=Екранот е отклучен
+Name[ml]=സ്ക്രീന് തുറന്നു
+Name[nb]=Skjermen låst opp
+Name[nds]=Schirm opslaten
+Name[nl]=Scherm ontgrendeld
+Name[nn]=Skjermen er låst opp
+Name[pa]=ਸਕਰੀਨ ਅਣ-ਲਾਕ ਹੈ
+Name[pl]=Ekran odblokowany
+Name[pt]=Ecrã desbloqueado
+Name[pt_BR]=Tela desbloqueada
+Name[ro]=Ecran deblocat
+Name[ru]=Экран разблокирован
+Name[si]=තිරය අගුළු හැරිනි
+Name[sk]=Obrazovka odomknutá
+Name[sl]=Odklep zaslona
+Name[sr]=Екран откључан
+Name[sr@ijekavian]=Екран откључан
+Name[sr@ijekavianlatin]=Ekran otključan
+Name[sr@latin]=Ekran otključan
+Name[sv]=Skärm upplåst
+Name[tg]=Экран кушода шуд
+Name[th]=ปลดล็อคหน้าจอแล้ว
+Name[tr]=Ekranın kilidi açıldı
+Name[ug]=ئېكران قۇلۇپسىزلاندى
+Name[uk]=Екран розблоковано
+Name[wa]=Waitroûle dizeclawêye
+Name[x-test]=xxScreen unlockedxx
+Name[zh_CN]=屏幕已解锁
+Name[zh_TW]=螢幕已解除鎖定
+Comment=The screen has been unlocked
+Comment[ar]=تم قفل الشاشة
+Comment[ast]=Desbloquióse la pantalla
+Comment[bg]=Екранът е отключен
+Comment[bs]=Ekran je upravo otključan
+Comment[ca]=S'ha desbloquejat la pantalla
+Comment[ca@valencia]=S'ha desbloquejat la pantalla
+Comment[cs]=Obrazovka byla odemknuta
+Comment[csb]=Ekran òstôł òdblokòwóny
+Comment[da]=Skærmen er blevet låst op
+Comment[de]=Der Bildschirm wurde freigegeben.
+Comment[el]=Η οθόνη έχει ξεκλειδωθεί
+Comment[en_GB]=The screen has been unlocked
+Comment[eo]=La ekrano malŝlosiĝis
+Comment[es]=Se ha desbloqueado la pantalla
+Comment[et]=Ekraan on lahtilukustatud
+Comment[eu]=Pantaila desblokeatu da
+Comment[fi]=Näytön lukitus on avautunut
+Comment[fr]=L'écran a été déverrouillé
+Comment[fy]=It skerm is ûntskoattele
+Comment[ga]=Tá an scáileán díghlasáilte
+Comment[gl]=A pantalla desatrancouse
+Comment[he]=המסך שוחרר
+Comment[hr]=Zaslon je otključan
+Comment[hu]=A képernyő feloldva
+Comment[ia]=Le schermo ha essite disblocate
+Comment[id]=Layar telah tidak dikunci
+Comment[is]=Skjánum hefur verið aflæst
+Comment[it]=Lo schermo è stato sbloccato
+Comment[ja]=スクリーンのロックが解除されました
+Comment[kk]=Экраннан бұғаты шешілді
+Comment[km]=ធាតុរក្សាអេក្រង់ត្រូវបានដោះសោ
+Comment[kn]=ತೆರೆಯನ್ನು ಅನ್ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ
+Comment[ko]=화면 잠금 풀림
+Comment[lt]=Ekranas buvo atrakintas
+Comment[lv]=Ekrāns tika atslēgts
+Comment[mk]=Екранот беше отклучен
+Comment[ml]=സ്ക്രീന് തുറന്നിരിയ്ക്കുന്നു
+Comment[nb]=Skjermen er blitt låst opp
+Comment[nds]=De Schirm wöör opslaten
+Comment[nl]=Het scherm is ontgrendeld
+Comment[nn]=Skjermen er låst opp
+Comment[pa]=ਸਕਰੀਨ ਨੂੰ ਅਣ-ਲਾਕ ਕੀਤਾ ਗਿਆ
+Comment[pl]=Ekran został odblokowany
+Comment[pt]=O ecrã foi desbloqueado
+Comment[pt_BR]=A tela foi desbloqueada
+Comment[ro]=Ecranul a fost deblocat
+Comment[ru]=Экран разблокирован
+Comment[si]=තිරය අගුළු හැර ඇත
+Comment[sk]=Obrazovka bola odomknutá
+Comment[sl]=Zaslon je bil odklenjen
+Comment[sr]=Екран је управо откључан
+Comment[sr@ijekavian]=Екран је управо откључан
+Comment[sr@ijekavianlatin]=Ekran je upravo otključan
+Comment[sr@latin]=Ekran je upravo otključan
+Comment[sv]=Skärmen har låsts upp
+Comment[tg]=Клавиша модификатора зафиксирована
+Comment[th]=หน้าจอถูกปลดล็อคแล้ว
+Comment[tr]=Ekranın kilidi açıldı
+Comment[ug]=ئېكران قۇلۇپسىزلانغان
+Comment[uk]=Екран було розблоковано
+Comment[wa]=Li waitroûle a stî dizeclawêye
+Comment[x-test]=xxThe screen has been unlockedxx
+Comment[zh_CN]=屏幕已经被解锁
+Comment[zh_TW]=螢幕已解除鎖定
+Action=None
+
+[Event/unlockfailed]
+Name=Screen unlock failed
+Name[ar]=فشل فك قفل الشاشة
+Name[ast]=Nun pudo desbloquiase la pantalla
+Name[bg]=Грешка при отключване на екрана
+Name[bs]=Otključavanje ekrana neuspelo
+Name[ca]=Ha fallat el desbloqueig de la pantalla
+Name[ca@valencia]=Ha fallat el desbloqueig de la pantalla
+Name[cs]=Odemknutí obrazovky selhalo
+Name[csb]=Felënk òdblokòwaniô ekranu
+Name[da]=Det mislykkedes at låse skærmen op
+Name[de]=Entsperren des Bildschirms fehlgeschlagen
+Name[el]=Το ξεκλειδωμα της οθόνης απέτυχε
+Name[en_GB]=Screen unlock failed
+Name[eo]=Malŝlositado de ekrano fiaskis
+Name[es]=No se pudo desbloquear la pantalla
+Name[et]=Ekraani lahtilukustamine nurjus
+Name[eu]=Pantaila desblokeatzeak huts egin du
+Name[fi]=Näytön lukinnan poisto epäonnistui
+Name[fr]=Le déverrouillage de l'écran a échoué
+Name[fy]=Skerm ûntskoatteling is mislearre
+Name[ga]=Níorbh fhéidir an scáileán a dhíghlasáil
+Name[gl]=Fallou o desbloqueo da pantalla
+Name[gu]=સ્ક્રિનનું તાળું ખોલવામાં નિષ્ફળ
+Name[he]=שיחרור המסך נכשל
+Name[hi]=स्क्रीन ताला नहीं खुला
+Name[hr]=Neuspjelo otključavanje zaslona
+Name[hu]=Nem sikerült feloldani a képernyőt
+Name[ia]=Disbloco de schermo falleva
+Name[id]=Gagal membuka kunci
+Name[is]=Aflæsing skjásins mistókst
+Name[it]=Sblocco dello schermo non riuscito
+Name[ja]=スクリーンのロック解除失敗
+Name[kk]=Экран бұғатын шешуі болмады
+Name[km]=បានបរាជ័យក្នុងការដោះសោអេក្រង់
+Name[kn]=ತೆರೆಯನ್ನು ಅನ್ ಲಾಕ್ ಮಾಡುವುದು ವಿಫಲವಾಗಿದೆ
+Name[ko]=화면 잠금 풀리지 않음
+Name[lt]=Ekrano atrakinimas nepavyko
+Name[lv]=Neizdevās atslēgt ekrānu
+Name[mk]=Не успеа отклучувањето на екранот
+Name[ml]=സ്ക്രീന് തുറക്കുന്നതില് പരാജയപ്പെട്ടു
+Name[nb]=Det lyktes ikke å låse opp skjermen
+Name[nds]=Opsluten vun den Schirm fehlslaan
+Name[nl]=Ontgrendelen van scherm is mislukt
+Name[nn]=Klarte ikkje låsa opp skjermen
+Name[pa]=ਸਕਰੀਨ ਖੋਲ੍ਹਣ ਲਈ ਫੇਲ੍ਹ
+Name[pl]=Odblokowanie ekranu nieudane
+Name[pt]=O desbloqueio do ecrã foi mal-sucedido
+Name[pt_BR]=O bloqueio de tela falhou
+Name[ro]=Deblocare ecranului a eșuat
+Name[ru]=Не удалось разблокировать экран
+Name[si]=තිරය අගුළු හැරීම අසාර්ථකයි
+Name[sk]=Odomknutie obrazovky zlyhalo
+Name[sl]=Spodletel odklep zaslona
+Name[sr]=Откључавање екрана неуспело
+Name[sr@ijekavian]=Откључавање екрана неуспјело
+Name[sr@ijekavianlatin]=Otključavanje ekrana neuspjelo
+Name[sr@latin]=Otključavanje ekrana neuspelo
+Name[sv]=Upplåsning av skärm misslyckades
+Name[tg]=Кушодани экран қатъ карда шуд
+Name[th]=ล้มเหลวในการปลดล็อคหน้าจอ
+Name[tr]=Ekran kilidi açılamadı
+Name[ug]=ئېكران قۇلۇپسىزلاش مەغلۇپ بولدى
+Name[uk]=Невдала спроба розблокування екрана
+Name[wa]=Li dizeclawaedje del waitroûle a fwait berwete
+Name[x-test]=xxScreen unlock failedxx
+Name[zh_CN]=屏幕解锁失败
+Name[zh_TW]=螢幕解除鎖定失敗
+Comment=Failed attempt to unlock the screen
+Comment[ar]=محاولة فاشلة لفك قفل الشاشة
+Comment[ast]=Fallu al intentar desbloquiar la pantalla
+Comment[bg]=Грешка при опит за отключване на екрана
+Comment[bs]=Pokušaj otključavanja ekrana nije uspeo
+Comment[ca]=L'intent de desbloquejar la pantalla ha fallat
+Comment[ca@valencia]=L'intent de desbloquejar la pantalla ha fallat
+Comment[cs]=Pokus o odemknutí obrazovky selhal
+Comment[csb]=Felënk przëstãpù do òdblokòwaniô ekranu
+Comment[da]=Mislykket forsøg på at låse skærmen op
+Comment[de]=Das Entsperren des Bildschirms ist fehlgeschlagen.
+Comment[el]=Αποτυχής προσπάθεια ξεκλειδώματος οθόνης
+Comment[en_GB]=Failed attempt to unlock the screen
+Comment[eo]=Provo de malŝlosi ekranon fiaskis
+Comment[es]=Error al intentar desbloquear la pantalla
+Comment[et]=Nurjunud katse ekraani lahti lukustada
+Comment[eu]=Pantaila desblokeatzeko saiakerak huts egin du
+Comment[fi]=Yritys näytön lukituksen poistamiseksi epäonnistui
+Comment[fr]=Tentative infructueuse de déverrouiller l'écran
+Comment[fy]=It is net slagge om it skerm te ûntskoatteljen
+Comment[ga]=Theip ar iarracht an scáileán a dhíghlasáil
+Comment[gl]=Fallou a tentativa de desbloquear a pantalla
+Comment[he]=ניסיון כושל לשיחרור המסך
+Comment[hr]=Propao je pokušaj otključavanja zaslona
+Comment[hu]=Nem sikerült feloldani a képernyőt
+Comment[ia]=Tentativa fallite de disblocar le schermo
+Comment[id]=Gagal mencoba membuka kunci layar
+Comment[is]=Tilraun til að aflæsa skjánum mistókst
+Comment[it]=Tentanivo di sbloccare lo schermo non riuscito
+Comment[ja]=スクリーンのロックを解除できませんでした
+Comment[kk]=Экран бұғатын шешу әректі сәтсіз аяқталды
+Comment[km]=បានបរាជ័យក្នុងការដោះសោអេក្រង់
+Comment[kn]=ತೆರೆಯನ್ನು ಅನ್ ಲಾಕ್ ಮಾಡುವ ವಿಫಲ ಯತ್ನ
+Comment[ko]=화면 잠금 풀리지 않음
+Comment[lt]=Nepavyko bandymas atrakinti ekraną
+Comment[lv]=Neizdevās atslēgt ekrānu
+Comment[mk]=Не успеа обидот да се отклучи екранот
+Comment[ml]=സ്ക്രീന് തുറക്കാനുള്ള ശ്രമം പരാജയപ്പെട്ടിരിയ്ക്കുന്നു
+Comment[nb]=Klarte ikke å låse opp skjermen
+Comment[nds]=Opsluten vun den Schirm hett nich funkscheneert
+Comment[nl]=Een mislukte poging om het scherm te ontgrendelen
+Comment[nn]=Forsøket på å låsa opp skjermen var mislukka
+Comment[pa]=ਸਕਰੀਨ ਅਣ-ਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਫੇਲ੍ਹ ਹੋਈ
+Comment[pl]=Nieudana próba odblokowania ekranu
+Comment[pt]=Falhou a tentativa de desbloquear o ecrã
+Comment[pt_BR]=A tentativa de desbloquear a tela falhou
+Comment[ro]=Încercare eșuată de a debloca ecranul
+Comment[ru]=Не удалось разблокировать экран
+Comment[si]=තිරය අගුළු හැරිමේ උත්සාහය අසාර්ථකයි
+Comment[sk]=Neúspešný pokus o odomknutie obrazovky
+Comment[sl]=Spodletel poskus odklepa zaslona
+Comment[sr]=Покушај откључавања екрана није успео
+Comment[sr@ijekavian]=Покушај откључавања екрана није успио
+Comment[sr@ijekavianlatin]=Pokušaj otključavanja ekrana nije uspio
+Comment[sr@latin]=Pokušaj otključavanja ekrana nije uspeo
+Comment[sv]=Misslyckat försök att låsa upp skärmen
+Comment[th]=ล้มเหลวในการพยายามปลดล็อคหน้าจอ
+Comment[tr]=Ekran kilidini açma denemesi başarısız oldu
+Comment[ug]=ئېكراننى قۇلۇپسىزلاندۇرالمىدى
+Comment[uk]=Спроба розблокування екрана завершилася невдало
+Comment[wa]=Li saye di dizeclawaedje del waitroûle a fwait berwete
+Comment[x-test]=xxFailed attempt to unlock the screenxx
+Comment[zh_CN]=尝试解锁屏幕失败
+Comment[zh_TW]=螢幕解除鎖定失敗
+Action=None
diff --git a/kwin/screenlocker/lock/lockdlg.cc b/kwin/screenlocker/lock/lockdlg.cc
new file mode 100644
index 0000000..14a9b34
--- /dev/null
+++ b/kwin/screenlocker/lock/lockdlg.cc
@@ -0,0 +1,667 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 1999 Martin R. Jones
+// Copyright 2003 Chris Howells
+// Copyright 2003 Oswald Buddenhagen
+
+#include // HAVE_PAM
+
+#include "lockprocess.h"
+#include "lockdlg.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+// #include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif
+
+#define PASSDLG_HIDE_TIMEOUT 10000
+
+//===========================================================================
+//
+// Simple dialog for entering a password.
+//
+PasswordDlg::PasswordDlg(LockProcess *parent, GreeterPluginHandle *plugin, const QString &text)
+ : KDialog(parent, Qt::X11BypassWindowManagerHint),
+ mPlugin( plugin ),
+ mCapsLocked(-1),
+ mUnlockingFailed(false),
+ sNot(0)
+{
+ QWidget* w = mainWidget();
+
+ QLabel *pixLabel = new QLabel( w );
+ pixLabel->setPixmap(DesktopIcon(QLatin1String( "system-lock-screen" )));
+
+ KUser user; QString fullName=user.property(KUser::FullName).toString();
+ QString greetString = text;
+ if (text.isEmpty()) {
+ greetString = fullName.isEmpty() ?
+ i18n("The session is locked
") :
+ i18n("The session was locked by %1
", fullName );
+ }
+ QLabel *greetLabel = new QLabel(greetString, w);
+
+ mStatusLabel = new QLabel( QLatin1String( " " ), w );
+ mStatusLabel->setAlignment( Qt::AlignCenter );
+
+ greet = plugin->info->create(this, w, QString(),
+ KGreeterPlugin::Authenticate,
+ KGreeterPlugin::ExUnlock);
+
+ KSeparator *sep = new KSeparator( Qt::Horizontal, w );
+
+ ok = new KPushButton( KGuiItem(i18n("Unl&ock"), QLatin1String( "object-unlocked" )), w );
+ cancel = new KPushButton( KStandardGuiItem::cancel(), w );
+ mNewSessButton = new KPushButton( KGuiItem(i18n("Sw&itch User..."), QLatin1String( "fork" )), w );
+
+ // Using keyboard layout component
+ KPluginFactory *kxkbFactory = KPluginLoader(QLatin1String( "keyboard_layout_widget" )).factory();
+ QWidget *kxkbComponent = NULL;
+ if (kxkbFactory) {
+ kxkbComponent = kxkbFactory->create(this);
+ }
+ else {
+ kDebug() << "can't load keyboard layout widget library";
+ }
+
+ QHBoxLayout *layStatus = new QHBoxLayout();
+ layStatus->addStretch();
+ layStatus->addWidget( mStatusLabel );
+ layStatus->addStretch();
+
+ if( kxkbComponent ) {
+ //TODO: without this the widget is off the parent area, but we need something better here
+ kxkbComponent->setFixedSize(48, 24);
+ layStatus->addWidget( kxkbComponent, 0, Qt::AlignRight );
+ }
+
+ QHBoxLayout *layButtons = new QHBoxLayout();
+ layButtons->addWidget( mNewSessButton );
+ layButtons->addStretch();
+ layButtons->addWidget( ok );
+ layButtons->addWidget( cancel );
+
+ frameLayout = new QGridLayout( w );
+ frameLayout->setSpacing( KDialog::spacingHint() );
+ frameLayout->setMargin( KDialog::marginHint() );
+ frameLayout->addWidget( pixLabel, 0, 0, 3, 1, Qt::AlignTop );
+ frameLayout->addWidget( greetLabel, 0, 1 );
+ frameLayout->addWidget( greet->getWidgets().first(), 1, 1 );
+ frameLayout->addLayout( layStatus, 2, 1 );
+ frameLayout->addWidget( sep, 3, 0, 1, 2 );
+ frameLayout->addLayout( layButtons, 4, 0, 1, 2 );
+
+ setButtons(None);
+ connect(cancel, SIGNAL(clicked()), SLOT(reject()));
+ connect(ok, SIGNAL(clicked()), SLOT(slotOK()));
+ connect(mNewSessButton, SIGNAL(clicked()), SLOT(slotSwitchUser()));
+
+ if (!text.isEmpty() || !KDisplayManager().isSwitchable() || !KAuthorized::authorizeKAction(QLatin1String( "switch_user" )))
+ mNewSessButton->hide();
+
+ installEventFilter(this);
+
+ mFailedTimerId = 0;
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+ connect(qApp, SIGNAL(activity()), SLOT(slotActivity()) );
+
+ greet->start();
+
+ capsLocked();
+}
+
+PasswordDlg::~PasswordDlg()
+{
+ hide();
+ delete greet;
+}
+
+void PasswordDlg::updateLabel()
+{
+ if (mUnlockingFailed)
+ {
+ QPalette palette;
+ KColorScheme::adjustForeground(palette, KColorScheme::NormalText, QPalette::WindowText);
+ mStatusLabel->setPalette(palette);
+ mStatusLabel->setText(i18n("Unlocking failed"));
+ }
+ else
+ if (mCapsLocked)
+ {
+ QPalette palette = mStatusLabel->palette();
+ KColorScheme::adjustForeground(palette, KColorScheme::NegativeText, QPalette::WindowText);
+ mStatusLabel->setPalette(palette);
+ mStatusLabel->setText(i18n("Warning: Caps Lock on"));
+ }
+ else
+ {
+ mStatusLabel->setText(QLatin1String( " " ));
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Handle timer events.
+//
+void PasswordDlg::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == mTimeoutTimerId)
+ {
+ done(TIMEOUT_CODE);
+ }
+ else if (ev->timerId() == mFailedTimerId)
+ {
+ killTimer(mFailedTimerId);
+ mFailedTimerId = 0;
+ // Show the normal password prompt.
+ mUnlockingFailed = false;
+ updateLabel();
+ ok->setEnabled(true);
+ cancel->setEnabled(true);
+ mNewSessButton->setEnabled( true );
+ greet->revive();
+ greet->start();
+ }
+}
+
+bool PasswordDlg::eventFilter(QObject *, QEvent *ev)
+{
+ if (ev->type() == QEvent::KeyPress || ev->type() == QEvent::KeyRelease)
+ capsLocked();
+ return false;
+}
+
+void PasswordDlg::slotActivity()
+{
+ if (mTimeoutTimerId) {
+ killTimer(mTimeoutTimerId);
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+ }
+}
+
+////// kckeckpass interface code
+
+int PasswordDlg::Reader (void *buf, int count)
+{
+ int ret, rlen;
+
+ for (rlen = 0; rlen < count; ) {
+ dord:
+ ret = ::read (sFd, (void *)((char *)buf + rlen), count - rlen);
+ if (ret < 0) {
+ if (errno == EINTR)
+ goto dord;
+ if (errno == EAGAIN)
+ break;
+ return -1;
+ }
+ if (!ret)
+ break;
+ rlen += ret;
+ }
+ return rlen;
+}
+
+bool PasswordDlg::GRead (void *buf, int count)
+{
+ return Reader (buf, count) == count;
+}
+
+bool PasswordDlg::GWrite (const void *buf, int count)
+{
+ return ::write (sFd, buf, count) == count;
+}
+
+bool PasswordDlg::GSendInt (int val)
+{
+ return GWrite (&val, sizeof(val));
+}
+
+bool PasswordDlg::GSendStr (const char *buf)
+{
+ int len = buf ? ::strlen (buf) + 1 : 0;
+ return GWrite (&len, sizeof(len)) && GWrite (buf, len);
+}
+
+bool PasswordDlg::GSendArr (int len, const char *buf)
+{
+ return GWrite (&len, sizeof(len)) && GWrite (buf, len);
+}
+
+bool PasswordDlg::GRecvInt (int *val)
+{
+ return GRead (val, sizeof(*val));
+}
+
+bool PasswordDlg::GRecvArr (char **ret)
+{
+ int len;
+ char *buf;
+
+ if (!GRecvInt(&len))
+ return false;
+ if (!len) {
+ *ret = 0;
+ return true;
+ }
+ if (!(buf = (char *)::malloc (len)))
+ return false;
+ *ret = buf;
+ if (GRead (buf, len)) {
+ return true;
+ } else {
+ ::free(buf);
+ *ret = 0;
+ return false;
+ }
+}
+
+void PasswordDlg::reapVerify()
+{
+ sNot->setEnabled( false );
+ sNot->deleteLater();
+ sNot = 0;
+ ::close( sFd );
+ int status;
+ while (::waitpid( sPid, &status, 0 ) < 0)
+ if (errno != EINTR) { // This should not happen ...
+ cantCheck();
+ return;
+ }
+ if (WIFEXITED(status))
+ switch (WEXITSTATUS(status)) {
+ case AuthOk:
+ greet->succeeded();
+ accept();
+ return;
+ case AuthBad:
+ greet->failed();
+ mUnlockingFailed = true;
+ updateLabel();
+ mFailedTimerId = startTimer(1500);
+ ok->setEnabled(false);
+ cancel->setEnabled(false);
+ mNewSessButton->setEnabled( false );
+ KNotification::event( QLatin1String( "unlockfailed" ) );
+ return;
+ case AuthAbort:
+ return;
+ }
+ cantCheck();
+}
+
+void PasswordDlg::handleVerify()
+{
+ int ret;
+ char *arr;
+
+ if (GRecvInt( &ret )) {
+ switch (ret) {
+ case ConvGetBinary:
+ if (!GRecvArr( &arr ))
+ break;
+ greet->binaryPrompt( arr, false );
+ if (arr)
+ ::free( arr );
+ return;
+ case ConvGetNormal:
+ if (!GRecvArr( &arr ))
+ break;
+ greet->textPrompt( arr, true, false );
+ if (arr)
+ ::free( arr );
+ return;
+ case ConvGetHidden:
+ if (!GRecvArr( &arr ))
+ break;
+ greet->textPrompt( arr, false, false );
+ if (arr)
+ ::free( arr );
+ return;
+ case ConvPutInfo:
+ if (!GRecvArr( &arr ))
+ break;
+ if (!greet->textMessage( arr, false ))
+ static_cast< LockProcess* >(parent())->msgBox( this, QMessageBox::Information, QString::fromLocal8Bit( arr ) );
+ ::free( arr );
+ return;
+ case ConvPutError:
+ if (!GRecvArr( &arr ))
+ break;
+ if (!greet->textMessage( arr, true ))
+ static_cast< LockProcess* >(parent())->msgBox( this, QMessageBox::Warning, QString::fromLocal8Bit( arr ) );
+ ::free( arr );
+ return;
+ }
+ }
+ reapVerify();
+}
+
+////// greeter plugin callbacks
+
+void PasswordDlg::gplugReturnText( const char *text, int tag )
+{
+ GSendStr( text );
+ if (text)
+ GSendInt( tag );
+}
+
+void PasswordDlg::gplugReturnBinary( const char *data )
+{
+ if (data) {
+ unsigned const char *up = (unsigned const char *)data;
+ int len = up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24);
+ if (!len)
+ GSendArr( 4, data );
+ else
+ GSendArr( len, data );
+ } else
+ GSendArr( 0, 0 );
+}
+
+void PasswordDlg::gplugSetUser( const QString & )
+{
+ // ignore ...
+}
+
+void PasswordDlg::cantCheck()
+{
+ greet->failed();
+ static_cast< LockProcess* >(parent())->msgBox( this, QMessageBox::Critical,
+ i18n("Cannot unlock the session because the authentication system failed to work;\n"
+ "you must kill kscreenlocker (pid %1) manually.", getpid()) );
+ greet->revive();
+}
+
+//---------------------------------------------------------------------------
+//
+// Starts the kcheckpass process to check the user's password.
+//
+void PasswordDlg::gplugStart()
+{
+ int sfd[2];
+ char fdbuf[16];
+
+ if (sNot)
+ return;
+ if (::socketpair(AF_LOCAL, SOCK_STREAM, 0, sfd)) {
+ cantCheck();
+ return;
+ }
+ if ((sPid = ::fork()) < 0) {
+ ::close(sfd[0]);
+ ::close(sfd[1]);
+ cantCheck();
+ return;
+ }
+ if (!sPid) {
+ ::close(sfd[0]);
+ sprintf(fdbuf, "%d", sfd[1]);
+ execlp(QFile::encodeName(KStandardDirs::findExe(QLatin1String( "kcheckpass" ))).data(),
+ "kcheckpass",
+ "-m", mPlugin->info->method,
+ "-S", fdbuf,
+ (char *)0);
+ _exit(20);
+ }
+ ::close(sfd[1]);
+ sFd = sfd[0];
+ sNot = new QSocketNotifier(sFd, QSocketNotifier::Read, this);
+ connect(sNot, SIGNAL(activated(int)), SLOT(handleVerify()));
+}
+
+void PasswordDlg::gplugChanged()
+{
+}
+
+void PasswordDlg::gplugActivity()
+{
+ slotActivity();
+}
+
+void PasswordDlg::gplugMsgBox( QMessageBox::Icon type, const QString &text )
+{
+ static_cast< LockProcess* >(parent())->msgBox( this, type, text );
+}
+
+bool PasswordDlg::gplugHasNode( const QString & )
+{
+ return false;
+}
+
+void PasswordDlg::slotOK()
+{
+ greet->next();
+}
+
+
+void PasswordDlg::setVisible( bool visible )
+{
+ QDialog::setVisible( visible );
+
+ if ( visible )
+ QApplication::flush();
+}
+
+void PasswordDlg::slotStartNewSession()
+{
+ if (!KMessageBox::shouldBeShownContinue( QLatin1String( ":confirmNewSession" ) )) {
+ KDisplayManager().startReserve();
+ return;
+ }
+
+ killTimer(mTimeoutTimerId);
+ mTimeoutTimerId = 0;
+
+ KDialog *dialog = new KDialog( this, Qt::X11BypassWindowManagerHint );
+ dialog->setModal( true );
+ dialog->setButtons( KDialog::Yes | KDialog::No );
+ dialog->setButtonGuiItem( KDialog::Yes, KGuiItem(i18n("&Start New Session"), QLatin1String( "fork" )) );
+ dialog->setButtonGuiItem( KDialog::No, KStandardGuiItem::cancel() );
+ dialog->setDefaultButton( KDialog::Yes );
+ dialog->setEscapeButton( KDialog::No );
+
+ bool dontAskAgain = false;
+
+ KMessageBox::createKMessageBox( dialog, QMessageBox::Warning,
+ i18n("You have chosen to open another desktop session "
+ "instead of resuming the current one.\n"
+ "The current session will be hidden "
+ "and a new login screen will be displayed.\n"
+ "An F-key is assigned to each session; "
+ "F%1 is usually assigned to the first session, "
+ "F%2 to the second session and so on. "
+ "You can switch between sessions by pressing "
+ "Ctrl, Alt and the appropriate F-key at the same time. "
+ "Additionally, the KDE Panel and Desktop menus have "
+ "actions for switching between sessions.",
+ 7, 8),
+ QStringList(),
+ i18n("&Do not ask again"), &dontAskAgain,
+ KMessageBox::NoExec );
+
+ int ret = static_cast< LockProcess* >( parent())->execDialog( dialog );
+
+ delete dialog;
+
+ if (ret == KDialog::Yes) {
+ if (dontAskAgain)
+ KMessageBox::saveDontShowAgainContinue( QLatin1String( ":confirmNewSession" ) );
+ KDisplayManager().startReserve();
+ }
+
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+}
+
+class LockListViewItem : public QTreeWidgetItem {
+public:
+ LockListViewItem( QTreeWidget *parent,
+ const QString &sess, const QString &loc, int _vt )
+ : QTreeWidgetItem( parent )
+ , vt( _vt )
+ {
+ setText( 0, sess );
+ setText( 1, loc );
+ }
+
+ int vt;
+};
+
+void PasswordDlg::slotSwitchUser()
+{
+ int p = 0;
+ KDisplayManager dm;
+
+ QDialog dialog( this, Qt::X11BypassWindowManagerHint );
+ dialog.setModal( true );
+
+ QBoxLayout *hbox = new QHBoxLayout( &dialog );
+ hbox->setSpacing( KDialog::spacingHint() );
+ hbox->setMargin( KDialog::marginHint() );
+
+ QBoxLayout *vbox1 = new QVBoxLayout( );
+ hbox->addItem( vbox1 );
+ QBoxLayout *vbox2 = new QVBoxLayout( );
+ hbox->addItem( vbox2 );
+
+ KPushButton *btn;
+
+ SessList sess;
+ if (dm.localSessions( sess )) {
+
+ lv = new QTreeWidget( &dialog );
+ connect( lv, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), SLOT(slotSessionActivated()) );
+ connect( lv, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), &dialog, SLOT(reject()) );
+ lv->setAllColumnsShowFocus( true );
+ lv->setHeaderLabels( QStringList() << i18n("Session") << i18n("Location") );
+ lv->header()->setResizeMode( 0, QHeaderView::Stretch );
+ lv->header()->setResizeMode( 1, QHeaderView::Stretch );
+ QTreeWidgetItem *itm = 0;
+ QString user, loc;
+ int ns = 0;
+ for (SessList::ConstIterator it = sess.constBegin(); it != sess.constEnd(); ++it) {
+ KDisplayManager::sess2Str2( *it, user, loc );
+ itm = new LockListViewItem( lv, user, loc, (*it).vt );
+ if (!(*it).vt)
+ itm->setFlags( itm->flags() & ~Qt::ItemIsEnabled );
+ if ((*it).self) {
+ lv->setCurrentItem( itm );
+ itm->setSelected( true );
+ }
+ ns++;
+ }
+ int fw = lv->frameWidth() * 2;
+ QSize hds( lv->header()->sizeHint() );
+ lv->setMinimumWidth( fw + hds.width() +
+ (ns > 10 ? style()->pixelMetric(QStyle::PM_ScrollBarExtent) : 0 ) );
+ int ih = lv->itemDelegate()->sizeHint(
+ QStyleOptionViewItem(), lv->model()->index( 0, 0 ) ).height();
+ lv->setFixedHeight( fw + hds.height() +
+ ih * (ns < 6 ? 6 : ns > 10 ? 10 : ns) );
+ lv->header()->adjustSize();
+ vbox1->addWidget( lv );
+
+ btn = new KPushButton( KGuiItem(i18nc("session", "&Activate"), QLatin1String( "fork" )), &dialog );
+ connect( btn, SIGNAL(clicked()), SLOT(slotSessionActivated()) );
+ connect( btn, SIGNAL(clicked()), &dialog, SLOT(reject()) );
+ vbox2->addWidget( btn );
+ vbox2->addStretch( 2 );
+ }
+
+ if (KAuthorized::authorizeKAction(QLatin1String( "start_new_session" )) && (p = dm.numReserve()) >= 0)
+ {
+ btn = new KPushButton( KGuiItem(i18n("Start &New Session"), QLatin1String( "fork" )), &dialog );
+ connect( btn, SIGNAL(clicked()), SLOT(slotStartNewSession()) );
+ connect( btn, SIGNAL(clicked()), &dialog, SLOT(reject()) );
+ if (!p)
+ btn->setEnabled( false );
+ vbox2->addWidget( btn );
+ vbox2->addStretch( 1 );
+ }
+
+ btn = new KPushButton( KStandardGuiItem::cancel(), &dialog );
+ connect( btn, SIGNAL(clicked()), &dialog, SLOT(reject()) );
+ vbox2->addWidget( btn );
+
+ static_cast< LockProcess* >(parent())->execDialog( &dialog );
+}
+
+void PasswordDlg::slotSessionActivated()
+{
+ LockListViewItem *itm = (LockListViewItem *)lv->currentItem();
+ if (itm && itm->vt > 0)
+ KDisplayManager().switchVT( itm->vt );
+}
+
+void PasswordDlg::capsLocked()
+{
+ unsigned int lmask;
+ Window dummy1, dummy2;
+ int dummy3, dummy4, dummy5, dummy6;
+ XQueryPointer(QX11Info::display(), DefaultRootWindow( QX11Info::display() ), &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &lmask);
+ mCapsLocked = lmask & LockMask;
+ updateLabel();
+}
+
+#include "lockdlg.moc"
diff --git a/kwin/screenlocker/lock/lockdlg.h b/kwin/screenlocker/lock/lockdlg.h
new file mode 100644
index 0000000..f25e55f
--- /dev/null
+++ b/kwin/screenlocker/lock/lockdlg.h
@@ -0,0 +1,96 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 1999 Martin R. Jones
+// Copyright 2003 Oswald Buddenhagen
+//
+
+#ifndef __LOCKDLG_H__
+#define __LOCKDLG_H__
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+struct GreeterPluginHandle;
+class LockProcess;
+class QFrame;
+class QGridLayout;
+class QLabel;
+class KPushButton;
+class QSocketNotifier;
+class QTreeWidget;
+
+//===========================================================================
+//
+// Simple dialog for entering a password.
+// It does not handle password validation.
+//
+class PasswordDlg : public KDialog, public KGreeterPluginHandler
+{
+ Q_OBJECT
+
+public:
+ PasswordDlg(LockProcess *parent, GreeterPluginHandle *plugin, const QString &text = QString());
+ ~PasswordDlg();
+ virtual void setVisible(bool visible);
+
+ // from KGreetPluginHandler
+ virtual void gplugReturnText( const char *text, int tag );
+ virtual void gplugReturnBinary( const char *data );
+ virtual void gplugSetUser( const QString & );
+ virtual void gplugStart();
+ virtual void gplugChanged();
+ virtual void gplugActivity();
+ virtual void gplugMsgBox( QMessageBox::Icon type, const QString &text );
+ virtual bool gplugHasNode( const QString &id );
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+ virtual bool eventFilter(QObject *, QEvent *);
+
+private Q_SLOTS:
+ void slotSwitchUser();
+ void slotSessionActivated();
+ void slotStartNewSession();
+ void slotOK();
+ void slotActivity();
+ void handleVerify();
+
+private:
+ void capsLocked();
+ void updateLabel();
+ int Reader (void *buf, int count);
+ bool GRead (void *buf, int count);
+ bool GWrite (const void *buf, int count);
+ bool GSendInt (int val);
+ bool GSendStr (const char *buf);
+ bool GSendArr (int len, const char *buf);
+ bool GRecvInt (int *val);
+ bool GRecvArr (char **buf);
+ void reapVerify();
+ void cantCheck();
+ GreeterPluginHandle *mPlugin;
+ KGreeterPlugin *greet;
+ QFrame *frame;
+ QGridLayout *frameLayout;
+ QLabel *mStatusLabel;
+ KPushButton *mNewSessButton, *ok, *cancel;
+ int mFailedTimerId;
+ int mTimeoutTimerId;
+ int mCapsLocked;
+ bool mUnlockingFailed;
+ int sPid, sFd;
+ QSocketNotifier *sNot;
+ QTreeWidget *lv;
+};
+
+#endif
+
diff --git a/kwin/screenlocker/lock/lockprocess.cc b/kwin/screenlocker/lock/lockprocess.cc
new file mode 100644
index 0000000..65c7f1d
--- /dev/null
+++ b/kwin/screenlocker/lock/lockprocess.cc
@@ -0,0 +1,1808 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 1999 Martin R. Jones
+// Copyright 2003 Oswald Buddenhagen
+// Copyright 2008 Chani Armitage
+//
+
+//krunner keeps running and checks user inactivity
+//when it should show screensaver (and maybe lock the session),
+//it starts kscreenlocker, who does all the locking and who
+//actually starts the screensaver
+
+//It's done this way to prevent screen unlocking when krunner
+//crashes
+
+#include "lockprocess.h"
+#include "lockprocessadaptor.h"
+
+#include
+#include
+#include
+#include "lockdlg.h"
+#include "autologout.h"
+#include "kscreensaversettings.h"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include // % operator for QString
+
+#include
+
+#include
+#include
+#include
+#include
+#ifdef HAVE_SETPRIORITY
+#include
+#include
+#endif
+
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_DPMS
+extern "C" {
+#include
+#ifndef Bool
+#define Bool BOOL
+#endif
+#include
+
+#ifndef HAVE_DPMSINFO_PROTO
+Status DPMSInfo ( Display *, CARD16 *, BOOL * );
+#endif
+}
+#endif
+
+#ifdef HAVE_XF86MISC
+#include
+#endif
+
+#ifdef HAVE_GLXCHOOSEVISUAL
+#include
+#endif
+
+#define LOCK_GRACE_DEFAULT 5000
+#define AUTOLOGOUT_DEFAULT 600
+
+static Window gVRoot = 0;
+static Window gVRootData = 0;
+static Atom gXA_VROOT;
+static Atom gXA_SCREENSAVER_VERSION;
+
+//#define CHECK_XSELECTINPUT
+#ifdef CHECK_XSELECTINPUT
+#include
+static bool check_xselectinput = false;
+extern "C"
+int XSelectInput( Display* dpy, Window w, long e )
+{
+ typedef int (*ptr)(Display*, Window, long);
+ static ptr fun = NULL;
+ if( fun == NULL )
+ fun = (ptr)dlsym( RTLD_NEXT, "XSelectInput" );
+ if( check_xselectinput && w == DefaultRootWindow( dpy ))
+ kDebug() << kBacktrace();
+ return fun( dpy, w, e );
+}
+#endif
+
+static QLatin1String s_overlayServiceName("org.kde.plasma-overlay");
+
+//===========================================================================
+//
+// Screen saver handling process. Handles screensaver window,
+// starting screensaver hacks, and password entry.f
+//
+LockProcess::LockProcess(bool child, bool useBlankOnly)
+ : QWidget(0L, Qt::X11BypassWindowManagerHint),
+ mInitialLock(false),
+ mLocked(false),
+ mBusy(false),
+ mPlasmaDBus(0),
+ mServiceWatcher(0),
+ mSetupMode(false),
+ mOpenGLVisual(false),
+ child_saver(child),
+ mParent(0),
+ mUseBlankOnly(useBlankOnly),
+ mSuspended(false),
+ mVisibility(false),
+ mEventRecursed(false),
+ mRestoreXF86Lock(false),
+ mForbidden(false),
+ mAutoLogoutTimerId(0)
+{
+ setObjectName(QLatin1String( "save window" ));
+ setupSignals();
+
+ new LockProcessAdaptor(this);
+ QDBusConnection::sessionBus().registerService(QLatin1String( "org.kde.screenlocker" ));
+ QDBusConnection::sessionBus().registerObject(QLatin1String( "/LockProcess" ), this);
+
+ kapp->installX11EventFilter(this);
+
+ // Get root window size
+ XWindowAttributes rootAttr;
+ QX11Info info;
+ XGetWindowAttributes(QX11Info::display(), RootWindow(QX11Info::display(),
+ info.screen()), &rootAttr);
+ kapp->desktop(); // make Qt set its event mask on the root window first
+ XSelectInput( QX11Info::display(), QX11Info::appRootWindow(),
+ SubstructureNotifyMask | rootAttr.your_event_mask );
+#ifdef CHECK_XSELECTINPUT
+ check_xselectinput = true;
+#endif
+ setGeometry(0, 0, rootAttr.width, rootAttr.height);
+
+ // virtual root property
+ gXA_VROOT = XInternAtom (QX11Info::display(), "__SWM_VROOT", False);
+ gXA_SCREENSAVER_VERSION = XInternAtom (QX11Info::display(), "_SCREENSAVER_VERSION", False);
+
+ connect(&mHackProc, SIGNAL(finished(int, QProcess::ExitStatus)),
+ SLOT(hackExited()));
+
+ mSuspendTimer.setSingleShot(true);
+ connect(&mSuspendTimer, SIGNAL(timeout()), SLOT(suspend()));
+
+ const QStringList dmopt =
+ QString::fromLatin1( ::getenv( "XDM_MANAGED" )).split(QLatin1Char(','), QString::SkipEmptyParts);
+ for (QStringList::ConstIterator it = dmopt.constBegin(); it != dmopt.constEnd(); ++it)
+ if ((*it).startsWith(QLatin1String( "method=" )))
+ mMethod = (*it).mid(7);
+
+ configure();
+
+#ifdef HAVE_DPMS
+ if (mDPMSDepend) {
+ BOOL on;
+ CARD16 state;
+ DPMSInfo(QX11Info::display(), &state, &on);
+ if (on)
+ {
+ connect(&mCheckDPMS, SIGNAL(timeout()), SLOT(checkDPMSActive()));
+ // we can save CPU if we stop it as quickly as possible
+ // but we waste CPU if we check too often -> so take 10s
+ mCheckDPMS.start(10000);
+ }
+ }
+#endif
+
+ greetPlugin.library = 0;
+
+ mSuppressUnlock.setSingleShot(true);
+ connect(&mSuppressUnlock, SIGNAL(timeout()), SLOT(deactivatePlasma()));
+
+ // read the initial information about all toplevel windows
+ Window r, p;
+ Window* real;
+ unsigned nreal;
+ if( XQueryTree( x11Info().display(), x11Info().appRootWindow(), &r, &p, &real, &nreal )
+ && real != NULL ) {
+ KXErrorHandler err; // ignore X errors here
+ for( unsigned i = 0; i < nreal; ++i ) {
+ XWindowAttributes winAttr;
+ if (XGetWindowAttributes(QX11Info::display(), real[ i ], &winAttr)) {
+ WindowInfo info;
+ info.window = real[ i ];
+ info.viewable = ( winAttr.map_state == IsViewable );
+ windowInfo.append( info ); // ordered bottom to top
+ }
+ }
+ XFree( real );
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Destructor - usual cleanups.
+//
+LockProcess::~LockProcess()
+{
+ if (greetPlugin.library) {
+ if (greetPlugin.info->done)
+ greetPlugin.info->done();
+ greetPlugin.library->unload();
+ }
+}
+
+static int signal_pipe[2];
+
+static void sigterm_handler(int)
+{
+ char tmp = 'T';
+ ::write( signal_pipe[1], &tmp, 1);
+}
+
+static void sighup_handler(int)
+{
+ char tmp = 'H';
+ ::write( signal_pipe[1], &tmp, 1);
+}
+
+static void sigusr1_handler(int)
+{
+ char tmp = '1';
+ ::write(signal_pipe[1], &tmp, 1);
+}
+
+void LockProcess::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == mAutoLogoutTimerId)
+ {
+ AutoLogout autologout(this);
+ execDialog(&autologout);
+ }
+}
+
+void LockProcess::setupSignals()
+{
+ struct sigaction act;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+ // ignore SIGINT
+ act.sa_handler=SIG_IGN;
+ sigaction(SIGINT, &act, 0L);
+ // ignore SIGQUIT
+ //act.sa_handler=SIG_IGN;
+ sigaction(SIGQUIT, &act, 0L);
+ // exit cleanly on SIGTERM
+ act.sa_handler= sigterm_handler;
+ sigaction(SIGTERM, &act, 0L);
+ // SIGHUP forces lock
+ act.sa_handler= sighup_handler;
+ sigaction(SIGHUP, &act, 0L);
+ // SIGUSR1 simulates user activity
+ act.sa_handler= sigusr1_handler;
+ sigaction(SIGUSR1, &act, 0L);
+
+ pipe(signal_pipe);
+ QSocketNotifier* notif = new QSocketNotifier(signal_pipe[0], QSocketNotifier::Read, this);
+ connect( notif, SIGNAL(activated(int)), SLOT(signalPipeSignal()));
+}
+
+
+void LockProcess::signalPipeSignal()
+{
+ char tmp;
+ ::read( signal_pipe[0], &tmp, 1);
+ if (tmp == 'T') {
+ quitSaver();
+ } else if (tmp == '1') {
+ // In case SimulateUserActivity (SIGUSR1) is called during the dead-time (mBusy == true).
+ mInitialLock = true;
+ if (!mBusy && mDialogs.isEmpty()) {
+ mBusy = true;
+ quit();
+ mBusy = false;
+ }
+ } else if (tmp == 'H') {
+ if( !mLocked )
+ startLock();
+ }
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::lock(bool initial)
+{
+ if (startSaver()) {
+ // In case of a forced lock we don't react to events during
+ // the dead-time to give the screensaver some time to activate.
+ // That way we don't accidentally show the password dialog before
+ // the screensaver kicks in because the user moved the mouse after
+ // selecting "lock screen", that looks really untidy.
+ mBusy = true;
+ mInitialLock = initial;
+ if (startLock())
+ {
+ QTimer::singleShot(1000, this, SLOT(slotDeadTimePassed()));
+ return true;
+ }
+ stopSaver();
+ mBusy = false;
+ }
+ return false;
+}
+//---------------------------------------------------------------------------
+void LockProcess::slotDeadTimePassed()
+{
+ if (mInitialLock)
+ quit();
+ mBusy = false;
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::defaultSave()
+{
+ mLocked = false;
+ if (startSaver()) {
+ if (mLockGrace >= 0)
+ QTimer::singleShot(mLockGrace, this, SLOT(startLock()));
+ return true;
+ }
+ return false;
+}
+
+bool LockProcess::startSetup()
+{
+ mPlasmaEnabled = true; //force it on in case the user didn't click apply yet
+ mLocked = false;
+ mSetupMode = true;
+ return startSaver();
+ //plasma startup will handle the suppressunlock bit
+}
+//---------------------------------------------------------------------------
+bool LockProcess::dontLock()
+{
+ mLocked = false;
+ return startSaver();
+}
+
+//---------------------------------------------------------------------------
+void LockProcess::quitSaver()
+{
+ stopSaver();
+ qApp->quit();
+}
+
+//---------------------------------------------------------------------------
+//
+// Read and apply configuration.
+//
+void LockProcess::configure()
+{
+ // the configuration is stored in krunner's config file
+ if( KScreenSaverSettings::lock() ) {
+ mLockGrace = KScreenSaverSettings::lockGrace();
+ if (mLockGrace < 0)
+ mLockGrace = 0;
+ else if (mLockGrace > 300000)
+ mLockGrace = 300000; // 5 minutes, keep the value sane
+ } else {
+ mLockGrace = -1;
+ }
+
+ mAutoLogoutTimeout = KScreenSaverSettings::autoLogout() ?
+ KScreenSaverSettings::autoLogoutTimeout() : 0;
+
+#ifdef HAVE_DPMS
+ mDPMSDepend = KScreenSaverSettings::suspendWhenInvisible();
+#endif
+
+ mPriority = KScreenSaverSettings::priority();
+ if (mPriority < 0) mPriority = 0;
+ if (mPriority > 19) mPriority = 19;
+
+ mSaver = KScreenSaverSettings::saver();
+ if (mSaver.isEmpty() || mUseBlankOnly) {
+ mSaver = QLatin1String( "kblank.desktop" );
+ }
+
+ readSaver();
+
+ mPlasmaEnabled = KScreenSaverSettings::plasmaEnabled();
+
+ mSuppressUnlockTimeout = qMax(0, KScreenSaverSettings::timeout() * 1000);
+ mSuppressUnlockTimeout = qMax(mSuppressUnlockTimeout, 30 * 1000); //min. 30 secs FIXME is this a good idea?
+
+ mPlugins = KScreenSaverSettings::pluginsUnlock();
+ if (mPlugins.isEmpty()) {
+ mPlugins << QLatin1String( "classic" ) << QLatin1String( "generic" );
+ }
+ mPluginOptions = KScreenSaverSettings::pluginOptions();
+}
+
+//---------------------------------------------------------------------------
+//
+// Read the command line needed to run the screensaver given a .desktop file.
+//
+void LockProcess::readSaver()
+{
+ if (!mSaver.isEmpty())
+ {
+ QString entryName = mSaver;
+ if( entryName.endsWith( QLatin1String( ".desktop" ) ))
+ entryName = entryName.left( entryName.length() - 8 ); // strip it
+ const KService::List offers = KServiceTypeTrader::self()->query( QLatin1String( "ScreenSaver" ),
+ QLatin1String( "DesktopEntryName == '" ) + entryName.toLower() + QLatin1Char( '\'' ) );
+ if( offers.isEmpty() )
+ {
+ kDebug(1204) << "Cannot find screesaver: " << mSaver;
+ return;
+ }
+ const QString file = KStandardDirs::locate("services", offers.first()->entryPath());
+
+ const bool opengl = KAuthorized::authorizeKAction(QLatin1String( "opengl_screensavers" ));
+ const bool manipulatescreen = KAuthorized::authorizeKAction(QLatin1String( "manipulatescreen_screensavers" ));
+ KDesktopFile config( file );
+ KConfigGroup desktopGroup = config.desktopGroup();
+ foreach (const QString &type, desktopGroup.readEntry("X-KDE-Type").split(QLatin1Char(';'))) {
+ if (type == QLatin1String("ManipulateScreen")) {
+ if (!manipulatescreen) {
+ kDebug(1204) << "Screensaver is type ManipulateScreen and ManipulateScreen is forbidden";
+ mForbidden = true;
+ }
+ } else if (type == QLatin1String("OpenGL")) {
+ mOpenGLVisual = true;
+ if (!opengl) {
+ kDebug(1204) << "Screensaver is type OpenGL and OpenGL is forbidden";
+ mForbidden = true;
+ }
+ }
+ }
+
+ kDebug(1204) << "mForbidden: " << (mForbidden ? "true" : "false");
+
+ if (config.hasActionGroup(QLatin1String( "Root" )))
+ {
+ mSaverExec = config.actionGroup(QLatin1String( "Root" )).readPathEntry("Exec", QString());
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Create a window to draw our screen saver on.
+//
+void LockProcess::createSaverWindow()
+{
+ Visual* visual = CopyFromParent;
+ int depth = CopyFromParent;
+ XSetWindowAttributes attrs;
+ int flags = CWOverrideRedirect;
+#ifdef HAVE_GLXCHOOSEVISUAL
+// this code is (partially) duplicated in kdebase/workspace/kcontrol/screensaver
+ if( mOpenGLVisual )
+ {
+ static const int attribs[][ 15 ] =
+ {
+ #define R GLX_RED_SIZE
+ #define G GLX_GREEN_SIZE
+ #define B GLX_BLUE_SIZE
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, GLX_DOUBLEBUFFER, None },
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, None }
+ #undef R
+ #undef G
+ #undef B
+ };
+ for( unsigned int i = 0;
+ i < sizeof( attribs ) / sizeof( attribs[ 0 ] );
+ ++i )
+ {
+ if( XVisualInfo* info = glXChooseVisual( x11Info().display(), x11Info().screen(), const_cast(attribs[ i ]) ))
+ {
+ visual = info->visual;
+ depth = info->depth;
+ static Colormap colormap = 0;
+ if( colormap != 0 )
+ XFreeColormap( x11Info().display(), colormap );
+ colormap = XCreateColormap( x11Info().display(), RootWindow( x11Info().display(), x11Info().screen()), visual, AllocNone );
+ attrs.colormap = colormap;
+ flags |= CWColormap;
+ XFree( info );
+ break;
+ }
+ }
+ }
+#endif
+ attrs.override_redirect = 1;
+ hide();
+ Window w = XCreateWindow( x11Info().display(), RootWindow( x11Info().display(), x11Info().screen()),
+ x(), y(), width(), height(), 0, depth, InputOutput, visual, flags, &attrs );
+
+ create( w, false, true );
+
+ // Some xscreensaver hacks check for this property
+ const char *version = "KDE 4.0";
+ XChangeProperty (QX11Info::display(), winId(),
+ gXA_SCREENSAVER_VERSION, XA_STRING, 8, PropModeReplace,
+ (unsigned char *) version, strlen(version));
+
+
+ XSetWindowAttributes attr;
+ attr.event_mask = KeyPressMask | ButtonPressMask | PointerMotionMask |
+ VisibilityChangeMask | ExposureMask;
+ XChangeWindowAttributes(QX11Info::display(), winId(),
+ CWEventMask, &attr);
+
+ // erase();
+
+ // set NoBackground so that the saver can capture the current
+ // screen state if necessary
+ setAttribute(Qt::WA_PaintOnScreen, true);
+ setAttribute(Qt::WA_NoSystemBackground, true);
+ setAttribute(Qt::WA_PaintOutsidePaintEvent, true); // for bitBlt in resume()
+
+ setCursor( Qt::BlankCursor );
+
+ kDebug(1204) << "Saver window Id: " << winId();
+}
+
+//---------------------------------------------------------------------------
+//
+// Hide the screensaver window
+//
+void LockProcess::hideSaverWindow()
+{
+ hide();
+ lower();
+ removeVRoot(winId());
+ XDeleteProperty(QX11Info::display(), winId(), gXA_SCREENSAVER_VERSION);
+ if ( gVRoot ) {
+ unsigned long vroot_data[1] = { gVRootData };
+ XChangeProperty(QX11Info::display(), gVRoot, gXA_VROOT, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)vroot_data, 1);
+ gVRoot = 0;
+ }
+ XSync(QX11Info::display(), False);
+}
+
+//---------------------------------------------------------------------------
+static int ignoreXError(Display *, XErrorEvent *)
+{
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+//
+// Save the current virtual root window
+//
+void LockProcess::saveVRoot()
+{
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+ QX11Info info;
+ Window root = RootWindowOfScreen(ScreenOfDisplay(QX11Info::display(), info.screen()));
+
+ gVRoot = 0;
+ gVRootData = 0;
+
+ int (*oldHandler)(Display *, XErrorEvent *);
+ oldHandler = XSetErrorHandler(ignoreXError);
+
+ if (XQueryTree(QX11Info::display(), root, &rootReturn, &parentReturn,
+ &children, &numChildren))
+ {
+ for (unsigned int i = 0; i < numChildren; i++)
+ {
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ unsigned char *newRoot = 0;
+
+ if ((XGetWindowProperty(QX11Info::display(), children[i], gXA_VROOT, 0, 1,
+ False, XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter,
+ &newRoot) == Success) && newRoot)
+ {
+ gVRoot = children[i];
+ Window *dummy = (Window*)newRoot;
+ gVRootData = *dummy;
+ XFree ((char*) newRoot);
+ break;
+ }
+ }
+ if (children)
+ {
+ XFree((char *)children);
+ }
+ }
+
+ XSetErrorHandler(oldHandler);
+}
+
+//---------------------------------------------------------------------------
+//
+// Set the virtual root property
+//
+void LockProcess::setVRoot(Window win, Window vr)
+{
+ if (gVRoot)
+ removeVRoot(gVRoot);
+
+ QX11Info info;
+ unsigned long rw = RootWindowOfScreen(ScreenOfDisplay(QX11Info::display(), info.screen()));
+ unsigned long vroot_data[1] = { vr };
+
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+ Window top = win;
+ while (1) {
+ if (!XQueryTree(QX11Info::display(), top , &rootReturn, &parentReturn,
+ &children, &numChildren))
+ return;
+ if (children)
+ XFree((char *)children);
+ if (parentReturn == rw) {
+ break;
+ } else
+ top = parentReturn;
+ }
+
+ XChangeProperty(QX11Info::display(), top, gXA_VROOT, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)vroot_data, 1);
+}
+
+//---------------------------------------------------------------------------
+//
+// Remove the virtual root property
+//
+void LockProcess::removeVRoot(Window win)
+{
+ XDeleteProperty (QX11Info::display(), win, gXA_VROOT);
+}
+
+//---------------------------------------------------------------------------
+//
+// Grab the keyboard. Returns true on success
+//
+bool LockProcess::grabKeyboard()
+{
+ int rv = XGrabKeyboard( QX11Info::display(), QApplication::desktop()->winId(),
+ True, GrabModeAsync, GrabModeAsync, CurrentTime );
+
+ return (rv == GrabSuccess);
+}
+
+#define GRABEVENTS ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \
+ EnterWindowMask | LeaveWindowMask
+
+//---------------------------------------------------------------------------
+//
+// Grab the mouse. Returns true on success
+//
+bool LockProcess::grabMouse()
+{
+ int rv = XGrabPointer( QX11Info::display(), QApplication::desktop()->winId(),
+ True, GRABEVENTS, GrabModeAsync, GrabModeAsync, None,
+ QCursor(Qt::BlankCursor).handle(), CurrentTime );
+
+ return (rv == GrabSuccess);
+}
+
+//---------------------------------------------------------------------------
+//
+// Grab keyboard and mouse. Returns true on success.
+//
+bool LockProcess::grabInput()
+{
+ XSync(QX11Info::display(), False);
+
+ if (!grabKeyboard())
+ {
+ sleep(1);
+ if (!grabKeyboard())
+ {
+ return false;
+ }
+ }
+
+ if (!grabMouse())
+ {
+ sleep(1);
+ if (!grabMouse())
+ {
+ XUngrabKeyboard(QX11Info::display(), CurrentTime);
+ return false;
+ }
+ }
+
+ lockXF86();
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Release mouse an keyboard grab.
+//
+void LockProcess::ungrabInput()
+{
+ XUngrabKeyboard(QX11Info::display(), CurrentTime);
+ XUngrabPointer(QX11Info::display(), CurrentTime);
+ unlockXF86();
+}
+
+//---------------------------------------------------------------------------
+//
+// Start the screen saver.
+//
+bool LockProcess::startSaver()
+{
+ if (!child_saver && !grabInput())
+ {
+ kWarning(1204) << "LockProcess::startSaver() grabInput() failed!!!!" ;
+ return false;
+ }
+ mBusy = false;
+
+ saveVRoot();
+
+ if (mParent) {
+ QSocketNotifier *notifier = new QSocketNotifier(mParent, QSocketNotifier::Read, this);
+ connect(notifier, SIGNAL( activated (int)), SLOT( quitSaver()));
+ }
+ if (mAutoLogoutTimeout && !mSetupMode)
+ mAutoLogoutTimerId = startTimer(mAutoLogoutTimeout * 1000); // in milliseconds
+ createSaverWindow();
+ move(0, 0);
+ show();
+ setCursor( Qt::BlankCursor );
+
+ raise();
+ XSync(QX11Info::display(), False);
+
+ setVRoot( winId(), winId() );
+ startHack();
+ startPlasma();
+ KNotification::event( QLatin1String( "savingstarted" ) );
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Stop the screen saver.
+//
+void LockProcess::stopSaver()
+{
+ kDebug(1204) << "LockProcess: stopping saver";
+ resume( true );
+ stopPlasma();
+ stopHack();
+ hideSaverWindow();
+ mVisibility = false;
+ if (!child_saver) {
+ if (mLocked) {
+ KDisplayManager().setLock( false );
+ mLocked = false;
+ KNotification *u = new KNotification( QLatin1String( "unlocked" ) );
+ u->sendEvent();
+ }
+ ungrabInput();
+ const char *out = "GOAWAY!";
+ for (QList::ConstIterator it = child_sockets.constBegin(); it != child_sockets.constEnd(); ++it)
+ write(*it, out, sizeof(out));
+ }
+ KNotification *s = new KNotification( QLatin1String( "savingstopped" ) );
+ s->sendEvent();
+}
+
+// private static
+QVariant LockProcess::getConf(void *ctx, const char *key, const QVariant &dflt)
+{
+ LockProcess *that = (LockProcess *)ctx;
+ QString fkey = QLatin1String( key ) % QLatin1Char( '=' );
+ for (QStringList::ConstIterator it = that->mPluginOptions.constBegin();
+ it != that->mPluginOptions.constEnd(); ++it)
+ if ((*it).startsWith( fkey ))
+ return (*it).mid( fkey.length() );
+ return dflt;
+}
+
+void LockProcess::cantLock( const QString &txt)
+{
+ msgBox( 0, QMessageBox::Critical, i18n("Will not lock the session, as unlocking would be impossible:\n") + txt );
+}
+
+#if 0 // placeholders for later
+i18n("Cannot start kcheckpass.");
+i18n("kcheckpass is unable to operate. Possibly it is not setuid root.");
+#endif
+
+//---------------------------------------------------------------------------
+//
+// Make the screen saver password protected.
+//
+bool LockProcess::startLock()
+{
+ if (loadGreetPlugin()) {
+ mLocked = true;
+ KDisplayManager().setLock(true);
+ lockPlasma();
+ KNotification::event( QLatin1String( "locked" ) );
+ return true;
+ }
+ return false;
+}
+
+bool LockProcess::loadGreetPlugin()
+{
+ if (greetPlugin.library) {
+ //we were locked once before, so all the plugin loading's done already
+ //FIXME should I be unloading the plugin on unlock instead?
+ return true;
+ }
+ for (QStringList::ConstIterator it = mPlugins.constBegin(); it != mPlugins.constEnd(); ++it) {
+ GreeterPluginHandle plugin;
+ KLibrary *lib = new KLibrary( (*it)[0] == QLatin1Char( '/' ) ? *it : QLatin1String( "kgreet_" ) + *it );
+ if (lib->fileName().isEmpty()) {
+ kWarning(1204) << "GreeterPlugin " << *it << " does not exist" ;
+ delete lib;
+ continue;
+ }
+ if (!lib->load()) {
+ kWarning(1204) << "Cannot load GreeterPlugin " << *it << " (" << lib->fileName() << ")" ;
+ delete lib;
+ continue;
+ }
+ plugin.library = lib;
+ plugin.info = (KGreeterPluginInfo *)lib->resolveSymbol( "kgreeterplugin_info" );
+ if (!plugin.info ) {
+ kWarning(1204) << "GreeterPlugin " << *it << " (" << lib->fileName() << ") is no valid greet widget plugin" ;
+ lib->unload();
+ delete lib;
+ continue;
+ }
+ if (plugin.info->method && !mMethod.isEmpty() && mMethod != QLatin1String( plugin.info->method )) {
+ kDebug(1204) << "GreeterPlugin " << *it << " (" << lib->fileName() << ") serves " << plugin.info->method << ", not " << mMethod;
+ lib->unload();
+ delete lib;
+ continue;
+ }
+ if (!plugin.info->init( mMethod, getConf, this )) {
+ kDebug(1204) << "GreeterPlugin " << *it << " (" << lib->fileName() << ") refuses to serve " << mMethod;
+ lib->unload();
+ delete lib;
+ continue;
+ }
+ kDebug(1204) << "GreeterPlugin " << *it << " (" << plugin.info->method << ", " << plugin.info->name << ") loaded";
+ greetPlugin = plugin;
+ return true;
+ }
+ cantLock( i18n("No appropriate greeter plugin configured.") );
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+
+
+bool LockProcess::startHack()
+{
+ kDebug(1204) << "Starting hack:" << mSaverExec;
+
+ if (mSaverExec.isEmpty() || mForbidden)
+ {
+ hackExited();
+ return false;
+ }
+
+ QHash keyMap;
+ keyMap.insert(QLatin1Char( 'w' ), QString::number(winId()));
+ mHackProc << KShell::splitArgs(KMacroExpander::expandMacrosShellQuote(mSaverExec, keyMap));
+
+ mHackProc.start();
+ if (mHackProc.waitForStarted())
+ {
+#ifdef HAVE_SETPRIORITY
+ setpriority(PRIO_PROCESS, mHackProc.pid(), mPriority);
+#endif
+ return true;
+ }
+
+ hackExited();
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+void LockProcess::stopHack()
+{
+ if (mHackProc.state() != QProcess::NotRunning)
+ {
+ mHackProc.terminate();
+ if (!mHackProc.waitForFinished(10000))
+ {
+ mHackProc.kill();
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+void LockProcess::hackExited()
+{
+ // Hack exited while we're supposed to be saving the screen.
+ // Make sure the saver window is black.
+ XSetWindowBackground(QX11Info::display(), winId(), BlackPixel( QX11Info::display(), QX11Info::appScreen()));
+ XClearWindow(QX11Info::display(), winId());
+}
+
+bool LockProcess::startPlasma()
+{
+ if (!mPlasmaEnabled) {
+ return false;
+ }
+
+ if (mSetupMode) {
+ mSuppressUnlock.start(mSuppressUnlockTimeout);
+ XChangeActivePointerGrab(QX11Info::display(), GRABEVENTS,
+ QCursor(Qt::ArrowCursor).handle(), CurrentTime);
+ }
+
+ kDebug() << "looking for plasma-overlay";
+ if (!mPlasmaDBus) {
+ //try to get it, in case it's already running somehow
+ //mPlasmaDBus = new QDBusInterface(s_overlayServiceName, "/MainApplication", QString(),
+ mPlasmaDBus = new org::kde::plasmaoverlay::App(s_overlayServiceName, QLatin1String( "/App" ),
+ QDBusConnection::sessionBus(), this);
+ //FIXME this might-already-be-running stuff seems really really Wrong.
+ }
+
+ if (mPlasmaDBus->isValid()) {
+ kDebug() << "weird, plasma-overlay is already running";
+ mPlasmaDBus->call(QDBus::NoBlock, QLatin1String( "setup" ), mSetupMode);
+ return true;
+ }
+
+ kDebug () << "...not found" << "starting plasma-overlay";
+ delete mPlasmaDBus;
+ mPlasmaDBus = 0;
+
+ if (!mServiceWatcher) {
+ mServiceWatcher = new QDBusServiceWatcher(s_overlayServiceName, QDBusConnection::sessionBus(),
+ QDBusServiceWatcher::WatchForOwnerChange, this);
+ connect(mServiceWatcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
+ this, SLOT(newService(QString,QString,QString)));
+ }
+
+ KProcess *plasmaProc = new KProcess;
+ plasmaProc->setProgram(QLatin1String( "plasma-overlay" ));
+ if (mSetupMode) {
+ *plasmaProc << QLatin1String( "--setup" );
+ }
+
+ //make sure it goes away when it's done (and not before)
+ connect(plasmaProc, SIGNAL(finished(int,QProcess::ExitStatus)), plasmaProc, SLOT(deleteLater()));
+
+ plasmaProc->start();
+ kDebug() << "process begun";
+
+ //plasma gets 15 seconds to load, or we assume it failed
+ QTimer::singleShot(15 * 1000, this, SLOT(checkPlasma()));
+ return true;
+}
+
+void LockProcess::checkPlasma()
+{
+ if (!mPlasmaEnabled) {
+ kDebug() << "You're Doing It Wrong!";
+ return;
+ }
+ if (mPlasmaDBus && mPlasmaDBus->isValid()) {
+ //hooray, looks like it started ok
+ kDebug() << "success!";
+ //...but just in case, make sure we're not waiting on it
+ mSetupMode = false;
+ return;
+ }
+
+ kDebug() << "ohnoes. plasma = teh fail.";
+ disablePlasma();
+}
+
+bool LockProcess::isPlasmaValid()
+{
+ //FIXME I'm assuming that if it's valid, calls will succeed. so if that's not the case we'll
+ //need to change things so that plasma's disabled properly if it fails
+ //damn. isValid is not quite enough. a call may still fail, and then we need to bail.
+ if (!(mPlasmaEnabled && mPlasmaDBus)) {
+ return false; //no plasma, at least not yet
+ }
+ if (mPlasmaDBus->isValid()) {
+ return true;
+ }
+ //oh crap, it ran away on us.
+ disablePlasma();
+ return false;
+}
+
+void LockProcess::disablePlasma()
+{
+ kDebug();
+ mPlasmaEnabled = false;
+ mSetupMode = false;
+ mSuppressUnlock.stop(); //FIXME we might need to start the lock timer ala deactivatePlasma()
+ //actually we could be lazy and just call deactivatePlasma() TODO check that this'll really work
+ delete mPlasmaDBus;
+ mPlasmaDBus=0;
+}
+
+void LockProcess::stopPlasma()
+{
+ if (mPlasmaDBus && mPlasmaDBus->isValid()) {
+ mPlasmaDBus->call(QDBus::NoBlock, QLatin1String( "quit" ));
+ } else {
+ kDebug() << "cannot stop plasma-overlay";
+ }
+}
+
+void LockProcess::newService(QString name, QString oldOwner, QString newOwner)
+{
+ Q_UNUSED(name);
+ Q_UNUSED(oldOwner);
+
+ if (mPlasmaDBus) {
+ if (newOwner.isEmpty()) {
+ kDebug() << "plasma ran away?";
+ disablePlasma();
+ } else {
+ kDebug() << "I'm confused!!";
+ }
+ return;
+ }
+
+ kDebug() << "plasma! yaay!";
+ mPlasmaDBus = new org::kde::plasmaoverlay::App(s_overlayServiceName, QLatin1String( "/App" ), QDBusConnection::sessionBus(), this);
+
+ //XXX this isn't actually used any more iirc
+ connect(mPlasmaDBus, SIGNAL(hidden()), SLOT(unSuppressUnlock()));
+
+ if (!mDialogs.isEmpty()) {
+ //whoops, activation probably failed earlier
+ mPlasmaDBus->call(QDBus::NoBlock, QLatin1String( "setActive" ), true);
+ }
+}
+
+void LockProcess::deactivatePlasma()
+{
+ if (isPlasmaValid()) {
+ mPlasmaDBus->call(QDBus::NoBlock, QLatin1String( "setActive" ), false);
+ }
+ if (!mLocked && mLockGrace >=0) {
+ QTimer::singleShot(mLockGrace, this, SLOT(startLock())); //this is only ok because any activity will quit
+ }
+}
+
+void LockProcess::lockPlasma()
+{
+ if (isPlasmaValid()) {
+ mPlasmaDBus->call(QDBus::NoBlock, QLatin1String( "lock" ));
+ }
+}
+
+void LockProcess::unSuppressUnlock()
+{
+ //note: suppressing unlock also now means suppressing quit-on-activity
+ //maybe some var renaming is in order.
+ mSuppressUnlock.stop();
+}
+
+void LockProcess::quit()
+{
+ mSuppressUnlock.stop();
+ if (!mLocked || checkPass()) {
+ quitSaver();
+ }
+}
+
+void LockProcess::suspend()
+{
+ if( !mSuspended && mHackProc.state() == QProcess::Running )
+ {
+ ::kill(mHackProc.pid(), SIGSTOP);
+ // We actually want to wait for the stopped hack's X commands
+ // having been handled, but that would require a custom
+ // protocol which would cause the hack to call XSync() and
+ // freeze itself. So just go to sleep and hope that the X
+ // server will have enough time ...
+ usleep(100000);
+ mSavedScreen = QPixmap::grabWindow( winId());
+ mSnapshotTimer.setSingleShot(true);
+ mSnapshotTimer.start(1000);
+ }
+ mSuspended = true;
+}
+
+void LockProcess::resume( bool force )
+{
+ if( !force && (!mDialogs.isEmpty() || !mVisibility ))
+ return; // no resuming with dialog visible or when not visible
+ if( mSuspended && mHackProc.state() == QProcess::Running )
+ {
+ QPainter p( this );
+ if (!mSavedScreen.isNull())
+ p.drawPixmap( 0, 0, mSavedScreen );
+ else
+ p.fillRect( rect(), Qt::black );
+ p.end();
+ QApplication::syncX();
+ mSavedScreen = QPixmap();
+ ::kill(mHackProc.pid(), SIGCONT);
+ }
+ mSuspended = false;
+}
+
+//---------------------------------------------------------------------------
+//
+// Show the password dialog
+// This is called only in the master process
+//
+bool LockProcess::checkPass()
+{
+ if (isPlasmaValid()) {
+ mPlasmaDBus->call(QDBus::NoBlock, QLatin1String( "setActive" ), true);
+ }
+
+ PasswordDlg passDlg( this, &greetPlugin);
+ const int ret = execDialog( &passDlg );
+
+ if (isPlasmaValid()) {
+ if (ret == QDialog::Rejected) {
+ mSuppressUnlock.start(mSuppressUnlockTimeout);
+ } else if (ret == TIMEOUT_CODE) {
+ mPlasmaDBus->call(QDBus::NoBlock, QLatin1String( "setActive" ), false);
+ }
+ }
+
+ XWindowAttributes rootAttr;
+ XGetWindowAttributes(QX11Info::display(), QX11Info::appRootWindow(), &rootAttr);
+ if(( rootAttr.your_event_mask & SubstructureNotifyMask ) == 0 )
+ {
+ kWarning() << "ERROR: Something removed SubstructureNotifyMask from the root window!!!" ;
+ XSelectInput( QX11Info::display(), QX11Info::appRootWindow(),
+ SubstructureNotifyMask | rootAttr.your_event_mask );
+ }
+
+ return ret == QDialog::Accepted;
+}
+
+bool LockProcess::checkPass(const QString &reason)
+{
+ if (! mLocked) {
+ //we were never locked... how can we unlock?!
+ //if anyone finds a use case for checking the password while unlocked, they'll have to load
+ //the greetplugin n'stuff
+ return false;
+ }
+ PasswordDlg passDlg(this, &greetPlugin, reason);
+ const int ret = execDialog( &passDlg );
+// kDebug() << ret;
+
+ //FIXME do we need to copy&paste that SubstructureNotifyMask code above?
+ if (ret == QDialog::Accepted) {
+ //we don't quit on a custom checkpass, but we do unlock
+ //so that the user doesn't have to type their password twice
+ mLocked = false;
+ KDisplayManager().setLock(false);
+ KNotification::event( QLatin1String( "unlocked" ) );
+ //FIXME while suppressUnlock *should* always be running, if it isn't
+ //(say if someone's doing things they shouldn't with dbus) then it won't get started by this
+ //which means that a successful unlock will never re-lock
+ //in fact, the next bit of activity would lead to the screensaver quitting.
+ //possible solutions:
+ //-treat this function like activity: quit if already unlocked, ensure suppress is started
+ //if we're locked and the dialog's rejected
+ //-return true if already unlocked, without doing anything, same as above if locked
+ //-let it quit, and tell people not to do such silly things :P
+ return true;
+ }
+ return false;
+}
+
+static void fakeFocusIn( WId window )
+{
+ // We have keyboard grab, so this application will
+ // get keyboard events even without having focus.
+ // Fake FocusIn to make Qt realize it has the active
+ // window, so that it will correctly show cursor in the dialog.
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xfocus.display = QX11Info::display();
+ ev.xfocus.type = FocusIn;
+ ev.xfocus.window = window;
+ ev.xfocus.mode = NotifyNormal;
+ ev.xfocus.detail = NotifyAncestor;
+ XSendEvent( QX11Info::display(), window, False, NoEventMask, &ev );
+}
+
+bool LockProcess::eventFilter(QObject *o, QEvent *e)
+{
+ if (e->type() == QEvent::Resize) {
+ QWidget *w = static_cast(o);
+ mFrames.value(w)->resize(w->size());
+ }
+ return false;
+}
+
+int LockProcess::execDialog( QDialog *dlg )
+{
+
+ QFrame *winFrame = new QFrame( dlg );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ winFrame->lower();
+ mFrames.insert(dlg, winFrame);
+ dlg->installEventFilter(this);
+
+ dlg->adjustSize();
+
+ int screen = Kephal::ScreenUtils::primaryScreenId();
+ if (Kephal::ScreenUtils::numScreens() > 1) {
+ screen = Kephal::ScreenUtils::screenId(QCursor::pos());
+ }
+
+ const QRect screenRect = Kephal::ScreenUtils::screenGeometry(screen);
+ QRect rect = dlg->geometry();
+ rect.moveCenter(screenRect.center());
+ dlg->move(rect.topLeft());
+
+ if (mDialogs.isEmpty())
+ {
+ if (mAutoLogoutTimerId)
+ killTimer(mAutoLogoutTimerId);
+ suspend();
+ XChangeActivePointerGrab( QX11Info::display(), GRABEVENTS,
+ QCursor(Qt::ArrowCursor).handle(), CurrentTime);
+ }
+ mDialogs.prepend( dlg );
+ fakeFocusIn( dlg->winId());
+ const int rt = dlg->exec();
+ const int pos = mDialogs.indexOf( dlg );
+ if (pos != -1)
+ mDialogs.remove( pos );
+ if( mDialogs.isEmpty() ) {
+ resume( false );
+ if (mAutoLogoutTimerId)
+ mAutoLogoutTimerId = startTimer(mAutoLogoutTimeout * 1000);
+ }
+ updateFocus();
+
+ dlg->removeEventFilter(this);
+ mFrames.remove(dlg);
+
+ return rt;
+}
+
+void LockProcess::updateFocus()
+{
+ if (mDialogs.isEmpty()) {
+ if (mForeignInputWindows.isEmpty()) {
+ XChangeActivePointerGrab( QX11Info::display(), GRABEVENTS,
+ QCursor(Qt::BlankCursor).handle(), CurrentTime);
+ } else {
+ fakeFocusIn(mForeignInputWindows.first());
+ }
+ } else {
+ fakeFocusIn(mDialogs.first()->winId());
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// X11 Event.
+//
+bool LockProcess::x11Event(XEvent *event)
+{
+ if (mEventRecursed)
+ return false;
+
+ bool ret = false;
+ switch (event->type)
+ {
+ case ButtonPress:
+ if (!mDialogs.isEmpty() && event->xbutton.window == event->xbutton.root) {
+ //kDebug() << "close" << mDialogs.first()->effectiveWinId();
+ KDialog *dlg = qobject_cast(mDialogs.first());
+ if (dlg) {
+ //kDebug() << "casting success";
+ dlg->reject();
+ }
+ break;
+ }
+ case KeyPress:
+ case MotionNotify:
+ if (mBusy || !mDialogs.isEmpty()) {
+ //kDebug() << "busy";
+ //FIXME shouldn't we be resetting some timers?
+ break;
+ }
+ mBusy = true;
+ //something happened. do we quit, ask for a password or forward it to plasma?
+ //if we're supposed to be forwarding, we check that there's actually a plasma window up
+ //so that the user isn't trapped if plasma crashes or is slow to load.
+ //however, if plasma started in setup mode, we don't want to let anything happen until
+ //it has a chance to load.
+ //note: mSetupMode should end when we either get a winid or hit the checkPlasma timeout
+ if (mSuppressUnlock.isActive() && (mSetupMode || !mForeignInputWindows.isEmpty())) {
+ mSuppressUnlock.start(); //help, help, I'm being suppressed!
+ if (mAutoLogoutTimerId) {
+ killTimer(mAutoLogoutTimerId);
+ mAutoLogoutTimerId = startTimer(mAutoLogoutTimeout * 1000);
+ }
+ } else if (!mLocked) {
+ quitSaver();
+ mBusy = false;
+ return true; //it's better not to forward any input while quitting, right?
+ } else {
+ if (event->type == KeyPress) {
+ // Bounce the keypress to the dialog
+ QByteArray chars;
+ chars.resize(513);
+ KeySym keysym;
+ XLookupString(&event->xkey, chars.data(), chars.size(), &keysym, 0);
+ switch (keysym) {
+ // These would cause immediate failure
+ case XK_Escape:
+ case XK_Return:
+ case XK_KP_Enter:
+ // These just make no sense
+ case XK_Tab:
+ case XK_space:
+ break;
+ default:
+ mEventQueue.enqueue(*event);
+ }
+ }
+ if (checkPass()) {
+ quitSaver();
+ mBusy = false;
+ return true; //it's better not to forward any input while quitting, right?
+ }
+ }
+ mBusy = false;
+ ret = true;
+ break;
+
+ case VisibilityNotify:
+ if( event->xvisibility.window == winId())
+ { // mVisibility == false means the screensaver is not visible at all
+ // e.g. when switched to text console
+ // ...or when plasma's over it non-compositely?
+ // hey, this gives me free "suspend saver when plasma obscures it"
+ mVisibility = !(event->xvisibility.state == VisibilityFullyObscured);
+ if (!mVisibility) {
+ mSuspendTimer.start(2000);
+ kDebug(1204) << "fully obscured";
+ } else {
+ kDebug(1204) << "not fully obscured";
+ mSuspendTimer.stop();
+ resume( false );
+ }
+ if (mForeignWindows.isEmpty() && event->xvisibility.state != VisibilityUnobscured) {
+ kDebug(1204) << "no plasma; saver obscured";
+ stayOnTop();
+ }
+ } else if (!mForeignWindows.isEmpty() && event->xvisibility.window == mForeignWindows.last() &&
+ event->xvisibility.state != VisibilityUnobscured) {
+ //FIXME now that we have several plasma winids this doesn't feel valid
+ //but I don't know what to do about it!
+ kDebug(1204) << "plasma obscured!";
+ stayOnTop();
+ }
+ break;
+
+ case ConfigureNotify: // from SubstructureNotifyMask on the root window
+ if(event->xconfigure.event == QX11Info::appRootWindow()) {
+ int index = findWindowInfo( event->xconfigure.window );
+ if( index >= 0 ) {
+ int index2 = event->xconfigure.above ? findWindowInfo( event->xconfigure.above ) : 0;
+ if( index2 < 0 )
+ kDebug(1204) << "Unknown above for ConfigureNotify";
+ else { // move just above the other window
+ if( index2 < index )
+ ++index2;
+ windowInfo.move( index, index2 );
+ }
+ } else
+ kDebug(1204) << "Unknown toplevel for ConfigureNotify";
+ //kDebug() << "ConfigureNotify:";
+ //the stacking order changed, so let's change the stacking order again to what we want
+ stayOnTop();
+ }
+ break;
+ case MapNotify: // from SubstructureNotifyMask on the root window
+ if( event->xmap.event == QX11Info::appRootWindow()) {
+ kDebug(1204) << "MapNotify:" << event->xmap.window;
+ if (!mDialogs.isEmpty() && mDialogs.first()->winId() == event->xmap.window)
+ mVisibleDialogs.append(event->xmap.window);
+ int index = findWindowInfo( event->xmap.window );
+ if( index >= 0 )
+ windowInfo[ index ].viewable = true;
+ else
+ kDebug(1204) << "Unknown toplevel for MapNotify";
+ KXErrorHandler err; // ignore X errors here
+ WindowType type = windowType(event->xmap.window);
+ if (type != IgnoreWindow) {
+ if (mForeignWindows.contains(event->xmap.window)) {
+ kDebug(1204) << "uhoh! duplicate!";
+ } else {
+ //ordered youngest-on-top
+ mForeignWindows.prepend(event->xmap.window);
+ }
+ if (type & InputWindow) {
+ kDebug(1204) << "input window";
+ if (mForeignInputWindows.contains(event->xmap.window)) {
+ kDebug(1204) << "uhoh! duplicate again"; //never happens
+ } else {
+ //ordered youngest-on-top
+ mForeignInputWindows.prepend(event->xmap.window);
+ fakeFocusIn(event->xmap.window);
+ }
+ mSetupMode = false; //no more waiting for plasma
+ }
+ }
+ stayOnTop();
+ }
+ break;
+ case UnmapNotify:
+ if (event->xunmap.event == QX11Info::appRootWindow()) {
+ kDebug(1204) << "UnmapNotify:" << event->xunmap.window;
+ int index = findWindowInfo( event->xunmap.window );
+ if( index >= 0 )
+ windowInfo[ index ].viewable = false;
+ else
+ kDebug(1204) << "Unknown toplevel for MapNotify";
+ mVisibleDialogs.removeAll(event->xunmap.window);
+ mForeignWindows.removeAll(event->xunmap.window);
+ if (mForeignInputWindows.removeAll(event->xunmap.window)) {
+ updateFocus();
+ }
+ }
+ break;
+ case CreateNotify:
+ if (event->xcreatewindow.parent == QX11Info::appRootWindow()) {
+ kDebug(1204) << "CreateNotify:" << event->xcreatewindow.window;
+ int index = findWindowInfo( event->xcreatewindow.window );
+ if( index >= 0 )
+ kDebug(1204) << "Already existing toplevel for CreateNotify";
+ else {
+ WindowInfo info;
+ info.window = event->xcreatewindow.window;
+ info.viewable = false;
+ windowInfo.append( info );
+ }
+ }
+ break;
+ case DestroyNotify:
+ if (event->xdestroywindow.event == QX11Info::appRootWindow()) {
+ int index = findWindowInfo( event->xdestroywindow.window );
+ if( index >= 0 )
+ windowInfo.removeAt( index );
+ else
+ kDebug(1204) << "Unknown toplevel for DestroyNotify";
+ }
+ break;
+ case ReparentNotify:
+ if (event->xreparent.event == QX11Info::appRootWindow() && event->xreparent.parent != QX11Info::appRootWindow()) {
+ int index = findWindowInfo( event->xreparent.window );
+ if( index >= 0 )
+ windowInfo.removeAt( index );
+ else
+ kDebug(1204) << "Unknown toplevel for ReparentNotify away";
+ } else if (event->xreparent.parent == QX11Info::appRootWindow()) {
+ int index = findWindowInfo( event->xreparent.window );
+ if( index >= 0 )
+ kDebug(1204) << "Already existing toplevel for ReparentNotify";
+ else {
+ WindowInfo info;
+ info.window = event->xreparent.window;
+ info.viewable = false;
+ windowInfo.append( info );
+ }
+ }
+ break;
+ case CirculateNotify:
+ if (event->xcirculate.event == QX11Info::appRootWindow()) {
+ int index = findWindowInfo( event->xcirculate.window );
+ if( index >= 0 ) {
+ windowInfo.move( index, event->xcirculate.place == PlaceOnTop ? windowInfo.size() - 1 : 0 );
+ } else
+ kDebug(1204) << "Unknown toplevel for CirculateNotify";
+ }
+ break;
+ }
+
+ // We have grab with the grab window being the root window.
+ // This results in key events being sent to the root window,
+ // but they should be sent to the dialog if it's visible.
+ // It could be solved by setFocus() call, but that would mess
+ // the focus after this process exits.
+ // Qt seems to be quite hard to persuade to redirect the event,
+ // so let's simply dupe it with correct destination window,
+ // and ignore the original one.
+ if (!mDialogs.isEmpty()) {
+ if (event->type == KeyPress || event->type == KeyRelease) {
+ mEventQueue.enqueue(*event);
+ ret = true;
+ }
+ if (!mVisibleDialogs.isEmpty())
+ while (!mEventQueue.isEmpty()) {
+ //kDebug() << "forward to dialog";
+ XEvent ev2 = mEventQueue.dequeue();
+ ev2.xkey.window = ev2.xkey.subwindow = mVisibleDialogs.last();
+ mEventRecursed = true;
+ qApp->x11ProcessEvent( &ev2 );
+ mEventRecursed = false;
+ }
+ } else {
+ mEventQueue.clear();
+ if (!mForeignInputWindows.isEmpty()) {
+ //when there are no dialogs, forward some events to plasma
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify: {
+ //kDebug() << "forward to plasma";
+ XEvent ev2 = *event;
+ Window root_return;
+ int x_return, y_return;
+ unsigned int width_return, height_return, border_width_return, depth_return;
+ WId targetWindow = 0;
+ //kDebug() << "root is" << winId();
+ //kDebug() << "search window under pointer with" << mForeignInputWindows.size() << "windows";
+ KXErrorHandler err; // ignore X errors
+ foreach(WId window, mForeignInputWindows)
+ {
+ if( XGetGeometry(QX11Info::display(), window, &root_return,
+ &x_return, &y_return,
+ &width_return, &height_return,
+ &border_width_return, &depth_return)
+ &&
+ (event->xkey.x>=x_return && event->xkey.x<=x_return+(int)width_return)
+ &&
+ (event->xkey.y>=y_return && event->xkey.y<=y_return+(int)height_return) )
+ {
+ //kDebug() << "found window" << window;
+ targetWindow = window;
+ ev2.xkey.window = ev2.xkey.subwindow = targetWindow;
+ ev2.xkey.x = event->xkey.x - x_return;
+ ev2.xkey.y = event->xkey.y - y_return;
+ break;
+ }
+ }
+ XSendEvent(QX11Info::display(), targetWindow, False, NoEventMask, &ev2);
+ ret = true;
+ break; }
+ default:
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+LockProcess::WindowType LockProcess::windowType(WId id)
+{
+ Atom tag = XInternAtom(QX11Info::display(), "_KDE_SCREENSAVER_OVERRIDE", False);
+ Atom actualType;
+ int actualFormat;
+ unsigned long nitems, remaining;
+ unsigned char *data = 0;
+ Display *display = QX11Info::display();
+
+ int result = XGetWindowProperty(display, id, tag, 0, 1, False, tag, &actualType,
+ &actualFormat, &nitems, &remaining, &data);
+
+ //kDebug() << (result == Success) << (actualType == tag);
+ WindowType type = IgnoreWindow;
+ if (result == Success && actualType == tag) {
+ if (nitems != 1 || actualFormat != 8) {
+ kDebug(1204) << "malformed property";
+ } else {
+ kDebug(1204) << "i can haz plasma window?" << data[0];
+ switch (data[0]) {
+ case 0: //FIXME magic numbers
+ type = SimpleWindow;
+ break;
+ case 1:
+ type = InputWindow;
+ break;
+ case 2:
+ type = DefaultWindow;
+ break;
+ }
+ }
+ }
+ if (data) {
+ XFree(data);
+ }
+ return type;
+}
+
+void LockProcess::stayOnTop()
+{
+ // this restacking is written in a way so that
+ // if the stacking positions actually don't change,
+ // all restacking operations will be no-op,
+ // and no ConfigureNotify will be generated,
+ // thus avoiding possible infinite loops
+ QVector< Window > stack( mDialogs.count() + mForeignWindows.count() + 1 );
+ int count = 0;
+ // dialogs first
+ foreach( QWidget* w, mDialogs )
+ stack[ count++ ] = w->winId();
+ // now the plasma stuff below the dialogs
+ foreach( WId w, mForeignWindows )
+ stack[ count++ ] = w;
+ // finally, the saver window
+ stack[ count++ ] = winId();
+ // We actually have to check the current stacking order. When an override-redirect
+ // window is shown or raised, it can get above the screensaver window and there's not
+ // much to do to prevent it (only the compositing manager can prevent that). This
+ // is detected by the screenlocker and handled here, but the contents of the window
+ // may remain visible, since some screensavers don't react to Expose events and
+ // don't repaint as necessary. Therefore, if a window is detected above any of the windows
+ // related to screenlocking, I don't see any better possibility than to completely
+ // erase the screenlocker window.
+ // It is important to first detect, then restack and then erase.
+ // Another catch here is that only viewable windows matter, but checking here whether
+ // a window is viewable is a race condition, since a window may map, paint and unmap
+ // before we reach this point, thus making this code fail to detect the need to do
+ // a repaint. Therefore we track all relevant X events about mapping state of toplevel
+ // windows (which ensures proper ordering) and here just consult the information.
+ bool needs_erase = false;
+ bool found_ours = false;
+ foreach( const WindowInfo& info, windowInfo ) {
+ if( stack.contains( info.window )) {
+ found_ours = true;
+ } else if( found_ours && info.viewable ) {
+ kDebug(1204) << "found foreign window above screensaver";
+ needs_erase = true;
+ break;
+ }
+ }
+ // do the actual restacking if needed
+ XRaiseWindow( x11Info().display(), stack[ 0 ] );
+ if( count > 1 )
+ XRestackWindows( x11Info().display(), stack.data(), count );
+ if( needs_erase ) {
+ // if the snapshot was taken recently it is possible that the rogue
+ // window was snapshotted at well.
+ if (mSnapshotTimer.isActive())
+ mSavedScreen = QPixmap();
+ QPainter p( this );
+ if (!mSavedScreen.isNull())
+ p.drawPixmap( 0, 0, mSavedScreen );
+ else
+ p.fillRect( rect(), Qt::black );
+ p.end();
+ QApplication::syncX();
+ }
+}
+
+void LockProcess::checkDPMSActive()
+{
+#ifdef HAVE_DPMS
+ BOOL on;
+ CARD16 state;
+ DPMSInfo(QX11Info::display(), &state, &on);
+ //kDebug() << "checkDPMSActive " << on << " " << state;
+ if (state == DPMSModeStandby || state == DPMSModeSuspend || state == DPMSModeOff)
+ suspend();
+ else
+ resume( false );
+#endif
+}
+
+#if defined(HAVE_XF86MISC) && defined(HAVE_XF86MISCSETGRABKEYSSTATE)
+// see http://cvsweb.xfree86.org/cvsweb/xc/programs/Xserver/hw/xfree86/common/xf86Events.c#rev3.113
+// This allows enabling the "Allow{Deactivate/Closedown}Grabs" options in XF86Config,
+// and kscreenlocker will still lock the session.
+static enum { Unknown, Yes, No } can_do_xf86_lock = Unknown;
+void LockProcess::lockXF86()
+{
+ if( can_do_xf86_lock == Unknown )
+ {
+ int major, minor, dummy;
+ if( XF86MiscQueryExtension( QX11Info::display(), &dummy, &dummy )
+ && XF86MiscQueryVersion( QX11Info::display(), &major, &minor )
+ && (major > 0 || minor >= 5) )
+ can_do_xf86_lock = Yes;
+ else
+ can_do_xf86_lock = No;
+ }
+ if( can_do_xf86_lock != Yes )
+ return;
+ if( mRestoreXF86Lock )
+ return;
+ if( XF86MiscSetGrabKeysState( QX11Info::display(), False ) != MiscExtGrabStateSuccess )
+ return;
+ // success
+ mRestoreXF86Lock = true;
+}
+
+void LockProcess::unlockXF86()
+{
+ if( can_do_xf86_lock != Yes )
+ return;
+ if( !mRestoreXF86Lock )
+ return;
+ XF86MiscSetGrabKeysState( QX11Info::display(), True );
+ mRestoreXF86Lock = false;
+}
+#else
+void LockProcess::lockXF86()
+{
+}
+
+void LockProcess::unlockXF86()
+{
+}
+#endif
+
+void LockProcess::msgBox( QWidget *parent, QMessageBox::Icon type, const QString &txt )
+{
+ QDialog box( parent, Qt::X11BypassWindowManagerHint );
+
+ QLabel *label1 = new QLabel( &box );
+ label1->setPixmap( QMessageBox::standardIcon( type ) );
+ QLabel *label2 = new QLabel( txt, &box );
+ KPushButton *button = new KPushButton( KStandardGuiItem::ok(), &box );
+ button->setDefault( true );
+ button->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+ connect( button, SIGNAL( clicked() ), &box, SLOT( accept() ) );
+
+ QGridLayout *grid = new QGridLayout( &box );
+ grid->setSpacing( 10 );
+ grid->addWidget( label1, 0, 0, Qt::AlignCenter );
+ grid->addWidget( label2, 0, 1, Qt::AlignCenter );
+ grid->addWidget( button, 1, 0, 1, 2, Qt::AlignCenter );
+
+ execDialog( &box );
+}
+
+int LockProcess::findWindowInfo( Window w )
+{
+ for( int i = 0;
+ i < windowInfo.size();
+ ++i )
+ if( windowInfo[ i ].window == w )
+ return i;
+ return -1;
+}
+
+#include "lockprocess.moc"
diff --git a/kwin/screenlocker/lock/lockprocess.h b/kwin/screenlocker/lock/lockprocess.h
new file mode 100644
index 0000000..8b6d9a8
--- /dev/null
+++ b/kwin/screenlocker/lock/lockprocess.h
@@ -0,0 +1,238 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 1999 Martin R. Jones
+// Copyright 2003 Oswald Buddenhagen
+// Copyright 2008 Chani Armitage
+//
+
+#ifndef LOCKPROCESS_H
+#define LOCKPROCESS_H
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "plasmaapp_interface.h"
+
+class KLibrary;
+
+struct KGreeterPluginInfo;
+
+struct GreeterPluginHandle {
+ KLibrary *library;
+ KGreeterPluginInfo *info;
+};
+
+const int TIMEOUT_CODE = 2; //from PasswordDlg
+
+class QDBusServiceWatcher;
+
+//===========================================================================
+//
+// Screen saver handling process. Handles screensaver window,
+// starting screensaver hacks, and password entry.
+//
+class LockProcess
+ : public QWidget
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.kde.screenlocker.LockProcess")
+public:
+ explicit LockProcess(bool child_saver = false, bool useBlankOnly = false);
+ ~LockProcess();
+
+ /**
+ * start the screensaver locked
+ */
+ bool lock(bool initial = false);
+
+ /**
+ * start the screensaver unlocked
+ */
+ bool defaultSave();
+
+ /**
+ * start the screensaver in plasma setup mode
+ * if plasma is disabled this just acts like defaultSave
+ */
+ bool startSetup();
+
+ /**
+ * start the screensaver unlocked, and *never* automatically lock it
+ */
+ bool dontLock();
+
+ void setChildren(QList children) { child_sockets = children; }
+ void setParent(int fd) { mParent = fd; }
+
+ void msgBox( QWidget *parent, QMessageBox::Icon type, const QString &txt );
+ int execDialog( QDialog* dlg );
+
+public Q_SLOTS:
+ void quitSaver();
+ //dbus methods
+ /**
+ * bring up the password dialog with @param reason displayed instead of the usual "this session
+ * is locked" message.
+ * @return true if the password was entered correctly
+ * if this returns true, it will also unlock the screensaver without quitting.
+ * it will re-lock after the lock timeout in the settings
+ */
+ Q_SCRIPTABLE bool checkPass(const QString &reason);
+ /**
+ * this will unlock and quit the screensaver, asking for a password first if necessary
+ */
+ Q_SCRIPTABLE void quit();
+ /**
+ * immediately lock the screen; it will now require a password to unlock.
+ */
+ Q_SCRIPTABLE bool startLock();
+
+protected:
+ virtual bool x11Event(XEvent *);
+ virtual void timerEvent(QTimerEvent *);
+ virtual bool eventFilter(QObject *o, QEvent *e);
+
+private Q_SLOTS:
+ void hackExited();
+ void signalPipeSignal();
+ void suspend();
+ void checkDPMSActive();
+ void slotDeadTimePassed();
+ /**
+ * check that plasma started properly (used for timeout)
+ * and disable it if it failed
+ */
+ void checkPlasma();
+ /**
+ * a new dbus service has come in
+ */
+ void newService(QString name, QString oldOwner, QString newOwner);
+ /**
+ * tell plasma we're in idle mode
+ */
+ void deactivatePlasma();
+ void lockPlasma();
+ /**
+ * immediately un-suppress the password dialog
+ * FIXME need a better name
+ */
+ void unSuppressUnlock();
+
+private:
+ void configure();
+ void readSaver();
+ void createSaverWindow();
+ void hideSaverWindow();
+ void saveVRoot();
+ void setVRoot(Window win, Window rw);
+ void removeVRoot(Window win);
+ bool grabKeyboard();
+ bool grabMouse();
+ bool grabInput();
+ void ungrabInput();
+ void cantLock(const QString &reason);
+ bool startSaver();
+ void stopSaver();
+ bool startHack();
+ void stopHack();
+ bool startPlasma();
+ void stopPlasma();
+ void setupSignals();
+ /**
+ * exec the password dialog
+ * @return true iff the password was checked and is valid
+ */
+ bool checkPass();
+ /**
+ * returns true if plasma is up and the dbus interface is valid
+ */
+ bool isPlasmaValid();
+ /**
+ * give up on plasma, probably because it crashed.
+ * this does *not* tell plasma to quit. it just stops using it.
+ */
+ void disablePlasma();
+ /**
+ * give a fakefocusin to the right window
+ */
+ void updateFocus();
+ void stayOnTop();
+ int findWindowInfo( Window window ); // returns index in windowInfo or -1
+ void lockXF86();
+ void unlockXF86();
+ void resume( bool force );
+ enum WindowType { IgnoreWindow = 0 /** regular window to be left below the saver */,
+ SimpleWindow = 1 /** simple popup that can't handle direct input */,
+ InputWindow = 2 /** annoying dialog that needs direct input */,
+ DefaultWindow = 6/** input window that's also the plasma view */
+ };
+ /**
+ * @return the type of window, based on its X property
+ */
+ WindowType windowType(WId id);
+
+ static QVariant getConf(void *ctx, const char *key, const QVariant &dflt);
+ bool loadGreetPlugin();
+
+ bool mInitialLock;
+ bool mLocked;
+ int mLockGrace;
+ int mPriority;
+ bool mBusy;
+ KProcess mHackProc;
+ org::kde::plasmaoverlay::App *mPlasmaDBus;
+ QDBusServiceWatcher *mServiceWatcher;
+ bool mPlasmaEnabled;
+ bool mSetupMode;
+ QString mSaverExec;
+ QString mSaver;
+ bool mOpenGLVisual;
+ bool child_saver;
+ QList child_sockets;
+ int mParent;
+ bool mUseBlankOnly;
+ bool mSuspended;
+ QTimer mSuspendTimer;
+ bool mVisibility;
+ bool mDPMSDepend;
+ QTimer mCheckDPMS;
+ QStack< QWidget* > mDialogs;
+ QHash< QWidget*, QWidget* > mFrames;
+ QList mVisibleDialogs;
+ QQueue mEventQueue;
+ bool mEventRecursed;
+ bool mRestoreXF86Lock;
+ bool mForbidden;
+ QStringList mPlugins, mPluginOptions;
+ QString mMethod;
+ GreeterPluginHandle greetPlugin;
+ QPixmap mSavedScreen;
+ QTimer mSnapshotTimer;
+ int mAutoLogoutTimerId;
+ int mAutoLogoutTimeout;
+ QTimer mSuppressUnlock;
+ int mSuppressUnlockTimeout;
+ QList mForeignWindows;
+ QList mForeignInputWindows;
+ struct WindowInfo
+ {
+ Window window;
+ bool viewable;
+ };
+ QList windowInfo;
+};
+
+#endif
+
diff --git a/kwin/screenlocker/lock/main.cc b/kwin/screenlocker/lock/main.cc
new file mode 100644
index 0000000..7b41024
--- /dev/null
+++ b/kwin/screenlocker/lock/main.cc
@@ -0,0 +1,204 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure
+ Copyright 2003 Oswald Buddenhagen
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "lockprocess.h"
+#include "main.h"
+#include "kscreensaversettings.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "kscreensaver_interface.h"
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+bool MyApp::x11EventFilter( XEvent *ev )
+{
+ if (ev->type == XKeyPress || ev->type == ButtonPress)
+ emit activity();
+ else if (ev->type == MotionNotify) {
+ time_t tick = time( 0 );
+ if (tick != lastTick) {
+ lastTick = tick;
+ emit activity();
+ }
+ }
+ return KApplication::x11EventFilter( ev );
+}
+
+
+// -----------------------------------------------------------------------------
+
+int main( int argc, char **argv )
+{
+ KCmdLineArgs::init(argc, argv, "kscreenlocker", "krunner", ki18n("KDE Screen Locker"),
+ "2.0" , ki18n("Session Locker for KDE Workspace"));
+
+ KCmdLineOptions options;
+ options.add("forcelock", ki18n("Force session locking"));
+ options.add("dontlock", ki18n("Only start screen saver"));
+ options.add("showunlock", ki18n("Immediately show the unlock dialog"));
+ options.add("blank", ki18n("Only use the blank screen saver"));
+ options.add("plasmasetup", ki18n("start with plasma unlocked for configuring"));
+ options.add("daemon", ki18n("Fork into the background after starting up"));
+ KCmdLineArgs::addCmdLineOptions( options );
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ bool daemonize = false;
+ int daemonPipe[2];
+ char daemonBuf;
+ if (args->isSet("daemon")) {
+ daemonize = true;
+ if (pipe(daemonPipe))
+ kFatal() << "pipe() failed";
+ switch (fork()) {
+ case -1:
+ kFatal() << "fork() failed";
+ case 0:
+ break;
+ default:
+ if (read(daemonPipe[0], &daemonBuf, 1) != 1)
+ _exit(1);
+ _exit(0);
+ }
+ }
+
+ putenv(strdup("SESSION_MANAGER="));
+
+ //KApplication::disableAutoDcopRegistration();
+
+ int kdesktop_screen_number = 0;
+ int starting_screen = 0;
+
+ bool child = false;
+ int parent_connection = 0; // socket to the parent saver
+ QList child_sockets;
+
+ if (KGlobalSettings::isMultiHead())
+ {
+ Display *dpy = XOpenDisplay(NULL);
+ if (! dpy) {
+ fprintf(stderr,
+ "%s: FATAL ERROR: could not open display '%s'\n",
+ argv[0], XDisplayName(NULL));
+ exit(1);
+ }
+
+ int number_of_screens = ScreenCount(dpy);
+ starting_screen = kdesktop_screen_number = DefaultScreen(dpy);
+ int pos;
+ QByteArray display_name = XDisplayString(dpy);
+ XCloseDisplay(dpy);
+ kDebug() << "screen " << number_of_screens << " " << kdesktop_screen_number << " " << display_name << " " << starting_screen;
+ dpy = 0;
+
+ if ((pos = display_name.lastIndexOf('.')) != -1)
+ display_name.remove(pos, 10);
+
+ QString env;
+ if (number_of_screens != 1) {
+ for (int i = 0; i < number_of_screens; i++) {
+ if (i != starting_screen) {
+ int fd[2];
+ if (pipe(fd)) {
+ perror("pipe");
+ break;
+ }
+ if (fork() == 0) {
+ child = true;
+ kdesktop_screen_number = i;
+ parent_connection = fd[0];
+ // break here because we are the child process, we don't
+ // want to fork() anymore
+ break;
+ } else {
+ child_sockets.append(fd[1]);
+ }
+ }
+ }
+
+ env.sprintf("DISPLAY=%s.%d", display_name.data(),
+ kdesktop_screen_number);
+ kDebug() << "env " << env;
+
+ if (putenv(strdup(env.toLatin1().data()))) {
+ fprintf(stderr,
+ "%s: WARNING: unable to set DISPLAY environment variable\n",
+ argv[0]);
+ perror("putenv()");
+ }
+ }
+ }
+
+ MyApp app;
+ kDebug() << "app " << kdesktop_screen_number << " " << starting_screen << " " << child << " " << child_sockets.count() << " " << parent_connection;
+ app.disableSessionManagement();
+ app.setQuitOnLastWindowClosed( false );
+ KGlobal::locale()->insertCatalog(QLatin1String( "libkworkspace" ));
+
+ LockProcess process(child, args->isSet("blank"));
+ if (!child)
+ process.setChildren(child_sockets);
+ else
+ process.setParent(parent_connection);
+
+ bool rt;
+ bool sig = false;
+ if (!child && (args->isSet("forcelock"))) {
+ rt = process.lock(args->isSet("showunlock"));
+ sig = true;
+ }
+ else if( child || args->isSet( "dontlock" ))
+ rt = process.dontLock();
+ else if (args->isSet("plasmasetup")) {
+ rt = process.startSetup();
+ }
+ else
+ rt = process.defaultSave();
+ if (!rt)
+ return 1;
+
+ if( sig )
+ {
+ org::kde::screensaver kscreensaver(QLatin1String( "org.kde.screensaver" ), QLatin1String( "/ScreenSaver" ), QDBusConnection::sessionBus());
+ kscreensaver.saverLockReady();
+ }
+ args->clear();
+ if (daemonize) {
+ daemonBuf = 0;
+ write(daemonPipe[1], &daemonBuf, 1);
+ }
+ return app.exec();
+}
+
+#include "main.moc"
+
+#define KDM_NO_SHUTDOWN
+#include
diff --git a/kwin/screenlocker/lock/main.h b/kwin/screenlocker/lock/main.h
new file mode 100644
index 0000000..8a60353
--- /dev/null
+++ b/kwin/screenlocker/lock/main.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ Copyright 2003 Oswald Buddenhagen
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _MAIN_H
+#define _MAIN_H
+
+#include
+
+#include
+
+class MyApp : public KApplication {
+ Q_OBJECT
+public:
+ MyApp() : KApplication(), lastTick( 0 ) {}
+protected:
+ bool x11EventFilter( XEvent * );
+Q_SIGNALS:
+ void activity();
+private:
+ time_t lastTick;
+};
+
+#endif
diff --git a/kwin/screenlocker/screenlocker.cpp b/kwin/screenlocker/screenlocker.cpp
new file mode 100644
index 0000000..7994b83
--- /dev/null
+++ b/kwin/screenlocker/screenlocker.cpp
@@ -0,0 +1,119 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2011 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#include "screenlocker.h"
+#include "saverengine.h"
+#include "workspace.h"
+#include
+#include "effects.h"
+// Qt
+#include
+#include
+// KDE
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace KWin
+{
+namespace ScreenLocker
+{
+
+ScreenLocker::ScreenLocker::ScreenLocker(QObject *parent)
+ : QObject(parent)
+ , m_saverEngine(new SaverEngine(this))
+ , m_locked(false)
+{
+ // TODO: test whether lock file exists
+}
+
+ScreenLocker::~ScreenLocker()
+{
+}
+
+void ScreenLocker::initShortcuts(KActionCollection *keys)
+{
+ if (KAuthorized::authorize(QLatin1String("lock_screen"))) {
+ // first make krunner forget its old shortcut
+ // we do this directly using the D-Bus interface, as KGlobalAccel/KAction has
+ // no nice way of doing this (other than registering and deregistering the
+ // krunner shortcut every time)
+ QDBusInterface accelIface("org.kde.kglobalaccel", "/kglobalaccel", "org.kde.KGlobalAccel");
+ QStringList krunnerShortcutId;
+ krunnerShortcutId << QLatin1String("krunner") << QLatin1String("Lock Session") << "" << "";
+ QDBusReply > reply = accelIface.call("shortcut", krunnerShortcutId);
+ int shortcut = -1;
+ if (reply.isValid() && reply.value().size() == 1) {
+ shortcut = reply.value().at(0);
+ kDebug(1212) << "Existing krunner shortcut for Lock Session found:" << KShortcut(shortcut).toString();
+ }
+ accelIface.call(QDBus::NoBlock, "unRegister", krunnerShortcutId);
+
+ KAction *a = keys->addAction(QLatin1String("Lock Session"));
+ a->setText(i18n("Lock Session"));
+ a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_L));
+ if (shortcut >= 0) {
+ // if there was a krunner shortcut, use that
+ a->setGlobalShortcut(KShortcut(shortcut), KAction::ActiveShortcut, KAction::NoAutoloading);
+ }
+ connect(a, SIGNAL(triggered(bool)), this, SLOT(lock()));
+ }
+}
+
+void ScreenLocker::lock()
+{
+ if (m_locked) {
+ return;
+ }
+ // TODO: create lock file
+ bool hasLock = false;
+ if (Workspace::self()->compositingActive() && static_cast(effects)->provides(Effect::ScreenLocking)) {
+ // try locking through an Effect
+ hasLock = static_cast(effects)->lockScreen();
+ }
+ if (!hasLock) {
+ // no Effect to lock the screen, try legacy X Screen Saver for locking
+ hasLock = !m_saverEngine->doLock();
+ }
+ if (!hasLock) {
+ // no working lock implementation
+ // TODO: remove lock file
+ return;
+ }
+ m_locked = true;
+ emit locked();
+}
+
+void ScreenLocker::unlock()
+{
+ if (!m_locked) {
+ return;
+ }
+ // TODO: remove lock file
+ // TODO: if compositing was enforced, remove the blocking
+ m_locked = false;
+ emit unlocked();
+}
+
+
+} // namespace ScreenLocker
+} // namespace KWin
diff --git a/kwin/screenlocker/screenlocker.h b/kwin/screenlocker/screenlocker.h
new file mode 100644
index 0000000..c156e39
--- /dev/null
+++ b/kwin/screenlocker/screenlocker.h
@@ -0,0 +1,92 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2011 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#ifndef KWIN_SCREENLOCKER_SCREENLOCKER_H
+#define KWIN_SCREENLOCKER_SCREENLOCKER_H
+
+#include
+
+// forward declarations
+class KActionCollection;
+class SaverEngine;
+
+namespace KWin
+{
+namespace ScreenLocker
+{
+
+/**
+ * @short Class handling screen locking.
+ *
+ * The classic Screen Saving is handled by the @link SaverEngine.
+ * This class only takes care of locking the screen. That is ensure that
+ * nothing is displayed on the screen.
+ *
+ * The D-Bus interface to screen locking is provided by the @link SaverEngine
+ * for backwards-compatibility. This class cannot implement the org.freedesktop.ScreenSaver
+ * interface as it does not provide the screen saving capabilities.
+ **/
+class ScreenLocker : public QObject
+{
+ Q_OBJECT
+public:
+ ScreenLocker(QObject *parent = NULL);
+ virtual ~ScreenLocker();
+
+ void initShortcuts(KActionCollection *keys);
+
+ /**
+ * Unlocks the screen. Inside KWin we trust each other and assume
+ * that the method will only be called when the screen got unlocked
+ * by a trusted authority. E.g. a KWin Effect or the SaverEngine.
+ **/
+ void unlock();
+ /**
+ * @returns Whether the screen is locked.
+ **/
+ bool isLocked() const {
+ return m_locked;
+ }
+
+Q_SIGNALS:
+ /**
+ * Emitted when the screen gets locked.
+ **/
+ void locked();
+ /**
+ * Emitted when the screen gets unlocked.
+ **/
+ void unlocked();
+
+public Q_SLOTS:
+ /**
+ * Locks the screen, either through a KWin effect (modern) or ScreenSaver Engine (legacy).
+ **/
+ void lock();
+
+private:
+ // legacy screen saver engine.
+ SaverEngine *m_saverEngine;
+ // indicates whether the screen is locked
+ bool m_locked;
+};
+} // namespace ScreenLocker
+} // namespace KWin
+
+#endif
diff --git a/kwin/screenlocker/screensaver/saverengine.cpp b/kwin/screenlocker/screensaver/saverengine.cpp
new file mode 100644
index 0000000..e6ad800
--- /dev/null
+++ b/kwin/screenlocker/screensaver/saverengine.cpp
@@ -0,0 +1,513 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 1999 Martin R. Jones
+//
+
+
+#include "saverengine.h"
+#include "kscreensaversettings.h"
+#include "screensaveradaptor.h"
+#include "kscreensaveradaptor.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "xautolock_c.h"
+#include "screenlocker.h"
+#include
+extern xautolock_corner_t xautolock_corners[ 4 ];
+
+//===========================================================================
+//
+// Screen saver engine. Doesn't handle the actual screensaver window,
+// starting screensaver hacks, or password entry. That's done by
+// a newly started process.
+//
+SaverEngine::SaverEngine(KWin::ScreenLocker::ScreenLocker *locker)
+ : QWidget()
+ , m_screenLocker(locker)
+{
+ (void) new ScreenSaverAdaptor( this );
+ QDBusConnection::sessionBus().registerService( QLatin1String( "org.freedesktop.ScreenSaver" ) ) ;
+ (void) new KScreenSaverAdaptor( this );
+ QDBusConnection::sessionBus().registerService( QLatin1String( "org.kde.screensaver" ) ) ;
+ QDBusConnection::sessionBus().registerObject( QLatin1String( "/ScreenSaver" ), this );
+
+ // Save X screensaver parameters
+ XGetScreenSaver(QX11Info::display(), &mXTimeout, &mXInterval,
+ &mXBlanking, &mXExposures);
+ // And disable it. The internal X screensaver is not used at all, but we use its
+ // internal idle timer (and it is also used by DPMS support in X). This timer must not
+ // be altered by this code, since e.g. resetting the counter after activating our
+ // screensaver would prevent DPMS from activating. We use the timer merely to detect
+ // user activity.
+ XSetScreenSaver(QX11Info::display(), 0, mXInterval, mXBlanking, mXExposures);
+
+ mState = Waiting;
+ mXAutoLock = 0;
+ mLockProcess = 0;
+
+ m_nr_throttled = 0;
+ m_nr_inhibited = 0;
+ m_actived_time = -1;
+
+ m_serviceWatcher = new QDBusServiceWatcher(this);
+ m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
+ m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
+ connect(m_serviceWatcher, SIGNAL(serviceUnregistered(QString)),
+ this, SLOT(serviceUnregistered(QString)));
+
+ // Also receive updates triggered through the DBus (from powerdevil) see Bug #177123
+ QStringList modules;
+ QDBusInterface kdedInterface(QLatin1String( "org.kde.kded" ), QLatin1String( "/kded" ), QLatin1String( "org.kde.kded" ));
+ QDBusReply reply = kdedInterface.call(QLatin1String( "loadedModules" ));
+
+ if (!reply.isValid()) {
+ return;
+ }
+
+ modules = reply.value();
+
+ if (modules.contains(QLatin1String( "powerdevil" ))) {
+ if (!QDBusConnection::sessionBus().connect(QLatin1String( "org.kde.kded" ), QLatin1String( "/modules/powerdevil" ), QLatin1String( "org.kde.PowerDevil" ),
+ QLatin1String( "DPMSconfigUpdated" ), this, SLOT(configure()))) {
+ kDebug() << "error!";
+ }
+ }
+
+ // I make it a really random number to avoid
+ // some assumptions in clients, but just increase
+ // while gnome-ss creates a random number every time
+ m_next_cookie = KRandom::random() % 20000;
+ configure();
+}
+
+//---------------------------------------------------------------------------
+//
+// Destructor - usual cleanups.
+//
+SaverEngine::~SaverEngine()
+{
+ delete mXAutoLock;
+ // Just let mLockProcess leak, so the saver is not killed
+
+ // Restore X screensaver parameters
+ XSetScreenSaver(QX11Info::display(), mXTimeout, mXInterval, mXBlanking,
+ mXExposures);
+}
+
+//---------------------------------------------------------------------------
+
+void SaverEngine::Lock()
+{
+ m_screenLocker->lock();
+}
+
+bool SaverEngine::doLock()
+{
+ if (mState == Waiting)
+ {
+ return startLockProcess( ForceLock );
+ }
+ else
+ {
+ // XXX race condition here
+ ::kill(mLockProcess->pid(), SIGHUP);
+ return false;
+ }
+}
+
+void SaverEngine::processLockTransactions()
+{
+ QList::ConstIterator it = mLockTransactions.constBegin(),
+ end = mLockTransactions.constEnd();
+ for ( ; it != end; ++it )
+ {
+ QDBusConnection::sessionBus().send(*it);
+ }
+ mLockTransactions.clear();
+}
+
+void SaverEngine::saverLockReady()
+{
+ if( mState != Preparing )
+ {
+ kDebug() << "Got unexpected saverLockReady()";
+ return;
+ }
+ kDebug() << "Saver Lock Ready";
+ processLockTransactions();
+ if (m_nr_throttled)
+ ::kill(mLockProcess->pid(), SIGSTOP);
+}
+
+void SaverEngine::SimulateUserActivity()
+{
+ XForceScreenSaver( QX11Info::display(), ScreenSaverReset );
+ if ( mXAutoLock && mState == Waiting )
+ {
+ mXAutoLock->resetTrigger();
+ }
+ else if (mLockProcess)
+ {
+ ::kill(mLockProcess->pid(), SIGUSR1);
+ }
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::save()
+{
+ if (mState == Waiting)
+ {
+ return startLockProcess( DefaultLock );
+ }
+ return false;
+}
+
+bool SaverEngine::setupPlasma()
+{
+ if (mState == Waiting)
+ {
+ return startLockProcess( PlasmaSetup );
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::quit()
+{
+ if (mState == Saving || mState == Preparing)
+ {
+ stopLockProcess();
+ return true;
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::isEnabled()
+{
+ return mXAutoLock != 0;
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::enable( bool e, bool force )
+{
+ if ( !force && e == isEnabled() )
+ return true;
+
+ // If we aren't in a suitable state, we will not reconfigure.
+ if (mState != Waiting)
+ return false;
+
+ if (e)
+ {
+ if (!mXAutoLock)
+ {
+ mXAutoLock = new XAutoLock();
+ connect(mXAutoLock, SIGNAL(timeout()), SLOT(idleTimeout()));
+ }
+
+ int timeout = KScreenSaverSettings::timeout();
+ mXAutoLock->setTimeout(timeout);
+ mXAutoLock->setDPMS(true);
+#ifdef NOT_FREAKIN_UGLY
+ mXAutoLock->changeCornerLockStatus( mLockCornerTopLeft, mLockCornerTopRight, mLockCornerBottomLeft, mLockCornerBottomRight);
+#else
+ xautolock_corners[0] = applyManualSettings(KScreenSaverSettings::actionTopLeft());
+ xautolock_corners[1] = applyManualSettings(KScreenSaverSettings::actionTopRight());
+ xautolock_corners[2] = applyManualSettings(KScreenSaverSettings::actionBottomLeft());
+ xautolock_corners[3] = applyManualSettings(KScreenSaverSettings::actionBottomRight());
+#endif
+
+ mXAutoLock->start();
+ kDebug() << "Saver Engine started, timeout: " << timeout;
+ }
+ else
+ {
+ delete mXAutoLock;
+ mXAutoLock = 0;
+ kDebug() << "Saver Engine disabled";
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::isBlanked()
+{
+ return (mState != Waiting);
+}
+
+//---------------------------------------------------------------------------
+//
+// Read and apply configuration.
+//
+void SaverEngine::configure()
+{
+ // create a new config obj to ensure we read the latest options
+ KScreenSaverSettings::self()->readConfig();
+
+ enable( KScreenSaverSettings::screenSaverEnabled(), true );
+}
+
+//---------------------------------------------------------------------------
+//
+// Start the screen saver.
+//
+bool SaverEngine::startLockProcess( LockType lock_type )
+{
+ Q_ASSERT(mState == Waiting);
+
+ kDebug() << "SaverEngine: starting saver";
+
+ QString path = KStandardDirs::findExe( QLatin1String( "kscreenlocker" ) );
+ if( path.isEmpty())
+ {
+ kDebug() << "Can't find kscreenlocker!";
+ return false;
+ }
+ mLockProcess = new KProcess; // No parent, so it is not auto-deleted
+ connect(mLockProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
+ SLOT(lockProcessExited()));
+ *mLockProcess << path;
+ switch( lock_type )
+ {
+ case ForceLock:
+ *mLockProcess << QLatin1String( "--forcelock" );
+ break;
+ case DontLock:
+ *mLockProcess << QLatin1String( "--dontlock" );
+ break;
+ case PlasmaSetup:
+ *mLockProcess << QLatin1String( "--plasmasetup" );
+ break;
+ default:
+ break;
+ }
+
+ m_actived_time = time( 0 );
+ mLockProcess->start();
+ if (mLockProcess->waitForStarted() == false )
+ {
+ kDebug() << "Failed to start kscreenlocker!";
+ delete mLockProcess;
+ mLockProcess = 0;
+ m_actived_time = -1;
+ return false;
+ }
+
+ if (mXAutoLock)
+ {
+ mXAutoLock->stop();
+ }
+
+ emit ActiveChanged(true); // DBus signal
+ mState = Preparing;
+
+ // It takes a while for kscreenlocker to start and lock the screen.
+ // Therefore delay the DBus call until it tells krunner that the locking is in effect.
+ // This is done only for --forcelock .
+ if (lock_type == ForceLock && calledFromDBus()) {
+ mLockTransactions.append(message().createReply());
+ setDelayedReply(true);
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Stop the screen saver.
+//
+void SaverEngine::stopLockProcess()
+{
+ Q_ASSERT(mState != Waiting);
+ kDebug() << "SaverEngine: stopping lock process";
+
+ mLockProcess->kill();
+}
+
+void SaverEngine::lockProcessExited()
+{
+ Q_ASSERT(mState != Waiting);
+ kDebug() << "SaverEngine: lock process exited";
+
+ delete mLockProcess;
+ mLockProcess = 0;
+
+ if (mXAutoLock)
+ {
+ mXAutoLock->start();
+ }
+
+ processLockTransactions();
+ emit ActiveChanged(false); // DBus signal
+ m_actived_time = -1;
+ mState = Waiting;
+ m_screenLocker->unlock();
+}
+
+//---------------------------------------------------------------------------
+//
+// XAutoLock has detected the required idle time.
+//
+void SaverEngine::idleTimeout()
+{
+ if( mState != Waiting )
+ return; // already saving
+
+ m_screenLocker->lock();
+}
+
+xautolock_corner_t SaverEngine::applyManualSettings(int action)
+{
+ if (action == 0)
+ {
+ kDebug() << "no lock";
+ return ca_nothing;
+ }
+ else if (action == 1)
+ {
+ kDebug() << "lock screen";
+ return ca_forceLock;
+ }
+ else if (action == 2)
+ {
+ kDebug() << "prevent lock";
+ return ca_dontLock;
+ }
+ else
+ {
+ kDebug() << "no lock nothing";
+ return ca_nothing;
+ }
+}
+
+uint SaverEngine::GetSessionIdleTime()
+{
+ return mXAutoLock ? mXAutoLock->idleTime() : 0;
+}
+
+uint SaverEngine::GetActiveTime()
+{
+ if ( m_actived_time == -1 )
+ return 0;
+ return time( 0 ) - m_actived_time;
+}
+
+bool SaverEngine::GetActive()
+{
+ return ( mState != Waiting );
+}
+
+bool SaverEngine::SetActive(bool state)
+{
+ if ( state )
+ return save();
+ else
+ return quit();
+}
+
+uint SaverEngine::Inhibit(const QString &/*application_name*/, const QString &/*reason*/)
+{
+ ScreenSaverRequest sr;
+// sr.appname = application_name;
+// sr.reasongiven = reason;
+ sr.cookie = m_next_cookie++;
+ sr.dbusid = message().service();
+ sr.type = ScreenSaverRequest::Inhibit;
+ m_requests.append( sr );
+ m_serviceWatcher->addWatchedService(sr.dbusid);
+ m_nr_inhibited++;
+ if (KScreenSaverSettings::screenSaverEnabled())
+ enable( false );
+ return sr.cookie;
+}
+
+void SaverEngine::UnInhibit(uint cookie)
+{
+ QMutableListIterator it( m_requests );
+ while ( it.hasNext() )
+ {
+ if ( it.next().cookie == cookie ) {
+ it.remove();
+ if ( !--m_nr_inhibited )
+ if (KScreenSaverSettings::screenSaverEnabled())
+ enable( true );
+ }
+ }
+}
+
+uint SaverEngine::Throttle(const QString &/*application_name*/, const QString &/*reason*/)
+{
+ ScreenSaverRequest sr;
+// sr.appname = application_name;
+// sr.reasongiven = reason;
+ sr.cookie = m_next_cookie++;
+ sr.type = ScreenSaverRequest::Throttle;
+ sr.dbusid = message().service();
+ m_requests.append( sr );
+ m_serviceWatcher->addWatchedService(sr.dbusid);
+ m_nr_throttled++;
+ if (mLockProcess)
+ // XXX race condition here (locker may be not ready yet)
+ ::kill(mLockProcess->pid(), SIGSTOP);
+ return sr.cookie;
+}
+
+void SaverEngine::UnThrottle(uint cookie)
+{
+ QMutableListIterator it( m_requests );
+ while ( it.hasNext() )
+ {
+ if ( it.next().cookie == cookie ) {
+ it.remove();
+ if ( !--m_nr_throttled )
+ if (mLockProcess)
+ ::kill(mLockProcess->pid(), SIGCONT);
+ }
+ }
+}
+
+void SaverEngine::serviceUnregistered(const QString& name)
+{
+ m_serviceWatcher->removeWatchedService( name );
+ QListIterator it( m_requests );
+ while ( it.hasNext() )
+ {
+ const ScreenSaverRequest &r = it.next();
+ if ( r.dbusid == name )
+ {
+ if ( r.type == ScreenSaverRequest::Throttle )
+ UnThrottle( r.cookie );
+ else
+ UnInhibit( r.cookie );
+ }
+ }
+}
+
+#include "saverengine.moc"
+
+
diff --git a/kwin/screenlocker/screensaver/saverengine.h b/kwin/screenlocker/screensaver/saverengine.h
new file mode 100644
index 0000000..4efebec
--- /dev/null
+++ b/kwin/screenlocker/screensaver/saverengine.h
@@ -0,0 +1,195 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright 1999 Martin R. Jones
+//
+
+#ifndef SAVERENGINE_H
+#define SAVERENGINE_H
+
+#include
+#include
+#include
+#include