~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kdm/kfrontend/kgreeter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Greeter widget for kdm
 
4
 
 
5
Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
 
6
Copyright (C) 2000-2004 Oswald Buddenhagen <ossi@kde.org>
 
7
 
 
8
 
 
9
This program is free software; you can redistribute it and/or modify
 
10
it under the terms of the GNU General Public License as published by
 
11
the Free Software Foundation; either version 2 of the License, or
 
12
(at your option) any later version.
 
13
 
 
14
This program is distributed in the hope that it will be useful,
 
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
GNU General Public License for more details.
 
18
 
 
19
You should have received a copy of the GNU General Public License
 
20
along with this program; if not, write to the Free Software
 
21
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
22
 
 
23
*/
 
24
 
 
25
#include "kgreeter.h"
 
26
#include "kconsole.h"
 
27
#include "kdmconfig.h"
 
28
#include "kdmclock.h"
 
29
#include "kdm_greet.h"
 
30
#include "themer/kdmthemer.h"
 
31
#include "themer/kdmitem.h"
 
32
#include "themer/kdmlabel.h"
 
33
 
 
34
#include <KColorScheme>
 
35
#include <KConfigGroup>
 
36
#include <klocale.h>
 
37
#include <kseparator.h>
 
38
#include <kstandarddirs.h>
 
39
#include <kstringhandler.h>
 
40
 
 
41
#include <QAction>
 
42
#include <QBuffer>
 
43
#include <QDir>
 
44
#include <QFile>
 
45
#include <QImageReader>
 
46
#include <QKeyEvent>
 
47
#include <QLabel>
 
48
#include <QListWidget>
 
49
#include <QListWidgetItem>
 
50
#include <QMenu>
 
51
#include <QMovie>
 
52
#include <QPainter>
 
53
#include <QPushButton>
 
54
#include <QShortcut>
 
55
#include <QStyle>
 
56
 
 
57
#include <sys/types.h>
 
58
#include <sys/stat.h>
 
59
#include <stdlib.h>
 
60
#include <unistd.h>
 
61
#include <fcntl.h>
 
62
#include <errno.h>
 
63
#include <pwd.h>
 
64
#include <grp.h>
 
65
 
 
66
#include <X11/Xlib.h>
 
67
#include <fixx11h.h>
 
68
 
 
69
class UserListView : public QListWidget {
 
70
  public:
 
71
    UserListView(QWidget *parent = 0)
 
72
        : QListWidget(parent)
 
73
        , cachedSizeHint(-1, 0)
 
74
    {
 
75
        setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Ignored);
 
76
        setUniformItemSizes(true);
 
77
        setVerticalScrollMode(ScrollPerPixel);
 
78
        setIconSize(QSize(48, 48));
 
79
        setAlternatingRowColors(true);
 
80
    }
 
81
 
 
82
    mutable QSize cachedSizeHint;
 
83
 
 
84
  protected:
 
85
    virtual QSize sizeHint() const
 
86
    {
 
87
        if (!cachedSizeHint.isValid()) {
 
88
            ensurePolished();
 
89
            QStyleOptionViewItem vo(viewOptions());
 
90
            QAbstractListModel *md(static_cast<QAbstractListModel *>(model()));
 
91
            uint maxw = 0, h = 0;
 
92
            for (int i = 0, rc = md->rowCount(); i < rc; i++) {
 
93
                QSize sh = itemDelegate()->sizeHint(vo, md->index(i));
 
94
                uint thisw = sh.width();
 
95
                if (thisw > maxw)
 
96
                    maxw = thisw;
 
97
                h += sh.height();
 
98
            }
 
99
            cachedSizeHint.setWidth(
 
100
                style()->pixelMetric(QStyle::PM_ScrollBarExtent) +
 
101
                (frameWidth() +
 
102
                 (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents) ?
 
103
                  style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0)) * 2 +
 
104
                maxw);
 
105
            cachedSizeHint.setHeight(frameWidth() * 2 + h);
 
106
        }
 
107
        return cachedSizeHint;
 
108
    }
 
109
 
 
110
    virtual void keyPressEvent(QKeyEvent *event)
 
111
    {
 
112
        switch (event->key()) {
 
113
        case Qt::Key_Enter:
 
114
        case Qt::Key_Return:
 
115
            if (currentItem())
 
116
                emit itemDoubleClicked(currentItem());
 
117
            event->accept();
 
118
            break;
 
119
        case Qt::Key_Space:
 
120
            if (currentItem())
 
121
                emit itemClicked(currentItem());
 
122
            event->accept();
 
123
            break;
 
124
        default:
 
125
            QListWidget::keyPressEvent(event);
 
126
            break;
 
127
        }
 
128
    }
 
129
 
 
130
    virtual void mousePressEvent(QMouseEvent *event)
 
131
    {
 
132
        m_suppressClick = false;
 
133
        QListWidget::mousePressEvent(event);
 
134
    }
 
135
 
 
136
    virtual void mouseReleaseEvent(QMouseEvent *event)
 
137
    {
 
138
        if (m_suppressClick)
 
139
            m_suppressClick = false;
 
140
        else
 
141
            QListWidget::mouseReleaseEvent(event);
 
142
    }
 
143
 
 
144
    virtual void mouseDoubleClickEvent(QMouseEvent *event)
 
145
    {
 
146
        m_suppressClick = true;
 
147
        QListWidget::mouseDoubleClickEvent(event);
 
148
    }
 
149
 
 
150
  private:
 
151
    bool m_suppressClick;
 
152
};
 
