util: Add coreboot-configurator

A simple GUI to change settings in coreboot's CBFS, via the nvramtool utility.

Test on the StarBook Mk IV running coreboot 4.15 with:
* Ubuntu 20.04
* Ubuntu 21.10
* MX Linux 21
* elementary OS 6
* Manjaro 21

Signed-off-by: Sean Rhodes <sean@starlabs.systems>
Change-Id: I491922bf55ed87c2339897099634a38f8d055876
Reviewed-on: https://review.coreboot.org/c/coreboot/+/59256
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
Sean Rhodes
2021-11-12 08:54:50 +00:00
committed by Martin Roth
parent aef6de3426
commit 9c89e3ada2
34 changed files with 2722 additions and 0 deletions

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include "AboutDialog.h"
#include "NvramToolCli.h"
#include "ui_AboutDialog.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
ui->logoLabel->setPixmap(QPixmap(":/images/star.svg"));
ui->versionLabel->setText("<tt>"+NvramToolCli::version()+"</tt>");
}
AboutDialog::~AboutDialog()
{
delete ui;
}

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
#include <QDialog>
namespace Ui {
class AboutDialog;
}
class AboutDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(QWidget *parent = nullptr);
~AboutDialog();
private:
Ui::AboutDialog *ui;
};

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>412</width>
<height>273</height>
</rect>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;coreboot configurator&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="logoLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="aboutDescriptionLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A simple GUI to change settings in coreboot's CBFS, via the nvramtool utility.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="versionLabel">
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="emailLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://support.starlabs.systems&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;starlabs.systems&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <QFile>
#include <QString>
#include <QTextStream>
#include "Configuration.h"
#include "Util.h"
QMap<QString, QString> Configuration::fromFile(const QString &curr_path)
{
QFile curr_file(curr_path);
if ( !curr_file.open(QFile::ReadOnly)
|| !curr_file.isReadable()
|| curr_file.atEnd()) {
return {};
}
auto result = Util::parseParameters(curr_file);
curr_file.close();
return result;
}
bool Configuration::toFile(const QString &curr_path, const Parameters &params)
{
QFile output(curr_path);
if(!output.open(QFile::WriteOnly|QFile::Truncate)){
return false;
}
QTextStream outStream(&output);
for(auto it = params.begin(); it != params.end(); ++it){
outStream << it.key() << " = " << it.value() << "\n";
}
output.close();
return true;
}

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
#include <QFile>
#include <QMap>
#include <QObject>
#include <QString>
namespace Configuration {
using Parameters = QMap<QString,QString>;
Parameters fromFile(const QString& curr_path);
bool toFile(const QString& curr_path, const Parameters& params);
}

View File

