From 073dee6c0b93b531b9567ec44ecdc6209a841c22 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 14 Nov 2017 12:39:18 +0100 Subject: Support autologin via guest session --- CMakeLists.txt | 28 +++++++++++++++------ src/global.cpp | 51 ++++++++++++++++++++++++++++++++++++++ src/global.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/loginform.cpp | 65 +++++++++++++++++------------------------------- src/loginform.h | 11 +++------ src/main.cpp | 46 +++++++++++++++++++++++----------- src/mainwindow.cpp | 7 ++++-- src/mainwindow.h | 2 +- src/settings.h | 1 + 9 files changed, 209 insertions(+), 74 deletions(-) create mode 100644 src/global.cpp create mode 100644 src/global.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e8f7a2e..e33c334 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +# Since some distro (debian) doesn't have a qt5 version of liblightdm-qt5, let's just ship it +OPTION(USE_INCLUDED_LDMQT "Use included liblightdm-qt" OFF) + PROJECT(qt-lightdm-greeter) set(CMAKE_CXX_STANDARD 11) @@ -8,9 +11,8 @@ set(CMAKE_BUILD_TYPE Debug) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) -file(GLOB_RECURSE SRCS src/*.cpp) -file(GLOB_RECURSE UIS src/*.ui) -#message(STATUS "SRCS ${SRCS}") +file(GLOB SRCS src/*.cpp) +file(GLOB UIS src/*.ui) find_package(Qt5Widgets REQUIRED) find_package(Qt5Svg REQUIRED) @@ -23,11 +25,21 @@ QT5_WRAP_UI(UI_HEADERS ${UIS}) # Some cmake versions can't understand the CMAKE_CXX_STANDARD option above? SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -include(FindPkgConfig) -pkg_check_modules(LIGHTDM_QT liblightdm-qt5-3) -if (NOT LIGHTDM_QT_INCLUDE_DIRS) - MESSAGE( FATAL_ERROR "Cannot find liblightdm-qt" ) -endif() +IF (USE_INCLUDED_LDMQT) + message( FATAL_ERROR "Using included liblightdm-qt is not implemented" ) + SET( LIGHTDM_QT_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src/liblightdm-qt" ) + SET( LIGHTDM_QT_LIBRARIES "" ) + FILE(GLOB LQT_SRCS src/liblightdm-qt/*.cpp) + SET( SRCS ${SRCS} ${LQT_SRCS} ) + # TODO + # pkg check modules liblightdm-gobject(-1)-dev +ELSE() + include(FindPkgConfig) + pkg_check_modules(LIGHTDM_QT liblightdm-qt5-3) + if (NOT LIGHTDM_QT_INCLUDE_DIRS) + MESSAGE( FATAL_ERROR "Cannot find liblightdm-qt" ) + endif() +ENDIF() include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/global.cpp b/src/global.cpp new file mode 100644 index 0000000..7039bc1 --- /dev/null +++ b/src/global.cpp @@ -0,0 +1,51 @@ +#include "global.h" +#include +#include +#include +#include +#include +#include + +bool Global::m_testMode = false; + +QLightDM::Greeter* Global::m_Greeter = nullptr; +QLightDM::PowerInterface* Global::m_Power = nullptr; +QLightDM::SessionsModel* Global::m_Sessions = nullptr; + +void Global::initGreeter() +{ + m_Greeter = new QLightDM::Greeter(); + if (!m_Greeter->connectSync()) { + m_Greeter->deleteLater(); + m_Greeter = nullptr; + } +} + +bool Global::autoLoginGuest() +{ + GreeterCb *cb = new GreeterCb(); + GreeterCb::connect(greeter(), SIGNAL(authenticationComplete()), cb, SLOT(authenticationComplete())); + GreeterCb::connect(greeter(), SIGNAL(autologinTimerExpired()), cb, SLOT(autologinTimerExpired())); + GreeterCb::connect(greeter(), SIGNAL(reset()), cb, SLOT(reset())); + qWarning() << "Trying to auth as guest"; + greeter()->authenticateAsGuest(); + QTimer::singleShot(3000, cb, SLOT(customTimeout())); + while (!cb->authComplete && !cb->authError && greeter()->inAuthentication()) { + QCoreApplication::instance()->processEvents(QEventLoop::AllEvents); + } + qWarning() << "Complete:" << cb->authComplete << "Error:" + << cb->authError << "InAuth:" << greeter()->inAuthentication() << "isAuthenticated" << greeter()->isAuthenticated(); + if (cb->authComplete && greeter()->isAuthenticated()) { + cb->deleteLater(); + return startSession(); + } + cb->deleteLater(); + return false; +} + +bool Global::startSession() +{ + QModelIndex i = sessions()->index(0, 0); + QString s = m_Sessions->data(i, QLightDM::SessionsModel::KeyRole).toString(); + return m_Greeter->startSessionSync(s); +} diff --git a/src/global.h b/src/global.h new file mode 100644 index 0000000..bdfda89 --- /dev/null +++ b/src/global.h @@ -0,0 +1,72 @@ +#ifndef GLOBAL_H_ +#define GLOBAL_H_ + +#include +#include +#include + +class Global { +public: + static inline QLightDM::Greeter* greeter() + { + if (!m_testMode && m_Greeter == nullptr) { + initGreeter(); + } + return m_Greeter; + } + + static inline QLightDM::PowerInterface* power() + { + if (!m_testMode && m_Power == nullptr) { + m_Power = new QLightDM::PowerInterface(); + } + return m_Power; + } + + static inline QLightDM::SessionsModel* sessions() + { + if (!m_testMode && m_Sessions == nullptr) { + m_Sessions = new QLightDM::SessionsModel(); + } + return m_Sessions; + } + + static inline void enableTestMode() + { + m_testMode = true; + } + + static inline bool testMode() + { + return m_testMode; + } + + static bool autoLoginGuest(); + + static bool startSession(); + +private: + static bool m_testMode; + static QLightDM::Greeter *m_Greeter; + static QLightDM::PowerInterface *m_Power; + static QLightDM::SessionsModel *m_Sessions; + + static void initGreeter(); + + Global() {}; +}; + +class GreeterCb : public QObject +{ + Q_OBJECT +public slots: + void authenticationComplete() { authComplete = true; } + void autologinTimerExpired() { authError = true; } + void reset() { authError = true; } + void customTimeout() { authError = true; } +public: + GreeterCb() : authComplete(false), authError(false) {} + bool authComplete, authError; +}; + +#endif /* GLOBAL_H_ */ diff --git a/src/loginform.cpp b/src/loginform.cpp index 2fb09df..c070f92 100644 --- a/src/loginform.cpp +++ b/src/loginform.cpp @@ -19,26 +19,13 @@ #include "loginform.h" #include "ui_loginform.h" #include "settings.h" +#include "global.h" -LoginForm::LoginForm(bool testMode, QWidget *parent) : +LoginForm::LoginForm(QWidget *parent) : QWidget(parent), ui(new Ui::LoginForm), - m_Greeter(nullptr), - power(nullptr), - sessionsModel(nullptr), clearMsg(false) { - if (!testMode) { - m_Greeter = new QLightDM::Greeter(this); - power = new QLightDM::PowerInterface(this); - sessionsModel = new QLightDM::SessionsModel(this); - } - - if (m_Greeter != nullptr && !m_Greeter->connectSync()) { - exit(0); - return; - } - ui->setupUi(this); initialize(); } @@ -64,9 +51,7 @@ void LoginForm::initialize() QPixmap icon(":/resources/bwlp.svg"); // This project came from Razor-qt ui->iconLabel->setPixmap(icon.scaled(ui->iconLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); - ui->leaveComboBox->setView(new QListView()); - //addLeaveEntry(power->canHibernate(), "system-suspend-hibernate", tr("Hibernate"), "hibernate"); - //addLeaveEntry(power->canSuspend(), "system-suspend", tr("Suspend"), "suspend"); + ui->leaveComboBox->setView(new QListView()); // This is required to get the stylesheet to apply cancelLoginTimer.setInterval(10000); cancelLoginTimer.setSingleShot(true); @@ -76,17 +61,16 @@ void LoginForm::initialize() hideMessageTimer.setSingleShot(true); connect(&hideMessageTimer, SIGNAL(timeout()), this, SLOT(hideMessage())); - if (m_Greeter != nullptr) { - ui->hostnameLabel->setText(m_Greeter->hostname()); + if (!Global::testMode()) { + ui->hostnameLabel->setText(Global::greeter()->hostname()); - addLeaveEntry(power->canShutdown(), "system-shutdown", tr("Shutdown"), "shutdown"); - addLeaveEntry(power->canRestart(), "system-reboot", tr("Restart"), "restart"); + addLeaveEntry(Global::power()->canShutdown(), "system-shutdown", tr("Shutdown"), "shutdown"); + addLeaveEntry(Global::power()->canRestart(), "system-reboot", tr("Restart"), "restart"); - //connect(ui->userInput, SIGNAL(editingFinished()), this, SLOT(userChanged())); connect(ui->leaveComboBox, SIGNAL(activated(int)), this, SLOT(leaveDropDownActivated(int))); - connect(m_Greeter, SIGNAL(showPrompt(QString, QLightDM::Greeter::PromptType)), this, SLOT(onPrompt(QString, QLightDM::Greeter::PromptType))); - connect(m_Greeter, SIGNAL(showMessage(QString, QLightDM::Greeter::MessageType)), this, SLOT(onMessage(QString, QLightDM::Greeter::MessageType))); - connect(m_Greeter, SIGNAL(authenticationComplete()), this, SLOT(onAuthenticationComplete())); + connect(Global::greeter(), SIGNAL(showPrompt(QString, QLightDM::Greeter::PromptType)), this, SLOT(onPrompt(QString, QLightDM::Greeter::PromptType))); + connect(Global::greeter(), SIGNAL(showMessage(QString, QLightDM::Greeter::MessageType)), this, SLOT(onMessage(QString, QLightDM::Greeter::MessageType))); + connect(Global::greeter(), SIGNAL(authenticationComplete()), this, SLOT(onAuthenticationComplete())); } ui->leaveComboBox->setDisabled(ui->leaveComboBox->count() <= 1); @@ -95,11 +79,11 @@ void LoginForm::initialize() void LoginForm::startAuthentication() { - if (m_Greeter == nullptr) { + if (Global::testMode()) { return; } - if (m_Greeter->inAuthentication()) { - m_Greeter->cancelAuthentication(); + if (Global::greeter()->inAuthentication()) { + Global::greeter()->cancelAuthentication(); } if (ui->userInput->text().isEmpty()) { ui->userInput->setFocus(); @@ -115,23 +99,23 @@ void LoginForm::startAuthentication() ui->userInput->setEnabled(false); ui->passwordInput->setEnabled(false); cancelLoginTimer.start(); - m_Greeter->authenticate(ui->userInput->text()); + Global::greeter()->authenticate(ui->userInput->text()); } void LoginForm::onPrompt(QString prompt, QLightDM::Greeter::PromptType promptType) { std::cerr << "Prompt: " << prompt.toStdString() << std::endl; - m_Greeter->respond(ui->passwordInput->text()); + Global::greeter()->respond(ui->passwordInput->text()); ui->passwordInput->clear(); } void LoginForm::leaveDropDownActivated(int index) { QString actionName = ui->leaveComboBox->itemData(index).toString(); - if (actionName == "shutdown") power->shutdown(); - else if (actionName == "restart") power->restart(); - else if (actionName == "hibernate") power->hibernate(); - else if (actionName == "suspend") power->suspend(); + if (actionName == "shutdown") Global::power()->shutdown(); + else if (actionName == "restart") Global::power()->restart(); + else if (actionName == "hibernate") Global::power()->hibernate(); + else if (actionName == "suspend") Global::power()->suspend(); } void LoginForm::onMessage(QString message, QLightDM::Greeter::MessageType type) @@ -150,13 +134,10 @@ void LoginForm::addLeaveEntry(bool canDo, QString iconName, QString text, QStrin void LoginForm::onAuthenticationComplete() { - if (m_Greeter->isAuthenticated()) { + if (Global::greeter()->isAuthenticated()) { std::cerr << "Auth complete, start session" << std::endl; showMessage(tr("Starting session..."), false); - QModelIndex i = sessionsModel->index(0, 0); - QString s = sessionsModel->data(i, QLightDM::SessionsModel::KeyRole).toString(); - std::cerr << s.toStdString() << std::endl; - if (m_Greeter->startSessionSync(s)) { + if (Global::startSession()) { cancelLoginTimer.stop(); } else { showMessage(tr("Cannot open session"), true); @@ -171,9 +152,9 @@ void LoginForm::onAuthenticationComplete() void LoginForm::cancelLogin() { std::cerr << "Cancel login" << std::endl; - if (m_Greeter->inAuthentication()) { + if (Global::greeter()->inAuthentication()) { std::cerr << "Was in authentication" << std::endl; - m_Greeter->cancelAuthentication(); + Global::greeter()->cancelAuthentication(); } cancelLoginTimer.stop(); ui->passwordInput->clear(); diff --git a/src/loginform.h b/src/loginform.h index 5e6f870..e414d2b 100644 --- a/src/loginform.h +++ b/src/loginform.h @@ -16,10 +16,11 @@ #include #include -#include #include -#include +namespace QLightDM { +class PowerInterface; +} namespace Ui { @@ -31,7 +32,7 @@ class LoginForm : public QWidget Q_OBJECT public: - explicit LoginForm(bool testMode, QWidget *parent = 0); + explicit LoginForm(QWidget *parent = nullptr); ~LoginForm(); virtual void setFocus(Qt::FocusReason reason); @@ -56,10 +57,6 @@ private: Ui::LoginForm *ui; - QLightDM::Greeter *m_Greeter; - QLightDM::PowerInterface *power; - QLightDM::SessionsModel *sessionsModel; - QMap powerSlots; QTimer cancelLoginTimer; diff --git a/src/main.cpp b/src/main.cpp index ece6b87..8eee16f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ #include "settings.h" #include "mainwindow.h" #include "x11util.h" +#include "global.h" static void messageHandler(QtMsgType type, const QMessageLogContext&, const QString& msg) { @@ -35,34 +36,49 @@ static inline int size(const QRect& r) int main(int argc, char *argv[]) { - //dup2(2, 1) + if (argc > 1 && QString(argv[1]) == QString("--test")) { + Global::enableTestMode(); + } + + QApplication a(argc, argv); + // I have no idea why, but Qt's stock qWarning() output never makes it // to /var/log/lightdm/x-0-greeter.log, so we use std::cerr instead.. qInstallMessageHandler(messageHandler); - QApplication a(argc, argv); - if (! Settings().iconThemeName().isEmpty()) { QIcon::setThemeName(Settings().iconThemeName()); } - // Build background for X server, in case we start a session that - // doesn't set one on its own this will make sure it's not simply - // black - QImage entire; - QSize desktopSize = QApplication::desktop()->size(); - qWarning() << "Desktop full size is " << desktopSize; - entire = QImage(desktopSize, QImage::Format_RGB32); - QPainter painter(&entire); + if (!Global::testMode() && !Settings().autoLoginCheckCmd().isEmpty()) { + QProcess p; + int ret = QProcess::execute(Settings().autoLoginCheckCmd()); + if (ret == 0) { + if (Global::autoLoginGuest()) { + qWarning() << "Guest login ok"; + return a.exec(); + // TODO: Background? + } else { + qWarning() << "Guest login failed"; + // TODO: Set error message, display somewhere + } + } + } - const bool testMode = argc > 1 && QString(argv[1]) == QString("--test"); + // Build background for X server, in case we start a session that + // doesn't set one on its own this will make sure it's not simply + // black + QImage entire; // Get a list of non-overlapping screens, as this might lead to a broken // greeter with main windows covering other login forms QMap screens; - if (testMode) { + if (Global::testMode()) { screens.insert(0, QRect(0, 0, 1024, 768)); } else { + QSize desktopSize = QApplication::desktop()->size(); + qWarning() << "Desktop full size is " << desktopSize; + entire = QImage(desktopSize, QImage::Format_RGB32); for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { QRect r = QApplication::desktop()->screenGeometry(i); QMutableMapIteratorit(screens); @@ -83,6 +99,7 @@ int main(int argc, char *argv[]) skip_rect: ; // Do nothing } } + // Determine primary screen int primary; if (screens.contains(QApplication::desktop()->primaryScreen())) { @@ -94,11 +111,12 @@ int main(int argc, char *argv[]) } // Now set up all the screens + QPainter painter(&entire); MainWindow *focusWindow = 0; QMapIterator it(screens); while (it.hasNext()) { it.next(); - MainWindow *w = new MainWindow(primary == it.key(), it.key(), it.value(), testMode); + MainWindow *w = new MainWindow(primary == it.key(), it.key(), it.value()); w->show(); if (w->showLoginForm()) { focusWindow = w; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3307ef8..2eb84c9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -23,7 +23,7 @@ static const Settings _settings; -MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, bool testMode, QWidget *parent) : +MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, QWidget *parent) : QWidget(parent), m_ScreenRect(screenRect), m_Primary(primary), @@ -35,12 +35,15 @@ MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, bool t setBackground(); + // TODO: Check if testMode == false and greeter == NULL, if so display big error message + // instead of exiting/crashing + // display login dialog only in the main screen int spaceY = screenRect.height() / 2; if (showLoginForm()) { - m_LoginForm = new LoginForm(testMode, this); + m_LoginForm = new LoginForm(this); spaceY -= m_LoginForm->height() / 2; int maxX = screenRect.width() - m_LoginForm->width(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 42d494e..ccaa073 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -27,7 +27,7 @@ class MainWindow : public QWidget Q_OBJECT public: - explicit MainWindow(bool primary, int screen, const QRect &rect, bool testMode, QWidget *parent = 0); + explicit MainWindow(bool primary, int screen, const QRect &rect, QWidget *parent = 0); ~MainWindow(); void setFocus(Qt::FocusReason reason); diff --git a/src/settings.h b/src/settings.h index 81b1381..0a03567 100644 --- a/src/settings.h +++ b/src/settings.h @@ -18,6 +18,7 @@ public: QString bottomLeftLogoPath() const { return value("greeter-bottom-left-logo-path").toString(); } QStringList gradientColors() const { return value("greeter-background-gradient").toString().split(QRegExp("\\s"), QString::SkipEmptyParts); } QString logMessageFile() const { return value("greeter-message-file").toString(); } + QString autoLoginCheckCmd() const { return value("auto-login-check-cmd").toString(); } }; -- cgit v1.2.3-55-g7522