153
 
 
154
class UserListViewItem : public QListWidgetItem {
 
155
  public:
 
156
    UserListViewItem(UserListView *parent, const QString &text,
 
157
                     const QPixmap &pixmap, const QString &username)
 
158
        : QListWidgetItem(parent)
 
159
        , login(username)
 
160
    {
 
161
        setIcon(pixmap);
 
162
        setText(text);
 
163
        parent->cachedSizeHint.setWidth(-1);
 
164
    }
 
165
 
 
166
    QString login;
 
167
};
 
168
 
 
169
 
 
170
int KGreeter::curPlugin = -1;
 
171
PluginList KGreeter::pluginList;
 
172
 
 
173
KGreeter::KGreeter(bool framed)
 
174
    : inherited(framed)
 
175
    , dName(dname)
 
176
    , userView(0)
 
177
    , userList(0)
 
178
    , nNormals(0)
 
179
    , nSpecials(0)
 
180
    , curPrev(0)
 
181
    , prevValid(true)
 
182
    , needLoad(false)
 
183
{
 
184
    stsGroup = new KConfigGroup(KSharedConfig::openConfig(_stsFile),
 
185
                                "PrevUser");
 
186
 
 
187
    if (_userList) {
 
188
        userView = new UserListView(this);
 
189
        connect(userView, SIGNAL(itemClicked(QListWidgetItem *)),
 
190
                SLOT(slotUserClicked(QListWidgetItem *)));
 
191
        connect(userView, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
 
192
                SLOT(accept()));
 
193
    }
 
194
    if (_userCompletion)
 
195
        userList = new QStringList;
 
196
    if (userView || userList)
 
197
        insertUsers();
 
198
 
 
199
    sessMenu = new QMenu(this);
 
200
    connect(sessMenu, SIGNAL(triggered(QAction *)),
 
201
            SLOT(slotSessionSelected()));
 
202
 
 
203
    sessGroup = new QActionGroup(this);
 
204
    insertSessions();
 
205
 
 
206
    if (curPlugin < 0) {
 
207
        curPlugin = 0;
 
208
        pluginList = KGVerify::init(_pluginsLogin);
 
209
    }
 
210
}
 
211
 
 
212
KGreeter::~KGreeter()
 
213
{
 
214
    hide();
 
215
    delete userList;
 
216
    delete verify;
 
217
    delete stsGroup;
 
218
}
 
219
 
 
220
#define FILE_LIMIT_ICON 20
 
221
#define FILE_LIMIT_IMAGE 200
 
222
#define PIXEL_LIMIT_ICON 100
 
223
#define PIXEL_LIMIT_IMAGE 300
 
224
 
 
225
// replace this with a simple !access(..., X_OK) once we run with non-root real uid
 
226
static bool
 
227
dirAccessible(const char *dir)
 
228
{
 
229
    struct stat st;
 
230
 
 
231
    if (stat(dir, &st))
 
232
        return false;
 
233
    return (st.st_mode & S_IXOTH) != 0;
 
234
}
 
235
 
 
236
static bool
 
237
loadFace(QByteArray &fn, QImage &p, const QByteArray &pp, bool complain = false)
 
238
{
 
239
    int fd, ico;
 
240
    if ((fd = open(fn.data(), O_RDONLY | O_NONBLOCK)) < 0) {
 
241
        if (errno != ENOENT) {
 
242
            if (pp.isEmpty() || dirAccessible(pp.data()))
 
243
                (complain ? logError : logInfo)
 
244
                    ("Cannot load %s: %m\n", fn.data());
 
245
            return false;
 
246
        }
 
247
        fn.chop(5);
 
248
        if ((fd = open(fn.data(), O_RDONLY | O_NONBLOCK)) < 0) {
 
249
            if ((complain || errno != ENOENT) &&
 
250
                (pp.isEmpty() || dirAccessible(pp.data())))
 
251
                (complain ? logError : logInfo)
 
252
                    ("Cannot load %s: %m\n", fn.data());
 
253
            return false;
 
254
        }
 
255
        ico = 0;
 
256
    } else {
 
257
        ico = 1;
 
258
    }
 
259
    QFile f;
 
260
    f.open(fd, QFile::ReadOnly);
 
261
    int fs = f.size();
 
262
    if (fs > (ico ? FILE_LIMIT_ICON : FILE_LIMIT_IMAGE) * 1000) {
 
263
        logWarn("%s exceeds file size limit (%dkB)\n",
 
264
                fn.data(), ico ? FILE_LIMIT_ICON : FILE_LIMIT_IMAGE);
 
265
        return false;
 
266
    }
 
267
    QByteArray fc = f.read(fs);
 
268
    ::close(fd);
 
269
    QBuffer buf(&fc);
 
270
    buf.open(QBuffer::ReadOnly);
 
271
    QImageReader ir(&buf);
 
272
    QSize sz = ir.size();
 
273
    int lim = ico ? PIXEL_LIMIT_ICON : PIXEL_LIMIT_IMAGE;
 
274
    if (sz.width() > lim || sz.height() > lim) {
 
275
        logWarn("%s exceeds image dimension limit (%dx%d)\n",
 
276
                fn.data(), lim, lim);
 
277
        return false;
 
278
    }
 
279
    sz.scale(48, 48, Qt::KeepAspectRatio);
 
280
    ir.setScaledSize(sz);
 
281
    p = ir.read();
 
282
    if (p.isNull()) {
 
283
        logInfo("%s is no valid image\n", fn.data());
 
284
        return false;
 
285
    }
 
286
    if (p.width() < 48) {
 
287
        QImage np(48, p.height(), QImage::Format_ARGB32);
 
288
        np.fill(0);
 
289
        QPainter pnt(&np);
 
290
        pnt.drawImage((48 - p.width()) / 2, 0, p);
 
291
        p = np;
 
292
    }
 
293
    return true;
 
294
}
 