@ -0,0 +1,388 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <QFileDialog>
#include <QHeaderView>
#include <QLabel>
#include <QMessageBox>
#include <QShortcut>
#include <QtGui>
#include "AboutDialog.h"
#include "Configuration.h"
#include "MainWindow.h"
#include "NvramToolCli.h"
#include "ToggleSwitch.h"
#include "ui_MainWindow.h"
static auto s_errorWindowTitle = MainWindow::tr("Error Occured");
static auto s_nvramErrorMessage = MainWindow::tr("Nvramtool was not able to access cmos settings. Look at documentation for possible causes of errors.");
QString makeNvramErrorMessage(const QString& error){
if(!error.trimmed().isEmpty()){
return QString(MainWindow::tr("%1<br><br>Error message:<br><tt>%2</tt>")).arg(s_nvramErrorMessage,
Qt::convertFromPlainText(error));
}
return s_nvramErrorMessage;
}
namespace YAML {
template <>
struct convert<QString>{
static Node encode(const QString& rhs) { return Node(rhs.toUtf8().data()); }
static bool decode(const Node& node, QString& rhs) {
if (!node.IsScalar())
return false;
rhs = QString::fromStdString(node.Scalar());
return true;
}
};
}
static auto s_metadataErrorMessage = MainWindow::tr("Can't load categories metadata file. Check your installation.");
static constexpr char s_sudoProg[] = "/usr/bin/pkexec";
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->actionAbout, &QAction::triggered, this, [](){
AboutDialog().exec();
});
#if MOCK
this->setWindowTitle("coreboot configurator "+tr("[MOCKED DATA]"));
#else
this->setWindowTitle("coreboot configurator");
#endif
this->setWindowIcon(QIcon::fromTheme("coreboot_configurator"));
QFile catFile(":/config/categories.yaml");
if(!catFile.open(QFile::ReadOnly)){
QMessageBox::critical(this, s_errorWindowTitle, s_metadataErrorMessage);
this->close();
return;
}
m_categories = YAML::Load(catFile.readAll());
if(m_categories.IsNull() || !m_categories.IsDefined()){
QMessageBox::critical(this, s_errorWindowTitle, s_metadataErrorMessage);
this->close();
return;
}
QShortcut* returnAction = new QShortcut(QKeySequence("Ctrl+Return"), this);
connect(returnAction, &QShortcut::activated, this, &MainWindow::on_saveButton_clicked);
generateUi();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::pullSettings()
{
QString error;
m_parameters = NvramToolCli::readParameters(&error);
if(m_parameters.isEmpty()){
QMessageBox::critical(this, s_errorWindowTitle, makeNvramErrorMessage(error));
/* we need delayed close as initialization error happened before event loop start so we can't stop application properly */
QTimer::singleShot(0, this, &MainWindow::close);
}
}
void MainWindow::pushSettings()
{
QString error;
if(!NvramToolCli::writeParameters(m_parameters, &error)){
QMessageBox::critical(this, s_errorWindowTitle, makeNvramErrorMessage(error));
}
}
QComboBox* MainWindow::createComboBox(const QString& key) {
auto box = new QComboBox(this);
auto opts = NvramToolCli::readOptions(key);
box->addItems(opts);
box->setCurrentText(m_parameters[key]);
connect(ui->advancedModeCheckBox, &QCheckBox::clicked, this, [box](bool clicked){
box->setEditable(clicked);
});
connect(this, &MainWindow::updateValue, this, [box, this, key](const QString& name){
if(key!=name || m_parameters[name]==box->currentText()){
return;
}
box->setCurrentText(m_parameters[name]);
});
connect(box, &QComboBox::currentTextChanged, this, [key, this](const QString& value){
if(value==m_parameters[key]){
return;
}
m_parameters[key] = value;
emit updateValue(key);
});
return box;
}
QString boolToString(bool value){
return value?QStringLiteral("Enable"):QStringLiteral("Disable");
}
bool stringToBool(const QString& str){
return str==QStringLiteral("Enable");
}
QCheckBox* MainWindow::createCheckBox(const QString& key) {
auto box = new ToggleSwitch(this);
box->setChecked(stringToBool(m_parameters[key]));
connect(this, &MainWindow::updateValue, this, [box, this, key](const QString& name){
if(key!=name || m_parameters[name]==boolToString(box->isChecked())){
return;
}
auto newValue = stringToBool(m_parameters[name]);
box->setChecked(newValue);
});
connect(box, &QCheckBox::clicked, this, [key, this](bool checked){
auto value = boolToString(checked);
if(value==m_parameters[key]){
return;
}
m_parameters[key] = value;
emit updateValue(key);
});
return box;
}
QTableWidget *MainWindow::createRawTable()
{
/* Create Raw values table */
auto table = new QTableWidget(m_parameters.size(), 2);
table->setHorizontalHeaderLabels({tr("Key"), tr("Value")});
table->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Stretch);
table->verticalHeader()->hide();
table->setSelectionBehavior(QTableWidget::SelectRows);
connect(table, &QTableWidget::cellChanged, this, [table, this](int row, int column){
if(column != 1 || row >= table->rowCount() || row < 0 ){
/* Weird state when changed cell is not a value cell */
return;
}
auto keyItem = table->item(row, 0);
auto valueItem = table->item(row, 1);
if(keyItem == nullptr || valueItem == nullptr){
/* Invalid cells */
return;
}
if(valueItem->text()==m_parameters[keyItem->text()]){
return;
}
m_parameters[keyItem->text()] = valueItem->text();
emit updateValue(keyItem->text());
});
auto it = m_parameters.begin();
for(int i = 0; i<m_parameters.size(); i++, ++it){
auto item = new QTableWidgetItem(it.key());
item->setFlags(item->flags() ^ Qt::ItemIsEditable);
table->setItem(i,0,item);
item = new QTableWidgetItem(it.value());
connect(this, &MainWindow::updateValue, this, [item, it, this](const QString& name){
if(it.key()!=name || m_parameters[name]==item->text()){
return;
}
item->setText(m_parameters[name]);
});
table->setItem(i,1,item);
}
return table;
}
void MainWindow::generateUi()
{
pullSettings();
if(!m_categories.IsMap()){
return;
}
for(const auto& category : m_categories){
if(!category.second.IsMap()){
continue;
}
auto name = category.second["displayName"].as<QString>();
auto layout = new QVBoxLayout;
auto tabPage = new QWidget(this);
tabPage->setLayout(layout);
ui->centralTabWidget->addTab(tabPage, name);
for(const auto& value : category.second){
if(!value.second.IsMap() || !m_parameters.contains(value.first.as<QString>())){
continue;
}
auto displayName = value.second["displayName"];
if(!displayName.IsDefined()){
continue;
}
auto type = value.second["type"];
if(!type.IsDefined()){
continue;
}
auto controlLayout = new QHBoxLayout();
auto help = value.second["help"];
if(help.IsDefined()){
auto labelWithTooltip = new QWidget;
labelWithTooltip->setToolTip(help.as<QString>());
labelWithTooltip->setCursor({Qt::WhatsThisCursor});
labelWithTooltip->setLayout(new QHBoxLayout);
auto helpButton = new QLabel();
helpButton->setPixmap(QIcon::fromTheme("help-hint").pixmap(16,16));
{
auto layout = qobject_cast<QHBoxLayout*>(labelWithTooltip->layout());
layout->addWidget(new QLabel(displayName.as<QString>()));
layout->addWidget(helpButton,1);
}
controlLayout->addWidget(labelWithTooltip, 0);
} else {
controlLayout->addWidget(new QLabel(displayName.as<QString>()), 0);
}
controlLayout->addStretch(1);
QWidget* res = nullptr;
if(type.as<QString>() == QStringLiteral("bool")){
res = createCheckBox(value.first.as<QString>());
} else if (type.as<QString>() == QStringLiteral("enum")){
res = createComboBox(value.first.as<QString>());
} else {
controlLayout->deleteLater();
continue;
}
res->setObjectName(value.first.as<QString>());
controlLayout->addWidget(res, 0);
layout->addLayout(controlLayout);
}
}
auto table = createRawTable();
connect(ui->advancedModeCheckBox, &QCheckBox::clicked, this, [table,this](bool clicked){
if(clicked && ui->centralTabWidget->widget(ui->centralTabWidget->count()-1) != table){
ui->centralTabWidget->addTab(table, tr("Raw"));
} else if(!clicked && ui->centralTabWidget->widget(ui->centralTabWidget->count()-1) == table) {
ui->centralTabWidget->removeTab(ui->centralTabWidget->count()-1);
}
});
}
void MainWindow::askForReboot()
{
QMessageBox rebootDialog(QMessageBox::Question,
tr("Reboot"),
tr("Changes are saved. Do you want to reboot to apply changes?"));
auto nowButton = rebootDialog.addButton(tr("Reboot now"), QMessageBox::AcceptRole);
rebootDialog.addButton(tr("Reboot later"), QMessageBox::RejectRole);
rebootDialog.exec();
if(rebootDialog.clickedButton()==nowButton){
QProcess::startDetached(s_sudoProg, {"/usr/bin/systemctl", "reboot"});
this->close();
}
}
void MainWindow::readSettings(const QString &fileName)
{
if(fileName.isEmpty()){
return;
}
auto configValues = Configuration::fromFile(fileName);
for(auto it = configValues.begin(); it != configValues.end(); ++it){
if(!m_parameters.contains(it.key())){
continue;
}
m_parameters[it.key()]=it.value();
emit updateValue(it.key());
}
}
void MainWindow::writeSettings(const QString &fileName)
{
if(fileName.isEmpty()){
return;
}
if(!Configuration::toFile(fileName, m_parameters)){
QMessageBox::critical(this, tr("Error Occured"), tr("Can't open file to write"));
this->close();
}
}
void MainWindow::on_actionSave_triggered()
{
auto filename = QFileDialog::getSaveFileName(this,
tr("Select File To Save"),
QDir::homePath(),
tr("Coreboot Configuration Files")+"(*.cfg)");
writeSettings(filename);
}
void MainWindow::on_actionLoad_triggered()
{
auto filename = QFileDialog::getOpenFileName(this,
tr("Select File To Load"),
QDir::homePath(),
tr("Coreboot Configuration Files")+"(*.cfg)");
readSettings(filename);
}
void MainWindow::on_saveButton_clicked()
{
ui->centralwidget->setEnabled(false);
ui->menubar->setEnabled(false);
pushSettings();
askForReboot();
ui->centralwidget->setEnabled(true);
ui->menubar->setEnabled(true);
}

