aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--CMakeLists.txt86
-rw-r--r--Kconfig42
-rw-r--r--LICENSE.md8
-rw-r--r--README.md46
-rw-r--r--cmake/CompilerWarnings.cmake77
-rw-r--r--cmake/Sanitize.cmake33
-rw-r--r--cmake/StandardProjectSettings.cmake44
-rw-r--r--cmake/ThirdParty.cmake17
-rw-r--r--cmake/lcov.cmake4
-rw-r--r--data/poi_window.svg (renamed from src/webengine/test/icon.svg)0
-rw-r--r--data/resources.qrc5
-rw-r--r--doc/building.md38
-rw-r--r--doc/man/CMakeLists.txt9
-rw-r--r--doc/man/smolbote.1.scd3
-rw-r--r--doc/man/smolboterc.5.scd12
-rw-r--r--doc/meson.build16
-rw-r--r--include/meson.build7
-rw-r--r--include/singleton.hpp27
-rw-r--r--lang/CMakeLists.txt10
-rw-r--r--lang/meson.build4
-rw-r--r--lib/bookmarks/CMakeLists.txt6
-rw-r--r--lib/bookmarks/meson.build16
-rw-r--r--lib/configuration/CMakeLists.txt24
-rw-r--r--lib/configuration/configuration.cpp105
-rw-r--r--lib/configuration/configuration.h10
-rw-r--r--lib/configuration/meson.build22
-rw-r--r--lib/configuration/test/main.cpp57
-rw-r--r--lib/configuration/test/qt.cpp71
-rw-r--r--lib/downloads/CMakeLists.txt6
-rw-r--r--lib/downloads/meson.build19
-rw-r--r--lib/downloads/widgets/downloaditemwidget.cpp4
-rw-r--r--lib/pluginloader/CMakeLists.txt54
-rw-r--r--lib/pluginloader/meson.build68
-rw-r--r--lib/pluginloader/pluginloader.cpp4
-rw-r--r--lib/pluginloader/pluginloader.h9
-rw-r--r--lib/pluginloader/test/pluginloader-sigmatch.cpp56
-rw-r--r--lib/session_formats/CMakeLists.txt8
-rw-r--r--lib/session_formats/meson.build9
-rw-r--r--lib/session_formats/session_json.hpp2
-rw-r--r--lib/smolblok/CMakeLists.txt8
-rw-r--r--lib/smolblok/README.md (renamed from staging/smolblok/README.md)0
-rw-r--r--lib/smolblok/filtermanager.hpp (renamed from staging/smolblok/filtermanager.hpp)0
-rw-r--r--lib/smolblok/smolblok.cpp (renamed from staging/smolblok/smolblok.cpp)0
-rw-r--r--lib/smolblok/smolblok.hpp (renamed from staging/smolblok/smolblok.hpp)4
-rw-r--r--lib/smolblok/test/loader.cpp (renamed from staging/smolblok/test/loader.cpp)0
-rw-r--r--lib/smolblok/test/main.cpp (renamed from staging/smolblok/test/main.cpp)0
-rw-r--r--lib/smolblok/test/sample-filters.txt (renamed from staging/smolblok/test/sample-filters.txt)0
-rw-r--r--lib/webengine/CMakeLists.txt21
-rw-r--r--lib/webengine/test/form.html (renamed from src/webengine/test/form.html)0
-rw-r--r--lib/webengine/test/icon.svg7
-rw-r--r--lib/webengine/test/profile.cpp (renamed from src/webengine/test/profile.cpp)0
-rw-r--r--lib/webengine/test/profilemanager.cpp (renamed from src/webengine/test/profilemanager.cpp)8
-rw-r--r--lib/webengine/test/sample.html (renamed from src/webengine/test/sample.html)0
-rw-r--r--lib/webengine/test/testing.profile (renamed from src/webengine/test/testing.profile)0
-rw-r--r--lib/webengine/test/view.cpp (renamed from src/webengine/test/view.cpp)0
-rw-r--r--lib/webengine/urlinterceptor.cpp (renamed from src/webengine/urlinterceptor.cpp)0
-rw-r--r--lib/webengine/urlinterceptor.h (renamed from src/webengine/urlinterceptor.h)0
-rw-r--r--lib/webengine/webpage.cpp (renamed from src/webengine/webpage.cpp)0
-rw-r--r--lib/webengine/webpage.h (renamed from src/webengine/webpage.h)0
-rw-r--r--lib/webengine/webprofile.cpp (renamed from src/webengine/webprofile.cpp)0
-rw-r--r--lib/webengine/webprofile.h (renamed from src/webengine/webprofile.h)0
-rw-r--r--lib/webengine/webprofilemanager.cpp (renamed from src/webengine/webprofilemanager.cpp)0
-rw-r--r--lib/webengine/webprofilemanager.h (renamed from src/webengine/webprofilemanager.h)15
-rw-r--r--lib/webengine/webview.cpp (renamed from src/webengine/webview.cpp)0
-rw-r--r--lib/webengine/webview.h (renamed from src/webengine/webview.h)0
-rw-r--r--lib/webengine/webviewcontextmenu.cpp (renamed from src/webengine/webviewcontextmenu.cpp)22
-rw-r--r--lib/webengine/webviewcontextmenu.h (renamed from src/webengine/webviewcontextmenu.h)0
-rw-r--r--linux/.config111
-rw-r--r--linux/CMakeLists.txt8
-rw-r--r--linux/makepkg/PKGBUILD94
-rw-r--r--linux/meson.build30
-rw-r--r--linux/poi.desktop (renamed from linux/poi.desktop.in)16
-rw-r--r--linux/poi.fish11
-rw-r--r--linux/poi_firejail.desktop.in21
-rw-r--r--linux/poi_picksession.desktop.in13
-rw-r--r--meson.build148
-rw-r--r--meson_options.txt10
-rw-r--r--plugins/AdblockFilter/filterlist.cpp (renamed from staging/adblock/filterlist.cpp)8
-rw-r--r--plugins/AdblockFilter/filterlist.h (renamed from staging/adblock/filterlist.h)6
-rw-r--r--plugins/AdblockFilter/meson.build (renamed from staging/adblock/meson.build)6
-rw-r--r--plugins/AdblockFilter/options.cpp (renamed from staging/adblock/options.cpp)2
-rw-r--r--plugins/AdblockFilter/options.h (renamed from staging/adblock/options.h)2
-rw-r--r--plugins/AdblockFilter/plugin/AdblockPlusPlugin.json (renamed from staging/adblock/plugin/AdblockPlusPlugin.json)0
-rw-r--r--plugins/AdblockFilter/plugin/plugin.cpp (renamed from staging/adblock/plugin/plugin.cpp)0
-rw-r--r--plugins/AdblockFilter/plugin/plugin.h (renamed from staging/adblock/plugin/plugin.h)0
-rw-r--r--plugins/AdblockFilter/rule.h (renamed from staging/adblock/rule.h)0
-rw-r--r--plugins/AdblockFilter/test/filterlist.cpp (renamed from staging/adblock/test/filterlist.cpp)14
-rw-r--r--plugins/AdblockFilter/test/options.cpp (renamed from staging/adblock/test/options.cpp)2
-rw-r--r--plugins/AdblockFilter/test/rule.cpp (renamed from staging/adblock/test/rule.cpp)2
-rw-r--r--plugins/HostlistFilter/CMakeLists.txt33
-rw-r--r--plugins/HostlistFilter/corpus/apple.txt (renamed from plugins/smolblok_hostlist/corpus/apple.txt)0
-rw-r--r--plugins/HostlistFilter/corpus/banana.txt (renamed from plugins/smolblok_hostlist/corpus/banana.txt)0
-rw-r--r--plugins/HostlistFilter/corpus/kiwi.txt (renamed from plugins/smolblok_hostlist/corpus/kiwi.txt)0
-rw-r--r--plugins/HostlistFilter/corpus/orange.txt (renamed from plugins/smolblok_hostlist/corpus/orange.txt)0
-rw-r--r--plugins/HostlistFilter/filterlist.cpp56
-rw-r--r--plugins/HostlistFilter/filterlist.h84
-rw-r--r--plugins/HostlistFilter/plugin/plugin.cpp (renamed from plugins/smolblok_hostlist/plugin/plugin.cpp)0
-rw-r--r--plugins/HostlistFilter/plugin/plugin.h (renamed from plugins/smolblok_hostlist/plugin/plugin.h)0
-rw-r--r--plugins/HostlistFilter/smolblokHostlistPlugin.json (renamed from plugins/smolblok_hostlist/plugin/smolblokHostlistPlugin.json)0
-rw-r--r--plugins/HostlistFilter/test/filterlist.cpp37
-rw-r--r--plugins/HostlistFilter/test/hostlist.txt (renamed from plugins/smolblok_hostlist/test/hostlist.txt)0
-rw-r--r--plugins/HostlistFilter/test/plugin.cpp (renamed from plugins/smolblok_hostlist/test/plugin.cpp)2
-rw-r--r--plugins/HostlistFilter/test/rule.cpp57
-rw-r--r--plugins/smolblok_hostlist/filterlist.cpp58
-rw-r--r--plugins/smolblok_hostlist/filterlist.h58
-rw-r--r--plugins/smolblok_hostlist/meson.build50
-rw-r--r--plugins/smolblok_hostlist/test/filterlist.cpp29
-rw-r--r--plugins/smolblok_hostlist/test/rule.cpp57
-rwxr-xr-xscripts/gen-crashhandler-default-go.py40
-rwxr-xr-xscripts/gen-default-cfg.py27
-rw-r--r--src/CMakeLists.txt42
-rw-r--r--src/about/CMakeLists.txt11
-rw-r--r--src/about/aboutdialog.cpp22
-rw-r--r--src/about/meson.build21
-rw-r--r--src/about/test/main.cpp8
-rw-r--r--src/applicationmenu.cpp17
-rw-r--r--src/autogen/CMakeLists.txt35
-rw-r--r--src/autogen/applicationstyle.cpp91
-rw-r--r--src/autogen/applicationstyle.h26
-rw-r--r--src/autogen/settings.h.in70
-rw-r--r--src/autogen/util.cpp (renamed from src/util.cpp)25
-rw-r--r--src/autogen/util.h (renamed from src/util.h)5
-rw-r--r--src/autogen/version.h.in21
-rw-r--r--src/bookmarks/bookmarkswidget.cpp4
-rw-r--r--src/bookmarks/builtin.cpp107
-rw-r--r--src/bookmarks/builtins.cpp105
-rw-r--r--src/browser.cpp116
-rw-r--r--src/browser.h25
-rw-r--r--src/builtins.cpp55
-rw-r--r--src/builtins.h28
-rw-r--r--src/cmd/CMakeLists.txt5
-rw-r--r--src/cmd/cmd.hpp89
-rw-r--r--src/cmd/test.cpp41
-rw-r--r--src/configuration/builtin.cpp41
-rw-r--r--src/crashhandler.cpp56
-rw-r--r--src/crashhandler.h30
-rw-r--r--src/crashhandler_dummy.cpp16
-rw-r--r--src/main.cpp166
-rw-r--r--src/mainwindow/addressbar.cpp4
-rw-r--r--src/mainwindow/mainwindow.cpp6
-rw-r--r--src/mainwindow/menubar.cpp4
-rw-r--r--src/mainwindow/widgets/navigationbar.cpp16
-rw-r--r--src/meson.build60
-rw-r--r--src/session/builtin.cpp61
-rw-r--r--src/session/savesessiondialog.cpp4
-rw-r--r--src/session/sessiondialog.cpp2
-rw-r--r--src/settings.h.in32
-rw-r--r--src/subwindow/subwindow.cpp6
-rw-r--r--src/subwindow/subwindow.h4
-rw-r--r--src/subwindow/tabwidget.cpp49
-rw-r--r--src/subwindow/tabwidget.h53
-rw-r--r--src/version.h.in8
-rw-r--r--src/wallet/wallet.cpp35
-rw-r--r--src/wallet/wallet.h18
-rw-r--r--src/webengine/meson.build27
-rw-r--r--staging/smolblok/meson.build17
-rw-r--r--subprojects/args.wrap6
-rw-r--r--subprojects/catch2.wrap10
-rw-r--r--subprojects/singleapplication.wrap6
-rw-r--r--subprojects/spdlog.wrap10
-rw-r--r--test/cli/cli.cpp92
-rw-r--r--test/cli/meson.build4
-rw-r--r--tools/meson.build36
-rw-r--r--tools/src/crashhandler/defaults.go.in4
-rw-r--r--tools/src/crashhandler/main.go81
-rw-r--r--tools/src/updater/main.go47
-rw-r--r--tools/src/updater/manifest.go16
-rw-r--r--windows/.config78
-rw-r--r--windows/icon.rc (renamed from data/windows.rc)0
-rw-r--r--windows/poi.ico (renamed from data/poi.ico)bin45842 -> 45842 bytes
171 files changed, 2020 insertions, 2280 deletions
diff --git a/.gitignore b/.gitignore
index 1d130a6..9403efb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,6 @@
-# kdevelop
-build*
-*.kdev4
-
-# qtcreator
-*.user
-
-subprojects/*
-!subprojects/*.wrap
+third-party
lang/*.qm
-tools/src/crashhandler/defaults.go
.config
.config.old
compile_commands.json
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4320962
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,86 @@
+cmake_minimum_required(VERSION 3.18)
+
+project(smolbote VERSION 0.1.0 LANGUAGES CXX)
+
+include(FeatureSummary)
+include(GNUInstallDirs)
+include(cmake/StandardProjectSettings.cmake)
+include(cmake/CompilerWarnings.cmake)
+include(cmake/Sanitize.cmake)
+include(cmake/ThirdParty.cmake)
+
+option(b_manpages "Build manpages (requires scdoc" OFF)
+option(b_translations "Build translations" OFF)
+option(b_tests "Build tests" ON)
+
+# TODO
+#option(b_signPlugins "Generate OpenSSL signing key and sign plugins" ON)
+
+if(b_manpages)
+ add_subdirectory(doc/man)
+endif()
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(b_tests)
+ enable_testing()
+endif()
+enable_warnings()
+
+find_package(Qt5 COMPONENTS Widgets Svg Network WebEngine WebEngineWidgets REQUIRED)
+find_package(spdlog REQUIRED)
+add_compile_options(-DSPDLOG_FMT_EXTERNAL)
+find_package(Catch2)
+find_package(OpenSSL REQUIRED)
+
+download_third_party(SingleApplication-3.1.5
+ "https://github.com/itay-grudev/SingleApplication/archive/v3.1.5.tar.gz" singleapplication-v3.1.5.tar.gz
+ SHA256 09b1e088dae8cf69187262554819b77f4ca7b65576b3f39c5b6885823e8a2dbb)
+set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
+add_subdirectory(third-party/SingleApplication-3.1.5)
+
+download_third_party(rcc-0.1.2
+ https://neueland.iserlohn-fortress.net/cgit/rcc/snapshot/rcc-0.1.2.tar.xz rcc-0.1.2.tar.xz
+ SHA256 5ee18b94401b720e6e65d8e0e38dd6ea23cab7ae4727742be313530969a69d50)
+set(RCC ${CMAKE_SOURCE_DIR}/third-party/rcc-0.1.2/rcc)
+
+download_third_party(tabler-icons-1.34.0
+ https://github.com/tabler/tabler-icons/archive/v1.34.0.tar.gz v1.34.0.tar.gz
+ SHA256 bc74e5bd28531445f2e50df44f3688b1116397a25a0086e6944ab52260b70ffd)
+set(ICONS_PATH ${CMAKE_SOURCE_DIR}/third-party/tabler-icons-1.34.0)
+
+add_subdirectory(lib/bookmarks)
+add_subdirectory(lib/configuration)
+add_subdirectory(lib/downloads)
+add_subdirectory(lib/pluginloader)
+add_subdirectory(lib/session_formats)
+add_subdirectory(lib/smolblok)
+add_subdirectory(lib/webengine)
+add_subdirectory(src)
+
+add_subdirectory(plugins/HostlistFilter)
+
+# TODO
+#add_subdirectory(lang)
+
+add_subdirectory(linux)
+
+feature_summary(WHAT ALL)
+message(STATUS "Project
+ name: ${CMAKE_PROJECT_NAME}
+ version: ${CMAKE_PROJECT_VERSION}")
+message(STATUS "Compiler
+ id: ${CMAKE_CXX_COMPILER_ID}
+ version: ${CMAKE_CXX_COMPILER_VERSION}
+ compiler: ${CMAKE_CXX_COMPILER}")
+message(STATUS "Install paths
+ prefix: ${CMAKE_INSTALL_PREFIX}
+ bindir: ${CMAKE_INSTALL_BINDIR}
+ libdir: ${CMAKE_INSTALL_LIBDIR}
+ datadir: ${CMAKE_INSTALL_DATADIR}
+ mandir: ${CMAKE_INSTALL_MANDIR}")
+message(STATUS "Build options
+ manpages: ${b_manpages}
+ i18n: ${b_translations}
+ tests: ${b_tests}")
diff --git a/Kconfig b/Kconfig
index 37d3d9c..5567816 100644
--- a/Kconfig
+++ b/Kconfig
@@ -2,9 +2,6 @@ menu "Application"
config POI_NAME
string "Application name"
default "smolbote"
- config POI_ICON
- string "Path to icon"
- default ":/icons/poi.svg"
config POI_CFG_PATH
string "Configuration location"
default "~/.config/smolbote/smolbote.cfg"
@@ -185,42 +182,3 @@ config session.path
string "Session location"
default "~/.config/smolbote/session.d"
-config USEPLASMA
- bool "Enable KDE Frameworks integration"
- default n
-
-menu "KDE Integration"
- depends on USEPLASMA
-
- config PLASMA_BLUR
- bool "Enable translucent background and blur behind window"
- default n
-
- config WALLET_FOLDER
- string "KDE Wallet folder name"
- default "smolbote"
-endmenu
-
-config USEBREAKPAD
- bool "Enable Breakpad integration"
- default n
-
-menu "Breakpad Integration"
- depends on USEBREAKPAD
-
- config PATH_CRASHDUMP
- string "Crash dump location"
- default "~/.config/smolbote/crash.d"
-
- config PATH_CRASHHANDLER
- string "Crash handler location"
- default "poi-crash"
-endmenu
-
-menu "Workarounds"
- config QTBUG_65223
- bool "Manually emit loadFinished"
- default y
- help
- See QTBUG-65223: loadStarted is emitted twice when loading link with anchor
-endmenu
diff --git a/LICENSE.md b/LICENSE.md
index 96bcfc3..e5bd938 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -27,11 +27,3 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
- url: https://github.com/itay-grudev/SingleApplication
- license: MIT
-## args
-- url: https://github.com/Taywee/args
-- license: MIT
-
-## Breakpad (optional)
-- url: https://chromium.googlesource.com/breakpad/breakpad
-- license: BSD-3-Clause
-
diff --git a/README.md b/README.md
index bd177b2..72de08a 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,21 @@
+ __ __
+ ____ ___ __ _____ / /___ _____ ____/ /
+ / __ \/ _ \/ / / / _ \/ / __ `/ __ \/ __ /
+ / / / / __/ /_/ / __/ / /_/ / / / / /_/ /
+ /_/ /_/\___/\__,_/\___/ /\__,_/_/ /_/\__,_/
+ out of foppery /_/ and whim
+
## *smolbote?*
_It's yet another no-frills browser, poi!_
-### What is this and why should I care?
+## What is this and why should I care?
smolbote is a [keep-it-simple][kiss-principle] free software web browser.
This program is free software. You can use it as you see fit, study and modify
the source code, and share the program with or without modification, while
providing the same terms.
-For more information, and a list of dependancies, see [LICENSE.md][repo-license].
+For more information and a list of dependancies, see [LICENSE.md][repo-license].
#### Simplicity
This should be a simple browser that only does its browsing job with as little
@@ -19,22 +26,33 @@ This browser should be usable out of the box, with minimal if any configuration
necessary. All functionality should be user-customizable, and it is the user's
responsibility to ensure a stable working state when changing settings.
-#### Pragmatic Freedom
-Free software should serve the user, not impose unbreakable barriers for
-ideological reasons.
+## What's up with the name?!
+It's a small boat. It says poi.
+
+## Sounds dumb, how do I use it?
-QtWebEngine allows the usage of third-party non-free codecs and non-free
-plugins. This browser does not prevent you from doing so. It's up to you how
-you exercise your freedom.
+### Nightly builds
-### What's up with the name?!
-It's a small boat. It says poi.
+### Building from source
+
+Required dependencies
+- latest stable [Qt](https://www.qt.io/)
+- [cmake](https://www.cmake.org/) 3.18+
+- A compiler with C++2a support
+
+```
+# clone
+git clone git://neueland.iserlohn-fortress.net/smolbote
+
+# configure
+cmake -S smolbote -B smolbote.build
-### Sounds dumb, how do I use it?
-You make it yourself. Detailed [build instructions](/smolbote/building.html) included.
+# make
+cmake --build smolbote.build
+```
-### It doesn't work, what now?
+## It doesn't work, what now?
Drop me an email at _aqua at iserlohn dash fortress dot net_.
[kiss-principle]: https://en.wikipedia.org/wiki/KISS_principle
-[repo-license]: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote/src/branch/master/LICENSE.md
+[repo-license]: https://neueland.iserlohn-fortress.net/cgit/smolbote/tree/LICENSE.md
diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake
new file mode 100644
index 0000000..c53660f
--- /dev/null
+++ b/cmake/CompilerWarnings.cmake
@@ -0,0 +1,77 @@
+# Based on:
+# https://github.com/lefticus/cpp_starter_project/blob/master/cmake/CompilerWarnings.cmake
+# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md
+
+function(enable_warnings)
+ # only enable warnings for debug builds
+ if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+ return()
+ endif()
+
+ set(MSVC_WARNINGS
+ /W4 # Baseline reasonable warnings
+ /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data
+ /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
+ /w14263 # 'function': member function does not override any base class virtual member function
+ /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not
+ # be destructed correctly
+ /w14287 # 'operator': unsigned/negative constant mismatch
+ /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside
+ # the for-loop scope
+ /w14296 # 'operator': expression is always 'boolean_value'
+ /w14311 # 'variable': pointer truncation from 'type1' to 'type2'
+ /w14545 # expression before comma evaluates to a function which is missing an argument list
+ /w14546 # function call before comma missing argument list
+ /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect
+ /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'?
+ /w14555 # expression has no effect; expected expression with side- effect
+ /w14619 # pragma warning: there is no warning number 'number'
+ /w14640 # Enable warning on thread un-safe static member initialization
+ /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
+ /w14905 # wide string literal cast to 'LPSTR'
+ /w14906 # string literal cast to 'LPWSTR'
+ /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
+ /permissive- # standards conformance mode for MSVC compiler.
+ )
+
+ set(BASE_WARNINGS
+ -Wall # reasonable and standard
+ -Wextra
+ -Werror=pedantic # warn if non-standard C++ is used
+
+ -Wunused # warn on anything being unused
+ -Wshadow # warn the user if a variable declaration shadows one from a parent context
+
+ -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor.
+ # This helps catch hard to track down memory errors
+ -Werror=redundant-decls
+ -Woverloaded-virtual # warn if you overload (not override) a virtual function
+ -Werror=return-type
+
+ -Wold-style-cast # warn for c-style casts
+ -Wcast-align # warn for potential performance problem casts
+ -Wconversion # warn on type conversions that may lose data
+ -Wsign-conversion # warn on sign conversions
+ -Wnull-dereference # warn if a null dereference is detected
+ -Wdouble-promotion # warn if float is implicit promoted to double
+ -Wformat=2 # warn on security issues around functions that format output (ie printf)
+
+ -Wconsumed
+ #-Wlifetime
+ -mspeculative-load-hardening # Spectre v1 mitigation
+
+ -Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist
+ #-Wduplicated-cond # warn if if / else chain has duplicated conditions
+ #-Wduplicated-branches # warn if if / else branches have duplicated code
+ #-Wlogical-op # warn about logical operations being used where bitwise were probably wanted
+ #-Wuseless-cast # warn if you perform a cast to the same type
+ )
+
+ if(MSVC)
+ add_compile_options(${MSVC_WARNINGS})
+ message(STATUS "added ${MSVC_WARNINGS}")
+ else()
+ add_compile_options(${BASE_WARNINGS})
+ message(STATUS "added ${BASE_WARNINGS}")
+ endif()
+endfunction()
diff --git a/cmake/Sanitize.cmake b/cmake/Sanitize.cmake
new file mode 100644
index 0000000..29f7fa5
--- /dev/null
+++ b/cmake/Sanitize.cmake
@@ -0,0 +1,33 @@
+include(CheckCXXCompilerFlag)
+include(CheckLinkerFlag)
+
+check_linker_flag(CXX -fsanitize=address cxx_asan)
+check_cxx_compiler_flag(-fsanitize=leak cxx_lsan)
+
+function(target_sanitize target_name)
+ option(sanitize_address "Use address sanitizer" ${cxx_asan})
+ option(sanitize_leak "Use leak sanitizer" ${cxx_lsan})
+
+ if(sanitize_address)
+ message(">>> using asan on ${target_name}")
+ target_compile_options(${target_name} PRIVATE -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer)
+ target_link_options(${target_name} PRIVATE -fsanitize=address)
+ endif()
+
+ if(sanitize_leak)
+ message(">>> using lsan on ${target_name}")
+ target_compile_options(${target_name} PRIVATE -fsanitize=leak -fno-omit-frame-pointer)
+ target_link_options(${target_name} PRIVATE -fsanitize=leak)
+ endif()
+endfunction()
+
+function(target_sanitize_fuzzer target_name)
+ if(NOT ${CMAKE_CXX_COMPILER_ID} MATCHES Clang)
+ message("Cannot sanitize with ${CMAKE_CXX_COMPILER_ID} (needs clang)")
+ return()
+ endif()
+
+ set_target_properties(${target_name} PROPERTIES
+ COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=fuzzer"
+ LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=fuzzer")
+endfunction()
diff --git a/cmake/StandardProjectSettings.cmake b/cmake/StandardProjectSettings.cmake
new file mode 100644
index 0000000..bd88a73
--- /dev/null
+++ b/cmake/StandardProjectSettings.cmake
@@ -0,0 +1,44 @@
+# from here:
+# https://github.com/lefticus/cpp_starter_project/blob/master/cmake/StandardProjectSettings.cmake
+
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# Set a default build type if none was specified
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+ message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.")
+ set(CMAKE_BUILD_TYPE
+ RelWithDebInfo
+ CACHE STRING "Choose the type of build." FORCE)
+ # Set the possible values of build type for cmake-gui, ccmake
+ set_property(
+ CACHE CMAKE_BUILD_TYPE
+ PROPERTY STRINGS
+ "Debug"
+ "Release"
+ "MinSizeRel"
+ "RelWithDebInfo")
+endif()
+
+# Generate compile_commands.json to make it easier to work with clang based tools
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+option(ENABLE_IPO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)" OFF)
+if(ENABLE_IPO)
+ include(CheckIPOSupported)
+ check_ipo_supported(RESULT result OUTPUT output)
+ if(result)
+ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+ else()
+ message(SEND_ERROR "IPO is not supported: ${output}")
+ endif()
+endif()
+
+option(VCS_TAG "Read version information from git" ON)
+if(VCS_TAG)
+ find_program(VCS git)
+ execute_process(COMMAND git describe --abbrev=0 OUTPUT_VARIABLE CMAKE_PROJECT_SHORT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND git describe --long --abbrev=40 OUTPUT_VARIABLE CMAKE_PROJECT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
+else()
+ set(CMAKE_PROJECT_SHORT_VERSION ${CMAKE_PROJECT_VERSION})
+endif() \ No newline at end of file
diff --git a/cmake/ThirdParty.cmake b/cmake/ThirdParty.cmake
new file mode 100644
index 0000000..8e5b1cc
--- /dev/null
+++ b/cmake/ThirdParty.cmake
@@ -0,0 +1,17 @@
+function(download_third_party path url archive hash_type hash)
+
+ if(NOT EXISTS ${CMAKE_SOURCE_DIR}/third-party/${path})
+
+ if(NOT EXISTS ${CMAKE_BINARY_DIR}/${archive})
+ message("${CMAKE_BINARY_DIR}/${archive} missing")
+ message("Downloading ${url}...")
+ file(DOWNLOAD ${url} ${CMAKE_BINARY_DIR}/${archive}
+ TIMEOUT 60 TLS_VERIFY ON
+ EXPECTED_HASH ${hash_type}=${hash})
+ endif()
+
+ file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/${archive}
+ DESTINATION ${CMAKE_SOURCE_DIR}/third-party)
+ endif()
+
+endfunction()
diff --git a/cmake/lcov.cmake b/cmake/lcov.cmake
new file mode 100644
index 0000000..d6f990d
--- /dev/null
+++ b/cmake/lcov.cmake
@@ -0,0 +1,4 @@
+function(target_lcov target_name)
+ target_compile_options(${target_name} INTERFACE --coverage -O0 -g)
+ target_link_libraries(${target_name} INTERFACE --coverage)
+endfunction()
diff --git a/src/webengine/test/icon.svg b/data/poi_window.svg
index a348cab..a348cab 100644
--- a/src/webengine/test/icon.svg
+++ b/data/poi_window.svg
diff --git a/data/resources.qrc b/data/resources.qrc
deleted file mode 100644
index b872d19..0000000
--- a/data/resources.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file alias="icons/poi.svg">poi.svg</file>
- </qresource>
-</RCC>
diff --git a/doc/building.md b/doc/building.md
index 9ea9344..52fac6a 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -1,37 +1,12 @@
-## Building from source
-
-### Dependencies
-- [Qt](https://www.qt.io/)
-- [meson](https://mesonbuild.com/) 0.52.0 or later
-- [kconfiglib](https://github.com/ulfalizer/Kconfiglib/)
-- A compiler with C++17 support
-- spdlog: if not found can be downloaded by meson
-
-### Optional dependencies
-- openssl or libressl: for signing plugins
-- breakpad-client
-- gtest
+## Using meson
-### Steps
+### Picking compiler
```
-# clone the repository
-git clone https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote.git smolbote.git
-cd smolbote.git
-
-# Get the submodules
-git submodule init
-git submodule update
-
-# configure
-mkdir build
-meson build
-
-# make
-ninja
+# set the environment variables as desired
+export CXX='ccache clazy'
+export CXX_LD='lld'
```
-## Using meson
-
### Listing build options
```
build% meson configure
@@ -50,7 +25,8 @@ phase:
repo% meson --wrap-mode=nodownload build-path
```
-For more information on how to use meson, see the meson [quick quide](https://mesonbuild.com/Quick-guide.html).
+For more information on how to use meson, see the meson
+[quick quide](https://mesonbuild.com/Quick-guide.html).
## Configuring builds
smolbote uses Kconfig to store and customize features and default settings such
diff --git a/doc/man/CMakeLists.txt b/doc/man/CMakeLists.txt
new file mode 100644
index 0000000..309ff7c
--- /dev/null
+++ b/doc/man/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(MANPAGES smolbote.1;smolbote-profile.5;smolboterc.5)
+
+find_program(SCDOC scdoc)
+foreach(F ${MANPAGES})
+ add_custom_command(OUTPUT ${F} COMMAND ${SCDOC} < ${CMAKE_CURRENT_SOURCE_DIR}/${F}.scd > ${F} VERBATIM)
+endforeach()
+
+add_custom_target(man DEPENDS ${MANPAGES})
+install(FILES smolbote.1 DESTINATION /usr/local/man)
diff --git a/doc/man/smolbote.1.scd b/doc/man/smolbote.1.scd
index 758fda3..2cdc1ba 100644
--- a/doc/man/smolbote.1.scd
+++ b/doc/man/smolbote.1.scd
@@ -23,6 +23,9 @@ smolbote is a cross-platform keep-it-simple free software web browser that uses
- `-s, --session`: Open the selected session.
- `--pick-session`: Open all available sessions and select which one to open.
+## Env
+- 'POI_LOG_PATTERN'
+
# SEE ALSO
*smolboterc*(5) - configuration file and options++
diff --git a/doc/man/smolboterc.5.scd b/doc/man/smolboterc.5.scd
index f340c01..0286abd 100644
--- a/doc/man/smolboterc.5.scd
+++ b/doc/man/smolboterc.5.scd
@@ -6,7 +6,17 @@ smolbote - configuration file and options description
# DESCRIPTION
-The smolbote configuration is loaded at startup, and is not reloaded when
+Configuration is loaded at startup from one of the following locations:
+0. The location specified with the -c/--config flag
+1. $HOME/.poirc
+2. $XDG_CONFIG_HOME/smolbote.conf
+3. $XDG_CONFIG_HOME/smolbote/config
+4. $HOME/.config/smolbote.conf
+5. $HOME/.config/smolbote/config
+6. /etc/smolbote/config
+
+
+It is not reloaded when
changed. By default (without any plugins), the browser does not change its
configuration or overwrite this file. Thus, it can be made read-only.
diff --git a/doc/meson.build b/doc/meson.build
deleted file mode 100644
index 6490969..0000000
--- a/doc/meson.build
+++ /dev/null
@@ -1,16 +0,0 @@
-if not get_option('manpage')
- subdir_done()
-endif
-
-sh = find_program('sh', required: true, native: true, disabler: true)
-
-foreach f : [ 'smolbote.1', 'smolboterc.5', 'smolbote-profile.5' ]
-manpage = custom_target(f,
- input: 'man'/f+'.scd',
- output: '@BASENAME@',
- capture: true,
- command: [ sh, meson.current_source_dir()/'man/genroff.sh', '@INPUT@' ],
- install: true,
- install_dir: get_option('mandir')
-)
-endforeach
diff --git a/include/meson.build b/include/meson.build
deleted file mode 100644
index 1372c86..0000000
--- a/include/meson.build
+++ /dev/null
@@ -1,7 +0,0 @@
-plugininterfaces_include = include_directories('.')
-smolbote_include = include_directories('.')
-
-install_headers('smolbote/plugininterface.hpp', 'smolbote/filterinterface.hpp', 'smolbote/session.hpp',
- subdir: 'smolbote'
-)
-
diff --git a/include/singleton.hpp b/include/singleton.hpp
deleted file mode 100644
index d13e29e..0000000
--- a/include/singleton.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef SMOLBOTE_SINGLETON_HPP
-#define SMOLBOTE_SINGLETON_HPP
-
-/*
- * Clang consumed semantics
- * States can be: unconsumed, consumed, unknown
- * Mark classes with consumable(unconsumed)
- * Mark constructors with return_typestate(unconsumed)
- * Mark invalidating functions with set_typestate(consumed)
- */
-
-#if defined(__clang__)
-#define consumable(X) [[clang::consumable(X)]]
-#define return_typestate(X) [[clang::return_typestate(X)]]
-#define set_typestate(X) [[clang::set_typestate(X)]]
-#define callable_when(X) [[clang::callable_when(X)]]
-#define param_typestate(X) [[clang::param_typestate(X)]]
-
-#else
-#define consumable(X)
-#define return_typestate(X)
-#define set_typestate(X)
-#define callable_when(X)
-#define param_typestate(X)
-#endif
-
-#endif // SMOLBOTE_SINGLETON_HPP
diff --git a/lang/CMakeLists.txt b/lang/CMakeLists.txt
new file mode 100644
index 0000000..319c706
--- /dev/null
+++ b/lang/CMakeLists.txt
@@ -0,0 +1,10 @@
+# https://wiki.qt.io/How_to_create_a_multi_language_application
+
+# generating .ts files
+# lupdate -verbose src/ -ts output.ts
+
+# updating .ts files
+# lupdate -verbose -no-obsolete src/ -ts output.ts
+
+# creating the binary language files (.qm)
+# lrelease -compress -removeidentical input.ts [-qm output.qm]
diff --git a/lang/meson.build b/lang/meson.build
deleted file mode 100644
index 8c4a820..0000000
--- a/lang/meson.build
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# translations
-mod_qt5.compile_translations(ts_files: 'bg.ts', install: get_option('translations').enabled(), install_dir: get_option('datadir') / 'smolbote/translations' , build_by_default: false)
-
diff --git a/lib/bookmarks/CMakeLists.txt b/lib/bookmarks/CMakeLists.txt
new file mode 100644
index 0000000..50c2942
--- /dev/null
+++ b/lib/bookmarks/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_library(bookmarks STATIC
+ bookmarkmodel.h
+ bookmarkformat.cpp bookmarkitem.cpp bookmarkmodel.cpp
+ formats/xbel.cpp formats/ffjson.cpp)
+target_link_libraries(bookmarks PUBLIC Qt5::Widgets)
+target_include_directories(bookmarks PUBLIC .)
diff --git a/lib/bookmarks/meson.build b/lib/bookmarks/meson.build
deleted file mode 100644
index 81c1ece..0000000
--- a/lib/bookmarks/meson.build
+++ /dev/null
@@ -1,16 +0,0 @@
-bookmarks_moc = mod_qt5.preprocess(
- moc_headers: [ 'bookmarkmodel.h' ],
- dependencies: dep_qt5
-)
-
-bookmarks_lib = static_library('bookmarks',
- [ bookmarks_moc,
- 'bookmarkformat.cpp', 'formats/xbel.cpp', 'formats/ffjson.cpp',
- 'bookmarkitem.cpp', 'bookmarkmodel.cpp' ],
- dependencies: dep_qt5
-)
-
-dep_bookmarks = declare_dependency(
- include_directories: include_directories('.'),
- link_with: bookmarks_lib
-)
diff --git a/lib/configuration/CMakeLists.txt b/lib/configuration/CMakeLists.txt
new file mode 100644
index 0000000..6484a70
--- /dev/null
+++ b/lib/configuration/CMakeLists.txt
@@ -0,0 +1,24 @@
+add_library(configuration STATIC configuration.cpp qt_specialization.cpp)
+target_link_libraries(configuration PUBLIC Qt5::Widgets)
+target_include_directories(configuration INTERFACE .)
+
+add_executable(conf_parser test/main.cpp)
+target_compile_definitions(conf_parser PRIVATE NO_QT_SPEC)
+target_sanitize(conf_parser)
+target_link_libraries(conf_parser PRIVATE configuration Catch2::Catch2)
+
+add_executable(conf_parser_qt test/qt.cpp)
+target_link_libraries(conf_parser_qt PRIVATE configuration Catch2::Catch2)
+
+add_test(NAME conf_parser COMMAND conf_parser
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test")
+add_test(NAME conf_parser_qt COMMAND conf_parser_qt -platform offscreen
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test")
+set_tests_properties(conf_parser PROPERTIES ENVIRONMENT "CONFIGFILE=${CMAKE_CURRENT_SOURCE_DIR}/test/defaultrc.ini")
+set_tests_properties(conf_parser_qt PROPERTIES ENVIRONMENT "CONFIGFILE=${CMAKE_CURRENT_SOURCE_DIR}/test/defaultrc.ini")
+
+if(${CMAKE_CXX_COMPILER_ID} MATCHES Clang)
+ add_executable(conf_fuzzer configuration.cpp)
+ target_compile_definitions(conf_fuzzer PRIVATE FUZZER NO_QT_SPEC)
+ target_sanitize_fuzzer(conf_fuzzer)
+endif()
diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp
index 75f863c..d11b342 100644
--- a/lib/configuration/configuration.cpp
+++ b/lib/configuration/configuration.cpp
@@ -10,29 +10,28 @@
#include <algorithm>
#include <fstream>
#include <iostream>
-#include <sstream>
#include <stdexcept>
#ifndef NO_QT_SPEC
#include <QStandardPaths>
#endif
-static std::unique_ptr<Configuration> s_conf;
+static const Configuration *s_conf = nullptr;
Configuration::Configuration()
: use_global(true)
{
- if(!s_conf) {
+ if(s_conf == nullptr) {
throw std::runtime_error("Trying to use default Configuration, but none has been set!");
}
}
-Configuration::Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept
+Configuration::Configuration(const std::initializer_list<std::pair<std::string, conf_value_t>> &list) noexcept
#ifndef NO_QT_SPEC
: m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString())
#endif
{
- for(const auto &i : l) {
+ for(const auto &i : list) {
insert_or_assign(i.first, i.second);
}
}
@@ -53,20 +52,36 @@ inline auto strip(std::string &value)
return value;
}
-inline auto parse(const std::string &line, std::string &section)
+enum parse_result {
+ None,
+ Pair,
+ Section,
+ Include,
+};
+
+inline auto parse(const std::string &line, const std::string &section)
{
struct {
- bool pair = false;
+ parse_result result = None;
std::string key;
std::string value;
} ret;
- if(line[0] == '#' || line.length() == 0) {
+ if(line.front() == '#' || line.length() == 0) {
+ return ret;
+ }
+
+ if(line.starts_with("@@")) {
+ if(line.starts_with("@@include ")) {
+ ret.result = parse_result::Include;
+ ret.key = line.substr(10);
+ }
return ret;
}
if(line.front() == '[' && line.back() == ']') {
- section = line.substr(1, line.length() - 2) + '/';
+ ret.result = parse_result::Section;
+ ret.key = line.substr(1, line.length() - 2) + '/';
return ret;
}
@@ -85,7 +100,7 @@ inline auto parse(const std::string &line, std::string &section)
ret.value = line.substr(pos + 1);
strip(ret.value);
- ret.pair = true;
+ ret.result = parse_result::Pair;
return ret;
}
@@ -93,7 +108,7 @@ inline auto parse(const std::string &line, std::string &section)
extern "C" int LLVMFuzzerTestOneInput(const char *Data, long long Size)
{
std::string section;
- parse(std::string(Data, Size), section);
+ parse(std::string(Data, static_cast<unsigned long>(Size)), section);
return 0;
}
#endif
@@ -103,45 +118,59 @@ void Configuration::read(std::basic_istream<char> &input)
std::string line, section;
while(std::getline(input, line)) {
- if(line.rfind("@@") == 0) {
- if(line.rfind("@@include ") == 0) {
- read_file(line.substr(10));
- }
- continue;
+ const auto p = parse(line, section);
+ switch(p.result) {
+ case parse_result::None:
+ break;
+ case parse_result::Section:
+ section = p.key;
+ break;
+ case parse_result::Include:
+ read_file(p.key);
+ break;
+ case parse_result::Pair:
+ setValue(p.key, p.value);
+ break;
}
+ }
+}
+
+void Configuration::setValue(const std::string &key, const std::string &value)
+{
+ if(use_global) {
+ throw std::runtime_error("Global configuration is read-only!");
+ }
- const auto pair = parse(line, section);
- if(pair.pair) {
-
- if(this->count(pair.key) == 0) {
- // no type has been specified for this key, assuming std::string
- insert(std::make_pair(pair.key, pair.value));
- continue;
- }
-
- auto v = at(pair.key);
- if(std::holds_alternative<std::string>(v)) {
- at(pair.key) = pair.value;
- } else if(std::holds_alternative<int>(v)) {
- at(pair.key) = std::stoi(pair.value);
- } else if(std::holds_alternative<bool>(v)) {
- at(pair.key) = (pair.value == "true");
- }
+ if(this->count(key) == 0) {
+ insert(std::make_pair(key, value));
+ } else {
+ auto v = at(key);
+ if(std::holds_alternative<std::string>(v)) {
+ at(key) = value;
+ } else if(std::holds_alternative<int>(v)) {
+ at(key) = std::stoi(value);
+ } else if(std::holds_alternative<bool>(v)) {
+ at(key) = (value == "true");
}
}
}
-void Configuration::move_global(std::unique_ptr<Configuration> &&conf)
+bool Configuration::make_global()
{
- s_conf = std::move(conf);
+ if(use_global || s_conf != nullptr) {
+ return false;
+ }
+
+ s_conf = this;
+ return true;
}
-Configuration *Configuration::instance()
+const Configuration *Configuration::instance()
{
- return s_conf.get();
+ return s_conf;
}
-std::ostream &operator<<(std::ostream &out, const Configuration &obj)
+std::ostream &operator<<(std::ostream &out, const Configuration &obj param_typestate(unconsumed))
{
if(obj.use_global) {
out << *s_conf;
diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h
index cd3c244..a80d8e5 100644
--- a/lib/configuration/configuration.h
+++ b/lib/configuration/configuration.h
@@ -29,7 +29,7 @@
#define param_typestate(X)
#endif
-typedef std::variant<std::string, int, bool> conf_value_t;
+using conf_value_t = std::variant<std::string, int, bool>;
template <typename T>
concept concept_value_t = std::is_arithmetic<T>::value || std::is_same<T, bool>::value || std::is_constructible<T, std::string>::value;
@@ -40,7 +40,7 @@ class consumable(unconsumed) Configuration : private std::unordered_map<std::str
public:
return_typestate(unconsumed) Configuration();
- return_typestate(unconsumed) Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept;
+ return_typestate(unconsumed) Configuration(const std::initializer_list<std::pair<std::string, conf_value_t>> &list) noexcept;
Configuration(const Configuration &) = delete;
Configuration &operator=(const Configuration &) = delete;
@@ -126,10 +126,12 @@ public:
return T{};
}
- static void move_global(std::unique_ptr<Configuration> && conf);
+ callable_when(unconsumed) void setValue(const std::string &key, const std::string &value);
+
+ bool make_global();
private:
- static Configuration *instance();
+ static const Configuration *instance();
const std::string m_homePath;
const bool use_global = false;
diff --git a/lib/configuration/meson.build b/lib/configuration/meson.build
deleted file mode 100644
index 5e3e4b2..0000000
--- a/lib/configuration/meson.build
+++ /dev/null
@@ -1,22 +0,0 @@
-dep_configuration = declare_dependency(
- include_directories: include_directories('.'),
- link_with: static_library('configuration', ['configuration.cpp', 'qt_specialization.cpp'], dependencies: dep_qt5)
-)
-
-test('conf parser', executable('configuration-parser',
- sources: [ 'test/main.cpp' ],
- dependencies: [ dep_qt5, dep_catch, dep_configuration ]
- ),
- env: 'CONFIGFILE='+meson.current_source_dir()/'test/defaultrc.ini',
- args: [ '-platform', 'offscreen' ],
- workdir: meson.current_source_dir()/'test'
-)
-
-if meson.get_compiler('cpp').has_multi_arguments('-g', '-fsanitize=fuzzer')
-executable('configuration-fuzzer',
- sources: 'configuration.cpp',
- cpp_args: [ '-g', '-fsanitize=fuzzer', '-DNO_QT_SPEC', '-DFUZZER' ],
- link_args: [ '-fsanitize=fuzzer' ]
-# args: [ '-seed=1', '-max_total_time=24', meson.current_source_dir()/'test/corpus' ]
-)
-endif
diff --git a/lib/configuration/test/main.cpp b/lib/configuration/test/main.cpp
index fa04f10..9c83f8b 100644
--- a/lib/configuration/test/main.cpp
+++ b/lib/configuration/test/main.cpp
@@ -1,9 +1,7 @@
-#define CATCH_CONFIG_RUNNER
-
// clazy:excludeall=non-pod-global-static
+#define CATCH_CONFIG_MAIN
#include "configuration.h"
-#include <QApplication>
#include <catch2/catch.hpp>
SCENARIO("Configuration")
@@ -17,22 +15,22 @@ SCENARIO("Configuration")
{ "other", std::string("not in cfg") },
// commented out entry in the conf file
{ "comment", std::string("123.456") },
- { "number", int(0) },
- { "toggle", bool(false) },
+ { "number", 0 },
+ { "toggle", false },
{ "main/name", std::string() },
- { "main/number", int(0) },
- { "main/toggle", bool(true) },
+ { "main/number", 0 },
+ { "main/toggle", true },
{ "extra/name", std::string() },
- { "extra/number", int(0) },
- { "extra/toggle", bool(false) },
+ { "extra/number", 0 },
+ { "extra/toggle", false },
};
WHEN("reading default values")
{
REQUIRE(conf.value<std::string>("name"));
- REQUIRE(conf.value<std::string>("name").value() == std::string());
+ REQUIRE(conf.value<std::string>("name").value().empty());
REQUIRE(conf.value<int>("number"));
REQUIRE(conf.value<int>("number").value() == 0);
REQUIRE(conf.value<bool>("toggle"));
@@ -43,7 +41,7 @@ SCENARIO("Configuration")
REQUIRE(!conf.value<std::string>("nullopt"));
REQUIRE(conf.value<std::string>("main/name"));
- REQUIRE(conf.value<std::string>("main/name").value() == std::string());
+ REQUIRE(conf.value<std::string>("main/name").value().empty());
REQUIRE(conf.value<int>("main/number"));
REQUIRE(conf.value<int>("main/number").value() == 0);
REQUIRE(conf.value<bool>("main/toggle"));
@@ -101,30 +99,6 @@ SCENARIO("Configuration")
REQUIRE(conf.value<std::string>("toggle").value() == "true");
REQUIRE(conf.value<std::string>("main/toggle").value() == "false");
}
-
- THEN("Qt cast specialization")
- {
- REQUIRE(conf.value<QString>("name").value() == "Top level");
- REQUIRE(conf.value<QString>("number").value() == "12");
- REQUIRE(conf.value<QString>("toggle").value() == "true");
- REQUIRE(conf.value<QString>("main/toggle").value() == "false");
- REQUIRE(!conf.value<QString>("nullopt"));
-
- REQUIRE(conf.value<QStringList>("list").value() == QStringList({ "one", "two", "three", "for four" }));
- REQUIRE(!conf.value<QStringList>("nullopt"));
- }
-
- THEN("Qt shortcut")
- {
- REQUIRE(conf.value<std::string>("qt/shortcut") == "Ctrl+Q");
- QAction action;
- REQUIRE(conf.shortcut<QAction>(action, "qt/shortcut").shortcut().toString() == "Ctrl+Q");
- REQUIRE(conf.shortcut<QAction>(action, "qt/nil").shortcut().toString() == "Ctrl+Q");
-
- QKeySequence sequence;
- REQUIRE(conf.shortcut<QKeySequence>(sequence, "qt/shortcut").toString() == "Ctrl+Q");
- REQUIRE(conf.shortcut<QKeySequence>(sequence, "qt/nil").toString() == "Ctrl+Q");
- }
}
}
@@ -132,8 +106,8 @@ SCENARIO("Configuration")
{
std::unique_ptr<Configuration> global_conf = std::make_unique<Configuration, std::initializer_list<std::pair<std::string, conf_value_t>>>({
{ "name", std::string("global") },
- { "number", int(123) },
- { "toggle", bool(true) },
+ { "number", 123 },
+ { "toggle", true },
});
@@ -151,7 +125,7 @@ SCENARIO("Configuration")
output << *global_conf;
REQUIRE(output.str() == "name=global\nnumber=123\ntoggle=true\n");
- Configuration::move_global(std::move(global_conf));
+ global_conf->make_global();
Configuration g;
REQUIRE(g.value<std::string>("name"));
REQUIRE(g.value<std::string>("name").value() == "global");
@@ -167,10 +141,3 @@ SCENARIO("Configuration")
}
}
}
-
-int main(int argc, char **argv)
-{
- QApplication app(argc, argv);
- int result = Catch::Session().run(argc, argv);
- return result;
-}
diff --git a/lib/configuration/test/qt.cpp b/lib/configuration/test/qt.cpp
new file mode 100644
index 0000000..44114df
--- /dev/null
+++ b/lib/configuration/test/qt.cpp
@@ -0,0 +1,71 @@
+// clazy:excludeall=non-pod-global-static
+#define CATCH_CONFIG_RUNNER
+
+#include "configuration.h"
+#include <QApplication>
+#include <catch2/catch.hpp>
+
+SCENARIO("Configuration")
+{
+ GIVEN("a Configuration object with some initial values")
+ {
+ Configuration conf{
+ { "name", std::string() },
+ { "over", std::string() },
+ // this entry is not in the conf file
+ { "other", std::string("not in cfg") },
+ // commented out entry in the conf file
+ { "comment", std::string("123.456") },
+ { "number", 0 },
+ { "toggle", false },
+
+ { "main/name", std::string() },
+ { "main/number", 0 },
+ { "main/toggle", true },
+
+ { "extra/name", std::string() },
+ { "extra/number", 0 },
+ { "extra/toggle", false },
+ };
+
+ WHEN("reading default values")
+ {
+ }
+
+ WHEN("reading configuration file")
+ {
+ conf.read_file(std::getenv("CONFIGFILE"));
+
+ THEN("Qt cast specialization")
+ {
+ REQUIRE(conf.value<QString>("name").value() == "Top level");
+ REQUIRE(conf.value<QString>("number").value() == "12");
+ REQUIRE(conf.value<QString>("toggle").value() == "true");
+ REQUIRE(conf.value<QString>("main/toggle").value() == "false");
+ REQUIRE(!conf.value<QString>("nullopt"));
+
+ REQUIRE(conf.value<QStringList>("list").value() == QStringList({ "one", "two", "three", "for four" }));
+ REQUIRE(!conf.value<QStringList>("nullopt"));
+ }
+
+ THEN("Qt shortcut")
+ {
+ REQUIRE(conf.value<std::string>("qt/shortcut") == "Ctrl+Q");
+ QAction action;
+ REQUIRE(conf.shortcut<QAction>(action, "qt/shortcut").shortcut().toString() == "Ctrl+Q");
+ REQUIRE(conf.shortcut<QAction>(action, "qt/nil").shortcut().toString() == "Ctrl+Q");
+
+ QKeySequence sequence;
+ REQUIRE(conf.shortcut<QKeySequence>(sequence, "qt/shortcut").toString() == "Ctrl+Q");
+ REQUIRE(conf.shortcut<QKeySequence>(sequence, "qt/nil").toString() == "Ctrl+Q");
+ }
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ int result = Catch::Session().run(argc, argv);
+ return result;
+}
diff --git a/lib/downloads/CMakeLists.txt b/lib/downloads/CMakeLists.txt
new file mode 100644
index 0000000..984d332
--- /dev/null
+++ b/lib/downloads/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_library(downloads
+ downloadswidget.h downloadswidget.cpp downloadsform.ui
+ widgets/downloaditemwidget.h widgets/downloaditemwidget.cpp widgets/downloaditemform.ui
+ widgets/elidedlabel.h widgets/elidedlabel.cpp)
+target_link_libraries(downloads PUBLIC Qt5::WebEngineWidgets)
+target_include_directories(downloads PUBLIC .)
diff --git a/lib/downloads/meson.build b/lib/downloads/meson.build
deleted file mode 100644
index 9b86391..0000000
--- a/lib/downloads/meson.build
+++ /dev/null
@@ -1,19 +0,0 @@
-downloads_inc = include_directories('.')
-downloads_moc = mod_qt5.preprocess(
- moc_headers: ['downloadswidget.h', 'widgets/downloaditemwidget.h', 'widgets/elidedlabel.h'],
- ui_files: ['downloadsform.ui', 'widgets/downloaditemform.ui'],
- dependencies: dep_qt5
-)
-
-downloads_lib = static_library('downloads',
- ['downloadswidget.cpp', downloads_moc,
- 'widgets/downloaditemwidget.cpp', 'widgets/elidedlabel.cpp'],
- dependencies: dep_qt5
-)
-
-dep_downloads = declare_dependency(
- include_directories: downloads_inc,
- link_with: downloads_lib,
- sources: ['downloadswidget.cpp', downloads_moc,
- 'widgets/downloaditemwidget.cpp', 'widgets/elidedlabel.cpp']
-)
diff --git a/lib/downloads/widgets/downloaditemwidget.cpp b/lib/downloads/widgets/downloaditemwidget.cpp
index e0c8a60..cb95965 100644
--- a/lib/downloads/widgets/downloaditemwidget.cpp
+++ b/lib/downloads/widgets/downloaditemwidget.cpp
@@ -34,8 +34,8 @@ DownloadItemWidget::DownloadItemWidget(QWebEngineDownloadItem *m_item, QWidget *
: QWidget(parent)
, ui(new Ui::DownloadItemForm)
{
- Q_CHECK_PTR(item);
- m_item = item;
+ Q_CHECK_PTR(m_item);
+ item = m_item;
ui->setupUi(this);
{
// pause/resume icons
diff --git a/lib/pluginloader/CMakeLists.txt b/lib/pluginloader/CMakeLists.txt
new file mode 100644
index 0000000..e0c8270
--- /dev/null
+++ b/lib/pluginloader/CMakeLists.txt
@@ -0,0 +1,54 @@
+find_program(SSL openssl)
+find_program(PYTHON python3)
+
+# generate a keypair
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/keypair.pem"
+ COMMAND ${SSL} genrsa -out "${CMAKE_CURRENT_BINARY_DIR}/keypair.pem" 4096)
+
+# export public key
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pubkey.pem"
+ DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/keypair.pem"
+ COMMAND ${SSL} rsa -in "${CMAKE_CURRENT_BINARY_DIR}/keypair.pem" -pubout -out "${CMAKE_CURRENT_BINARY_DIR}/pubkey.pem")
+
+# turn the public key into a header
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/publicKey.h"
+ DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pubkey.pem"
+ COMMAND ${PYTHON} "${CMAKE_CURRENT_SOURCE_DIR}/ssl-keygen.py"
+ --private "${CMAKE_CURRENT_BINARY_DIR}/keypair.pem"
+ --public "${CMAKE_CURRENT_BINARY_DIR}/pubkey.pem"
+ --output "${CMAKE_CURRENT_BINARY_DIR}/publicKey.h" --array-name=publicKey_pem)
+
+add_library(pluginloader STATIC pluginloader.h pluginloader.cpp "${CMAKE_CURRENT_BINARY_DIR}/publicKey.h")
+target_link_libraries(pluginloader PUBLIC OpenSSL::SSL Qt5::Core)
+target_include_directories(pluginloader PUBLIC . PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+
+## Testing
+# sigmatch
+add_executable(pluginloader_sigmatch test/pluginloader-sigmatch.cpp)
+target_link_libraries(pluginloader_sigmatch PRIVATE pluginloader Catch2::Catch2 fmt)
+#target_sanitize(pluginloader_sigmatch)
+
+# load
+add_executable(pluginloader_load test/pluginloader-load.cpp)
+target_link_libraries(pluginloader_load PRIVATE pluginloader Catch2::Catch2 fmt)
+target_sanitize(pluginloader_load)
+
+# generate a random file and properly sign it
+add_test(NAME good.dat COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/write-random.py --output=good.dat)
+add_test(NAME good.dat.sig COMMAND ${SSL} dgst -sha256 -sign=keypair.pem -out=good.dat.sig good.dat)
+set_tests_properties(good.dat.sig PROPERTIES DEPENDS good.dat)
+# generate a random file and improperly sign it
+add_test(NAME bad.dat COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/write-random.py --output=bad.dat)
+add_test(NAME bad.dat.sig COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/write-random.py --output=bad.dat.sig)
+# generate a random file and don't sign it
+add_test(NAME none.dat COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/write-random.py --output=none.dat)
+
+add_test(NAME pluginloader_sigmatch COMMAND pluginloader_sigmatch)
+set_tests_properties(pluginloader_sigmatch PROPERTIES
+ DEPENDS "good.dat;good.dat.sig;bad.dat;bad.dat.sig;none.dat"
+ REQUIRED_FILES "good.dat;good.dat.sig;bad.dat;bad.dat.sig;none.dat"
+ ENVIRONMENT "SIGNEDFILE=${CMAKE_CURRENT_BINARY_DIR}/good.dat;UNSIGNEDFILE=${CMAKE_CURRENT_BINARY_DIR}/none.dat;BADSIGNEDFILE=${CMAKE_CURRENT_BINARY_DIR}/bad.dat")
+
+# make sure this fails when no plugin or an invalid file is passed
+#test('load', poi_plugin_loader, suite: 'pluginloader', should_fail: true)
+#test('load', poi_plugin_loader, suite: 'pluginloader', args: files('meson.build'), should_fail: true)
diff --git a/lib/pluginloader/meson.build b/lib/pluginloader/meson.build
deleted file mode 100644
index 5e7c39c..0000000
--- a/lib/pluginloader/meson.build
+++ /dev/null
@@ -1,68 +0,0 @@
-python = import('python')
-python3 = python.find_installation('python3')
-
-openssl = find_program('openssl', required: true)
-
-private_pem = custom_target('privateKey.pem',
- output: 'privateKey.pem',
- command: [ openssl, 'genrsa', '-out', '@OUTPUT@', '4096' ]
-)
-
-public_pem = custom_target('publicKey.pem',
- input: private_pem,
- output: 'publicKey.pem',
- command: [ openssl, 'rsa', '-in', '@INPUT@', '-pubout', '-out', '@OUTPUT@' ]
-)
-
-publicKey_h = custom_target('publicKey_h',
- input: files('ssl-keygen.py'),
- output: 'publicKey.h',
- command: [python3, '@INPUT@',
- '--private', private_pem, '--public', public_pem,
- '--output=@OUTPUT@', '--array-name=publicKey_pem']
-)
-
-dep_pluginloader = declare_dependency(
- include_directories: include_directories('.'),
- link_with: static_library('plugin',
- ['pluginloader.cpp', publicKey_h],
- include_directories: include_directories('.'),
- dependencies: [dep_qt5, dependency('openssl', required: true)])
-)
-
-# generate a test file that would be signed
-unsignedfile_dat = custom_target('unsignedfile.dat', input: 'write-random.py', output: 'unsignedfile.dat', command: [ python3, '@INPUT@', '--output=@OUTPUT@' ])
-
-signedfile_dat = custom_target('signedfile.dat', input: 'write-random.py', output: 'signedfile.dat', command: [ python3, '@INPUT@', '--output=@OUTPUT@' ])
-
-badsignedfile_dat = custom_target('badsignedfile.dat', input: 'write-random.py', output: 'badsignedfile.dat', command: [ python3, '@INPUT@', '--output=@OUTPUT@' ])
-badsignedfile_sig = custom_target('badsignedfile.dat.sig', input: 'write-random.py', output: 'badsignedfile.dat.sig', command: [ python3, '@INPUT@', '--output=@OUTPUT@' ])
-
-# sign test file
-signedfile_sig = custom_target('signedfile.dat.sig',
- input: signedfile_dat,
- output: 'signedfile.dat.sig',
- command: [ openssl, 'dgst', '-sha256', '-sign', private_pem, '-out', '@OUTPUT@', '@INPUT@' ]
-)
-
-signedfile_idep = declare_dependency(sources: [ unsignedfile_dat, signedfile_dat, signedfile_sig, badsignedfile_dat, badsignedfile_sig ])
-
-pluginloader_sigmatch = executable('pluginloader-sigmatch',
- sources: [ 'test/pluginloader-sigmatch.cpp' ],
- dependencies: [ dep_qt5, dep_catch, dep_pluginloader, signedfile_idep ]
-)
-
-test('signature matching', pluginloader_sigmatch, suite: 'pluginloader',
- env: {
- 'SIGNEDFILE' : signedfile_dat.full_path(),
- 'UNSIGNEDFILE': unsignedfile_dat.full_path(),
- 'BADSIGNEDFILE': badsignedfile_dat.full_path()
- },
-)
-
-poi_plugin_loader = executable('poi-plugin-load', dependencies: [ dep_qt5, dep_spdlog, dep_pluginloader ], sources: 'test/pluginloader-load.cpp')
-
-# make sure this fails when no plugin or an invalid file is passed
-test('load', poi_plugin_loader, suite: 'pluginloader', should_fail: true)
-test('load', poi_plugin_loader, suite: 'pluginloader', args: files('meson.build'), should_fail: true)
-
diff --git a/lib/pluginloader/pluginloader.cpp b/lib/pluginloader/pluginloader.cpp
index ce84c7a..d4c3dff 100644
--- a/lib/pluginloader/pluginloader.cpp
+++ b/lib/pluginloader/pluginloader.cpp
@@ -17,8 +17,8 @@
bool PluginLoader::verify(const char *hashName)
{
const std::filesystem::path plugin_path(fileName().toStdString());
- if(!std::filesystem::is_regular_file(plugin_path)) {
- m_sigError = tr("A plugin is required, but none was found.");
+ if(!std::filesystem::exists(plugin_path)) {
+ m_sigError = tr("Plugin doesn't exist.");
return false;
}
diff --git a/lib/pluginloader/pluginloader.h b/lib/pluginloader/pluginloader.h
index cc67901..bb5e1e0 100644
--- a/lib/pluginloader/pluginloader.h
+++ b/lib/pluginloader/pluginloader.h
@@ -16,13 +16,12 @@ public:
SigChecked = (1 << 1),
SigEnforced = (1 << 2),
};
- typedef unsigned int signature_state_t;
- static signature_state_t signature_state(bool ignore, bool check, bool enforce)
+ static constexpr signature_level signature_state(bool ignore, bool check, bool enforce)
{
- return (static_cast<unsigned int>(enforce) << 2) | (static_cast<unsigned int>(check) << 1) | static_cast<unsigned int>(ignore);
+ return enforce ? signature_level::SigEnforced : (check ? signature_level::SigChecked : signature_level::SigIgnored);
}
- PluginLoader(const QString &fileName, const signature_state_t state, QObject *parent = nullptr)
+ PluginLoader(const QString &fileName, const signature_level state, QObject *parent = nullptr)
: QPluginLoader(fileName, parent)
, m_state(state)
{
@@ -45,6 +44,6 @@ public:
bool verify(const char *hashName = "SHA256");
private:
- const signature_state_t m_state;
+ const signature_level m_state;
QString m_sigError;
};
diff --git a/lib/pluginloader/test/pluginloader-sigmatch.cpp b/lib/pluginloader/test/pluginloader-sigmatch.cpp
index 0f4789a..fab8b5a 100644
--- a/lib/pluginloader/test/pluginloader-sigmatch.cpp
+++ b/lib/pluginloader/test/pluginloader-sigmatch.cpp
@@ -23,28 +23,40 @@ TEST_CASE("PluginLoader::signature_state")
REQUIRE(PluginLoader::signature_state(true, true, true) >= PluginLoader::SigEnforced);
}
-TEST_CASE("files")
+SCENARIO("PluginLoader")
{
- REQUIRE(qEnvironmentVariableIsSet("UNSIGNEDFILE"));
- REQUIRE(qEnvironmentVariableIsSet("SIGNEDFILE"));
- REQUIRE(qEnvironmentVariableIsSet("BADSIGNEDFILE"));
-}
-
-TEST_CASE("PluginLoader::verify missing plugin")
-{
- const auto state = PluginLoader::signature_state(false, false, false);
- PluginLoader loader("", state);
-
- REQUIRE_FALSE(loader.verify());
- REQUIRE_FALSE(loader.errorString().isEmpty());
-}
-
-TEST_CASE("PluginLoader::verify signature ignored")
-{
- const auto state = PluginLoader::signature_state(true, false, false);
- PluginLoader loader(qgetenv("UNSIGNEDFILE"), state);
-
- REQUIRE(loader.verify());
+ GIVEN("no plugin") {
+ const auto state = PluginLoader::signature_state(false, false, false);
+ PluginLoader loader("", state);
+
+ CHECK_FALSE(loader.verify());
+ CHECK_FALSE(loader.errorString().isEmpty());
+ }
+
+ GIVEN("A plugin with no signature")
+ {
+ const auto f = qgetenv("UNSIGNEDFILE");
+ REQUIRE(!f.isEmpty());
+
+ WHEN("sig is ignored") {
+ const auto state = PluginLoader::signature_state(true, false, false);
+ PluginLoader loader(f, state);
+
+ THEN("verify ok") {
+ REQUIRE(loader.verify());
+ }
+ }
+ }
+
+ GIVEN("A signed plugin")
+ {
+ REQUIRE(qEnvironmentVariableIsSet("SIGNEDFILE"));
+ }
+
+ GIVEN("A badly signed plugin")
+ {
+ REQUIRE(qEnvironmentVariableIsSet("BADSIGNEDFILE"));
+ }
}
TEST_CASE("PluginLoader::verify signature checked [avialable]")
@@ -96,4 +108,4 @@ TEST_CASE("PluginLoader::verify signature enforced [bad]")
REQUIRE_FALSE(loader.verify());
REQUIRE_FALSE(loader.errorString().isEmpty());
-}
+} \ No newline at end of file
diff --git a/lib/session_formats/CMakeLists.txt b/lib/session_formats/CMakeLists.txt
new file mode 100644
index 0000000..75a472c
--- /dev/null
+++ b/lib/session_formats/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(session_formats STATIC session_json.hpp session_json.cpp)
+target_link_libraries(session_formats PUBLIC Qt5::Core)
+target_include_directories(session_formats INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC "${CMAKE_SOURCE_DIR}/include")
+
+add_executable(session_json test/json.cpp)
+target_link_libraries(session_json PRIVATE session_formats Catch2::Catch2)
+target_sanitize(session_json)
+add_test(NAME session-json_format COMMAND session_json) \ No newline at end of file
diff --git a/lib/session_formats/meson.build b/lib/session_formats/meson.build
deleted file mode 100644
index 8d52455..0000000
--- a/lib/session_formats/meson.build
+++ /dev/null
@@ -1,9 +0,0 @@
-lib_session_formats = declare_dependency(
- include_directories: [ '.', plugininterfaces_include ],
- link_with: library('sessionformats', [ 'session_json.cpp' ], include_directories: plugininterfaces_include, dependencies: dep_qt5)
-)
-
-test('session: json format', executable('session_json',
- sources: 'test/json.cpp',
- dependencies: [ dep_qt5, dep_catch, lib_session_formats ]
-))
diff --git a/lib/session_formats/session_json.hpp b/lib/session_formats/session_json.hpp
index 142d9ef..2de6f5b 100644
--- a/lib/session_formats/session_json.hpp
+++ b/lib/session_formats/session_json.hpp
@@ -10,7 +10,7 @@
#define SESSION_JSON_HPP
#include <QJsonObject>
-#include "smolbote/session.hpp"
+#include <smolbote/session.hpp>
class JsonSession : public Session
{
diff --git a/lib/smolblok/CMakeLists.txt b/lib/smolblok/CMakeLists.txt
new file mode 100644
index 0000000..80d419a
--- /dev/null
+++ b/lib/smolblok/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(smolblok STATIC smolblok.hpp smolblok.cpp)
+target_link_libraries(smolblok PUBLIC Qt5::WebEngineWidgets)
+target_include_directories(smolblok
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC "${CMAKE_SOURCE_DIR}/include")
+
+add_executable(smolblok-load test/loader.cpp)
+target_link_libraries(smolblok-load PRIVATE smolblok fmt spdlog) \ No newline at end of file
diff --git a/staging/smolblok/README.md b/lib/smolblok/README.md
index 1793009..1793009 100644
--- a/staging/smolblok/README.md
+++ b/lib/smolblok/README.md
diff --git a/staging/smolblok/filtermanager.hpp b/lib/smolblok/filtermanager.hpp
index 6ee4d3f..6ee4d3f 100644
--- a/staging/smolblok/filtermanager.hpp
+++ b/lib/smolblok/filtermanager.hpp
diff --git a/staging/smolblok/smolblok.cpp b/lib/smolblok/smolblok.cpp
index 465c348..465c348 100644
--- a/staging/smolblok/smolblok.cpp
+++ b/lib/smolblok/smolblok.cpp
diff --git a/staging/smolblok/smolblok.hpp b/lib/smolblok/smolblok.hpp
index e547d67..dc79232 100644
--- a/staging/smolblok/smolblok.hpp
+++ b/lib/smolblok/smolblok.hpp
@@ -10,9 +10,9 @@
#define SMOLBOTE_SMOLBLOK_HPP
#include "filtermanager.hpp"
+#include "smolbote/filterinterface.hpp"
#include <QPluginLoader>
#include <QWebEngineUrlRequestInterceptor>
-#include <smolbote/filterinterface.hpp>
class smolblok
{
@@ -56,7 +56,7 @@ public:
return ret;
}
- const auto formats() const
+ auto formats() const
{
return m_formats.keys();
}
diff --git a/staging/smolblok/test/loader.cpp b/lib/smolblok/test/loader.cpp
index 9e27a26..9e27a26 100644
--- a/staging/smolblok/test/loader.cpp
+++ b/lib/smolblok/test/loader.cpp
diff --git a/staging/smolblok/test/main.cpp b/lib/smolblok/test/main.cpp
index 5624ee9..5624ee9 100644
--- a/staging/smolblok/test/main.cpp
+++ b/lib/smolblok/test/main.cpp
diff --git a/staging/smolblok/test/sample-filters.txt b/lib/smolblok/test/sample-filters.txt
index 59e0e7b..59e0e7b 100644
--- a/staging/smolblok/test/sample-filters.txt
+++ b/lib/smolblok/test/sample-filters.txt
diff --git a/lib/webengine/CMakeLists.txt b/lib/webengine/CMakeLists.txt
new file mode 100644
index 0000000..3e5fa71
--- /dev/null
+++ b/lib/webengine/CMakeLists.txt
@@ -0,0 +1,21 @@
+add_library(webengine STATIC
+ webprofile.h webprofile.cpp webprofilemanager.h webprofilemanager.cpp
+ webpage.h webpage.cpp
+ webview.h webview.cpp webviewcontextmenu.h webviewcontextmenu.cpp
+ urlinterceptor.h urlinterceptor.cpp)
+target_include_directories(webengine PUBLIC ${CMAKE_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(webengine PUBLIC Qt5::WebEngineWidgets fmt)
+
+# tests
+add_executable(profile_test test/profile.cpp)
+target_link_libraries(profile_test PRIVATE webengine Catch2::Catch2)
+#target_sanitize(profile_test)
+
+add_executable(profilemanager_test test/profilemanager.cpp)
+target_link_libraries(profilemanager_test PRIVATE webengine Catch2::Catch2)
+#target_sanitize(profilemanager_test)
+
+add_test(NAME webengine_profile COMMAND profile_test)
+add_test(NAME webengine_profilemanager COMMAND profilemanager_test)
+set_tests_properties(webengine_profile webengine_profilemanager PROPERTIES
+ ENVIRONMENT "PROFILE=${CMAKE_CURRENT_SOURCE_DIR}/test/testing.profile")
diff --git a/src/webengine/test/form.html b/lib/webengine/test/form.html
index 9d8b19e..9d8b19e 100644
--- a/src/webengine/test/form.html
+++ b/lib/webengine/test/form.html
diff --git a/lib/webengine/test/icon.svg b/lib/webengine/test/icon.svg
new file mode 100644
index 0000000..a348cab
--- /dev/null
+++ b/lib/webengine/test/icon.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" version="1.1">
+ <circle cx="150" cy="150" r="100" stroke="#000000" stroke-width="6" fill="#e60026"></circle>
+ <circle cx="150" cy="150" r="87" stroke="#000000" stroke-width="4" fill="#e5e4e2"></circle>
+ <path d="M230,150 A80,80 0 0 0 150,70 L150,150 Z" />
+ <path d="M70,150 A80,80 0 0 0 150,230 L150,150 Z" />
+</svg>
+
diff --git a/src/webengine/test/profile.cpp b/lib/webengine/test/profile.cpp
index ae3a4e3..ae3a4e3 100644
--- a/src/webengine/test/profile.cpp
+++ b/lib/webengine/test/profile.cpp
diff --git a/src/webengine/test/profilemanager.cpp b/lib/webengine/test/profilemanager.cpp
index dc7c903..8f6a34f 100644
--- a/src/webengine/test/profilemanager.cpp
+++ b/lib/webengine/test/profilemanager.cpp
@@ -60,9 +60,9 @@ SCENARIO("WebProfileManager")
GIVEN("a number of profiles, default undefined")
{
- REQUIRE(qEnvironmentVariableIsSet("PROFILES"));
+ REQUIRE(qEnvironmentVariableIsSet("PROFILE"));
- WebProfileManager<false> profiles(QString::fromLatin1(qgetenv("PROFILES")).split(';'), default_id, search, homepage, newtab);
+ WebProfileManager<false> profiles(QString::fromLatin1(qgetenv("PROFILE")).split(';'), default_id, search, homepage, newtab);
REQUIRE(profiles.idList().count() == 2);
REQUIRE(profiles.profile(default_id) == WebProfile::defaultProfile());
@@ -94,9 +94,9 @@ SCENARIO("WebProfileManager")
GIVEN("a number of profiles, default defined")
{
- REQUIRE(qEnvironmentVariableIsSet("PROFILES"));
+ REQUIRE(qEnvironmentVariableIsSet("PROFILE"));
- WebProfileManager<false> profiles(QString::fromLatin1(qgetenv("PROFILES")).split(';'), "testing", search, homepage, newtab);
+ WebProfileManager<false> profiles(QString::fromLatin1(qgetenv("PROFILE")).split(';'), "testing", search, homepage, newtab);
REQUIRE(profiles.idList().count() == 1);
REQUIRE(profiles.profile("testing") == WebProfile::defaultProfile());
diff --git a/src/webengine/test/sample.html b/lib/webengine/test/sample.html
index 54746d5..54746d5 100644
--- a/src/webengine/test/sample.html
+++ b/lib/webengine/test/sample.html
diff --git a/src/webengine/test/testing.profile b/lib/webengine/test/testing.profile
index e345a3e..e345a3e 100644
--- a/src/webengine/test/testing.profile
+++ b/lib/webengine/test/testing.profile
diff --git a/src/webengine/test/view.cpp b/lib/webengine/test/view.cpp
index 8aa639a..8aa639a 100644
--- a/src/webengine/test/view.cpp
+++ b/lib/webengine/test/view.cpp
diff --git a/src/webengine/urlinterceptor.cpp b/lib/webengine/urlinterceptor.cpp
index 047cad4..047cad4 100644
--- a/src/webengine/urlinterceptor.cpp
+++ b/lib/webengine/urlinterceptor.cpp
diff --git a/src/webengine/urlinterceptor.h b/lib/webengine/urlinterceptor.h
index eb3ce67..eb3ce67 100644
--- a/src/webengine/urlinterceptor.h
+++ b/lib/webengine/urlinterceptor.h
diff --git a/src/webengine/webpage.cpp b/lib/webengine/webpage.cpp
index b2b19b5..b2b19b5 100644
--- a/src/webengine/webpage.cpp
+++ b/lib/webengine/webpage.cpp
diff --git a/src/webengine/webpage.h b/lib/webengine/webpage.h
index 91ae4f3..91ae4f3 100644
--- a/src/webengine/webpage.h
+++ b/lib/webengine/webpage.h
diff --git a/src/webengine/webprofile.cpp b/lib/webengine/webprofile.cpp
index f1e71fb..f1e71fb 100644
--- a/src/webengine/webprofile.cpp
+++ b/lib/webengine/webprofile.cpp
diff --git a/src/webengine/webprofile.h b/lib/webengine/webprofile.h
index 894463f..894463f 100644
--- a/src/webengine/webprofile.h
+++ b/lib/webengine/webprofile.h
diff --git a/src/webengine/webprofilemanager.cpp b/lib/webengine/webprofilemanager.cpp
index 5cc83f8..5cc83f8 100644
--- a/src/webengine/webprofilemanager.cpp
+++ b/lib/webengine/webprofilemanager.cpp
diff --git a/src/webengine/webprofilemanager.h b/lib/webengine/webprofilemanager.h
index a356506..e5df6d5 100644
--- a/src/webengine/webprofilemanager.h
+++ b/lib/webengine/webprofilemanager.h
@@ -9,7 +9,6 @@
#ifndef SMOLBOTE_WEBPROFILEMANAGER_H
#define SMOLBOTE_WEBPROFILEMANAGER_H
-#include "singleton.hpp"
#include "webprofile.h"
#include <QDir>
#include <QFile>
@@ -18,6 +17,20 @@
#include <QMenu>
#include <functional>
+#if defined(__clang__)
+#define consumable(X) [[clang::consumable(X)]]
+#define return_typestate(X) [[clang::return_typestate(X)]]
+#define set_typestate(X) [[clang::set_typestate(X)]]
+#define callable_when(X) [[clang::callable_when(X)]]
+#define param_typestate(X) [[clang::param_typestate(X)]]
+#else
+#define consumable(X)
+#define return_typestate(X)
+#define set_typestate(X)
+#define callable_when(X)
+#define param_typestate(X)
+#endif
+
void profileMenu(QMenu *menu, const std::function<void(WebProfile *)> &callback, WebProfile *current = nullptr, bool checkable = false);
template <bool use_global = true>
diff --git a/src/webengine/webview.cpp b/lib/webengine/webview.cpp
index bc52102..bc52102 100644
--- a/src/webengine/webview.cpp
+++ b/lib/webengine/webview.cpp
diff --git a/src/webengine/webview.h b/lib/webengine/webview.h
index 538ffa9..538ffa9 100644
--- a/src/webengine/webview.h
+++ b/lib/webengine/webview.h
diff --git a/src/webengine/webviewcontextmenu.cpp b/lib/webengine/webviewcontextmenu.cpp
index ea5e8c6..83bad3b 100644
--- a/src/webengine/webviewcontextmenu.cpp
+++ b/lib/webengine/webviewcontextmenu.cpp
@@ -13,7 +13,6 @@
#include <QDialog>
#include <QMenu>
#include <QSlider>
-#include <QStatusBar>
#include <QStyle>
#include <QToolButton>
#include <QVBoxLayout>
@@ -21,13 +20,17 @@
#include <QWebEngineHistory>
#include <QWidgetAction>
+constexpr int min_width = 250;
+constexpr QSize button_size(32, 32);
+
inline QAction *historyAction(QWebEngineView *view, const QWebEngineHistoryItem &item)
{
- QAction *action = new QAction(view);
- if(item.title().isEmpty())
+ auto *action = new QAction(view);
+ if(item.title().isEmpty()) {
action->setText(item.url().toString());
- else
+ } else {
action->setText(QObject::tr("%1 (%2)").arg(item.title(), item.url().toString()));
+ }
QObject::connect(action, &QAction::triggered, view, [view, item]() {
view->history()->goToItem(item);
@@ -38,7 +41,7 @@ inline QAction *historyAction(QWebEngineView *view, const QWebEngineHistoryItem
WebViewContextMenu::WebViewContextMenu(WebView *view)
: QMenu(view)
{
- setMinimumWidth(250);
+ setMinimumWidth(min_width);
auto *navButtons = new QWidgetAction(this);
@@ -48,6 +51,7 @@ WebViewContextMenu::WebViewContextMenu(WebView *view)
buttonsLayout->setSpacing(2);
auto *backButton = new QToolButton(this);
+ backButton->setMinimumSize(button_size);
backButton->setEnabled(view->history()->canGoBack());
backButton->setIcon(style()->standardIcon(QStyle::SP_ArrowBack));
connect(backButton, &QToolButton::clicked, view, [this, view]() {
@@ -57,6 +61,7 @@ WebViewContextMenu::WebViewContextMenu(WebView *view)
buttonsLayout->addWidget(backButton);
auto *forwardButton = new QToolButton(this);
+ forwardButton->setMinimumSize(button_size);
forwardButton->setEnabled(view->history()->canGoForward());
forwardButton->setIcon(style()->standardIcon(QStyle::SP_ArrowForward));
connect(forwardButton, &QToolButton::clicked, view, [this, view]() {
@@ -66,6 +71,7 @@ WebViewContextMenu::WebViewContextMenu(WebView *view)
buttonsLayout->addWidget(forwardButton);
auto *refreshButton = new QToolButton(this);
+ refreshButton->setMinimumSize(button_size);
refreshButton->setIcon(style()->standardIcon(QStyle::SP_BrowserReload));
connect(refreshButton, &QToolButton::clicked, view, [view, this]() {
view->reload();
@@ -76,12 +82,10 @@ WebViewContextMenu::WebViewContextMenu(WebView *view)
buttonsLayout->addStretch();
auto *muteButton = new QToolButton(this);
+ muteButton->setMinimumSize(button_size);
muteButton->setCheckable(true);
muteButton->setChecked(view->page()->isAudioMuted());
- QIcon muteIcon;
- muteIcon.addPixmap(style()->standardPixmap(QStyle::SP_MediaVolume), QIcon::Normal, QIcon::Off);
- muteIcon.addPixmap(style()->standardPixmap(QStyle::SP_MediaVolumeMuted), QIcon::Normal, QIcon::On);
- muteButton->setIcon(muteIcon);
+ muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume));
connect(muteButton, &QToolButton::clicked, view, [view, this](bool checked) {
view->page()->setAudioMuted(checked);
this->close();
diff --git a/src/webengine/webviewcontextmenu.h b/lib/webengine/webviewcontextmenu.h
index 881670a..881670a 100644
--- a/src/webengine/webviewcontextmenu.h
+++ b/lib/webengine/webviewcontextmenu.h
diff --git a/linux/.config b/linux/.config
new file mode 100644
index 0000000..8999ecb
--- /dev/null
+++ b/linux/.config
@@ -0,0 +1,111 @@
+
+#
+# Application
+#
+CONFIG_POI_NAME="smolbote"
+CONFIG_POI_CFG_PATH="~/.config/smolbote/smolbote.cfg"
+# end of Application
+
+#
+# Keyboard shortcuts
+#
+
+#
+# Main Window shortcuts
+#
+CONFIG_shortcuts.session.save="Ctrl+S,S"
+CONFIG_shortcuts.session.open="Ctrl+S,O"
+CONFIG_shortcuts.window.newgroup="Ctrl+G"
+CONFIG_shortcuts.window.newwindow="Ctrl+N"
+CONFIG_shortcuts.window.about="F1"
+CONFIG_shortcuts.window.quit="Ctrl+Q"
+CONFIG_shortcuts.window.search="F3"
+CONFIG_shortcuts.window.downloads.show="Ctrl+D"
+
+#
+# Navigation Bar shortcuts
+#
+CONFIG_navigationbar.show="Ctrl+Shift+N"
+CONFIG_shortcuts.navigation.back="Ctrl+Left"
+CONFIG_shortcuts.navigation.backmenu="Ctrl+Down"
+CONFIG_shortcuts.navigation.forward="Ctrl+Right"
+CONFIG_shortcuts.navigation.forwardmenu="Ctrl+Up"
+CONFIG_shortcuts.navigation.refresh="F5"
+CONFIG_shortcuts.navigation.reload="Ctrl+F5"
+CONFIG_shortcuts.navigation.home="Ctrl+Home"
+
+#
+# Address Bar shortcuts
+#
+CONFIG_shortcuts.address.focus="F4"
+CONFIG_shortcuts.address.menu="F2"
+
+#
+# Subwindow shortcuts
+#
+CONFIG_shortcuts.subwindow.tile="F9"
+CONFIG_shortcuts.subwindow.cascade="F10"
+CONFIG_shortcuts.subwindow.fullscreen="F11"
+CONFIG_shortcuts.subwindow.newtab="Ctrl+T"
+CONFIG_shortcuts.subwindow.closetab="Ctrl+W"
+CONFIG_shortcuts.subwindow.restoretab="Ctrl+Shift+T"
+CONFIG_shortcuts.subwindow.tableft="Ctrl+O"
+CONFIG_shortcuts.subwindow.movetableft="Ctrl+Shift+O"
+CONFIG_shortcuts.subwindow.tabright="Ctrl+P"
+CONFIG_shortcuts.subwindow.movetabright="Ctrl+Shift+P"
+# end of Keyboard shortcuts
+
+#
+# Main Window
+#
+CONFIG_mainwindow.title="smolbote"
+CONFIG_mainwindow.width=1280
+CONFIG_mainwindow.height=720
+# end of Main Window
+
+#
+# Bookmarks
+#
+CONFIG_bookmarks.path="~/.config/smolbote/bookmarks.xbel"
+CONFIG_shortcuts.window.bookmarks.show="Ctrl+B"
+CONFIG_bookmarks.toolbar.show="Ctrl+Shift+B"
+# CONFIG_bookmarks.toolbar.movable is not set
+# CONFIG_bookmarks.toolbar.visible is not set
+# end of Bookmarks
+
+#
+# Profile Settings
+#
+CONFIG_profile.path="~/.config/smolbote/profiles.d"
+CONFIG_profile.default=""
+CONFIG_profile.search="https://duckduckgo.com/?q=%1&ia=web"
+CONFIG_profile.homepage="about:blank"
+CONFIG_profile.newtab="about:blank"
+# end of Profile Settings
+
+CONFIG_USEPLUGINS=y
+
+#
+# Plugin Settings
+#
+CONFIG_PLUGINS_PATH="~/.config/smolbote/plugins.d"
+# CONFIG_PLUGINS_SIGNATURE_IGNORED is not set
+CONFIG_PLUGINS_SIGNATURE_CHECKED=y
+# CONFIG_PLUGINS_SIGNATURE_ENFORCED is not set
+CONFIG_PLUGINS_SIGNATURE_HASH="SHA256"
+# end of Plugin Settings
+
+#
+# Default paths
+#
+CONFIG_filter.path="~/.config/smolbote/hosts.d"
+CONFIG_downloads.path="~/Downloads"
+CONFIG_session.path="~/.config/smolbote/session.d"
+# CONFIG_USEPLASMA is not set
+# CONFIG_USEBREAKPAD is not set
+
+#
+# Workarounds
+#
+CONFIG_QTBUG_65223=y
+# end of Workarounds
diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt
new file mode 100644
index 0000000..f9937ff
--- /dev/null
+++ b/linux/CMakeLists.txt
@@ -0,0 +1,8 @@
+find_program(XDG_VALIDATE desktop-file-validate)
+
+add_test(NAME verify_poi.desktop COMMAND ${XDG_VALIDATE} poi.desktop
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
+install(FILES firejail/poi.profile DESTINATION ${CMAKE_INSTALL_LIBDIR}/smolbote)
+install(FILES ${CMAKE_SOURCE_DIR}/data/poi.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
+install(FILES poi.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
diff --git a/linux/makepkg/PKGBUILD b/linux/makepkg/PKGBUILD
index 5bcf684..f262530 100644
--- a/linux/makepkg/PKGBUILD
+++ b/linux/makepkg/PKGBUILD
@@ -3,8 +3,6 @@
## not-use flags
# Enable plugin signing:
_signPlugins=0
-# Enable breakpad integraton:
-_enableBreakpad=0
# install prefix
_prefix='/usr/local'
@@ -13,97 +11,49 @@ pkgdesc='Yet another no-frills browser'
pkgver=0
pkgrel=1
-url="https://neueland.iserlohn-fortress.net/gitea/smolbote"
-install="smolbote.install"
+url="https://neueland.iserlohn-fortress.net/cgit/smolbote"
arch=('x86_64' 'aarch64')
license=('GPL3')
depends=('qt5-svg' 'qt5-webengine>=5.11.0' 'spdlog')
-makedepends=('git' 'meson' 'python-kconfiglib' 'openssl' 'qt5-tools' 'scdoc' 'catch2')
-if [ $_enableBreakpad == "1" ]; then
- makedepends+=('breakpad-git')
-fi
+makedepends=('git' 'cmake' 'python-kconfiglib' 'openssl' 'qt5-tools' 'scdoc' 'catch2')
optdepends=('firejail: launch a sandboxed instance')
-# use git+file:///path/to/your/repo to build from a local repo
-source=("git+https://neueland.iserlohn-fortress.net/cgit/smolbote"
- "https://neueland.iserlohn-fortress.net/releases/SingleApplication-3.1.1a.tar.xz"{,.sig}
- "https://neueland.iserlohn-fortress.net/releases/args.hxx-6.2.2.tar.xz"{,.sig})
+# use git+file:///path/to/your/repo#branch=devel to build from a local repo
+source=("git+git://neueland.iserlohn-fortress.net/cgit/smolbote#branch=devel"
+ "https://github.com/itay-grudev/SingleApplication/archive/v3.1.5.tar.gz"
+ "https://neueland.iserlohn-fortress.net/cgit/rcc/snapshot/rcc-0.1.2.tar.xz"
+ "https://github.com/tabler/tabler-icons/archive/v1.34.0.tar.gz")
-b2sums=('SKIP'
- 'cec3de8dbf252bfa6dc488e5a1440695f4dd3abffdf30948b7d1a3df3d9c85911e981c802ed5a882f1407315114529f4016e55c7d05fbbd1dafe5495b0a63f4a'
- 'SKIP'
- '440e357006883fbf1b1a796051500a6b068858a35947cd1119767bed8e0a86a7db4aff16498934d7217c375fe643da03c22007e438f30899e247153f25c922b6'
- 'SKIP')
-
-validgpgkeys=(BB1C090188E3E32B375C13FD095DE26BC16D2E98) # Aqua-sama <aqua@iserlohn-fortress.net>
+sha256sums=('SKIP'
+ '09b1e088dae8cf69187262554819b77f4ca7b65576b3f39c5b6885823e8a2dbb'
+ '5ee18b94401b720e6e65d8e0e38dd6ea23cab7ae4727742be313530969a69d50'
+ 'bc74e5bd28531445f2e50df44f3688b1116397a25a0086e6944ab52260b70ffd'
+)
prepare() {
- mkdir "$srcdir/smolbote/subprojects/packagecache/"
- ln -s "$srcdir/SingleApplication-3.1.1a" "$srcdir/smolbote/subprojects/"
- ln -s "$srcdir/args.hxx-6.2.2" "$srcdir/smolbote/subprojects/"
-
- cd $srcdir/smolbote
- KCONFIG_CONFIG=linux/.config alldefconfig
+ mkdir "$srcdir/smolbote-devel/third-party"
+ ln -s "$srcdir/SingleApplication-3.1.5" "$srcdir/smolbote-devel/third-party/"
+ ln -s "$srcdir/rcc-0.1.2" "$srcdir/smolbote-devel/third-party/"
+ ln -s "$srcdir/tabler-icons-1.34.0" "$srcdir/smolbote-devel/third-party/"
+ ln -s "$srcdir/smolbote-devel/linux/.config" "$srcdir/smolbote-devel/"
}
pkgver() {
- cd smolbote
+ cd "$srcdir/smolbote-devel"
# Without version tag
echo r$(git rev-list --count HEAD)-$(git rev-parse --short HEAD) | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
}
build() {
- mkdir -p $srcdir/build
-
- # For a list of configureable options, check smolbote/meson_options.txt, or run `meson configure` in $srcdir/build
-
- # --wrap-mode=nodownload - disable meson from downloading dependency wraps. This will cause it to fail if makedepends are not found by pkg-config or cmake.
- # --wrap-mode=nofallback - disable downloads as a fallback too. Implies --wrap-mode=nodownload
- # --buildtype=plain - meson won't add any flags to the command line
- # --prefix=... - install prefix
- # --auto-features=disabled - features should be explicitly enabled
- # b_pie: Build executables as position independent
- # b_lto: Use link time optimization
- meson setup \
- --buildtype=plain --prefix=$_prefix --wrap-mode=nodownload --auto-features=disabled \
- -Db_pie=true -Ddefault_library=static \
- -Dmanpage=true \
- $srcdir/smolbote $srcdir/build
+ cmake -B build -S "smolbote-devel" -DVCS_TAG=OFF -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX=$_prefix
+ make -C build
- if [ $_enableBreakpad == "1" ]; then
- msg2 "Enabling crashhandler"
- meson configure -Ddebug=true -Dcrashhandler=enabled
- KCONFIG_CONFIG=linux/.config setconfig USEBREAKPAD=y
- fi
-
- # Build
- ninja -C $srcdir/build
}
-#check() {
-# ninja -C $srcdir/build test
-#}
-
package() {
- # Install
- cd $srcdir/build
- DESTDIR="$pkgdir" ninja install
-
- if [ $_signPlugins == "1" ]; then
- msg "Signing plugins"
- for so in $pkgdir/$_prefix/lib/smolbote/plugins/*.so; do
- openssl dgst -sha256 -sign $srcdir/build/lib/pluginloader/privateKey.pem -out $so.sig $so
- msg2 "Signed $(basename $so)"
- done
- fi
-
- if [ $_enableBreakpad == "1" ]; then
- msg "Installing debug symbols"
- ninja -C $srcdir/build linux/poi.sym
- install -dm644 $pkgdir/$_prefix/lib/smolbote/symbols/poi/$(head -n1 linux/poi.sym | awk '{ print $(NF-1) }')
- install -m644 -t $pkgdir/$_prefix/lib/smolbote/symbols/poi/$(head -n1 linux/poi.sym | awk '{ print $(NF-1) }') $srcdir/build/linux/poi.sym
- fi
+ make DESTDIR="$pkgdir" -C build install
}
diff --git a/linux/meson.build b/linux/meson.build
deleted file mode 100644
index 5b5c79e..0000000
--- a/linux/meson.build
+++ /dev/null
@@ -1,30 +0,0 @@
-# application icon
-install_data('../data/poi.svg', install_dir: get_option('datadir') / 'icons/hicolor/scalable/apps')
-
-# firejail profile
-install_data('firejail/poi.profile', install_dir: get_option('libdir') / 'smolbote')
-
-# .desktop files
-conf = configuration_data({
- 'exec_poi': get_option('prefix')/get_option('bindir')/get_option('poi'),
- 'firejail': get_option('firejail'),
- 'firejail_profile': get_option('prefix')/get_option('libdir')/'smolbote/poi.profile'
-})
-desktop_files = ['poi.desktop', 'poi_firejail.desktop', 'poi_picksession.desktop']
-desktop_dir = get_option('datadir')/'applications'
-foreach f : desktop_files
- configure_file(input: f + '.in', output: f, configuration: conf, install_dir: desktop_dir)
-endforeach
-
-# producing debug symbols
-if get_option('crashhandler').enabled()
-custom_target('poi-sym',
- input: poi_exe,
- output: 'poi.sym',
- capture: true,
- command: [ find_program('dump_syms'), '@INPUT@' ],
- build_by_default: false,
-# install_dir: symbols/poi/$(head -n1 linux/poi.sym | awk '{ print $(NF-1) }')
-)
-endif
-
diff --git a/linux/poi.desktop.in b/linux/poi.desktop
index a31a84c..56c3217 100644
--- a/linux/poi.desktop.in
+++ b/linux/poi.desktop
@@ -1,21 +1,21 @@
[Desktop Entry]
+# (required) Application, Link or Directory
+Type=Application
+# The version of the desktop entry specification to which this file complies
Version=1.0
+
+# (required)
Name=smolbote
GenericName=Web Browser
Comment=yet another no-frills browser
-Exec=@exec_poi@ %u
+Exec=poi %u
Icon=poi
Terminal=false
-Type=Application
MimeType=text/html;text/xml;application/xhtml+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;
Categories=Network;WebBrowser;
Keywords=web;browser;internet;
-Actions=pickSession;configure
+Actions=pickSession
[Desktop Action pickSession]
Name=Pick Session
-Exec=@exec_poi@ --pick-session
-
-[Desktop Action configure]
-Name=Configure smolbote
-Exec=@exec_poi@ configure
+Exec=poi session --pick
diff --git a/linux/poi.fish b/linux/poi.fish
deleted file mode 100644
index d0b3e21..0000000
--- a/linux/poi.fish
+++ /dev/null
@@ -1,11 +0,0 @@
-# -c short option <short>
-# -l long option <long>
-# -a accepts option "option1 option2"
-
-complete -c poi -s h -l help --description 'Display command-line options list.'
-complete -c poi -s v -l version --description 'Display version information.'
-complete -c poi -l build --description 'Display build commit.'
-complete -c poi -s c -l config -r --description 'Set configuration file.'
-complete -c poi -l no-remote --description 'Do not accept or send remote commands.'
-complete -c poi -s s -l session -r --description 'Open the selected session'
-complete -c poi -l pick-session --description 'Show all available sessions and select which one to open.'
diff --git a/linux/poi_firejail.desktop.in b/linux/poi_firejail.desktop.in
deleted file mode 100644
index 31e5b64..0000000
--- a/linux/poi_firejail.desktop.in
+++ /dev/null
@@ -1,21 +0,0 @@
-[Desktop Entry]
-Version=1.0
-Name=smolbote (in firejail)
-GenericName=Web Browser
-Comment=yet another no-frills browser
-Exec=@firejail@ --profile=@firejail_profile@ @exec_poi@ --mainwindow.title="[[smolbote]]" %u
-Icon=poi
-Terminal=false
-Type=Application
-MimeType=text/html;text/xml;application/xhtml+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;
-Categories=Network;WebBrowser;
-Keywords=web;browser;internet;
-Actions=pickSession;configure
-
-[Desktop Action pickSession]
-Name=Pick Session
-Exec=@firejail@ --profile=@firejail_profile@ @exec_poi@ --pick-session
-
-[Desktop Action configure]
-Name=Configure smolbote
-Exec=@firejail@ --profile=@firejail_profile@ @exec_poi@ configure
diff --git a/linux/poi_picksession.desktop.in b/linux/poi_picksession.desktop.in
deleted file mode 100644
index 7cfb7a9..0000000
--- a/linux/poi_picksession.desktop.in
+++ /dev/null
@@ -1,13 +0,0 @@
-[Desktop Entry]
-Version=1.0
-Name=smolbote (Pick Session)
-GenericName=Web Browser
-Comment=yet another no-frills browser
-Exec=@exec_poi@ --pick-session
-Icon=poi
-Terminal=false
-Type=Application
-MimeType=text/html;text/xml;application/xhtml+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;
-Categories=Network;WebBrowser;
-Keywords=web;browser;internet;
-
diff --git a/meson.build b/meson.build
deleted file mode 100644
index 8290125..0000000
--- a/meson.build
+++ /dev/null
@@ -1,148 +0,0 @@
-project('smolbote', ['cpp'],
- version: '0.1.0',
- default_options: ['cpp_std=c++2a', 'warning_level=3'],
- license: 'GPL3',
- meson_version: '>=0.53.0'
-)
-
-summary({
- 'prefix': get_option('prefix'),
- 'bindir': get_option('bindir'),
- 'libdir': get_option('libdir'),
- 'datadir': get_option('datadir')
-}, section: 'Install locations')
-
-kconfig = import('unstable-kconfig')
-kconf = kconfig.load(host_machine.system() + '/.config')
-cdata = configuration_data(kconf)
-
-version_h = vcs_tag(
- command: [find_program('git').path(), 'describe', '--long', '--abbrev=40'],
- #fallback: defaults to meson.project_version(),
- input: 'src/version.h.in',
- output: 'version.h'
-)
-
-# add -DQT_NO_DEBUG to non-debug builds
-if not get_option('debug')
- add_project_arguments('-DQT_NO_DEBUG', language: 'cpp')
-endif
-
-sourceset = import('sourceset')
-
-cxx = meson.get_compiler('cpp')
-
-# add some specific flags
-add_project_arguments(cxx.get_supported_arguments([
- '-ffunction-sections', # Place each function into its own section, better ASLR but larger executables
- '-fstack-protector-all', # Emit code to check for buffer overflows on all functions
- '-fstack-clash-protection', # Emit code to check for stack clash attacks
-
- # gcc specific
- '-fconcepts', # gcc9 c++20 compat
-
- # clang specific
- '-mspeculative-load-hardening', # Spectre v1 mitigation
- '-Xclang -plugin-arg-clazy -Xclang level0,level1', # clazy default warning level
-
- ## warnings
- # variables
- '-Wunused', # warn on anything being unused
- '-Wshadow', # if variable declaration shadows one from a parent context
- # functions
- '-Wnon-virtual-dtor', # if class with virtual functions has non-virtual dtor
- '-Werror=missing-declarations', # missing function declarations in header files
- '-Werror=redundant-decls',
- '-Woverloaded-virtual', # warn if you overload (not override) a virtual function
- '-Werror=return-type',
- # style
- '-Wformat=2', # security issues around printf
- '-Wdate-time', # __TIME__ and __DATE__ macros
- '-Werror=missing-field-initializers',
- # objects
- '-Wnull-dereference',
- '-Wconsumed', # use-after-move warnings
- '-Wlifetime', # object lifetime issues
- # logic
- '-Wlogical-op', # logical operations being used where bitwise were probably wanted
- '-Wimplicit-fallthrough',
- '-Wduplicated-cond', # if/else chain has duplicated conditions
- '-Wduplicated-brances', # if/else branches have duplicated code
- # casts
- '-Wold-style-cast',
- '-Wcast-align', # potential performance problem casts
- '-Wuseless-cast', # cast to same type
- '-Wconversion', # type conversions that may lose data
- '-Wsign-conversion', # sign conversions
- '-Wdouble-promotion', # float is promoted to double
- # others
- '-Werror=pedantic', # if non-standard c++ is used
- #'-Weffc++',
-]), language: 'cpp')
-
-# Dependencies
-mod_qt5 = import('qt5')
-dep_qt5 = dependency('qt5',
- modules: [ 'Core', 'Network', 'Widgets', 'Svg', 'WebEngine', 'WebEngineWidgets', 'Concurrent' ],
- include_type: 'system'
-)
-
-dep_spdlog = dependency('spdlog', fallback: ['spdlog', 'spdlog_dep'], version: '>=1.3.1')
-
-optional_deps = []
-poi_cpp_args = []
-
-dep_breakpad = dependency('breakpad-client', include_type: 'system', required: get_option('crashhandler'))
-dep_threads = dependency('threads', include_type: 'system', required: get_option('crashhandler'))
-
-dep_gtest = dependency('gtest', required: false, disabler: true)
-dep_catch = dependency('catch2', required: true, fallback: ['catch2', 'catch2_dep'] )
-dep_SingleApplication = dependency('singleapplication', fallback: [ 'singleapplication', 'SingleApplication_dep' ])
-dep_args = dependency('args.hxx', fallback: [ 'args', 'args_dep' ])
-
-# Generate config header
-poi_sourceset = sourceset.source_set()
-
-subdir('include')
-smolbote_interfaces = include_directories('include')
-
-subdir('lib/bookmarks')
-subdir('lib/configuration')
-subdir('lib/downloads')
-subdir('lib/pluginloader')
-subdir('lib/session_formats')
-
-subdir('src')
-subdir('lang')
-subdir('doc')
-subdir('tools')
-
-subdir('plugins/ProfileEditor')
-
-subdir('test/firefox-bookmarks-json-parser')
-subdir('test/matcherbenchmark')
-
-subdir('staging/smolblok')
-subdir('plugins/smolblok_hostlist')
-
-ssconfig = poi_sourceset.apply(cdata)
-
-poi_exe = executable(get_option('poi'),
- cpp_args: ['-DQAPPLICATION_CLASS=QApplication', poi_cpp_args],
- sources: [ssconfig.sources()],
- include_directories: [ plugininterfaces_include, include_directories('src') ],
- dependencies: [ dep_qt5, dep_spdlog, dep_SingleApplication, dep_args, optional_deps, dep_bookmarks, dep_configuration, dep_downloads, dep_pluginloader, ssconfig.dependencies(), lib_session_formats ],
- install: true,
-)
-
-test('poi-bookmarks: xbel', poi_exe, args: [ 'bookmarks', '-x', files('test/bookmarks.xbel'), '--export=stdout' ])
-
-subdir(host_machine.system())
-
-# cppcheck target
-cppcheck = find_program('cppcheck', required: false)
-if cppcheck.found()
-run_target('cppcheck',
- command: [cppcheck, '--enable=all', '--project=' + meson.build_root() / 'compile_commands.json']
-)
-endif
diff --git a/meson_options.txt b/meson_options.txt
deleted file mode 100644
index eb39c03..0000000
--- a/meson_options.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-option('poi', description: 'Executable name', type: 'string', value: 'poi')
-option('firejail', description: 'firejail executable name', type: 'string', value: '/usr/bin/firejail')
-
-option('manpage', description: 'Generate and install manpage', type: 'boolean', value: 'true')
-option('translations', description: 'Generate and install translations', type: 'feature', value: 'auto')
-option('crashhandler', description: 'Enable breakpad crash reporting', type: 'feature', value: 'auto')
-option('updater', description: 'Build updater component', type: 'feature', value: 'auto')
-
-# Build options
-option('signPlugins', description: 'Generate OpenSSL signing key', type: 'feature', value: 'auto')
diff --git a/staging/adblock/filterlist.cpp b/plugins/AdblockFilter/filterlist.cpp
index 1846ff6..76953fc 100644
--- a/staging/adblock/filterlist.cpp
+++ b/plugins/AdblockFilter/filterlist.cpp
@@ -26,7 +26,7 @@ const QLatin1String comment_expires("! Expires: ");
using namespace AdblockPlus;
-FilterList::FilterList(QIODevice &from)
+Filterlist::Filterlist(QIODevice &from)
{
if(from.isReadable() && from.isTextModeEnabled()) {
while(from.bytesAvailable() > 0) {
@@ -46,7 +46,7 @@ FilterList::FilterList(QIODevice &from)
}
}
-void FilterList::parseComment(const QString &line)
+void Filterlist::parseComment(const QString &line)
{
if(line.startsWith(comment_lastModified)) {
lastModified = QDateTime::fromString(line.mid(comment_lastModified.size()), "dd MMM yyyy HH:mm 'UTC'");
@@ -62,7 +62,7 @@ void FilterList::parseComment(const QString &line)
}
}
-Rule *FilterList::parseRule(const QByteArray &line)
+Rule *Filterlist::parseRule(const QByteArray &line)
{
QString pattern = line;
Options opt;
@@ -122,7 +122,7 @@ Rule *FilterList::parseRule(const QByteArray &line)
return nullptr;
}
-bool FilterList::filter(QWebEngineUrlRequestInfo &info) const
+bool Filterlist::filter(QWebEngineUrlRequestInfo &info) const
{
return false;
}
diff --git a/staging/adblock/filterlist.h b/plugins/AdblockFilter/filterlist.h
index 24464c8..dba2138 100644
--- a/staging/adblock/filterlist.h
+++ b/plugins/AdblockFilter/filterlist.h
@@ -16,11 +16,11 @@
namespace AdblockPlus
{
-class FilterList : public Filter
+class Filterlist : public FilterList
{
public:
- explicit FilterList(QIODevice &from);
- ~FilterList()
+ explicit Filterlist(QIODevice &from);
+ ~Filterlist()
{
qDeleteAll(m_rules);
}
diff --git a/staging/adblock/meson.build b/plugins/AdblockFilter/meson.build
index 942f325..19d2509 100644
--- a/staging/adblock/meson.build
+++ b/plugins/AdblockFilter/meson.build
@@ -21,17 +21,17 @@ dep_adblockfilter = declare_dependency(
# install_dir: get_option('libdir')/'smolbote/plugins'
#)
-test('adblock: rule', executable('libadblockfilter_rule',
+test('adblock_rule', executable('libadblockfilter_rule',
sources: 'test/rule.cpp',
dependencies: [ dep_qt5, dep_catch, dep_adblockfilter ]
))
-test('adblock: options', executable('libadblockfilter_options',
+test('adblock_options', executable('libadblockfilter_options',
sources: 'test/options.cpp',
dependencies: [ dep_qt5, dep_catch, dep_adblockfilter ]
))
-test('adblock: filterlist', executable('libadblockfilter_filterlist',
+test('adblock_filterlist', executable('libadblockfilter_filterlist',
sources: 'test/filterlist.cpp',
dependencies: [ dep_qt5, dep_catch, dep_adblockfilter ]
))
diff --git a/staging/adblock/options.cpp b/plugins/AdblockFilter/options.cpp
index 08f30ee..ad231bf 100644
--- a/staging/adblock/options.cpp
+++ b/plugins/AdblockFilter/options.cpp
@@ -34,7 +34,7 @@ constexpr std::array abpTypeOptions = {
"__unknown" // ResourceTypeUnknown 255 Unknown request type.
};
-auto parseTypeOption(QStringRef &option)
+inline auto parseTypeOption(QStringRef &option)
{
struct {
bool found = false;
diff --git a/staging/adblock/options.h b/plugins/AdblockFilter/options.h
index efc47a6..9f7a374 100644
--- a/staging/adblock/options.h
+++ b/plugins/AdblockFilter/options.h
@@ -37,7 +37,7 @@ struct Options {
bool parseAbp(const QStringRef &options);
// TODO private:
- std::bitset<32> flags;
+ std::bitset<32> flags = 0;
};
} // namespace AdblockPlus
diff --git a/staging/adblock/plugin/AdblockPlusPlugin.json b/plugins/AdblockFilter/plugin/AdblockPlusPlugin.json
index 053826a..053826a 100644
--- a/staging/adblock/plugin/AdblockPlusPlugin.json
+++ b/plugins/AdblockFilter/plugin/AdblockPlusPlugin.json
diff --git a/staging/adblock/plugin/plugin.cpp b/plugins/AdblockFilter/plugin/plugin.cpp
index 028c83f..028c83f 100644
--- a/staging/adblock/plugin/plugin.cpp
+++ b/plugins/AdblockFilter/plugin/plugin.cpp
diff --git a/staging/adblock/plugin/plugin.h b/plugins/AdblockFilter/plugin/plugin.h
index db419bd..db419bd 100644
--- a/staging/adblock/plugin/plugin.h
+++ b/plugins/AdblockFilter/plugin/plugin.h
diff --git a/staging/adblock/rule.h b/plugins/AdblockFilter/rule.h
index aaab49a..aaab49a 100644
--- a/staging/adblock/rule.h
+++ b/plugins/AdblockFilter/rule.h
diff --git a/staging/adblock/test/filterlist.cpp b/plugins/AdblockFilter/test/filterlist.cpp
index ca122ac..90860fd 100644
--- a/staging/adblock/test/filterlist.cpp
+++ b/plugins/AdblockFilter/test/filterlist.cpp
@@ -3,6 +3,8 @@
#include <QBuffer>
#include <catch2/catch.hpp>
+// clazy:skip
+
using namespace AdblockPlus;
QByteArray sampleList =
@@ -16,7 +18,7 @@ TEST_CASE("placeholder")
QBuffer buffer(&sampleList);
buffer.open(QIODevice::ReadOnly | QIODevice::Text);
- AdblockPlus::FilterList list(buffer);
+ AdblockPlus::Filterlist list(buffer);
REQUIRE(!list.isUpToDate());
}
@@ -32,7 +34,7 @@ TEST_CASE("domain match")
const QString allow1 = "http://ads.example.com.ua/foo.gif";
const QString allow2 = "http://example.com/redirect/http://ads.example.com/";
- auto *rule = FilterList::parseRule("||ads.example.com^");
+ auto *rule = Filterlist::parseRule("||ads.example.com^");
REQUIRE(rule->shouldBlock());
REQUIRE(!rule->shouldRedirect());
@@ -56,7 +58,7 @@ TEST_CASE("string equals")
const QString allow1 = "http://example.com/foo.gif";
const QString allow2 = "http://example.info/redirect/http://example.com/";
- auto *rule = FilterList::parseRule("|http://example.com/|");
+ auto *rule = Filterlist::parseRule("|http://example.com/|");
REQUIRE(rule->shouldBlock());
REQUIRE(!rule->shouldRedirect());
@@ -72,7 +74,7 @@ TEST_CASE("string starts with")
{
const QString defaultUrl = "";
- auto *rule = FilterList::parseRule("|http://baddomain.example/");
+ auto *rule = Filterlist::parseRule("|http://baddomain.example/");
REQUIRE(rule->shouldBlock());
REQUIRE(!rule->shouldRedirect());
@@ -88,7 +90,7 @@ TEST_CASE("string ends with")
{
const QString defaultUrl = "";
- auto *rule = FilterList::parseRule("swf|");
+ auto *rule = Filterlist::parseRule("swf|");
REQUIRE(rule->shouldBlock());
REQUIRE(!rule->shouldRedirect());
@@ -104,7 +106,7 @@ TEST_CASE("regular expressions")
{
const QString defaultUrl = "";
- auto *rule = FilterList::parseRule("/banner\\d+/");
+ auto *rule = Filterlist::parseRule("/banner\\d+/");
const QString matches1 = "banner123";
const QString matches2 = "banner321";
diff --git a/staging/adblock/test/options.cpp b/plugins/AdblockFilter/test/options.cpp
index 67dc143..19f972c 100644
--- a/staging/adblock/test/options.cpp
+++ b/plugins/AdblockFilter/test/options.cpp
@@ -2,6 +2,8 @@
#include "options.h"
#include <catch2/catch.hpp>
+// clazy:skip
+
using namespace AdblockPlus;
SCENARIO("parsing adblock options")
diff --git a/staging/adblock/test/rule.cpp b/plugins/AdblockFilter/test/rule.cpp
index 07186b9..a1cd3ed 100644
--- a/staging/adblock/test/rule.cpp
+++ b/plugins/AdblockFilter/test/rule.cpp
@@ -2,6 +2,8 @@
#include "rule.h"
#include <catch2/catch.hpp>
+// clazy:skip
+
using namespace AdblockPlus;
SCENARIO("MatcherRule")
diff --git a/plugins/HostlistFilter/CMakeLists.txt b/plugins/HostlistFilter/CMakeLists.txt
new file mode 100644
index 0000000..b477967
--- /dev/null
+++ b/plugins/HostlistFilter/CMakeLists.txt
@@ -0,0 +1,33 @@
+# interface
+add_library(hostlist INTERFACE)
+target_sources(hostlist INTERFACE filterlist.h filterlist.cpp)
+target_link_libraries(hostlist INTERFACE Qt5::WebEngine)
+target_include_directories(hostlist INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include)
+
+# plugin
+add_library(hostlistPlugin MODULE plugin/plugin.cpp)
+target_link_libraries(hostlistPlugin PRIVATE hostlist)
+
+# tests
+
+add_executable(hostlistRule_test test/rule.cpp)
+target_link_libraries(hostlistRule_test PRIVATE hostlist)
+target_sanitize(hostlistRule_test)
+add_test(NAME hostlist_rule COMMAND hostlistRule_test)
+
+add_executable(hostlistFilter_test test/filterlist.cpp)
+target_link_libraries(hostlistFilter_test PRIVATE hostlist)
+target_sanitize(hostlistFilter_test)
+add_test(NAME hostlist_filter COMMAND hostlistFilter_test)
+set_tests_properties(hostlist_filter PROPERTIES ENVIRONMENT "HOSTLIST_TXT=${CMAKE_CURRENT_SOURCE_DIR}/test/hostlist.txt")
+
+# plugin load test
+add_test(NAME hostlist_load COMMAND pluginloader_load $<TARGET_FILE:hostlistPlugin>)
+
+# fuzzer
+if(${CMAKE_CXX_COMPILER_ID} MATCHES Clang)
+ add_executable(hostlistFilter_fuzzer filterlist.cpp)
+ target_link_libraries(hostlistFilter_fuzzer PRIVATE hostlist)
+ target_compile_definitions(hostlistFilter_fuzzer PRIVATE FUZZER)
+ target_sanitize_fuzzer(hostlistFilter_fuzzer)
+endif()
diff --git a/plugins/smolblok_hostlist/corpus/apple.txt b/plugins/HostlistFilter/corpus/apple.txt
index 3a8973b..3a8973b 100644
--- a/plugins/smolblok_hostlist/corpus/apple.txt
+++ b/plugins/HostlistFilter/corpus/apple.txt
diff --git a/plugins/smolblok_hostlist/corpus/banana.txt b/plugins/HostlistFilter/corpus/banana.txt
index c30aa84..c30aa84 100644
--- a/plugins/smolblok_hostlist/corpus/banana.txt
+++ b/plugins/HostlistFilter/corpus/banana.txt
diff --git a/plugins/smolblok_hostlist/corpus/kiwi.txt b/plugins/HostlistFilter/corpus/kiwi.txt
index 77c325c..77c325c 100644
--- a/plugins/smolblok_hostlist/corpus/kiwi.txt
+++ b/plugins/HostlistFilter/corpus/kiwi.txt
diff --git a/plugins/smolblok_hostlist/corpus/orange.txt b/plugins/HostlistFilter/corpus/orange.txt
index 583273d..583273d 100644
--- a/plugins/smolblok_hostlist/corpus/orange.txt
+++ b/plugins/HostlistFilter/corpus/orange.txt
diff --git a/plugins/HostlistFilter/filterlist.cpp b/plugins/HostlistFilter/filterlist.cpp
new file mode 100644
index 0000000..8faa4ef
--- /dev/null
+++ b/plugins/HostlistFilter/filterlist.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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://library.iserlohn-fortress.net/aqua/smolbote.git
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#include "filterlist.h"
+#include <QIODevice>
+#include <QTextStream>
+
+inline void Hostlist::parseRule(const QString &line, QStringList &blocked, QHash<QString, QString> &redirected)
+{
+ if(line.isEmpty() || line.at(0) == '#')
+ return;
+
+ auto parts = line.trimmed().split(' ');
+ if(parts.size() < 2)
+ return;
+
+ if(parts[0] == "0.0.0.0") {
+ parts.pop_front();
+ blocked << parts;
+ return;
+ }
+
+ for(int i = 1; i < parts.size(); ++i) {
+ redirected.insert(parts[i], parts[0]);
+ }
+}
+
+#ifdef FUZZER
+extern "C" int LLVMFuzzerTestOneInput(const char *Data, long long Size)
+{
+ QStringList b;
+ QHash<QString, QString> r;
+ Hostlist::parseRule(QString::fromLatin1(Data, static_cast<int>(Size)), b, r);
+ b.clear();
+ r.clear();
+ return 0;
+}
+#endif
+
+bool Hostlist::Filterlist::load(QIODevice &from)
+{
+ if(!from.isReadable() || !from.isTextModeEnabled()) {
+ return false;
+ }
+
+ while(from.bytesAvailable() > 0) {
+ const auto line = from.readLine(512);
+ parseRule(line, blocked, redirected);
+ }
+ return true;
+}
diff --git a/plugins/HostlistFilter/filterlist.h b/plugins/HostlistFilter/filterlist.h
new file mode 100644
index 0000000..a0fa6f7
--- /dev/null
+++ b/plugins/HostlistFilter/filterlist.h
@@ -0,0 +1,84 @@
+/*
+ * 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://library.iserlohn-fortress.net/aqua/smolbote.git
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#ifndef SMOLBOTE_HOSTLIST_FILTERLIST
+#define SMOLBOTE_HOSTLIST_FILTERLIST
+
+#include <QHash>
+#include <smolbote/filterinterface.hpp>
+
+namespace Hostlist
+{
+
+void parseRule(const QString &line, QStringList &blocked, QHash<QString, QString> &redirected);
+
+class Filterlist final : public FilterList
+{
+public:
+ Filterlist() = default;
+ Filterlist(const Filterlist &) = delete;
+ Filterlist &operator=(const Filterlist &) = delete;
+ ~Filterlist() = default;
+
+ enum Match {
+ NotFound,
+ Block,
+ Redirect
+ };
+
+ [[nodiscard]] Match findMatch(QUrl &url) const
+ {
+ const auto domain = url.host();
+
+ if(blocked.contains(domain))
+ return Block;
+
+ const auto iter = redirected.find(domain);
+ if(iter != redirected.end()) {
+ url.setHost(iter.value());
+ return Redirect;
+ }
+
+ return NotFound;
+ }
+
+ [[nodiscard]] auto count() const
+ {
+ return blocked.size() + redirected.size();
+ }
+
+ [[nodiscard]] bool filter(QWebEngineUrlRequestInfo &info) const
+ {
+ auto url = info.requestUrl();
+ switch(findMatch(url)) {
+ case NotFound:
+ return false;
+ case Block:
+ info.block(true);
+ return true;
+ case Redirect:
+ info.block(false);
+ info.redirect(url);
+ return true;
+ }
+ }
+
+ [[nodiscard]] bool isUpToDate() const
+ {
+ return true;
+ }
+
+ bool load(QIODevice &device);
+
+private:
+ QStringList blocked;
+ QHash<QString, QString> redirected;
+};
+} // namespace Hostlist
+
+#endif // SMOLBOTE_HOSTLIST_FILTERLIST
diff --git a/plugins/smolblok_hostlist/plugin/plugin.cpp b/plugins/HostlistFilter/plugin/plugin.cpp
index 28a7706..28a7706 100644
--- a/plugins/smolblok_hostlist/plugin/plugin.cpp
+++ b/plugins/HostlistFilter/plugin/plugin.cpp
diff --git a/plugins/smolblok_hostlist/plugin/plugin.h b/plugins/HostlistFilter/plugin/plugin.h
index 53b5d36..53b5d36 100644
--- a/plugins/smolblok_hostlist/plugin/plugin.h
+++ b/plugins/HostlistFilter/plugin/plugin.h
diff --git a/plugins/smolblok_hostlist/plugin/smolblokHostlistPlugin.json b/plugins/HostlistFilter/smolblokHostlistPlugin.json
index aa53cdd..aa53cdd 100644
--- a/plugins/smolblok_hostlist/plugin/smolblokHostlistPlugin.json
+++ b/plugins/HostlistFilter/smolblokHostlistPlugin.json
diff --git a/plugins/HostlistFilter/test/filterlist.cpp b/plugins/HostlistFilter/test/filterlist.cpp
new file mode 100644
index 0000000..b9b3812
--- /dev/null
+++ b/plugins/HostlistFilter/test/filterlist.cpp
@@ -0,0 +1,37 @@
+#define CATCH_CONFIG_MAIN
+#include "filterlist.h"
+#include <QFile>
+#include <catch2/catch.hpp>
+
+// clazy:skip
+
+using namespace Hostlist;
+
+TEST_CASE("Hostlist")
+{
+ Filterlist list;
+
+ const QString filename(qgetenv("HOSTLIST_TXT"));
+ REQUIRE(!filename.isEmpty());
+
+ QFile f(filename);
+ REQUIRE(f.open(QIODevice::ReadOnly | QIODevice::Text));
+
+ REQUIRE(list.load(f));
+ f.close();
+
+ REQUIRE(list.count() == 4);
+
+ QUrl first("http://blockeddomain.first");
+ REQUIRE(list.findMatch(first) == Filterlist::Block);
+
+ QUrl second("http://blockeddomain.second/path/to/something");
+ REQUIRE(list.findMatch(second) == Filterlist::Block);
+
+ QUrl localhost("http://localhost.localdomain");
+ REQUIRE(list.findMatch(localhost) == Filterlist::Redirect);
+ REQUIRE(localhost.toString() == "http://127.0.0.1");
+
+ QUrl other("http://other.domain");
+ REQUIRE(list.findMatch(other) == Filterlist::NotFound);
+}
diff --git a/plugins/smolblok_hostlist/test/hostlist.txt b/plugins/HostlistFilter/test/hostlist.txt
index a0b4e5c..a0b4e5c 100644
--- a/plugins/smolblok_hostlist/test/hostlist.txt
+++ b/plugins/HostlistFilter/test/hostlist.txt
diff --git a/plugins/smolblok_hostlist/test/plugin.cpp b/plugins/HostlistFilter/test/plugin.cpp
index fad34f2..026f579 100644
--- a/plugins/smolblok_hostlist/test/plugin.cpp
+++ b/plugins/HostlistFilter/test/plugin.cpp
@@ -3,6 +3,8 @@
#include <QFile>
#include <catch2/catch.hpp>
+// clazy:skip
+
TEST_CASE("Hostlist")
{
HostlistFilterPlugin plugin;
diff --git a/plugins/HostlistFilter/test/rule.cpp b/plugins/HostlistFilter/test/rule.cpp
new file mode 100644
index 0000000..5ee9881
--- /dev/null
+++ b/plugins/HostlistFilter/test/rule.cpp
@@ -0,0 +1,57 @@
+#define CATCH_CONFIG_MAIN
+#include "filterlist.h"
+#include <catch2/catch.hpp>
+
+// clazy:skip
+
+using namespace Hostlist;
+
+SCENARIO("Hostlist::Rule")
+{
+ GIVEN("an invalid rule")
+ {
+ QStringList b;
+ QHash<QString, QString> r;
+ parseRule("0.0.0.0 ", b, r);
+
+ REQUIRE(b.empty());
+ REQUIRE(r.empty());
+ }
+ GIVEN("127.0.0.1 localhost.localdomain")
+ {
+ QStringList b;
+ QHash<QString, QString> r;
+ parseRule("127.0.0.1 localhost.localdomain", b, r);
+
+ REQUIRE(b.empty());
+ REQUIRE(r.size() == 1);
+
+ REQUIRE(r.value("localhost.localdomain") == "127.0.0.1");
+ }
+
+ GIVEN("0.0.0.0 blockeddomain.com")
+ {
+ QStringList b;
+ QHash<QString, QString> r;
+ parseRule("0.0.0.0 blockeddomain.com", b, r);
+
+ REQUIRE(b.size() == 1);
+ REQUIRE(r.empty());
+
+ REQUIRE(b.contains("blockeddomain.com"));
+ ;
+ }
+
+ GIVEN("0.0.0.0 blockeddomain.first blockeddomain.second")
+ {
+ QStringList b;
+ QHash<QString, QString> r;
+ parseRule("0.0.0.0 blockeddomain.first blockeddomain.second", b, r);
+
+ REQUIRE(b.size() == 2);
+ REQUIRE(r.empty());
+
+ REQUIRE(b.contains("blockeddomain.first"));
+ REQUIRE(b.contains("blockeddomain.second"));
+ }
+}
diff --git a/plugins/smolblok_hostlist/filterlist.cpp b/plugins/smolblok_hostlist/filterlist.cpp
deleted file mode 100644
index a0fd414..0000000
--- a/plugins/smolblok_hostlist/filterlist.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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://library.iserlohn-fortress.net/aqua/smolbote.git
- *
- * SPDX-License-Identifier: GPL-3.0
- */
-
-#include "filterlist.h"
-#include <QIODevice>
-#include <QTextStream>
-
-using namespace Hostlist;
-
-#ifdef FUZZER
-extern "C" int LLVMFuzzerTestOneInput(const char *Data, long long Size)
-{
- Filterlist::parseRule(QString::fromLatin1(Data, Size));
- return 0;
-}
-#endif
-
-std::map<Filterlist::DomainHash, Filterlist::Rule> Filterlist::parseRule(const QString &line)
-{
- if(line.isEmpty() || line.at(0) == '#') {
- return {};
- }
-
- auto parts = line.trimmed().split(' ');
- if(parts.size() < 2) {
- return {};
- }
-
- const auto redirect = (parts[0] == "0.0.0.0") ? QString() : parts[0];
-
- std::map<DomainHash, Rule> r;
- for(int i = 1; i < parts.size(); ++i) {
- r.emplace(qHash(parts[i], 0), Filterlist::Rule{ parts[i], redirect });
- }
- return r;
-}
-
-bool Filterlist::load(QIODevice &from)
-{
- if(!from.isReadable() || !from.isTextModeEnabled()) {
- return false;
- }
-
- while(from.bytesAvailable() > 0) {
- const auto line = from.readLine(512).trimmed();
- auto r = parseRule(line);
- if(!r.empty()) {
- qDebug("merging in %lu rules", r.size());
- rules.merge(r);
- }
- }
- return true;
-}
diff --git a/plugins/smolblok_hostlist/filterlist.h b/plugins/smolblok_hostlist/filterlist.h
deleted file mode 100644
index 7301f20..0000000
--- a/plugins/smolblok_hostlist/filterlist.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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://library.iserlohn-fortress.net/aqua/smolbote.git
- *
- * SPDX-License-Identifier: GPL-3.0
- */
-
-#pragma once
-
-#include <map>
-#include <smolbote/filterinterface.hpp>
-
-namespace Hostlist
-{
-
-class Filterlist final : public FilterList
-{
-public:
- typedef uint DomainHash;
- struct Rule {
- QString domain;
- QString redirect;
- };
-
- Filterlist() = default;
- ~Filterlist() = default;
-
- [[nodiscard]] bool findMatch(const QString &domain) const
- {
- const auto hash = qHash(domain, 0);
- const auto found = rules.find(hash);
- if(found != rules.end()) {
- return true;
- }
- return false;
- }
- int count() const
- {
- return rules.size();
- }
-
- [[nodiscard]] bool filter(QWebEngineUrlRequestInfo &info) const
- {
- return false;
- }
- [[nodiscard]] bool isUpToDate() const
- {
- return true;
- }
-
- bool load(QIODevice &device);
- [[nodiscard]] static std::map<DomainHash, Rule> parseRule(const QString &line);
-
-private:
- std::map<DomainHash, Rule> rules;
-};
-} // namespace Hostlist
diff --git a/plugins/smolblok_hostlist/meson.build b/plugins/smolblok_hostlist/meson.build
deleted file mode 100644
index c9ff303..0000000
--- a/plugins/smolblok_hostlist/meson.build
+++ /dev/null
@@ -1,50 +0,0 @@
-lib_hostlistfilter = static_library('hostlistfilter',
- [ 'filterlist.cpp' ],
- include_directories: smolbote_interfaces,
- dependencies: [dep_qt5]
-)
-
-dep_hostlistfilter = declare_dependency(
- include_directories: [ '.', smolbote_interfaces ],
- link_with: lib_hostlistfilter
-)
-
-# plugin
-plugin = shared_library('smolblokHostlistPlugin',
- [ 'plugin/plugin.cpp',
- mod_qt5.preprocess(include_directories: smolbote_interfaces, moc_headers: 'plugin/plugin.h', dependencies: dep_qt5) ],
- include_directories: smolbote_interfaces,
- dependencies: [ dep_hostlistfilter, dep_qt5 ],
- install: true,
- install_dir: get_option('libdir')/'smolbote/plugins'
-)
-
-# tests
-test('rule', executable('rule', sources: 'test/rule.cpp', dependencies: [dep_qt5, dep_catch, dep_hostlistfilter]), suite: 'hostlist')
-
-test('filterlist', executable('filterlist',
- sources: 'test/filterlist.cpp',
- dependencies: [dep_qt5, dep_catch, dep_hostlistfilter]),
- env: 'HOSTLIST_TXT='+meson.current_source_dir()/'test/hostlist.txt',
- suite: 'hostlist'
-)
-test('plugin', executable('filterlist-plugin',
- sources: [ 'test/plugin.cpp', 'plugin/plugin.cpp',
- mod_qt5.preprocess(include_directories: smolbote_interfaces, moc_headers: 'plugin/plugin.h', dependencies: dep_qt5) ],
- dependencies: [dep_qt5, dep_catch, dep_hostlistfilter]),
- env: 'HOSTLIST_TXT='+meson.current_source_dir()/'test/hostlist.txt',
- suite: 'hostlist'
-)
-
-test('smolblok-load', smolblok_load, workdir: meson.build_root(), args: plugin.full_path(), suite: 'hostlist')
-
-# fuzzer
-if meson.get_compiler('cpp').has_multi_arguments('-g', '-fsanitize=fuzzer')
-executable('hostlist-fuzzer',
- sources: 'filterlist.cpp',
- include_directories: smolbote_interfaces,
- dependencies: dep_qt5,
- cpp_args: [ '-g', '-fsanitize=fuzzer', '-DFUZZER' ],
- link_args: [ '-fsanitize=fuzzer' ]
-)
-endif
diff --git a/plugins/smolblok_hostlist/test/filterlist.cpp b/plugins/smolblok_hostlist/test/filterlist.cpp
deleted file mode 100644
index 4aa532b..0000000
--- a/plugins/smolblok_hostlist/test/filterlist.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#define CATCH_CONFIG_MAIN
-#include "filterlist.h"
-#include <QFile>
-#include <catch2/catch.hpp>
-
-using namespace Hostlist;
-
-TEST_CASE("Hostlist")
-{
- Filterlist list;
-
- const QString filename(qgetenv("HOSTLIST_TXT"));
- REQUIRE(!filename.isEmpty());
-
- QFile f(filename);
- REQUIRE(f.open(QIODevice::ReadOnly | QIODevice::Text));
-
- REQUIRE(list.load(f));
- f.close();
-
- REQUIRE(list.count() == 4);
-
- REQUIRE(list.findMatch("blockeddomain.first"));
- REQUIRE(list.findMatch("blockeddomain.second"));
-
- REQUIRE(list.findMatch("localhost.localdomain"));
-
- REQUIRE(!list.findMatch("other.domain"));
-}
diff --git a/plugins/smolblok_hostlist/test/rule.cpp b/plugins/smolblok_hostlist/test/rule.cpp
deleted file mode 100644
index b5ba6e0..0000000
--- a/plugins/smolblok_hostlist/test/rule.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#define CATCH_CONFIG_MAIN
-#include "filterlist.h"
-#include <catch2/catch.hpp>
-
-using namespace Hostlist;
-
-SCENARIO("Hostlist::Rule")
-{
- GIVEN("an invalid rule")
- {
- const auto rule = Filterlist::parseRule("0.0.0.0 ");
- REQUIRE(rule.empty());
- }
- GIVEN("127.0.0.1 localhost.localdomain")
- {
- auto rule = Filterlist::parseRule("127.0.0.1 localhost.localdomain");
-
- REQUIRE(!rule.empty());
- REQUIRE(rule.size() == 1);
-
- // note: you need to force it to hash a string, rather than the address itself
- const auto index = qHash(QString("localhost.localdomain"), 0);
- REQUIRE(rule[index].domain == "localhost.localdomain");
- REQUIRE(rule[index].redirect == "127.0.0.1");
- }
-
- GIVEN("0.0.0.0 blockeddomain.com")
- {
- auto rule = Filterlist::parseRule("0.0.0.0 blockeddomain.com");
-
- REQUIRE(!rule.empty());
- REQUIRE(rule.size() == 1);
-
- const auto index = qHash(QString("blockeddomain.com"), 0);
- REQUIRE(rule[index].domain == "blockeddomain.com");
- REQUIRE(rule[index].redirect.isEmpty());
- ;
- }
-
- GIVEN("0.0.0.0 blockeddomain.first blockeddomain.second")
- {
- auto rule = Filterlist::parseRule("0.0.0.0 blockeddomain.first blockeddomain.second");
-
- REQUIRE(!rule.empty());
- REQUIRE(rule.size() == 2);
- {
- const auto index = qHash(QString("blockeddomain.first"), 0);
- REQUIRE(rule[index].domain == "blockeddomain.first");
- REQUIRE(rule[index].redirect.isEmpty());
- }
- {
- const auto index = qHash(QString("blockeddomain.second"), 0);
- REQUIRE(rule[index].domain == "blockeddomain.second");
- REQUIRE(rule[index].redirect.isEmpty());
- }
- }
-}
diff --git a/scripts/gen-crashhandler-default-go.py b/scripts/gen-crashhandler-default-go.py
deleted file mode 100755
index e080ed9..0000000
--- a/scripts/gen-crashhandler-default-go.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-import argparse
-import kconfiglib
-import re
-
-def findItem(node, name):
- while node:
- if isinstance(node.item, kconfiglib.Symbol):
- if node.item.name == name:
- return node.item.str_value
-
- if node.list:
- found = findItem(node.list, name)
- if found is not None:
- return found
-
- node = node.next
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser()
- parser.add_argument("--kconfig", nargs="?", default="Kconfig", help="Top-level Kconfig")
- parser.add_argument("--dotconfig", nargs="?", help=".config")
- parser.add_argument("--input", type=argparse.FileType('r'), help="default.go.in")
- parser.add_argument("--output", type=argparse.FileType('w'), default=sys.stdout, help="Output location")
- args = parser.parse_args()
-
- kconf = kconfiglib.Kconfig(args.kconfig)
- if args.dotconfig is not None:
- kconf.load_config(args.dotconfig)
-
- marker = re.compile('.+(@(\w+)@)')
- for line in args.input:
- found = marker.match(line)
- if found:
- print(str.replace(line, found.group(1), findItem(kconf.top_node, found.group(2))), end='', file=args.output)
- else:
- print(line, end='', file=args.output)
-
diff --git a/scripts/gen-default-cfg.py b/scripts/gen-default-cfg.py
index dc88ceb..afcaed2 100755
--- a/scripts/gen-default-cfg.py
+++ b/scripts/gen-default-cfg.py
@@ -8,10 +8,10 @@ def node_to_str(node):
if(node.item.type == kconfiglib.STRING):
return "std::string(\"" + node.item.str_value + "\")"
elif(node.item.type == kconfiglib.INT):
- return "int(" + node.item.str_value + ")"
+ return node.item.str_value
elif(node.item.type == kconfiglib.BOOL):
tri_val_str = ("false", "unknown", "true")[node.item.tri_value]
- return "bool(" + tri_val_str + ")"
+ return tri_val_str
return None
@@ -26,6 +26,27 @@ def writeItem(node, file):
node = node.next
+def writeConfigPaths(file):
+ # -1: invalid
+ # 0: $HOME
+ # 1: $XDG_CONFIG_HOME
+
+ locations = [
+ "$HOME/.poirc",
+ "$XDG_CONFIG_HOME/smolbote.conf",
+ "$XDG_CONFIG_HOME/smolbote/config",
+ "$HOME/.config/smolbote.conf",
+ "$HOME/.config/smolbote/config",
+ "/etc/smolbote/config"]
+
+ for item in locations:
+ if item.startswith("$HOME/"):
+ print('\t\tstd::make_pair(0, "{}"),'.format(item[len("$HOME/"):]), file=file)
+ elif item.startswith("$XDG_CONFIG_HOME/"):
+ print('\t\tstd::make_pair(1, "{}"),'.format(item[len("$XDG_CONFIG_HOME/"):]), file=file)
+ else:
+ print('\t\tstd::make_pair(-1, "{}"),'.format(item), file=file)
+
if __name__ == "__main__":
parser = argparse.ArgumentParser()
@@ -47,5 +68,7 @@ if __name__ == "__main__":
for line in args.input:
if "@__DEFAULT_CFG__" in line:
writeItem(kconf.top_node.list, file=args.output)
+ elif "@__CONFIG_PATHS__" in line:
+ writeConfigPaths(file=args.output)
else:
print(line, end='', file=args.output)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..865c3f7
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,42 @@
+add_subdirectory(autogen)
+add_subdirectory(about)
+add_subdirectory(cmd)
+
+add_executable(poi
+ bookmarks/builtin.cpp
+ bookmarks/bookmarkswidget.h bookmarks/bookmarkswidget.cpp bookmarks/bookmarksform.ui
+ bookmarks/bookmarkstoolbar.h bookmarks/bookmarkstoolbar.cpp
+ bookmarks/editbookmarkdialog.h bookmarks/editbookmarkdialog.cpp bookmarks/editbookmarkdialog.ui
+
+ cmd/cmd.hpp
+ configuration/builtin.cpp
+
+ mainwindow/widgets/completer.h mainwindow/widgets/completer.cpp
+ mainwindow/widgets/dockwidget.h mainwindow/widgets/dockwidget.cpp
+ mainwindow/widgets/menusearch.h mainwindow/widgets/menusearch.cpp
+ mainwindow/widgets/navigationbar.h mainwindow/widgets/navigationbar.cpp
+ mainwindow/widgets/searchform.h mainwindow/widgets/searchform.cpp mainwindow/widgets/searchform.ui
+ mainwindow/widgets/urllineedit.h mainwindow/widgets/urllineedit.cpp
+ mainwindow/addressbar.h mainwindow/addressbar.cpp mainwindow/addressbar.ui
+ mainwindow/mainwindow.h mainwindow/mainwindow.cpp
+ mainwindow/menubar.h mainwindow/menubar.cpp
+
+ session/builtin.cpp
+ session/savesessiondialog.h session/savesessiondialog.cpp session/savesessiondialog.ui
+ session/sessiondialog.h session/sessiondialog.cpp session/sessiondialog.ui
+
+ subwindow/subwindow.h subwindow/subwindow.cpp
+ subwindow/tabwidget.h subwindow/tabwidget.cpp
+
+ main.cpp
+ applicationmenu.h applicationmenu.cpp
+ browser.h browser.cpp)
+
+target_link_libraries(poi PRIVATE Qt5::Widgets Qt5::WebEngineWidgets Qt5::Svg
+ SingleApplication::SingleApplication fmt spdlog
+ autogen about_dialog about_plugin webengine
+ bookmarks configuration downloads pluginloader session_formats smolblok)
+
+target_include_directories(poi PRIVATE . ${CMAKE_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR})
+install(TARGETS poi DESTINATION bin)
+
diff --git a/src/about/CMakeLists.txt b/src/about/CMakeLists.txt
new file mode 100644
index 0000000..027d509
--- /dev/null
+++ b/src/about/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_library(about_dialog INTERFACE)
+target_sources(about_dialog INTERFACE aboutdialog.h aboutdialog.cpp aboutdialog.ui)
+target_include_directories(about_dialog INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(about_dialog INTERFACE autogen Qt5::Widgets Qt5::Svg)
+
+add_library(about_plugin INTERFACE)
+target_sources(about_plugin INTERFACE aboutplugin.h aboutplugin.cpp aboutplugin.ui)
+
+add_executable(test_about test/main.cpp)
+target_link_libraries(test_about PRIVATE about_dialog Catch2::Catch2)
+target_sanitize(test_about) \ No newline at end of file
diff --git a/src/about/aboutdialog.cpp b/src/about/aboutdialog.cpp
index 894b1ec..643b87c 100644
--- a/src/about/aboutdialog.cpp
+++ b/src/about/aboutdialog.cpp
@@ -7,8 +7,9 @@
*/
#include "aboutdialog.h"
+#include "poi_logos.h"
#include "ui_aboutdialog.h"
-#include <version.h>
+#include "version.h"
// compiler
// clang also defines __GNUC__, so we need to check for clang first
@@ -26,18 +27,13 @@ AboutDialog::AboutDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::AboutDialog)
{
+ // This causes a double-free in the destructor
//setAttribute(Qt::WA_DeleteOnClose, true);
+
ui->setupUi(this);
- const QByteArray icon_svg = R"SVG(
-<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" version="1.1">
- <circle cx="150" cy="150" r="100" stroke="#000000" stroke-width="6" fill="#e60026"></circle>
- <circle cx="150" cy="150" r="87" stroke="#000000" stroke-width="4" fill="#e5e4e2"></circle>
- <path d="M230,150 A80,80 0 0 0 150,70 L150,150 Z" />
- <path d="M70,150 A80,80 0 0 0 150,230 L150,150 Z" />
-</svg>
-)SVG";
- ui->appIcon_svg->load(icon_svg);
+ constexpr auto icon_svg = logos::get([] { return std::string_view("poi_window.svg"); });
+ ui->appIcon_svg->load(QByteArray(icon_svg.data(), icon_svg.size()));
ui->appName_label->setText(qApp->applicationName());
ui->appVersion_label->setText(qApp->applicationVersion());
@@ -59,16 +55,12 @@ AboutDialog::AboutDialog(QWidget *parent)
"<p>This program is distributed in the hope that it will be useful, but without any warranty.</p>"
"<p>You can read the full terms of the license on <a href='https://www.gnu.org/licenses/gpl-3.0.en.html'>the GNU website</a>.</p>"));
- ui->detailsLabel->setText(tr("<p>Version " poi_Version "</p>"
+ ui->detailsLabel->setText(tr("<p>Version " POI_VERSION "</p>"
"<p>Compiled with " compiler "</p>"
"<p>Libraries: <ul>"
"<li><a href='https://www.qt.io/'>Qt5</a> " QT_VERSION_STR "</li>"
"<li>spdlog</li>"
- "<li><a href='https://github.com/Taywee/args'>args.hxx</a></li>"
"<li><a href='https://github.com/itay-grudev/SingleApplication'>SingleApplication</a></li>"
-#ifdef CONFIG_USEBREAKPAD
- "<li><a href='https://chromium.googlesource.com/breakpad/breakpad'>Breakpad</a></li>"
-#endif
"</ul></p>"));
}
diff --git a/src/about/meson.build b/src/about/meson.build
deleted file mode 100644
index 49274a8..0000000
--- a/src/about/meson.build
+++ /dev/null
@@ -1,21 +0,0 @@
-about_moc = mod_qt5.preprocess(
- moc_headers: ['aboutdialog.h', 'aboutplugin.h'],
- ui_files: ['aboutdialog.ui', 'aboutplugin.ui'],
- dependencies: dep_qt5
-)
-
-dep_about = declare_dependency(
- include_directories: '.',
- link_with: static_library('about',
- [ 'aboutdialog.cpp', 'aboutplugin.cpp', about_moc, version_h],
- dependencies: [dep_qt5])
-)
-
-poi_sourceset.add(dep_about)
-
-test('about dialog', executable('about',
- sources: 'test/main.cpp',
- dependencies: [ dep_qt5, dep_about, dep_catch ]),
- args: [ '-platform', 'offscreen' ],
- env: 'autoclose=1'
-)
diff --git a/src/about/test/main.cpp b/src/about/test/main.cpp
index 18037e1..1b71c8e 100644
--- a/src/about/test/main.cpp
+++ b/src/about/test/main.cpp
@@ -1,12 +1,13 @@
#include <QApplication>
#include <QTimer>
#include "aboutdialog.h"
+#include "version.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
- app.setApplicationName("about");
- app.setApplicationVersion("1.2.3");
+ app.setApplicationName(POI_NAME);
+ app.setApplicationVersion(POI_SHORT_VERSION);
AboutDialog dlg;
QObject::connect(&dlg, &AboutDialog::finished, &app, &QApplication::quit);
@@ -17,5 +18,4 @@ int main(int argc, char **argv)
}
return app.exec();
-}
-
+} \ No newline at end of file
diff --git a/src/applicationmenu.cpp b/src/applicationmenu.cpp
index dc888e7..e6cc538 100644
--- a/src/applicationmenu.cpp
+++ b/src/applicationmenu.cpp
@@ -7,6 +7,8 @@
*/
#include "applicationmenu.h"
+#include "about/aboutdialog.h"
+#include "about/aboutplugin.h"
#include "browser.h"
#include "configuration.h"
#include "session/savesessiondialog.h"
@@ -19,7 +21,7 @@ ApplicationMenu::ApplicationMenu(Browser *app, QWidget *parent)
: QMenu(parent)
{
m_app = app;
- setTitle(qApp->applicationName());
+ setTitle(QApplication::applicationName());
Configuration conf;
const auto sessionPath = conf.value<QString>("session.path").value();
@@ -39,10 +41,19 @@ ApplicationMenu::ApplicationMenu(Browser *app, QWidget *parent)
bottom_pluginSeparator = addSeparator();
- auto *actionAbout = addAction(tr("About"), app, &Browser::about);
+ auto *actionAbout = addAction(tr("About"), app, []() {
+ auto *dlg = new AboutDialog(QApplication::activeWindow());
+ dlg->show();
+ });
conf.shortcut<QAction>(*actionAbout, "shortcuts.window.about");
- auto *action_aboutPlugins = addAction(tr("About Plugins"), app, &Browser::aboutPlugins);
+ auto *action_aboutPlugins = addAction(tr("About Plugins"), app, [app]() {
+ auto *dlg = new AboutPluginDialog(QApplication::activeWindow());
+ for(auto *info : qAsConst(app->m_plugins)) {
+ dlg->add(info->loader);
+ }
+ dlg->show();
+ });
conf.shortcut(*action_aboutPlugins, "app.shortcuts.about.plugins");
auto *actionQuit = addAction(tr("Quit"), app, &Browser::quit);
diff --git a/src/autogen/CMakeLists.txt b/src/autogen/CMakeLists.txt
new file mode 100644
index 0000000..f97526f
--- /dev/null
+++ b/src/autogen/CMakeLists.txt
@@ -0,0 +1,35 @@
+find_program(PYTHON python3)
+
+# version.h
+configure_file(version.h.in version.h @ONLY)
+
+# settings.h
+add_custom_command(OUTPUT settings.h DEPENDS settings.h.in
+ COMMAND ${PYTHON} ${CMAKE_SOURCE_DIR}/scripts/gen-default-cfg.py
+ --kconfig=${CMAKE_SOURCE_DIR}/Kconfig --dotconfig=${CMAKE_SOURCE_DIR}/linux/.config
+ --input=${CMAKE_CURRENT_SOURCE_DIR}/settings.h.in --output=settings.h)
+
+# poi_logos.h
+set(poi_logos ${CMAKE_SOURCE_DIR}/data/poi.svg ${CMAKE_SOURCE_DIR}/data/poi_window.svg)
+add_custom_command(OUTPUT poi_logos.h DEPENDS ${poi_logos}
+ COMMAND ${PYTHON} ${RCC} -o=poi_logos.h dump -ns=logos ${poi_logos})
+
+# poi_icons.h
+set(poi_icons
+ icons/arrow-left.svg icons/arrow-right.svg icons/circle-x.svg icons/refresh.svg icons/home.svg
+ icons/volume.svg icons/volume-3.svg)
+foreach(f ${poi_icons})
+ list(REMOVE_ITEM poi_icons ${f})
+ list(APPEND poi_icons ${ICONS_PATH}/${f})
+endforeach()
+add_custom_command(OUTPUT poi_icons.h DEPENDS ${poi_icons}
+ COMMAND ${PYTHON} ${RCC} -o=poi_icons.h dump -ns=icons ${poi_icons})
+
+# autogen target
+add_custom_target(py_autogen DEPENDS settings.h poi_logos.h poi_icons.h)
+
+add_library(autogen INTERFACE)
+target_sources(autogen INTERFACE util.h util.cpp applicationstyle.h applicationstyle.cpp)
+target_include_directories(autogen INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(autogen INTERFACE fmt Qt5::Svg)
+add_dependencies(autogen py_autogen)
diff --git a/src/autogen/applicationstyle.cpp b/src/autogen/applicationstyle.cpp
new file mode 100644
index 0000000..40c93d3
--- /dev/null
+++ b/src/autogen/applicationstyle.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#include "applicationstyle.h"
+#include "poi_icons.h"
+#include "poi_logos.h"
+#include <QPainter>
+#include <QStyleFactory>
+#include <QSvgRenderer>
+#include <spdlog/spdlog.h>
+
+[[nodiscard]] inline QPixmap render(const auto &data, const QSize size = QSize())
+{
+ QSvgRenderer renderer;
+ renderer.load(QByteArray(data.data(), static_cast<int>(data.size())));
+
+ QPixmap pm(size.isValid() ? size : renderer.defaultSize());
+ pm.fill(Qt::transparent);
+
+ QPainter painter(&pm);
+ renderer.render(&painter, pm.rect());
+
+ return pm;
+}
+
+ApplicationStyle::ApplicationStyle()
+ : QProxyStyle(QStyleFactory::create("fusion"))
+{
+}
+
+QIcon ApplicationStyle::standardIcon(QStyle::StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *w) const
+{
+ using namespace std::literals;
+
+ if(standardPixmap == QStyle::SP_MediaVolume) {
+ auto on = render(icons::get([] { return "volume-3.svg"sv; }));
+ auto off = render(icons::get([] { return "volume.svg"sv; }));
+ QIcon m;
+ m.addPixmap(on, QIcon::Normal, QIcon::On);
+ m.addPixmap(off, QIcon::Normal, QIcon::Off);
+ return m;
+ }
+
+ const auto id = [standardPixmap]() {
+ switch(standardPixmap) {
+ case QStyle::SP_ArrowBack:
+ return "arrow-left.svg"sv;
+ case QStyle::SP_ArrowForward:
+ return "arrow-right.svg"sv;
+ case QStyle::SP_BrowserStop:
+ return "circle-x.svg"sv;
+ case QStyle::SP_BrowserReload:
+ return "refresh.svg"sv;
+ case QStyle::SP_DirHomeIcon:
+ return "home.svg"sv;
+ default:
+ return "__unknown__"sv;
+ }
+ }();
+
+ const auto *const data = std::find_if(icons::entries.begin(), icons::entries.end(), [id](const auto &tuple) -> bool {
+ return std::get<0>(tuple) == id;
+ });
+
+ if(data == icons::entries.end()) {
+ spdlog::error("fixme: getting default fusion icon for StandardPixmap({})", standardPixmap);
+ return QStyleFactory::create("fusion")->standardIcon(standardPixmap, opt, w);
+ }
+
+ const auto d = std::get<1>(*data);
+ return QIcon(render(d));
+}
+
+QIcon ApplicationStyle::applicationIcon()
+{
+ using namespace std::literals;
+ constexpr auto d = logos::get([]{ return "poi.svg"sv; });
+ return QIcon(render(d));
+}
+
+QIcon ApplicationStyle::windowIcon()
+{
+ using namespace std::literals;
+ constexpr auto d = logos::get([]{ return "poi_window.svg"sv; });
+ return QIcon(render(d));
+}
diff --git a/src/autogen/applicationstyle.h b/src/autogen/applicationstyle.h
new file mode 100644
index 0000000..f9bf1bd
--- /dev/null
+++ b/src/autogen/applicationstyle.h
@@ -0,0 +1,26 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#ifndef SMOLBOTE_APPLICATION_STYLE_H
+#define SMOLBOTE_APPLICATION_STYLE_H
+
+#include <QProxyStyle>
+
+class ApplicationStyle : public QProxyStyle
+{
+public:
+ ApplicationStyle();
+ ~ApplicationStyle() override = default;
+
+ QIcon standardIcon(QStyle::StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const override;
+
+ static QIcon applicationIcon();
+ static QIcon windowIcon();
+};
+
+#endif \ No newline at end of file
diff --git a/src/autogen/settings.h.in b/src/autogen/settings.h.in
new file mode 100644
index 0000000..51b2bd0
--- /dev/null
+++ b/src/autogen/settings.h.in
@@ -0,0 +1,70 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#pragma once
+
+#include <configuration.h>
+#include <fstream>
+#include <cstdlib>
+#include <filesystem>
+#include <array>
+#include <spdlog/spdlog.h>
+
+inline auto init_conf(const std::string &path)
+{
+ namespace fs = std::filesystem;
+ struct {
+ std::optional<fs::path> path;
+ std::unique_ptr<Configuration> ptr;
+ } conf;
+
+ conf.ptr = std::make_unique<Configuration, std::initializer_list<std::pair<std::string, conf_value_t>>>({
+ @__DEFAULT_CFG__
+ });
+
+ conf.path = [&]() -> std::optional<fs::path> {
+ if(!path.empty()) {
+ return fs::path(path);
+ }
+
+ // 1000: invalid; 0: $HOME; 1: $XDG_CONFIG_HOME
+ std::array<std::optional<fs::path>, 2> home = { std::nullopt, std::nullopt };
+ if(const char* usr = std::getenv("HOME"))
+ home[0] = fs::path(usr);
+ if(const char* xdg = std::getenv("XDG_CONFIG_HOME"))
+ home[1] = fs::path(xdg);
+
+ for(const auto &pair : {
+ @__CONFIG_PATHS__
+ }) {
+ if(pair.first < 0) {
+ auto p = fs::path(pair.second);
+ spdlog::debug("Trying {}", p.c_str());
+ if(fs::exists(p))
+ return p;
+ } else if(home[static_cast<std::size_t>(pair.first)]) {
+ auto p = home[static_cast<std::size_t>(pair.first)].value() / pair.second;
+ spdlog::debug("Trying {}", p.c_str());
+ if(fs::exists(p))
+ return p;
+ }
+ }
+
+ return std::nullopt;
+
+ }();
+
+ if(conf.path) {
+ std::fstream file(conf.path.value(), std::fstream::in);
+ if(file.is_open()) {
+ conf.ptr->read(file);
+ file.close();
+ }
+ }
+ return conf;
+}
diff --git a/src/util.cpp b/src/autogen/util.cpp
index fe74175..0120be2 100644
--- a/src/util.cpp
+++ b/src/autogen/util.cpp
@@ -7,17 +7,15 @@
*/
#include "util.h"
+#include <QApplication>
#include <QDir>
#include <QFileInfo>
-#include <QApplication>
-#include <spdlog/spdlog.h>
#define ListSeparator QLatin1String(";")
const QStringList Util::files(const QString &location, const QStringList &nameFilters)
{
- if(location.isEmpty())
- return QStringList();
+ if(location.isEmpty()) return QStringList();
QStringList filelist;
@@ -47,22 +45,3 @@ const QStringList Util::files(const QString &location, const QStringList &nameFi
return filelist;
}
-// icon names: https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
-QIcon Util::icon(QStyle::StandardPixmap id) {
- switch(id) {
- case QStyle::SP_ArrowBack:
- return QIcon::fromTheme("go-previous", qApp->style()->standardIcon(id));
- case QStyle::SP_ArrowForward:
- return QIcon::fromTheme("go-next", qApp->style()->standardIcon(id));
- case QStyle::SP_BrowserStop:
- return QIcon::fromTheme("process-stop", qApp->style()->standardIcon(id));
- case QStyle::SP_BrowserReload:
- return QIcon::fromTheme("view-refresh", qApp->style()->standardIcon(id));
- case QStyle::SP_DirHomeIcon:
- return QIcon::fromTheme("go-home", qApp->style()->standardIcon(id));
-
- default:
- spdlog::warn("FIXME: unhandled StandardPixmap {}", id);
- return qApp->style()->standardIcon(id);
- }
-}
diff --git a/src/util.h b/src/autogen/util.h
index d96dc19..aa3e954 100644
--- a/src/util.h
+++ b/src/autogen/util.h
@@ -10,14 +10,11 @@
#define SMOLBOTE_UTIL_H
#include <QStringList>
-#include <QIcon>
-#include <QStyle>
namespace Util {
const QStringList files(const QString &location, const QStringList &nameFilters = QStringList());
-[[nodiscard]] QIcon icon(QStyle::StandardPixmap id);
-}
+} // namespace Util
#endif // SMOLBOTE_UTIL_H
diff --git a/src/autogen/version.h.in b/src/autogen/version.h.in
new file mode 100644
index 0000000..4d50885
--- /dev/null
+++ b/src/autogen/version.h.in
@@ -0,0 +1,21 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#ifndef SMOLBOTE_VERSION_H
+#define SMOLBOTE_VERSION_H
+
+/*
+ * This is an automatically generated file, any changes to it may be overwritten.
+ * Edit src/version.h.in instead.
+ */
+
+#define POI_NAME "@CMAKE_PROJECT_NAME@"
+#define POI_VERSION "@CMAKE_PROJECT_VERSION@"
+#define POI_SHORT_VERSION "@CMAKE_PROJECT_SHORT_VERSION@"
+
+#endif // SMOLBOTE_VERSION_H
diff --git a/src/bookmarks/bookmarkswidget.cpp b/src/bookmarks/bookmarkswidget.cpp
index c7bc5f0..969f19e 100644
--- a/src/bookmarks/bookmarkswidget.cpp
+++ b/src/bookmarks/bookmarkswidget.cpp
@@ -12,8 +12,8 @@
#include "mainwindow/mainwindow.h"
#include "subwindow/subwindow.h"
#include "ui_bookmarksform.h"
-#include "webengine/webprofilemanager.h"
-#include "webengine/webview.h"
+#include "webprofilemanager.h"
+#include "webview.h"
#include <QFileDialog>
#include <QMenu>
#include <QTreeView>
diff --git a/src/bookmarks/builtin.cpp b/src/bookmarks/builtin.cpp
new file mode 100644
index 0000000..b8b925c
--- /dev/null
+++ b/src/bookmarks/builtin.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#include "bookmarkmodel.h"
+#include "browser.h"
+#include "configuration.h"
+#include <QBuffer>
+#include <QCommandLineParser>
+#include <QFile>
+#include <cstdlib>
+#include <iostream>
+#include <spdlog/spdlog.h>
+
+template <auto T>
+[[nodiscard]] inline bool import(BookmarkModel *model, const QString &path)
+{
+ QFile f(path);
+ if(f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ BookmarkFormat<T>(&f) >> model;
+ f.close();
+ return true;
+ }
+ return false;
+}
+
+namespace builtins
+{
+int sub_bookmarks(const QStringList &l, Browser &)
+{
+ const QCommandLineOption output({ "o", "output" }, "Output location (default: append to browser bookmarks).", "file");
+
+ const QCommandLineOption import_xbel({ "x", "import-xbel" }, "Import xbel format.", "xbel");
+ const QCommandLineOption import_json({ "j", "import-json" }, "Import json format.", "json");
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("smolbote: bookmarks");
+ parser.addHelpOption();
+
+ parser.addOptions({ output, import_xbel, import_json });
+
+ if(l.count() <= 1) {
+ parser.showHelp();
+ }
+
+ parser.process(l);
+ Configuration conf;
+ const auto bookmarks_path = conf.value<QString>("bookmarks.path").value();
+ auto *model = new BookmarkModel;
+
+ // implicit bookmarks.path import
+ if(!parser.isSet(output)) {
+ if(!import<XbelFormat>(model, bookmarks_path)) {
+ spdlog::error("Could not open %s", qUtf8Printable(bookmarks_path));
+ }
+ }
+
+ for(const auto &i : parser.values(import_xbel)) {
+ if(!import<XbelFormat>(model, i)) {
+ spdlog::error("Could not open %s", qUtf8Printable(i));
+ }
+ }
+
+ for(const auto &i : parser.values(import_json)) {
+ if(!import<FirefoxJsonFormat>(model, i)) {
+ spdlog::error("Could not open %s", qUtf8Printable(i));
+ }
+ }
+
+ QIODevice *out = nullptr;
+ if(!parser.isSet(output)) {
+ out = new QFile(bookmarks_path);
+ } else {
+ const auto o = parser.value(output);
+
+ if(o == "stdout") {
+ out = new QBuffer;
+ QObject::connect(out, &QIODevice::aboutToClose, [out]() {
+ out->seek(0);
+ std::cout << qUtf8Printable(out->readAll()) << std::endl;
+ });
+
+ } else {
+ out = new QFile(o);
+ }
+ }
+
+ if(!out->isOpen()) {
+ if(!out->open(QIODevice::ReadWrite | QIODevice::Text)) {
+ spdlog::error("Could not open output");
+ return EXIT_FAILURE;
+ }
+ }
+
+ BookmarkFormat<XbelFormat> format(out);
+ format << model;
+ out->close();
+
+ delete out;
+ delete model;
+ return EXIT_SUCCESS;
+}
+} // namespace
diff --git a/src/bookmarks/builtins.cpp b/src/bookmarks/builtins.cpp
deleted file mode 100644
index f7b6f3f..0000000
--- a/src/bookmarks/builtins.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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 "builtins.h"
-#include "bookmarkmodel.h"
-#include "configuration.h"
-#include <QBuffer>
-#include <QFile>
-#include <iostream>
-#include <spdlog/spdlog.h>
-
-int builtins::bookmarks(const std::string &progname, std::vector<std::string>::const_iterator beginargs, std::vector<std::string>::const_iterator endargs)
-{
- args::ArgumentParser parser("bookmarks",
- "If an output location is not specified, this command will append imported bookmarks to the browser's bookmarks.\n"
- "If an output location is specified, this command will load all XBEL-format bookmarks, then all JSON-format bookmarks, and write them to the output location.");
- parser.Prog(progname);
-
- args::HelpFlag help(parser, "help", "Display this help message and exit.", { 'h', "help" });
- args::ValueFlag<std::string> save(parser, "file, stdout", "Output location.", { 'e', "export" });
- args::ValueFlagList<std::string> import_xbel(parser, "bookmarks.xbel", "Import xbel format.", { 'x', "import-xbel" });
- args::ValueFlagList<std::string> import_json(parser, "bookmarks.json", "Import json format.", { 'j', "import-json" });
-
- try {
- parser.ParseArgs(beginargs, endargs);
- } catch(args::Help &) {
- std::cout << parser;
- return 0;
- } catch(args::Error &e) {
- std::cerr << e.what() << std::endl;
- std::cerr << parser;
- return -1;
- }
-
- auto *model = new BookmarkModel;
-
- // implicit bookmarks.path import
- if(!save) {
- Configuration conf;
- QFile f(conf.value<QString>("bookmarks.path").value());
- if(f.open(QIODevice::ReadOnly | QIODevice::Text)) {
- BookmarkFormat<XbelFormat>(&f) >> model;
- f.close();
- }
- }
-
- for(const auto &i : args::get(import_xbel)) {
- QFile f(QString::fromStdString(i));
- if(f.open(QIODevice::ReadOnly | QIODevice::Text)) {
- BookmarkFormat<XbelFormat>(&f) >> model;
- f.close();
- } else {
- spdlog::error("Could not open %s", i);
- return -1;
- }
- }
-
- for(const auto &i : args::get(import_json)) {
- QFile f(QString::fromStdString(i));
- if(f.open(QIODevice::ReadOnly | QIODevice::Text)) {
- BookmarkFormat<FirefoxJsonFormat>(&f) >> model;
- f.close();
- } else {
- spdlog::error("Could not open %s", i);
- return -1;
- }
- }
-
- QIODevice *output = nullptr;
- if(save && args::get(save) == "stdout") {
- output = new QBuffer;
- QObject::connect(output, &QIODevice::aboutToClose, [output]() {
- output->seek(0);
- std::cout << qUtf8Printable(output->readAll()) << std::endl;
- });
-
- output->open(QIODevice::ReadWrite | QIODevice::Text);
-
- } else if(!save) {
- Configuration conf;
- output = new QFile(conf.value<QString>("bookmarks.path").value());
- } else {
- output = new QFile(QString::fromStdString(args::get(save)));
- }
-
- if(!output->isOpen()) {
- if(!output->open(QIODevice::ReadWrite | QIODevice::Text)) {
- spdlog::error("Could not open output");
- return -1;
- }
- }
-
- BookmarkFormat<XbelFormat> format(output);
- format << model;
- output->close();
-
- delete output;
-
- return 0;
-}
diff --git a/src/browser.cpp b/src/browser.cpp
index ff948e4..232af59 100644
--- a/src/browser.cpp
+++ b/src/browser.cpp
@@ -1,34 +1,28 @@
/*
* 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
+ * location: https://neueland.iserlohn-fortress.net/cgit/smolbote
*
* SPDX-License-Identifier: GPL-3.0
*/
#include "browser.h"
-#include "aboutdialog.h"
-#include "aboutplugin.h"
#include "applicationmenu.h"
+#include "applicationstyle.h"
#include "bookmarks/bookmarkswidget.h"
#include "configuration.h"
#include "downloadswidget.h"
#include "mainwindow/addressbar.h"
#include "mainwindow/mainwindow.h"
#include "mainwindow/menubar.h"
-#include "smolbote/plugininterface.hpp"
-#include "subwindow/subwindow.h"
+#include "session_json.hpp"
+#include "settings.h"
#include "util.h"
-#include "webengine/urlinterceptor.h"
-#include "webengine/webprofile.h"
-#include "webengine/webprofilemanager.h"
-#include "webengine/webview.h"
-#include <QAction>
+#include "webprofile.h"
#include <QLibraryInfo>
#include <QPluginLoader>
#include <QTimer>
#include <QTranslator>
-#include <QVersionNumber>
#include <pluginloader.h>
#include <spdlog/spdlog.h>
#include <version.h>
@@ -36,13 +30,31 @@
Browser::Browser(int &argc, char *argv[], bool allowSecondary)
: SingleApplication(argc, argv, allowSecondary, SingleApplication::User | SingleApplication::SecondaryNotification | SingleApplication::ExcludeAppVersion)
{
- Configuration conf;
+ QApplication::setStyle(new ApplicationStyle);
+ setApplicationName(POI_NAME);
+ setWindowIcon(ApplicationStyle::windowIcon());
+ setApplicationVersion(POI_SHORT_VERSION);
+}
+
+Browser::~Browser()
+{
+ if(m_bookmarks)
+ m_bookmarks->save();
- setApplicationName(conf.value<QString>("poi.name").value());
- setWindowIcon(QIcon(conf.value<QString>("poi.icon").value()));
- setApplicationVersion(QVersionNumber::fromString(QLatin1String(poi_Version)).toString());
+ for(auto *info : qAsConst(m_plugins))
+ delete info;
- if(const auto _translation = conf.value<QString>("browser.translation")) {
+ qDeleteAll(m_windows);
+ m_windows.clear();
+}
+
+void Browser::loadConfiguration(const QString &path)
+{
+ auto ctx = init_conf(path.toStdString());
+ spdlog::info("Using configuration [{}]: {}", (ctx.path ? ctx.path->c_str() : "none"), ctx.ptr->make_global() ? "okay" : "failed");
+ m_conf = std::move(ctx.ptr);
+
+ if(const auto _translation = m_conf->value<QString>("browser.translation")) {
auto *translator = new QTranslator(this);
if(translator->load(_translation.value()))
installTranslator(translator);
@@ -50,7 +62,7 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
delete translator;
}
- if(const auto _locale = conf.value<QString>("browser.locale")) {
+ if(const auto _locale = m_conf->value<QString>("browser.locale")) {
auto *locale = new QTranslator(this);
if(locale->load("qt_" + _locale.value(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
installTranslator(locale);
@@ -58,11 +70,11 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
delete locale;
}
- if(auto iconTheme = conf.value<QString>("browser.iconTheme")) {
+ if(auto iconTheme = m_conf->value<QString>("browser.iconTheme")) {
QIcon::setThemeName(iconTheme.value());
}
- if(auto stylesheet = conf.value<QString>("browser.stylesheet")) {
+ if(auto stylesheet = m_conf->value<QString>("browser.stylesheet")) {
QFile f(stylesheet.value());
if(f.open(QIODevice::ReadOnly)) {
setStyleSheet(f.readAll());
@@ -70,13 +82,21 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
}
}
+ // content filter - register format plugins
+ if(const auto hostlist_plugin = m_conf->value<QString>("smolblok.plugins.hostlist")) {
+ content_filter.registerFormatPlugin("hostlist", hostlist_plugin.value());
+ }
+ if(const auto adblock_plugin = m_conf->value<QString>("smolblok.plugins.adblock")) {
+ content_filter.registerFormatPlugin("adblock", adblock_plugin.value());
+ }
+
// load profiles
{
- const auto profiles = Util::files(conf.value<QString>("profile.path").value(), { "*.profile" });
- const auto search = conf.value<QString>("profile.search").value();
- const auto homepage = QUrl::fromUserInput(conf.value<QString>("profile.homepage").value());
- const auto newtab = QUrl::fromUserInput(conf.value<QString>("profile.newtab").value());
- const auto default_id = conf.value<QString>("profile.default").value();
+ const auto profiles = Util::files(m_conf->value<QString>("profile.path").value(), { "*.profile" });
+ const auto search = m_conf->value<QString>("profile.search").value();
+ const auto homepage = QUrl::fromUserInput(m_conf->value<QString>("profile.homepage").value());
+ const auto newtab = QUrl::fromUserInput(m_conf->value<QString>("profile.newtab").value());
+ const auto default_id = m_conf->value<QString>("profile.default").value();
m_profileManager = std::make_unique<WebProfileManager<false>>(profiles, default_id, search, homepage, newtab);
m_profileManager->make_global();
@@ -90,13 +110,14 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
}
// downloads
- m_downloads = std::make_unique<DownloadsWidget>(conf.value<QString>("downloads.path").value());
+ m_downloads = std::make_unique<DownloadsWidget>(m_conf->value<QString>("downloads.path").value());
m_profileManager->walk([this](const QString &, WebProfile *profile, QSettings *) {
+ profile->setUrlRequestInterceptor(content_filter.interceptor());
connect(profile, &QWebEngineProfile::downloadRequested, m_downloads.get(), &DownloadsWidget::addDownload);
});
// bookmarks
- m_bookmarks = std::make_shared<BookmarksWidget>(QString::fromStdString(conf.value<std::string>("bookmarks.path").value()));
+ m_bookmarks = std::make_shared<BookmarksWidget>(m_conf->value<QString>("bookmarks.path").value());
connect(m_bookmarks.get(), &BookmarksWidget::openUrl, this, [this](const QUrl &url) {
m_windows.last()->createTab(url);
});
@@ -106,33 +127,6 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
timer->start(5 * 60 * 1000); // 5min * 60sec * 1000ms
}
-Browser::~Browser()
-{
- if(m_bookmarks)
- m_bookmarks->save();
-
- for(auto *info : qAsConst(m_plugins))
- delete info;
-
- qDeleteAll(m_windows);
- m_windows.clear();
-}
-
-void Browser::about()
-{
- auto *dlg = new AboutDialog;
- dlg->exec();
-}
-
-void Browser::aboutPlugins()
-{
- auto *dlg = new AboutPluginDialog;
- for(auto *info : qAsConst(m_plugins)) {
- dlg->add(info->loader);
- }
- dlg->exec();
-}
-
bool Browser::loadPlugin(const QString &path)
{
if(path.isEmpty()) {
@@ -159,6 +153,22 @@ bool Browser::loadPlugin(const QString &path)
return true;
}
+void Browser::enableRemote(bool toggle)
+{
+ if(static_cast<bool>(remoteConnection) == toggle)
+ return;
+
+ if(!toggle) {
+ disconnect(remoteConnection);
+ return;
+ }
+
+ remoteConnection = connect(this, &Browser::receivedMessage, this, [this](quint32, const QByteArray &message) {
+ JsonSession s(message);
+ this->open(s.get());
+ });
+}
+
void Browser::showWidget(QWidget *widget, MainWindow *where) const
{
bool wasVisible = widget->isVisible();
diff --git a/src/browser.h b/src/browser.h
index 0a0b201..6a92d8b 100644
--- a/src/browser.h
+++ b/src/browser.h
@@ -1,7 +1,7 @@
/*
* 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
+ * location: https://neueland.iserlohn-fortress.net/cgit/smolbote
*
* SPDX-License-Identifier: GPL-3.0
*/
@@ -9,8 +9,9 @@
#ifndef SMOLBOTE_BROWSER_H
#define SMOLBOTE_BROWSER_H
-#include "webengine/webprofilemanager.h"
+#include "smolblok.hpp"
#include "smolbote/session.hpp"
+#include "webprofilemanager.h"
#include <QJsonObject>
#include <QMenu>
#include <QPluginLoader>
@@ -23,9 +24,11 @@ class Configuration;
class BookmarksWidget;
class DownloadsWidget;
class MainWindow;
+class ApplicationMenu;
class Browser final : public SingleApplication
{
Q_OBJECT
+ friend class ApplicationMenu;
public:
explicit Browser(int &argc, char *argv[], bool allowSecondary = true);
@@ -36,26 +39,29 @@ public:
return qAsConst(m_windows);
}
- BookmarksWidget *bookmarks() const
+ [[deprecated]] BookmarksWidget *bookmarks() const
{
return m_bookmarks.get();
}
- DownloadsWidget *downloads() const
+ [[deprecated]] DownloadsWidget *downloads() const
{
return m_downloads.get();
}
+ bool remoteEnabled() const
+ {
+ return static_cast<bool>(remoteConnection);
+ }
signals:
void pluginAdded(QPluginLoader *);
public slots:
- void about();
- void aboutPlugins();
-
- void showWidget(QWidget *widget, MainWindow *where) const;
+ [[deprecated]] void showWidget(QWidget *widget, MainWindow *where) const;
void open(const QVector<Session::MainWindow> &data, bool merge = true);
+ void loadConfiguration(const QString &path);
bool loadPlugin(const QString &path);
+ void enableRemote(bool toggle);
private:
struct PluginInfo {
@@ -76,9 +82,12 @@ private:
Q_DISABLE_COPY(Browser)
+ QMetaObject::Connection remoteConnection;
+ std::unique_ptr<Configuration> m_conf;
std::shared_ptr<BookmarksWidget> m_bookmarks;
std::unique_ptr<DownloadsWidget> m_downloads;
std::unique_ptr<WebProfileManager<false>> m_profileManager{ nullptr };
+ smolblok content_filter;
QVector<MainWindow *> m_windows;
QVector<PluginInfo *> m_plugins;
diff --git a/src/builtins.cpp b/src/builtins.cpp
deleted file mode 100644
index ab5942c..0000000
--- a/src/builtins.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 "builtins.h"
-#include "configuration.h"
-#include "version.h"
-#include <QObject>
-#include <QVersionNumber>
-#include <iostream>
-
-int builtins::version()
-{
- const auto version = QVersionNumber::fromString(QLatin1String(poi_Version)).toString().toStdString();
- std::cout << "smolbote " << version << std::endl;
- return 0;
-}
-
-int builtins::build()
-{
- std::cout << poi_Version << std::endl;
- return 0;
-}
-
-int builtins::configuration(const std::string &progname, std::vector<std::string>::const_iterator beginargs, std::vector<std::string>::const_iterator endargs)
-{
- args::ArgumentParser parser("configuration");
- parser.Prog(progname);
-
- args::HelpFlag help(parser, "help", "Display this help message and exit.", { 'h', "help" });
- args::Flag dump(parser, "dump", "Dump currently used configuration and exit", { "dump" });
-
- try {
- parser.ParseArgs(beginargs, endargs);
- } catch(args::Help &e) {
- std::cout << parser;
- return 0;
- } catch(args::Error &e) {
- std::cerr << e.what() << std::endl;
- std::cerr << parser;
- return -1;
- }
-
- if(dump) {
- Configuration conf;
- std::cout << conf << std::endl;
- return 0;
- }
-
- return 0;
-}
diff --git a/src/builtins.h b/src/builtins.h
deleted file mode 100644
index 9fdca98..0000000
--- a/src/builtins.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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_BUILTINS_H
-#define SMOLBOTE_BUILTINS_H
-
-#include "smolbote/plugininterface.hpp"
-#include <args.hxx>
-
-typedef std::function<int(const std::string &, std::vector<std::string>::const_iterator, std::vector<std::string>::const_iterator)> subcommand_func;
-typedef std::unordered_map<std::string, subcommand_func> command_map;
-
-namespace builtins
-{
-int version();
-int build();
-
-int configuration(const std::string &progname, std::vector<std::string>::const_iterator beginargs, std::vector<std::string>::const_iterator endargs);
-
-int bookmarks(const std::string &progname, std::vector<std::string>::const_iterator beginargs, std::vector<std::string>::const_iterator endargs);
-}
-
-#endif
diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt
new file mode 100644
index 0000000..31563c9
--- /dev/null
+++ b/src/cmd/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(cmd_test test.cpp)
+target_link_libraries(cmd_test PRIVATE autogen Qt5::Core)
+target_sanitize(cmd_test)
+
+add_test(NAME cmd_parser COMMAND cmd_test) \ No newline at end of file
diff --git a/src/cmd/cmd.hpp b/src/cmd/cmd.hpp
new file mode 100644
index 0000000..1aad060
--- /dev/null
+++ b/src/cmd/cmd.hpp
@@ -0,0 +1,89 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#ifndef SMOLBOTE_CMD_HPP
+#define SMOLBOTE_CMD_HPP
+
+#include "version.h"
+#include <QCommandLineParser>
+#include <QCoreApplication>
+#include <functional>
+#include <iostream>
+
+namespace command_line
+{
+template <typename T>
+using subcommand_fn = std::function<int(const QStringList &, T &)>;
+template <typename T>
+using map = std::unordered_map<std::string, subcommand_fn<T>>;
+
+// a helper function to join the keys of a command_map into a string
+template <typename T>
+[[nodiscard]] inline QString join_keys(const map<T> &map, const QString &sep = ", ")
+{
+ QString k;
+ for(auto it = map.cbegin(); it != map.cend(); ++it) {
+ k += QString::fromStdString(it->first);
+ if(std::next(it) != map.cend()) {
+ k += sep;
+ }
+ }
+ return k;
+}
+
+template <typename T>
+[[nodiscard]] std::function<int(T &)> process(T &app, const map<T> &map, const std::string &d)
+{
+ const QCommandLineOption build({ "b", "build" }, "Display build information.");
+ const QCommandLineOption config({ "c", "config" }, "Set the configuration file.", "file");
+ const QCommandLineOption noRemote("no-remote", "Do not accept or send remote commands.");
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("smolbote: yet another no-frills browser");
+ parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ parser.addOption(build);
+ parser.addOption(config);
+ parser.addOption(noRemote);
+
+ parser.addPositionalArgument("subcommand", QString("%1; default: %2").arg(join_keys(map), QString::fromStdString(d)));
+ parser.addPositionalArgument("urls", "List of URLs to open.");
+
+ parser.process(app);
+
+ if(parser.isSet(build)) {
+ std::cout << app.applicationName().toStdString() << " " << POI_VERSION << std::endl;
+ exit(0);
+ }
+
+ if constexpr(requires { app.loadConfiguration(parser.value(config)); }) {
+ app.loadConfiguration(parser.value(config));
+ } else {
+ qDebug("warning: cannot init configuration");
+ }
+
+ if constexpr(requires { app.enableRemote(true); }) {
+ app.enableRemote(!parser.isSet(noRemote));
+ }
+
+ const auto args = parser.positionalArguments();
+
+ if(args.count() >= 1) {
+ auto i = map.find(args.first().toStdString());
+ if(i != map.end())
+ return std::bind(i->second, args, std::placeholders::_1);
+ }
+
+ return std::bind(map.at(d), args, std::placeholders::_1);
+}
+
+} // namespace
+
+#endif
diff --git a/src/cmd/test.cpp b/src/cmd/test.cpp
new file mode 100644
index 0000000..fc102ff
--- /dev/null
+++ b/src/cmd/test.cpp
@@ -0,0 +1,41 @@
+#include "cmd.hpp"
+#include <QCoreApplication>
+
+int sub_bookmarks(const QStringList &l, QCoreApplication &)
+{
+ const QCommandLineOption q("q", "something");
+ QCommandLineParser parser;
+ parser.setApplicationDescription("testing bookmarks editor");
+ parser.addHelpOption();
+ parser.addOption(q);
+
+ if(l.count() <= 1) {
+ parser.showHelp();
+ }
+ parser.process(l);
+ return 0;
+}
+
+int sub_list(const QStringList &args, QCoreApplication &)
+{
+ for(const auto &x : args) {
+ qDebug("-%s", qUtf8Printable(x));
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ app.setApplicationName("cmd_test");
+ app.setApplicationVersion("0.1.0");
+
+ const command_line::map<QCoreApplication> m{
+ { "bookmarks", &sub_bookmarks },
+ { "list", &sub_list }
+ };
+
+ const auto f = command_line::process<QCoreApplication>(app, m, "list");
+ return f(app);
+}
+
diff --git a/src/configuration/builtin.cpp b/src/configuration/builtin.cpp
new file mode 100644
index 0000000..a6ed002
--- /dev/null
+++ b/src/configuration/builtin.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#include "browser.h"
+#include "configuration.h"
+#include <QCommandLineParser>
+#include <QCoreApplication>
+#include <cstdlib>
+#include <iostream>
+
+namespace builtins
+{
+int sub_configuration(const QStringList &l, Browser &)
+{
+ const QCommandLineOption dump({ "d", "dump" }, "Print the currently used configuration and exit.");
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("configuration");
+ parser.addHelpOption();
+ parser.addOption(dump);
+
+ if(l.count() <= 1) {
+ parser.showHelp();
+ }
+
+ parser.process(l);
+
+ if(parser.isSet(dump)) {
+ Configuration conf;
+ std::cout << conf << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ return EXIT_FAILURE;
+}
+}
diff --git a/src/crashhandler.cpp b/src/crashhandler.cpp
deleted file mode 100644
index ed9298f..0000000
--- a/src/crashhandler.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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 "crashhandler.h"
-#include "version.h"
-#include <QByteArray>
-#include <client/linux/handler/exception_handler.h>
-#include <unistd.h>
-
-// bool filter_callback (void*)
-// --> true: continue processing and write a minidump
-static bool minidumpCb(const google_breakpad::MinidumpDescriptor &descriptor, void *context, bool succeeded)
-{
- printf("Dump path: %s\n", descriptor.path());
-
- auto *ctx = static_cast<CrashHandler::Context *>(context);
- if(ctx != nullptr) {
- if(!ctx->handler.empty()) {
- // fork and run 'handler master:commit path.dmp'
- pid_t pid = fork();
- if(pid == 0) {
- // pathname program argument ... nullptr
- execlp(ctx->handler.c_str(),
- ctx->handler.c_str(), "--crashd", ctx->dumppath.c_str(), "-c", descriptor.path(), poi_Version,
- (char *)nullptr);
- }
- }
- }
-
- return succeeded;
-}
-
-bool CrashHandler::install_handler(CrashHandler::Context &ctx)
-{
- if(ctx.dumppath.empty())
- return false;
-
- // Disable Chromium's crash handler so breakpad can capture crashes instead.
- // This has to be done before QtWebEngine gets initialized.
- const auto chromiumFlags = qgetenv("QTWEBENGINE_CHROMIUM_FLAGS");
- if(!chromiumFlags.contains("disable-in-process-stack-traces")) {
- qputenv("QTWEBENGINE_CHROMIUM_FLAGS", chromiumFlags + " --disable-in-process-stack-traces");
- }
-
- google_breakpad::MinidumpDescriptor descriptor(ctx.dumppath.c_str());
-
- // minidump descriptor, filter callback, minidump callback, callback_context, install handler, server_fd
- new google_breakpad::ExceptionHandler(descriptor, nullptr, minidumpCb, &ctx, true, -1);
-
- return true;
-}
diff --git a/src/crashhandler.h b/src/crashhandler.h
deleted file mode 100644
index 73b1768..0000000
--- a/src/crashhandler.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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_CRASHHANDLER_H
-#define SMOLBOTE_CRASHHANDLER_H
-
-#include <string>
-
-namespace CrashHandler
-{
-struct Context {
- const std::string dumppath;
- const std::string handler;
-
- explicit Context(const std::string &path, const std::string &crashhandler)
- : dumppath(path)
- , handler(crashhandler)
- {
- }
-};
-
-bool install_handler(Context &ctx);
-}
-
-#endif // SMOLBOTE_CRASHHANDLER_H
diff --git a/src/crashhandler_dummy.cpp b/src/crashhandler_dummy.cpp
deleted file mode 100644
index e230c82..0000000
--- a/src/crashhandler_dummy.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * 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 "crashhandler.h"
-
-
-bool CrashHandler::install_handler(CrashHandler::Context &)
-{
- return false;
-}
-
diff --git a/src/main.cpp b/src/main.cpp
index dad1f73..65c8c26 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,178 +1,60 @@
/*
* 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
+ * location: https://neueland.iserlohn-fortress.net/cgit/smolbote
*
* SPDX-License-Identifier: GPL-3.0
*/
#include "browser.h"
-#include "builtins.h"
+#include "cmd/cmd.hpp"
#include "configuration.h"
-#include "crashhandler.h"
-#include "session/sessiondialog.h"
-#include "session_json.hpp"
-#include "settings.h"
#include "util.h"
-#include "version.h"
-#include <QFile>
-#include <QPluginLoader>
#include <QStandardPaths>
-#include <iostream>
-#include <memory>
-#include <pluginloader.h>
#include <spdlog/spdlog.h>
-// a helper function to join the keys of a command_map into a string
-inline std::string join_keys(const command_map &map, const std::string sep = ", ")
+namespace builtins
{
- std::vector<std::string> keys(map.size());
- std::transform(map.begin(), map.end(), keys.begin(), [](auto pair) { return pair.first; });
- std::sort(keys.begin(), keys.end());
-
- std::string k;
- std::for_each(keys.begin(), keys.end() - 1, [&k, &sep](const std::string &piece) { k += piece + sep; });
- k += keys.back();
-
- return k;
+int sub_configuration(const QStringList &l, Browser &);
+int sub_bookmarks(const QStringList &l, Browser &);
+int sub_session(const QStringList &l, Browser &);
}
int main(int argc, char **argv)
{
- // change log pattern
- spdlog::set_pattern("[%^%l%$] [%P:%t] %v");
+ // spdlog pattern
+ if(const char *env_spdlog = std::getenv("POI_LOG_PATTERN")) {
+ spdlog::set_pattern(env_spdlog);
+ } else {
+ spdlog::set_pattern("[%^%l%$] [%P:%t] %v");
+ }
+
#ifdef QT_DEBUG
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
#endif
- const command_map commands{
- { "configuration", builtins::configuration },
- { "bookmarks", builtins::bookmarks },
+ const command_line::map<Browser> subcommands{
+ { "configuration", builtins::sub_configuration },
+ { "bookmarks", builtins::sub_bookmarks },
+ { "session", builtins::sub_session },
};
- const std::vector<std::string> args(argv + 1, argv + argc);
- args::ArgumentParser parser("smolbote: yet another no-frills browser", "Subcommands: " + join_keys(commands));
- parser.Prog(argv[0]);
-
- args::HelpFlag cmd_help(parser, "help", "Display this help message.", { 'h', "help" });
- args::Flag cmd_version(parser, "version", "Display version information.", { 'v', "version" });
- args::Flag cmd_build(parser, "build", "Display build commit.", { 'b', "build" });
-
- args::ValueFlag<std::string> cmd_config(parser, "config", "Set the configuration file.", { 'c', "config" });
-
- args::Flag cmd_noRemote(parser, "no-remote", "Do not accept or send remote commands.", { "no-remote" });
-
- args::Flag cmd_pickSession(parser, "pick-session", "Show all available sessions and select which one to open", { "pick-session" });
- args::ValueFlag<std::string> cmd_session(parser, "session", "Open the specified session.", { 's', "session" });
-
- args::PositionalList<std::string> cmd_args(parser, "URL(s)", "List of URLs to open");
- cmd_args.KickOut(true);
-
- try {
- auto next = parser.ParseArgs(args);
-
- if(cmd_version)
- return builtins::version();
- if(cmd_build)
- return builtins::build();
-
- // create and load configuration
- spdlog::debug("Loading configuration {}", init_conf(args::get(cmd_config)));
-
- if(cmd_args) {
- const auto front = args::get(cmd_args).front();
- const auto cmd = commands.find(front);
- if(cmd != commands.end()) {
- return cmd->second(argv[0], next, std::end(args));
- }
- }
-
- } catch(args::Help &) {
- std::cout << parser;
- return 0;
-
- } catch(args::Error &e) {
- std::cerr << e.what() << std::endl;
- std::cerr << parser;
- return -1;
- }
-
// argc, argv, allowSecondary
Browser app(argc, argv);
// set this, otherwise the webview becomes black when using a stylesheet
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
- {
- Configuration conf;
-
- if(conf.value<bool>("usebreakpad").value()) {
- CrashHandler::Context ctx(
- conf.value<std::string>("path.crashdump").value(),
- conf.value<std::string>("path.crashhandler").value());
-
- if(CrashHandler::install_handler(ctx)) {
- spdlog::info("Installed breakpad crash handler: {}", ctx.dumppath);
- } else {
- spdlog::warn("Failed to install breakpad crash handler: {}", ctx.dumppath);
- }
- }
+ const auto f = command_line::process<Browser>(app, subcommands, "session");
+ {
// load plugins
- for(const QString &path : Util::files(conf.value<QString>("plugins.path").value(), { "*.so", "*.dll" })) {
- if(app.loadPlugin(path)) {
- spdlog::debug("Loaded plugin [{}]", qUtf8Printable(path));
- } else {
- spdlog::warn("Failed loading plugin [{}]", qUtf8Printable(path));
- }
+ Configuration conf;
+ const auto plugins_path = conf.value<QString>("plugins.path").value();
+ for(const QString &path : Util::files(plugins_path, { "*.so", "*.dll" })) {
+ app.loadPlugin(path) ? spdlog::debug("Loaded plugin [{}]", qUtf8Printable(path)) : spdlog::warn("Failed loading plugin [{}]", qUtf8Printable(path));
}
}
- const auto profile = []() {
- Configuration c;
- return c.value<QString>("profile.default").value();
- }();
-
- QStringList urls;
- for(const auto &u : args::get(cmd_args)) {
- urls.append(QString::fromStdString(u));
- }
- if(urls.isEmpty()) {
- urls.append(QString());
- }
-
- // if app is primary, create new sessions from received messages
- if(app.isPrimary() && !cmd_noRemote) {
- QObject::connect(&app, &Browser::receivedMessage, &app, [&app](quint32 instanceId, QByteArray message) {
- Q_UNUSED(instanceId);
- JsonSession session(message);
- app.open(session.get());
- });
- }
-
- {
- const auto session = [&]() {
- if(cmd_session) {
- QFile sessionJson(QString::fromStdString(args::get(cmd_session)));
- if(sessionJson.open(QIODevice::ReadOnly | QIODevice::Text)) {
- return JsonSession(sessionJson.readAll());
- }
- }
- if(cmd_pickSession) {
- SessionDialog dlg;
- if(const auto pick = dlg.pickSession()) {
- return JsonSession(pick.value());
- }
- }
- return JsonSession(profile, urls);
- }();
-
- if(app.isPrimary() || cmd_noRemote) {
- app.open(session.get());
- } else {
- // app is secondary and not standalone
- return app.sendMessage(session.serialize());
- }
- }
+ return f(app);
- return app.exec();
}
diff --git a/src/mainwindow/addressbar.cpp b/src/mainwindow/addressbar.cpp
index d37a6a7..6b2cfd8 100644
--- a/src/mainwindow/addressbar.cpp
+++ b/src/mainwindow/addressbar.cpp
@@ -7,10 +7,10 @@
*/
#include "addressbar.h"
+#include "configuration.h"
#include "ui_addressbar.h"
+#include "webview.h"
#include <QShortcut>
-#include "configuration.h"
-#include "webengine/webview.h"
AddressBar::AddressBar(QWidget *parent)
: QWidget(parent)
diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp
index 64c149c..0d4a978 100644
--- a/src/mainwindow/mainwindow.cpp
+++ b/src/mainwindow/mainwindow.cpp
@@ -13,9 +13,9 @@
#include "browser.h"
#include "configuration.h"
#include "menubar.h"
-#include "webengine/webprofile.h"
-#include "webengine/webprofilemanager.h"
-#include "webengine/webview.h"
+#include "webprofile.h"
+#include "webprofilemanager.h"
+#include "webview.h"
#include "widgets/dockwidget.h"
#include "widgets/navigationbar.h"
#include "widgets/searchform.h"
diff --git a/src/mainwindow/menubar.cpp b/src/mainwindow/menubar.cpp
index 5fc039a..80cb3ea 100644
--- a/src/mainwindow/menubar.cpp
+++ b/src/mainwindow/menubar.cpp
@@ -13,8 +13,8 @@
#include "downloadswidget.h"
#include "mainwindow.h"
#include "subwindow/subwindow.h"
-#include "webengine/webprofilemanager.h"
-#include "webengine/webview.h"
+#include "webprofilemanager.h"
+#include "webview.h"
#include "widgets/menusearch.h"
#include <QDir>
#include <QFileDialog>
diff --git a/src/mainwindow/widgets/navigationbar.cpp b/src/mainwindow/widgets/navigationbar.cpp
index 799ebec..f76d348 100644
--- a/src/mainwindow/widgets/navigationbar.cpp
+++ b/src/mainwindow/widgets/navigationbar.cpp
@@ -10,8 +10,8 @@
#include "configuration.h"
#include "urllineedit.h"
#include "util.h"
-#include "webengine/webprofile.h"
-#include "webengine/webview.h"
+#include "webprofile.h"
+#include "webview.h"
#include <QHBoxLayout>
#include <QMenu>
#include <QShortcut>
@@ -28,7 +28,7 @@ NavigationBar::NavigationBar(QWidget *parent)
Configuration config;
// Back button
- backAction = addAction(Util::icon(QStyle::SP_ArrowBack), tr("Back"));
+ backAction = addAction(style()->standardIcon(QStyle::SP_ArrowBack), tr("Back"));
config.shortcut<QAction>(*backAction, "shortcuts.navigation.back");
connect(backAction, &QAction::triggered, this, [this]() {
m_view->history()->back();
@@ -56,7 +56,7 @@ NavigationBar::NavigationBar(QWidget *parent)
});
// Forward button
- forwardAction = addAction(Util::icon(QStyle::SP_ArrowForward), tr("Forward"));
+ forwardAction = addAction(style()->standardIcon(QStyle::SP_ArrowForward), tr("Forward"));
config.shortcut<QAction>(*forwardAction, "shortcuts.navigation.forward");
connect(forwardAction, &QAction::triggered, this, [this]() {
m_view->history()->forward();
@@ -84,7 +84,7 @@ NavigationBar::NavigationBar(QWidget *parent)
});
// Stop/Refresh button
- stopReloadAction = addAction(Util::icon(QStyle::SP_BrowserReload), tr("Refresh"));
+ stopReloadAction = addAction(style()->standardIcon(QStyle::SP_BrowserReload), tr("Refresh"));
config.shortcut<QAction>(*stopReloadAction, "shortcuts.navigation.refresh");
connect(stopReloadAction, &QAction::triggered, this, [this]() {
if(m_view->isLoaded())
@@ -99,7 +99,7 @@ NavigationBar::NavigationBar(QWidget *parent)
});
// Home button
- homeAction = addAction(Util::icon(QStyle::SP_DirHomeIcon), tr("Home"));
+ homeAction = addAction(style()->standardIcon(QStyle::SP_DirHomeIcon), tr("Home"));
config.shortcut<QAction>(*homeAction, "shortcuts.navigation.home");
connect(homeAction, &QAction::triggered, this, [this]() {
m_view->load(m_view->profile()->homepage());
@@ -138,12 +138,12 @@ void NavigationBar::update_loadStarted()
{
backAction->setEnabled(m_view->history()->canGoForward());
forwardAction->setEnabled(m_view->history()->canGoForward());
- stopReloadAction->setIcon(Util::icon(QStyle::SP_BrowserStop));
+ stopReloadAction->setIcon(style()->standardIcon(QStyle::SP_BrowserStop));
}
void NavigationBar::update_loadFinished()
{
backAction->setEnabled(m_view->history()->canGoBack());
forwardAction->setEnabled(m_view->history()->canGoForward());
- stopReloadAction->setIcon(Util::icon(QStyle::SP_BrowserReload));
+ stopReloadAction->setIcon(style()->standardIcon(QStyle::SP_BrowserReload));
}
diff --git a/src/meson.build b/src/meson.build
deleted file mode 100644
index 6a4abd8..0000000
--- a/src/meson.build
+++ /dev/null
@@ -1,60 +0,0 @@
-python = import('python')
-python3 = python.find_installation('python3')
-
-poi_settings_h = custom_target('default_config_value',
- input: files('../scripts/gen-default-cfg.py', '../Kconfig', '..'/host_machine.system()/'.config', 'settings.h.in'),
- output: 'settings.h',
- command: [ python3, '@INPUT0@', '--kconfig=@INPUT1@', '--dotconfig=@INPUT2@', '--input=@INPUT3@', '--output=@OUTPUT@' ]
-)
-
-subdir('about')
-subdir('webengine')
-
-poi_sourceset.add(mod_qt5.preprocess(
- moc_headers: ['browser.h', 'applicationmenu.h',
- 'mainwindow/mainwindow.h', 'mainwindow/addressbar.h', 'mainwindow/menubar.h', 'mainwindow/widgets/completer.h', 'mainwindow/widgets/urllineedit.h', 'mainwindow/widgets/dockwidget.h', 'mainwindow/widgets/navigationbar.h', 'mainwindow/widgets/searchform.h',
- 'bookmarks/bookmarkswidget.h', 'bookmarks/editbookmarkdialog.h',
- 'session/savesessiondialog.h', 'session/sessiondialog.h',
- 'subwindow/subwindow.h', 'subwindow/tabwidget.h' ],
- ui_files: [
- 'mainwindow/addressbar.ui', 'mainwindow/widgets/searchform.ui',
- 'bookmarks/bookmarksform.ui', 'bookmarks/editbookmarkdialog.ui',
- 'session/savesessiondialog.ui', 'session/sessiondialog.ui' ],
- qresources: '../data/resources.qrc',
- rcc_extra_arguments: ['--format-version=1'],
- dependencies: dep_qt5
-))
-
-poi_sourceset.add(files(
- 'main.cpp', 'builtins.cpp',
- 'browser.cpp', 'applicationmenu.cpp',
- 'util.cpp', 'util.h',
-
- 'mainwindow/mainwindow.cpp',
- 'mainwindow/addressbar.cpp',
- 'mainwindow/menubar.cpp',
- 'mainwindow/widgets/completer.cpp',
- 'mainwindow/widgets/urllineedit.cpp',
- 'mainwindow/widgets/dockwidget.cpp',
- 'mainwindow/widgets/menusearch.cpp',
- 'mainwindow/widgets/navigationbar.cpp',
- 'mainwindow/widgets/searchform.cpp',
-
- 'bookmarks/builtins.cpp', 'bookmarks/bookmarkswidget.cpp', 'bookmarks/editbookmarkdialog.cpp', 'bookmarks/bookmarkstoolbar.cpp',
-
- 'session/savesessiondialog.cpp',
- 'session/sessiondialog.cpp',
-
- 'subwindow/subwindow.cpp',
- 'subwindow/tabwidget.cpp',
-
- 'wallet/wallet.cpp', 'wallet/wallet.h'
-),
- version_h, poi_settings_h
-)
-
-poi_sourceset.add(when: [dep_breakpad, dep_threads],
- if_true: files('crashhandler.cpp'),
- if_false: files('crashhandler_dummy.cpp')
-)
-
diff --git a/src/session/builtin.cpp b/src/session/builtin.cpp
new file mode 100644
index 0000000..0359b42
--- /dev/null
+++ b/src/session/builtin.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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/cgit/smolbote
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#include "browser.h"
+#include "configuration.h"
+#include "session/sessiondialog.h"
+#include "session_json.hpp"
+#include <QCommandLineParser>
+#include <variant>
+
+namespace builtins
+{
+int sub_session(const QStringList &args, Browser &app)
+{
+ const auto default_profile = []() {
+ Configuration conf;
+ return conf.value<QString>("profile.default").value();
+ }();
+
+ const auto session = args.count() == 0 ? JsonSession(default_profile, args) : [&]() {
+ const QCommandLineOption profile({ "p", "profile" }, "Create session with specified profile.", "profile-id", default_profile);
+ const QCommandLineOption pick("pick", "Show all available sessions and select which one to open.");
+ const QCommandLineOption open({ "o", "open" }, "Open the specified session.", "file");
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("session");
+ parser.addHelpOption();
+ parser.addOptions({ pick, open, profile });
+
+ parser.process(args);
+
+ if(parser.isSet(pick)) {
+ SessionDialog dlg;
+ if(const auto s = dlg.pickSession()) {
+ return JsonSession(s.value());
+ }
+
+ } else if(parser.isSet(open)) {
+ QFile sessionJson(parser.value(open));
+ if(sessionJson.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ return JsonSession(sessionJson.readAll());
+ }
+ }
+
+ return JsonSession(parser.isSet(profile) ? parser.value(profile) : default_profile, args);
+ }();
+
+ if(app.isPrimary() || !app.remoteEnabled()) {
+ app.open(session.get());
+ return app.exec();
+ }
+
+ app.sendMessage(session.serialize());
+ return 0;
+}
+}
diff --git a/src/session/savesessiondialog.cpp b/src/session/savesessiondialog.cpp
index e22ce3a..3bc4150 100644
--- a/src/session/savesessiondialog.cpp
+++ b/src/session/savesessiondialog.cpp
@@ -12,8 +12,8 @@
#include "session_json.hpp"
#include "subwindow/subwindow.h"
#include "ui_savesessiondialog.h"
-#include "webengine/webprofile.h"
-#include "webengine/webview.h"
+#include "webprofile.h"
+#include "webview.h"
#include <QFileDialog>
#include <QPointer>
#include <QTreeWidgetItem>
diff --git a/src/session/sessiondialog.cpp b/src/session/sessiondialog.cpp
index 36cf9cb..548f73e 100644
--- a/src/session/sessiondialog.cpp
+++ b/src/session/sessiondialog.cpp
@@ -8,7 +8,7 @@
#include "sessiondialog.h"
#include "../browser.h"
-#include "../util.h"
+#include "util.h"
#include "configuration.h"
#include "session_json.hpp"
#include "ui_sessiondialog.h"
diff --git a/src/settings.h.in b/src/settings.h.in
deleted file mode 100644
index 88fbcf5..0000000
--- a/src/settings.h.in
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include <QStandardPaths>
-#include <configuration.h>
-#include <fstream>
-
-inline const std::string init_conf(const std::string &path)
-{
- auto value_map = std::make_unique<Configuration, std::initializer_list<std::pair<std::string, conf_value_t>>>({
- @__DEFAULT_CFG__
- });
-
- const std::string cfgpath = [&]() {
- if(path.empty())
- return value_map->value<std::string>("poi.cfg.path").value();
-
- auto p = path;
- if(p.front() == '~')
- p.replace(0, 1, QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString());
- return p;
- }();
-
- std::fstream fs;
- fs.open(cfgpath, std::fstream::in);
- if(fs.is_open()) {
- value_map->read(fs);
- fs.close();
- }
-
- Configuration::move_global(std::move(value_map));
- return cfgpath;
-}
diff --git a/src/subwindow/subwindow.cpp b/src/subwindow/subwindow.cpp
index a2d6138..60ea633 100644
--- a/src/subwindow/subwindow.cpp
+++ b/src/subwindow/subwindow.cpp
@@ -9,9 +9,9 @@
#include "subwindow.h"
#include "browser.h"
#include "configuration.h"
-#include "webengine/webprofile.h"
-#include "webengine/webprofilemanager.h"
-#include "webengine/webview.h"
+#include "webprofile.h"
+#include "webprofilemanager.h"
+#include "webview.h"
#include <QAction>
#include <QCloseEvent>
#include <QHideEvent>
diff --git a/src/subwindow/subwindow.h b/src/subwindow/subwindow.h
index 80e8520..a7b4564 100644
--- a/src/subwindow/subwindow.h
+++ b/src/subwindow/subwindow.h
@@ -11,7 +11,7 @@
#include "smolbote/session.hpp"
#include "tabwidget.h"
-#include "webengine/webview.h"
+#include "webview.h"
#include <QMenu>
#include <QUrl>
#include <QWidget>
@@ -29,7 +29,7 @@ public:
explicit SubWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
explicit SubWindow(const Session::SubWindow &tab_data, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
- ~SubWindow() = default;
+ ~SubWindow() override = default;
[[nodiscard]] Session::SubWindow serialize() const;
[[nodiscard]] int currentTabIndex() const
diff --git a/src/subwindow/tabwidget.cpp b/src/subwindow/tabwidget.cpp
index 69f3b8a..1e1d939 100644
--- a/src/subwindow/tabwidget.cpp
+++ b/src/subwindow/tabwidget.cpp
@@ -8,29 +8,22 @@
#include "tabwidget.h"
#include "browser.h"
-#include "webengine/webview.h"
+#include "subwindow.h"
+#include "webprofile.h"
+#include "webview.h"
#include <QAction>
#include <QContextMenuEvent>
#include <QMenu>
#include <QTabBar>
-#include "webengine/webprofile.h"
#include <QWebEngineHistory>
-#include "subwindow.h"
-inline WebView *createViewFromInfo(TabWidget::TabInformation &tab, SubWindow *parent)
-{
- auto *view = new WebView(tab.profile, std::bind(&SubWindow::createView, parent, std::placeholders::_1), parent);
- QDataStream stream(&tab.historyBuffer, QIODevice::ReadOnly);
- stream >> *view->history();
- view->history()->goToItem(view->history()->itemAt(tab.historyIndex));
- return view;
-}
+const QLatin1String stylesheet("QTabBar::tab { width: 200px; }");
TabWidget::TabWidget(SubWindow *parent)
: QTabWidget(parent)
, m_parent(parent)
{
- setStyleSheet("QTabBar::tab { width: 200px; }");
+ setStyleSheet(stylesheet);
setTabsClosable(true);
setTabBarAutoHide(true);
@@ -80,29 +73,6 @@ TabWidget::~TabWidget()
}
}
-int TabWidget::addTab(WebView *view)
-{
- if(view == nullptr) {
- return -1;
- }
-
- const int idx = QTabWidget::addTab(view, view->title());
- connect(view, &WebView::titleChanged, [this, view](const QString &title) {
- const int current_idx = indexOf(view);
- if(current_idx != -1) {
- setTabText(current_idx, title);
- }
- });
- connect(view, &WebView::iconChanged, [this, view](const QIcon &icon) {
- const int current_idx = indexOf(view);
- if(current_idx != -1) {
- setTabIcon(current_idx, icon);
- }
- });
- tabBar()->setTabData(idx, QVariant::fromValue<SubWindow::TabData>(SubWindow::TabData{}));
- return idx;
-}
-
void TabWidget::removeTab(int index)
{
// deleting the widget automatically removes the tab?
@@ -180,3 +150,12 @@ void TabWidget::mousePressEvent(QMouseEvent *event)
QTabWidget::mousePressEvent(event);
}
+
+WebView *TabWidget::createViewFromInfo(TabWidget::TabInformation &tab, SubWindow *parent)
+{
+ auto *view = new WebView(tab.profile, std::bind(&SubWindow::createView, parent, std::placeholders::_1), parent);
+ QDataStream stream(&tab.historyBuffer, QIODevice::ReadOnly);
+ stream >> *view->history();
+ view->history()->goToItem(view->history()->itemAt(tab.historyIndex));
+ return view;
+}
diff --git a/src/subwindow/tabwidget.h b/src/subwindow/tabwidget.h
index de5e6fb..2a5f360 100644
--- a/src/subwindow/tabwidget.h
+++ b/src/subwindow/tabwidget.h
@@ -9,9 +9,17 @@
#ifndef SMOLBOTE_TABWIDGET_H
#define SMOLBOTE_TABWIDGET_H
-#include <QTabWidget>
-#include <QQueue>
#include <QBuffer>
+#include <QQueue>
+#include <QTabWidget>
+
+template <typename T>
+concept c_WebView = requires(T *a)
+{
+ a->title();
+ a->titleChanged(QString());
+ a->iconChanged(QIcon());
+};
class QAction;
class QMenu;
@@ -24,19 +32,34 @@ class TabWidget : public QTabWidget
Q_OBJECT
public:
- struct TabInformation
- {
- WebProfile *profile;
- QString title;
- int historyIndex;
- QByteArray historyBuffer;
- };
-
explicit TabWidget(SubWindow *parent = nullptr);
~TabWidget() override;
+ template <c_WebView T>
+ int addTab(T *view)
+ {
+ if(view == nullptr) {
+ return -1;
+ }
+
+ const int idx = QTabWidget::addTab(view, view->title());
+ connect(view, &T::titleChanged, [this, view](const QString &title) {
+ const int current_idx = indexOf(view);
+ if(current_idx != -1) {
+ setTabText(current_idx, title);
+ }
+ });
+ connect(view, &T::iconChanged, [this, view](const QIcon &icon) {
+ const int current_idx = indexOf(view);
+ if(current_idx != -1) {
+ setTabIcon(current_idx, icon);
+ }
+ });
+ //tabBar()->setTabData(idx, QVariant::fromValue<SubWindow::TabData>(SubWindow::TabData{}));
+ return idx;
+ }
+
public slots:
- int addTab(WebView *view);
void removeTab(int index);
int restoreLastTab();
@@ -47,6 +70,14 @@ protected:
void mousePressEvent(QMouseEvent *event) override;
private:
+ struct TabInformation {
+ WebProfile *profile;
+ QString title;
+ int historyIndex;
+ QByteArray historyBuffer;
+ };
+ [[nodiscard]] WebView *createViewFromInfo(TabInformation &tab, SubWindow *parent);
+
SubWindow *m_parent;
int current = -1;
int previous = -1;
diff --git a/src/version.h.in b/src/version.h.in
deleted file mode 100644
index 44f10d9..0000000
--- a/src/version.h.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef SMOLBOTE_VERSION_H
-#define SMOLBOTE_VERSION_H
-
-// output of 'git describe --long --abbrev=40':
-// x.y.z-0-g0123456789012345678901234567890123456789
-#define poi_Version "@VCS_TAG@"
-
-#endif // SMOLBOTE_VERSION_H
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
deleted file mode 100644
index 5023ea4..0000000
--- a/src/wallet/wallet.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 "wallet.h"
-#include <QWebEngineView>
-#include <QWebEngineScript>
-
-void Wallet::autocompleteForm(QWebEngineView *view)
-{
- const auto findFormFunction = QLatin1String("index = undefined; for(var i = 0; i < document.forms.length; ++i) { if(document.forms[i].autocomplete) { index = i } }; index");
-
- view->page()->runJavaScript(findFormFunction, QWebEngineScript::ApplicationWorld, [view](const QVariant &v) {
- if(!v.isNull()) {
- const QString username = "test-username";
- const QString password = "test-password";
-
- auto autofillFunction = QString("inputs = document.forms[%1].getElementsByTagName('input');"
- "for(var i = 0; i < inputs.length; ++i) {"
- " if(inputs[i].type == 'username') { inputs[i].value='username' }"
- " else if(inputs[i].type == 'email') { inputs[i].value='%2' }"
- " else if(inputs[i].type == 'password') { inputs[i].value='%3' }"
- " else { inputs[i].value=inputs[i].type }"
- "}")
- .arg(v.toString(), username, password);
- // TODO
- // for page->url() get list of pairs type = value
- view->page()->runJavaScript(autofillFunction, QWebEngineScript::ApplicationWorld);
- }
- });
-}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
deleted file mode 100644
index d2fdb71..0000000
--- a/src/wallet/wallet.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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_WALLET_H
-#define SMOLBOTE_WALLET_H
-
-class QWebEngineView;
-
-namespace Wallet {
- void autocompleteForm(QWebEngineView *view);
-}
-
-#endif // SMOLBOTE_WALLET_H
diff --git a/src/webengine/meson.build b/src/webengine/meson.build
deleted file mode 100644
index 47e4adf..0000000
--- a/src/webengine/meson.build
+++ /dev/null
@@ -1,27 +0,0 @@
-webengine_moc = mod_qt5.preprocess(
- moc_headers: [ 'webprofile.h', 'webpage.h', 'webview.h' ],
- dependencies: dep_qt5
-)
-
-dep_webengine = declare_dependency(
- include_directories: [ '.', smolbote_include ],
- link_with: static_library('webengine', dependencies: [ dep_qt5, dep_spdlog ],
- include_directories: smolbote_include,
- sources: [ 'webprofile.cpp', 'urlinterceptor.cpp', 'webprofilemanager.cpp', 'webpage.cpp', 'webview.cpp', 'webviewcontextmenu.cpp', webengine_moc ])
-)
-
-poi_sourceset.add(dep_webengine)
-
-test('profile', executable('profile', 'test/profile.cpp', dependencies: [ dep_qt5, dep_webengine, dep_catch ]),
- env: { 'PROFILE' : meson.current_source_dir()/'test/testing.profile' },
- suite: 'webengine')
-
-test('profilemanager', executable('profilemanager', 'test/profilemanager.cpp', dependencies: [ dep_qt5, dep_webengine, dep_catch ]),
- env: { 'PROFILES' : meson.current_source_dir()/'test/testing.profile' },
- suite: 'webengine')
-
-test('view', executable('view', 'test/view.cpp', dependencies: [ dep_qt5, dep_webengine, dep_catch ]),
- args: [ '-platform', 'offscreen' ],
- env: { 'PROFILE' : meson.current_source_dir()/'test/testing.profile',
- 'URL' : meson.current_source_dir()/'test/sample.html' },
- suite: 'webengine')
diff --git a/staging/smolblok/meson.build b/staging/smolblok/meson.build
deleted file mode 100644
index 6105179..0000000
--- a/staging/smolblok/meson.build
+++ /dev/null
@@ -1,17 +0,0 @@
-dep_smolblok = declare_dependency(
- include_directories: [ '.', smolbote_interfaces ],
- link_with: library('smolblok',
- [ 'smolblok.cpp' ],
- include_directories: smolbote_interfaces,
- dependencies: dep_qt5
- )
-)
-
-smolblok_load = executable('smolblok-load',
- dependencies: [ dep_qt5, dep_spdlog, dep_smolblok ],
- sources: [ 'test/loader.cpp' ]
-)
-
-test('load', smolblok_load, suite: 'smolblok', should_fail: true)
-test('load', smolblok_load, suite: 'smolblok', args: files('meson.build'), should_fail: true)
-
diff --git a/subprojects/args.wrap b/subprojects/args.wrap
deleted file mode 100644
index ac19afa..0000000
--- a/subprojects/args.wrap
+++ /dev/null
@@ -1,6 +0,0 @@
-[wrap-file]
-directory = args.hxx-6.2.2
-
-source_url = https://neueland.iserlohn-fortress.net/releases/args.hxx-6.2.2.tar.xz
-source_filename = args.hxx-6.2.2.tar.xz
-source_hash = c1ed4bc76d3c343f493e6ae2c10ebcf3fdfaf013210b0a3dead04cef30c63fb6
diff --git a/subprojects/catch2.wrap b/subprojects/catch2.wrap
deleted file mode 100644
index 2e20085..0000000
--- a/subprojects/catch2.wrap
+++ /dev/null
@@ -1,10 +0,0 @@
-[wrap-file]
-directory = Catch2-2.11.3
-
-source_url = https://github.com/catchorg/Catch2/archive/v2.11.3.zip
-source_filename = Catch2-2.11.3.zip
-source_hash = c5a0a7510379c6f37f70b329986a335a7b8489d67ac417ce8f4262d0cae4cc5d
-
-patch_url = https://wrapdb.mesonbuild.com/v1/projects/catch2/2.11.3/1/get_zip
-patch_filename = catch2-2.11.3-1-wrap.zip
-patch_hash = 63c09cb68280435040ad304b3dd87ecfe69dbc216608991d0a82569a63119e57
diff --git a/subprojects/singleapplication.wrap b/subprojects/singleapplication.wrap
deleted file mode 100644
index ac817db..0000000
--- a/subprojects/singleapplication.wrap
+++ /dev/null
@@ -1,6 +0,0 @@
-[wrap-file]
-directory = SingleApplication-3.1.1a
-
-source_url = https://neueland.iserlohn-fortress.net/releases/SingleApplication-3.1.1a.tar.xz
-source_filename = SingleApplication-3.1.1a.tar.xz
-source_hash = df21800c9f3b254048ed34f6cfe96e5a540dc8ab4533b327a6982a6030f77080
diff --git a/subprojects/spdlog.wrap b/subprojects/spdlog.wrap
deleted file mode 100644
index b0f760b..0000000
--- a/subprojects/spdlog.wrap
+++ /dev/null
@@ -1,10 +0,0 @@
-[wrap-file]
-directory = spdlog-1.4.2
-
-source_url = https://github.com/gabime/spdlog/archive/v1.4.2.tar.gz
-source_filename = v1.4.2.tar.gz
-source_hash = 821c85b120ad15d87ca2bc44185fa9091409777c756029125a02f81354072157
-
-patch_url = https://wrapdb.mesonbuild.com/v1/projects/spdlog/1.4.2/1/get_zip
-patch_filename = spdlog-1.4.2-1-wrap.zip
-patch_hash = e0616f2a956670b0b23daba08f14d4f51a9551e74071269bc218cd05b666b229
diff --git a/test/cli/cli.cpp b/test/cli/cli.cpp
deleted file mode 100644
index 322c365..0000000
--- a/test/cli/cli.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <linenoise.h>
-#include <Python.h>
-
-static int numargs=0;
-
-/* Return the number of arguments of the application command line */
-static PyObject* emb_numargs(PyObject *self, PyObject *args)
-{
- if(!PyArg_ParseTuple(args, ":numargs"))
- return NULL;
-
- numargs = 19;
- return PyLong_FromLong(numargs);
-}
-
-static PyMethodDef EmbMethods[] = {
- /* ml_name Name of the method
- * ml_meth pointer to C implementation
- * ml_flags flag bits indicating how it should be called
- * ml_doc docstring
- */
- {"numargs", emb_numargs, METH_VARARGS, "Return the number of arguments received by the process."},
- {NULL, NULL, 0, NULL}
-};
-
-static PyModuleDef EmbModule = {
- /* m_base */ PyModuleDef_HEAD_INIT, // base module, always HEAD_INIT
- /* m_name */ "emb", // module name
- /* m_doc */ NULL, // Docstring for the module; usually a docstring variable created with PyDoc_STRVAR()
- /* m_size */ -1, //
- /* m_methods */ EmbMethods, // A pointer to a table of module-level functions
- /* m_slots */ NULL, // An array of slot definitions for multi-phase initialization
- /* traverse */ NULL, // A traversal function to call during GC traversal of the module object
- /* clear */ NULL, // A clear function to call during GC clearing of the module object
- /* free */ NULL // A function to call during deallocation of the module object
-};
-
-static PyObject* PyInit_emb(void)
-{
- return PyModule_Create(&EmbModule);
-}
-
-int main(int argc, char** argv)
-{
- printf("cli test application\n");
-
- wchar_t *program = Py_DecodeLocale(argv[0], NULL);
- if (program == NULL) {
- fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
- exit(1);
- }
-
- // inform the interpreter about paths to run-time libraries
- Py_SetProgramName(program); /* optional but recommended */
-
- printf("import emb: %i\n", PyImport_AppendInittab("emb", &PyInit_emb));
-
- // Initialize the python interpreter
- Py_Initialize();
-
- PyRun_SimpleString("print('Python interpreter ready')\n");
-
- const char* prompt = "poi> ";
-
- while(true) {
- char *cmd = linenoise(prompt);
-
- if(cmd == nullptr || *cmd == '\0') {
- printf("breaking out of repl\n");
- free(cmd);
- break;
- }
-
- //printf("echo(%i):'%s'\n", strlen(cmd), cmd);
- PyRun_SimpleString(cmd);
- linenoiseHistoryAdd(cmd);
- free(cmd);
- }
-
- // finalize the interpreter
- if (Py_FinalizeEx() < 0) {
- exit(120);
- }
-
- //
- PyMem_RawFree(program);
-
- return 0;
-}
-
diff --git a/test/cli/meson.build b/test/cli/meson.build
deleted file mode 100644
index 298e1db..0000000
--- a/test/cli/meson.build
+++ /dev/null
@@ -1,4 +0,0 @@
-cli_demo = executable('cli', install: false, dependencies: [ optional_deps ],
- sources: [ 'cli.cpp' ]
-)
-
diff --git a/tools/meson.build b/tools/meson.build
deleted file mode 100644
index fd1547e..0000000
--- a/tools/meson.build
+++ /dev/null
@@ -1,36 +0,0 @@
-if get_option('crashhandler').enabled() or get_option('updater').enabled()
- go = find_program('go', required: true)
- go_args = [ '-buildmode=pie' ]
-endif
-
-if get_option('crashhandler').enabled()
-
-# normally, you'd use configure_file to create this file, but that would only place it in build,
-# and go will refuse to build from files in two different directories
-meson.add_postconf_script(meson.source_root()/'scripts/gen-crashhandler-default-go.py',
- '--kconfig=' + meson.source_root()/'Kconfig',
- '--dotconfig=' + meson.source_root()/host_machine.system()/'.config',
- '--input=' + meson.current_source_dir()/'src/crashhandler/defaults.go.in',
- '--output=' + meson.current_source_dir()/'src/crashhandler/defaults.go'
-)
-
-custom_target('poi-crash',
- input: [ files('src/updater/main.go'), meson.current_source_dir()/'src/crashhandler/defaults.go' ],
- output: 'poi-crash',
- command: ['env', 'GOPATH='+meson.current_source_dir(), go, 'build', go_args, '-o=@OUTPUT@', 'crashhandler'],
- build_by_default: true,
- install: true,
- install_dir: get_option('bindir'),
-)
-endif
-
-if get_option('updater').enabled()
-custom_target('poi-update',
- input: files('src/updater/main.go'),
- output: 'poi-update',
- command: ['env', 'GOPATH='+meson.current_source_dir(), go, 'build', go_args, '-o=@OUTPUT@', 'updater'],
- build_by_default: true,
- install: true,
- install_dir: get_option('bindir'),
-)
-endif
diff --git a/tools/src/crashhandler/defaults.go.in b/tools/src/crashhandler/defaults.go.in
deleted file mode 100644
index 2ea5827..0000000
--- a/tools/src/crashhandler/defaults.go.in
+++ /dev/null
@@ -1,4 +0,0 @@
-package main
-
-var dumpPath = "@PATH_CRASHDUMP@"
-
diff --git a/tools/src/crashhandler/main.go b/tools/src/crashhandler/main.go
deleted file mode 100644
index 7b1717f..0000000
--- a/tools/src/crashhandler/main.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "io/ioutil"
- "os"
- "strings"
-)
-
-type CrashDump struct {
- Name string
- DumpPath string
- MetadataPath string
-}
-
-func expandHomeDir(path string) (string, error) {
- home, err := os.UserHomeDir()
- if err != nil {
- return path, err
- }
-
- return strings.Replace(path, "~/", home, -1), nil
-}
-
-func dumps(path string) ([]CrashDump, error) {
- files, err := ioutil.ReadDir(path)
- if err != nil {
- return nil, err
- }
-
- var crashes []CrashDump
-
- for i, file := range files {
- if strings.HasSuffix(file.Name(), ".dmp") {
- if i+1 < len(files) && files[i+1].Name() == file.Name()+".txt" {
- crashes = append(crashes, CrashDump{Name: strings.TrimSuffix(file.Name(), ".dmp"),
- DumpPath: file.Name(), MetadataPath: files[i+1].Name()})
- } else {
- crashes = append(crashes, CrashDump{Name: strings.TrimSuffix(file.Name(), ".dmp"), DumpPath: file.Name()})
- }
- }
- }
-
- return crashes, nil
-}
-
-func main() {
- helpFlag := flag.Bool("help", false, "Show help information.")
- flag.StringVar(&dumpPath, "crashd", dumpPath, "Crash dump path")
-
- // create crash report flags
- crashedFlag := flag.String("c", "", "Create crash report at specified location and write any specified data into it")
-
- flag.Parse()
- dumpPath, _ = expandHomeDir(dumpPath)
-
- if *helpFlag {
- flag.PrintDefaults()
- return
- }
-
- if *crashedFlag != "" {
- fmt.Println("Creating crash dump report", *crashedFlag)
- contents := []byte("Additional information: " + strings.Join(flag.Args(), ""))
- ioutil.WriteFile(*crashedFlag+".txt", contents, 0644)
- return
- }
-
- fmt.Printf(" [%s]\n", dumpPath)
- c, err := dumps(dumpPath)
- if err != nil {
- panic(err)
- }
- for _, d := range c {
- fmt.Printf("\t- %s\n", d.Name)
- }
- fmt.Println(" To analyze a crashdump, use the minidump_stackwalk tool:")
- fmt.Println("minidump_stackwalk <minidump-file> [symbol-path]")
-
-}
diff --git a/tools/src/updater/main.go b/tools/src/updater/main.go
deleted file mode 100644
index e6e1560..0000000
--- a/tools/src/updater/main.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "net/http"
- "encoding/json"
- "io/ioutil"
-)
-
-func main() {
- helpFlag := flag.Bool("help", false, "Show help information")
- //verboseFlag := flag.Bool("verbose", false, "Print more information")
- //repoFlag := flag.String("repo", "https://neueland.iserlohn-fortress.net/smolbote/downloads", "Repository path")
- //dryRunFlag := flag.Bool("dry-run", false, "Dry run: only check files, do not download")
-
- flag.Parse()
-
- branchesRequest := "https://neueland.iserlohn-fortress.net/gitea/api/v1/repos/aqua/smolbote/branches"
-
- // help flag --> show usage and exit
- if *helpFlag {
- flag.PrintDefaults()
- return
- }
-
- response, err := http.Get(branchesRequest)
- if err != nil {
- panic(err)
- } else if response.StatusCode != 200 {
- fmt.Printf("Could not get manifest: %s\n", response.Status)
- return
- }
- defer response.Body.Close()
-
- body, _ := ioutil.ReadAll(response.Body)
-
- var branches []BranchResponse
- json.Unmarshal(body, &branches)
-
-
- for _,v := range(branches) {
- fmt.Printf("%s\t%s %s\n", v.Name, v.Commit.ID, v.Commit.Timestamp)
- }
- fmt.Println("done")
-
-}
diff --git a/tools/src/updater/manifest.go b/tools/src/updater/manifest.go
deleted file mode 100644
index f9d3d86..0000000
--- a/tools/src/updater/manifest.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package main
-
-import (
- "time"
-)
-
-type CommitResponse struct {
- ID string `json:"id"`
- Timestamp time.Time `json:"timestamp"`
-}
-
-type BranchResponse struct {
- Name string `json:"name"`
- Commit CommitResponse `json:"commit"`
-}
-
diff --git a/windows/.config b/windows/.config
deleted file mode 100644
index 235612f..0000000
--- a/windows/.config
+++ /dev/null
@@ -1,78 +0,0 @@
-# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)
-
-#
-# Application
-#
-CONFIG_POI_NAME="smolbote"
-CONFIG_POI_ICON=":/icons/poi.svg"
-
-#
-# Configuration defaults
-#
-CONFIG_PATH_CONFIG="smolbote.cfg"
-CONFIG_PATH_FILTER="hosts"
-CONFIG_PATH_PLUGINS="plugins"
-CONFIG_PATH_PROFILES="profiles"
-CONFIG_PATH_BOOKMARKS="bookmarks.xbel"
-CONFIG_PATH_DOWNLOADS="~/Downloads"
-
-#
-# Keyboard shortcuts
-#
-
-#
-# Main Window shortcuts
-#
-CONFIG_SHORTCUT_WINDOW_NEWGROUP="Ctrl+G"
-CONFIG_SHORTCUT_WINDOW_NEWWINDOW="Ctrl+N"
-CONFIG_SHORTCUT_WINDOW_ABOUT="Ctrl+H"
-CONFIG_SHORTCUT_WINDOW_QUIT="Ctrl+Q"
-CONFIG_SHORTCUT_WINDOW_SEARCH="F3"
-CONFIG_SHORTCUT_WINDOW_BOOKMARKS="Ctrl+B"
-CONFIG_SHORTCUT_WINDOW_DOWNLOADS="Ctrl+D"
-
-#
-# Navigation Bar shortcuts
-#
-CONFIG_SHORTCUT_NAVIGATION_BACK="Ctrl+Left"
-CONFIG_SHORTCUT_NAVIGATION_BACKMENU="Ctrl+Down"
-CONFIG_SHORTCUT_NAVIGATION_FORWARD="Ctrl+Right"
-CONFIG_SHORTCUT_NAVIGATION_FORWARDMENU="Ctrl+Up"
-CONFIG_SHORTCUT_NAVIGATION_REFRESH="F5"
-CONFIG_SHORTCUT_NAVIGATION_RELOAD="Ctrl+F5"
-CONFIG_SHORTCUT_NAVIGATION_HOME="Ctrl+Home"
-
-#
-# Address Bar shortcuts
-#
-CONFIG_SHORTCUT_ADDRESS_FOCUS="F4"
-CONFIG_SHORTCUT_ADDRESS_MENU="F2"
-
-#
-# Subwindow shortcuts
-#
-CONFIG_SHORTCUT_SUBWINDOW_MENU="F1"
-CONFIG_SHORTCUT_SUBWINDOW_TILE="F9"
-CONFIG_SHORTCUT_SUBWINDOW_CASCADE="F10"
-CONFIG_SHORTCUT_SUBWINDOW_FULLSCREEN="F11"
-CONFIG_SHORTCUT_SUBWINDOW_NEWTAB="Ctrl+T"
-CONFIG_SHORTCUT_SUBWINDOW_CLOSETAB="Ctrl+X"
-CONFIG_SHORTCUT_SUBWINDOW_TABLEFT="Ctrl+O"
-CONFIG_SHORTCUT_SUBWINDOW_MOVETABLEFT="Ctrl+Shift+O"
-CONFIG_SHORTCUT_SUBWINDOW_TABRIGHT="Ctrl+P"
-CONFIG_SHORTCUT_SUBWINDOW_MOVETABRIGHT="Ctrl+Shift+P"
-
-#
-# Profile defaults
-#
-CONFIG_PROFILE_DEFAULT=""
-CONFIG_PROFILE_DEFAULT_SEARCH="https://duckduckgo.com/?q=%1&ia=web"
-CONFIG_PROFILE_DEFAULT_HOMEPAGE="about:blank"
-CONFIG_PROFILE_DEFAULT_NEWTAB="about:blank"
-# CONFIG_USEPLASMA is not set
-# CONFIG_USEBREAKPAD is not set
-
-#
-# Workarounds
-#
-CONFIG_QTBUG_65223=y
diff --git a/data/windows.rc b/windows/icon.rc
index 050404d..050404d 100644
--- a/data/windows.rc
+++ b/windows/icon.rc
diff --git a/data/poi.ico b/windows/poi.ico
index 69d15e2..69d15e2 100644
--- a/data/poi.ico
+++ b/windows/poi.ico
Binary files differ