diff options
-rw-r--r-- | doc/Development.asciidoc | 9 | ||||
-rw-r--r-- | doc/Development/Fuzzing.asciidoc | 49 | ||||
-rw-r--r-- | lib/configuration/configuration.cpp | 2 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | src/mainwindow/mainwindow.cpp | 11 | ||||
-rw-r--r-- | src/meson.build | 12 | ||||
-rw-r--r-- | src/session/sessiondialog.cpp | 87 | ||||
-rw-r--r-- | src/session/sessiondialog.h | 34 | ||||
-rw-r--r-- | src/session/sessiondialog.ui | 96 | ||||
-rw-r--r-- | src/session/sessionform.cpp | 36 | ||||
-rw-r--r-- | src/session/sessionform.h | 37 | ||||
-rw-r--r-- | src/session/sessionform.ui | 41 | ||||
-rwxr-xr-x | tools/format-code.sh | 4 |
13 files changed, 407 insertions, 13 deletions
diff --git a/doc/Development.asciidoc b/doc/Development.asciidoc index c849d67..1ef2ded 100644 --- a/doc/Development.asciidoc +++ b/doc/Development.asciidoc @@ -15,6 +15,15 @@ extensions. Source code should be kept as platform-agnostic as possible. syntax (SIGNAL/SLOT). This enables compile-time connect checks. * Prefer QVector over QList: http://lists.qt-project.org/pipermail/development/2017-March/029040.html +=== Setting linker +Meson has no environment variable to set the linker (link:https://github.com/mesonbuild/meson/issues/3597[issue]). + +Instead, this can be done using the cpp_link_args: +[source, sh] +---- +build% meson configure -Dcpp_link_args='-fuse-ld=gold' +---- + === clazy You can use https://github.com/KDE/clazy[clazy] to check Qt semantics. diff --git a/doc/Development/Fuzzing.asciidoc b/doc/Development/Fuzzing.asciidoc new file mode 100644 index 0000000..0981f1a --- /dev/null +++ b/doc/Development/Fuzzing.asciidoc @@ -0,0 +1,49 @@ +=== Setup +Required packages: afl + +==== Compiling Qt +This will build an instrumented Qt: + +[source, sh] +---- +export CC=$(which afl-gcc) +export CXX=$(which afl-g++) +./configure ... +make +---- + +=== Running the fuzzer +[source, sh] +---- +cd /sys/devices/system/cpu +su +echo performance | tee cpu*/cpufreq/scaling_governor +exit + +cd $testdir +afl-fuzz -m 512 -t 40 -i $input -o $output -- $testexe @@ + +# see for available scaling_governor values: +cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors + +cd /sys/devices/system/cpu +su +echo powersave | tee cpu*/cpufreq/scaling_governor +exit +---- + +The $input directory contains your reference input files, while the findings of the fuzzers will be written in $output. + +@@ gets replaced by the name of a file generated by AFL, containing the mutated input. + +=== Using ramdisk for tests +[source, sh] +---- +$ mkdir afl +# mount -t tmpfs -o size=1024M tmpfs afl/ +$ cd afl/ +$ afl-fuzz -i inputs -o findings ... +---- + +=== Sources +1. https://www.kdab.com/fuzzing-qt-fun-profit/ diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp index 388c7bd..398044b 100644 --- a/lib/configuration/configuration.cpp +++ b/lib/configuration/configuration.cpp @@ -55,6 +55,8 @@ Configuration::Configuration(QObject *parent) ("browser.locale", po::value<std::string>(), "Set Qt localization.") ("browser.translation", po::value<std::string>(), "Set application localization.") + ("browser.session.path", po::value<std::string>()->default_value("~/.config/smolbote/session.d")) + #ifdef CONFIG_USEBREAKPAD ("browser.crash.path", po::value<std::string>()->default_value(CONFIG_PATH_CRASHDUMP)) ("browser.crash.handler", po::value<std::string>()->default_value(CONFIG_PATH_CRASHHANDLER)) diff --git a/meson.build b/meson.build index 25fced3..06d52b6 100644 --- a/meson.build +++ b/meson.build @@ -26,7 +26,7 @@ dep_plasma = declare_dependency( ) # add -DQT_NO_DEBUG to non-debug builds -if not get_option('buildtype').startswith('debug') +if not get_option('debug') add_global_arguments('-DQT_NO_DEBUG', language: 'cpp') endif diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp index 8f635c9..80e4faa 100644 --- a/src/mainwindow/mainwindow.cpp +++ b/src/mainwindow/mainwindow.cpp @@ -13,6 +13,7 @@ #include "configuration.h" #include "profilemanager.h" #include "session.h" +#include "session/sessiondialog.h" #include "subwindow/subwindow.h" #include "ui_mainwindow.h" #include "webengine/webview.h" @@ -126,14 +127,8 @@ MainWindow::MainWindow(const std::unique_ptr<Configuration> &config, QWidget *pa } }); connect(ui->actionLoadSession, &QAction::triggered, this, [this]() { - const QString filename = QFileDialog::getOpenFileName(this, tr("Load Session"), QDir::homePath(), tr("JSON (*.json)")); - QFile json(filename); - if(json.open(QIODevice::ReadOnly | QIODevice::Text)) { - auto *browser = qobject_cast<Browser *>(qApp); - auto doc = QJsonDocument::fromJson(json.readAll()); - browser->createSession(doc.object()); - json.close(); - } + auto *sessionDialog = new SessionDialog(this); + sessionDialog->exec(); }); } diff --git a/src/meson.build b/src/meson.build index f99d0c7..5df5a36 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,10 +1,11 @@ # poi poi_moc = qt5.preprocess( moc_headers: ['browser.h', - 'mainwindow/mainwindow.h', 'mainwindow/widgets/dockwidget.h', 'mainwindow/widgets/navigationbar.h', 'mainwindow/widgets/searchform.h', - 'subwindow/subwindow.h', 'subwindow/tabwidget.h', + 'mainwindow/mainwindow.h', 'mainwindow/widgets/dockwidget.h', 'mainwindow/widgets/navigationbar.h', 'mainwindow/widgets/searchform.h', + 'session/sessiondialog.h', 'session/sessionform.h', + 'subwindow/subwindow.h', 'subwindow/tabwidget.h', 'webengine/filter.h', 'webengine/urlinterceptor.h', 'webengine/webpage.h', 'webengine/webview.h'], - ui_files: ['mainwindow/mainwindow.ui', 'mainwindow/widgets/searchform.ui'], + ui_files: ['mainwindow/mainwindow.ui', 'mainwindow/widgets/searchform.ui', 'session/sessiondialog.ui', 'session/sessionform.ui'], qresources: '../data/resources.qrc', rcc_extra_arguments: ['--format-version=1'], dependencies: dep_qt5 @@ -32,7 +33,10 @@ poi = executable(get_option('poiName'), install: true, 'mainwindow/mainwindow.cpp', 'mainwindow/widgets/dockwidget.cpp', 'mainwindow/widgets/navigationbar.cpp', - 'mainwindow/widgets/searchform.cpp', + 'mainwindow/widgets/searchform.cpp', + + 'session/sessiondialog.cpp', + 'session/sessionform.cpp', 'subwindow/subwindow.cpp', 'subwindow/tabwidget.cpp', diff --git a/src/session/sessiondialog.cpp b/src/session/sessiondialog.cpp new file mode 100644 index 0000000..e31a42f --- /dev/null +++ b/src/session/sessiondialog.cpp @@ -0,0 +1,87 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "sessiondialog.h" +#include "../browser.h" +#include "../util.h" +#include "sessionform.h" +#include "ui_sessiondialog.h" +#include "ui_sessionform.h" +#include <QFile> +#include <QFileDialog> +#include <QToolButton> +#include <QStyle> + +SessionDialog::SessionDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::SessionDialog) +{ + ui->setupUi(this); + ui->open->setIcon(style()->standardIcon(QStyle::SP_DirOpenIcon)); + + auto *browser = qobject_cast<Browser *>(qApp); + Q_CHECK_PTR(browser); + + for(const QString &path : Util::files(browser->configuration("browser.session.path"), { "*.json" })) { + auto *item = new QListWidgetItem(ui->listWidget); + auto *widget = new SessionForm(path, this); + connect(widget->ui->delete_toolButton, &QToolButton::clicked, this, [item, widget]() { + delete item; + delete widget; + }); + ui->listWidget->setItemWidget(item, widget); + } + +#ifdef QT_DEBUG + ui->listWidget->addItem(tr("Start new session")); +#endif + + connect(ui->listWidget, &QListWidget::currentItemChanged, this, [this](QListWidgetItem *currentItem, QListWidgetItem *previousItem) { + auto *currentWidget = qobject_cast<SessionForm *>(ui->listWidget->itemWidget(currentItem)); + if(currentWidget) + currentWidget->ui->delete_toolButton->show(); + + auto *previousWidget = qobject_cast<SessionForm *>(ui->listWidget->itemWidget(previousItem)); + if(previousWidget) + previousWidget->ui->delete_toolButton->hide(); + }); + + connect(ui->open, &QPushButton::clicked, this, [this]() { + const QString filename = QFileDialog::getOpenFileName(this, tr("Select Session file"), QDir::homePath(), tr("JSON (*.json)")); + if(!filename.isEmpty()) { + this->openSession(filename); + // close the dialog window; reject so it doesn't open another session + this->reject(); + } + }); + + connect(this, &SessionDialog::accepted, this, [this]() { + auto *currentWidget = qobject_cast<SessionForm *>(ui->listWidget->itemWidget(ui->listWidget->currentItem())); + if(currentWidget) + this->openSession(currentWidget->ui->label->text()); + }); +} + +SessionDialog::~SessionDialog() +{ + delete ui; +} + +void SessionDialog::openSession(const QString &filename) +{ + auto *browser = qobject_cast<Browser *>(qApp); + Q_CHECK_PTR(browser); + + QFile json(filename); + if(json.open(QIODevice::ReadOnly | QIODevice::Text)) { + auto *browser = qobject_cast<Browser *>(qApp); + auto doc = QJsonDocument::fromJson(json.readAll()); + browser->createSession(doc.object()); + json.close(); + } +} diff --git a/src/session/sessiondialog.h b/src/session/sessiondialog.h new file mode 100644 index 0000000..7fea3c2 --- /dev/null +++ b/src/session/sessiondialog.h @@ -0,0 +1,34 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef SMOLBOTE_SESSIONDIALOG_H +#define SMOLBOTE_SESSIONDIALOG_H + +#include <QDialog> + +namespace Ui +{ +class SessionDialog; +} + +class SessionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SessionDialog(QWidget *parent = nullptr); + ~SessionDialog() override; + +private: + void openSession(const QString &filename); + +private: + Ui::SessionDialog *ui; +}; + +#endif // SMOLBOTE_SESSIONDIALOG_H diff --git a/src/session/sessiondialog.ui b/src/session/sessiondialog.ui new file mode 100644 index 0000000..3a61dc1 --- /dev/null +++ b/src/session/sessiondialog.ui @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SessionDialog</class> + <widget class="QDialog" name="SessionDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1000</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>Select Session</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Filter</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit"> + <property name="placeholderText"> + <string>Search</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QListWidget" name="listWidget"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="open"> + <property name="text"> + <string>Open from File</string> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close|QDialogButtonBox::Open</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>SessionDialog</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>SessionDialog</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> diff --git a/src/session/sessionform.cpp b/src/session/sessionform.cpp new file mode 100644 index 0000000..761cb42 --- /dev/null +++ b/src/session/sessionform.cpp @@ -0,0 +1,36 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "sessionform.h" +#include "ui_sessionform.h" +#include <QStyle> + +SessionForm::SessionForm(const QString &path, QWidget *parent) + : QWidget(parent) + , ui(new Ui::SessionForm) +{ + ui->setupUi(this); + ui->label->setText(path); + ui->delete_toolButton->setIcon(style()->standardIcon(QStyle::SP_TrashIcon)); + ui->delete_toolButton->hide(); +} + +SessionForm::~SessionForm() +{ + delete ui; +} + +void SessionForm::showDetails() +{ + ui->delete_toolButton->show(); +} + +void SessionForm::hideDetails() +{ + ui->delete_toolButton->hide(); +} diff --git a/src/session/sessionform.h b/src/session/sessionform.h new file mode 100644 index 0000000..5e5f52e --- /dev/null +++ b/src/session/sessionform.h @@ -0,0 +1,37 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef SMOLBOTE_SESSIONFORM_H +#define SMOLBOTE_SESSIONFORM_H + +#include <QWidget> + +namespace Ui +{ +class SessionForm; +} + +class SessionForm : public QWidget +{ + Q_OBJECT + + friend class SessionDialog; + +public: + explicit SessionForm(const QString &path, QWidget *parent = nullptr); + ~SessionForm() override; + +public slots: + void showDetails(); + void hideDetails(); + +private: + Ui::SessionForm *ui; +}; + +#endif // SMOLBOTE_SESSIONFORM_H diff --git a/src/session/sessionform.ui b/src/session/sessionform.ui new file mode 100644 index 0000000..dbf0237 --- /dev/null +++ b/src/session/sessionform.ui @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SessionForm</class> + <widget class="QWidget" name="SessionForm"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>711</width> + <height>34</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="delete_toolButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/format-code.sh b/tools/format-code.sh new file mode 100755 index 0000000..68be1d8 --- /dev/null +++ b/tools/format-code.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# get names of staged files | filter out the header and cpp files | clang-format them +git diff --staged --name-only | grep --regex="\.h\|\.cpp" | xargs clang-format -i |