View File

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
#include <Configuration.h>
#include <QCheckBox>
#include <QComboBox>
#include <QMainWindow>
#include <QString>
#include <QTableWidget>
#include <yaml-cpp/yaml.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void updateValue(const QString& key);
private slots:
void on_actionSave_triggered(void);
void on_actionLoad_triggered(void);
void on_saveButton_clicked(void);
private:
void pullSettings(void);
void pushSettings(void);
void generateUi(void);
void askForReboot(void);
void readSettings(const QString& fileName);
void writeSettings(const QString& fileName);
Configuration::Parameters m_parameters;
YAML::Node m_categories;
Ui::MainWindow *ui;
QComboBox *createComboBox(const QString &key);
QCheckBox *createCheckBox(const QString &key);
QTableWidget *createRawTable();
};

View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>400</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>600</width>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>600</width>
<height>400</height>
</size>
</property>
<property name="windowTitle">
<string>coreboot configurator</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="centralTabWidget"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="advancedModeCheckBox">
<property name="text">
<string>Advanced mode</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="saveButton">
<property name="text">
<string>Save</string>
</property>
<property name="icon">
<iconset theme="document-save-symbolic"/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionSave"/>
<addaction name="actionLoad"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="actionAbout"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuHelp"/>
</widget>
<action name="actionSave">
<property name="text">
<string>Save to File...</string>
</property>
</action>
<action name="actionLoad">
<property name="text">
<string>Load from File...</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>About...</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,120 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <QProcess>
#include <QTextStream>
#include "NvramToolCli.h"
#include "Util.h"
static constexpr char s_sudoProg[] = "/usr/bin/pkexec";
static constexpr char s_nvramToolProg[] = "/usr/sbin/nvramtool";
#if MOCK
QMap<QString, QString> NvramToolCli::readParameters(QString *error) {
return QMap<QString,QString>({
{"boot_option","Normal"},
{"reboot_counter","0x0"},
{"debug_level","Spew"},
{"vtd","Enable"},
{"power_profile","Performance"},
{"wireless","Enable"},
{"webcam","Enable"},
{"microphone","Enable"},
{"legacy_8254_timer","Enable"},
{"usb_always_on","Disable"},
{"kbl_timeout","Never"},
{"fn_ctrl_swap","Enable"},
{"max_charge","100%"},
{"power_on_after_fail","Disable"},
{"fn_lock_state","0x2"},
{"trackpad_state","0x40"},
{"kbl_brightness","0xc4"},
{"kbl_state","0x22"}
});
}
QStringList NvramToolCli::readOptions(const QString &parameter, QString *error){
return (parameter=="power_profile")?
QStringList{
"Power Saver","Balanced","Performance"
} : QStringList{};
}
#else
QMap<QString, QString> NvramToolCli::readParameters(QString *error)
{
QProcess nvramtoolProcess;
nvramtoolProcess.start(s_sudoProg, {s_nvramToolProg, "-a"});
nvramtoolProcess.waitForFinished();
if(error) *error = nvramtoolProcess.readAllStandardError();
if(nvramtoolProcess.exitCode() != 0){
return {};
}
return Util::parseParameters(nvramtoolProcess);
}
QStringList NvramToolCli::readOptions(const QString &parameter, QString *error)
{
QStringList result;
QProcess nvramtoolProcess;
nvramtoolProcess.start(s_sudoProg, {s_nvramToolProg, "-e", parameter});
nvramtoolProcess.waitForFinished();
if(error) *error = nvramtoolProcess.readAllStandardError();
while (nvramtoolProcess.canReadLine()) {
result.append(nvramtoolProcess.readLine().trimmed());
}
return result;
}
#endif
bool NvramToolCli::writeParameters(const QMap<QString, QString> &parameters, QString *error)
{
#if MOCK
QTextStream outStream(stdout);
#else
QProcess nvramtoolProcess;
nvramtoolProcess.start(s_sudoProg, {s_nvramToolProg, "-i"});
nvramtoolProcess.waitForStarted();
QTextStream outStream(&nvramtoolProcess);
#endif
for(auto it = parameters.begin(); it != parameters.end(); ++it){
outStream << it.key() << " = " << it.value() << "\n";
}
outStream.flush();
#if MOCK
return true;
#else
nvramtoolProcess.closeWriteChannel();
nvramtoolProcess.waitForFinished();
if(error){
*error = nvramtoolProcess.readAllStandardError();
}
return nvramtoolProcess.exitCode()==0;
#endif
}
QString NvramToolCli::version()
{
QProcess nvramtoolProcess;
nvramtoolProcess.start(s_nvramToolProg, {"-v"});
nvramtoolProcess.waitForFinished();
return nvramtoolProcess.readAll();
}

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
#include <QList>
#include <QMap>
#include <QString>
#include "Configuration.h"
/*
* Namespace for convinient functions to work with nvramtool CLI utility
*/
namespace NvramToolCli {
Configuration::Parameters readParameters(QString* error = nullptr);
QStringList readOptions(const QString& parameter, QString* error = nullptr);
bool writeParameters(const Configuration::Parameters& parameters, QString* error = nullptr);
QString version();
}