295
 
 
296
void
 
297
KGreeter::insertUser(const QImage &default_pix,
 
298
                     const QString &username, struct passwd *ps)
 
299
{
 
300
    if (userList)
 
301
        userList->append(username);
 
302
    if (!userView)
 
303
        return;
 
304
 
 
305
    int dp = 0, nd = 0;
 
306
    if (_faceSource == FACE_USER_ONLY ||
 
307
        _faceSource == FACE_PREFER_USER)
 
308
        dp = 1;
 
309
    if (_faceSource != FACE_USER_ONLY &&
 
310
        _faceSource != FACE_ADMIN_ONLY)
 
311
        nd = 1;
 
312
    QImage p;
 
313
    do {
 
314
        dp ^= 1;
 
315
        QByteArray pp, fn;
 
316
        if (!dp) {
 
317
            fn = pp = QByteArray(ps->pw_dir);
 
318
            fn += '/';
 
319
        } else {
 
320
            fn = QFile::encodeName(_faceDir);
 
321
            fn += '/';
 
322
            fn += ps->pw_name;
 
323
        }
 
324
        fn += ".face.icon";
 
325
        if (loadFace(fn, p, pp))
 
326
            goto gotit;
 
327
    } while (--nd >= 0);
 
328
    p = default_pix;
 
329
  gotit:
 
330
    QString realname = KStringHandler::from8Bit(ps->pw_gecos);
 
331
    realname.truncate(realname.indexOf(',') & (~0U >> 1));
 
332
    if (realname.isEmpty() || realname == username) {
 
333
        new UserListViewItem(userView, username, QPixmap::fromImage(p), username);
 
334
    } else {
 
335
        realname.append("\n").append(username);
 
336
        new UserListViewItem(userView, realname, QPixmap::fromImage(p), username);
 
337
    }
 
338
}
 
339
 
 
340
class UserList {
 
341
  public:
 
342
    UserList(char **in);
 
343
    bool hasUser(const char *str) const { return users.contains(str); }
 
344
    bool hasGroup(gid_t gid) const { return groups.contains(gid); }
 
345
    bool hasGroups() const { return !groups.isEmpty(); }
 
346
 
 
347
  private:
 
348
    QSet<gid_t> groups;
 
349
    QSet<QByteArray> users;
 
350
};
 
351
 
 
352
UserList::UserList(char **in)
 
353
{
 
354
    struct group *grp;
 
355
 
 
356
    for (; *in; in++)
 
357
        if (**in == '@') {
 
358
            if ((grp = getgrnam(*in + 1))) {
 
359
                for (; *grp->gr_mem; grp->gr_mem++)
 
360
                    users.insert(*grp->gr_mem);
 
361
                groups.insert(grp->gr_gid);
 
362
            }
 
363
        } else {
 
364
            users.insert(*in);
 
365
        }
 
366
}
 
367
 
 
368
void
 
369
KGreeter::insertUsers()
 
370
{
 
371
    struct passwd *ps;
 
372
 
 
373
    if (!getuid()) {
 
374
        if (!(ps = getpwnam("nobody")))
 
375
            return;
 
376
        if (setegid(ps->pw_gid))
 
377
            return;
 
378
        if (seteuid(ps->pw_uid)) {
 
379
            setegid(0);
 
380
            return;
 
381
        }
 
382
    }
 
383
 
 
384
    QImage default_pix;
 
385
    if (userView) {
 
386
        QByteArray fn = QFile::encodeName(_faceDir) + "/.default.face.icon";
 
387
        if (!loadFace(fn, default_pix, QByteArray(), true)) {
 
388
            default_pix = QImage(48, 48, QImage::Format_ARGB32);
 
389
            default_pix.fill(0);
 
390
        }
 
391
    }
 
392
    if (_showUsers == SHOW_ALL) {
 
393
        UserList noUsers(_noUsers);
 
394
        QSet<QString> dupes;
 
395
        for (setpwent(); (ps = getpwent()) != 0;) {
 
396
            if (*ps->pw_dir && *ps->pw_shell &&
 
397
                (ps->pw_uid >= (unsigned)_lowUserId ||
 
398
                 (!ps->pw_uid && _showRoot)) &&
 
399
                ps->pw_uid <= (unsigned)_highUserId &&
 
400
                !noUsers.hasUser(ps->pw_name) &&
 
401
                !noUsers.hasGroup(ps->pw_gid))
 
402
            {
 
403
                QString username(QFile::decodeName(ps->pw_name));
 
404
                if (!dupes.contains(username)) {
 
405
                    dupes.insert(username);
 
406
                    insertUser(default_pix, username, ps);
 
407
                }
 
408
            }
 
409
        }
 
410
    } else {
 
411
        UserList users(_users);
 
412
        if (users.hasGroups()) {
 
413
            QSet<QString> dupes;
 
414
            for (setpwent(); (ps = getpwent()) != 0;) {
 
415
                if (*ps->pw_dir && *ps->pw_shell &&
 
416
                    (ps->pw_uid >= (unsigned)_lowUserId ||
 
417
                     (!ps->pw_uid && _showRoot)) &&
 
418
                    ps->pw_uid <= (unsigned)_highUserId &&
 
419
                    (users.hasUser(ps->pw_name) ||
 
420
                     users.hasGroup(ps->pw_gid)))
 
421
                {
 
422
                    QString username(QFile::decodeName(ps->pw_name));
 
423
                    if (!dupes.contains(username)) {
 
424
                        dupes.insert(username);
 
425
                        insertUser(default_pix, username, ps);
 
426
                    }
 
427
                }
 
428
            }
 
429
        } else {
 
430
            for (int i = 0; _users[i]; i++)
 
431
                if ((ps = getpwnam(_users[i])) && (ps->pw_uid || _showRoot))
 
432
                    insertUser(default_pix, QFile::decodeName(_users[i]), ps);
 
433
        }
 
434
    }
 
435
    endpwent();
 
436
    endgrent();
 
437
    if (_sortUsers) {
 
438
        if (userView)
 
439
            userView->sortItems();
 
440
        if (userList)
 
441
            userList->sort();
 
442
    }
 
443
 
 
444
    if (!getuid()) {
 
445
        seteuid(0);
 
446
        setegid(0);
 
447
    }
 
448
}
 
