#include <QLightDM/Language>
#include <QListWidgetItem>
+#include <QLightDM/usersmodel.h>
LoginPrompt::LoginPrompt(QLightDM::Greeter *greeter, QWidget *parent) :
QWidget(parent),
{
ui->setupUi(this);
ui->feedbackLabel->setText(QString());
-
- m_greeter->connectToServer();
-
+
ui->hostnameLabel->setText(m_greeter->hostname());
-
- QList<QLightDM::User*> users = m_greeter->users();
- foreach(QLightDM::User *user, users) {
- QListWidgetItem* item = new QListWidgetItem(user->displayName(), ui->userList);
- item->setData(Qt::UserRole, user->name());
- if(user->image().isEmpty()) {
- item->setIcon(QIcon::fromTheme("user-identity"));
- } else {
- item->setIcon(QIcon(user->image()));
- }
-
- }
+
+ QLightDM::UsersModel *usersModel = new QLightDM::UsersModel(greeter->config(), this);
+ ui->userListView->setModel(usersModel);
connect(ui->loginButton, SIGNAL(released()), SLOT(onLoginButtonClicked()));
connect(m_greeter, SIGNAL(authenticationComplete(bool)), SLOT(onAuthenticationComplete(bool)));
delete ui;
}
+
void LoginPrompt::onLoginButtonClicked()
{
ui->feedbackLabel->setText(QString());
- if (ui->userList->currentItem()) {
- m_greeter->startAuthentication(ui->userList->currentItem()->data(Qt::UserRole).toString());
+ if (ui->userListView->currentIndex().isValid()) {
+ m_greeter->startAuthentication(ui->userListView->currentIndex().data(Qt::UserRole).toString());
}
}
</widget>
</item>
<item>
- <widget class="QListWidget" name="userList"/>
+ <widget class="QListView" name="userListView"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
ui->powerOptionsButton->setMenu(powerMenu);
- ui->sessionCombo->setModel(m_greeter->sessionsModel());
+
+ QLightDM::SessionsModel* sessionsModel = new QLightDM::SessionsModel(this);
+ ui->sessionCombo->setModel(sessionsModel);
}
Panel::~Panel()
greeter_moc.cpp \
sessionsmodel_moc.cpp \
user_moc.cpp \
- config_moc.cpp
+ config_moc.cpp \
+ usersmodel_moc.cpp
greeter_moc.cpp: greeter.h
moc $< -o $@
moc $< -o $@
config_moc.cpp: config.h
moc $< -o $@
+usersmodel_moc.cpp: usersmodel.h
+ moc $< -o $@
liblightdm_qt_0include_HEADERS = \
sessionsmodel.h \
user.h \
config.h \
+ usersmodel.h \
Greeter \
Language \
SessionsModel \
sessionsmodel.cpp \
user.cpp \
config.cpp \
+ usersmodel.cpp \
$(MOC_FILES)
pkgconfigdir = $(libdir)/pkgconfig
--- /dev/null
+#include "QLightDM/usersmodel.h"
\ No newline at end of file
#include <QtCore/QSettings>
+#include <QDebug>
+
using namespace QLightDM;
class ConfigPrivate {
QObject(parent),
d (new ConfigPrivate())
{
+ qDebug() << "creating config";
+ qDebug() << this;
d->settings = new QSettings(filePath, QSettings::IniFormat, this);
+ qDebug() << d->settings;
+ qDebug() << d->settings->value("UserManager/load-users", QVariant(true)).toBool();
}
Config::~Config()
{
+ qDebug() << "deleting config";
+
delete d;
}
bool QLightDM::Config::loadUsers() const
{
+ qDebug() << this;
+ qDebug() << d->settings;
return d->settings->value("UserManager/load-users", QVariant(true)).toBool();
}
class ConfigPrivate;
-//Ideas:
-// This uses an sync method to get the filename to load from dbus. For bonus points we should make it async and emit a sort of "finsihed() signal"
+//Logic for loading file name should be here.
+//For bonus points it should be async.
namespace QLightDM
{
#include "config.h"
#include <security/pam_appl.h>
-#include <pwd.h>
-#include <errno.h>
#include <QtNetwork/QHostInfo> //needed for localHostName
#include <QtCore/QDebug>
SessionsModel *sessionsModel;
Config *config;
- QList<User*> users;
- bool haveUsers;
-
QDBusInterface* lightdmInterface;
QDBusInterface* powerManagementInterface;
QDBusInterface* consoleKitInterface;
{
d->readBuffer = (char *)malloc (HEADER_SIZE);
d->nRead = 0;
- d->haveUsers = false;
-
+ d->config = 0;
d->sessionsModel = new SessionsModel(this);
}
busType = QDBusConnection::sessionBus();
}
-
d->lightdmInterface = new QDBusInterface("org.lightdm.LightDisplayManager", "/org/lightdm/LightDisplayManager", "org.lightdm.LightDisplayManager", busType);
d->powerManagementInterface = new QDBusInterface("org.freedesktop.PowerManagement","/org/freedesktop/PowerManagement", "org.freedesktop.PowerManagement");
d->consoleKitInterface = new QDBusInterface("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit");
+ QString file;
+ file = d->lightdmInterface->property("ConfigFile").toString();
+ qDebug() << "Loading configuration from " << file;
+ d->config = new Config(file, this);
+
char* fd = getenv("LDM_TO_SERVER_FD");
if(!fd) {
qDebug() << "No LDM_TO_SERVER_FD environment variable";
flush();
- QString file;
- file = d->lightdmInterface->property("ConfigFile").toString();
- qDebug() << "Loading configuration from " << file;
- d->config = new Config(file, this);
+
}
void Greeter::startAuthentication(const QString &username)
return d->loginDelay;
}
-void Greeter::loadUsers()
-{
- QStringList hiddenUsers, hiddenShells;
- int minimumUid;
- QList<User*> users, oldUsers, newUsers, changedUsers;
-
- minimumUid = d->config->minimumUid();
- hiddenUsers = d->config->hiddenUsers();
- hiddenShells = d->config->hiddenShells();
-
- setpwent();
-
- while(TRUE)
- {
- struct passwd *entry;
- User *user;
- QStringList tokens;
- QString realName, image;
- QFile *imageFile;
- int i;
-
- errno = 0;
- entry = getpwent();
- if(!entry)
- break;
-
- /* Ignore system users */
- if(entry->pw_uid < minimumUid)
- continue;
-
- /* Ignore users disabled by shell */
- if(entry->pw_shell)
- {
- for(i = 0; i < hiddenShells.size(); i++)
- if(entry->pw_shell == hiddenShells.at(i))
- break;
- if(i < hiddenShells.size())
- continue;
- }
-
- /* Ignore certain users */
- for(i = 0; i < hiddenUsers.size(); i++)
- if(entry->pw_name == hiddenUsers.at(i))
- break;
- if(i < hiddenUsers.size())
- continue;
-
- tokens = QString(entry->pw_gecos).split(",");
- if(tokens.size() > 0 && tokens.at(i) != "")
- realName = tokens.at(i);
-
- QDir homeDir(entry->pw_dir);
- imageFile = new QFile(homeDir.filePath(".face"));
- if(!imageFile->exists())
- {
- delete imageFile;
- imageFile = new QFile(homeDir.filePath(".face.icon"));
- }
- if(imageFile->exists())
- image = "file://" + imageFile->fileName();
- delete imageFile;
-
- user = new User(entry->pw_name, realName, entry->pw_dir, image, FALSE);
-
- /* Update existing users if have them */
- bool matchedUser = false;
- foreach(User *info, d->users)
- {
- if(info->name() == user->name())
- {
- matchedUser = true;
- if(info->update(user->realName(), user->homeDirectory(), user->image(), user->isLoggedIn()))
- changedUsers.append(user);
- delete user;
- user = info;
- break;
- }
- }
- if(!matchedUser)
- {
- /* Only notify once we have loaded the user list */
- if(d->haveUsers)
- newUsers.append(user);
- }
- users.append(user);
- }
-
- if(errno != 0)
- qDebug() << "Failed to read password database: " << strerror(errno);
-
- endpwent();
-
- /* Use new user list */
- oldUsers = d->users;
- d->users = users;
-
- /* Notify of changes */
- foreach(User *user, newUsers)
- {
- qDebug() << "User " << user->name() << " added";
- emit userAdded(user);
- }
-
- foreach(User *user, changedUsers)
- {
- qDebug() << "User " << user->name() << " changed";
- emit userChanged(user);
- }
-
- foreach(User *user, oldUsers)
- {
- /* See if this user is in the current list */
- bool existing = false;
- foreach(User *new_user, d->users)
- {
- if (new_user == user)
- {
- existing = true;
- break;
- }
- }
-
- if(!existing)
- {
- qDebug() << "User " << user->name() << " removed";
- emit userRemoved(user);
- delete user;
- }
- }
-}
-
-void Greeter::updateUsers()
+Config* Greeter::config() const
{
- if (d->haveUsers) {
- return;
- }
-
- /** Load users if we need to. */
- if (d->config->loadUsers()) {
- loadUsers();
- }
-
- d->haveUsers = true;
-}
-
-QList<User*> Greeter::users()
-{
- updateUsers();
- return d->users;
+ return d->config;
}
-SessionsModel* Greeter::sessionsModel() const
-{
- return d->sessionsModel;
-}
-
-
bool Greeter::canSuspend() const
{
QDBusReply<bool> reply = d->powerManagementInterface->call("CanSuspend");
namespace QLightDM
{
- class SessionsModel;
+ class Config;
class Q_DECL_EXPORT Greeter : public QObject
{
QString timedLoginUser() const;
int timedLoginDelay() const;
- QList<QLightDM::User*> users();
-
QList<QLightDM::Language> languages() const;
QString defaultLanguage() const;
QString defaultLayout() const;
QString layout() const;
- //TODO why did I make this? the clients can just create a session model when they need to
- QLightDM::SessionsModel *sessionsModel() const;
+ QLightDM::Config *config() const;
+
QString defaultSession() const;
bool inAuthentication() const;
void showError(QString message);
void authenticationComplete(bool isAuthenticated);
void timedLogin(QString username);
- void userAdded(User *user);
- void userChanged(User *user);
- void userRemoved(User *user);
void quit();
private slots:
int getPacketLength();
int readInt(int *offset);
QString readString(int *offset);
- void loadUsers();
- void updateUsers();
};
};//end namespace
--- /dev/null
+#include "usersmodel.h"
+#include "user.h"
+#include "config.h"
+
+#include <pwd.h>
+#include <errno.h>
+
+#include <QtCore/QString>
+#include <QtCore/QFileSystemWatcher>
+#include <QtGui/QPixmap>
+
+using namespace QLightDM;
+
+class UsersModelPrivate {
+public:
+ QList<User*> users;
+ QLightDM::Config *config;
+};
+
+UsersModel::UsersModel(QLightDM::Config *config, QObject *parent) :
+ QAbstractListModel(parent),
+ d (new UsersModelPrivate())
+{
+ d->config = config;
+
+ if (d->config->loadUsers()) {
+ //load users on startup and if the password file changes.
+ QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
+ watcher->addPath("/etc/passwd"); //FIXME harcoded path
+ connect(watcher, SIGNAL(fileChanged(QString)), SLOT(loadUsers()));
+
+ loadUsers();
+ }
+}
+
+UsersModel::~UsersModel()
+{
+ delete d;
+}
+
+
+int UsersModel::rowCount(const QModelIndex &parent) const
+{
+ return d->users.count();
+}
+
+QVariant UsersModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ int row = index.row();
+ switch (role) {
+ case Qt::DisplayRole:
+ return d->users[row]->displayName();
+ case Qt::DecorationRole:
+ return QPixmap(d->users[row]->image());
+ }
+
+ return QVariant();
+}
+
+
+void UsersModel::loadUsers()
+{
+ QStringList hiddenUsers, hiddenShells;
+ int minimumUid;
+ QList<User*> newUsers;
+
+ minimumUid = d->config->minimumUid();
+ hiddenUsers = d->config->hiddenUsers();
+ hiddenShells = d->config->hiddenShells();
+ //FIXME accidently not got the "if contact removed" code. Need to fix.
+
+ setpwent();
+
+ while(TRUE)
+ {
+ struct passwd *entry;
+ User *user;
+ QStringList tokens;
+ QString realName, image;
+ QFile *imageFile;
+ int i;
+
+ errno = 0;
+ entry = getpwent();
+ if(!entry)
+ break;
+
+ /* Ignore system users */
+ if(entry->pw_uid < minimumUid)
+ continue;
+
+ /* Ignore users disabled by shell */
+ if(entry->pw_shell)
+ {
+ for(i = 0; i < hiddenShells.size(); i++)
+ if(entry->pw_shell == hiddenShells.at(i))
+ break;
+ if(i < hiddenShells.size())
+ continue;
+ }
+
+ /* Ignore certain users */
+ for(i = 0; i < hiddenUsers.size(); i++)
+ if(entry->pw_name == hiddenUsers.at(i))
+ break;
+ if(i < hiddenUsers.size())
+ continue;
+
+ tokens = QString(entry->pw_gecos).split(",");
+ if(tokens.size() > 0 && tokens.at(i) != "")
+ realName = tokens.at(i);
+
+
+ //replace this with QFile::exists();
+ QDir homeDir(entry->pw_dir);
+ imageFile = new QFile(homeDir.filePath(".face"));
+ if(!imageFile->exists())
+ {
+ delete imageFile;
+ imageFile = new QFile(homeDir.filePath(".face.icon"));
+ }
+ if(imageFile->exists()) {
+ image = "file://" + imageFile->fileName();
+ }
+ delete imageFile;
+
+ //FIXME don't create objects on the heap in the middle of a loop with breaks in it! Destined for fail.
+ //FIXME pointers all over the place in this code.
+ user = new User(entry->pw_name, realName, entry->pw_dir, image, false, this);
+
+ /* Update existing users if have them */
+ bool matchedUser = false;
+
+ for (int i=0; i < d->users.size(); i++)
+ {
+ User* info = d->users[i];
+ if(info->name() == user->name()) {
+ matchedUser = true;
+ info->update(user->realName(), user->homeDirectory(), user->image(), user->isLoggedIn());
+ dataChanged(createIndex(i, 0), createIndex(i,0));
+ delete user;
+ }
+ }
+ if(!matchedUser) {
+ newUsers.append(user);
+ }
+ }
+
+ if(errno != 0) {
+ qDebug() << "Failed to read password database: " << strerror(errno);
+ }
+
+ endpwent();
+
+ //FIXME accidently not got the "if contact removed" code. Need to restore that.
+ //should call beginRemoveRows, and then remove the row from the model.
+ //might get rid of "User" object, keep as private object (like sessionsmodel) - or make it copyable.
+
+
+ //append new users
+ if (newUsers.size() > 0) {
+ beginInsertRows(QModelIndex(), 0, newUsers.size());
+ d->users.append(newUsers);
+ endInsertRows();
+ }
+}
--- /dev/null
+#ifndef USERSMODEL_H
+#define USERSMODEL_H
+
+#include <QAbstractListModel>
+
+class UsersModelPrivate;
+
+namespace QLightDM
+{
+
+class Config;
+
+class Q_DECL_EXPORT UsersModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ explicit UsersModel(QLightDM::Config *config, QObject *parent = 0);
+ ~UsersModel();
+ int rowCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+
+signals:
+
+public slots:
+
+private slots:
+ void loadUsers();
+
+private:
+ UsersModelPrivate *d;
+};
+};
+
+#endif // USERSMODEL_H