File indexing completed on 2024-05-12 05:29:27

0001 // SPDX-FileCopyrightText: 2019, 2022 Mikhail Zolotukhin <zomial@protonmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0003 
0004 #include "xsettings.h"
0005 
0006 #include <unistd.h>
0007 
0008 #include <QDir>
0009 #include <QProcess>
0010 #include <QRegularExpression>
0011 #include <QStandardPaths>
0012 
0013 #include <csignal>
0014 #include <glib.h>
0015 
0016 #include "config_editor/utils.h"
0017 
0018 namespace
0019 {
0020 constinit unsigned s_applyId = 0;
0021 
0022 void replaceValueInXSettingsdContents(QString &xSettingsdContents, const QString &paramName, const QVariant &paramValue)
0023 {
0024     const QRegularExpression regExp(paramName + QStringLiteral(" [^\n]*($|\n)"));
0025 
0026     QString newConfigString;
0027     if (paramValue.type() == QVariant::Type::String) {
0028         newConfigString = QStringLiteral("%1 \"%2\"\n").arg(paramName, paramValue.toString());
0029     } else if (paramValue.type() == QVariant::Type::Bool) {
0030         // XSettigsd does not support 'true' and 'false' as values
0031         newConfigString = QStringLiteral("%1 %2\n").arg(paramName, QString::number(paramValue.toInt()));
0032     } else {
0033         newConfigString = QStringLiteral("%1 %2\n").arg(paramName, paramValue.toString());
0034     }
0035 
0036     if (paramValue.isNull()) {
0037         // unset value
0038         xSettingsdContents.replace(regExp, QString());
0039     } else if (xSettingsdContents.contains(regExp)) {
0040         xSettingsdContents.replace(regExp, newConfigString);
0041     } else {
0042         xSettingsdContents = newConfigString + xSettingsdContents;
0043     }
0044 }
0045 
0046 pid_t pidOfXSettingsd()
0047 {
0048     QProcess pgrep;
0049     pgrep.start(QStringLiteral("pgrep"),
0050                 QStringList{
0051                     QStringLiteral("-u"),
0052                     QString::number(getuid()),
0053                     QStringLiteral("-n"), // select most recently started
0054                     QStringLiteral("xsettingsd"),
0055                 });
0056     pgrep.waitForFinished();
0057     QString xsettingsdPid = QString(pgrep.readAllStandardOutput()).remove('\n');
0058     return xsettingsdPid.toInt();
0059 }
0060 
0061 #if GLIB_CHECK_VERSION(2, 74, 0)
0062 void reloadXSettingsd(void *)
0063 #else
0064 int reloadXSettingsd(void *)
0065 #endif
0066 {
0067     pid_t xSettingsdPid = pidOfXSettingsd();
0068     if (xSettingsdPid == 0) {
0069         QProcess::startDetached(QStandardPaths::findExecutable(QStringLiteral("xsettingsd")), QStringList());
0070     } else {
0071         kill(xSettingsdPid, SIGHUP);
0072     }
0073 
0074     s_applyId = 0;
0075 #if !GLIB_CHECK_VERSION(2, 74, 0)
0076     return G_SOURCE_REMOVE;
0077 #endif
0078 }
0079 
0080 }
0081 
0082 namespace XSettingsEditor
0083 {
0084 
0085 void setValue(const QString &paramName, const QVariant &paramValue)
0086 {
0087     QString configLocation = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
0088 
0089     QDir xsettingsdPath = configLocation + QStringLiteral("/xsettingsd");
0090     if (!xsettingsdPath.exists()) {
0091         xsettingsdPath.mkpath(QStringLiteral("."));
0092     }
0093 
0094     QString xSettingsdConfigPath = xsettingsdPath.path() + QStringLiteral("/xsettingsd.conf");
0095 
0096     QFile xSettingsdConfig(xSettingsdConfigPath);
0097     QString xSettingsdConfigContents = Utils::readFileContents(xSettingsdConfig);
0098     replaceValueInXSettingsdContents(xSettingsdConfigContents, paramName, paramValue);
0099     xSettingsdConfig.remove();
0100     xSettingsdConfig.open(QIODevice::WriteOnly | QIODevice::Text);
0101     xSettingsdConfig.write(xSettingsdConfigContents.toUtf8());
0102 
0103     if (s_applyId == 0) {
0104 #if GLIB_CHECK_VERSION(2, 74, 0)
0105         s_applyId = g_timeout_add_once(100, reloadXSettingsd, nullptr);
0106 #else
0107         s_applyId = g_timeout_add(100, reloadXSettingsd, nullptr);
0108 #endif
0109     }
0110 }
0111 
0112 void unsetValue(const QString &paramName)
0113 {
0114     setValue(paramName, QVariant());
0115 }
0116 }