/*

Greeter module for xdm

Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
Copyright (C) 2000-2003 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 <QTextStream>
#include "kgapp.h"

#include "kdm_greet.h"
#include "kdmshutdown.h"
#include "kdmconfig.h"
#include "kgreeter.h"
#ifdef XDMCP
# include "kchooser.h"
#endif
#include "themer/kdmthemer.h"
#include "utils.h"

//#include <kcrash.h>
//#include <kglobalsettings.h>
//#include <kcomponentdata.h>
#include <qprocess.h>
#include <QSettings> //<kconfig.h>
//#include <kstandarddirs.h>
#include <QDir>
#include <QTranslator>

#include <QEvent>
#include <QKeyEvent>

#include <QScreen>
#include <QDesktopWidget>
#include <QPainter>
#include <QX11Info>

#include <QTouchDevice> //alex

#include <stdio.h>
#include <stdlib.h> // free(), exit()
#include <unistd.h> // alarm()
#include <signal.h>
#include <locale.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef USE_SYSLOG
# include <syslog.h>
#endif

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#include <fixx11h.h>
#include <fly/flyfileutils.h> //GetFlyDir()
#include <fly/flymisc.h>
#include <fly/flydesktopentry.h>

extern "C" {

static void
sigAlarm(int)
{
    exit(EX_RESERVER_DPY);
}

}

GreeterApp::GreeterApp(int &argc, char **argv) :
    inherited(argc, argv),
    regrabPtr(false), regrabKbd(false), initalBusy(true), sendInteract(false),
    dragWidget(nullptr)
{
    pingInterval = _isLocal ? 0 : _pingInterval;
    if (pingInterval) {
        struct sigaction sa;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sa.sa_handler = sigAlarm;
        sigaction(SIGALRM, &sa, nullptr);
        alarm(pingInterval * 70); // sic! give the "proper" pinger enough time
        pingTimerId = startTimer(pingInterval * 60000);
    } else
        pingTimerId = 0;
}

void
GreeterApp::markBusy()
{
    if (initalBusy)
        initalBusy = false;
    else
        setCursor(QX11Info::display(), desktop()->winId(), XC_watch);
    setOverrideCursor(Qt::WaitCursor);
}

void
GreeterApp::markReady()
{
    restoreOverrideCursor();
    setCursor(QX11Info::display(), desktop()->winId(), XC_left_ptr);
}

void
GreeterApp::timerEvent(QTimerEvent *ev)
{
    if (ev->timerId() == pingTimerId) {
        alarm(0);
        if (!pingServer(QX11Info::display()))
            ::exit(EX_RESERVER_DPY);
        alarm(pingInterval * 70); // sic! give the "proper" pinger enough time
    }
}

/* FIXME, TODO: not for qt5, what can we do? need it?
bool
GreeterApp::x11EventFilter(XEvent * ev)
{
    KeySym sym;

    if (_grabInput) {
        switch (ev->type) {
        case FocusIn:
        case FocusOut:
            if (ev->xfocus.mode == NotifyUngrab) {
                if (!regrabKbd) {
                    secureKeyboard(QX11Info::display());
                    regrabKbd = true;
                }
            } else {
                regrabKbd = false;
            }
            return false;
        case EnterNotify:
        case LeaveNotify:
            if (ev->xcrossing.mode == NotifyUngrab) {
                if (!regrabPtr) {
                    securePointer(QX11Info::display());
                    regrabPtr = true;
                }
            } else {
                regrabPtr = false;
            }
            return false;
        }
    }
    switch (ev->type) {
    case KeyPress:
        sym = XLookupKeysym(&ev->xkey, 0);
        if (sym != XK_Return && !IsModifierKey(sym))
            emit activity();
        break;
    case ButtonPress:
        emit activity();
        // fall through
    case ButtonRelease:
        // Hack to let the RMB work as LMB
        if (ev->xbutton.button == 3)
            ev->xbutton.button = 1;
        // fall through
    case MotionNotify:
        if (ev->xbutton.state & Button3Mask)
            ev->xbutton.state = (ev->xbutton.state & ~Button3Mask) | Button1Mask;
        switch (ev->type) {
        case ButtonPress:
            if (((ev->xbutton.state & Mod1Mask) && ev->xbutton.button == 1) ||
                dragWidget)
            {
                if (!dragWidget &&
                    ev->xbutton.window != QX11Info::appRootWindow(_greeterScreen) &&
                    (dragWidget = QWidget::find(ev->xbutton.window)))
                {
                    dragWidget = dragWidget->window();
                    dialogStartPos = dragWidget->geometry().center();
                    mouseStartPos = QPoint(ev->xbutton.x_root, ev->xbutton.y_root);
                    setOverrideCursor(QCursor(Qt::SizeAllCursor));
                }
                return true;
            }
            break;
        case ButtonRelease:
            if (dragWidget) {
                restoreOverrideCursor();
                dragWidget = 0;
                return true;
            }
            break;
        case MotionNotify:
            if (dragWidget) {
                QRect grt(dragWidget->rect());
                grt.moveCenter(dialogStartPos +
                               QPoint(ev->xbutton.x_root, ev->xbutton.y_root) -
                               mouseStartPos);
                FDialog::fitInto(qApp->desktop()->screenGeometry(_greeterScreen), grt);
                dragWidget->setGeometry(grt);
                return true;
            }
            break;
        }
        break;
    default:
        return false;
    }
    if (sendInteract) {
        sendInteract = false;
        // We assume that no asynchronous communication is going on
        // before the first user interaction.
        gSendInt(G_Interact);
    }
    return false;
}
*/
extern "C" {

static int
xIOErr(Display *)
{
    exit(EX_RESERVER_DPY);
    // Bogus return value, notreached
    return 0;
}

static void
sigterm(int n ATTR_UNUSED)
{
    static int cnt=0;
    if (cnt>0) {
      logError("sigterm call the %d-nd time - ignored\n",cnt+1);
      return;
    }
    cnt++;
    exit(/*EX_NORMAL*/EX_RESERVER_DPY); //for restart by kill fly-dm_greeter (alladin)
}

static char *savhome;

static void
cleanup(void)
{
    char buf[128];

    if (strcmp(savhome, getenv("HOME")) || memcmp(savhome, "/tmp/", 5)) {
        logError("Internal error: memory corruption detected\n"); /* no panic: recursion */
    } else {
        sprintf(buf, "rm -rf %s", savhome);
        system(buf);
    }
}

static int
goodLocale(const char *var)
{
    char *l = getenv(var);
    if (!l)
        return False;
    if (*l && strcmp(l, "C") && strcmp(l, "POSIX"))
        return True;
    unsetenv(l);
    return False;
}

} // extern "C"

