mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-24 10:52:51 +00:00
1107 lines
30 KiB
C++
1107 lines
30 KiB
C++
/*
|
|
|
|
Greeter widget for kdm
|
|
|
|
Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
|
|
Copyright (C) 2000-2004 Oswald Buddenhagen <ossi@kde.org>
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
#include "kgreeter.h"
|
|
#include "kconsole.h"
|
|
#include "kdmconfig.h"
|
|
#include "kdmclock.h"
|
|
#include "kdm_greet.h"
|
|
#include "themer/kdmthemer.h"
|
|
#include "themer/kdmitem.h"
|
|
#include "themer/kdmlabel.h"
|
|
|
|
#include <KColorScheme>
|
|
#include <KConfigGroup>
|
|
#include <klocale.h>
|
|
#include <kseparator.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kstringhandler.h>
|
|
|
|
#include <QAction>
|
|
#include <QBuffer>
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QImageReader>
|
|
#include <QKeyEvent>
|
|
#include <QLabel>
|
|
#include <QListWidget>
|
|
#include <QListWidgetItem>
|
|
#include <QMenu>
|
|
#include <QMovie>
|
|
#include <QPainter>
|
|
#include <QPushButton>
|
|
#include <QShortcut>
|
|
#include <QStyle>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <fixx11h.h>
|
|
|
|
class UserListView : public QListWidget {
|
|
public:
|
|
UserListView(QWidget *parent = 0)
|
|
: QListWidget(parent)
|
|
, cachedSizeHint(-1, 0)
|
|
{
|
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Ignored);
|
|
setUniformItemSizes(true);
|
|
setVerticalScrollMode(ScrollPerPixel);
|
|
setIconSize(QSize(48, 48));
|
|
setAlternatingRowColors(true);
|
|
}
|
|
|
|
mutable QSize cachedSizeHint;
|
|
|
|
protected:
|
|
virtual QSize sizeHint() const
|
|
{
|
|
if (!cachedSizeHint.isValid()) {
|
|
ensurePolished();
|
|
QStyleOptionViewItem vo(viewOptions());
|
|
QAbstractListModel *md(static_cast<QAbstractListModel *>(model()));
|
|
uint maxw = 0, h = 0;
|
|
for (int i = 0, rc = md->rowCount(); i < rc; i++) {
|
|
QSize sh = itemDelegate()->sizeHint(vo, md->index(i));
|
|
uint thisw = sh.width();
|
|
if (thisw > maxw)
|
|
maxw = thisw;
|
|
h += sh.height();
|
|
}
|
|
cachedSizeHint.setWidth(
|
|
style()->pixelMetric(QStyle::PM_ScrollBarExtent) +
|
|
(frameWidth() +
|
|
(style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents) ?
|
|
style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0)) * 2 +
|
|
maxw);
|
|
cachedSizeHint.setHeight(frameWidth() * 2 + h);
|
|
}
|
|
return cachedSizeHint;
|
|
}
|
|
|
|
virtual void keyPressEvent(QKeyEvent *event)
|
|
{
|
|
switch (event->key()) {
|
|
case Qt::Key_Enter:
|
|
case Qt::Key_Return:
|
|
if (currentItem())
|
|
emit itemDoubleClicked(currentItem());
|
|
event->accept();
|
|
break;
|
|
case Qt::Key_Space:
|
|
if (currentItem())
|
|
emit itemClicked(currentItem());
|
|
event->accept();
|
|
break;
|
|
default:
|
|
QListWidget::keyPressEvent(event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
virtual void mousePressEvent(QMouseEvent *event)
|
|
{
|
|
m_suppressClick = false;
|
|
QListWidget::mousePressEvent(event);
|
|
}
|
|
|
|
virtual void mouseReleaseEvent(QMouseEvent *event)
|
|
{
|
|
if (m_suppressClick)
|
|
m_suppressClick = false;
|
|
else
|
|
QListWidget::mouseReleaseEvent(event);
|
|
}
|
|
|
|
virtual void mouseDoubleClickEvent(QMouseEvent *event)
|
|
{
|
|
m_suppressClick = true;
|
|
QListWidget::mouseDoubleClickEvent(event);
|
|
}
|
|
|
|
private:
|
|
bool m_suppressClick;
|
|
};
|
|
|
|
class UserListViewItem : public QListWidgetItem {
|
|
public:
|
|
UserListViewItem(UserListView *parent, const QString &text,
|
|
const QPixmap &pixmap, const QString &username)
|
|
: QListWidgetItem(parent)
|
|
, login(username)
|
|
{
|
|
setIcon(pixmap);
|
|
setText(text);
|
|
parent->cachedSizeHint.setWidth(-1);
|
|
}
|
|
|
|
QString login;
|
|
};
|
|
|
|
|
|
int KGreeter::curPlugin = -1;
|
|
PluginList KGreeter::pluginList;
|
|
|
|
KGreeter::KGreeter(bool framed)
|
|
: inherited(framed)
|
|
, dName(dname)
|
|
, userView(0)
|
|
, userList(0)
|
|
, nNormals(0)
|
|
, nSpecials(0)
|
|
, curPrev(0)
|
|
, prevValid(true)
|
|
, needLoad(false)
|
|
{
|
|
stsGroup = new KConfigGroup(KSharedConfig::openConfig(_stsFile),
|
|
"PrevUser");
|
|
|
|
if (_userList) {
|
|
userView = new UserListView(this);
|
|
connect(userView, SIGNAL(itemClicked(QListWidgetItem*)),
|
|
SLOT(slotUserClicked(QListWidgetItem*)));
|
|
connect(userView, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
|
|
SLOT(accept()));
|
|
}
|
|
if (_userCompletion)
|
|
userList = new QStringList;
|
|
if (userView || userList)
|
|
insertUsers();
|
|
|
|
sessMenu = new QMenu(this);
|
|
connect(sessMenu, SIGNAL(triggered(QAction*)),
|
|
SLOT(slotSessionSelected()));
|
|
|
|
sessGroup = new QActionGroup(this);
|
|
insertSessions();
|
|
|
|
if (curPlugin < 0) {
|
|
curPlugin = 0;
|
|
pluginList = KGVerify::init(_pluginsLogin);
|
|
}
|
|
}
|
|
|
|
KGreeter::~KGreeter()
|
|
{
|
|
hide();
|
|
delete userList;
|
|
delete verify;
|
|
delete stsGroup;
|
|
}
|
|
|
|
#define FILE_LIMIT_ICON 20
|
|
#define FILE_LIMIT_IMAGE 200
|
|
#define PIXEL_LIMIT_ICON 100
|
|
#define PIXEL_LIMIT_IMAGE 300
|
|
|
|
// replace this with a simple !access(..., X_OK) once we run with non-root real uid
|
|
static bool
|
|
dirAccessible(const char *dir)
|
|
{
|
|
struct stat st;
|
|
|
|
if (stat(dir, &st))
|
|
return false;
|
|
return (st.st_mode & S_IXOTH) != 0;
|
|
}
|
|
|
|
static bool
|
|
loadFace(QByteArray &fn, QImage &p, const QByteArray &pp, bool complain = false)
|
|
{
|
|
int fd, ico;
|
|
if ((fd = open(fn.data(), O_RDONLY | O_NONBLOCK)) < 0) {
|
|
if (errno != ENOENT) {
|
|
if (pp.isEmpty() || dirAccessible(pp.data()))
|
|
(complain ? logError : logInfo)
|
|
("Cannot load %s: %m\n", fn.data());
|
|
return false;
|
|
}
|
|
fn.chop(5);
|
|
if ((fd = open(fn.data(), O_RDONLY | O_NONBLOCK)) < 0) {
|
|
if ((complain || errno != ENOENT) &&
|
|
(pp.isEmpty() || dirAccessible(pp.data())))
|
|
(complain ? logError : logInfo)
|
|
("Cannot load %s: %m\n", fn.data());
|
|
return false;
|
|
}
|
|
ico = 0;
|
|
} else {
|
|
ico = 1;
|
|
}
|
|
QFile f;
|
|
f.open(fd, QFile::ReadOnly);
|
|
int fs = f.size();
|
|
if (fs > (ico ? FILE_LIMIT_ICON : FILE_LIMIT_IMAGE) * 1000) {
|
|
logWarn("%s exceeds file size limit (%dkB)\n",
|
|
fn.data(), ico ? FILE_LIMIT_ICON : FILE_LIMIT_IMAGE);
|
|
return false;
|
|
}
|
|
QByteArray fc = f.read(fs);
|
|
::close(fd);
|
|
QBuffer buf(&fc);
|
|
buf.open(QBuffer::ReadOnly);
|
|
QImageReader ir(&buf);
|
|
QSize sz = ir.size();
|
|
int lim = ico ? PIXEL_LIMIT_ICON : PIXEL_LIMIT_IMAGE;
|
|
if (sz.width() > lim || sz.height() > lim) {
|
|
logWarn("%s exceeds image dimension limit (%dx%d)\n",
|
|
fn.data(), lim, lim);
|
|
return false;
|
|
}
|
|
sz.scale(48, 48, Qt::KeepAspectRatio);
|
|
ir.setScaledSize(sz);
|
|
p = ir.read();
|
|
if (p.isNull()) {
|
|
logInfo("%s is no valid image\n", fn.data());
|
|
return false;
|
|
}
|
|
if (p.width() < 48) {
|
|
QImage np(48, p.height(), QImage::Format_ARGB32);
|
|
np.fill(0);
|
|
QPainter pnt(&np);
|
|
pnt.drawImage((48 - p.width()) / 2, 0, p);
|
|
p = np;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
KGreeter::insertUser(const QImage &default_pix,
|
|
const QString &username, struct passwd *ps)
|
|
{
|
|
if (userList)
|
|
userList->append(username);
|
|
if (!userView)
|
|
return;
|
|
|
|
int dp = 0, nd = 0;
|
|
if (_faceSource == FACE_USER_ONLY ||
|
|
_faceSource == FACE_PREFER_USER)
|
|
dp = 1;
|
|
if (_faceSource != FACE_USER_ONLY &&
|
|
_faceSource != FACE_ADMIN_ONLY)
|
|
nd = 1;
|
|
QImage p;
|
|
do {
|
|
dp ^= 1;
|
|
QByteArray pp, fn;
|
|
if (!dp) {
|
|
fn = pp = QByteArray(ps->pw_dir);
|
|
fn += '/';
|
|
} else {
|
|
fn = QFile::encodeName(_faceDir);
|
|
fn += '/';
|
|
fn += ps->pw_name;
|
|
}
|
|
fn += ".face.icon";
|
|
if (loadFace(fn, p, pp))
|
|
goto gotit;
|
|
} while (--nd >= 0);
|
|
p = default_pix;
|
|
gotit:
|
|
QString realname = KStringHandler::from8Bit(ps->pw_gecos);
|
|
realname.truncate(realname.indexOf(',') & (~0U >> 1));
|
|
if (realname.isEmpty() || realname == username) {
|
|
new UserListViewItem(userView, username, QPixmap::fromImage(p), username);
|
|
} else {
|
|
realname.append("\n").append(username);
|
|
new UserListViewItem(userView, realname, QPixmap::fromImage(p), username);
|
|
}
|
|
}
|
|
|
|
class UserList {
|
|
public:
|
|
UserList(char **in);
|
|
bool hasUser(const char *str) const { return users.contains(str); }
|
|
bool hasGroup(gid_t gid) const { return groups.contains(gid); }
|
|
bool hasGroups() const { return !groups.isEmpty(); }
|
|
|
|
private:
|
|
QSet<gid_t> groups;
|
|
QSet<QByteArray> users;
|
|
};
|
|
|
|
UserList::UserList(char **in)
|
|
{
|
|
struct group *grp;
|
|
|
|
for (; *in; in++)
|
|
if (**in == '@') {
|
|
if ((grp = getgrnam(*in + 1))) {
|
|
for (; *grp->gr_mem; grp->gr_mem++)
|
|
users.insert(*grp->gr_mem);
|
|
groups.insert(grp->gr_gid);
|
|
}
|
|
} else {
|
|
users.insert(*in);
|
|
}
|
|
}
|
|
|
|
void
|
|
KGreeter::insertUsers()
|
|
{
|
|
struct passwd *ps;
|
|
|
|
if (!getuid()) {
|
|
if (!(ps = getpwnam("nobody")))
|
|
return;
|
|
if (setegid(ps->pw_gid))
|
|
return;
|
|
if (seteuid(ps->pw_uid)) {
|
|
setegid(0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
QImage default_pix;
|
|
if (userView) {
|
|
QByteArray fn = QFile::encodeName(_faceDir) + "/.default.face.icon";
|
|
if (!loadFace(fn, default_pix, QByteArray(), true)) {
|
|
default_pix = QImage(48, 48, QImage::Format_ARGB32);
|
|
default_pix.fill(0);
|
|
}
|
|
}
|
|
if (_showUsers == SHOW_ALL) {
|
|
UserList noUsers(_noUsers);
|
|
QSet<QString> dupes;
|
|
for (setpwent(); (ps = getpwent()) != 0;) {
|
|
if (*ps->pw_dir && *ps->pw_shell &&
|
|
(ps->pw_uid >= (unsigned)_lowUserId ||
|
|
(!ps->pw_uid && _showRoot)) &&
|
|
ps->pw_uid <= (unsigned)_highUserId &&
|
|
!noUsers.hasUser(ps->pw_name) &&
|
|
!noUsers.hasGroup(ps->pw_gid))
|
|
{
|
|
QString username(QFile::decodeName(ps->pw_name));
|
|
if (!dupes.contains(username)) {
|
|
dupes.insert(username);
|
|
insertUser(default_pix, username, ps);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
UserList users(_users);
|
|
if (users.hasGroups()) {
|
|
QSet<QString> dupes;
|
|
for (setpwent(); (ps = getpwent()) != 0;) {
|
|
if (*ps->pw_dir && *ps->pw_shell &&
|
|
(ps->pw_uid >= (unsigned)_lowUserId ||
|
|
(!ps->pw_uid && _showRoot)) &&
|
|
ps->pw_uid <= (unsigned)_highUserId &&
|
|
(users.hasUser(ps->pw_name) ||
|
|
users.hasGroup(ps->pw_gid)))
|
|
{
|
|
QString username(QFile::decodeName(ps->pw_name));
|
|
if (!dupes.contains(username)) {
|
|
dupes.insert(username);
|
|
insertUser(default_pix, username, ps);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (int i = 0; _users[i]; i++)
|
|
if ((ps = getpwnam(_users[i])) && (ps->pw_uid || _showRoot))
|
|
insertUser(default_pix, QFile::decodeName(_users[i]), ps);
|
|
}
|
|
}
|
|
endpwent();
|
|
endgrent();
|
|
if (_sortUsers) {
|
|
if (userView)
|
|
userView->sortItems();
|
|
if (userList)
|
|
userList->sort();
|
|
}
|
|
|
|
if (!getuid()) {
|
|
seteuid(0);
|
|
setegid(0);
|
|
}
|
|
}
|
|
|
|
void
|
|
KGreeter::putSession(const QString &type, const QString &name, bool hid, const char *exe)
|
|
{
|
|
int prio = exe ? (!strcmp(exe, "default") ? 0 :
|
|
!strcmp(exe, "custom") ? 1 :
|
|
!strcmp(exe, "failsafe") ? 3 : 2) : 2;
|
|
for (int i = 0; i < sessionTypes.size(); i++)
|
|
if (sessionTypes[i].type == type) {
|
|
sessionTypes[i].prio = prio;
|
|
return;
|
|
}
|
|
sessionTypes.append(SessType(name, type, hid, prio));
|
|
}
|
|
|
|
void
|
|
KGreeter::insertSessions()
|
|
{
|
|
for (char **dit = _sessionsDirs; *dit; ++dit)
|
|
foreach (QString ent, QDir(*dit).entryList())
|
|
if (ent.endsWith(".desktop")) {
|
|
KConfigGroup dsk(
|
|
KSharedConfig::openConfig(
|
|
QString(*dit).append('/').append(ent)),
|
|
"Desktop Entry");
|
|
putSession(ent.left(ent.length() - 8),
|
|
dsk.readEntry("Name"),
|
|
(dsk.readEntry("Hidden", false) ||
|
|
(dsk.hasKey("TryExec") &&
|
|
KStandardDirs::findExe(
|
|
dsk.readEntry("TryExec")).isEmpty())),
|
|
dsk.readEntry("Exec").toLatin1());
|
|
}
|
|
putSession("default", i18nc("@item:inlistbox session type", "Default"), false, "default");
|
|
putSession("custom", i18nc("@item:inlistbox session type", "Custom"), false, "custom");
|
|
putSession("failsafe", i18nc("@item:inlistbox session type", "Failsafe"), false, "failsafe");
|
|
qSort(sessionTypes);
|
|
for (int i = 0; i < sessionTypes.size() && !sessionTypes[i].hid; i++) {
|
|
sessionTypes[i].action = sessGroup->addAction(sessionTypes[i].name);
|
|
sessionTypes[i].action->setData(i);
|
|
sessionTypes[i].action->setCheckable(true);
|
|
switch (sessionTypes[i].prio) {
|
|
case 0: case 1: nSpecials++; break;
|
|
case 2: nNormals++; break;
|
|
}
|
|
}
|
|
sessMenu->addActions(sessGroup->actions());
|
|
}
|
|
|
|
void
|
|
KGreeter::slotUserEntered()
|
|
{
|
|
struct passwd *pw;
|
|
|
|
if (userView) {
|
|
if ((pw = getpwnam(curUser.toLocal8Bit().data()))) {
|
|
QString theUser = QString::fromLocal8Bit(pw->pw_name);
|
|
for (int i = 0, rc = userView->model()->rowCount(); i < rc; i++) {
|
|
UserListViewItem *item =
|
|
static_cast<UserListViewItem *>(userView->item(i));
|
|
if (item->login == theUser) {
|
|
userView->setCurrentItem(item);
|
|
goto oke;
|
|
}
|
|
}
|
|
}
|
|
userView->clearSelection();
|
|
}
|
|
oke:
|
|
if (isVisible())
|
|
slotLoadPrevWM();
|
|
else
|
|
QTimer::singleShot(0, this, SLOT(slotLoadPrevWM()));
|
|
}
|
|
|
|
void
|
|
KGreeter::slotUserClicked(QListWidgetItem *item)
|
|
{
|
|
if (item) {
|
|
curUser = ((UserListViewItem *)item)->login;
|
|
verify->setUser(curUser);
|
|
slotLoadPrevWM();
|
|
}
|
|
}
|
|
|
|
void
|
|
KGreeter::slotSessionSelected()
|
|
{
|
|
verify->gplugChanged();
|
|
}
|
|
|
|
void
|
|
KGreeter::reject()
|
|
{
|
|
verify->reject();
|
|
}
|
|
|
|
void
|
|
KGreeter::accept()
|
|
{
|
|
verify->accept();
|
|
}
|
|
|
|
void // private
|
|
KGreeter::setPrevWM(QAction *wm)
|
|
{
|
|
if (curPrev != wm) {
|
|
if (curPrev)
|
|
curPrev->setText(sessionTypes[curPrev->data().toInt()].name);
|
|
if (wm)
|
|
wm->setText(i18nc("@item:inmenu session type",
|
|
"%1 (previous)",
|
|
sessionTypes[wm->data().toInt()].name));
|
|
curPrev = wm;
|
|
}
|
|
}
|
|
|
|
void
|
|
KGreeter::slotLoadPrevWM()
|
|
{
|
|
int len, i, b;
|
|
unsigned long crc, by;
|
|
QByteArray name;
|
|
char *sess;
|
|
|
|
// XXX this should actually check for !CoreBusy - would it be safe?
|
|
if (verify->coreState != KGVerify::CoreIdle) {
|
|
needLoad = true;
|
|
return;
|
|
}
|
|
needLoad = false;
|
|
|
|
prevValid = true;
|
|
name = curUser.toLocal8Bit();
|
|
gSendInt(G_ReadDmrc);
|
|
gSendStr(name.data());
|
|
gRecvInt(); // ignore status code ...
|
|
if ((len = name.length())) {
|
|
gSendInt(G_GetDmrc);
|
|
gSendStr("Session");
|
|
sess = gRecvStr();
|
|
if (!sess) { /* no such user */
|
|
if (!userView && !userList) { // don't fake if user list shown
|
|
prevValid = false;
|
|
/* simple crc32 */
|
|
for (crc = _forgingSeed, i = 0; i < len; i++) {
|
|
by = (crc & 255) ^ name[i];
|
|
for (b = 0; b < 8; b++)
|
|
by = (by >> 1) ^ (-(by & 1) & 0xedb88320);
|
|
crc = (crc >> 8) ^ by;
|
|
}
|
|
/* forge a session with this hash - default & custom more probable */
|
|
/* XXX - this should do a statistical analysis of the real users */
|
|
#if 1
|
|
setPrevWM(sessionTypes[crc % (nSpecials * 2 + nNormals) % (nSpecials + nNormals)].action);
|
|
#else
|
|
i = crc % (nSpecials * 2 + nNormals);
|
|
if (i < nNormals)
|
|
setPrevWM(sessionTypes[i + nSpecials].action);
|
|
else
|
|
setPrevWM(sessionTypes[(i - nNormals) / 2].action);
|
|
#endif
|
|
return;
|
|
}
|
|
} else {
|
|
for (int i = 0; i < sessionTypes.count() && !sessionTypes[i].hid; i++)
|
|
if (sessionTypes[i].type == sess) {
|
|
free(sess);
|
|
setPrevWM(sessionTypes[i].action);
|
|
return;
|
|
}
|
|
if (!sessGroup->checkedAction())
|
|
KFMsgBox::box(this, sorrybox,
|
|
i18n("Your saved session type '%1' is not valid any more.\n"
|
|
"Please select a new one, otherwise 'default' will be used.", sess));
|
|
free(sess);
|
|
prevValid = false;
|
|
}
|
|
}
|
|
setPrevWM(0);
|
|
}
|
|
|
|
void // protected
|
|
KGreeter::pluginSetup()
|
|
{
|
|
int field = 0;
|
|
QString ent, pn(verify->pluginName()), dn(dName + '_' + pn);
|
|
|
|
if (_preselUser != PRESEL_PREV)
|
|
stsGroup->deleteEntry(verify->entitiesLocal() ? dName : dn, 0);
|
|
if (_preselUser != PRESEL_NONE && verify->entityPresettable()) {
|
|
if (verify->entitiesLocal())
|
|
ent = _preselUser == PRESEL_PREV ?
|
|
stsGroup->readEntry(dName, QString()) : _defaultUser;
|
|
else
|
|
ent = _preselUser == PRESEL_PREV ?
|
|
stsGroup->readEntry(dn, QString()) :
|
|
verify->getConf(0, (pn + ".DefaultEntity").toLatin1(), QVariant()).toString();
|
|
field = verify->entitiesFielded() ?
|
|
verify->getConf(0, (pn + ".FocusField").toLatin1(), QVariant(0)).toInt() :
|
|
_focusPasswd;
|
|
}
|
|
verify->presetEntity(ent, field);
|
|
if (userList)
|
|
verify->loadUsers(*userList);
|
|
}
|
|
|
|
void
|
|
KGreeter::verifyPluginChanged(int id)
|
|
{
|
|
curPlugin = id;
|
|
pluginSetup();
|
|
}
|
|
|
|
void
|
|
KGreeter::verifyClear()
|
|
{
|
|
curUser.clear();
|
|
slotUserEntered();
|
|
if (QAction *curSel = sessGroup->checkedAction())
|
|
curSel->setChecked(false);
|
|
}
|
|
|
|
void
|
|
KGreeter::verifyOk()
|
|
{
|
|
if (_preselUser == PRESEL_PREV && verify->entityPresettable())
|
|
stsGroup->writeEntry(verify->entitiesLocal() ?
|
|
dName :
|
|
dName + '_' + verify->pluginName(),
|
|
verify->getEntity());
|
|
if (QAction *curSel = sessGroup->checkedAction()) {
|
|
gSendInt(G_PutDmrc);
|
|
gSendStr("Session");
|
|
gSendStr(sessionTypes[curSel->data().toInt()].type.toUtf8());
|
|
} else if (!prevValid) {
|
|
gSendInt(G_PutDmrc);
|
|
gSendStr("Session");
|
|
gSendStr("default");
|
|
}
|
|
done(ex_login);
|
|
}
|
|
|
|
void
|
|
KGreeter::verifyFailed()
|
|
{
|
|
if (userView)
|
|
userView->setEnabled(false);
|
|
if (needLoad)
|
|
slotLoadPrevWM();
|
|
}
|
|
|
|
void
|
|
KGreeter::verifyRetry()
|
|
{
|
|
if (userView)
|
|
userView->setEnabled(true);
|
|
}
|
|
|
|
void
|
|
KGreeter::verifySetUser(const QString &user)
|
|
{
|
|
curUser = user;
|
|
slotUserEntered();
|
|
}
|
|
|
|
|
|
KStdGreeter::KStdGreeter()
|
|
: KGreeter()
|
|
, clock(0)
|
|
, pixLabel(0)
|
|
{
|
|
QBoxLayout *main_box;
|
|
#ifdef WITH_KDM_XCONSOLE
|
|
if (consoleView) {
|
|
QBoxLayout *ex_box = new QVBoxLayout(this);
|
|
main_box = new QHBoxLayout();
|
|
ex_box->addLayout(main_box);
|
|
ex_box->addWidget(consoleView);
|
|
} else
|
|
#endif
|
|
{
|
|
main_box = new QHBoxLayout(this);
|
|
}
|
|
int rs = layout()->spacing();
|
|
main_box->setSpacing(layout()->margin());
|
|
|
|
if (userView)
|
|
main_box->addWidget(userView);
|
|
|
|
QBoxLayout *inner_box = new QVBoxLayout();
|
|
main_box->addLayout(inner_box);
|
|
inner_box->setSpacing(rs);
|
|
|
|
if (!_authorized && _authComplain) {
|
|
QLabel *complainLabel = new QLabel(
|
|
i18n("Warning: this is an unsecured session"), this);
|
|
complainLabel->setToolTip(
|
|
i18n("This display requires no X authorization.\n"
|
|
"This means that anybody can connect to it,\n"
|
|
"open windows on it or intercept your input."));
|
|
complainLabel->setAlignment(Qt::AlignCenter);
|
|
complainLabel->setFont(*_failFont);
|
|
QPalette p;
|
|
p.setBrush(QPalette::WindowText,
|
|
KColorScheme(QPalette::Active, KColorScheme::Window)
|
|
.foreground(KColorScheme::NegativeText));
|
|
complainLabel->setPalette(p);
|
|
inner_box->addWidget(complainLabel);
|
|
}
|
|
if (!_greetString.isEmpty()) {
|
|
QLabel *welcomeLabel = new QLabel(_greetString, this);
|
|
welcomeLabel->setAlignment(Qt::AlignCenter);
|
|
welcomeLabel->setFont(*_greetFont);
|
|
inner_box->addWidget(welcomeLabel);
|
|
}
|
|
|
|
switch (_logoArea) {
|
|
case LOGO_CLOCK:
|
|
clock = new KdmClock(this);
|
|
break;
|
|
case LOGO_LOGO: {
|
|
QMovie *movie = new QMovie(this);
|
|
movie->setFileName(_logo);
|
|
if (movie->isValid()) {
|
|
movie->start();
|
|
pixLabel = new QLabel(this);
|
|
pixLabel->setMovie(movie);
|
|
if (!movie->currentImage().hasAlphaChannel())
|
|
pixLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
|
pixLabel->setIndent(0);
|
|
} else {
|
|
delete movie;
|
|
}
|
|
break; }
|
|
}
|
|
|
|
if (userView) {
|
|
if (clock)
|
|
inner_box->addWidget(clock, 0, Qt::AlignCenter);
|
|
else if (pixLabel)
|
|
inner_box->addWidget(pixLabel, 0, Qt::AlignCenter);
|
|
inner_box->addSpacing(inner_box->spacing());
|
|
} else {
|
|
if (clock)
|
|
main_box->addWidget(clock, 0, Qt::AlignCenter);
|
|
else if (pixLabel)
|
|
main_box->addWidget(pixLabel, 0, Qt::AlignCenter);
|
|
}
|
|
|
|
goButton = new QPushButton(i18nc("@action:button", "L&ogin"), this);
|
|
goButton->setDefault(true);
|
|
connect(goButton, SIGNAL(clicked()), SLOT(accept()));
|
|
QPushButton *menuButton = new QPushButton(i18nc("@action:button", "&Menu"), this);
|
|
//helpButton
|
|
|
|
QWidget *prec;
|
|
if (userView)
|
|
prec = userView;
|
|
#ifdef WITH_KDM_XCONSOLE
|
|
else if (consoleView)
|
|
prec = consoleView;
|
|
#endif
|
|
else
|
|
prec = menuButton;
|
|
KGStdVerify *sverify =
|
|
new KGStdVerify(this, this, prec, QString(),
|
|
pluginList, KGreeterPlugin::Authenticate,
|
|
KGreeterPlugin::Login);
|
|
inner_box->addLayout(sverify->getLayout());
|
|
QMenu *plugMenu = sverify->getPlugMenu();
|
|
sverify->selectPlugin(curPlugin);
|
|
verify = sverify;
|
|
|
|
inner_box->addWidget(new KSeparator(Qt::Horizontal, this));
|
|
|
|
QBoxLayout *hbox2 = new QHBoxLayout();
|
|
inner_box->addLayout(hbox2);
|
|
hbox2->addWidget(goButton);
|
|
hbox2->addStretch(1);
|
|
hbox2->addWidget(menuButton);
|
|
hbox2->addStretch(1);
|
|
|
|
if (sessMenu->actions().count() > 1) {
|
|
inserten(i18nc("@title:menu", "Session &Type"), Qt::ALT + Qt::Key_T, sessMenu);
|
|
needSep = true;
|
|
}
|
|
|
|
if (plugMenu) {
|
|
inserten(i18nc("@title:menu", "&Authentication Method"), Qt::ALT + Qt::Key_A, plugMenu);
|
|
needSep = true;
|
|
}
|
|
|
|
#ifdef XDMCP
|
|
completeMenu(LOGIN_LOCAL_ONLY, ex_choose, i18nc("@action:inmenu", "&Remote Login"), Qt::ALT + Qt::Key_R);
|
|
#else
|
|
completeMenu();
|
|
#endif
|
|
|
|
if (optMenu)
|
|
menuButton->setMenu(optMenu);
|
|
else
|
|
menuButton->hide();
|
|
|
|
pluginSetup();
|
|
|
|
verify->start();
|
|
}
|
|
|
|
void
|
|
KStdGreeter::pluginSetup()
|
|
{
|
|
inherited::pluginSetup();
|
|
if (userView) {
|
|
if (verify->entitiesLocal() && verify->entityPresettable())
|
|
userView->show();
|
|
else
|
|
userView->hide();
|
|
}
|
|
adjustGeometry();
|
|
update();
|
|
}
|
|
|
|
void
|
|
KStdGreeter::verifyFailed()
|
|
{
|
|
goButton->setEnabled(false);
|
|
inherited::verifyFailed();
|
|
}
|
|
|
|
void
|
|
KStdGreeter::verifyRetry()
|
|
{
|
|
goButton->setEnabled(true);
|
|
inherited::verifyRetry();
|
|
}
|
|
|
|
|
|
KThemedGreeter::KThemedGreeter(KdmThemer *_themer)
|
|
: KGreeter(true)
|
|
, themer(_themer)
|
|
// , clock(0)
|
|
{
|
|
// We do all painting ourselves
|
|
setAttribute(Qt::WA_NoSystemBackground, true);
|
|
// Allow tracking the mouse position
|
|
setMouseTracking(true);
|
|
|
|
adjustGeometry();
|
|
|
|
themer->setWidget(this);
|
|
|
|
if (_allowThemeDebug)
|
|
new QShortcut(QKeySequence(QLatin1String("Ctrl+Alt+D")),
|
|
this, SLOT(slotDebugToggled()));
|
|
|
|
connect(themer, SIGNAL(activated(QString)),
|
|
SLOT(slotThemeActivated(QString)));
|
|
|
|
KdmItem *console_node = themer->findNode("xconsole"); // kdm ext
|
|
KdmItem *console_rect = themer->findNode("xconsole-rect"); // kdm ext
|
|
if (!console_rect)
|
|
console_rect = console_node;
|
|
userlist_node = themer->findNode("userlist");
|
|
userlist_rect = themer->findNode("userlist-rect");
|
|
if (!userlist_rect)
|
|
userlist_rect = userlist_node;
|
|
caps_warning = themer->findNode("caps-lock-warning");
|
|
xauth_warning = themer->findNode("xauth-warning"); // kdm ext
|
|
pam_error = themer->findNode("pam-error");
|
|
KdmLabel *pam_error_label = qobject_cast<KdmLabel *>(pam_error);
|
|
if (pam_error_label)
|
|
pam_error_label->setText(i18n("Login failed"));
|
|
timed_label = themer->findNode("timed-label");
|
|
|
|
KdmItem *itm;
|
|
if ((itm = themer->findNode("pam-message"))) // done via msgboxes
|
|
itm->setVisible(false);
|
|
if ((itm = themer->findNode("language_button"))) // not implemented yet
|
|
itm->setVisible(false);
|
|
|
|
if (console_node) {
|
|
#ifdef WITH_KDM_XCONSOLE
|
|
if (consoleView)
|
|
console_node->setWidget(consoleView);
|
|
else
|
|
#endif
|
|
console_rect->setVisible(false);
|
|
}
|
|
|
|
if (xauth_warning && (_authorized || !_authComplain))
|
|
xauth_warning->setVisible(false);
|
|
|
|
// if (!_greetString.isEmpty()) {
|
|
// }
|
|
// clock = new KdmClock(this, "clock");
|
|
|
|
QWidget *prec;
|
|
if (userView)
|
|
prec = userView;
|
|
#ifdef WITH_KDM_XCONSOLE
|
|
else if (consoleView)
|
|
prec = consoleView;
|
|
#endif
|
|
else
|
|
prec = 0;
|
|
KGThemedVerify *tverify =
|
|
new KGThemedVerify(this, themer, this, prec, QString(),
|
|
pluginList, KGreeterPlugin::Authenticate,
|
|
KGreeterPlugin::Login);
|
|
QMenu *plugMenu = tverify->getPlugMenu();
|
|
tverify->selectPlugin(curPlugin);
|
|
verify = tverify;
|
|
|
|
if ((session_button = themer->findNode("session_button"))) {
|
|
if (sessMenu->actions().count() <= 1) {
|
|
session_button->setVisible(false);
|
|
session_button = 0;
|
|
}
|
|
} else {
|
|
if (sessMenu->actions().count() > 1) {
|
|
inserten(i18nc("@title:menu", "Session &Type"), Qt::ALT + Qt::Key_T, sessMenu);
|
|
needSep = true;
|
|
}
|
|
}
|
|
|
|
if (plugMenu) {
|
|
inserten(i18nc("@title:menu", "&Authentication Method"), Qt::ALT + Qt::Key_A, plugMenu);
|
|
needSep = true;
|
|
}
|
|
|
|
#ifdef XDMCP
|
|
completeMenu(LOGIN_LOCAL_ONLY, ex_choose, i18nc("@action:inmenu", "&Remote Login"), Qt::ALT + Qt::Key_R);
|
|
#else
|
|
completeMenu();
|
|
#endif
|
|
|
|
if ((system_button = themer->findNode("system_button"))) {
|
|
if (optMenu)
|
|
addAction(optMenu->menuAction());
|
|
else
|
|
system_button->setVisible(false);
|
|
}
|
|
|
|
pluginSetup();
|
|
|
|
verify->start();
|
|
}
|
|
|
|
KThemedGreeter::~KThemedGreeter()
|
|
{
|
|
themer->setWidget(0);
|
|
}
|
|
|
|
void
|
|
KThemedGreeter::slotDebugToggled()
|
|
{
|
|
if ((debugLevel ^= DEBUG_THEMING))
|
|
themer->slotNeedPlacement();
|
|
}
|
|
|
|
bool
|
|
KThemedGreeter::event(QEvent *e)
|
|
{
|
|
if (themer)
|
|
themer->widgetEvent(e);
|
|
return inherited::event(e);
|
|
}
|
|
|
|
void
|
|
KThemedGreeter::pluginSetup()
|
|
{
|
|
inherited::pluginSetup();
|
|
|
|
if (userView && verify->entitiesLocal() && verify->entityPresettable() && userlist_node) {
|
|
userlist_node->setWidget(userView);
|
|
userlist_rect->setVisible(true);
|
|
} else {
|
|
if (userView)
|
|
userView->hide();
|
|
if (userlist_rect)
|
|
userlist_rect->setVisible(false);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void
|
|
KThemedGreeter::verifyFailed()
|
|
{
|
|
// goButton->setEnabled(false);
|
|
inherited::verifyFailed();
|
|
}
|
|
|
|
void
|
|
KThemedGreeter::verifyRetry()
|
|
{
|
|
// goButton->setEnabled(true);
|
|
inherited::verifyRetry();
|
|
}
|
|
#endif
|
|
|
|
void
|
|
KThemedGreeter::updateStatus(bool fail, bool caps, int timedleft)
|
|
{
|
|
if (pam_error)
|
|
pam_error->setVisible(fail);
|
|
if (caps_warning)
|
|
caps_warning->setVisible(caps);
|
|
if (timed_label) {
|
|
if (timedleft) {
|
|
if (timedleft != KdmLabel::timedDelay) {
|
|
KdmLabel::timedDelay = timedleft;
|
|
KdmLabel::timedUser = curUser;
|
|
timed_label->setVisible(true);
|
|
timed_label->update();
|
|
}
|
|
} else {
|
|
KdmLabel::timedDelay = -1;
|
|
timed_label->setVisible(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
KThemedGreeter::slotThemeActivated(const QString &id)
|
|
{
|
|
if (id == "login_button")
|
|
accept();
|
|
else if (id == "session_button")
|
|
slotSessMenu();
|
|
else if (id == "system_button")
|
|
slotActionMenu();
|
|
}
|
|
|
|
void
|
|
KThemedGreeter::slotSessMenu()
|
|
{
|
|
sessMenu->popup(mapToGlobal(session_button->rect().center()));
|
|
}
|
|
|
|
void
|
|
KThemedGreeter::slotActionMenu()
|
|
{
|
|
if (system_button)
|
|
optMenu->popup(mapToGlobal(system_button->rect().center()));
|
|
else
|
|
optMenu->popup(mapToGlobal(rect().center()));
|
|
}
|
|
|
|
void
|
|
KThemedGreeter::keyPressEvent(QKeyEvent *e)
|
|
{
|
|
inherited::keyPressEvent(e);
|
|
if (!(e->modifiers() & ~Qt::KeypadModifier) &&
|
|
(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter))
|
|
accept();
|
|
}
|
|
|
|
#include "kgreeter.moc"
|