449
 
 
450
void
 
451
KGreeter::putSession(const QString &type, const QString &name, bool hid, const char *exe)
 
452
{
 
453
    int prio = exe ? (!strcmp(exe, "default") ? 0 :
 
454
                      !strcmp(exe, "custom") ? 1 :
 
455
                      !strcmp(exe, "failsafe") ? 3 : 2) : 2;
 
456
    for (int i = 0; i < sessionTypes.size(); i++)
 
457
        if (sessionTypes[i].type == type) {
 
458
            sessionTypes[i].prio = prio;
 
459
            return;
 
460
        }
 
461
    sessionTypes.append(SessType(name, type, hid, prio));
 
462
}
 
463
 
 
464
void
 
465
KGreeter::insertSessions()
 
466
{
 
467
    for (char **dit = _sessionsDirs; *dit; ++dit)
 
468
        foreach (QString ent, QDir(*dit).entryList())
 
469
            if (ent.endsWith(".desktop")) {
 
470
                KConfigGroup dsk(
 
471
                    KSharedConfig::openConfig(
 
472
                        QString(*dit).append('/').append(ent)),
 
473
                    "Desktop Entry");
 
474
                putSession(ent.left(ent.length() - 8),
 
475
                            dsk.readEntry("Name"),
 
476
                            (dsk.readEntry("Hidden", false) ||
 
477
                             (dsk.hasKey("TryExec") &&
 
478
                              KStandardDirs::findExe(
 
479
                                  dsk.readEntry("TryExec")).isEmpty())),
 
480
                            dsk.readEntry("Exec").toLatin1());
 
481
            }
 
482
    putSession("default", i18nc("@item:inlistbox session type", "Default"), false, "default");
 
483
    putSession("custom", i18nc("@item:inlistbox session type", "Custom"), false, "custom");
 
484
    putSession("failsafe", i18nc("@item:inlistbox session type", "Failsafe"), false, "failsafe");
 
485
    qSort(sessionTypes);
 
486
    for (int i = 0; i < sessionTypes.size() && !sessionTypes[i].hid; i++) {
 
487
        sessionTypes[i].action = sessGroup->addAction(sessionTypes[i].name);
 
488
        sessionTypes[i].action->setData(i);
 
489
        sessionTypes[i].action->setCheckable(true);
 
490
        switch (sessionTypes[i].prio) {
 
491
        case 0: case 1: nSpecials++; break;
 
492
        case 2: nNormals++; break;
 
493
        }
 
494
    }
 
495
    sessMenu->addActions(sessGroup->actions());
 
496
}
 
497
 
 
498
void
 
499
KGreeter::slotUserEntered()
 
500
{
 
501
    struct passwd *pw;
 
502
 
 
503
    if (userView) {
 
504
        if ((pw = getpwnam(curUser.toLocal8Bit().data()))) {
 
505
            QString theUser = QString::fromLocal8Bit(pw->pw_name);
 
506
            for (int i = 0, rc = userView->model()->rowCount(); i < rc; i++) {
 
507
                UserListViewItem *item =
 
508
                    static_cast<UserListViewItem *>(userView->item(i));
 
509
                if (item->login == theUser) {
 
510
                    userView->setCurrentItem(item);
 
511
                    goto oke;
 
512
                }
 
513
            }
 
514
        }
 
515
        userView->clearSelection();
 
516
    }
 
517
  oke:
 
518
    if (isVisible())
 
519
        slotLoadPrevWM();
 
520
    else
 
521
        QTimer::singleShot(0, this, SLOT(slotLoadPrevWM()));
 
522
}
 
523
 
 
524
void
 
525
KGreeter::slotUserClicked(QListWidgetItem *item)
 
526
{
 
527
    if (item) {
 
528
        curUser = ((UserListViewItem *)item)->login;
 
529
        verify->setUser(curUser);
 
530
        slotLoadPrevWM();
 
531
    }
 
532
}
 
533
 
 
534
void
 
535
KGreeter::slotSessionSelected()
 
536
{
 
537
    verify->gplugChanged();
 
538
}
 
539
 
 
540
void
 
541
KGreeter::reject()
 
542
{
 
543
    verify->reject();
 
544
}
 
545
 
 
546
void
 
547
KGreeter::accept()
 
548
{
 
549
    verify->accept();
 
550
}
 
551
 
 
552
void // private
 
553
KGreeter::setPrevWM(QAction *wm)
 