View File

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <QEvent>
#include <QGuiApplication>
#include <QPainter>
#include <QPalette>
#include <QTimer>
#include "ToggleSwitch.h"
#include "ToggleSwitch.svg.h"
const QByteArray ToggleSwitch::s_toggleOffSvgContent = ToggleSwitchSVG::s_toggledOffContent;
const QByteArray ToggleSwitch::s_toggleOnSvgContent = ToggleSwitchSVG::s_toggledOnContent;
const int ToggleSwitch::s_colorPosInToggleOn = ToggleSwitch::s_toggleOnSvgContent.indexOf("#1a73e8");
ToggleSwitch::ToggleSwitch(QWidget *parent) : QCheckBox(parent){
setFixedWidth(50);
setFixedHeight(width()/2);
m_toggleOnSvgContentColored = s_toggleOnSvgContent;
}
void ToggleSwitch::paintEvent(QPaintEvent *event){
QPainter p(this);
if(isChecked()){
auto accent = palette().highlight().color();
m_toggleOnSvgContentColored = m_toggleOnSvgContentColored.replace(s_colorPosInToggleOn, 7, accent.name().toLatin1());
m_svgr.load(m_toggleOnSvgContentColored);
} else {
m_svgr.load(s_toggleOffSvgContent);
}
m_svgr.render(&p, this->rect());
p.end();
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
#include <QCheckBox>
#include <QFile>
#include <QObject>
#include <QSvgRenderer>
/*
* The ToggleSwitch class represents Toggle Switch widget based on QCheckBox and toggles svg with colorscheme support
*/
class ToggleSwitch : public QCheckBox {
Q_OBJECT
public:
explicit ToggleSwitch(QWidget* parent = nullptr);
private:
QSvgRenderer m_svgr;
static const QByteArray s_toggleOnSvgContent;
static const QByteArray s_toggleOffSvgContent;
static const int s_colorPosInToggleOn;
QByteArray m_toggleOnSvgContentColored;
/* QWidget interface */
protected:
void paintEvent(QPaintEvent *event) override;
/* QAbstractButton interface */
protected:
bool hitButton(const QPoint &pos) const override
{
/* needs to be clickable on */
return rect().contains(pos);
}
};

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
/* Embed SVG files into code as debian packages does weird things when svgs are included as qrc */
namespace ToggleSwitchSVG {
static constexpr char s_toggledOnContent[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
"<svg\n"
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
" xmlns:cc=\"http://creativecommons.org/ns#\"\n"
" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"
" xmlns:svg=\"http://www.w3.org/2000/svg\"\n"
" xmlns=\"http://www.w3.org/2000/svg\"\n"
" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"
" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"\n"
" inkscape:version=\"1.0rc1 (1.0rc1+100)\"\n"
" sodipodi:docname=\"toggle-on.svg\"\n"
" id=\"svg6\"\n"
" version=\"1.1\"\n"
" viewBox=\"0 0 40 20\"\n"
" height=\"20\"\n"
" width=\"40\">\n"
" <metadata\n"
" id=\"metadata12\">\n"
" <rdf:RDF>\n"
" <cc:Work\n"
" rdf:about=\"\">\n"
" <dc:format>image/svg+xml</dc:format>\n"
" <dc:type\n"
" rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n"
" </cc:Work>\n"
" </rdf:RDF>\n"
" </metadata>\n"
" <defs\n"
" id=\"defs10\" />\n"
" <sodipodi:namedview\n"
" inkscape:current-layer=\"svg6\"\n"
" inkscape:window-maximized=\"1\"\n"
" inkscape:window-y=\"28\"\n"
" inkscape:window-x=\"65\"\n"
" inkscape:cy=\"10\"\n"
" inkscape:cx=\"20.062112\"\n"
" inkscape:zoom=\"32.2\"\n"
" showgrid=\"false\"\n"
" id=\"namedview8\"\n"
" inkscape:window-height=\"1020\"\n"
" inkscape:window-width=\"1855\"\n"
" inkscape:pageshadow=\"2\"\n"
" inkscape:pageopacity=\"0\"\n"
" guidetolerance=\"10\"\n"
" gridtolerance=\"10\"\n"
" objecttolerance=\"10\"\n"
" borderopacity=\"1\"\n"
" bordercolor=\"#666666\"\n"
" pagecolor=\"#ffffff\" />\n"
" <rect\n"
" style=\"fill:#0068bf;fill-opacity:1\"\n"
" id=\"rect2\"\n"
" fill=\"#1a73e8\"\n"
" ry=\"8\"\n"
" height=\"16\"\n"
" width=\"36\"\n"
" y=\"2\"\n"
" x=\"2\" />\n"
" <circle\n"
" id=\"circle4\"\n"
" fill=\"#ffffff\"\n"
" r=\"6\"\n"
" cy=\"10\"\n"
" cx=\"30\" />\n"
"</svg>\n";
static constexpr char s_toggledOffContent[] =
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"20\" viewBox=\"0 0 40 20\">\n"
" <rect x=\"2\" y=\"2\" width=\"36\" height=\"16\" ry=\"8\" fill=\"#000000\" fill-opacity=\".26\"/>\n"
" <circle cx=\"10\" cy=\"10\" r=\"6\" fill=\"#ffffff\"/>\n"
"</svg>";
}

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
#include <QIODevice>
#include <QMap>
#include <QString>
namespace Util {
inline QMap<QString,QString> parseParameters(QIODevice& dev){
QString curr_line;
QMap<QString, QString> result;
while (!dev.atEnd()) {
curr_line = dev.readLine().trimmed();
auto split = curr_line.split('=');
if(split.size()!=2){
continue;
}
result.insert(split[0].trimmed(), split[1].trimmed());
}
return result;
}
}

View File

@ -0,0 +1,3 @@
<RCC>
<qresource prefix="/lang"/>
</RCC>

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <QApplication>
#include <QTranslator>
#include "MainWindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator translator;
if (translator.load(QLocale(), QLatin1String("corebootconfigurator"), QLatin1String("_"), QLatin1String(":/lang/i18n"))){
a.installTranslator(&translator);
}
MainWindow w;
w.show();
return a.exec();
}

View File

@ -0,0 +1,35 @@
## SPDX-License-Identifier: GPL-2.0-only
# Documentation: https://mesonbuild.com/Qt5-module.html
qt5 = import('qt5')
qt5_dep = dependency('qt5', modules : ['Core', 'Widgets', 'Svg'])
yamlcpp_dep = dependency('yaml-cpp', version: '>= 0.5.1', required: true)
# TODO: Translations
# lang_cpp = qt5.compile_translations(qresource: 'lang.qrc')
generated_files = qt5.preprocess(
moc_headers : ['MainWindow.h', 'AboutDialog.h', 'ToggleSwitch.h'],
ui_files : ['MainWindow.ui', 'AboutDialog.ui'],
dependencies : [qt5_dep],
qresources : ['resources.qrc'],
)
mock = get_option('mock')
if mock
add_project_arguments('-DMOCK', language : 'cpp')
endif
executable('coreboot-configurator',
'main.cpp',
'MainWindow.cpp',
'AboutDialog.cpp',
'Configuration.cpp',
'ToggleSwitch.cpp',
'NvramToolCli.cpp',
# lang_cpp,
generated_files,
dependencies : [qt5_dep, yamlcpp_dep],
install : true
)

View File

@ -0,0 +1,119 @@
processor:
displayName: Processor
hyper_threading:
displayName: Hyper-Threading
type: bool
help: Enable or disable Hyper-Threading
vtd:
displayName: Intel VT-d
type: bool
help: Enable or disable Intel VT-d (virtualisation)
power_profile:
displayName: Power Profile
type: enum
help: Select whether to maximise performance, battery life or both
me_state:
displayName: Intel Management Engine
type: bool
help: Enable or disable the Intel Management Engine
devices:
displayName: Devices
wireless:
displayName: Wireless
type: bool
help: Enable or disable the built-in wireless card
wlan:
displayName: Wireless
type: bool
help: Enable or disable the built-in wireless card
bluetooth:
displayName: Bluetooth
type: bool
help: Enable or disable the built-in bluetooth
wwan:
displayName: Mobile Network
type: bool
help: Enable or disable the built-in mobile network
ethernet1:
displayName: Ethernet 1
type: bool
help: Enable or disable the built-in Ethernet Port 1
ethernet2:
displayName: Ethernet 2
type: bool
help: Enable or disable the built-in Ethernet Port 2
ethernet3:
displayName: Ethernet 3
type: bool
help: Enable or disable the built-in Ethernet Port 3
webcam:
displayName: Webcam
type: bool
help: Enable or disable the built-in webcam
microphone:
displayName: Microphone
type: bool
help: Enable or disable the built-in microphone
legacy_8254_timer:
displayName: Clock Gating
type: bool
help: Enable or disable the legacy 8254 timer. Reduces power consumption when enabled but must be disabled for certain distributions such as Qubes
usb_always_on:
displayName: USB Always On
type: bool
help: Allow the USB ports to provide power to connected devices when the computer is suspended
touchpad:
displayName: Touchpad
type: bool
help: Enable or disable the built-in touchpad
trackpoint:
displayName: Trackpoint
type: bool
help: Enable or disable the built-in trackpoint
sata_mode:
displayName: SATA Mode
type: enum
help: Set the mode of the SATA controller from AHCI or Compatible
thunderbolt:
displayName: Thunderbolt
type: bool
help: Enable or disable Thunderbolt functionality
system:
displayName: System
kbl_timeout:
displayName: Keyboard Backlight Timeout
type: enum
help: Adjust the amout of time before the keyboard backlight turns off when un-used
fn_ctrl_swap:
displayName: Fn Ctrl Reverse
type: bool
help: Swap the functions of the [Fn] and [Ctrl] keys
max_charge:
displayName: Max Charge
type: enum
help: Set the maximum level the battery will charge to
fan_mode:
displayName: Fan Mode
type: enum
help: Adjust the fan curve to priotise performance or noise levels
f1_to_f12_as_primary:
displayName: Function Lock
type: bool
help: Make the F-keys behave as if you are holding down the Fn key
advanced:
displayName: Advanced
boot_option:
displayName: Boot Options
type: enum
help: Change the boot device in the event of a failed boot
debug_level:
displayName: Debug Level
type: enum
help: Set the verbosity of the debug output
power_on_after_fail:
displayName: Power on Behaviour
type: enum
help: Select whether to power on in the event of a power failure

View File

@ -0,0 +1,391 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="100"
height="100"
viewBox="0 0 26.458334 26.458334"
version="1.1"
id="svg5517"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:docname="star.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview5519"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.73406285"
inkscape:cx="396.42382"
inkscape:cy="207.06674"
inkscape:window-width="1854"
inkscape:window-height="1020"
inkscape:window-x="66"
inkscape:window-y="28"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
units="px" />
<defs
id="defs5514">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10558"
id="linearGradient10560"
x1="3.9647901"
y1="311.93555"
x2="25.1075"
y2="299.72879"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10558">
<stop
style="stop-color:#86868a;stop-opacity:1"
offset="0"
id="stop10554" />
<stop
style="stop-color:#3d3d40;stop-opacity:1"
offset="1"
id="stop10556" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10622"
id="linearGradient10624"
x1="3.9647901"
y1="311.93555"
x2="25.107491"
y2="299.72879"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10622">
<stop
style="stop-color:#444447;stop-opacity:1"
offset="0"
id="stop10618" />
<stop
style="stop-color:#757579;stop-opacity:1"
offset="1"
id="stop10620" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10630"
id="linearGradient10632"
x1="35.217491"
y1="299.72879"
x2="56.360199"
y2="311.93555"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10630">
<stop
style="stop-color:#4f4f52;stop-opacity:1"
offset="0"
id="stop10626" />
<stop
style="stop-color:#525255;stop-opacity:1"
offset="1"
id="stop10628" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10566"
id="linearGradient10568"
x1="35.217491"
y1="299.72879"
x2="56.360199"
y2="311.93555"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10566">
<stop
style="stop-color:#404043;stop-opacity:1"
offset="0"
id="stop10562" />
<stop
style="stop-color:#7c7c80;stop-opacity:1"
offset="1"
id="stop10564" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10646"
id="linearGradient10648"
x1="30.1625"
y1="266.55981"
x2="30.1625"
y2="290.97327"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10646">
<stop
style="stop-color:#4f4f52;stop-opacity:1"
offset="0"
id="stop10642" />
<stop
style="stop-color:#737376;stop-opacity:1"
offset="1"
id="stop10644" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10638"
id="linearGradient10640"
x1="30.1625"
y1="266.55981"
x2="30.1625"
y2="290.9733"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10638">
<stop
style="stop-color:#76767a;stop-opacity:1"
offset="0"
id="stop10634" />
<stop
style="stop-color:#505053;stop-opacity:1"
offset="1"
id="stop10636" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10598"
id="linearGradient10600"
x1="30.1625"
y1="296.8103"
x2="56.360199"
y2="311.93555"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10598">
<stop
style="stop-color:#0165ba;stop-opacity:1"
offset="0"
id="stop10594" />
<stop
style="stop-color:#001425;stop-opacity:1"
offset="1"
id="stop10596" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10606"
id="linearGradient10608"
x1="30.1625"
y1="296.8103"
x2="30.1625"
y2="323.45831"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10606">
<stop
style="stop-color:#0084f3;stop-opacity:1"
offset="0"
id="stop10602" />
<stop
style="stop-color:#003766;stop-opacity:1"
offset="1"
id="stop10604" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10574"
id="linearGradient10576"
x1="30.1625"
y1="296.8103"
x2="30.1625"
y2="266.55981"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10574">
<stop
style="stop-color:#0063b5;stop-opacity:1"
offset="0"
id="stop10570" />
<stop
style="stop-color:#000f1c;stop-opacity:1"
offset="1"
id="stop10572" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10590"
id="linearGradient10592"
x1="30.1625"
y1="296.8103"
x2="56.360199"
y2="311.93555"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10590">
<stop
style="stop-color:#015dab;stop-opacity:1"
offset="0"
id="stop10586" />
<stop
style="stop-color:#007ce5;stop-opacity:1"
offset="1"
id="stop10588" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10614"
id="linearGradient10616"
x1="7.08464"
y1="283.4863"
x2="30.1625"
y2="296.8103"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10614">
<stop
style="stop-color:#003563;stop-opacity:1"
offset="0"
id="stop10610" />
<stop
style="stop-color:#0080ec;stop-opacity:1"
offset="1"
id="stop10612" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10582"
id="linearGradient10584"
x1="30.1625"
y1="266.55981"
x2="30.1625"
y2="296.8103"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0744218,0,0,1.0744218,-38.534669,-244.51634)" />
<linearGradient
inkscape:collect="always"
id="linearGradient10582">
<stop
style="stop-color:#001424;stop-opacity:1"
offset="0"
id="stop10578" />
<stop
style="stop-color:#0065b9;stop-opacity:1"
offset="1"
id="stop10580" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g5791"
transform="matrix(0.43279952,0,0,0.43279952,15.881114,-18.126215)">
<path
id="path10367"
style="fill:url(#linearGradient10560);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
d="m -34.274812,90.63402 24.045828,-7.35759 -1.32964,-5.75761 z" />
<path
id="path10369"
style="fill:url(#linearGradient10624);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
d="m -34.274812,90.634 18.394778,-17.1455 4.321399,4.03031 z" />
<path
id="path10373"
style="fill:url(#linearGradient10632);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
d="M 22.019958,90.634 3.62518,73.4885 -0.69623,77.51881 Z" />
<path
id="path10375"
style="fill:url(#linearGradient10568);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
d="M 22.019958,90.634 -2.02587,83.27642 -0.69623,77.51881 Z" />
<path
id="path10379"
style="fill:url(#linearGradient10648);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
d="m -6.127422,41.88132 -5.651061,24.50309 5.651061,1.7273 z" />
<path
id="path10381"
style="fill:url(#linearGradient10640);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
d="m -6.127422,41.88132 5.651051,24.50309 -5.651051,1.7273 z" />
<path
d="m -6.127422,74.38311 5.431192,3.1357 -5.431192,25.49551 V 74.38311"
style="fill:url(#linearGradient10600);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
id="path10385"
inkscape:connector-curvature="0"
inkscape:export-filename="/home/sean/Insync/Shared/Technical/Logo/coreboot-gif/green-star.png"
inkscape:export-xdpi="166.19583"
inkscape:export-ydpi="166.19583"
sodipodi:nodetypes="cccc" />
<path
d="m -6.127422,74.38311 -5.431191,3.1357 5.431191,25.49551 V 74.38311"
style="fill:url(#linearGradient10608);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
id="path10387"
inkscape:connector-curvature="0"
inkscape:export-filename="/home/sean/Insync/Shared/Technical/Logo/coreboot-gif/green-star.png"
inkscape:export-xdpi="166.19583"
inkscape:export-ydpi="166.19583"
sodipodi:nodetypes="cccc" />
<path
d="M -6.127422,74.38311 V 68.1117 L 18.667945,60.0675 -6.127422,74.38311"
style="fill:url(#linearGradient10576);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
id="path10391"
inkscape:connector-curvature="0"
inkscape:export-filename="/home/sean/Insync/Shared/Technical/Logo/coreboot-gif/green-star.png"
inkscape:export-xdpi="166.19583"
inkscape:export-ydpi="166.19583"
sodipodi:nodetypes="cccc" />
<path
d="M -6.127422,74.38311 -0.69623,77.51881 18.667934,60.06749 -6.127422,74.38311"
style="fill:url(#linearGradient10592);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
id="path10393"
inkscape:connector-curvature="0"
inkscape:export-filename="/home/sean/Insync/Shared/Technical/Logo/coreboot-gif/green-star.png"
inkscape:export-xdpi="166.19583"
inkscape:export-ydpi="166.19583"
sodipodi:nodetypes="cccc" />
<path
d="m -6.127422,74.38312 -5.431191,3.1357 -19.364164,-17.45132 24.795355,14.31562"
style="fill:url(#linearGradient10616);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
id="path10397"
inkscape:connector-curvature="0"
inkscape:export-filename="/home/sean/Insync/Shared/Technical/Logo/coreboot-gif/green-star.png"
inkscape:export-xdpi="166.19583"
inkscape:export-ydpi="166.19583"
sodipodi:nodetypes="cccc" />
<path
d="m -6.127422,74.38312 v -6.27141 l -24.795355,-8.0442 24.795355,14.31561"
style="fill:url(#linearGradient10584);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.158757"
id="path10399"
inkscape:connector-curvature="0"
inkscape:export-filename="/home/sean/Insync/Shared/Technical/Logo/coreboot-gif/green-star.png"
inkscape:export-xdpi="166.19583"
inkscape:export-ydpi="166.19583"
sodipodi:nodetypes="cccc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="20" viewBox="0 0 40 20">
<rect x="2" y="2" width="36" height="16" ry="8" fill="#000000" fill-opacity=".26"/>
<circle cx="10" cy="10" r="6" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 226 B

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0rc1 (1.0rc1+100)"
sodipodi:docname="toggle-on.svg"
id="svg6"
version="1.1"
viewBox="0 0 40 20"
height="20"
width="40">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
inkscape:current-layer="svg6"
inkscape:window-maximized="1"
inkscape:window-y="28"
inkscape:window-x="65"
inkscape:cy="10"
inkscape:cx="20.062112"
inkscape:zoom="32.2"
showgrid="false"
id="namedview8"
inkscape:window-height="1020"
inkscape:window-width="1855"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<rect
style="fill:#0068bf;fill-opacity:1"
id="rect2"
fill="#1a73e8"
ry="8"
height="16"
width="36"
y="2"
x="2" />
<circle
id="circle4"
fill="#ffffff"
r="6"
cy="10"
cx="30" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,12 @@
<RCC>
<qresource prefix="/toggle">
<file alias="toggle-off.svg">qrc/toggle-off.svg</file>
<file alias="toggle-on.svg">qrc/toggle-on.svg</file>
</qresource>
<qresource prefix="/config">
<file alias="categories.yaml">qrc/categories.yaml</file>
</qresource>
<qresource prefix="/images">
<file alias="star.svg">qrc/star.svg</file>
</qresource>
</RCC>