Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ set(PROJECT_SOURCES
src/layoutmodel.h
src/environment.cpp
src/environment.h
src/settings.cpp
src/settings.h
src/theme.c
src/theme.h
src/xml.c
Expand Down
43 changes: 42 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@

#include <QApplication>
#include <QLibraryInfo>
#include <QMessageBox>
#include <QTranslator>
#include <QFileInfo>

#include "settings.h"

extern "C" {
#include "xml.h"
}

static void initLocale(QTranslator *qtTranslator, QTranslator *translator)
{
QApplication *app = qApp;
Expand Down Expand Up @@ -37,6 +44,30 @@ static void initLocale(QTranslator *qtTranslator, QTranslator *translator)
app->installTranslator(translator);
}

void initConfig(std::string &config_file)
{
bool success = xml_init(config_file.data());

if (!success) {
QMessageBox msgBox;
msgBox.setText(QObject::tr("Error loading ") + QString(config_file.data()));
msgBox.setInformativeText(
QObject::tr("Run labwc-tweaks from a terminal to view error messages"));
msgBox.exec();
exit(EXIT_FAILURE);
}

/* Ensure all relevant nodes exist before we start getting/setting */
xpath_add_node("/labwc_config/theme/cornerRadius");
xpath_add_node("/labwc_config/theme/name");
xpath_add_node("/labwc_config/theme/dropShadows");
xpath_add_node("/labwc_config/theme/icon");
xpath_add_node("/labwc_config/placement/policy");
xpath_add_node("/labwc_config/libinput/device/naturalScroll");

xml_save();
}

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Expand All @@ -45,7 +76,17 @@ int main(int argc, char *argv[])
QTranslator qtTranslator, translator;
initLocale(&qtTranslator, &translator);

MainDialog w;
std::string config_dir =
std::getenv("LABWC_CONFIG_DIR") ?: std::getenv("HOME") + std::string("/.config/labwc");
std::string config_file = config_dir + "/rc.xml";
initConfig(config_file);

// The 'settings' vector contains the master state of all settings that can
// be changed by labwc-tweaks.
std::vector<std::shared_ptr<Setting>> settings;
initSettings(settings);

MainDialog w(settings);
w.show();

// Make work the window icon also when the application is not (yet) installed
Expand Down
119 changes: 89 additions & 30 deletions src/maindialog.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <QDebug>
#include <QDir>
#include <QMessageBox>
#include <QFile>
#include <QString>
#include <QStandardPaths>
Expand All @@ -11,14 +10,16 @@
#include "evdev-lst-layouts.h"
#include "layoutmodel.h"
#include "maindialog.h"
#include "settings.h"
#include "./ui_maindialog.h"

extern "C" {
#include "theme.h"
#include "xml.h"
}

MainDialog::MainDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MainDialog)
MainDialog::MainDialog(std::vector<std::shared_ptr<Setting>> &settings, QWidget *parent)
: QDialog(parent), ui(new Ui::MainDialog), m_settings(settings)
{
ui->setupUi(this);

Expand All @@ -27,11 +28,6 @@ MainDialog::MainDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MainDialog
m_model = new LayoutModel(this);
ui->layoutView->setModel(m_model);

std::string config_dir =
std::getenv("LABWC_CONFIG_DIR") ?: std::getenv("HOME") + std::string("/.config/labwc");
std::string config_file = config_dir + "/rc.xml";
initConfig(config_file);

QObject::connect(ui->buttonBox, &QDialogButtonBox::clicked, [&](QAbstractButton *button) {
if (ui->buttonBox->standardButton(button) == QDialogButtonBox::Apply) {
onApply();
Expand Down Expand Up @@ -87,7 +83,7 @@ void MainDialog::activate()
theme_free_vector(&openbox_themes);

/* Corner Radius */
ui->cornerRadius->setValue(xml_get_int("/labwc_config/theme/cornerradius"));
ui->cornerRadius->setValue(xml_get_int("/labwc_config/theme/cornerRadius"));

/* Drop Shadows */
ui->dropShadows->addItem("no");
Expand Down Expand Up @@ -153,39 +149,102 @@ void MainDialog::activate()
}
}

void MainDialog::initConfig(std::string &config_file)
void setInt(std::vector<std::shared_ptr<Setting>> &settings, QString name, int value)
{
bool success = xml_init(config_file.data());
std::shared_ptr<Setting> setting = retrieve(settings, name);
if (setting == nullptr) {
qDebug() << "warning: no settings with name" << name;
return;
}
if (setting->valueType() != LAB_VALUE_TYPE_INT) {
qDebug() << "setInt(): not valid int setting" << name << value;
}
if (value != std::get<int>(setting->value())) {
qDebug() << name << "has changed to" << value;
xml_set_num(name.toStdString().c_str(), value);
}
}

if (!success) {
QMessageBox msgBox;
msgBox.setText(tr("Error loading ") + QString(config_file.data()));
msgBox.setInformativeText(tr("Run labwc-tweaks from a terminal to view error messages"));
msgBox.exec();
exit(EXIT_FAILURE);
void setStr(std::vector<std::shared_ptr<Setting>> &settings, QString name, QString value)
{
std::shared_ptr<Setting> setting = retrieve(settings, name);
if (setting == nullptr) {
qDebug() << "warning: no settings with name" << name;
return;
}
if (setting->valueType() != LAB_VALUE_TYPE_STRING) {
qDebug() << "setStr(): not valid string setting" << name << value;
}
if (value != std::get<QString>(setting->value())) {
qDebug() << name << "has changed to" << value;
xml_set(name.toStdString().c_str(), value.toStdString().c_str());
}
}

/* Ensure all relevant nodes exist before we start getting/setting */
xpath_add_node("/labwc_config/theme/cornerRadius");
xpath_add_node("/labwc_config/theme/name");
xpath_add_node("/labwc_config/theme/dropShadows");
xpath_add_node("/labwc_config/theme/name");
xpath_add_node("/labwc_config/placement/policy");
xpath_add_node("/labwc_config/libinput/device/naturalScroll");
/**
* parse_bool() - Parse boolean value of string.
* @string: String to interpret. This check is case-insensitive.
* @default_value: Default value to use if string is not a recognised boolean.
* Use -1 to avoid setting a default value.
*
* Return: 0 for false; 1 for true; -1 for non-boolean
*/
int parseBool(const char *str, int defaultValue)
{
if (!str)
goto error_not_a_boolean;
else if (!strcasecmp(str, "yes"))
return 1;
else if (!strcasecmp(str, "true"))
return 1;
else if (!strcasecmp(str, "on"))
return 1;
else if (!strcmp(str, "1"))
return 1;
else if (!strcasecmp(str, "no"))
return 0;
else if (!strcasecmp(str, "false"))
return 0;
else if (!strcasecmp(str, "off"))
return 0;
else if (!strcmp(str, "0"))
return 0;
error_not_a_boolean:
qDebug() << str << "is not a boolean value";
return defaultValue;
}

xml_save();
// TODO: make this more bool-ish
void setBool(std::vector<std::shared_ptr<Setting>> &settings, QString name, QString value)
{
std::shared_ptr<Setting> setting = retrieve(settings, name);
if (setting == nullptr) {
qDebug() << "warning: no settings with name" << name;
return;
}
if (setting->valueType() != LAB_VALUE_TYPE_BOOL) {
qDebug() << "setBool(): not valid bool setting" << name << value;
}
int boolValue = parseBool(value.toStdString().c_str(), -1);
if (boolValue != std::get<int>(setting->value())) {
qDebug() << name << "has changed to" << value;
xml_set(name.toStdString().c_str(), value.toStdString().c_str());
}
}

void MainDialog::onApply()
{
/* ~/.config/labwc/rc.xml */
xml_set_num("/labwc_config/theme/cornerradius", ui->cornerRadius->value());
xml_set("/labwc_config/theme/name", ui->openboxTheme->currentText().toLatin1().data());
xml_set("/labwc_config/theme/dropShadows", ui->dropShadows->currentText().toLatin1().data());
xml_set("/labwc_config/theme/icon", ui->iconTheme->currentText().toLatin1().data());
xml_set("/labwc_config/libinput/device/naturalscroll",
setInt(m_settings, "/labwc_config/theme/cornerRadius", ui->cornerRadius->value());
setStr(m_settings, "/labwc_config/theme/name",
ui->openboxTheme->currentText().toLatin1().data());
setBool(m_settings, "/labwc_config/theme/dropShadows",
ui->dropShadows->currentText().toLatin1().data());
setStr(m_settings, "/labwc_config/theme/icon", ui->iconTheme->currentText().toLatin1().data());
setBool(m_settings, "/labwc_config/libinput/device/naturalScroll",
ui->naturalScroll->currentText().toLatin1().data());
xml_set("/labwc_config/placement/policy", ui->placementPolicy->currentText().toLatin1().data());
setStr(m_settings, "/labwc_config/placement/policy",
ui->placementPolicy->currentText().toLatin1().data());
xml_save();

/* ~/.config/labwc/environment */
Expand Down
5 changes: 3 additions & 2 deletions src/maindialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define MAINDIALOG_H
#include <QDialog>
#include "layoutmodel.h"
#include "settings.h"

QT_BEGIN_NAMESPACE
namespace Ui {
Expand All @@ -14,7 +15,7 @@ class MainDialog : public QDialog
Q_OBJECT

public:
MainDialog(QWidget *parent = nullptr);
MainDialog(std::vector<std::shared_ptr<Setting>> &settings, QWidget *parent = nullptr);
~MainDialog();
void activate();
QStringList findIconThemes();
Expand All @@ -25,8 +26,8 @@ private slots:

private:
LayoutModel *m_model;
std::vector<std::shared_ptr<Setting>> &m_settings;

void initConfig(std::string &config_file);
void onApply();

Ui::MainDialog *ui;
Expand Down
88 changes: 88 additions & 0 deletions src/settings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <QDebug>
#include <variant>
#include "settings.h"

extern "C" {
#include "xml.h"
}

void initSettings(std::vector<std::shared_ptr<Setting>> &settings)
{
// Appearance
settings.push_back(std::make_shared<Setting>("/labwc_config/theme/name", LAB_FILE_TYPE_RCXML,
LAB_VALUE_TYPE_STRING, ""));
settings.push_back(std::make_shared<Setting>("/labwc_config/theme/cornerRadius",
LAB_FILE_TYPE_RCXML, LAB_VALUE_TYPE_INT, 8));
settings.push_back(std::make_shared<Setting>("/labwc_config/theme/dropShadows",
LAB_FILE_TYPE_RCXML, LAB_VALUE_TYPE_BOOL, 1));
settings.push_back(std::make_shared<Setting>("/labwc_config/theme/icon", LAB_FILE_TYPE_RCXML,
LAB_VALUE_TYPE_STRING, ""));

// Behaviour
settings.push_back(std::make_shared<Setting>("/labwc_config/placement/policy",
LAB_FILE_TYPE_RCXML, LAB_VALUE_TYPE_STRING,
"Cascade"));

// Mouse & Touchpad
settings.push_back(std::make_shared<Setting>("XCURSOR_THEME", LAB_FILE_TYPE_ENVIRONMENT,
LAB_VALUE_TYPE_STRING, "Adwaita"));
settings.push_back(std::make_shared<Setting>("XCURSOR_SIZE", LAB_FILE_TYPE_ENVIRONMENT,
LAB_VALUE_TYPE_INT, 24));
settings.push_back(std::make_shared<Setting>("/labwc_config/libinput/device/naturalScroll",
LAB_FILE_TYPE_RCXML, LAB_VALUE_TYPE_BOOL, 0));

// Language
settings.push_back(std::make_shared<Setting>("XKB_DEFAULT_LAYOUT", LAB_FILE_TYPE_ENVIRONMENT,
LAB_VALUE_TYPE_STRING, "us"));
}

Setting::Setting(QString name, enum settingFileType fileType, enum settingValueType valueType,
std::variant<int, QString> defaultValue)
: m_name(name), m_fileType(fileType), m_valueType(valueType), m_value(defaultValue)
{
m_valueOrigin = LAB_VALUE_ORIGIN_DEFAULT;

if (m_fileType == LAB_FILE_TYPE_RCXML) {
switch (m_valueType) {
case LAB_VALUE_TYPE_STRING: {
QString value = QString(xml_get(m_name.toStdString().c_str()));
if (value != std::get<QString>(m_value)) {
m_valueOrigin = LAB_VALUE_ORIGIN_USER_OVERRIDE;
m_value = value;
qDebug() << "USER OVERRIDE: " << m_name << "=" << value;
}
break;
}
case LAB_VALUE_TYPE_INT: {
int value = xml_get_int(m_name.toStdString().c_str());
if (value != std::get<int>(m_value)) {
m_valueOrigin = LAB_VALUE_ORIGIN_USER_OVERRIDE;
m_value = value;
qDebug() << "USER OVERRIDE: " << m_name << "=" << value;
}
break;
}
case LAB_VALUE_TYPE_BOOL: {
int value = xml_get_bool_text(m_name.toStdString().c_str());
if (value != std::get<int>(m_value)) {
m_valueOrigin = LAB_VALUE_ORIGIN_USER_OVERRIDE;
m_value = value;
qDebug() << "USER OVERRIDE: " << m_name << "=" << value;
}
break;
}
default:
break;
}
}
};

std::shared_ptr<Setting> retrieve(std::vector<std::shared_ptr<Setting>> &settings, QString name)
{
for (auto &setting : settings) {
if (name == setting->name()) {
return setting;
}
}
return nullptr;
}
Loading