feat: add an own lock screen with the bubble and your wallpaper
This commit is contained in:
1 parent
c693ca216c
commit
c228291520
44 files changed
+3891
-1033
No files matched your search
@@ -0,0 +1,180 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "wallpaper.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QRandomGenerator>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
// A picture, or one at random from a folder.
|
||||
QUrl picture(const QString &setting)
|
||||
{
|
||||
QString path = setting;
|
||||
if (path.startsWith(u"~/")) {
|
||||
path = QDir::homePath() + path.mid(1);
|
||||
}
|
||||
const QFileInfo info(path);
|
||||
if (setting.isEmpty() || !info.exists()) {
|
||||
return {};
|
||||
}
|
||||
if (info.isFile()) {
|
||||
return QUrl::fromLocalFile(info.absoluteFilePath());
|
||||
}
|
||||
const QStringList pictures = QDir(path).entryList({QStringLiteral("*.jpg"), QStringLiteral("*.jpeg"), QStringLiteral("*.png"), QStringLiteral("*.webp")},
|
||||
QDir::Files | QDir::Readable);
|
||||
if (pictures.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
return QUrl::fromLocalFile(QDir(path).absoluteFilePath(pictures.at(QRandomGenerator::global()->bounded(int(pictures.size())))));
|
||||
}
|
||||
|
||||
// What a command prints, or nothing when it is not there or hangs.
|
||||
QString run(const QString &program, const QStringList &args)
|
||||
{
|
||||
QProcess process;
|
||||
process.start(program, args);
|
||||
if (!process.waitForFinished(1000) || process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) {
|
||||
process.kill();
|
||||
process.waitForFinished(100);
|
||||
return {};
|
||||
}
|
||||
return QString::fromLocal8Bit(process.readAllStandardOutput());
|
||||
}
|
||||
|
||||
// The pictures the running wallpaper programs of this user show.
|
||||
QHash<QString, QString> desktop()
|
||||
{
|
||||
QHash<QString, QString> found;
|
||||
const uint me = getuid();
|
||||
const QStringList pids = QDir(QStringLiteral("/proc")).entryList({QStringLiteral("[0-9]*")}, QDir::Dirs);
|
||||
for (const QString &pid : pids) {
|
||||
const QString dir = QStringLiteral("/proc/") + pid;
|
||||
if (QFileInfo(dir).ownerId() != me) {
|
||||
continue;
|
||||
}
|
||||
QFile comm(dir + QStringLiteral("/comm"));
|
||||
if (!comm.open(QIODevice::ReadOnly)) {
|
||||
continue;
|
||||
}
|
||||
const QByteArray name = comm.readAll().trimmed();
|
||||
if (name == "swaybg") {
|
||||
QFile cmdline(dir + QStringLiteral("/cmdline"));
|
||||
if (cmdline.open(QIODevice::ReadOnly)) {
|
||||
QStringList args;
|
||||
for (const QByteArray &arg : cmdline.readAll().split('\0')) {
|
||||
args << QString::fromLocal8Bit(arg);
|
||||
}
|
||||
// Relative to where it was started.
|
||||
const QDir cwd(QFileInfo(dir + QStringLiteral("/cwd")).symLinkTarget());
|
||||
QHash<QString, QString> shown = Wallpaper::fromSwaybg(args.mid(1));
|
||||
for (QString &path : shown) {
|
||||
path = cwd.absoluteFilePath(path);
|
||||
}
|
||||
found.insert(shown);
|
||||
}
|
||||
} else if (name == "awww-daemon" || name == "swww-daemon") {
|
||||
found.insert(Wallpaper::fromAwww(run(QString::fromLatin1(name.left(4)), {QStringLiteral("query")})));
|
||||
} else if (name == "hyprpaper") {
|
||||
found.insert(Wallpaper::fromList(run(QStringLiteral("hyprctl"), {QStringLiteral("hyprpaper"), QStringLiteral("listactive")})));
|
||||
} else if (name == "wpaperd") {
|
||||
found.insert(Wallpaper::fromList(run(QStringLiteral("wpaperctl"), {QStringLiteral("all-wallpapers")})));
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
QHash<QString, QString> Wallpaper::fromSwaybg(const QStringList &args)
|
||||
{
|
||||
QHash<QString, QString> found;
|
||||
QString output;
|
||||
for (int i = 0; i < args.size(); ++i) {
|
||||
const QString &arg = args.at(i);
|
||||
const bool hasNext = i + 1 < args.size();
|
||||
if ((arg == u"-o" || arg == u"--output") && hasNext) {
|
||||
output = args.at(++i);
|
||||
} else if (arg.startsWith(u"--output=")) {
|
||||
output = arg.mid(9);
|
||||
} else if ((arg == u"-i" || arg == u"--image") && hasNext) {
|
||||
found.insert(output == u"*" ? QString() : output, args.at(++i));
|
||||
} else if (arg.startsWith(u"--image=")) {
|
||||
found.insert(output == u"*" ? QString() : output, arg.mid(8));
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
QHash<QString, QString> Wallpaper::fromAwww(const QString &text)
|
||||
{
|
||||
// "eDP-1: 1920x1080, scale: 1, currently displaying: image: /a/b.jpg",
|
||||
// with a namespace in front on awww. A plain colour is no picture.
|
||||
static const QRegularExpression line(QStringLiteral("([^\\s:]+): \\d+x\\d+,.*currently displaying: image: (.+)$"), QRegularExpression::MultilineOption);
|
||||
QHash<QString, QString> found;
|
||||
auto it = line.globalMatch(text);
|
||||
while (it.hasNext()) {
|
||||
const auto match = it.next();
|
||||
found.insert(match.captured(1), match.captured(2).trimmed());
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
QHash<QString, QString> Wallpaper::fromList(const QString &text)
|
||||
{
|
||||
// "eDP-1: /a/b.jpg", on older hyprpaper "eDP-1 = /a/b.jpg".
|
||||
static const QRegularExpression line(QStringLiteral("^([^\\s:=]+)(?:: | = )(/.+)$"), QRegularExpression::MultilineOption);
|
||||
QHash<QString, QString> found;
|
||||
auto it = line.globalMatch(text);
|
||||
while (it.hasNext()) {
|
||||
const auto match = it.next();
|
||||
found.insert(match.captured(1), match.captured(2).trimmed());
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
QHash<QString, QUrl> Wallpaper::forLock(const QString &setting)
|
||||
{
|
||||
QHash<QString, QUrl> pictures;
|
||||
if (setting.compare(u"none", Qt::CaseInsensitive) == 0) {
|
||||
return pictures;
|
||||
}
|
||||
if (!setting.isEmpty()) {
|
||||
const QUrl url = picture(setting);
|
||||
if (!url.isEmpty()) {
|
||||
pictures.insert(QString(), url);
|
||||
}
|
||||
return pictures;
|
||||
}
|
||||
const QHash<QString, QString> shown = desktop();
|
||||
for (auto it = shown.cbegin(); it != shown.cend(); ++it) {
|
||||
const QUrl url = picture(it.value());
|
||||
if (!url.isEmpty()) {
|
||||
pictures.insert(it.key(), url);
|
||||
}
|
||||
}
|
||||
return pictures;
|
||||
}
|
||||
|
||||
QUrl Wallpaper::pick(const QHash<QString, QUrl> &pictures, const QString &output)
|
||||
{
|
||||
if (pictures.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
if (pictures.contains(output)) {
|
||||
return pictures.value(output);
|
||||
}
|
||||
if (pictures.contains(QString())) {
|
||||
return pictures.value(QString());
|
||||
}
|
||||
// Named differently than here: some picture of the desktop is still
|
||||
// better than none.
|
||||
QStringList outputs = pictures.keys();
|
||||
outputs.sort();
|
||||
return pictures.value(outputs.first());
|
||||
}
|
||||
Reference in new issue
Block a user