554
{
 
555
    if (curPrev != wm) {
 
556
        if (curPrev)
 
557
            curPrev->setText(sessionTypes[curPrev->data().toInt()].name);
 
558
        if (wm)
 
559
            wm->setText(i18nc("@item:inmenu session type",
 
560
                              "%1 (previous)",
 
561
                              sessionTypes[wm->data().toInt()].name));
 
562
        curPrev = wm;
 
563
    }
 
564
}
 
565
 
 
566
void
 
567
KGreeter::slotLoadPrevWM()
 
568
{
 
569
    int len, i, b;
 
570
    unsigned long crc, by;
 
571
    QByteArray name;
 
572
    char *sess;
 
573
 
 
574
    // XXX this should actually check for !CoreBusy - would it be safe?
 
575
    if (verify->coreState != KGVerify::CoreIdle) {
 
576
        needLoad = true;
 
577
        return;
 
578
    }
 
579
    needLoad = false;
 
580
 
 
581
    prevValid = true;
 
582
    name = curUser.toLocal8Bit();
 
583
    gSendInt(G_ReadDmrc);
 
584
    gSendStr(name.data());
 
585
    gRecvInt(); // ignore status code ...
 
586
    if ((len = name.length())) {
 
587
        gSendInt(G_GetDmrc);
 
588
        gSendStr("Session");
 
589
        sess = gRecvStr();
 
590
        if (!sess) { /* no such user */
 
591
            if (!userView && !userList) { // don't fake if user list shown
 
592
                prevValid = false;
 
593
                /* simple crc32 */
 
594
                for (crc = _forgingSeed, i = 0; i < len; i++) {
 
595
                    by = (crc & 255) ^ name[i];
 
596
                    for (b = 0; b < 8; b++)
 
597
                        by = (by >> 1) ^ (-(by & 1) & 0xedb88320);
 
598
                    crc = (crc >> 8) ^ by;
 
599
                }
 
600
                /* forge a session with this hash - default & custom more probable */
 
601
                /* XXX - this should do a statistical analysis of the real users */
 
602
#if 1
 
603
                setPrevWM(sessionTypes[crc % (nSpecials * 2 + nNormals) % (nSpecials + nNormals)].action);
 
604
#else
 
605
                i = crc % (nSpecials * 2 + nNormals);
 
606
                if (i < nNormals)
 
607
                    setPrevWM(sessionTypes[i + nSpecials].action);
 
608
                else
 
609
                    setPrevWM(sessionTypes[(i - nNormals) / 2].action);
 
610
#endif
 
611
                return;
 
612
            }
 
613
        } else {
 
614
            for (int i = 0; i < sessionTypes.count() && !sessionTypes[i].hid; i++)
 
615
                if (sessionTypes[i].type == sess) {
 
616
                    free(sess);
 
617
                    setPrevWM(sessionTypes[i].action);
 
618
                    return;
 
619
                }
 
620
            if (!sessGroup->checkedAction())
 
621
                KFMsgBox::box(this, sorrybox,
 
622
                              i18n("Your saved session type '%1' is not valid any more.\n"
 
623
                                   "Please select a new one, otherwise 'default' will be used.", sess));
 
624
            free(sess);
 
625
            prevValid = false;
 
626
        }
 
627
    }
 
628
    setPrevWM(0);
 
629
}
 
630
 
 
631
void // protected
 
632
KGreeter::pluginSetup()
 
633
{
 
634
    int field = 0;
 
635
    QString ent, pn(verify->pluginName()), dn(dName + '_' + pn);
 
636
 
 
637
    if (_preselUser != PRESEL_PREV)
 
638
        stsGroup->deleteEntry(verify->entitiesLocal() ? dName : dn, 0);
 
639
    if (_preselUser != PRESEL_NONE && verify->entityPresettable()) {
 
640
        if (verify->entitiesLocal())
 
641
            ent = _preselUser == PRESEL_PREV ?
 
642
                stsGroup->readEntry(dName, QString()) : _defaultUser;
 
643
        else
 
644
            ent = _preselUser == PRESEL_PREV ?
 
645
                stsGroup->readEntry(dn, QString()) :
 
646
                verify->getConf(0, (pn + ".DefaultEntity").toLatin1(), QVariant()).toString();
 
647
        field = verify->entitiesFielded() ?
 
648
            verify->getConf(0, (pn + ".FocusField").toLatin1(), QVariant(0)).toInt() :
 
649
            _focusPasswd;
 
650
    }
 
651
    verify->presetEntity(ent, field);
 
652
    if (userList)
 
653
        verify->loadUsers(*userList);
 
654
}
 
655
 
 
656
void
 
657
KGreeter::verifyPluginChanged(int id)
 
658
{
 
659
    curPlugin = id;
 
660
    pluginSetup();
 
661
}
 
662
 
 
663
void
 
664
KGreeter::verifyClear()
 
665
{
 
666
    curUser.clear();
 
667
    slotUserEntered();
 
668
    if (QAction *curSel = sessGroup->checkedAction())
 
669
        curSel->setChecked(false);
 
670
}
 
671
 
 
672
void
 
673
KGreeter::verifyOk()
 
674
{
 
675
    if (_preselUser == PRESEL_PREV && verify->entityPresettable())
 
676
        stsGroup->writeEntry(verify->entitiesLocal() ?
 
677
                                 dName :
 
678
                                 dName + '_' + verify->pluginName(),
 
679
                             verify->getEntity());
 
680
    if (QAction *curSel = sessGroup->checkedAction()) {
 
681
        gSendInt(G_PutDmrc);
 
682
        gSendStr("Session");
 
683
        gSendStr(sessionTypes[curSel->data().toInt()].type.toUtf8());
 
684
    } else if (!prevValid) {
 
685
        gSendInt(G_PutDmrc);
 
686
        gSendStr("Session");
 
687
        gSendStr("default");
 
688
    }
 
689
    done(ex_login);
 
690
}
 