static uint
qHash(const QSize &sz)
{
    return (sz.width() << 12) ^ sz.height();
}

int
main(int argc ATTR_UNUSED, char **/*argv*/)
{
    char *ci;
    int i;
    char qtrc[40];

    if (!(ci = getenv("CONINFO"))) {
        fprintf(stderr, "This program is part of dm and should not be run manually.\n");
        return 1;
    }
    if (sscanf(ci, "%d %d %d %d", &srfd, &swfd, &mrfd, &mwfd) != 4)
        return 1;
    fcntl(srfd, F_SETFD, FD_CLOEXEC);
    fcntl(swfd, F_SETFD, FD_CLOEXEC);
    fcntl(mrfd, F_SETFD, FD_CLOEXEC);
    fcntl(mwfd, F_SETFD, FD_CLOEXEC);
    gSet(0);

#ifdef USE_SYSLOG
    openlog("fly-dm_greet", LOG_PID, LOG_DAEMON);
#endif

    if ((debugLevel = gRecvInt()) & DEBUG_WGREET)
        sleep(100);

    signal(SIGTERM, sigterm);

    setenv("DBUS_SESSION_BUS_ADDRESS","nothing",1); //to prevent high integrity dbus daemon start

    dname = getenv("DISPLAY");

    initConfig();

    /* for QSettings - alex: TODO: obsolete? - remove in astra 1.7 */
    srand(time(nullptr));
    for (i = 0; i < 10000; i++) {
        sprintf(qtrc, "/tmp/%010d", rand());
        if (!mkdir(qtrc, 0700))
            goto okay;
    }
    logPanic("Cannot create $HOME (dir for qtrc in /tmp)\n");
  okay:
    if (setenv("HOME", qtrc, 1))
        logPanic("Cannot set $HOME\n");
    if (!(savhome = strdup(qtrc)))
        logPanic("Cannot save $HOME\n");
    atexit(cleanup);

    if (*_language) {
        /*
         * Make reasonably sure the locale is not POSIX. This will still fail
         * if all of the following apply:
         * - LANG, LC_MESSAGES & LC_ALL resolve to POSIX
         * - an abbreviated locale is configured (the kcm does this)
         * - the en_US locale is not installed
         */
        if (!goodLocale("LC_ALL") &&
            !goodLocale("LC_MESSAGES") &&
            !goodLocale("LANG"))
        {
            if (strchr(_language, '_') && setlocale(LC_ALL, _language))
                setenv("LANG", _language, 1);
            else if (setlocale(LC_ALL, "ru_RU.UTF-8")) //alex: our locale
                setenv("LANG", "ru_RU.UTF-8", 1);
            else
                logError("Cannot set locale. Translations will not work.\n");
        }

        setenv("LANGUAGE", _language, 1);
    }

    // fool qt's platform detection so it loads the kde platform plugin
    //setenv("KDE_FULL_SESSION", "true", 1);
    //setenv("KDE_SESSION_VERSION", "4", 1);
    setenv("DESKTOP_SESSION",     "fly"/*"kde"*/, 1); // for qt 4.6 only
    setenv("XDG_CURRENT_DESKTOP", "fly",1); //for qt5
    setenv("QT_QPA_PLATFORMTHEME","fly",1); //for qt5
    // fool d-bus, so we get no kbuildsycoca, etc.
    setenv("DBUS_SESSION_BUS_ADDRESS", "fake", 1);

    static char *fakeArgv[] = { (char *)"fly-dm_greet"/*"kdmgreet"*/, nullptr };
    static int fakeArgc = as(fakeArgv) - 1;

    if (!_grabServer) {
        gSendInt(G_SetupDpy);
        gRecvInt();
    }

    //alex: do secure before this qt5 app instantiation not to kill ourself
    int xdpi = 96;
    Display *disp = XOpenDisplay(dname);
    if (disp)
    {
        //alex: try to do dpi stuff before secure display QApplication
        int scr = DefaultScreen(disp);
        Window rWin = RootWindow(disp, scr);
        SetRRPrimary(disp,rWin); //alex
        //get dpi from X server, if it is fake 96, then from Xft, if it is fake 96 or 0, then from xrandr
        xdpi = FindDPI(disp,scr,rWin);
        if (xdpi>120)
        {
            debug("dpi=%d is high, so Xft.dpi=%d, AA=true\n",xdpi,xdpi);
            if (!_antiAliasing) _antiAliasing = true;
            char buf[256];
            sprintf(buf,"/bin/echo \"Xft.dpi: %d\" | /usr/bin/xrdb -merge -quiet",xdpi);
            system(buf);
            sprintf(buf,"/bin/echo \"Xft.antialias: 1\" | /usr/bin/xrdb -merge -quiet");
            system(buf);
        }

      secureDisplay(disp);

      XCloseDisplay(disp);
    }
    else debug("Can't open display %s\n",dname?dname:"null");

    //KCrash::setFlags(KCrash::KeepFDs | KCrash::SaferDialog | KCrash::AlwaysDirectly);
    //KCrash::setApplicationName(QLatin1String(fakeArgv[0]));
    //KCrash::setDrKonqiEnabled(true);
    XSetIOErrorHandler(xIOErr);

    if (xdpi>120) {
        setenv("QT_AUTO_SCREEN_SCALE_FACTOR","1",1);
        qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
        //TODO: calc and set QT_SCREEN_SCALE_FACTORS (rounded xdpi/96.) instead of QT_AUTO_SCREEN_SCALE_FACTOR
    }

    //KComponentData inst(fakeArgv[0]);
    //foreach (const QString &dir, KGlobal::dirs()->resourceDirs("qtplugins"))
    //    QCoreApplication::addLibraryPath(dir);
    GreeterApp app(fakeArgc, fakeArgv);

    //alex: check real keyboard
    bool isKeyb=false;
    for (int i=0;i<20;i++) {
        struct stat st;
        char path[PATH_MAX];
        sprintf(path,"/sys/class/input/input%d/input%d::capslock",i,i);
        if (stat(path,&st)==0) {
            debug("keyboard found by '%s'\n",path);
            isKeyb=true;
            break;
        }
    }
    //alex: -------------------------- setup for touchscreen ---------
    isTouch = false;
    if (!isKeyb) {
        QList<const QTouchDevice *> tdl = QTouchDevice::devices();
        for (int i=0; i < tdl.size(); ++i)
        {
           if (tdl[i]->type()==QTouchDevice::TouchScreen)
           {
             debug("touchscreen %s\n",tdl[i]->name().toLocal8Bit().data());
             isTouch=true;
             break;
           }
        }
    }

    if (isTouch && xdpi>120) //alex
    {
        //debug("touchscreen found, FlyPlastiqueTablet in use\n");
        //if (_GUIStyle=="FlyPlastique") _GUIStyle = "FlyPlastiqueTablet";

        if (_useTheme && !_theme.isEmpty())
        {
            if (_theme=="/usr/share/fly-dm/themes/fly-flat")
            {
                _theme = "/usr/share/fly-dm/themes/fly-tablet-flat";
                debug("touchscreen found, use 'fly-tablet' theme instead of 'fly' %d\n",_showVkbd);
            }
            else if (_theme=="/usr/share/fly-dm/themes/fly")
            {
                _theme = "/usr/share/fly-dm/themes/fly-tablet";
                debug("touchscreen found, use 'fly-tablet' theme instead of 'fly' %d\n",_showVkbd);
            }
        }
    }

    //-------------------------------------------------------------------------
    if (!_GUIStyle.isEmpty()) app.setStyle(_GUIStyle); //alex: apply style

    initQAppConfig(); //alex: dont move it above app contructor due to ugly side effect: wrong label size calculation
    //KGlobalSettings::self()->activate(KGlobalSettings::ApplySettings);

    app.setFont(*_normalFont); //alex: apply font

    Display *dpy = QX11Info::display();
    QDesktopWidget *dw = app.desktop();

    if (_greeterScreen < 0)
    {
        _greeterScreen = _greeterScreen == -2 ?
            dw->screenNumber(QPoint(dw->width() - 1, 0)) :
            dw->screenNumber(QPoint(0, 0));
    }

	//alex: install translator
    QString lang = QString::fromUtf8(qgetenv("LANG")); //LANG was set in main() - form is ru_RU.UTF-8, en_US, etc.
    if (lang.isNull() || lang.isEmpty()) lang = QString::fromUtf8(qgetenv("LC_ALL"));
    if (lang.isNull() || lang.isEmpty()) lang = QString::fromUtf8(qgetenv("LANGUAGE"));
	if (lang.isNull() || lang.isEmpty()) //fallback to "ru", nothing or special check for Debian?
	{
		QFile f("/etc/default/locale");
		if (f.open(QIODevice::ReadOnly))
		{		
			QTextStream stream(&f);
			for (QString line=stream.readLine(); !line.isNull(); line=stream.readLine())
			{
			  line = line.simplified();
			  if (!line.startsWith('#') && line.contains("LANG="))
			  {
				  lang = line.section(QChar('='),1,1,QString::SectionSkipEmpty);
				  lang.remove(QChar('\"'));
				  break;
			  }
			}
		}
		else
		{
		  QFile f("/etc/locale.gen");
		  if (f.open(QIODevice::ReadOnly))
		  {		
			QTextStream stream(&f);
			for (QString line=stream.readLine(); !line.isNull(); line=stream.readLine())
			{
			  line = line.simplified();
			  if (!line.startsWith('#') && line.length()>2)
			  {
				  lang = line.section(QChar(' '),0,0,QString::SectionSkipEmpty);
				  break;
			  }
			}
		  }
		}
		if (!lang.isNull() && !lang.isEmpty())
		{
			setenv( "LANG",  lang.toLocal8Bit().data(), 1 );
			setlocale(LC_ALL,lang.toLocal8Bit().data());
		}
	}
	if (!lang.isNull() && !lang.isEmpty() && !lang.startsWith("en")) //alex: no translators in this case
	{
    QDir        tdir(QString::fromStdString(GetFlyDir(APP_TRANS_DIR)));
	QStringList filter(QString("*greet*") + "_" + (lang.isEmpty()?QString("ru"):lang.left(2)) + ".qm"); //i.e. k*greet*_ru.qm
	QStringList tlist = tdir.entryList(filter,QDir::Files|QDir::Readable);
	QStringListIterator iter(tlist);
	while (iter.hasNext())
	{
	    QString filename = iter.next();
	    filename.chop(3); //cut ".qm"?
	
	    QTranslator *trans = new QTranslator();
        trans->load( filename, QString::fromStdString(GetFlyDir(APP_TRANS_DIR)) );
	    app.installTranslator( trans );
    }
	}
/*
    _colorScheme = KStandardDirs::locate("data", "color-schemes/" + _colorScheme + ".colors");
    if (!_colorScheme.isEmpty()) {
        KSharedConfigPtr config = KSharedConfig::openConfig(_colorScheme, KConfig::SimpleConfig);
        app.setPalette(KGlobalSettings::createApplicationPalette(config));
    }
*/

    if (_theme.contains("flat")) QIcon::setThemeName("fly-astra-flat");

    KdmThemer *themer=nullptr;
    if (_useTheme && !_theme.isEmpty()) {
        QMap<QString, bool> showTypes;
        // "config" not implemented
#ifdef XDMCP
        if (_loginMode != LOGIN_LOCAL_ONLY)
            showTypes["chooser"] = true;
#endif
        showTypes["system"] = true;
        if (_allowShutdown != SHUT_NONE) {
            showTypes["halt"] = true;
            showTypes["reboot"] = true;
            // "suspend" not implemented
        }

        themer = new KdmThemer(_theme, showTypes, app.desktop()->screen());
        if (!themer->isOK()) {
            delete themer;
            themer = nullptr;
        }
    }

    setupModifiers(dpy, _numLockStatus);

    //secureDisplay(dpy); alex: moved above!

    /*alex: obsolete due to unable paint on desktop/root window with Qt5?
    QProcess *proc = nullptr;
    if (!_grabServer) {
        if (_useBackground && !themer) {
            // proc = new KProcess;
            // *proc << QByteArray(argv[0], strrchr(argv[0], '/') - argv[0] + 1) + "krootimage";
            // *proc << _backgroundCfg;
            //proc->start();
			proc = new QProcess(); //alex
			QStringList args;
            args << QString::fromLocal8Bit(_backgroundCfg);
            proc->start("/usr/bin/fly-dmrootimage",args);
		}
    }
    if (themer) {
        // Group by size to avoid rescaling images repeatedly
        QHash<QSize, QList<int> > scrns;
        for (int i = 0; i < dw->numScreens(); i++)
            scrns[dw->screenGeometry(i).size()] << i;

        QPixmap pm(dw->size());
        QPainter p(&pm);
        p.fillRect(dw->rect(), Qt::black);

        QSize gsz = dw->screenGeometry(_greeterScreen).size();

        // Paint these first, as throwing away their images does not hurt
        QHash<QSize, QList<int> >::ConstIterator it;
        for (it = scrns.constBegin(); it != scrns.constEnd(); ++it)
            if (it.key() != gsz)
                foreach (int i, it.value())
                    themer->paintBackground(&p, dw->screenGeometry(i), false);

        // If we are lucky, these will use the same images as the greeter
        foreach (int i, scrns.value(gsz))
            if (i != _greeterScreen)
                themer->paintBackground(&p, dw->screenGeometry(i), false);

        // Paint the greeter background last - it will be re-used.
        themer->paintBackground(&p, dw->screenGeometry(_greeterScreen), true);
        QPalette palette;
        palette.setBrush(dw->backgroundRole(), QBrush(pm));
        dw->setPalette(palette);

        XClearWindow(dpy, dw->winId()); //alex: not for qt5?
    }
*/
    //TODO: autostart items from /usr/share/fly-dm/autostart/greeter


  QString autostartPath = "/usr/share/fly-dm/autostart/greeter";
  QStringList filters; filters << "*.desktop";
  QDir autostartDir(autostartPath);
  QStringList autostartFileList = autostartDir.entryList(filters, QDir::Files);

  QStringList::Iterator it;
  for (it = autostartFileList.begin(); it != autostartFileList.end(); it++)
  {
    FlyDesktopEntry autostartDesktopEntry((autostartPath + "/" + *it).toStdString());
    if (autostartDesktopEntry.isValid()) {
        std::string autoStartExec = autostartDesktopEntry.exec();
        if (!autoStartExec.empty()) {
            QProcess *proc = new QProcess(&app);
            proc->start(QString::fromStdString(autoStartExec));
        }
    }
  }


    gSendInt(G_Ready);

    int rslt = ex_exit;
    for (;;) {
        int cmd = gRecvInt();

        if (cmd == G_ConfShutdown) {
            gSet(1);
            gSendInt(G_QryDpyShutdown);
            int how = gRecvInt(), uid = gRecvInt();
            QString os = qString(gRecvStr());
            gSet(0);
            app.markReady();
            KDMSlimShutdown::externShutdown(how, os, uid, true);
            gSendInt(G_Ready);
            break;
        }

        if (cmd == G_ErrorGreet) {
            app.markReady();
            if (KGVerify::handleFailVerify(qApp->desktop()->screen(_greeterScreen), true))
                break;
            _autoLoginDelay = 0;
            cmd = G_Greet;
        }

        QProcess *proc2 = nullptr; //alex
        app.markBusy();
        FDialog *dialog;
        bool chooserDialog=false; //alex
#ifdef XDMCP
        if (cmd == G_Choose) {
            dialog = new ChooserDlg;
            gSendInt(G_Ready); /* tell chooser to go into async mode */
            gRecvInt(); /* ack */
            chooserDialog=true; //alex
        } else
#endif
        {
            if ((cmd != G_GreetTimed && !_autoLoginAgain) ||
                    _autoLoginUser.isEmpty())
                _autoLoginDelay = 0;
            if (themer)
                dialog = new KThemedGreeter(themer);
            else
                dialog = new KStdGreeter;
            if (*_preloader) {
                proc2 = new QProcess; //alex
                //*proc2 << _preloader;
                proc2->start(QString::fromLocal8Bit(_preloader));
            }
        }


        if (isTouch && xdpi>120) dialog->setDefaultFirstSession("fly-tablet"); //alex
        
        dialog->setWindowTitle("fly-dm_greet"); //alex: to detect in fly-vkbd by this name
        //if (_showVkbd==VKBD_TRUE || (_showVkbd==VKBD_AUTO && isTouch)) dialog->slotVkbd(); //alex, moved to exec()


        QObject::connect(dialog, SIGNAL(ready()), &app, SLOT(markReady()));
        if (cmd != G_Choose) //alex: fly-dm will close greeter if unexpectedly get G_Interact command (4)
        app.enableSendInteract();
        debug("entering event loop\n");

        QScreen *primaryScr = app.primaryScreen();
        primaryScr->connect(primaryScr,SIGNAL(geometryChanged(const QRect &)),dialog,SLOT(slotScreenResized(const QRect &)));

        rslt = dialog->exec();
        debug("left event loop with result=\n",rslt);

        delete dialog;
        if (proc2) delete proc2;

        if (rslt==EX_RESERVE || rslt==EX_RESERVER_DPY //alex
#ifdef XDMCP
          || (chooserDialog && (rslt==EX_NORMAL || rslt==EX_RESERVE))
#endif
        )
        {
        KGVerify::done();
        //if (proc)   delete proc;
        if (themer) delete themer;
        return rslt;
        }
#ifdef XDMCP
        switch (rslt) {
        case ex_greet:
            gSendInt(G_DGreet);
            continue;
        case ex_choose:
            gSendInt(G_DChoose);
            continue;
        default:
            break;
        }
#endif
        break;
    }

    KGVerify::done();


    //if (proc)   delete proc;
    if (themer) delete themer;

    unsecureDisplay(dpy);
    restoreModifiers();

    if (rslt == ex_login) {
        gSendInt(G_Ready);
        KGVerify::handleFailVerify(qApp->desktop()->screen(_greeterScreen), false);
    }

    return EX_NORMAL;
}

//#include "kgapp.moc"
