summaryrefslogtreecommitdiffstats
path: root/kdesktop/lock
diff options
context:
space:
mode:
Diffstat (limited to 'kdesktop/lock')
-rw-r--r--kdesktop/lock/Makefile.am24
-rw-r--r--kdesktop/lock/autologout.cc115
-rw-r--r--kdesktop/lock/autologout.h51
-rw-r--r--kdesktop/lock/configure.in.in37
-rw-r--r--kdesktop/lock/lockdlg.cc720
-rw-r--r--kdesktop/lock/lockdlg.h92
-rw-r--r--kdesktop/lock/lockprocess.cc1172
-rw-r--r--kdesktop/lock/lockprocess.h131
-rw-r--r--kdesktop/lock/main.cc174
-rw-r--r--kdesktop/lock/main.h39
10 files changed, 2555 insertions, 0 deletions
diff --git a/kdesktop/lock/Makefile.am b/kdesktop/lock/Makefile.am
new file mode 100644
index 000000000..4af8d4fae
--- /dev/null
+++ b/kdesktop/lock/Makefile.am
@@ -0,0 +1,24 @@
+## Makefile.am of kdebase/kdesktop/lock
+
+INCLUDES = -I.. -I$(top_srcdir)/kcheckpass -I$(top_srcdir)/kdmlib $(GLINC) $(all_includes)
+kdesktop_lock_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kdesktop_lock_LDADD = ../libkdesktopsettings.la ../../kdmlib/libdmctl.la $(LIB_KIO) $(LIB_XF86MISC) $(GLLIB)
+
+####### Files
+
+bin_PROGRAMS = kdesktop_lock
+
+kdesktop_lock_SOURCES = lockprocess.cc lockdlg.cc autologout.cc main.cc
+
+noinst_HEADERS = lockprocess.h lockdlg.h autologout.h main.h
+
+METASOURCES = AUTO
+
+lockprocess.o: ../kdesktopsettings.h
+
+####### Build rules
+
+PAM = @KSCREENSAVER_PAM_SERVICE@
+
+install-data-local:
+ -@test -n "$(DESTDIR)" || test -z "$(PAM)" || $(top_srcdir)/mkpamserv $(PAM)
diff --git a/kdesktop/lock/autologout.cc b/kdesktop/lock/autologout.cc
new file mode 100644
index 000000000..f351fe2e7
--- /dev/null
+++ b/kdesktop/lock/autologout.cc
@@ -0,0 +1,115 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 2004 Chris Howells <[email protected]>
+
+#include "lockprocess.h"
+#include "autologout.h"
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <dcopref.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+
+#include <qlayout.h>
+#include <qmessagebox.h>
+#include <qlabel.h>
+#include <qstyle.h>
+#include <qapplication.h>
+#include <qdialog.h>
+#include <qprogressbar.h>
+
+#define COUNTDOWN 30
+
+AutoLogout::AutoLogout(LockProcess *parent) : QDialog(parent, "password dialog", true, WX11BypassWM)
+{
+ frame = new QFrame(this);
+ frame->setFrameStyle(QFrame::Panel | QFrame::Raised);
+ frame->setLineWidth(2);
+
+ QLabel *pixLabel = new QLabel( frame, "pixlabel" );
+ pixLabel->setPixmap(DesktopIcon("exit"));
+
+ QLabel *greetLabel = new QLabel(i18n("<nobr><qt><b>Automatic Log Out</b></qt><nobr>"), frame);
+ QLabel *infoLabel = new QLabel(i18n("<qt>To prevent being logged out, resume using this session by moving the mouse or pressing a key.</qt>"), frame);
+
+ mStatusLabel = new QLabel("<b> </b>", frame);
+ mStatusLabel->setAlignment(QLabel::AlignCenter);
+
+ QLabel *mProgressLabel = new QLabel("Time Remaining:", frame);
+ mProgressRemaining = new QProgressBar(frame);
+ mProgressRemaining->setPercentageVisible(false);
+
+ QVBoxLayout *unlockDialogLayout = new QVBoxLayout( this );
+ unlockDialogLayout->addWidget( frame );
+
+ frameLayout = new QGridLayout(frame, 1, 1, KDialog::marginHint(), KDialog::spacingHint());
+ frameLayout->addMultiCellWidget(pixLabel, 0, 2, 0, 0, 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->setTotalSteps(COUNTDOWN * 25);
+
+ updateInfo(mRemaining);
+
+ mCountdownTimerId = startTimer(1000/25);
+
+ connect(qApp, SIGNAL(activity()), SLOT(slotActivity()));
+}
+
+AutoLogout::~AutoLogout()
+{
+ hide();
+}
+
+void AutoLogout::updateInfo(int timeout)
+{
+ mStatusLabel->setText(i18n("<nobr><qt>You will be automatically logged out in 1 second</qt></nobr>",
+ "<nobr><qt>You will be automatically logged out in %n seconds</qt></nobr>",
+ timeout / 25) );
+ mProgressRemaining->setProgress(timeout);
+}
+
+void AutoLogout::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == mCountdownTimerId)
+ {
+ updateInfo(mRemaining);
+ --mRemaining;
+ if (mRemaining < 0)
+ {
+ logout();
+ }
+ }
+}
+
+void AutoLogout::slotActivity()
+{
+ accept();
+}
+
+void AutoLogout::logout()
+{
+ killTimers();
+ DCOPRef("ksmserver","ksmserver").send("logout", 0, 0, 0);
+}
+
+void AutoLogout::show()
+{
+ QDialog::show();
+ QApplication::flushX();
+}
+
+#include "autologout.moc"
diff --git a/kdesktop/lock/autologout.h b/kdesktop/lock/autologout.h
new file mode 100644
index 000000000..e48716575
--- /dev/null
+++ b/kdesktop/lock/autologout.h
@@ -0,0 +1,51 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <[email protected]>
+// Copyright (c) 2003 Oswald Buddenhagen <[email protected]>
+// Coypright (c) 2004 Chris Howells <[email protected]>
+
+#ifndef __TIMEOUT_H__
+#define __TIMEOUT_H__
+
+#include <qstringlist.h>
+
+#include <qlayout.h>
+
+class LockProcess;
+class QFrame;
+class QGridLayout;
+class QLabel;
+class QDialog;
+class QProgressBar;
+
+class AutoLogout : public QDialog
+{
+ Q_OBJECT
+
+public:
+ AutoLogout(LockProcess *parent);
+ ~AutoLogout();
+ virtual void show();
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+
+private slots:
+ void slotActivity();
+
+private:
+ void updateInfo(int);
+ QFrame *frame;
+ QGridLayout *frameLayout;
+ QLabel *mStatusLabel;
+ int mCountdownTimerId;
+ int mRemaining;
+ QTimer countDownTimer;
+ QProgressBar *mProgressRemaining;
+ void logout();
+};
+
+#endif
+
diff --git a/kdesktop/lock/configure.in.in b/kdesktop/lock/configure.in.in
new file mode 100644
index 000000000..d5d61a5f9
--- /dev/null
+++ b/kdesktop/lock/configure.in.in
@@ -0,0 +1,37 @@
+xss_save_ldflags="$LDFLAGS"
+LDFLAGS="$X_LDFLAGS"
+
+LIB_XF86MISC=
+
+KDE_CHECK_HEADER(X11/extensions/xf86misc.h,
+ [
+ AC_CHECK_LIB(Xxf86misc,XF86MiscQueryVersion,
+ [
+ AC_DEFINE(HAVE_XF86MISC, 1, [Define if you have the xf86misc extension])
+ LIB_XF86MISC="-lXxf86misc"
+ ],
+ [], [ $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS ])
+ ],[],
+ [
+ #include <X11/Xlib.h>
+ ])
+AC_SUBST(LIB_XF86MISC)
+
+if test -n "$LIB_XF86MISC"; then
+ AC_CHECK_LIB(Xxf86misc,XF86MiscSetGrabKeysState,
+ [
+ AC_DEFINE(HAVE_XF86MISCSETGRABKEYSSTATE, 1, [Define if you have XF86MiscSetGrabKeysState()])
+ ],
+ [], [ $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS ])
+fi
+
+LDFLAGS="$xss_save_ldflags"
+
+AC_HAVE_GL(
+ [
+ AC_CHECK_LIB(GL,glXChooseVisual,
+ [
+ AC_DEFINE(HAVE_GLXCHOOSEVISUAL, 1, [Define if you have glXChooseVisual()])
+ ])
+ ],[]
+ )
diff --git a/kdesktop/lock/lockdlg.cc b/kdesktop/lock/lockdlg.cc
new file mode 100644
index 000000000..8006cf29d
--- /dev/null
+++ b/kdesktop/lock/lockdlg.cc
@@ -0,0 +1,720 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <[email protected]>
+// Copyright (c) 2003 Chris Howells <[email protected]>
+// Copyright (c) 2003 Oswald Buddenhagen <[email protected]>
+
+#include <config.h>
+
+#include "lockprocess.h"
+#include "lockdlg.h"
+
+#include <kcheckpass.h>
+#include <dmctl.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kseparator.h>
+#include <kstandarddirs.h>
+#include <kglobalsettings.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kdesu/defaults.h>
+#include <kpassdlg.h>
+#include <kdebug.h>
+#include <kuser.h>
+#include <dcopref.h>
+#include <kmessagebox.h>
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qmessagebox.h>
+#include <qsimplerichtext.h>
+#include <qlabel.h>
+#include <qstringlist.h>
+#include <qfontmetrics.h>
+#include <qstyle.h>
+#include <qapplication.h>
+#include <qlistview.h>
+#include <qheader.h>
+#include <qcheckbox.h>
+
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <fixx11h.h>
+
+#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)
+ : QDialog(parent, "password dialog", true, WX11BypassWM),
+ mPlugin( plugin ),
+ mCapsLocked(-1),
+ mUnlockingFailed(false)
+{
+ frame = new QFrame( this );
+ frame->setFrameStyle( QFrame::Panel | QFrame::Raised );
+ frame->setLineWidth( 2 );
+
+ QLabel *pixLabel = new QLabel( frame, "pixlabel" );
+ pixLabel->setPixmap(DesktopIcon("lock"));
+
+ KUser user;
+ QLabel *greetLabel = new QLabel( user.fullName().isEmpty() ?
+ i18n("<nobr><b>The session is locked</b><br>") :
+ i18n("<nobr><b>The session was locked by %1</b><br>").arg( user.fullName() ), frame );
+
+ mStatusLabel = new QLabel( "<b> </b>", frame );
+ mStatusLabel->setAlignment( QLabel::AlignCenter );
+
+ mLayoutButton = new QPushButton( frame );
+ mLayoutButton->setFlat( true );
+
+ KSeparator *sep = new KSeparator( KSeparator::HLine, frame );
+
+ mNewSessButton = new KPushButton( KGuiItem(i18n("Sw&itch User..."), "fork"), frame );
+ ok = new KPushButton( i18n("Unl&ock"), frame );
+ cancel = new KPushButton( KStdGuiItem::cancel(), frame );
+
+ greet = plugin->info->create( this, 0, this, mLayoutButton, QString::null,
+ KGreeterPlugin::Authenticate, KGreeterPlugin::ExUnlock );
+
+
+ QVBoxLayout *unlockDialogLayout = new QVBoxLayout( this );
+ unlockDialogLayout->addWidget( frame );
+
+ QHBoxLayout *layStatus = new QHBoxLayout( 0, 0, KDialog::spacingHint());
+ layStatus->addWidget( mStatusLabel );
+ layStatus->addWidget( mLayoutButton );
+
+ QHBoxLayout *layButtons = new QHBoxLayout( 0, 0, KDialog::spacingHint());
+ layButtons->addWidget( mNewSessButton );
+ layButtons->addStretch();
+ layButtons->addWidget( ok );
+ layButtons->addWidget( cancel );
+
+ frameLayout = new QGridLayout( frame, 1, 1, KDialog::marginHint(), KDialog::spacingHint() );
+ frameLayout->addMultiCellWidget( pixLabel, 0, 2, 0, 0, AlignTop );
+ frameLayout->addWidget( greetLabel, 0, 1 );
+ frameLayout->addItem( greet->getLayoutItem(), 1, 1 );
+ frameLayout->addLayout( layStatus, 2, 1 );
+ frameLayout->addMultiCellWidget( sep, 3, 3, 0, 1 );
+ frameLayout->addMultiCellLayout( layButtons, 4, 4, 0, 1 );
+
+ setTabOrder( ok, cancel );
+ setTabOrder( cancel, mNewSessButton );
+ setTabOrder( mNewSessButton, mLayoutButton );
+
+ connect(mLayoutButton, SIGNAL(clicked()), this, SLOT(layoutClicked()));
+ connect(cancel, SIGNAL(clicked()), SLOT(reject()));
+ connect(ok, SIGNAL(clicked()), SLOT(slotOK()));
+ connect(mNewSessButton, SIGNAL(clicked()), SLOT(slotSwitchUser()));
+
+ if (!DM().isSwitchable() || !kapp->authorize("switch_user"))
+ mNewSessButton->hide();
+
+ installEventFilter(this);
+
+ mFailedTimerId = 0;
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+ connect(qApp, SIGNAL(activity()), SLOT(slotActivity()) );
+
+ greet->start();
+
+ DCOPRef kxkb("kxkb", "kxkb");
+ if( !kxkb.isNull() ) {
+ layoutsList = kxkb.call("getLayoutsList");
+ QString currentLayout = kxkb.call("getCurrentLayout");
+ if( !currentLayout.isEmpty() && layoutsList.count() > 1 ) {
+ currLayout = layoutsList.find(currentLayout);
+ if (currLayout == layoutsList.end())
+ setLayoutText("err");
+ else
+ setLayoutText(*currLayout);
+ } else
+ mLayoutButton->hide();
+ } else {
+ mLayoutButton->hide(); // no kxkb running
+ }
+ capsLocked();
+}
+
+PasswordDlg::~PasswordDlg()
+{
+ hide();
+ frameLayout->removeItem( greet->getLayoutItem() );
+ delete greet;
+}
+
+void PasswordDlg::layoutClicked()
+{
+
+ if( ++currLayout == layoutsList.end() )
+ currLayout = layoutsList.begin();
+
+ DCOPRef kxkb("kxkb", "kxkb");
+ setLayoutText( kxkb.call("setLayout", *currLayout) ? *currLayout : "err" );
+
+}
+
+void PasswordDlg::setLayoutText( const QString &txt )
+{
+ mLayoutButton->setText( txt );
+ QSize sz = mLayoutButton->fontMetrics().size( 0, txt );
+ int mrg = mLayoutButton->style().pixelMetric( QStyle::PM_ButtonMargin ) * 2;
+ mLayoutButton->setFixedSize( sz.width() + mrg, sz.height() + mrg );
+}
+
+void PasswordDlg::updateLabel()
+{
+ if (mUnlockingFailed)
+ {
+ mStatusLabel->setPaletteForegroundColor(Qt::black);
+ mStatusLabel->setText(i18n("<b>Unlocking failed</b>"));
+ }
+ else
+ if (mCapsLocked)
+ {
+ mStatusLabel->setPaletteForegroundColor(Qt::red);
+ mStatusLabel->setText(i18n("<b>Warning: Caps Lock on</b>"));
+ }
+ else
+ {
+ mStatusLabel->setText("<b> </b>");
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Handle timer events.
+//
+void PasswordDlg::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == mTimeoutTimerId)
+ {
+ reject();
+ }
+ 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;
+ return GRead (buf, len);
+}
+
+void PasswordDlg::reapVerify()
+{
+ ::close( sFd );
+ int status;
+ ::waitpid( sPid, &status, 0 );
+ 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 );
+ return;
+ case AuthAbort:
+ return;
+ }
+ cantCheck();
+}
+
+void PasswordDlg::handleVerify()
+{
+ int ret;
+ char *arr;
+
+ while (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( QMessageBox::Information, QString::fromLocal8Bit( arr ) );
+ ::free( arr );
+ continue;
+ case ConvPutError:
+ if (!GRecvArr( &arr ))
+ break;
+ if (!greet->textMessage( arr, true ))
+ static_cast< LockProcess* >(parent())->msgBox( QMessageBox::Warning, QString::fromLocal8Bit( arr ) );
+ ::free( arr );
+ continue;
+ }
+ break;
+ }
+ reapVerify();
+}
+
+////// greeter plugin callbacks
+
+void PasswordDlg::gplugReturnText( const char *text, int tag )
+{
+ GSendStr( text );
+ if (text)
+ GSendInt( tag );
+ handleVerify();
+}
+
+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 );
+ handleVerify();
+}
+
+void PasswordDlg::gplugSetUser( const QString & )
+{
+ // ignore ...
+}
+
+void PasswordDlg::cantCheck()
+{
+ greet->failed();
+ static_cast< LockProcess* >(parent())->msgBox( QMessageBox::Critical,
+ i18n("Cannot unlock the session because the authentication system failed to work;\n"
+ "you must kill kdesktop_lock (pid %1) manually.").arg(getpid()) );
+ greet->revive();
+}
+
+//---------------------------------------------------------------------------
+//
+// Starts the kcheckpass process to check the user's password.
+//
+void PasswordDlg::gplugStart()
+{
+ int sfd[2];
+ char fdbuf[16];
+
+ 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("kcheckpass", "kcheckpass",
+#ifdef HAVE_PAM
+ "-c", KSCREENSAVER_PAM_SERVICE,
+#endif
+ "-m", mPlugin->info->method,
+ "-S", fdbuf,
+ (char *)0);
+ exit(20);
+ }
+ ::close(sfd[1]);
+ sFd = sfd[0];
+ handleVerify();
+}
+
+void PasswordDlg::gplugActivity()
+{
+ slotActivity();
+}
+
+void PasswordDlg::gplugMsgBox( QMessageBox::Icon type, const QString &text )
+{
+ QDialog dialog( this, 0, true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( &dialog );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QVBoxLayout *vbox = new QVBoxLayout( &dialog );
+ vbox->addWidget( winFrame );
+
+ QLabel *label1 = new QLabel( winFrame );
+ label1->setPixmap( QMessageBox::standardIcon( type ) );
+ QLabel *label2 = new QLabel( text, winFrame );
+ KPushButton *button = new KPushButton( KStdGuiItem::ok(), winFrame );
+ button->setDefault( true );
+ button->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+ connect( button, SIGNAL( clicked() ), SLOT( accept() ) );
+
+ QGridLayout *grid = new QGridLayout( winFrame, 2, 2, 10 );
+ grid->addWidget( label1, 0, 0, Qt::AlignCenter );
+ grid->addWidget( label2, 0, 1, Qt::AlignCenter );
+ grid->addMultiCellWidget( button, 1,1, 0,1, Qt::AlignCenter );
+
+ static_cast< LockProcess* >(parent())->execDialog( &dialog );
+}
+
+void PasswordDlg::slotOK()
+{
+ greet->next();
+}
+
+
+void PasswordDlg::show()
+{
+ QDialog::show();
+ QApplication::flushX();
+}
+
+void PasswordDlg::slotStartNewSession()
+{
+ if (!KMessageBox::shouldBeShownContinue( ":confirmNewSession" )) {
+ DM().startReserve();
+ return;
+ }
+
+ killTimer(mTimeoutTimerId);
+ mTimeoutTimerId = 0;
+
+ QDialog *dialog = new QDialog( this, "warnbox", true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( dialog );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QVBoxLayout *vbox = new QVBoxLayout( dialog );
+ vbox->addWidget( winFrame );
+
+ QLabel *label1 = new QLabel( winFrame );
+ label1->setPixmap( QMessageBox::standardIcon( QMessageBox::Warning ) );
+ QString qt_text =
+ i18n("You have chosen to open another desktop session "
+ "instead of resuming the current one.<br>"
+ "The current session will be hidden "
+ "and a new login screen will be displayed.<br>"
+ "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.")
+ .arg(7).arg(8);
+ QLabel *label2 = new QLabel( qt_text, winFrame );
+ KPushButton *okbutton = new KPushButton( KGuiItem(i18n("&Start New Session"), "fork"), winFrame );
+ okbutton->setDefault( true );
+ connect( okbutton, SIGNAL( clicked() ), dialog, SLOT( accept() ) );
+ KPushButton *cbutton = new KPushButton( KStdGuiItem::cancel(), winFrame );
+ connect( cbutton, SIGNAL( clicked() ), dialog, SLOT( reject() ) );
+
+ QBoxLayout *mbox = new QVBoxLayout( winFrame, KDialog::marginHint(), KDialog::spacingHint() );
+
+ QGridLayout *grid = new QGridLayout( mbox, 2, 2, 2 * KDialog::spacingHint() );
+ grid->setMargin( KDialog::marginHint() );
+ grid->addWidget( label1, 0, 0, Qt::AlignCenter );
+ grid->addWidget( label2, 0, 1, Qt::AlignCenter );
+ QCheckBox *cb = new QCheckBox( i18n("&Do not ask again"), winFrame );
+ grid->addMultiCellWidget( cb, 1,1, 0,1 );
+
+ QBoxLayout *hbox = new QHBoxLayout( mbox, KDialog::spacingHint() );
+ hbox->addStretch( 1 );
+ hbox->addWidget( okbutton );
+ hbox->addStretch( 1 );
+ hbox->addWidget( cbutton );
+ hbox->addStretch( 1 );
+
+ // stolen from kmessagebox
+ int pref_width = 0;
+ int pref_height = 0;
+ // Calculate a proper size for the text.
+ {
+ QSimpleRichText rt(qt_text, dialog->font());
+ QRect rect = KGlobalSettings::desktopGeometry(dialog);
+
+ pref_width = rect.width() / 3;
+ rt.setWidth(pref_width);
+ int used_width = rt.widthUsed();
+ pref_height = rt.height();
+ if (used_width <= pref_width)
+ {
+ while(true)
+ {
+ int new_width = (used_width * 9) / 10;
+ rt.setWidth(new_width);
+ int new_height = rt.height();
+ if (new_height > pref_height)
+ break;
+ used_width = rt.widthUsed();
+ if (used_width > new_width)
+ break;
+ }
+ pref_width = used_width;
+ }
+ else
+ {
+ if (used_width > (pref_width *2))
+ pref_width = pref_width *2;
+ else
+ pref_width = used_width;
+ }
+ }
+ label2->setFixedSize(QSize(pref_width+10, pref_height));
+
+ int ret = static_cast< LockProcess* >( parent())->execDialog( dialog );
+
+ delete dialog;
+
+ if (ret == QDialog::Accepted) {
+ if (cb->isChecked())
+ KMessageBox::saveDontShowAgainContinue( ":confirmNewSession" );
+ DM().startReserve();
+ }
+
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+}
+
+class LockListViewItem : public QListViewItem {
+public:
+ LockListViewItem( QListView *parent,
+ const QString &sess, const QString &loc, int _vt )
+ : QListViewItem( parent )
+ , vt( _vt )
+ {
+ setText( 0, sess );
+ setText( 1, loc );
+ }
+
+ int vt;
+};
+
+void PasswordDlg::slotSwitchUser()
+{
+ int p = 0;
+ DM dm;
+
+ QDialog dialog( this, "sessbox", true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( &dialog );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QBoxLayout *vbox = new QVBoxLayout( &dialog );
+ vbox->addWidget( winFrame );
+
+ QBoxLayout *hbox = new QHBoxLayout( winFrame, KDialog::marginHint(), KDialog::spacingHint() );
+
+ QBoxLayout *vbox1 = new QVBoxLayout( hbox, KDialog::spacingHint() );
+ QBoxLayout *vbox2 = new QVBoxLayout( hbox, KDialog::spacingHint() );
+
+ KPushButton *btn;
+
+ SessList sess;
+ if (dm.localSessions( sess )) {
+
+ lv = new QListView( winFrame );
+ connect( lv, SIGNAL(doubleClicked(QListViewItem *, const QPoint&, int)), SLOT(slotSessionActivated()) );
+ connect( lv, SIGNAL(doubleClicked(QListViewItem *, const QPoint&, int)), &dialog, SLOT(reject()) );
+ lv->setAllColumnsShowFocus( true );
+ lv->addColumn( i18n("Session") );
+ lv->addColumn( i18n("Location") );
+ lv->setColumnWidthMode( 0, QListView::Maximum );
+ lv->setColumnWidthMode( 1, QListView::Maximum );
+ QListViewItem *itm = 0;
+ QString user, loc;
+ int ns = 0;
+ for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ DM::sess2Str2( *it, user, loc );
+ itm = new LockListViewItem( lv, user, loc, (*it).vt );
+ if (!(*it).vt)
+ itm->setEnabled( false );
+ 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 ) );
+ lv->setFixedHeight( fw + hds.height() +
+ itm->height() * (ns < 6 ? 6 : ns > 10 ? 10 : ns) );
+ lv->header()->adjustHeaderSize();
+ vbox1->addWidget( lv );
+
+ btn = new KPushButton( KGuiItem(i18n("session", "&Activate"), "fork"), winFrame );
+ connect( btn, SIGNAL(clicked()), SLOT(slotSessionActivated()) );
+ connect( btn, SIGNAL(clicked()), &dialog, SLOT(reject()) );
+ vbox2->addWidget( btn );
+ vbox2->addStretch( 2 );
+ }
+
+ if (kapp->authorize("start_new_session") && (p = dm.numReserve()) >= 0)
+ {
+ btn = new KPushButton( KGuiItem(i18n("Start &New Session"), "fork"), winFrame );
+ 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( KStdGuiItem::cancel(), winFrame );
+ 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)
+ DM().switchVT( itm->vt );
+}
+
+void PasswordDlg::capsLocked()
+{
+ unsigned int lmask;
+ Window dummy1, dummy2;
+ int dummy3, dummy4, dummy5, dummy6;
+ XQueryPointer(qt_xdisplay(), DefaultRootWindow( qt_xdisplay() ), &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &lmask);
+ mCapsLocked = lmask & LockMask;
+ updateLabel();
+}
+
+#include "lockdlg.moc"
diff --git a/kdesktop/lock/lockdlg.h b/kdesktop/lock/lockdlg.h
new file mode 100644
index 000000000..4bb468c03
--- /dev/null
+++ b/kdesktop/lock/lockdlg.h
@@ -0,0 +1,92 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <[email protected]>
+// Copyright (c) 2003 Oswald Buddenhagen <[email protected]>
+//
+
+#ifndef __LOCKDLG_H__
+#define __LOCKDLG_H__
+
+#include <kgreeterplugin.h>
+
+#include <qdialog.h>
+#include <qstringlist.h>
+
+struct GreeterPluginHandle;
+class LockProcess;
+class QFrame;
+class QGridLayout;
+class QLabel;
+class KPushButton;
+class QListView;
+
+//===========================================================================
+//
+// Simple dialog for entering a password.
+// It does not handle password validation.
+//
+class PasswordDlg : public QDialog, public KGreeterPluginHandler
+{
+ Q_OBJECT
+
+public:
+ PasswordDlg(LockProcess *parent, GreeterPluginHandle *plugin);
+ ~PasswordDlg();
+ virtual void show();
+
+ // 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 gplugActivity();
+ virtual void gplugMsgBox( QMessageBox::Icon type, const QString &text );
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+ virtual bool eventFilter(QObject *, QEvent *);
+
+private slots:
+ void slotSwitchUser();
+ void slotSessionActivated();
+ void slotStartNewSession();
+ void slotOK();
+ void layoutClicked();
+ void slotActivity();
+
+private:
+ void setLayoutText( const QString &txt );
+ 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 handleVerify();
+ void reapVerify();
+ void cantCheck();
+ GreeterPluginHandle *mPlugin;
+ KGreeterPlugin *greet;
+ QFrame *frame;
+ QGridLayout *frameLayout;
+ QLabel *mStatusLabel;
+ KPushButton *mNewSessButton, *ok, *cancel;
+ QPushButton *mLayoutButton;
+ int mFailedTimerId;
+ int mTimeoutTimerId;
+ int mCapsLocked;
+ bool mUnlockingFailed;
+ QStringList layoutsList;
+ QStringList::iterator currLayout;
+ int sPid, sFd;
+ QListView *lv;
+};
+
+#endif
+
diff --git a/kdesktop/lock/lockprocess.cc b/kdesktop/lock/lockprocess.cc
new file mode 100644
index 000000000..a813b6899
--- /dev/null
+++ b/kdesktop/lock/lockprocess.cc
@@ -0,0 +1,1172 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <[email protected]>
+// Copyright (c) 2003 Oswald Buddenhagen <[email protected]>
+//
+
+//kdesktop keeps running and checks user inactivity
+//when it should show screensaver (and maybe lock the session),
+//it starts kdesktop_lock, who does all the locking and who
+//actually starts the screensaver
+
+//It's done this way to prevent screen unlocking when kdesktop
+//crashes (e.g. because it's set to multiple wallpapers and
+//some image will be corrupted).
+
+#include <config.h>
+
+#include "lockprocess.h"
+#include "lockdlg.h"
+#include "autologout.h"
+#include "kdesktopsettings.h"
+
+#include <dmctl.h>
+
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kservicegroup.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <klibloader.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kpixmapeffect.h>
+#include <kpixmap.h>
+
+#include <qframe.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qfile.h>
+#include <qsocketnotifier.h>
+#include <qvaluevector.h>
+#include <qtooltip.h>
+
+#include <qdatetime.h>
+
+#include <stdlib.h>
+#include <assert.h>
+#include <signal.h>
+#ifdef HAVE_SETPRIORITY
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+
+#ifdef HAVE_DPMS
+extern "C" {
+#include <X11/Xmd.h>
+#ifndef Bool
+#define Bool BOOL
+#endif
+#include <X11/extensions/dpms.h>
+
+#ifndef HAVE_DPMSINFO_PROTO
+Status DPMSInfo ( Display *, CARD16 *, BOOL * );
+#endif
+}
+#endif
+
+#ifdef HAVE_XF86MISC
+#include <X11/extensions/xf86misc.h>
+#endif
+
+#ifdef HAVE_GLXCHOOSEVISUAL
+#include <GL/glx.h>
+#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;
+
+//===========================================================================
+//
+// Screen saver handling process. Handles screensaver window,
+// starting screensaver hacks, and password entry.f
+//
+LockProcess::LockProcess(bool child, bool useBlankOnly)
+ : QWidget(0L, "saver window", WX11BypassWM),
+ mOpenGLVisual(0),
+ child_saver(child),
+ mParent(0),
+ mUseBlankOnly(useBlankOnly),
+ mSuspended(false),
+ mVisibility(false),
+ mRestoreXF86Lock(false),
+ mForbidden(false),
+ mAutoLogout(false)
+{
+ setupSignals();
+
+ kapp->installX11EventFilter(this);
+
+ // Get root window size
+ XWindowAttributes rootAttr;
+ XGetWindowAttributes(qt_xdisplay(), RootWindow(qt_xdisplay(),
+ qt_xscreen()), &rootAttr);
+ mRootWidth = rootAttr.width;
+ mRootHeight = rootAttr.height;
+ { // trigger creation of QToolTipManager, it does XSelectInput() on the root window
+ QWidget w;
+ QToolTip::add( &w, "foo" );
+ }
+ XSelectInput( qt_xdisplay(), qt_xrootwin(),
+ SubstructureNotifyMask | rootAttr.your_event_mask );
+
+ // Add non-KDE path
+ KGlobal::dirs()->addResourceType("scrsav",
+ KGlobal::dirs()->kde_default("apps") +
+ "System/ScreenSavers/");
+
+ // Add KDE specific screensaver path
+ QString relPath="System/ScreenSavers/";
+ KServiceGroup::Ptr servGroup = KServiceGroup::baseGroup( "screensavers");
+ if (servGroup)
+ {
+ relPath=servGroup->relPath();
+ kdDebug(1204) << "relPath=" << relPath << endl;
+ }
+ KGlobal::dirs()->addResourceType("scrsav",
+ KGlobal::dirs()->kde_default("apps") +
+ relPath);
+
+ // virtual root property
+ gXA_VROOT = XInternAtom (qt_xdisplay(), "__SWM_VROOT", False);
+ gXA_SCREENSAVER_VERSION = XInternAtom (qt_xdisplay(), "_SCREENSAVER_VERSION", False);
+
+ connect(&mHackProc, SIGNAL(processExited(KProcess *)),
+ SLOT(hackExited(KProcess *)));
+
+ connect(&mSuspendTimer, SIGNAL(timeout()), SLOT(suspend()));
+
+ QStringList dmopt =
+ QStringList::split(QChar(','),
+ QString::fromLatin1( ::getenv( "XDM_MANAGED" )));
+ for (QStringList::ConstIterator it = dmopt.begin(); it != dmopt.end(); ++it)
+ if ((*it).startsWith("method="))
+ mMethod = (*it).mid(7);
+
+ configure();
+
+#ifdef HAVE_DPMS
+ if (mDPMSDepend) {
+ BOOL on;
+ CARD16 state;
+ DPMSInfo(qt_xdisplay(), &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;
+}
+
+//---------------------------------------------------------------------------
+//
+// 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);
+}
+
+void LockProcess::timerEvent(QTimerEvent *ev)
+{
+ if (mAutoLogout && ev->timerId() == mAutoLogoutTimerId)
+ {
+ killTimer(mAutoLogoutTimerId);
+ AutoLogout autologout(this);
+ execDialog(&autologout);
+ }
+}
+
+void LockProcess::setupSignals()
+{
+ struct sigaction act;
+ // ignore SIGINT
+ act.sa_handler=SIG_IGN;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGINT);
+ act.sa_flags = 0;
+ sigaction(SIGINT, &act, 0L);
+ // ignore SIGQUIT
+ act.sa_handler=SIG_IGN;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGQUIT);
+ act.sa_flags = 0;
+ sigaction(SIGQUIT, &act, 0L);
+ // exit cleanly on SIGTERM
+ act.sa_handler= sigterm_handler;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGTERM);
+ act.sa_flags = 0;
+ sigaction(SIGTERM, &act, 0L);
+ // SIGHUP forces lock
+ act.sa_handler= sighup_handler;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGHUP);
+ act.sa_flags = 0;
+ sigaction(SIGHUP, &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 == 'H' ) {
+ if( !mLocked )
+ startLock();
+ }
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::lock()
+{
+ 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;
+ if (startLock())
+ {
+ QTimer::singleShot(1000, this, SLOT(slotDeadTimePassed()));
+ return true;
+ }
+ stopSaver();
+ mBusy = false;
+ }
+ return false;
+}
+//---------------------------------------------------------------------------
+void LockProcess::slotDeadTimePassed()
+{
+ mBusy = false;
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::defaultSave()
+{
+ mLocked = false;
+ if (startSaver()) {
+ if (mLockGrace >= 0)
+ QTimer::singleShot(mLockGrace, this, SLOT(startLock()));
+ return true;
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::dontLock()
+{
+ mLocked = false;
+ return startSaver();
+}
+
+//---------------------------------------------------------------------------
+void LockProcess::quitSaver()
+{
+ stopSaver();
+ kapp->quit();
+}
+
+//---------------------------------------------------------------------------
+//
+// Read and apply configuration.
+//
+void LockProcess::configure()
+{
+ // the configuration is stored in kdesktop's config file
+ if( KDesktopSettings::lock() )
+ {
+ mLockGrace = KDesktopSettings::lockGrace();
+ if (mLockGrace < 0)
+ mLockGrace = 0;
+ else if (mLockGrace > 300000)
+ mLockGrace = 300000; // 5 minutes, keep the value sane
+ }
+ else
+ mLockGrace = -1;
+
+ if ( KDesktopSettings::autoLogout() )
+ {
+ mAutoLogout = true;
+ mAutoLogoutTimeout = KDesktopSettings::autoLogoutTimeout();
+ mAutoLogoutTimerId = startTimer(mAutoLogoutTimeout * 1000); // in milliseconds
+ }
+
+#ifdef HAVE_DPMS
+ //if the user decided that the screensaver should run independent from
+ //dpms, we shouldn't check for it, aleXXX
+ mDPMSDepend = KDesktopSettings::dpmsDependent();
+#endif
+
+ mPriority = KDesktopSettings::priority();
+ if (mPriority < 0) mPriority = 0;
+ if (mPriority > 19) mPriority = 19;
+
+ mSaver = KDesktopSettings::saver();
+ if (mSaver.isEmpty() || mUseBlankOnly)
+ mSaver = "KBlankscreen.desktop";
+
+ readSaver();
+
+ mPlugins = KDesktopSettings::pluginsUnlock();
+ if (mPlugins.isEmpty())
+ mPlugins = QStringList("classic");
+ mPluginOptions = KDesktopSettings::pluginOptions();
+}
+
+//---------------------------------------------------------------------------
+//
+// Read the command line needed to run the screensaver given a .desktop file.
+//
+void LockProcess::readSaver()
+{
+ if (!mSaver.isEmpty())
+ {
+ QString file = locate("scrsav", mSaver);
+
+ bool opengl = kapp->authorize("opengl_screensavers");
+ bool manipulatescreen = kapp->authorize("manipulatescreen_screensavers");
+ KDesktopFile config(file, true);
+ if (config.readEntry("X-KDE-Type").utf8())
+ {
+ QString saverType = config.readEntry("X-KDE-Type").utf8();
+ QStringList saverTypes = QStringList::split(";", saverType);
+ for (uint i = 0; i < saverTypes.count(); i++)
+ {
+ if ((saverTypes[i] == "ManipulateScreen") && !manipulatescreen)
+ {
+ kdDebug(1204) << "Screensaver is type ManipulateScreen and ManipulateScreen is forbidden" << endl;
+ mForbidden = true;
+ }
+ if ((saverTypes[i] == "OpenGL") && !opengl)
+ {
+ kdDebug(1204) << "Screensaver is type OpenGL and OpenGL is forbidden" << endl;
+ mForbidden = true;
+ }
+ if (saverTypes[i] == "OpenGL")
+ {
+ mOpenGLVisual = true;
+ }
+ }
+ }
+
+ kdDebug(1204) << "mForbidden: " << (mForbidden ? "true" : "false") << endl;
+
+ if (config.hasActionGroup("Root"))
+ {
+ config.setActionGroup("Root");
+ mSaverExec = config.readPathEntry("Exec");
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Create a window to draw our screen saver on.
+//
+void LockProcess::createSaverWindow()
+{
+ Visual* visual = CopyFromParent;
+ XSetWindowAttributes attrs;
+ int flags = CWOverrideRedirect;
+#ifdef HAVE_GLXCHOOSEVISUAL
+ if( mOpenGLVisual )
+ {
+ static 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( x11Display(), x11Screen(), attribs[ i ] ))
+ {
+ visual = info->visual;
+ static Colormap colormap = 0;
+ if( colormap != 0 )
+ XFreeColormap( x11Display(), colormap );
+ colormap = XCreateColormap( x11Display(), RootWindow( x11Display(), x11Screen()), visual, AllocNone );
+ attrs.colormap = colormap;
+ flags |= CWColormap;
+ XFree( info );
+ break;
+ }
+ }
+ }
+#endif
+
+ attrs.override_redirect = 1;
+ hide();
+ Window w = XCreateWindow( x11Display(), RootWindow( x11Display(), x11Screen()),
+ x(), y(), width(), height(), 0, x11Depth(), InputOutput, visual, flags, &attrs );
+ create( w );
+
+ // Some xscreensaver hacks check for this property
+ const char *version = "KDE 2.0";
+ XChangeProperty (qt_xdisplay(), winId(),
+ gXA_SCREENSAVER_VERSION, XA_STRING, 8, PropModeReplace,
+ (unsigned char *) version, strlen(version));
+
+ XSetWindowAttributes attr;
+ attr.event_mask = KeyPressMask | ButtonPressMask | PointerMotionMask |
+ VisibilityChangeMask | ExposureMask;
+ XChangeWindowAttributes(qt_xdisplay(), winId(),
+ CWEventMask, &attr);
+
+ // erase();
+
+ // set NoBackground so that the saver can capture the current
+ // screen state if necessary
+ setBackgroundMode(QWidget::NoBackground);
+
+ setCursor( blankCursor );
+ setGeometry(0, 0, mRootWidth, mRootHeight);
+
+ kdDebug(1204) << "Saver window Id: " << winId() << endl;
+}
+
+//---------------------------------------------------------------------------
+//
+// Hide the screensaver window
+//
+void LockProcess::hideSaverWindow()
+{
+ hide();
+ lower();
+ removeVRoot(winId());
+ XDeleteProperty(qt_xdisplay(), winId(), gXA_SCREENSAVER_VERSION);
+ if ( gVRoot ) {
+ unsigned long vroot_data[1] = { gVRootData };
+ XChangeProperty(qt_xdisplay(), gVRoot, gXA_VROOT, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)vroot_data, 1);
+ gVRoot = 0;
+ }
+ XSync(qt_xdisplay(), False);
+}
+
+//---------------------------------------------------------------------------
+static int ignoreXError(Display *, XErrorEvent *)
+{
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+//
+// Save the current virtual root window
+//
+void LockProcess::saveVRoot()
+{
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+ Window root = RootWindowOfScreen(ScreenOfDisplay(qt_xdisplay(), qt_xscreen()));
+
+ gVRoot = 0;
+ gVRootData = 0;
+
+ int (*oldHandler)(Display *, XErrorEvent *);
+ oldHandler = XSetErrorHandler(ignoreXError);
+
+ if (XQueryTree(qt_xdisplay(), 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(qt_xdisplay(), 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);
+
+ unsigned long rw = RootWindowOfScreen(ScreenOfDisplay(qt_xdisplay(), qt_xscreen()));
+ unsigned long vroot_data[1] = { vr };
+
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+ Window top = win;
+ while (1) {
+ XQueryTree(qt_xdisplay(), top , &rootReturn, &parentReturn,
+ &children, &numChildren);
+ if (children)
+ XFree((char *)children);
+ if (parentReturn == rw) {
+ break;
+ } else
+ top = parentReturn;
+ }
+
+ XChangeProperty(qt_xdisplay(), top, gXA_VROOT, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)vroot_data, 1);
+}
+
+//---------------------------------------------------------------------------
+//
+// Remove the virtual root property
+//
+void LockProcess::removeVRoot(Window win)
+{
+ XDeleteProperty (qt_xdisplay(), win, gXA_VROOT);
+}
+
+//---------------------------------------------------------------------------
+//
+// Grab the keyboard. Returns true on success
+//
+bool LockProcess::grabKeyboard()
+{
+ int rv = XGrabKeyboard( qt_xdisplay(), 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( qt_xdisplay(), QApplication::desktop()->winId(),
+ True, GRABEVENTS, GrabModeAsync, GrabModeAsync, None,
+ blankCursor.handle(), CurrentTime );
+
+ return (rv == GrabSuccess);
+}
+
+//---------------------------------------------------------------------------
+//
+// Grab keyboard and mouse. Returns true on success.
+//
+bool LockProcess::grabInput()
+{
+ XSync(qt_xdisplay(), False);
+
+ if (!grabKeyboard())
+ {
+ sleep(1);
+ if (!grabKeyboard())
+ {
+ return false;
+ }
+ }
+
+ if (!grabMouse())
+ {
+ sleep(1);
+ if (!grabMouse())
+ {
+ XUngrabKeyboard(qt_xdisplay(), CurrentTime);
+ return false;
+ }
+ }
+
+ lockXF86();
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Release mouse an keyboard grab.
+//
+void LockProcess::ungrabInput()
+{
+ XUngrabKeyboard(qt_xdisplay(), CurrentTime);
+ XUngrabPointer(qt_xdisplay(), CurrentTime);
+ unlockXF86();
+}
+
+//---------------------------------------------------------------------------
+//
+// Start the screen saver.
+//
+bool LockProcess::startSaver()
+{
+ if (!child_saver && !grabInput())
+ {
+ kdWarning(1204) << "LockProcess::startSaver() grabInput() failed!!!!" << endl;
+ return false;
+ }
+ mBusy = false;
+
+ saveVRoot();
+
+ if (mParent) {
+ QSocketNotifier *notifier = new QSocketNotifier(mParent, QSocketNotifier::Read, this, "notifier");
+ connect(notifier, SIGNAL( activated (int)), SLOT( quitSaver()));
+ }
+ createSaverWindow();
+ move(0, 0);
+ show();
+ setCursor( blankCursor );
+
+ raise();
+ XSync(qt_xdisplay(), False);
+ setVRoot( winId(), winId() );
+ startHack();
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Stop the screen saver.
+//
+void LockProcess::stopSaver()
+{
+ kdDebug(1204) << "LockProcess: stopping saver" << endl;
+ resume( true );
+ stopHack();
+ hideSaverWindow();
+ mVisibility = false;
+ if (!child_saver) {
+ if (mLocked)
+ DM().setLock( false );
+ ungrabInput();
+ const char *out = "GOAWAY!";
+ for (QValueList<int>::ConstIterator it = child_sockets.begin(); it != child_sockets.end(); ++it)
+ write(*it, out, sizeof(out));
+ }
+}
+
+// private static
+QVariant LockProcess::getConf(void *ctx, const char *key, const QVariant &dflt)
+{
+ LockProcess *that = (LockProcess *)ctx;
+ QString fkey = QString::fromLatin1( key ) + '=';
+ for (QStringList::ConstIterator it = that->mPluginOptions.begin();
+ it != that->mPluginOptions.end(); ++it)
+ if ((*it).startsWith( fkey ))
+ return (*it).mid( fkey.length() );
+ return dflt;
+}
+
+void LockProcess::cantLock( const QString &txt)
+{
+ msgBox( QMessageBox::Critical, i18n("Will not lock the session, as unlocking would be impossible:\n") + txt );
+}
+
+#if 0 // placeholders for later
+i18n("Cannot start <i>kcheckpass</i>.");
+i18n("<i>kcheckpass</i> is unable to operate. Possibly it is not SetUID root.");
+#endif
+
+//---------------------------------------------------------------------------
+//
+// Make the screen saver password protected.
+//
+bool LockProcess::startLock()
+{
+ for (QStringList::ConstIterator it = mPlugins.begin(); it != mPlugins.end(); ++it) {
+ GreeterPluginHandle plugin;
+ QString path = KLibLoader::self()->findLibrary(
+ ((*it)[0] == '/' ? *it : "kgreet_" + *it ).latin1() );
+ if (path.isEmpty()) {
+ kdWarning(1204) << "GreeterPlugin " << *it << " does not exist" << endl;
+ continue;
+ }
+ if (!(plugin.library = KLibLoader::self()->library( path.latin1() ))) {
+ kdWarning(1204) << "Cannot load GreeterPlugin " << *it << " (" << path << ")" << endl;
+ continue;
+ }
+ if (!plugin.library->hasSymbol( "kgreeterplugin_info" )) {
+ kdWarning(1204) << "GreeterPlugin " << *it << " (" << path << ") is no valid greet widget plugin" << endl;
+ plugin.library->unload();
+ continue;
+ }
+ plugin.info = (kgreeterplugin_info*)plugin.library->symbol( "kgreeterplugin_info" );
+ if (plugin.info->method && !mMethod.isEmpty() && mMethod != plugin.info->method) {
+ kdDebug(1204) << "GreeterPlugin " << *it << " (" << path << ") serves " << plugin.info->method << ", not " << mMethod << endl;
+ plugin.library->unload();
+ continue;
+ }
+ if (!plugin.info->init( mMethod, getConf, this )) {
+ kdDebug(1204) << "GreeterPlugin " << *it << " (" << path << ") refuses to serve " << mMethod << endl;
+ plugin.library->unload();
+ continue;
+ }
+ kdDebug(1204) << "GreeterPlugin " << *it << " (" << plugin.info->method << ", " << plugin.info->name << ") loaded" << endl;
+ greetPlugin = plugin;
+ mLocked = true;
+ DM().setLock( true );
+ return true;
+ }
+ cantLock( i18n("No appropriate greeter plugin configured.") );
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+
+
+bool LockProcess::startHack()
+{
+ if (mSaverExec.isEmpty())
+ {
+ return false;
+ }
+
+ if (mHackProc.isRunning())
+ {
+ stopHack();
+ }
+
+ mHackProc.clearArguments();
+
+ QTextStream ts(&mSaverExec, IO_ReadOnly);
+ QString word;
+ ts >> word;
+ QString path = KStandardDirs::findExe(word);
+
+ if (!path.isEmpty())
+ {
+ mHackProc << path;
+
+ kdDebug(1204) << "Starting hack: " << path << endl;
+
+ while (!ts.atEnd())
+ {
+ ts >> word;
+ if (word == "%w")
+ {
+ word = word.setNum(winId());
+ }
+ mHackProc << word;
+ }
+
+ if (!mForbidden)
+ {
+
+ if (mHackProc.start() == true)
+ {
+#ifdef HAVE_SETPRIORITY
+ setpriority(PRIO_PROCESS, mHackProc.pid(), mPriority);
+#endif
+ //bitBlt(this, 0, 0, &mOriginal);
+ return true;
+ }
+ }
+ else
+ // we aren't allowed to start the specified screensaver either because it didn't run for some reason
+ // according to the kiosk restrictions forbid it
+ {
+ setBackgroundColor(black);
+ }
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+void LockProcess::stopHack()
+{
+ if (mHackProc.isRunning())
+ {
+ mHackProc.kill();
+ if (!mHackProc.wait(10))
+ {
+ mHackProc.kill(SIGKILL);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+void LockProcess::hackExited(KProcess *)
+{
+ // Hack exited while we're supposed to be saving the screen.
+ // Make sure the saver window is black.
+ setBackgroundColor(black);
+}
+
+void LockProcess::suspend()
+{
+ if(!mSuspended)
+ {
+ mHackProc.kill(SIGSTOP);
+ QApplication::syncX();
+ mSavedScreen = QPixmap::grabWindow( winId());
+ }
+ mSuspended = true;
+}
+
+void LockProcess::resume( bool force )
+{
+ if( !force && (!mDialogs.isEmpty() || !mVisibility ))
+ return; // no resuming with dialog visible or when not visible
+ if(mSuspended)
+ {
+ XForceScreenSaver(qt_xdisplay(), ScreenSaverReset );
+ bitBlt( this, 0, 0, &mSavedScreen );
+ QApplication::syncX();
+ mHackProc.kill(SIGCONT);
+ }
+ mSuspended = false;
+}
+
+//---------------------------------------------------------------------------
+//
+// Show the password dialog
+// This is called only in the master process
+//
+bool LockProcess::checkPass()
+{
+ if (mAutoLogout)
+ killTimer(mAutoLogoutTimerId);
+
+ PasswordDlg passDlg( this, &greetPlugin);
+
+ int ret = execDialog( &passDlg );
+
+ XWindowAttributes rootAttr;
+ XGetWindowAttributes(qt_xdisplay(), RootWindow(qt_xdisplay(),
+ qt_xscreen()), &rootAttr);
+ if(( rootAttr.your_event_mask & SubstructureNotifyMask ) == 0 )
+ {
+ kdWarning() << "ERROR: Something removed SubstructureNotifyMask from the root window!!!" << endl;
+ XSelectInput( qt_xdisplay(), qt_xrootwin(),
+ SubstructureNotifyMask | rootAttr.your_event_mask );
+ }
+
+ return ret == QDialog::Accepted;
+}
+
+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 = qt_xdisplay();
+ ev.xfocus.type = FocusIn;
+ ev.xfocus.window = window;
+ ev.xfocus.mode = NotifyNormal;
+ ev.xfocus.detail = NotifyAncestor;
+ XSendEvent( qt_xdisplay(), window, False, NoEventMask, &ev );
+}
+
+int LockProcess::execDialog( QDialog *dlg )
+{
+ dlg->adjustSize();
+
+ QRect rect = dlg->geometry();
+ rect.moveCenter(KGlobalSettings::desktopGeometry(QCursor::pos()).center());
+ dlg->move( rect.topLeft() );
+
+ if (mDialogs.isEmpty())
+ {
+ suspend();
+ XChangeActivePointerGrab( qt_xdisplay(), GRABEVENTS,
+ arrowCursor.handle(), CurrentTime);
+ }
+ mDialogs.prepend( dlg );
+ fakeFocusIn( dlg->winId());
+ int rt = dlg->exec();
+ mDialogs.remove( dlg );
+ if( mDialogs.isEmpty() ) {
+ XChangeActivePointerGrab( qt_xdisplay(), GRABEVENTS,
+ blankCursor.handle(), CurrentTime);
+ resume( false );
+ } else
+ fakeFocusIn( mDialogs.first()->winId());
+ return rt;
+}
+
+void LockProcess::preparePopup()
+{
+ QWidget *dlg = (QWidget *)sender();
+ mDialogs.prepend( dlg );
+ fakeFocusIn( dlg->winId() );
+}
+
+void LockProcess::cleanupPopup()
+{
+ QWidget *dlg = (QWidget *)sender();
+ mDialogs.remove( dlg );
+ fakeFocusIn( mDialogs.first()->winId() );
+}
+
+//---------------------------------------------------------------------------
+//
+// X11 Event.
+//
+bool LockProcess::x11Event(XEvent *event)
+{
+ switch (event->type)
+ {
+ case KeyPress:
+ case ButtonPress:
+ case MotionNotify:
+ if (mBusy || !mDialogs.isEmpty())
+ break;
+ mBusy = true;
+ if (!mLocked || checkPass())
+ {
+ stopSaver();
+ kapp->quit();
+ }
+ else if (mAutoLogout) // we need to restart the auto logout countdown
+ {
+ killTimer(mAutoLogoutTimerId);
+ mAutoLogoutTimerId = startTimer(mAutoLogoutTimeout);
+ }
+ mBusy = false;
+ return true;
+
+ case VisibilityNotify:
+ if( event->xvisibility.window == winId())
+ { // mVisibility == false means the screensaver is not visible at all
+ // e.g. when switched to text console
+ mVisibility = !(event->xvisibility.state == VisibilityFullyObscured);
+ if(!mVisibility)
+ mSuspendTimer.start(2000, true);
+ else
+ {
+ mSuspendTimer.stop();
+ resume( false );
+ }
+ if (event->xvisibility.state != VisibilityUnobscured)
+ stayOnTop();
+ }
+ break;
+
+ case ConfigureNotify: // from SubstructureNotifyMask on the root window
+ if(event->xconfigure.event == qt_xrootwin())
+ stayOnTop();
+ break;
+ case MapNotify: // from SubstructureNotifyMask on the root window
+ if( event->xmap.event == qt_xrootwin())
+ stayOnTop();
+ 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() && ( event->type == KeyPress || event->type == KeyRelease)
+ && event->xkey.window != mDialogs.first()->winId())
+ {
+ XEvent ev2 = *event;
+ ev2.xkey.window = ev2.xkey.subwindow = mDialogs.first()->winId();
+ qApp->x11ProcessEvent( &ev2 );
+ return true;
+ }
+
+ return false;
+}
+
+void LockProcess::stayOnTop()
+{
+ if(!mDialogs.isEmpty())
+ {
+ // 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
+ XRaiseWindow( qt_xdisplay(), mDialogs.first()->winId()); // raise topmost
+ // and stack others below it
+ Window* stack = new Window[ mDialogs.count() + 1 ];
+ int count = 0;
+ for( QValueList< QWidget* >::ConstIterator it = mDialogs.begin();
+ it != mDialogs.end();
+ ++it )
+ stack[ count++ ] = (*it)->winId();
+ stack[ count++ ] = winId();
+ XRestackWindows( x11Display(), stack, count );
+ delete[] stack;
+ }
+ else
+ XRaiseWindow(qt_xdisplay(), winId());
+}
+
+void LockProcess::checkDPMSActive()
+{
+#ifdef HAVE_DPMS
+ BOOL on;
+ CARD16 state;
+ DPMSInfo(qt_xdisplay(), &state, &on);
+ //kdDebug() << "checkDPMSActive " << on << " " << state << endl;
+ if (state == DPMSModeStandby || state == DPMSModeSuspend || state == DPMSModeOff)
+ {
+ suspend();
+ } else if ( mSuspended )
+ {
+ resume( true );
+ }
+#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 kdesktop_lock 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;
+ if( XF86MiscQueryVersion( qt_xdisplay(), &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( qt_xdisplay(), False ) != MiscExtGrabStateSuccess )
+ return;
+ // success
+ mRestoreXF86Lock = true;
+}
+
+void LockProcess::unlockXF86()
+{
+ if( can_do_xf86_lock != Yes )
+ return;
+ if( !mRestoreXF86Lock )
+ return;
+ XF86MiscSetGrabKeysState( qt_xdisplay(), True );
+ mRestoreXF86Lock = false;
+}
+#else
+void LockProcess::lockXF86()
+{
+}
+
+void LockProcess::unlockXF86()
+{
+}
+#endif
+
+void LockProcess::msgBox( QMessageBox::Icon type, const QString &txt )
+{
+ QDialog box( 0, "messagebox", true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( &box );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QLabel *label1 = new QLabel( winFrame );
+ label1->setPixmap( QMessageBox::standardIcon( type ) );
+ QLabel *label2 = new QLabel( txt, winFrame );
+ KPushButton *button = new KPushButton( KStdGuiItem::ok(), winFrame );
+ button->setDefault( true );
+ button->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+ connect( button, SIGNAL( clicked() ), &box, SLOT( accept() ) );
+
+ QVBoxLayout *vbox = new QVBoxLayout( &box );
+ vbox->addWidget( winFrame );
+ QGridLayout *grid = new QGridLayout( winFrame, 2, 2, 10 );
+ grid->addWidget( label1, 0, 0, Qt::AlignCenter );
+ grid->addWidget( label2, 0, 1, Qt::AlignCenter );
+ grid->addMultiCellWidget( button, 1,1, 0,1, Qt::AlignCenter );
+
+ execDialog( &box );
+}
+
+#include "lockprocess.moc"
diff --git a/kdesktop/lock/lockprocess.h b/kdesktop/lock/lockprocess.h
new file mode 100644
index 000000000..d7043e64d
--- /dev/null
+++ b/kdesktop/lock/lockprocess.h
@@ -0,0 +1,131 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <[email protected]>
+// Copyright (c) 2003 Oswald Buddenhagen <[email protected]>
+//
+
+#ifndef __LOCKENG_H__
+#define __LOCKENG_H__
+
+#include <kgreeterplugin.h>
+
+#include <kprocess.h>
+#include <kpixmap.h>
+
+#include <qwidget.h>
+#include <qtimer.h>
+#include <qvaluestack.h>
+#include <qmessagebox.h>
+#include <qpixmap.h>
+
+#include <X11/Xlib.h>
+
+class KLibrary;
+
+struct GreeterPluginHandle {
+ KLibrary *library;
+ kgreeterplugin_info *info;
+};
+
+//===========================================================================
+//
+// Screen saver handling process. Handles screensaver window,
+// starting screensaver hacks, and password entry.
+//
+class LockProcess
+ : public QWidget
+{
+ Q_OBJECT
+public:
+ LockProcess(bool child_saver = false, bool useBlankOnly = false);
+ ~LockProcess();
+
+ bool lock();
+
+ bool defaultSave();
+
+ bool dontLock();
+
+ void setChildren(QValueList<int> children) { child_sockets = children; }
+ void setParent(int fd) { mParent = fd; }
+
+ void msgBox( QMessageBox::Icon type, const QString &txt );
+ int execDialog( QDialog* dlg );
+
+public slots:
+ void quitSaver();
+ void preparePopup();
+ void cleanupPopup();
+
+protected:
+ virtual bool x11Event(XEvent *);
+ virtual void timerEvent(QTimerEvent *);
+
+private slots:
+ void hackExited(KProcess *);
+ void signalPipeSignal();
+ bool startLock();
+ void suspend();
+ void checkDPMSActive();
+ void slotDeadTimePassed();
+
+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();
+ void setupSignals();
+ bool checkPass();
+ void stayOnTop();
+ void lockXF86();
+ void unlockXF86();
+ void resume( bool force );
+ static QVariant getConf(void *ctx, const char *key, const QVariant &dflt);
+
+ bool mLocked;
+ int mLockGrace;
+ int mPriority;
+ bool mBusy;
+ KProcess mHackProc;
+ int mRootWidth;
+ int mRootHeight;
+ QString mSaverExec;
+ QString mSaver;
+ bool mOpenGLVisual;
+ bool child_saver;
+ QValueList<int> child_sockets;
+ int mParent;
+ bool mUseBlankOnly;
+ bool mSuspended;
+ QTimer mSuspendTimer;
+ bool mVisibility;
+ bool mDPMSDepend;
+ QTimer mCheckDPMS;
+ QValueStack< QWidget* > mDialogs;
+ bool mRestoreXF86Lock;
+ bool mForbidden;
+ QStringList mPlugins, mPluginOptions;
+ QString mMethod;
+ GreeterPluginHandle greetPlugin;
+ QPixmap mSavedScreen;
+ int mAutoLogoutTimerId;
+ int mAutoLogoutTimeout;
+ bool mAutoLogout;
+};
+
+#endif
+
diff --git a/kdesktop/lock/main.cc b/kdesktop/lock/main.cc
new file mode 100644
index 000000000..b55e67ea6
--- /dev/null
+++ b/kdesktop/lock/main.cc
@@ -0,0 +1,174 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure
+ Copyright (c) 2003 Oswald Buddenhagen <[email protected]>
+
+ 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 "kdesktopsettings.h"
+
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <dcopref.h>
+
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <fixx11h.h>
+
+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 );
+}
+
+
+static KCmdLineOptions options[] =
+{
+ { "forcelock", I18N_NOOP("Force session locking"), 0 },
+ { "dontlock", I18N_NOOP("Only start screensaver"), 0 },
+ { "blank", I18N_NOOP("Only use the blank screensaver"), 0 },
+ KCmdLineLastOption
+};
+
+// -----------------------------------------------------------------------------
+
+int main( int argc, char **argv )
+{
+ KLocale::setMainCatalogue("kdesktop");
+
+ KCmdLineArgs::init( argc, argv, "kdesktop_lock", I18N_NOOP("KDesktop Locker"), I18N_NOOP("Session Locker for KDesktop"), "2.0" );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ putenv(strdup("SESSION_MANAGER="));
+
+ KApplication::disableAutoDcopRegistration(); // not needed
+
+ int kdesktop_screen_number = 0;
+ int starting_screen = 0;
+
+ bool child = false;
+ int parent_connection = 0; // socket to the parent saver
+ QValueList<int> child_sockets;
+
+ if (KGlobalSettings::isMultiHead())
+ {
+ Display *dpy = XOpenDisplay(NULL);
+ if (! dpy) {
+ fprintf(stderr,
+ "%s: FATAL ERROR: couldn't 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;
+ QCString display_name = XDisplayString(dpy);
+ XCloseDisplay(dpy);
+ kdDebug() << "screen " << number_of_screens << " " << kdesktop_screen_number << " " << display_name << " " << starting_screen << endl;
+ dpy = 0;
+
+ if ((pos = display_name.findRev('.')) != -1)
+ display_name.remove(pos, 10);
+
+ QCString 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);
+ kdDebug() << "env " << env << endl;
+
+ if (putenv(strdup(env.data()))) {
+ fprintf(stderr,
+ "%s: WARNING: unable to set DISPLAY environment variable\n",
+ argv[0]);
+ perror("putenv()");
+ }
+ }
+ }
+
+ MyApp app;
+ kdDebug() << "app " << kdesktop_screen_number << " " << starting_screen << " " << child << " " << child_sockets.count() << " " << parent_connection << endl;
+ app.disableSessionManagement();
+ KGlobal::locale()->insertCatalogue("libdmctl");
+
+ // we need to read from the right rc file - possibly taking screen number in account
+ KDesktopSettings::instance("kdesktoprc");
+
+ 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();
+ sig = true;
+ }
+ else if( child || args->isSet( "dontlock" ))
+ rt = process.dontLock();
+ else
+ rt = process.defaultSave();
+ if (!rt)
+ return 1;
+
+ if( sig )
+ {
+ DCOPRef ref( "kdesktop", "KScreensaverIface");
+ ref.send( "saverLockReady" );
+ }
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/kdesktop/lock/main.h b/kdesktop/lock/main.h
new file mode 100644
index 000000000..c8e0e05a4
--- /dev/null
+++ b/kdesktop/lock/main.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ Copyright (c) 2003 Oswald Buddenhagen <[email protected]>
+
+ 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 <kapplication.h>
+
+#include <time.h>
+
+class MyApp : public KApplication {
+ Q_OBJECT
+public:
+ MyApp() : KApplication(), lastTick( 0 ) {}
+protected:
+ bool x11EventFilter( XEvent * );
+signals:
+ void activity();
+private:
+ time_t lastTick;
+};
+
+#endif