691
 
 
692
void
 
693
KGreeter::verifyFailed()
 
694
{
 
695
    if (userView)
 
696
        userView->setEnabled(false);
 
697
    if (needLoad)
 
698
        slotLoadPrevWM();
 
699
}
 
700
 
 
701
void
 
702
KGreeter::verifyRetry()
 
703
{
 
704
    if (userView)
 
705
        userView->setEnabled(true);
 
706
}
 
707
 
 
708
void
 
709
KGreeter::verifySetUser(const QString &user)
 
710
{
 
711
    curUser = user;
 
712
    slotUserEntered();
 
713
}
 
714
 
 
715
 
 
716
KStdGreeter::KStdGreeter()
 
717
    : KGreeter()
 
718
    , clock(0)
 
719
    , pixLabel(0)
 
720
{
 
721
    QBoxLayout *main_box;
 
722
#ifdef WITH_KDM_XCONSOLE
 
723
    if (consoleView) {
 
724
        QBoxLayout *ex_box = new QVBoxLayout(this);
 
725
        main_box = new QHBoxLayout();
 
726
        ex_box->addLayout(main_box);
 
727
        ex_box->addWidget(consoleView);
 
728
    } else
 
729
#endif
 
730
    {
 
731
        main_box = new QHBoxLayout(this);
 
732
    }
 
733
    int rs = layout()->spacing();
 
734
    main_box->setSpacing(layout()->margin());
 
735
 
 
736
    if (userView)
 
737
        main_box->addWidget(userView);
 
738
 
 
739
    QBoxLayout *inner_box = new QVBoxLayout();
 
740
    main_box->addLayout(inner_box);
 
741
    inner_box->setSpacing(rs);
 
742
 
 
743
    if (!_authorized && _authComplain) {
 
744
        QLabel *complainLabel = new QLabel(
 
745
            i18n("Warning: this is an unsecured session"), this);
 
746
        complainLabel->setToolTip(
 
747
            i18n("This display requires no X authorization.\n"
 
748
                 "This means that anybody can connect to it,\n"
 
749
                 "open windows on it or intercept your input."));
 
750
        complainLabel->setAlignment(Qt::AlignCenter);
 
751
        complainLabel->setFont(*_failFont);
 
752
        QPalette p;
 
753
        p.setBrush(QPalette::WindowText,
 
754
            KColorScheme(QPalette::Active, KColorScheme::Window)
 
755
                .foreground(KColorScheme::NegativeText));
 
756
        complainLabel->setPalette(p);
 
757
        inner_box->addWidget(complainLabel);
 
758
    }
 
759
    if (!_greetString.isEmpty()) {
 
760
        QLabel *welcomeLabel = new QLabel(_greetString, this);
 
761
        welcomeLabel->setAlignment(Qt::AlignCenter);
 
762
        welcomeLabel->setFont(*_greetFont);
 
763
        inner_box->addWidget(welcomeLabel);
 
764
    }
 
765
 
 
766
    switch (_logoArea) {
 
767
    case LOGO_CLOCK:
 
768
        clock = new KdmClock(this);
 
769
        break;
 
770
    case LOGO_LOGO: {
 
771
        QMovie *movie = new QMovie(this);
 
772
        movie->setFileName(_logo);
 
773
        if (movie->isValid()) {
 
774
            movie->start();
 
775
            pixLabel = new QLabel(this);
 
776
            pixLabel->setMovie(movie);
 
777
            if (!movie->currentImage().hasAlphaChannel())
 
778
                pixLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
 
779
            pixLabel->setIndent(0);
 
780
        } else {
 
781
            delete movie;
 
782
        }
 
783
        break; }
 
784
    }
 
785
 
 
786
    if (userView) {
 
787
        if (clock)
 
788
            inner_box->addWidget(clock, 0, Qt::AlignCenter);
 
789
        else if (pixLabel)
 
790
            inner_box->addWidget(pixLabel, 0, Qt::AlignCenter);
 
791
        inner_box->addSpacing(inner_box->spacing());
 
792
    } else {
 
793
        if (clock)
 
794
            main_box->addWidget(clock, 0, Qt::AlignCenter);
 
795
        else if (pixLabel)
 
796
            main_box->addWidget(pixLabel, 0, Qt::AlignCenter);
 
797
    }
 
798
 
 
799
    goButton = new QPushButton(i18nc("@action:button", "L&ogin"), this);
 
800
    goButton->setDefault(true);
 
801
    connect(goButton, SIGNAL(clicked()), SLOT(accept()));
 
802
    QPushButton *menuButton = new QPushButton(i18nc("@action:button", "&Menu"), this);
 
803
    //helpButton
 
804
 
 
805
    QWidget *prec;
 
806
    if (userView)
 
807
        prec = userView;
 
808
#ifdef WITH_KDM_XCONSOLE
 
809
    else if (consoleView)
 
810
        prec = consoleView;
 
811
#endif
 
812
    else
 
813
        prec = menuButton;
 
814
    KGStdVerify *sverify =
 
815
        new KGStdVerify(this, this, prec, QString(),
 
816
                        pluginList, KGreeterPlugin::Authenticate,
 
817
                        KGreeterPlugin::Login);
 
818
    inner_box->addLayout(sverify->getLayout());
 
819
    QMenu *plugMenu = sverify->getPlugMenu();
 
820
    sverify->selectPlugin(curPlugin);
 
821
    verify = sverify;
 
822
 
 
823
    inner_box->addWidget(new KSeparator(Qt::Horizontal, this));
 
824
 
 
825
    QBoxLayout *hbox2 = new QHBoxLayout();
 
826
    inner_box->addLayout(hbox2);
 
827
    hbox2->addWidget(goButton);
 
828
    hbox2->addStretch(1);
 
829
    hbox2->addWidget(menuButton);
 
830
    hbox2->addStretch(1);
 
831
 
 
832
    if (sessMenu->actions().count() > 1) {
 
833
        inserten(i18nc("@title:menu", "Session &Type"), Qt::ALT + Qt::Key_T, sessMenu);
 
834
        needSep = true;
 
835
    }
 
836
 
 
837
    if (plugMenu) {
 
838
        inserten(i18nc("@title:menu", "&Authentication Method"), Qt::ALT + Qt::Key_A, plugMenu);
 
839
        needSep = true;
 
840
    }
 
841
 
 
842
#ifdef XDMCP
 
843
    completeMenu(LOGIN_LOCAL_ONLY, ex_choose, i18nc("@action:inmenu", "&Remote Login"), Qt::ALT + Qt::Key_R);
 
844
#else
 
845
    completeMenu();
 
846
#endif
 
847
 
 
848
    if (optMenu)
 
849
        menuButton->setMenu(optMenu);
 
850
    else
 
851
        menuButton->hide();
 
852
 
 
853
    pluginSetup();
 
854
 
 
855
    verify->start();
 
856
}
 
857
 
 
858
void
 
859
KStdGreeter::pluginSetup()
 
860
{
 
861
    inherited::pluginSetup();
 
862
    if (userView) {
 
863
        if (verify->entitiesLocal() && verify->entityPresettable())
 
864
            userView->show();
 
865
        else
 
866
            userView->hide();
 
867
    }
 
868
    adjustGeometry();
 
869
    update();
 
870
}
 
871
 
 
872
void
 
873
KStdGreeter::verifyFailed()
 
874
{
 
875
    goButton->setEnabled(false);
 
876
    inherited::verifyFailed();
 
877
}
 
878
 
 
879
void
 
880
KStdGreeter::verifyRetry()
 
881
{
 
882
    goButton->setEnabled(true);
 
883
    inherited::verifyRetry();
 
884
}
 
885
 
 
886
 
 
887
KThemedGreeter::KThemedGreeter(KdmThemer *_themer)
 
888
    : KGreeter(true)
 
889
    , themer(_themer)
 
890
//    , clock(0)
 
891
{
 
892
    // We do all painting ourselves
 
893
    setAttribute(Qt::WA_NoSystemBackground, true);
 
894
    // Allow tracking the mouse position
 
895
    setMouseTracking(true);
 
896
 
 
897
    adjustGeometry();
 
898
 
 
899
    themer->setWidget(this);
 
900
 
 
901
    if (_allowThemeDebug)
 
902
        new QShortcut(QKeySequence(QLatin1String("Ctrl+Alt+D")),
 
903
                      this, SLOT(slotDebugToggled()));
 
904
 
 
905
    connect(themer, SIGNAL(activated(const QString &)),
 
906
            SLOT(slotThemeActivated(const QString &)));
 
907
 
 
908
    KdmItem *console_node = themer->findNode("xconsole"); // kdm ext
 
909
    KdmItem *console_rect = themer->findNode("xconsole-rect"); // kdm ext
 
910
    if (!console_rect)
 
911
        console_rect = console_node;
 
912
    userlist_node = themer->findNode("userlist");
 
913
    userlist_rect = themer->findNode("userlist-rect");
 
914
    if (!userlist_rect)
 
915
        userlist_rect = userlist_node;
 
916
    caps_warning = themer->findNode("caps-lock-warning");
 
917
    xauth_warning = themer->findNode("xauth-warning"); // kdm ext
 
918
    pam_error = themer->findNode("pam-error");
 
919
    KdmLabel *pam_error_label = qobject_cast<KdmLabel *>(pam_error);
 
920
    if (pam_error_label)
 
921
        pam_error_label->setText(i18n("Login failed"));
 
922
    timed_label = themer->findNode("timed-label");
 
923
 
 
924
    KdmItem *itm;
 
925
    if ((itm = themer->findNode("pam-message"))) // done via msgboxes
 
926
        itm->setVisible(false);
 
927
    if ((itm = themer->findNode("language_button"))) // not implemented yet
 
928
        itm->setVisible(false);
 
929
 
 
930
    if (console_node) {
 
931
#ifdef WITH_KDM_XCONSOLE
 
932
        if (consoleView)
 
933
            console_node->setWidget(consoleView);
 
934
        else
 
935
#endif
 
936
            console_rect->setVisible(false);
 
937
    }
 
938
 
 
939
    if (xauth_warning && (_authorized || !_authComplain))
 
940
        xauth_warning->setVisible(false);
 
941
 
 
942
//    if (!_greetString.isEmpty()) {
 
943
//    }
 
944
//    clock = new KdmClock(this, "clock");
 
945
 
 
946
    QWidget *prec;
 
947
    if (userView)
 
948
        prec = userView;
 
949
#ifdef WITH_KDM_XCONSOLE
 
950
    else if (consoleView)
 
951
        prec = consoleView;
 
952
#endif
 
953
    else
 
954
        prec = 0;
 
955
    KGThemedVerify *tverify =
 
956
        new KGThemedVerify(this, themer, this, prec, QString(),
 
957
                           pluginList, KGreeterPlugin::Authenticate,
 
958
                           KGreeterPlugin::Login);
 
959
    QMenu *plugMenu = tverify->getPlugMenu();
 
960
    tverify->selectPlugin(curPlugin);
 
961
    verify = tverify;
 
962
 
 
963
    if ((session_button = themer->findNode("session_button"))) {
 
964
        if (sessMenu->actions().count() <= 1) {
 
965
            session_button->setVisible(false);
 
966
            session_button = 0;
 
967
        }
 
968
    } else {
 
969
        if (sessMenu->actions().count() > 1) {
 
970
            inserten(i18nc("@title:menu", "Session &Type"), Qt::ALT + Qt::Key_T, sessMenu);
 
971
            needSep = true;
 
972
        }
 
973
    }
 
974
 
 
975
    if (plugMenu) {
 
976
        inserten(i18nc("@title:menu", "&Authentication Method"), Qt::ALT + Qt::Key_A, plugMenu);
 
977
        needSep = true;
 
978
    }
 
979
 
 
980
#ifdef XDMCP
 
981
    completeMenu(LOGIN_LOCAL_ONLY, ex_choose, i18nc("@action:inmenu", "&Remote Login"), Qt::ALT + Qt::Key_R);
 
982
#else
 
983
    completeMenu();
 
984
#endif
 
985
 
 
986
    if ((system_button = themer->findNode("system_button"))) {
 
987
        if (optMenu)
 
988
            addAction(optMenu->menuAction());
 
989
        else
 
990
            system_button->setVisible(false);
 
991
    }
 
992
 
 
993
    pluginSetup();
 
994
 
 
995
    verify->start();
 
996
}
 
997
 
 
998
KThemedGreeter::~KThemedGreeter()
 
999
{
 
1000
    themer->setWidget(0);
 
1001
}
 
1002
 
 
1003
void
 
1004
KThemedGreeter::slotDebugToggled()
 
1005
{
 
1006
    if ((debugLevel ^= DEBUG_THEMING))
 
1007
        themer->slotNeedPlacement();
 
1008
}
 
1009
 
 
1010
bool
 
1011
KThemedGreeter::event(QEvent *e)
 
1012
{
 
1013
    if (themer)
 
1014
        themer->widgetEvent(e);
 
1015
    return inherited::event(e);
 
1016
}
 
1017
 
 
1018
void
 
1019
KThemedGreeter::pluginSetup()
 
1020
{
 
1021
    inherited::pluginSetup();
 
1022
 
 
1023
    if (userView && verify->entitiesLocal() && verify->entityPresettable() && userlist_node) {
 
1024
        userlist_node->setWidget(userView);
 
1025
        userlist_rect->setVisible(true);
 
1026
    } else {
 
1027
        if (userView)
 
1028
            userView->hide();
 
1029
        if (userlist_rect)
 
1030
            userlist_rect->setVisible(false);
 
1031
    }
 
1032
}
 
1033
 
 
1034
#if 0
 
1035
void
 
1036
KThemedGreeter::verifyFailed()
 
1037
{
 
1038
//    goButton->setEnabled(false);
 
1039
    inherited::verifyFailed();
 
1040
}
 
1041
 
 
1042
void
 
1043
KThemedGreeter::verifyRetry()
 
1044
{
 
1045
//    goButton->setEnabled(true);
 
1046
    inherited::verifyRetry();
 
1047
}
 
1048
#endif
 
1049
 
 
1050
void
 
1051
KThemedGreeter::updateStatus(bool fail, bool caps, int timedleft)
 
1052
{
 
1053
    if (pam_error)
 
1054
        pam_error->setVisible(fail);
 
1055
    if (caps_warning)
 
1056
        caps_warning->setVisible(caps);
 
1057
    if (timed_label) {
 
1058
        if (timedleft) {
 
1059
            if (timedleft != KdmLabel::timedDelay) {
 
1060
                KdmLabel::timedDelay = timedleft;
 
1061
                KdmLabel::timedUser = curUser;
 
1062
                timed_label->setVisible(true);
 
1063
                timed_label->update();
 
1064
            }
 
1065
        } else {
 
1066
            KdmLabel::timedDelay = -1;
 
1067
            timed_label->setVisible(false);
 
1068
        }
 
1069
    }
 
1070
}
 
1071
 
 
1072
void
 
1073
KThemedGreeter::slotThemeActivated(const QString &id)
 
1074
{
 
1075
    if (id == "login_button")
 
1076
        accept();
 
1077
    else if (id == "session_button")
 
1078
        slotSessMenu();
 
1079
    else if (id == "system_button")
 
1080
        slotActionMenu();
 
1081
}
 
1082
 
 
1083
void
 
1084
KThemedGreeter::slotSessMenu()
 
1085
{
 
1086
    sessMenu->popup(mapToGlobal(session_button->rect().center()));
 
1087
}
 
1088
 
 
1089
void
 
1090
KThemedGreeter::slotActionMenu()
 
1091
{
 
1092
    if (system_button)
 
1093
        optMenu->popup(mapToGlobal(system_button->rect().center()));
 
1094
    else
 
1095
        optMenu->popup(mapToGlobal(rect().center()));
 
1096
}
 
1097
 
 
1098
void
 
1099
KThemedGreeter::keyPressEvent(QKeyEvent *e)
 
1100
{
 
1101
    inherited::keyPressEvent(e);
 
1102
    if (!(e->modifiers() & ~Qt::KeypadModifier) &&
 
1103
        (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter))
 
1104
        accept();
 
1105
}
 
1106
 
 
1107
#include "kgreeter.moc"