aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt58
-rw-r--r--CppCheckSuppressions.txt3
-rw-r--r--Kconfig226
-rw-r--r--cmake/CompilerOptions.cmake89
-rw-r--r--cmake/CppCheck.cmake11
-rw-r--r--doc/CMakeLists.txt38
-rw-r--r--doc/building.md40
-rwxr-xr-xdoc/man/genroff.sh2
-rw-r--r--doc/meson.build16
-rw-r--r--lib/bookmarks/CMakeLists.txt9
-rw-r--r--lib/bookmarks/formats/ffjson.cpp7
-rw-r--r--lib/bookmarks/formats/xbel.cpp17
-rw-r--r--lib/bookmarks/meson.build16
-rw-r--r--lib/configuration/CMakeLists.txt24
-rw-r--r--lib/configuration/configuration.cpp118
-rw-r--r--lib/configuration/configuration.h61
-rwxr-xr-xlib/configuration/gen-default-cfg.py43
-rw-r--r--lib/configuration/init_global.cpp.in25
-rw-r--r--lib/configuration/qt_specialization.cpp31
-rw-r--r--lib/configuration/qt_specialization.h8
-rw-r--r--lib/configuration/test/configuration.cpp57
-rw-r--r--lib/downloads/CMakeLists.txt8
-rw-r--r--lib/downloads/downloadswidget.cpp2
-rw-r--r--lib/downloads/downloadswidget.h4
-rw-r--r--lib/downloads/meson.build19
-rw-r--r--lib/downloads/widgets/downloaditemwidget.cpp27
-rw-r--r--lib/downloads/widgets/downloaditemwidget.h10
-rw-r--r--lib/pluginloader/CMakeLists.txt0
-rw-r--r--lib/session_formats/CMakeLists.txt5
-rw-r--r--lib/urlfilter/CMakeLists.txt27
-rw-r--r--lib/urlfilter/meson.build26
-rw-r--r--linux/.config111
-rw-r--r--linux/config.yaml63
-rw-r--r--linux/firejail/poi.profile48
-rw-r--r--linux/makepkg/PKGBUILD98
-rw-r--r--meson.build147
-rwxr-xr-xscripts/gen-default-cfg.py51
-rw-r--r--src/CMakeLists.txt69
-rw-r--r--src/about/CMakeLists.txt12
-rw-r--r--src/about/aboutdialog.cpp6
-rw-r--r--src/about/meson.build21
-rw-r--r--src/applicationmenu.cpp12
-rw-r--r--src/bookmarks/bookmarkstoolbar.cpp6
-rw-r--r--src/browser.cpp39
-rw-r--r--src/main.cpp166
-rw-r--r--src/mainwindow/addressbar.cpp4
-rw-r--r--src/mainwindow/mainwindow.cpp8
-rw-r--r--src/mainwindow/menubar.cpp29
-rw-r--r--src/mainwindow/widgets/navigationbar.cpp14
-rw-r--r--src/mainwindow/widgets/searchform.cpp4
-rw-r--r--src/meson.build60
-rw-r--r--src/session/sessiondialog.h1
-rw-r--r--src/settings.h.in32
-rw-r--r--src/subwindow/subwindow.cpp3
-rw-r--r--src/subwindow/tabwidget.cpp16
-rw-r--r--src/util.cpp2
-rw-r--r--src/version.h.in (renamed from include/version.h.in)2
-rw-r--r--src/webengine/CMakeLists.txt10
-rw-r--r--src/webengine/webpage.cpp4
-rw-r--r--src/webengine/webpage.h4
-rw-r--r--src/webengine/webprofile.cpp2
-rw-r--r--src/webengine/webprofilemanager.cpp1
-rw-r--r--src/webengine/webprofilemanager.h13
-rw-r--r--src/webengine/webview.cpp14
-rw-r--r--src/webengine/webviewcontextmenu.cpp97
-rw-r--r--subprojects/args.wrap6
-rw-r--r--subprojects/catch2.wrap10
-rw-r--r--subprojects/singleapplication.wrap6
-rw-r--r--subprojects/spdlog.wrap10
69 files changed, 1016 insertions, 1212 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..d83676c
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,58 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(smolbote VERSION 0.1.0 LANGUAGES CXX)
+
+list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
+
+include(CppCheck)
+include(CompilerOptions)
+include(FeatureSummary)
+include(GNUInstallDirs)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+# set C++ standard for all targets
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+# set PIE for all targets
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+# dependencies
+find_package(GTest)
+enable_testing()
+
+find_package(spdlog REQUIRED)
+
+find_package(Qt6 6.0.0 REQUIRED COMPONENTS
+ Network
+ Widgets
+ SvgWidgets
+ WebEngineCore
+ WebEngineWidgets
+ Concurrent
+)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
+add_subdirectory(third_party/SingleApplication)
+
+add_subdirectory(lib/bookmarks)
+add_subdirectory(lib/configuration)
+add_subdirectory(lib/downloads)
+#add_subdirectory(lib/pluginloader)
+add_subdirectory(lib/session_formats)
+add_subdirectory(lib/urlfilter)
+
+add_subdirectory(src/about)
+add_subdirectory(src/webengine)
+add_subdirectory(src)
+
+add_subdirectory(doc)
+
+install(TARGETS poi DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+feature_summary(WHAT ALL)
diff --git a/CppCheckSuppressions.txt b/CppCheckSuppressions.txt
new file mode 100644
index 0000000..6ed9d86
--- /dev/null
+++ b/CppCheckSuppressions.txt
@@ -0,0 +1,3 @@
+// for all files
+missingIncludeSystem
+unknownMacro
diff --git a/Kconfig b/Kconfig
deleted file mode 100644
index 37d3d9c..0000000
--- a/Kconfig
+++ /dev/null
@@ -1,226 +0,0 @@
-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"
-endmenu
-
-menu "Keyboard shortcuts"
- comment "Main Window shortcuts"
- config shortcuts.session.save
- string "Save Session shortcut"
- default "Ctrl+S,S"
- config shortcuts.session.open
- string "Load Session shortcut"
- default "Ctrl+S,O"
- config shortcuts.window.newgroup
- string "New Group shortcut"
- default "Ctrl+G"
- config shortcuts.window.newwindow
- string "New Window shortcut"
- default "Ctrl+N"
- config shortcuts.window.about
- string "Show About Dialog"
- default "F1"
- config shortcuts.window.quit
- string "Quit shortcut"
- default "Ctrl+Q"
- config shortcuts.window.search
- string "Show or hide search box"
- default "F3"
- config shortcuts.window.downloads.show
- string "Show downloads dialog in this window"
- default "Ctrl+D"
-
- comment "Navigation Bar shortcuts"
- config navigationbar.show
- string "Toggle navigation bar"
- default "Ctrl+Shift+N"
- config shortcuts.navigation.back
- string "Go back in history"
- default "Ctrl+Left"
- config shortcuts.navigation.backmenu
- string "Show Back history menu"
- default "Ctrl+Down"
- config shortcuts.navigation.forward
- string "Go forward in history"
- default "Ctrl+Right"
- config shortcuts.navigation.forwardmenu
- string "Show Forward history menu"
- default "Ctrl+Up"
- config shortcuts.navigation.refresh
- string "Refresh the page"
- default "F5"
- config shortcuts.navigation.reload
- string "Reload the page"
- default "Ctrl+F5"
- config shortcuts.navigation.home
- string "Load homepage"
- default "Ctrl+Home"
-
- comment "Address Bar shortcuts"
- config shortcuts.address.focus
- string "Focus the Address Bar"
- default "F4"
- config shortcuts.address.menu
- string "Show Address Bar menu"
- default "F2"
-
- comment "Subwindow shortcuts"
- config shortcuts.subwindow.close
- string "Close Subwindow shortcut"
- default "Ctrl+Shift+W"
- config shortcuts.subwindow.fullscreen
- string "Make current subwindow fullscreen"
- default "F11"
- config shortcuts.subwindow.newtab
- string "Create new tab"
- default "Ctrl+T"
- config shortcuts.subwindow.closetab
- string "Close current tab"
- default "Ctrl+W"
- config shortcuts.subwindow.restoretab
- string "Restore last closed tab"
- default "Ctrl+Shift+T"
- config shortcuts.subwindow.tableft
- string "Switch to the tab on the left"
- default "Ctrl+O"
- config shortcuts.subwindow.movetableft
- string "Move tab to the left"
- default "Ctrl+Shift+O"
- config shortcuts.subwindow.tabright
- string "Switch to the tab on the right"
- default "Ctrl+P"
- config shortcuts.subwindow.movetabright
- string "Move tab to the right"
- default "Ctrl+Shift+P"
-
-endmenu
-
-menu "Main Window"
- config mainwindow.title
- string "Main window title"
- default "smolbote"
- config mainwindow.width
- int "Main window width"
- default 1280
- config mainwindow.height
- int "Main window height"
- default 720
-endmenu
-
-menu "Bookmarks"
- config bookmarks.path
- string "Bookmarks location"
- default "~/.config/smolbote/bookmarks.xbel"
- config shortcuts.window.bookmarks.show
- string "Show bookmarks dialog in this window"
- default "Ctrl+B"
- config bookmarks.toolbar.show
- string "Toggle bookmarks toolbar visibility"
- default "Ctrl+Shift+B"
- config bookmarks.toolbar.movable
- bool "Default bookmarks toolbar movable"
- default n
- config bookmarks.toolbar.visible
- bool "Default bookmarks toolbar visibility"
- default n
-endmenu
-
-menu "Profile Settings"
- config profile.path
- string "Profile load location"
- default "~/.config/smolbote/profiles.d"
- config profile.default
- string "Default profile"
- default ""
- config profile.search
- string "Search engine"
- default "https://duckduckgo.com/?q=%1&ia=web"
- config profile.homepage
- string "Homepage"
- default "about:blank"
- config profile.newtab
- string "New tab page"
- default "about:blank"
-endmenu
-
-config USEPLUGINS
- bool "Enable plugins"
- default y
-
-menu "Plugin Settings"
- depends on USEPLUGINS
- config PLUGINS_PATH
- string "Plugin load location"
- default "~/.config/smolbote/plugins.d"
- choice PLUGINS_SIGNATURE_CHECK
- bool "Plugin Signature enforcement"
- default PLUGINS_SIGNATURE_CHECKED
- config PLUGINS_SIGNATURE_IGNORED
- bool "Don't check plugin signatures"
- config PLUGINS_SIGNATURE_CHECKED
- bool "Don't load plugins with invalid signatures"
- config PLUGINS_SIGNATURE_ENFORCED
- bool "Only load plugins with valid signatures"
- endchoice
- config PLUGINS_SIGNATURE_HASH
- string "Hashing algorithm used by the signature"
- default "SHA256"
-endmenu
-
-comment "Default paths"
-config filter.path
- string "Host filter path"
- default "~/.config/smolbote/hosts.d"
-config downloads.path
- string "Downloads location"
- default "~/Downloads"
-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/cmake/CompilerOptions.cmake b/cmake/CompilerOptions.cmake
new file mode 100644
index 0000000..dbb37fd
--- /dev/null
+++ b/cmake/CompilerOptions.cmake
@@ -0,0 +1,89 @@
+# ==================================================================================
+# adapted from
+# https://github.com/zhivkopetrov/cmake_helpers.git
+# MIT License Copyright (c) 2020-2023 Zhivko Petrov
+#
+# some compiler warnings from
+# https://lefticus.gitbooks.io/cpp-best-practices/content/02-Use_the_Tools_Available.html
+#
+# ==================================================================================
+# target_enable_warnings
+
+function(target_enable_warnings target)
+ if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+ target_compile_options(
+ ${target}
+ PRIVATE
+ /W4
+ /WX
+ )
+ endif()
+
+ if((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR
+ (CMAKE_CXX_COMPILER_ID MATCHES Clang))
+ target_compile_options(
+ ${target}
+ PRIVATE
+ # compiler warnings
+ # generic
+ -Wall -Wextra # reasonable and standard
+ -Wpedantic # non-standard cpp is used
+ -Wmisleading-indentation
+ -Wlogical-op # logical op being used instead of bitwise
+ -Wundef
+ -Wuninitialized
+ -Weffc++ # disabled because it would require skeleton changes
+ # variables
+ -Wshadow # variable declaration shadows one from parent context
+ -Wunused # anything being unused
+ # casts
+ -Werror=old-style-cast # C-style casts
+ -Wcast-align # performance problem casts
+ -Wcast-qual
+ -Wuseless-cast # cast to same type
+ # conversion
+ #-Wconversion # type conversion may lose data
+ -Wsign-conversion # sign conversion
+ -Wdouble-promotion # implicit float to double
+ # functions
+ -Wunused-parameter
+ -Werror=missing-declarations # missing function declaration in header files
+ -Werror=redundant-decls
+ -Werror=return-type
+ -Werror=overloaded-virtual
+ # inheritance
+ -Wnon-virtual-dtor # class with virtual functions has non-virt dtor
+ -Woverloaded-virtual # overloaded (not override) virtual function
+ # branches
+ -Wduplicated-cond # if/else chain has duplicated conditions
+ -Wduplicated-branches # if/else chain has duplicated code
+ # pointers
+ -Wpointer-arith
+ -Wnull-dereference
+ # style
+ -Wformat=2 # security issues around printf
+ -Werror=date-time # usage of __DATE__ and __TIME__ macros
+ -Werror=missing-field-initializers
+ # logic
+ -Wlogical-op
+ -Wimplicit-fallthrough
+ -Wduplicated-cond
+ -Wduplicated-branches
+
+ # other flags
+ -ffunction-sections # place each function into its own section
+ # better ASLR but larger executables
+ -fstack-protector-all # emit check for buffer overflows on all functions
+ -fstack-clash-protection # emit check for stack clash attacks
+ )
+ endif()
+
+ # add -Werror to release builds
+ if((${CMAKE_BUILD_TYPE} MATCHES Release) OR
+ (${CMAKE_BUILD_TYPE} MATCHES MinSizeRel))
+ # currently disabled
+ #target_compile_options(${target} PRIVATE -Werror)
+ endif()
+
+endfunction()
+
diff --git a/cmake/CppCheck.cmake b/cmake/CppCheck.cmake
new file mode 100644
index 0000000..d8a4559
--- /dev/null
+++ b/cmake/CppCheck.cmake
@@ -0,0 +1,11 @@
+find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck)
+
+if(CMAKE_CXX_CPPCHECK)
+ list(APPEND CMAKE_CXX_CPPCHECK
+ --std=c++20
+ --enable=all
+ --inconclusive
+ --quiet
+ --suppressions-list=${PROJECT_SOURCE_DIR}/CppCheckSuppressions.txt
+ )
+endif()
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..0f33bcc
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,38 @@
+option(INSTALL_MANPAGES "Install manpages")
+
+add_custom_command(
+ OUTPUT smolbote.1
+ COMMAND ${CMAKE_CURRENT_LIST_DIR}/man/genroff.sh ${CMAKE_CURRENT_LIST_DIR}/man/smolbote.1.scd smolbote.1
+ DEPENDS ${CMAKE_CURRENT_LIST_DIR}/man/smolbote.1.scd
+ USES_TERMINAL
+)
+
+add_custom_command(
+ OUTPUT smolboterc.5
+ COMMAND ${CMAKE_CURRENT_LIST_DIR}/man/genroff.sh ${CMAKE_CURRENT_LIST_DIR}/man/smolboterc.5.scd smolboterc.5
+ DEPENDS ${CMAKE_CURRENT_LIST_DIR}/man/smolboterc.5.scd
+ USES_TERMINAL
+)
+
+add_custom_command(
+ OUTPUT smolbote-profile.5
+ COMMAND ${CMAKE_CURRENT_LIST_DIR}/man/genroff.sh ${CMAKE_CURRENT_LIST_DIR}/man/smolbote-profile.5.scd smolbote-profile.5
+ DEPENDS ${CMAKE_CURRENT_LIST_DIR}/man/smolbote-profile.5.scd
+ USES_TERMINAL
+)
+
+add_custom_target(manpages DEPENDS
+ smolbote.1
+ smolboterc.5
+ smolbote-profile.5
+)
+
+if(${INSTALL_MANPAGES})
+install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/smolbote.1
+ ${CMAKE_CURRENT_BINARY_DIR}/smolboterc.5
+ ${CMAKE_CURRENT_BINARY_DIR}/smolbote-profile.5
+ TYPE MAN
+)
+endif()
diff --git a/doc/building.md b/doc/building.md
index 9ea9344..a7feab1 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -1,11 +1,12 @@
## Building from source
### Dependencies
-- [Qt](https://www.qt.io/)
-- [meson](https://mesonbuild.com/) 0.52.0 or later
+- [Qt](https://www.qt.io/) 6
+- [cmake](https://cmake.org/) 3.16 or later
- [kconfiglib](https://github.com/ulfalizer/Kconfiglib/)
- A compiler with C++17 support
-- spdlog: if not found can be downloaded by meson
+- spdlog
+- SingleApplication
### Optional dependencies
- openssl or libressl: for signing plugins
@@ -13,45 +14,22 @@
- gtest
### Steps
-```
+```sh
# clone the repository
-git clone https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote.git smolbote.git
-cd smolbote.git
+git clone https://neueland.iserlohn-fortress.net/cgit/smolbote.git
+cd smolbote
# Get the submodules
git submodule init
git submodule update
# configure
-mkdir build
-meson build
+cmake -S . -B cmake-build
# make
-ninja
-```
-
-## Using meson
-
-### Listing build options
-```
-build% meson configure
-```
-
-### Changing build options
-```
-build% meson configure -D<option-name>=<enabled|disabled>
-```
-
-### Prevent meson from downloading wraps
-During configure, meson can download missing dependencies on its own using
-wraps. To disable this, pass '--wrap-mode=nodownload' during the configure
-phase:
-```
-repo% meson --wrap-mode=nodownload build-path
+cmake --build cmake-build
```
-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
as keyboard shortcuts and paths. You can edit these settings using `menuconfig`
diff --git a/doc/man/genroff.sh b/doc/man/genroff.sh
index 1d513f4..d1c74a1 100755
--- a/doc/man/genroff.sh
+++ b/doc/man/genroff.sh
@@ -1,4 +1,4 @@
#/usr/bin/env sh
-scdoc < $1
+scdoc < $1 > $2
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/lib/bookmarks/CMakeLists.txt b/lib/bookmarks/CMakeLists.txt
new file mode 100644
index 0000000..d4bd3c7
--- /dev/null
+++ b/lib/bookmarks/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_library(bookmarks STATIC
+ bookmarkformat.cpp bookmarkformat.h
+ bookmarkitem.cpp bookmarkitem.h
+ bookmarkmodel.cpp bookmarkmodel.h
+ formats/xbel.cpp formats/xbel.h
+ formats/ffjson.cpp formats/ffjson.h
+)
+target_link_libraries(bookmarks PUBLIC Qt6::Widgets)
+target_include_directories(bookmarks PUBLIC ${CMAKE_CURRENT_LIST_DIR})
diff --git a/lib/bookmarks/formats/ffjson.cpp b/lib/bookmarks/formats/ffjson.cpp
index f9e0866..f95d0d8 100644
--- a/lib/bookmarks/formats/ffjson.cpp
+++ b/lib/bookmarks/formats/ffjson.cpp
@@ -8,11 +8,12 @@
#include "ffjson.h"
#include "bookmarkitem.h"
+#include <QDateTime>
+#include <QDebug>
+#include <QIODevice>
+#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
-#include <QJsonArray>
-#include <QDebug>
-#include <QDateTime>
inline auto asDate(const QJsonValue &v)
{
diff --git a/lib/bookmarks/formats/xbel.cpp b/lib/bookmarks/formats/xbel.cpp
index 7ff79a9..a0a553f 100644
--- a/lib/bookmarks/formats/xbel.cpp
+++ b/lib/bookmarks/formats/xbel.cpp
@@ -15,28 +15,28 @@
inline void readChildElements(QXmlStreamReader &reader, BookmarkItem *parent)
{
while(reader.readNextStartElement()) {
- if(reader.name() == "title") {
+ if(reader.name() == QLatin1String("title")) {
parent->setData(BookmarkItem::Title, reader.readElementText());
- } else if(reader.name() == "dateAdded") {
+ } else if(reader.name() == QLatin1String("dateAdded")) {
parent->setData(BookmarkItem::DateAdded, QDateTime::fromString(reader.readElementText(), Qt::RFC2822Date));
- } else if(reader.name() == "lastModified") {
+ } else if(reader.name() == QLatin1String("lastModified")) {
parent->setData(BookmarkItem::LastModified, QDateTime::fromString(reader.readElementText(), Qt::RFC2822Date));
- } else if(reader.name() == "tags") {
+ } else if(reader.name() == QLatin1String("tags")) {
parent->setData(BookmarkItem::Tags, reader.readElementText().split(";"));
- } else if(reader.name() == "description") {
+ } else if(reader.name() == QLatin1String("description")) {
parent->setData(BookmarkItem::Description, reader.readElementText());
- } else if(reader.name() == "folder") {
+ } else if(reader.name() == QLatin1String("folder")) {
auto *item = new BookmarkItem({}, BookmarkItem::Folder, parent);
item->setExpanded(!(reader.attributes().value("folded") == QLatin1String("yes")));
parent->appendChild(item);
readChildElements(reader, item);
- } else if(reader.name() == "bookmark") {
+ } else if(reader.name() == QLatin1String("bookmark")) {
auto *item = new BookmarkItem({}, BookmarkItem::Bookmark, parent);
item->setData(BookmarkItem::Href, reader.attributes().value("href").toString());
parent->appendChild(item);
@@ -53,7 +53,8 @@ void Xbel::read(QIODevice *device, BookmarkItem *item)
QXmlStreamReader qXmlStreamReader(device);
if(qXmlStreamReader.readNextStartElement()) {
- if(!(qXmlStreamReader.name() == "xbel" && qXmlStreamReader.attributes().value("version") == "1.0")) {
+ if(!(qXmlStreamReader.name() == QLatin1String("xbel")
+ && qXmlStreamReader.attributes().value("version") == QLatin1String("1.0"))) {
return;
}
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..2e77782
--- /dev/null
+++ b/lib/configuration/CMakeLists.txt
@@ -0,0 +1,24 @@
+# generate init_global.cpp
+add_custom_command(
+ OUTPUT init_global.cpp
+ COMMAND ${CMAKE_CURRENT_LIST_DIR}/gen-default-cfg.py
+ --config ${PROJECT_SOURCE_DIR}/linux/config.yaml
+ --template ${CMAKE_CURRENT_LIST_DIR}/init_global.cpp.in
+ --output init_global.cpp
+ DEPENDS
+ ${CMAKE_CURRENT_LIST_DIR}/gen-default-cfg.py
+ ${PROJECT_SOURCE_DIR}/linux/config.yaml
+)
+add_library(configuration STATIC
+ configuration.cpp configuration.h
+ init_global.cpp
+ qt_specialization.cpp qt_specialization.h
+)
+target_link_libraries(configuration PUBLIC Qt6::Gui spdlog::spdlog)
+target_include_directories(configuration PUBLIC ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(test_configuration test/configuration.cpp)
+target_link_libraries(test_configuration PUBLIC configuration GTest::gtest_main)
+gtest_add_tests(TARGET test_configuration
+ SOURCES test/configuration.cpp
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/test)
diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp
index 75f863c..f2a2218 100644
--- a/lib/configuration/configuration.cpp
+++ b/lib/configuration/configuration.cpp
@@ -10,13 +10,15 @@
#include <algorithm>
#include <fstream>
#include <iostream>
-#include <sstream>
#include <stdexcept>
+#include <variant>
#ifndef NO_QT_SPEC
#include <QStandardPaths>
#endif
+using namespace std::placeholders;
+
static std::unique_ptr<Configuration> s_conf;
Configuration::Configuration()
@@ -27,66 +29,64 @@ Configuration::Configuration()
}
}
-Configuration::Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept
+Configuration::Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> p_list) noexcept
#ifndef NO_QT_SPEC
: m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString())
#endif
{
- for(const auto &i : l) {
- insert_or_assign(i.first, i.second);
+ for(const auto &item : p_list) {
+ insert_or_assign(item);
}
}
-void Configuration::read_file(const std::string &location)
+bool Configuration::read_file(const std::string &location)
{
- std::fstream fs(location, std::fstream::in);
- if(fs.is_open()) {
- read(fs);
- fs.close();
+ std::fstream fstream(location, std::fstream::in);
+ bool result = false;
+
+ if(fstream.is_open()) {
+ read(fstream);
+ fstream.close();
+ result = true;
}
+
+ return result;
}
inline auto strip(std::string &value)
{
- value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to<char>(), ' ')));
- value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end());
+ // strip whitespace at the begining
+ value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind(std::not_equal_to<>(), ' ', _1)));
+
+ // strip whitespace from the end
+ value.erase(std::find_if(value.rbegin(), value.rend(), std::bind(std::not_equal_to<>(), ' ', _1)).base(), value.end());
+
return value;
}
-inline auto parse(const std::string &line, std::string &section)
+inline std::optional<Configuration::kv_pair> parse_line(const std::string &line, /* in/out */ std::string &section)
{
- struct {
- bool pair = false;
- std::string key;
- std::string value;
- } ret;
-
- if(line[0] == '#' || line.length() == 0) {
- return ret;
- }
-
if(line.front() == '[' && line.back() == ']') {
section = line.substr(1, line.length() - 2) + '/';
- return ret;
+ return std::nullopt;
}
const auto pos = line.find_first_of('=');
if(pos == std::string::npos) {
- return ret;
+ return std::nullopt;
}
- ret.key = line.substr(0, pos);
- strip(ret.key);
- if(ret.key.empty()) {
- return ret;
- }
- ret.key = section + ret.key;
+ std::string key = line.substr(0, pos);
+ std::string val = line.substr(pos + 1);
+ strip(key);
+ strip(val);
- ret.value = line.substr(pos + 1);
- strip(ret.value);
+ if(key.empty()) {
+ return std::nullopt;
+ }
+ key = section + key;
- ret.pair = true;
- return ret;
+ return std::make_optional<Configuration::kv_pair>({ key, val });
}
#ifdef FUZZER
@@ -100,9 +100,16 @@ extern "C" int LLVMFuzzerTestOneInput(const char *Data, long long Size)
void Configuration::read(std::basic_istream<char> &input)
{
- std::string line, section;
+ std::string line;
+ std::string section;
while(std::getline(input, line)) {
+ // skip empty lines and comments
+ if(line.length() == 0 || line[0] == '#') {
+ continue;
+ }
+
+ // include file
if(line.rfind("@@") == 0) {
if(line.rfind("@@include ") == 0) {
read_file(line.substr(10));
@@ -110,23 +117,30 @@ void Configuration::read(std::basic_istream<char> &input)
continue;
}
- const auto pair = parse(line, section);
- if(pair.pair) {
+ const auto pair = parse_line(line, section);
+ if(pair) {
+ insert_or_assign(*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;
- }
+void Configuration::insert_or_assign(const Configuration::kv_pair &pair)
+{
+ // insert
+ if(count(pair.first) == 0) {
+ insert(pair);
+ } else {
+ // when assigning we have to keep the same type
+ const auto old_value = at(pair.first);
- 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(std::holds_alternative<std::string>(old_value)) {
+ at(pair.first) = pair.second;
+
+ } else if(std::holds_alternative<int>(old_value)) {
+ at(pair.first) = std::stoi(std::get<std::string>(pair.second));
+
+ } else if(std::holds_alternative<bool>(old_value)) {
+ at(pair.first) = (std::get<std::string>(pair.second) == "true");
}
}
}
@@ -150,9 +164,7 @@ std::ostream &operator<<(std::ostream &out, const Configuration &obj)
// unordered_map is, well, unordered, so grab the keys and sort them before printing them
std::vector<std::string> keys;
- for(const auto &pair : obj) {
- keys.emplace_back(pair.first);
- }
+ std::transform(obj.cbegin(), obj.cend(), std::inserter(keys, keys.end()), [](const auto &pair) { return pair.first; });
std::sort(keys.begin(), keys.end());
for(const auto &key : keys) {
diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h
index cd3c244..f2de92f 100644
--- a/lib/configuration/configuration.h
+++ b/lib/configuration/configuration.h
@@ -12,52 +12,44 @@
#include <initializer_list>
#include <memory>
#include <optional>
+#include <source_location>
+#include <spdlog/spdlog.h>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <variant>
-#if defined(__clang__)
-#define consumable(X) [[clang::consumable(X)]]
-#define return_typestate(X) [[clang::return_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 callable_when(X)
-#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;
+concept concept_value_t = std::is_arithmetic_v<T> || std::is_same_v<T, bool> || std::is_constructible_v<T, std::string>;
-class consumable(unconsumed) Configuration : private std::unordered_map<std::string, conf_value_t>
+class Configuration : private std::unordered_map<std::string, conf_value_t>
{
friend std::ostream &operator<<(std::ostream &out, const Configuration &obj);
public:
- return_typestate(unconsumed) Configuration();
- return_typestate(unconsumed) Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept;
+ using kv_pair = std::pair<std::string, conf_value_t>;
+
+ Configuration();
+ Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> p_list) noexcept;
Configuration(const Configuration &) = delete;
Configuration &operator=(const Configuration &) = delete;
- return_typestate(unconsumed) Configuration(Configuration && other param_typestate(unconsumed)) = default;
+ Configuration(Configuration &&other) = default;
Configuration &operator=(Configuration &&) = delete;
~Configuration() = default;
- callable_when(unconsumed) void read_file(const std::string &location);
- callable_when(unconsumed) void read(std::basic_istream<char> & input);
+ bool read_file(const std::string &location);
+ void read(std::basic_istream<char> &input);
template <typename T>
- callable_when(unconsumed) [[nodiscard]] std::optional<T> value(const char *path) const
+ [[nodiscard]] std::optional<T> value(const char *path, const std::source_location location = std::source_location::current()) const
{
if(use_global) {
- return instance()->value<T>(path);
+ return instance()->value<T>(path, location);
}
if(count(path) == 0) {
@@ -68,18 +60,19 @@ public:
}
template <concept_value_t T>
- callable_when(unconsumed) [[nodiscard]] std::optional<T> value(const char *path) const
+ [[nodiscard]] std::optional<T> value(const char *p_path, const std::source_location location = std::source_location::current()) const
{
if(use_global) {
- return instance()->value<T>(path);
+ return instance()->value<T>(p_path, location);
}
- if(this->count(path) == 0) {
+ if(this->count(p_path) == 0) {
+ spdlog::warn("requested non-existent configuration value {} at {}:{}", p_path, location.file_name(), location.line());
return std::nullopt;
}
// path is guaranteed to exist
- const auto value = at(path);
+ const auto value = at(p_path);
if(std::holds_alternative<int>(value)) {
if constexpr(std::is_arithmetic<T>::value) {
@@ -89,9 +82,11 @@ public:
}
} else if(std::holds_alternative<bool>(value)) {
- if constexpr(std::is_constructible<T, bool>::value) {
+ if constexpr(std::is_constructible_v<T, bool> || std::is_same_v<T, bool>) {
return std::get<bool>(value);
- } else if constexpr(std::is_constructible<T, const char *>::value) {
+ } else if constexpr(std::is_arithmetic_v<T>) {
+ return static_cast<T>(std::get<bool>(value));
+ } else if constexpr(std::is_constructible_v<T, const char *>) {
return std::get<bool>(value) ? T{ "true" } : T{ "false" };
}
@@ -99,7 +94,9 @@ public:
auto str = std::get<std::string>(value);
try {
- if constexpr(std::is_floating_point<T>::value) {
+ if constexpr(std::is_same_v<T, bool>) {
+ return (str == "true");
+ } else if constexpr(std::is_floating_point<T>::value) {
return static_cast<T>(std::stod(str));
} else if constexpr(std::is_arithmetic<T>::value) {
return static_cast<T>(std::stol(str));
@@ -121,13 +118,17 @@ public:
}
template <typename T>
- callable_when(unconsumed) T &shortcut(T & /* unused */, const char * /* unused */) const
+ T &shortcut(T & /* unused */, const char * /* unused */, const std::source_location location = std::source_location::current()) const
{
return T{};
}
+ static std::string init_global(const std::string &p_path);
static void move_global(std::unique_ptr<Configuration> && conf);
+protected:
+ void insert_or_assign(const kv_pair &pair);
+
private:
static Configuration *instance();
diff --git a/lib/configuration/gen-default-cfg.py b/lib/configuration/gen-default-cfg.py
new file mode 100755
index 0000000..5d9f8da
--- /dev/null
+++ b/lib/configuration/gen-default-cfg.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+import sys
+import argparse
+import yaml
+
+def v_to_str(value):
+ if type(value) is str:
+ return f"std::string(\"{value}\")"
+ if type(value) is int:
+ return value
+ if type(value) is bool:
+ return "true" if True else "false"
+
+def kv_pairs_to_str(section, pairs):
+ pairs_str = "\n".join([f" {{ \"{section}/{key}\", {v_to_str(pairs[key])} }}," for key in pairs])
+ return pairs_str
+
+def writeConfigInitList(config, file):
+ for node in config:
+ for section, pairs in node.items():
+ print(kv_pairs_to_str(section, pairs), file=file)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--config", type=argparse.FileType('r'), required=True, help="configuration yaml")
+ parser.add_argument("--template", type=argparse.FileType('r'), required=True, help="settings.h.in")
+ parser.add_argument("--output", type=argparse.FileType('w'), default=sys.stdout, help="Output location")
+ args = parser.parse_args()
+
+ config = yaml.safe_load(args.config)
+ print("config: ", config)
+
+ print("/* Autogenerated file", file=args.output)
+ print(" * config: {}".format(args.config), file=args.output)
+ print(" */", file=args.output)
+
+ for line in args.template:
+ if "@__DEFAULT_CFG__" in line:
+ writeConfigInitList(config, args.output)
+ else:
+ print(line, end='', file=args.output)
diff --git a/lib/configuration/init_global.cpp.in b/lib/configuration/init_global.cpp.in
new file mode 100644
index 0000000..9179130
--- /dev/null
+++ b/lib/configuration/init_global.cpp.in
@@ -0,0 +1,25 @@
+/*
+ * This is a generated file.
+ *
+ * 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.git
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#include "configuration.h"
+
+std::string Configuration::init_global(const std::string &p_path)
+{
+ auto value_map = std::make_unique<Configuration, std::initializer_list<std::pair<std::string, conf_value_t>>>({
+ /* @__DEFAULT_CFG__ */
+ });
+
+ // load the actual configuration file
+ const auto cfgpath = p_path.empty() ? value_map->value<std::string>("poi/config").value() : p_path;
+ value_map->read_file(cfgpath);
+
+ move_global(std::move(value_map));
+ return cfgpath;
+}
diff --git a/lib/configuration/qt_specialization.cpp b/lib/configuration/qt_specialization.cpp
index 8487e62..cd7a99a 100644
--- a/lib/configuration/qt_specialization.cpp
+++ b/lib/configuration/qt_specialization.cpp
@@ -1,36 +1,39 @@
#include "configuration.h"
-#include <stdexcept>
template <>
-callable_when(unconsumed) [[nodiscard]] std::optional<QString> Configuration::value(const char *path) const
+[[nodiscard]] std::optional<QString> Configuration::value(const char *path, std::source_location location) const
{
- const auto v = value<std::string>(path);
- return v ? std::make_optional(QString::fromStdString(v.value())) : std::nullopt;
+ const auto result = value<std::string>(path, location);
+ return result ? std::make_optional(QString::fromStdString(result.value())) : std::nullopt;
}
template <>
-callable_when(unconsumed) [[nodiscard]] std::optional<QStringList> Configuration::value(const char *path) const
+[[nodiscard]] std::optional<QStringList> Configuration::value(const char *path, std::source_location location) const
{
- const auto v = value<std::string>(path);
- return v ? std::make_optional(QString::fromStdString(v.value()).split(';')) : std::nullopt;
+ const auto result = value<std::string>(path, location);
+ return result ? std::make_optional(QString::fromStdString(result.value()).split(';')) : std::nullopt;
}
template <>
-callable_when(unconsumed) QAction &Configuration::shortcut(QAction &action, const char *name) const
+QAction &Configuration::shortcut(QAction &action, const char *name, const std::source_location location) const
{
- if(const auto shortcut = value<QString>(name)) {
+ if(const auto result = value<QString>(name, location)) {
const QString old_tooltip = action.toolTip();
- action.setShortcut(QKeySequence::fromString(shortcut.value()));
- action.setToolTip(QString("%1 (%2)").arg(old_tooltip, shortcut.value()));
+ const auto &result_value = result.value();
+
+ action.setShortcut(QKeySequence::fromString(result_value));
+ action.setToolTip(QString("%1 (%2)").arg(old_tooltip, result_value));
}
return action;
}
template <>
-callable_when(unconsumed) QKeySequence &Configuration::shortcut(QKeySequence &sequence, const char *name) const
+QKeySequence &Configuration::shortcut(QKeySequence &sequence, const char *name, const std::source_location location) const
{
- if(const auto shortcut = value<QString>(name)) {
- sequence = QKeySequence::fromString(shortcut.value());
+ if(const auto result = value<QString>(name, location)) {
+ const auto &result_value = result.value();
+
+ sequence = QKeySequence::fromString(result_value);
}
return sequence;
}
diff --git a/lib/configuration/qt_specialization.h b/lib/configuration/qt_specialization.h
index 9634261..26f9593 100644
--- a/lib/configuration/qt_specialization.h
+++ b/lib/configuration/qt_specialization.h
@@ -5,11 +5,11 @@
#include <QStringList>
template <>
-callable_when(unconsumed) [[nodiscard]] std::optional<QString> Configuration::value(const char *path) const;
+[[nodiscard]] std::optional<QString> Configuration::value(const char *path, std::source_location location) const;
template <>
-callable_when(unconsumed) [[nodiscard]] std::optional<QStringList> Configuration::value(const char *path) const;
+[[nodiscard]] std::optional<QStringList> Configuration::value(const char *path, std::source_location location) const;
template <>
-callable_when(unconsumed) QAction &Configuration::shortcut(QAction &, const char *) const;
+QAction &Configuration::shortcut(QAction &, const char *, const std::source_location) const;
template <>
-callable_when(unconsumed) QKeySequence &Configuration::shortcut(QKeySequence &, const char *) const;
+QKeySequence &Configuration::shortcut(QKeySequence &, const char *, const std::source_location) const;
diff --git a/lib/configuration/test/configuration.cpp b/lib/configuration/test/configuration.cpp
new file mode 100644
index 0000000..0796c11
--- /dev/null
+++ b/lib/configuration/test/configuration.cpp
@@ -0,0 +1,57 @@
+#include "configuration.h"
+#include <gtest/gtest.h>
+
+TEST(Configuration, ctor_empty_initializer_list)
+{
+ Configuration conf({});
+
+ std::cout << conf;
+}
+
+TEST(Configuration, ctor_initializer_list)
+{
+ Configuration conf({
+ { "some_string", "value1" },
+ { "some_bool", true },
+ { "some_int", 42 },
+ });
+
+ // operator<< should not throw exceptions
+ std::cout << conf;
+
+ EXPECT_EQ(*conf.value<std::string>("some_string"), "value1");
+ EXPECT_EQ(*conf.value<bool>("some_bool"), true);
+ EXPECT_EQ(*conf.value<int>("some_int"), 42);
+
+ EXPECT_FALSE(conf.value<int>("no_int"));
+}
+
+TEST(Configuration, read_file)
+{
+ // because the init_list is empty, all types are strings
+ Configuration conf({});
+
+ EXPECT_TRUE(conf.read_file("defaultrc.ini"));
+
+ std::cout << "---------\n";
+ std::cout << conf;
+ std::cout << "---------\n";
+
+ // defaultrc.ini contents
+ EXPECT_EQ(*conf.value<std::string>("name"), "Top level");
+ EXPECT_FALSE(conf.value<std::string>("comment"));
+
+ EXPECT_EQ(*conf.value<std::string>("main/name"), "Section Testing");
+
+ // casting a string to an integer
+ EXPECT_EQ(*conf.value<int>("number"), 12);
+
+ // casting a string to a boolean
+ EXPECT_EQ(*conf.value<std::string>("toggle"), "true");
+ EXPECT_EQ(*conf.value<bool>("toggle"), true);
+ EXPECT_EQ(*conf.value<bool>("main/toggle"), false);
+
+ // extrarc.ini contents
+ EXPECT_EQ(*conf.value<std::string>("over"), "extra");
+ EXPECT_EQ(*conf.value<std::string>("extra/name"), "extra section");
+}
diff --git a/lib/downloads/CMakeLists.txt b/lib/downloads/CMakeLists.txt
new file mode 100644
index 0000000..b310e3a
--- /dev/null
+++ b/lib/downloads/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(downloads STATIC
+ downloadsform.ui
+ downloadswidget.cpp downloadswidget.h
+ widgets/downloaditemform.ui widgets/downloaditemwidget.cpp widgets/downloaditemwidget.h
+ widgets/elidedlabel.cpp widgets/elidedlabel.h
+)
+target_link_libraries(downloads PUBLIC Qt6::Widgets Qt6::WebEngineWidgets)
+target_include_directories(downloads PUBLIC ${CMAKE_CURRENT_LIST_DIR})
diff --git a/lib/downloads/downloadswidget.cpp b/lib/downloads/downloadswidget.cpp
index 02ed08a..2f192e9 100644
--- a/lib/downloads/downloadswidget.cpp
+++ b/lib/downloads/downloadswidget.cpp
@@ -28,7 +28,7 @@ DownloadsWidget::~DownloadsWidget()
delete ui;
}
-void DownloadsWidget::addDownload(QWebEngineDownloadItem *item)
+void DownloadsWidget::addDownload(QWebEngineDownloadRequest *item)
{
const QString filepath = QFileDialog::getSaveFileName(this, tr("Save File"), m_downloadPath + "/" + item->downloadFileName());
diff --git a/lib/downloads/downloadswidget.h b/lib/downloads/downloadswidget.h
index eb4ce57..d0aa2b4 100644
--- a/lib/downloads/downloadswidget.h
+++ b/lib/downloads/downloadswidget.h
@@ -10,7 +10,7 @@
#define SMOLBOTE_DOWNLOADDIALOG_H
#include <QDialog>
-#include <QWebEngineDownloadItem>
+#include <QWebEngineDownloadRequest>
namespace Ui
{
@@ -26,7 +26,7 @@ public:
~DownloadsWidget() override;
public slots:
- void addDownload(QWebEngineDownloadItem *item);
+ void addDownload(QWebEngineDownloadRequest *item);
private:
Ui::DownloadDialog *ui;
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..169ba6f 100644
--- a/lib/downloads/widgets/downloaditemwidget.cpp
+++ b/lib/downloads/widgets/downloaditemwidget.cpp
@@ -30,7 +30,7 @@ inline QString sizeString(qint64 size)
return QString("%1 GB").arg(size / (1024 * 1024 * 1024));
}
-DownloadItemWidget::DownloadItemWidget(QWebEngineDownloadItem *m_item, QWidget *parent)
+DownloadItemWidget::DownloadItemWidget(QWebEngineDownloadRequest *m_item, QWidget *parent)
: QWidget(parent)
, ui(new Ui::DownloadItemForm)
{
@@ -51,11 +51,11 @@ DownloadItemWidget::DownloadItemWidget(QWebEngineDownloadItem *m_item, QWidget *
ui->path_label->setText(QString("%1<br>%2").arg(item->downloadDirectory(), item->downloadFileName()));
this->updateState(item->state());
- connect(item, &QWebEngineDownloadItem::stateChanged, this, &DownloadItemWidget::updateState);
- connect(item, &QWebEngineDownloadItem::downloadProgress, this, &DownloadItemWidget::updateProgress);
- connect(item, &QWebEngineDownloadItem::finished, this, &DownloadItemWidget::updateFinished);
+ connect(item, &QWebEngineDownloadRequest::stateChanged, this, &DownloadItemWidget::updateState);
+ connect(item, &QWebEngineDownloadRequest::receivedBytesChanged, this, &DownloadItemWidget::updateProgress);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, this, &DownloadItemWidget::updateFinished);
- connect(ui->abort_toolButton, &QToolButton::clicked, item, &QWebEngineDownloadItem::cancel);
+ connect(ui->abort_toolButton, &QToolButton::clicked, item, &QWebEngineDownloadRequest::cancel);
connect(ui->pause_toolButton, &QToolButton::clicked, item, [m_item](bool clicked) {
clicked ? m_item->pause() : m_item->resume();
});
@@ -69,34 +69,34 @@ DownloadItemWidget::~DownloadItemWidget()
delete ui;
}
-void DownloadItemWidget::updateState(QWebEngineDownloadItem::DownloadState state)
+void DownloadItemWidget::updateState(QWebEngineDownloadRequest::DownloadState state)
{
switch(state) {
- case QWebEngineDownloadItem::DownloadRequested:
+ case QWebEngineDownloadRequest::DownloadRequested:
ui->status_label->setText(tr("Requested"));
ui->pause_toolButton->setEnabled(true);
ui->abort_toolButton->setEnabled(true);
ui->open_toolButton->setEnabled(false);
break;
- case QWebEngineDownloadItem::DownloadInProgress:
+ case QWebEngineDownloadRequest::DownloadInProgress:
ui->status_label->setText(tr("In progress"));
ui->pause_toolButton->setEnabled(true);
ui->abort_toolButton->setEnabled(true);
ui->open_toolButton->setEnabled(false);
break;
- case QWebEngineDownloadItem::DownloadCompleted:
+ case QWebEngineDownloadRequest::DownloadCompleted:
ui->status_label->setText(tr("Completed"));
ui->pause_toolButton->setEnabled(false);
ui->abort_toolButton->setEnabled(false);
ui->open_toolButton->setEnabled(true);
break;
- case QWebEngineDownloadItem::DownloadCancelled:
+ case QWebEngineDownloadRequest::DownloadCancelled:
ui->status_label->setText(tr("Cancelled"));
ui->pause_toolButton->setEnabled(false);
ui->abort_toolButton->setEnabled(false);
ui->open_toolButton->setEnabled(false);
break;
- case QWebEngineDownloadItem::DownloadInterrupted:
+ case QWebEngineDownloadRequest::DownloadInterrupted:
ui->status_label->setText(tr("Interrupted"));
ui->pause_toolButton->setEnabled(false);
ui->abort_toolButton->setEnabled(false);
@@ -107,8 +107,11 @@ void DownloadItemWidget::updateState(QWebEngineDownloadItem::DownloadState state
}
}
-void DownloadItemWidget::updateProgress(qint64 value, qint64 total)
+void DownloadItemWidget::updateProgress()
{
+ const auto value = item->receivedBytes();
+ const auto total = item->totalBytes();
+
ui->progressBar->setValue(static_cast<int>((static_cast<long double>(value) / static_cast<long double>(total)) * 100));
ui->progressBar->setFormat(QString("%1 / %2").arg(sizeString(value), sizeString(total)));
}
diff --git a/lib/downloads/widgets/downloaditemwidget.h b/lib/downloads/widgets/downloaditemwidget.h
index a1de175..5d540a3 100644
--- a/lib/downloads/widgets/downloaditemwidget.h
+++ b/lib/downloads/widgets/downloaditemwidget.h
@@ -9,7 +9,7 @@
#ifndef SMOLBOTE_DOWNLOADITEMFORM_H
#define SMOLBOTE_DOWNLOADITEMFORM_H
-#include <QWebEngineDownloadItem>
+#include <QWebEngineDownloadRequest>
#include <QWidget>
namespace Ui
@@ -22,17 +22,17 @@ class DownloadItemWidget : public QWidget
Q_OBJECT
public:
- explicit DownloadItemWidget(QWebEngineDownloadItem *m_item, QWidget *parent = 0);
+ explicit DownloadItemWidget(QWebEngineDownloadRequest *m_item, QWidget *parent = 0);
~DownloadItemWidget() override;
private slots:
- void updateState(QWebEngineDownloadItem::DownloadState state);
- void updateProgress(qint64 value, qint64 total);
+ void updateState(QWebEngineDownloadRequest::DownloadState state);
+ void updateProgress();
void updateFinished();
private:
Ui::DownloadItemForm *ui;
- QWebEngineDownloadItem *item = nullptr;
+ QWebEngineDownloadRequest *item = nullptr;
};
#endif // SMOLBOTE_DOWNLOADITEMFORM_H
diff --git a/lib/pluginloader/CMakeLists.txt b/lib/pluginloader/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/pluginloader/CMakeLists.txt
diff --git a/lib/session_formats/CMakeLists.txt b/lib/session_formats/CMakeLists.txt
new file mode 100644
index 0000000..c043559
--- /dev/null
+++ b/lib/session_formats/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_library(session_formats STATIC
+ session_json.cpp session_json.hpp
+)
+target_link_libraries(session_formats PUBLIC Qt6::Core)
+target_include_directories(session_formats PUBLIC ${CMAKE_CURRENT_LIST_DIR} ${PROJECT_SOURCE_DIR}/include)
diff --git a/lib/urlfilter/CMakeLists.txt b/lib/urlfilter/CMakeLists.txt
new file mode 100644
index 0000000..012839d
--- /dev/null
+++ b/lib/urlfilter/CMakeLists.txt
@@ -0,0 +1,27 @@
+add_library(urlfilter STATIC
+ matcher.h urlfilter.h
+ adblock/adblocklist.cpp adblock/adblocklist.h
+ adblock/parser.cpp adblock/parser.h
+ hostlist/hostlist.cpp hostlist/hostlist.h
+)
+target_link_libraries(urlfilter PUBLIC Qt6::WebEngineCore)
+target_include_directories(urlfilter PUBLIC ${CMAKE_CURRENT_LIST_DIR})
+
+
+add_executable(test_urlfilter_matcher test/matcher.cpp)
+target_link_libraries(test_urlfilter_matcher PUBLIC urlfilter GTest::gtest_main)
+gtest_add_tests(TARGET test_urlfilter_matcher
+ SOURCES test/matcher.cpp
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/test)
+
+add_executable(test_urlfilter_hostlist test/hostlist.cpp)
+target_link_libraries(test_urlfilter_hostlist PUBLIC urlfilter GTest::gtest_main)
+gtest_add_tests(TARGET test_urlfilter_hostlist
+ SOURCES test/hostlist.cpp
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/test)
+
+add_executable(test_urlfilter_adblock test/adblock.cpp)
+target_link_libraries(test_urlfilter_adblock PUBLIC urlfilter GTest::gtest_main)
+gtest_add_tests(TARGET test_urlfilter_adblock
+ SOURCES test/adblock.cpp
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/test)
diff --git a/lib/urlfilter/meson.build b/lib/urlfilter/meson.build
deleted file mode 100644
index 2591028..0000000
--- a/lib/urlfilter/meson.build
+++ /dev/null
@@ -1,26 +0,0 @@
-urlfilter_lib = static_library('urlfilter',
- ['urlfilter.h', 'matcher.h',
- 'hostlist/hostlist.cpp', 'hostlist/hostlist.h',
- 'adblock/adblocklist.cpp', 'adblock/adblocklist.h', 'adblock/parser.cpp', 'adblock/parser.h'],
- dependencies: dep_qt5
-)
-
-dep_urlfilter = declare_dependency(
- include_directories: include_directories('.'),
- link_with: urlfilter_lib
-)
-
-if dep_gtest.found()
- test('urlfilter: matcher',
- executable('urlfilter-matcher', dependencies: [dep_qt5, dep_gtest, dep_urlfilter], sources: ['test/matcher.cpp']),
- workdir: meson.current_source_dir() / 'test'
- )
- test('urlfilter: host list',
- executable('urlfilter-hostlist', dependencies: [dep_qt5, dep_gtest, dep_urlfilter], sources: ['test/hostlist.cpp']),
- workdir: meson.current_source_dir() / 'test'
- )
- test('urlfilter: adblock list',
- executable('urlfilter-adblocklist', dependencies: [dep_qt5, dep_gtest, dep_urlfilter], sources: ['test/adblock.cpp']),
- workdir: meson.current_source_dir() / 'test'
- )
-endif
diff --git a/linux/.config b/linux/.config
new file mode 100644
index 0000000..2fb8236
--- /dev/null
+++ b/linux/.config
@@ -0,0 +1,111 @@
+
+#
+# Application
+#
+CONFIG_POI_NAME="smolbote"
+CONFIG_POI_ICON=":/icons/poi.svg"
+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.close="Ctrl+Shift+W"
+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="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/config.yaml b/linux/config.yaml
new file mode 100644
index 0000000..38e6e6e
--- /dev/null
+++ b/linux/config.yaml
@@ -0,0 +1,63 @@
+---
+- poi:
+ name: smolbote
+ icon: :/icons/poi.svg
+ config: ~/.config/smolbote/smolbote.cfg
+
+- shortcuts:
+ session.save: Ctrl+S,S
+ session.open: Ctrl+S,O
+
+ window.newgroup: Ctrl+G
+ window.newwindow: Ctrl+N
+ window.about: F1
+ window.quit: Ctrl+Q
+ window.search: F3
+ window.bookmarks.show: Ctrl+B
+ window.downloads.show: Ctrl+D
+
+ navigationbar.show: Ctrl+Shift+N
+ navigation.back: Ctrl+Left
+ navigation.backmenu: Ctrl+Down
+ navigation.forward: Ctrl+Right
+ navigation.forwardmenu: Ctrl+Up
+ navigation.refresh: F5
+ navigation.reload: Ctrl+F5
+ navigation.home: Ctrl+Home
+
+ address.focus: F4
+ address.menu: F2
+
+ subwindow.close: Ctrl+Shift+W
+ subwindow.fullscreen: F11
+ subwindow.newtab: Ctrl+T
+ subwindow.closetab: Ctrl+W
+ subwindow.restoretab: Ctrl+Shift+T
+ subwindow.tableft: Ctrl+O
+ subwindow.movetableft: Ctrl+Shift+O
+ subwindow.tabright: Ctrl+P
+ subwindow.movetabright: Ctrl+Shift+P
+
+- mainwindow:
+ title: smolbote
+ width: 1280
+ height: 720
+
+- bookmarks:
+ path: ~/.config/smolbote/bookmarks.xbel
+ toolbar.show: Ctrl+Shift+B
+ toolbar.movable: false
+ toolbar.visible: true
+
+- downloads:
+ path: ~/Downloads
+
+- profile:
+ path: ~/.config/smolbote/profiles.d
+ default: default
+ search: https://duckduckgo.com/?q=%1&ia=web
+ homepage: about:blank
+ newtab: about:blank
+
+- session:
+ path: ~/.config/smolbote/session.d
diff --git a/linux/firejail/poi.profile b/linux/firejail/poi.profile
index a7d3005..1a644d7 100644
--- a/linux/firejail/poi.profile
+++ b/linux/firejail/poi.profile
@@ -1,21 +1,22 @@
# Firejail profile for poi
# This file is overwritten after every install/update
# Persistent local customizations
-include /etc/firejail/poi.local
+include poi.local
# Persistent global definitions
-include /etc/firejail/globals.local
+include globals.local
# noblacklist: exclude from blacklist
noblacklist ${HOME}/.cache/smolbote
noblacklist ${HOME}/.config/smolbote
noblacklist ${HOME}/.local/share/smolbote
-include /etc/firejail/disable-common.inc
-include /etc/firejail/disable-devel.inc
-include /etc/firejail/disable-interpreters.inc
-include /etc/firejail/disable-passwdmgr.inc
-include /etc/firejail/disable-programs.inc
-include /etc/firejail/disable-xdg.inc
+include disable-common.inc
+include disable-devel.inc
+include disable-exec.inc
+include disable-interpreters.inc
+include disable-passwdmgr.inc
+include disable-programs.inc
+include disable-xdg.inc
mkdir ${HOME}/.cache/smolbote
mkdir ${HOME}/.config/smolbote
@@ -25,7 +26,7 @@ whitelist ${DOWNLOADS}
whitelist ${HOME}/.cache/smolbote
whitelist ${HOME}/.config/smolbote
whitelist ${HOME}/.local/share/smolbote
-include /etc/firejail/whitelist-common.inc
+include whitelist-common.inc
## caps.drop all - Removes the ability to call programs usually run only by root. Ex - chown, setuid
@@ -43,7 +44,9 @@ caps.drop all
netfilter
## nodbus - Disable access to dbus.
-nodbus
+#nodbus
+dbus-user none
+dbus-system none
## nodvd - Disable access to optical disk drives.
nodvd
@@ -60,6 +63,9 @@ noroot
## notv - Disable access to DVB TV devices.
notv
+## nou2f - Disable access to U2F devices.
+nou2f
+
# novideo - Disable access to video devices.
novideo
@@ -67,20 +73,16 @@ novideo
protocol unix,inet,inet6,netlink
## seccomp - Blacklists a large swath of syscalls from being accessible.
-#seccomp
-## Use seccomp.drop for now as seccomp is broken with many programs.
-seccomp.drop @clock,@cpu-emulation,@module,@obsolete,@privileged,@raw-io,@reboot,@resources,@swap,ptrace
-# QtWebEngine require chroot syscall on AMD CPUS and/or ATI Graphics for some bizarre reason
-# Use the following seccomp.drop instead on such systems.
-#seccomp.drop @clock,@cpu-emulation,@module,@obsolete,@raw-io,@reboot,@resources,@swap,ptrace,mount,umount2,pivot_root
+# QtWebEngine requires chroot syscall on AMD and ATI Graphics for some bizarre reason
+seccomp !name_to_handle_at,!chroot
## shell - Run the program directly, without a user shell.
# breaks secondary instances when using join-or-start after shell=none
-#shell none
+shell none
## tracelog - Log all viloations to syslog.
-# tracelog segfaults QtWebEngine on AMD CPUS and/or ATI Graphics for some bizarre reason
-tracelog
+# tracelog segfaults QtWebEngine on AMD and ATI Graphics for some bizarre reason
+#tracelog
## disable-mnt - Deny access to /mnt, /media, /run/mount, and /run/media
disable-mnt
@@ -88,7 +90,7 @@ disable-mnt
## private-bin - Creates a virtual /bin directory containing only temporary copies of the following executables.
# bash required to launch from kde kickoff menu
# breaks if installed to /usr/local
-#private-bin bash,poi
+private-bin bash,poi
## private-dev - Create a virtual /dev directory. Only dri, null, full, zero, tty, pts, ptmx, random, snd, urandom, video, log and shm devices are available.
private-dev
@@ -101,12 +103,6 @@ private-etc fonts,group,machine-id,resolv.conf
# breaks SingleApplication without join-or-start set
private-tmp
-
-## noexec - Prevent execution of files in the specified locations
-noexec ${HOME}
-noexec /tmp
-
-
# join-or-start - Join the sandbox identified by name or start a new one
join-or-start poi
diff --git a/linux/makepkg/PKGBUILD b/linux/makepkg/PKGBUILD
index 5e27542..efdea15 100644
--- a/linux/makepkg/PKGBUILD
+++ b/linux/makepkg/PKGBUILD
@@ -1,53 +1,43 @@
# Maintainer: Aqua-sama <aqua at iserlohn-fortress dot net>
## not-use flags
-# Enable plugin signing:
-_signPlugins=0
-# Enable breakpad integraton:
-_enableBreakpad=0
# install prefix
-_prefix='/usr/local'
+_prefix='/usr'
pkgname=smolbote-git
pkgdesc='Yet another no-frills browser'
pkgver=0
pkgrel=1
-url="https://neueland.iserlohn-fortress.net/gitea/smolbote"
+url="https://neueland.iserlohn-fortress.net/cgit/smolbote"
install="smolbote.install"
arch=('x86_64' 'aarch64')
license=('GPL3')
-depends=('qt5-webengine>=5.11.0' 'spdlog')
-makedepends=('git' 'meson' 'python-kconfiglib' 'openssl' 'qt5-tools' 'scdoc' 'catch2')
-if [ $_enableBreakpad == "1" ]; then
- makedepends+=('breakpad-git')
-fi
+depends=('qt6-svg' 'qt6-webengine' 'spdlog' 'fmt')
+makedepends=('git' 'cmake' 'openssl' 'qt6-tools' 'scdoc')
optdepends=('firejail: launch a sandboxed instance')
-# this isn't a hard requirement, simply a workaround as the build script
-# sets some additional hardening flags that the default makepkg.conf
-# will turn down
-options=(!buildflags)
-
# use git+file:///path/to/your/repo to build from a local repo
-source=("git+https://library.iserlohn-fortress.net/aqua/smolbote.git"
- "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})
+source=("git+https://neueland.iserlohn-fortress.net/cgit/smolbote"
+ "SingleApplication-v3.4.1.tar.gz::https://github.com/itay-grudev/SingleApplication/archive/refs/tags/v3.4.1.tar.gz")
b2sums=('SKIP'
- 'cec3de8dbf252bfa6dc488e5a1440695f4dd3abffdf30948b7d1a3df3d9c85911e981c802ed5a882f1407315114529f4016e55c7d05fbbd1dafe5495b0a63f4a'
- 'SKIP'
- '440e357006883fbf1b1a796051500a6b068858a35947cd1119767bed8e0a86a7db4aff16498934d7217c375fe643da03c22007e438f30899e247153f25c922b6'
- 'SKIP')
+ 'fe320ccb0390b13b1c7b0c017cff34b02f5138bd6643457843a7200374c8a994a37a1b00a65c70e83ba5bdc61f157ccfaa8cdfc0eee7b2149df4acda06173669')
-validgpgkeys=(BB1C090188E3E32B375C13FD095DE26BC16D2E98) # Aqua-sama <aqua@iserlohn-fortress.net>
+validpgpkeys=(BB1C090188E3E32B375C13FD095DE26BC16D2E98) # Aqua-sama <aqua@iserlohn-fortress.net>
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/"
+ msg2 "Populate third_party packages..."
+ mkdir "$srcdir/smolbote/third_party"
+ ln -s "$srcdir/SingleApplication-3.4.1" "$srcdir/smolbote/third_party/SingleApplication"
+
+ msg2 "Configure..."
+ cmake -S $srcdir/smolbote -B $srcdir/build \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX=/usr \
+ -DINSTALL_MANPAGES=ON
}
pkgver() {
@@ -57,61 +47,15 @@ pkgver() {
}
build() {
- mkdir -p $srcdir/build
- cd $srcdir/smolbote
- KCONFIG_CONFIG=linux/.config alldefconfig
-
- # 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 --buildtype=release --wrap-mode=nodownload \
- --prefix=$_prefix --auto-features=disabled \
- -Db_pie=true -Ddefault_library=static \
- -Dmanpage=enabled \
- $srcdir/build
-
- if [ $_enableBreakpad == "1" ]; then
- msg2 "Enabling crashhandler"
- meson configure -Ddebug=true -Dcrashhandler=enabled
- KCONFIG_CONFIG=linux/.config setconfig USEBREAKPAD=y
- fi
-
- # Run menuconfig
- #KCONFIG_CONFIG=linux/.config menuconfig
-
- # Build
- ninja -C $srcdir/build "$MAKEFLAGS"
+ cmake --build $srcdir/build -- ${MAKEFLAGS}
+ cmake --build $srcdir/build --target manpages -- ${MAKEFLAGS}
}
check() {
- ninja -C $srcdir/build test
+ ctest --test-dir $srcdir/build
}
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
+ DESTDIR="$pkgdir" cmake --install $srcdir/build --strip
}
diff --git a/meson.build b/meson.build
deleted file mode 100644
index bc72ff3..0000000
--- a/meson.build
+++ /dev/null
@@ -1,147 +0,0 @@
-project('smolbote', ['cpp'],
- version: '0.1.0',
- default_options: ['cpp_std=c++2a', 'warning_level=3'],
- license: 'GPL3',
- meson_version: '>=0.52.0'
-)
-
-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: 'include/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')
-
-if get_option('buildtype') == 'release'
- add_project_arguments(cxx.get_supported_arguments([
- '-flto=4',
- ]), language: 'cpp')
-endif
-
-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'))
-if dep_breakpad.found()
- poi_cpp_args += '-DHAVE_BREAKPAD'
-endif
-
-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') # plugin interaces
-
-subdir('lib/bookmarks')
-subdir('lib/configuration')
-subdir('lib/downloads')
-subdir('lib/pluginloader')
-subdir('lib/urlfilter')
-subdir('lib/session_formats')
-
-subdir('src')
-subdir('lang')
-subdir('doc')
-subdir('tools')
-
-subdir('plugins/ProfileEditor')
-
-subdir('test/firefox-bookmarks-json-parser')
-
-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, dep_urlfilter, 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/scripts/gen-default-cfg.py b/scripts/gen-default-cfg.py
deleted file mode 100755
index dc88ceb..0000000
--- a/scripts/gen-default-cfg.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-import argparse
-import kconfiglib
-
-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 + ")"
- elif(node.item.type == kconfiglib.BOOL):
- tri_val_str = ("false", "unknown", "true")[node.item.tri_value]
- return "bool(" + tri_val_str + ")"
-
- return None
-
-def writeItem(node, file):
- while node:
- if isinstance(node.item, kconfiglib.Symbol):
- name = node.item.name.lower().replace('_', '.')
- print("\t{ \"" + name + "\", " + node_to_str(node) + " },", file=file)
-
- if node.list:
- writeItem(node.list, file)
-
- 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="settings.h.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)
-
- print("/* Autogenerated file", file=args.output)
- print(" * kconfig: {}".format(args.kconfig), file=args.output)
- print(" * dotconfig: {}".format(args.dotconfig), file=args.output)
- print(" */", file=args.output)
-
- for line in args.input:
- if "@__DEFAULT_CFG__" in line:
- writeItem(kconf.top_node.list, 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..f80dbc7
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,69 @@
+# version.h
+configure_file(version.h.in version.h)
+
+add_executable(poi
+ applicationmenu.cpp
+ applicationmenu.h
+ bookmarks/bookmarksform.ui
+ bookmarks/bookmarkstoolbar.cpp
+ bookmarks/bookmarkstoolbar.h
+ bookmarks/bookmarkswidget.cpp
+ bookmarks/bookmarkswidget.h
+ #bookmarks/builtins.cpp
+ bookmarks/editbookmarkdialog.cpp
+ bookmarks/editbookmarkdialog.h
+ bookmarks/editbookmarkdialog.ui
+ browser.cpp
+ browser.h
+ #builtins.cpp
+ #builtins.h
+ #crashhandler.cpp
+ #crashhandler.h
+ #crashhandler_dummy.cpp
+ main.cpp
+ mainwindow/addressbar.cpp
+ mainwindow/addressbar.h
+ mainwindow/addressbar.ui
+ mainwindow/mainwindow.cpp
+ mainwindow/mainwindow.h
+ mainwindow/menubar.cpp
+ mainwindow/menubar.h
+ mainwindow/widgets/completer.cpp
+ mainwindow/widgets/completer.h
+ mainwindow/widgets/dockwidget.cpp
+ mainwindow/widgets/dockwidget.h
+ mainwindow/widgets/menusearch.cpp
+ mainwindow/widgets/menusearch.h
+ mainwindow/widgets/navigationbar.cpp
+ mainwindow/widgets/navigationbar.h
+ mainwindow/widgets/searchform.cpp
+ mainwindow/widgets/searchform.h
+ mainwindow/widgets/searchform.ui
+ mainwindow/widgets/urllineedit.cpp
+ mainwindow/widgets/urllineedit.h
+ session/savesessiondialog.cpp
+ session/savesessiondialog.h
+ session/savesessiondialog.ui
+ session/sessiondialog.cpp
+ session/sessiondialog.h
+ session/sessiondialog.ui
+ subwindow/subwindow.cpp
+ subwindow/subwindow.h
+ subwindow/tabwidget.cpp
+ subwindow/tabwidget.h
+ util.cpp
+ util.h
+ wallet/wallet.cpp
+ wallet/wallet.h
+
+ # resources
+ ${PROJECT_SOURCE_DIR}/data/resources.qrc
+)
+target_include_directories(poi PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+target_enable_warnings(poi)
+target_link_libraries(poi
+ PRIVATE SingleApplication::SingleApplication spdlog::spdlog
+ PRIVATE bookmarks configuration downloads session_formats urlfilter
+ PRIVATE about webengine
+)
+
diff --git a/src/about/CMakeLists.txt b/src/about/CMakeLists.txt
new file mode 100644
index 0000000..f1e2c41
--- /dev/null
+++ b/src/about/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_library(about STATIC
+ aboutdialog.cpp aboutdialog.h aboutdialog.ui
+ aboutplugin.cpp aboutplugin.h aboutplugin.ui
+)
+target_link_libraries(about PUBLIC Qt6::Widgets Qt6::SvgWidgets)
+target_include_directories(about PUBLIC ${CMAKE_CURRENT_LIST_DIR})
+
+# tests
+add_executable(test_about test/main.cpp)
+target_link_libraries(test_about PRIVATE about)
+add_test(NAME about_dialog COMMAND $<TARGET_FILE:test_about> -platform offscreen)
+set_property(TEST about_dialog PROPERTY ENVIRONMENT autoclose=1)
diff --git a/src/about/aboutdialog.cpp b/src/about/aboutdialog.cpp
index 894b1ec..1013866 100644
--- a/src/about/aboutdialog.cpp
+++ b/src/about/aboutdialog.cpp
@@ -8,7 +8,6 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
-#include <version.h>
// compiler
// clang also defines __GNUC__, so we need to check for clang first
@@ -59,7 +58,7 @@ 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 %1</p>"
"<p>Compiled with " compiler "</p>"
"<p>Libraries: <ul>"
"<li><a href='https://www.qt.io/'>Qt5</a> " QT_VERSION_STR "</li>"
@@ -69,7 +68,8 @@ AboutDialog::AboutDialog(QWidget *parent)
#ifdef CONFIG_USEBREAKPAD
"<li><a href='https://chromium.googlesource.com/breakpad/breakpad'>Breakpad</a></li>"
#endif
- "</ul></p>"));
+ "</ul></p>")
+ .arg(qApp->applicationVersion()));
}
AboutDialog::~AboutDialog()
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/applicationmenu.cpp b/src/applicationmenu.cpp
index dc888e7..aff5576 100644
--- a/src/applicationmenu.cpp
+++ b/src/applicationmenu.cpp
@@ -22,31 +22,31 @@ ApplicationMenu::ApplicationMenu(Browser *app, QWidget *parent)
setTitle(qApp->applicationName());
Configuration conf;
- const auto sessionPath = conf.value<QString>("session.path").value();
+ const auto sessionPath = conf.value<QString>("session/path").value();
auto *actionSaveSession = addAction(tr("Save Session"), this, [sessionPath]() {
auto *sessionDialog = new SaveSessionDialog(nullptr);
if(sessionDialog->exec() == QDialog::Accepted) {
sessionDialog->save(sessionPath);
}
});
- conf.shortcut<QAction>(*actionSaveSession, "shortcuts.session.save");
+ conf.shortcut<QAction>(*actionSaveSession, "shortcuts/session.save");
auto *actionOpenSession = addAction(tr("Open Session"), this, []() {
auto *sessionDialog = new SessionDialog(nullptr);
sessionDialog->exec();
});
- conf.shortcut<QAction>(*actionOpenSession, "shortcuts.session.open");
+ conf.shortcut<QAction>(*actionOpenSession, "shortcuts/session.open");
bottom_pluginSeparator = addSeparator();
auto *actionAbout = addAction(tr("About"), app, &Browser::about);
- conf.shortcut<QAction>(*actionAbout, "shortcuts.window.about");
+ conf.shortcut<QAction>(*actionAbout, "shortcuts/window.about");
auto *action_aboutPlugins = addAction(tr("About Plugins"), app, &Browser::aboutPlugins);
- conf.shortcut(*action_aboutPlugins, "app.shortcuts.about.plugins");
+ conf.shortcut(*action_aboutPlugins, "shortcuts/about.plugins");
auto *actionQuit = addAction(tr("Quit"), app, &Browser::quit);
- conf.shortcut<QAction>(*actionQuit, "shortcuts.window.quit");
+ conf.shortcut<QAction>(*actionQuit, "shortcuts/window.quit");
}
void ApplicationMenu::addPlugin(QPluginLoader *plugin)
diff --git a/src/bookmarks/bookmarkstoolbar.cpp b/src/bookmarks/bookmarkstoolbar.cpp
index 52dcae2..3174874 100644
--- a/src/bookmarks/bookmarkstoolbar.cpp
+++ b/src/bookmarks/bookmarkstoolbar.cpp
@@ -18,10 +18,10 @@ BookmarksToolbar::BookmarksToolbar(const BookmarkModel *model, MainWindow *paren
m_window = parent;
Configuration conf;
- setObjectName("bookmarks.toolbar");
+ setObjectName("bookmarks/toolbar");
setWindowTitle(tr("Bookmarks Toolbar"));
- setMovable(conf.value<bool>("bookmarks.toolbar.movable").value());
- setVisible(conf.value<bool>("bookmarks.toolbar.visible").value());
+ setMovable(conf.value<bool>("bookmarks/toolbar.movable").value());
+ setVisible(conf.value<bool>("bookmarks/toolbar.visible").value());
setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
const auto *root = model->root();
diff --git a/src/browser.cpp b/src/browser.cpp
index f748e2f..74da540 100644
--- a/src/browser.cpp
+++ b/src/browser.cpp
@@ -31,7 +31,7 @@
#include <QTimer>
#include <QTranslator>
#include <QVersionNumber>
-#include <pluginloader.h>
+// #include <pluginloader.h>
#include <spdlog/spdlog.h>
#include <version.h>
@@ -40,11 +40,11 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
{
Configuration conf;
- setApplicationName(conf.value<QString>("poi.name").value());
- setWindowIcon(QIcon(conf.value<QString>("poi.icon").value()));
+ setApplicationName(conf.value<QString>("poi/name").value());
+ setWindowIcon(QIcon(conf.value<QString>("poi/icon").value()));
setApplicationVersion(QVersionNumber::fromString(QLatin1String(poi_Version)).toString());
- if(const auto _translation = conf.value<QString>("browser.translation")) {
+ if(const auto _translation = conf.value<QString>("browser/translation")) {
auto *translator = new QTranslator(this);
if(translator->load(_translation.value()))
installTranslator(translator);
@@ -52,7 +52,7 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
delete translator;
}
- if(const auto _locale = conf.value<QString>("browser.locale")) {
+ if(const auto _locale = conf.value<QString>("browser/locale")) {
auto *locale = new QTranslator(this);
if(locale->load("qt_" + _locale.value(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
installTranslator(locale);
@@ -60,11 +60,11 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
delete locale;
}
- if(auto iconTheme = conf.value<QString>("browser.iconTheme")) {
+ if(auto iconTheme = conf.value<QString>("browser/iconTheme")) {
QIcon::setThemeName(iconTheme.value());
}
- if(auto stylesheet = conf.value<QString>("browser.stylesheet")) {
+ if(auto stylesheet = conf.value<QString>("browser/stylesheet")) {
QFile f(stylesheet.value());
if(f.open(QIODevice::ReadOnly)) {
setStyleSheet(f.readAll());
@@ -74,11 +74,11 @@ Browser::Browser(int &argc, char *argv[], bool allowSecondary)
// 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(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();
m_profileManager = std::make_unique<WebProfileManager<false>>(profiles, default_id, search, homepage, newtab);
m_profileManager->make_global();
@@ -92,13 +92,13 @@ 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>(conf.value<QString>("downloads/path").value());
m_profileManager->walk([this](const QString &, WebProfile *profile, QSettings *) {
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>(QString::fromStdString(conf.value<std::string>("bookmarks/path").value()));
connect(m_bookmarks.get(), &BookmarksWidget::openUrl, this, [this](const QUrl &url) {
m_windows.last()->createTab(url);
});
@@ -142,22 +142,31 @@ bool Browser::loadPlugin(const QString &path)
}
Configuration conf;
+ bool loaded = false;
+
+#ifdef HAVE_PLUGINLOADER
const auto state = PluginLoader::signature_state(
conf.value<bool>("plugins.signature.ignored").value(),
conf.value<bool>("plugins.signature.checked").value(),
conf.value<bool>("plugins.signature.enforced").value());
auto *loader = new PluginLoader(path, state, this);
- const bool loaded = loader->load();
+ loaded = loader->load();
+#endif
if(!loaded) {
+#ifdef HAVE_PLUGINLOADER
delete loader;
+#endif
return false;
}
+#ifdef HAVE_PLUGINLOADER
auto *info = new PluginInfo(loader);
m_plugins.append(info);
emit pluginAdded(loader);
+#endif
+
return true;
}
diff --git a/src/main.cpp b/src/main.cpp
index dad1f73..8cd1d34 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,36 +7,15 @@
*/
#include "browser.h"
-#include "builtins.h"
#include "configuration.h"
-#include "crashhandler.h"
#include "session/sessiondialog.h"
#include "session_json.hpp"
-#include "settings.h"
-#include "util.h"
-#include "version.h"
+#include <QCommandLineParser>
#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 = ", ")
-{
- 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 main(int argc, char **argv)
{
// change log pattern
@@ -45,104 +24,71 @@ int main(int argc, char **argv)
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
#endif
- const command_map commands{
- { "configuration", builtins::configuration },
- { "bookmarks", builtins::bookmarks },
- };
-
- 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));
+ QCommandLineParser parser;
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addPositionalArgument("url", "URLs to open");
+
+ // generic options
+ QCommandLineOption cmd_config({ "c", "config" }, "Set the configuration file.", "path");
+ parser.addOption(cmd_config);
+
+ QCommandLineOption cmd_session({ "s", "session" }, "Open the specified session.", "path");
+ parser.addOption(cmd_session);
+
+ QCommandLineOption cmd_pick_session("pick-session", "Show all available sessions and select which one to open.");
+ parser.addOption(cmd_pick_session);
+
+ // Qt options
+ QCommandLineOption cmd_renderer("renderer", "Select the OpenGL renderer used by the application. Available options are: desktop, gles, software", "value");
+ parser.addOption(cmd_renderer);
+
+ // SingleApplication options
+ QCommandLineOption cmd_no_remote("no-remote", "Start a new instance that won't accept or send remote commands.");
+ parser.addOption(cmd_no_remote);
+
+ { // handle command line options that need to be set before the QApplication object is created
+ QStringList args;
+ for(int i = 0; i < argc; ++i)
+ args.append(argv[i]);
+ parser.parse(args);
+
+ // the OpenGL implementation needs to be manually set to software if it's not properly configured
+ if(parser.isSet(cmd_renderer)) {
+ const auto value = parser.value(cmd_renderer);
+ if(value == QLatin1String("desktop")) {
+ QApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true);
+ } else if(value == QLatin1String("gles")) {
+ QApplication::setAttribute(Qt::AA_UseOpenGLES, true);
+ } else if(value == QLatin1String("software")) {
+ QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL, true);
+ } else {
+ spdlog::error("Unknown cmd_renderer flag: {}", qUtf8Printable(value));
}
}
-
- } 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());
+ QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
- if(CrashHandler::install_handler(ctx)) {
- spdlog::info("Installed breakpad crash handler: {}", ctx.dumppath);
- } else {
- spdlog::warn("Failed to install breakpad crash handler: {}", ctx.dumppath);
- }
- }
+ spdlog::info("Loaded configuration: {}", Configuration::init_global(parser.value(cmd_config).toStdString()));
- // 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));
- }
- }
- }
+ Browser app(argc, argv);
+ parser.process(app);
const auto profile = []() {
- Configuration c;
- return c.value<QString>("profile.default").value();
+ Configuration conf;
+ return conf.value<QString>("profile/default").value();
}();
- QStringList urls;
- for(const auto &u : args::get(cmd_args)) {
- urls.append(QString::fromStdString(u));
- }
+ QStringList urls = parser.positionalArguments();
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) {
+ if(app.isPrimary() && !parser.isSet(cmd_no_remote)) {
+ QObject::connect(&app, &Browser::receivedMessage, &app, [&app](quint32 instanceId, const QByteArray &message) {
Q_UNUSED(instanceId);
JsonSession session(message);
app.open(session.get());
@@ -151,13 +97,13 @@ int main(int argc, char **argv)
{
const auto session = [&]() {
- if(cmd_session) {
- QFile sessionJson(QString::fromStdString(args::get(cmd_session)));
+ if(parser.isSet(cmd_session)) {
+ QFile sessionJson(parser.value(cmd_session));
if(sessionJson.open(QIODevice::ReadOnly | QIODevice::Text)) {
return JsonSession(sessionJson.readAll());
}
}
- if(cmd_pickSession) {
+ if(parser.isSet(cmd_pick_session)) {
SessionDialog dlg;
if(const auto pick = dlg.pickSession()) {
return JsonSession(pick.value());
@@ -166,13 +112,13 @@ int main(int argc, char **argv)
return JsonSession(profile, urls);
}();
- if(app.isPrimary() || cmd_noRemote) {
+ if(app.isPrimary() || parser.isSet(cmd_no_remote)) {
app.open(session.get());
} else {
// app is secondary and not standalone
- return app.sendMessage(session.serialize());
+ return app.sendMessage(session.serialize()) ? EXIT_SUCCESS : EXIT_FAILURE;
}
}
- return app.exec();
+ return QApplication::exec();
}
diff --git a/src/mainwindow/addressbar.cpp b/src/mainwindow/addressbar.cpp
index d37a6a7..ed1cb3e 100644
--- a/src/mainwindow/addressbar.cpp
+++ b/src/mainwindow/addressbar.cpp
@@ -19,9 +19,9 @@ AddressBar::AddressBar(QWidget *parent)
ui->setupUi(this);
Configuration conf;
- ui->urlBar->menuAction->setShortcut(QKeySequence(conf.value<QString>("shortcuts.address.menu").value()));
+ ui->urlBar->menuAction->setShortcut(QKeySequence(conf.value<QString>("shortcuts/address.menu").value()));
- auto *focusShortcut = new QShortcut(QKeySequence(conf.value<QString>("shortcuts.address.focus").value()), parent);
+ auto *focusShortcut = new QShortcut(QKeySequence(conf.value<QString>("shortcuts/address.focus").value()), parent);
connect(focusShortcut, &QShortcut::activated, ui->urlBar, [this]() {
ui->urlBar->setFocus();
ui->urlBar->selectAll();
diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp
index 64c149c..bd5d0c2 100644
--- a/src/mainwindow/mainwindow.cpp
+++ b/src/mainwindow/mainwindow.cpp
@@ -30,16 +30,16 @@ MainWindow::MainWindow(const Session::MainWindow &mainwindow_data, QMenu *appMen
Configuration config;
// create UI
- defaultWindowTitle = config.value<QString>("mainwindow.title").value();
+ defaultWindowTitle = config.value<QString>("mainwindow/title").value();
setWindowTitle(defaultWindowTitle);
- resize(config.value<int>("mainwindow.width").value(), config.value<int>("mainwindow.height").value());
- if(config.value<bool>("mainwindow.maximized").value_or(false)) {
+ resize(config.value<int>("mainwindow/width").value(), config.value<int>("mainwindow/height").value());
+ if(config.value<bool>("mainwindow/maximized").value_or(false)) {
setWindowState(Qt::WindowMaximized);
}
show();
navigationToolBar = new NavigationBar(this);
- navigationToolBar->setMovable(config.value<bool>("navigation.movable").value_or(false));
+ navigationToolBar->setMovable(config.value<bool>("navigation/movable").value_or(false));
addToolBar(Qt::TopToolBarArea, navigationToolBar);
navigationToolBar->connectWebView(nullptr);
diff --git a/src/mainwindow/menubar.cpp b/src/mainwindow/menubar.cpp
index 5fc039a..e479e8d 100644
--- a/src/mainwindow/menubar.cpp
+++ b/src/mainwindow/menubar.cpp
@@ -79,30 +79,30 @@ MenuBar::MenuBar(QMenu *appMenu, MainWindow *parent)
auto *actionBookmarks = window->addAction(tr("Bookmarks"), browser, [browser, parent]() {
browser->showWidget(browser->bookmarks(), parent);
});
- conf.shortcut<QAction>(*actionBookmarks, "shortcuts.window.bookmarks.show");
+ conf.shortcut<QAction>(*actionBookmarks, "shortcuts/window.bookmarks.show");
auto *actionDownloads = window->addAction(tr("Downloads"), browser, [browser, parent]() {
browser->showWidget(browser->downloads(), parent);
});
- conf.shortcut<QAction>(*actionDownloads, "shortcuts.window.downloads.show");
+ conf.shortcut<QAction>(*actionDownloads, "shortcuts/window.downloads.show");
window->addSeparator();
auto *actionNewWindow = window->addAction(tr("New Window"), browser, [browser]() {
const Session::MainWindow window_data;
browser->open({ window_data }, false);
});
- conf.shortcut<QAction>(*actionNewWindow, "shortcuts.window.newwindow");
+ conf.shortcut<QAction>(*actionNewWindow, "shortcuts/window.newwindow");
auto *actionNewSubwindow = window->addAction(tr("New Subwindow"), parent, [parent]() {
const Session::SubWindow session;
parent->createSubWindow(session);
});
- conf.shortcut<QAction>(*actionNewSubwindow, "shortcuts.window.newgroup");
+ conf.shortcut<QAction>(*actionNewSubwindow, "shortcuts/window.newgroup");
auto *actionCloseSubwindow = window->addAction(tr("Close Subwindow"), parent, [parent]() {
parent->currentSubWindow()->close();
});
- conf.shortcut<QAction>(*actionCloseSubwindow, "shortcuts.subwindow.close");
+ conf.shortcut<QAction>(*actionCloseSubwindow, "shortcuts/subwindow.close");
window->addSeparator()->setText(tr("Toolbars"));
@@ -140,7 +140,7 @@ MenuBar::MenuBar(QMenu *appMenu, MainWindow *parent)
_subwindow->setCurrentTab(index);
});
});
- conf.shortcut<QAction>(*actionNewTab, "shortcuts.subwindow.newtab");
+ conf.shortcut<QAction>(*actionNewTab, "shortcuts/subwindow.newtab");
subwindow->addSeparator();
@@ -150,7 +150,7 @@ MenuBar::MenuBar(QMenu *appMenu, MainWindow *parent)
_subwindow->setCurrentTab(index);
});
});
- conf.shortcut<QAction>(*actionRestoreTab, "shortcuts.subwindow.restoretab");
+ conf.shortcut<QAction>(*actionRestoreTab, "shortcuts/subwindow.restoretab");
auto *restoreTabsMenu = subwindow->addMenu(tr("Restore previous tab"));
connect(restoreTabsMenu, &QMenu::aboutToShow, parent, [parent, restoreTabsMenu]() {
@@ -200,28 +200,28 @@ MenuBar::MenuBar(QMenu *appMenu, MainWindow *parent)
_subwindow->setCurrentTab(qMax(0, currentIdx - 1));
});
});
- conf.shortcut<QAction>(*leftTab, "shortcuts.subwindow.tableft");
+ conf.shortcut<QAction>(*leftTab, "shortcuts/subwindow.tableft");
auto *moveTabLeft = subwindow->addAction(tr("Move tab left"), parent, [parent]() {
run_if(parent->currentSubWindow(), [](SubWindow *_subwindow, int currentIdx) {
_subwindow->moveTab(currentIdx, currentIdx - 1);
});
});
- conf.shortcut<QAction>(*moveTabLeft, "shortcuts.subwindow.movetableft");
+ conf.shortcut<QAction>(*moveTabLeft, "shortcuts/subwindow.movetableft");
auto *rightTab = subwindow->addAction(tr("Switch to tab on the right"), parent, [parent]() {
run_if(parent->currentSubWindow(), [](SubWindow *_subwindow, int currentIdx) {
_subwindow->setCurrentTab(qMin(currentIdx + 1, _subwindow->tabCount() - 1));
});
});
- conf.shortcut<QAction>(*rightTab, "shortcuts.subwindow.tabright");
+ conf.shortcut<QAction>(*rightTab, "shortcuts/subwindow.tabright");
auto *moveTabRight = subwindow->addAction(tr("Move tab right"), parent, [parent]() {
run_if(parent->currentSubWindow(), [](SubWindow *_subwindow, int currentIdx) {
_subwindow->moveTab(currentIdx, currentIdx + 1);
});
});
- conf.shortcut<QAction>(*moveTabRight, "shortcuts.subwindow.movetabright");
+ conf.shortcut<QAction>(*moveTabRight, "shortcuts/subwindow.movetabright");
subwindow->addSeparator();
@@ -230,7 +230,7 @@ MenuBar::MenuBar(QMenu *appMenu, MainWindow *parent)
_subwindow->closeTab(currentIdx);
});
});
- conf.shortcut<QAction>(*closeTab, "shortcuts.subwindow.closetab");
+ conf.shortcut<QAction>(*closeTab, "shortcuts/subwindow.closetab");
subwindow->addAction(tr("Close tabs to the left"), parent, [parent]() {
run_if(parent->currentSubWindow(), [](SubWindow *_subwindow, int currentIdx) {
@@ -329,10 +329,7 @@ MenuBar::MenuBar(QMenu *appMenu, MainWindow *parent)
auto *printer = new QPrinter(QPrinterInfo::defaultPrinter());
QPrintDialog dlg(printer, parent);
if(dlg.exec() == QDialog::Accepted) {
- parent->currentView()->page()->print(printer, [printer](bool success) {
- Q_UNUSED(success);
- delete printer;
- });
+ parent->currentView()->print(printer);
}
}
});
diff --git a/src/mainwindow/widgets/navigationbar.cpp b/src/mainwindow/widgets/navigationbar.cpp
index 799ebec..6da6f6c 100644
--- a/src/mainwindow/widgets/navigationbar.cpp
+++ b/src/mainwindow/widgets/navigationbar.cpp
@@ -29,7 +29,7 @@ NavigationBar::NavigationBar(QWidget *parent)
// Back button
backAction = addAction(Util::icon(QStyle::SP_ArrowBack), tr("Back"));
- config.shortcut<QAction>(*backAction, "shortcuts.navigation.back");
+ config.shortcut<QAction>(*backAction, "shortcuts/navigation.back");
connect(backAction, &QAction::triggered, this, [this]() {
m_view->history()->back();
});
@@ -47,7 +47,7 @@ NavigationBar::NavigationBar(QWidget *parent)
});
backAction->setMenu(backMenu);
- auto *backMenuShortcut = new QShortcut(QKeySequence(config.value<QString>("shortcuts.navigation.backmenu").value()), this);
+ auto *backMenuShortcut = new QShortcut(QKeySequence(config.value<QString>("shortcuts/navigation.backmenu").value()), this);
connect(backMenuShortcut, &QShortcut::activated, backMenu, [this, backMenu]() {
if(backAction->isEnabled()) {
auto *widget = this->widgetForAction(backAction);
@@ -57,7 +57,7 @@ NavigationBar::NavigationBar(QWidget *parent)
// Forward button
forwardAction = addAction(Util::icon(QStyle::SP_ArrowForward), tr("Forward"));
- config.shortcut<QAction>(*forwardAction, "shortcuts.navigation.forward");
+ config.shortcut<QAction>(*forwardAction, "shortcuts/navigation.forward");
connect(forwardAction, &QAction::triggered, this, [this]() {
m_view->history()->forward();
});
@@ -75,7 +75,7 @@ NavigationBar::NavigationBar(QWidget *parent)
});
forwardAction->setMenu(forwardMenu);
- auto *forwardMenuShortcut = new QShortcut(QKeySequence(config.value<QString>("shortcuts.navigation.forwardmenu").value()), this);
+ auto *forwardMenuShortcut = new QShortcut(QKeySequence(config.value<QString>("shortcuts/navigation.forwardmenu").value()), this);
connect(forwardMenuShortcut, &QShortcut::activated, forwardMenu, [this, forwardMenu]() {
if(forwardAction->isEnabled()) {
auto *widget = this->widgetForAction(forwardAction);
@@ -85,7 +85,7 @@ NavigationBar::NavigationBar(QWidget *parent)
// Stop/Refresh button
stopReloadAction = addAction(Util::icon(QStyle::SP_BrowserReload), tr("Refresh"));
- config.shortcut<QAction>(*stopReloadAction, "shortcuts.navigation.refresh");
+ config.shortcut<QAction>(*stopReloadAction, "shortcuts/navigation.refresh");
connect(stopReloadAction, &QAction::triggered, this, [this]() {
if(m_view->isLoaded())
m_view->reload();
@@ -93,14 +93,14 @@ NavigationBar::NavigationBar(QWidget *parent)
m_view->stop();
});
- auto *reloadShortcut = new QShortcut(QKeySequence(config.value<QString>("shortcuts.navigation.reload").value()), this);
+ auto *reloadShortcut = new QShortcut(QKeySequence(config.value<QString>("shortcuts/navigation.reload").value()), this);
connect(reloadShortcut, &QShortcut::activated, this, [this]() {
m_view->triggerPageAction(QWebEnginePage::ReloadAndBypassCache);
});
// Home button
homeAction = addAction(Util::icon(QStyle::SP_DirHomeIcon), tr("Home"));
- config.shortcut<QAction>(*homeAction, "shortcuts.navigation.home");
+ config.shortcut<QAction>(*homeAction, "shortcuts/navigation.home");
connect(homeAction, &QAction::triggered, this, [this]() {
m_view->load(m_view->profile()->homepage());
});
diff --git a/src/mainwindow/widgets/searchform.cpp b/src/mainwindow/widgets/searchform.cpp
index e10933b..af54f5c 100644
--- a/src/mainwindow/widgets/searchform.cpp
+++ b/src/mainwindow/widgets/searchform.cpp
@@ -10,6 +10,7 @@
#include "ui_searchform.h"
#include <QHideEvent>
#include <QShowEvent>
+#include <QWebEngineFindTextResult>
#include <QWebEngineView>
SearchForm::SearchForm(QWidget *parent)
@@ -26,7 +27,8 @@ SearchForm::SearchForm(QWidget *parent)
QWebEnginePage::FindFlags searchFlags;
searchFlags.setFlag(QWebEnginePage::FindCaseSensitively, ui->caseSensitivity_checkBox->isChecked());
searchFlags.setFlag(QWebEnginePage::FindBackward, ui->reverseSearch_checkBox->isChecked());
- m_view->findText(ui->lineEdit->text(), searchFlags, [this](bool found) {
+ m_view->findText(ui->lineEdit->text(), searchFlags, [this](const QWebEngineFindTextResult &result) {
+ const bool found = result.numberOfMatches() > 0;
ui->result_label->setVisible(!found);
});
}
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/sessiondialog.h b/src/session/sessiondialog.h
index 0a04940..fc31aa4 100644
--- a/src/session/sessiondialog.h
+++ b/src/session/sessiondialog.h
@@ -11,6 +11,7 @@
#include "session.hpp"
#include <QDialog>
+#include <optional>
namespace Ui
{
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 6e9a713..a2d6138 100644
--- a/src/subwindow/subwindow.cpp
+++ b/src/subwindow/subwindow.cpp
@@ -57,7 +57,6 @@ SubWindow::SubWindow(QWidget *parent, Qt::WindowFlags flags)
close();
} else {
auto *view = dynamic_cast<WebView *>(tabWidget->widget(index));
- Q_CHECK_PTR(view);
disconnect(titleConnection);
disconnect(linkHoveredConnection);
@@ -67,12 +66,10 @@ SubWindow::SubWindow(QWidget *parent, Qt::WindowFlags flags)
this->setWindowTitle(QString("%1 :%2").arg(title, v->profile()->name()));
});
setWindowTitle(QString("%1 :%2").arg(view->title(), view->profile()->name()));
-
linkHoveredConnection = connect(view->page(), &WebPage::linkHovered, this, [this](const QString &url) {
if(!url.isEmpty())
emit showStatusMessage(url, 3000);
});
-
emit currentViewChanged(view);
}
});
diff --git a/src/subwindow/tabwidget.cpp b/src/subwindow/tabwidget.cpp
index 6f1e348..69f3b8a 100644
--- a/src/subwindow/tabwidget.cpp
+++ b/src/subwindow/tabwidget.cpp
@@ -42,8 +42,11 @@ TabWidget::TabWidget(SubWindow *parent)
// when changing tabs, give focus to the widget
// otherwise when closing tabs, the tabwidget will retain focus
connect(this, &TabWidget::currentChanged, this, [this](int index) {
- if(widget(index))
+ previous = current;
+ current = index;
+ /*if(widget(index)) {
widget(index)->setFocus();
+ }*/
});
// context menu
@@ -68,12 +71,6 @@ TabWidget::TabWidget(SubWindow *parent)
removeTab(i);
}
});
-
- //
- connect(this, &TabWidget::currentChanged, this, [this](int index) {
- previous = current;
- current = index;
- });
}
TabWidget::~TabWidget()
@@ -85,7 +82,9 @@ TabWidget::~TabWidget()
int TabWidget::addTab(WebView *view)
{
- Q_ASSERT_X(view != nullptr, "TabWidget::addTab", "Tried to add null view");
+ if(view == nullptr) {
+ return -1;
+ }
const int idx = QTabWidget::addTab(view, view->title());
connect(view, &WebView::titleChanged, [this, view](const QString &title) {
@@ -100,7 +99,6 @@ int TabWidget::addTab(WebView *view)
setTabIcon(current_idx, icon);
}
});
-
tabBar()->setTabData(idx, QVariant::fromValue<SubWindow::TabData>(SubWindow::TabData{}));
return idx;
}
diff --git a/src/util.cpp b/src/util.cpp
index fe74175..3061c96 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -62,7 +62,7 @@ QIcon Util::icon(QStyle::StandardPixmap id) {
return QIcon::fromTheme("go-home", qApp->style()->standardIcon(id));
default:
- spdlog::warn("FIXME: unhandled StandardPixmap {}", id);
+ spdlog::warn("FIXME: unhandled StandardPixmap");
return qApp->style()->standardIcon(id);
}
}
diff --git a/include/version.h.in b/src/version.h.in
index 44f10d9..b387811 100644
--- a/include/version.h.in
+++ b/src/version.h.in
@@ -3,6 +3,6 @@
// output of 'git describe --long --abbrev=40':
// x.y.z-0-g0123456789012345678901234567890123456789
-#define poi_Version "@VCS_TAG@"
+#define poi_Version "@CMAKE_PROJECT_VERSION@"
#endif // SMOLBOTE_VERSION_H
diff --git a/src/webengine/CMakeLists.txt b/src/webengine/CMakeLists.txt
new file mode 100644
index 0000000..704a6d0
--- /dev/null
+++ b/src/webengine/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_library(webengine STATIC
+ urlinterceptor.cpp urlinterceptor.h
+ webpage.cpp webpage.h
+ webprofile.cpp webprofile.h
+ webprofilemanager.cpp webprofilemanager.h
+ webviewcontextmenu.cpp webviewcontextmenu.h
+ webview.cpp webview.h
+)
+target_link_libraries(webengine PUBLIC Qt6::WebEngineCore Qt6::WebEngineWidgets)
+target_include_directories(webengine PUBLIC ${CMAKE_CURRENT_LIST_DIR} ${PROJECT_SOURCE_DIR}/include)
diff --git a/src/webengine/webpage.cpp b/src/webengine/webpage.cpp
index b2b19b5..f8a8f7f 100644
--- a/src/webengine/webpage.cpp
+++ b/src/webengine/webpage.cpp
@@ -62,6 +62,7 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::featurePermissionDialog);
connect(this, &QWebEnginePage::renderProcessTerminated, this, &WebPage::renderProcessCrashed);
+ connect(this, &QWebEnginePage::certificateError, this, &WebPage::certificateError);
}
bool WebPage::certificateError(const QWebEngineCertificateError &certificateError)
@@ -77,9 +78,8 @@ bool WebPage::certificateError(const QWebEngineCertificateError &certificateErro
messageBox.setText(tr("An SSL error has occurred on <strong>%1</strong>").arg(certificateError.url().toString()));
messageBox.setInformativeText(tr("<p>%1</p>"
"<p>This error %2 be overridden.</p>")
- .arg(certificateError.errorDescription(),
+ .arg(certificateError.description(),
certificateError.isOverridable() ? tr("can") : tr("cannot")));
- messageBox.setDetailedText(tr("Error code: %1").arg(certificateError.error()));
if(certificateError.isOverridable()) {
messageBox.setStandardButtons(QMessageBox::Ignore | QMessageBox::Abort);
diff --git a/src/webengine/webpage.h b/src/webengine/webpage.h
index 91ae4f3..bd7d54c 100644
--- a/src/webengine/webpage.h
+++ b/src/webengine/webpage.h
@@ -19,12 +19,10 @@ public:
WebPage(QWebEngineProfile *profile, QObject *parent = nullptr);
~WebPage() override = default;
-protected:
- bool certificateError(const QWebEngineCertificateError &certificateError) override;
-
protected slots:
void featurePermissionDialog(const QUrl &securityOrigin, QWebEnginePage::Feature feature);
void renderProcessCrashed(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode);
+ bool certificateError(const QWebEngineCertificateError &certificateError);
};
#endif // SMOLBOTE_WEBPAGE_H
diff --git a/src/webengine/webprofile.cpp b/src/webengine/webprofile.cpp
index 719ab34..f1e71fb 100644
--- a/src/webengine/webprofile.cpp
+++ b/src/webengine/webprofile.cpp
@@ -18,12 +18,10 @@ static WebProfile *s_profile = nullptr;
void WebProfile::setDefaultProfile(WebProfile *profile)
{
- Q_CHECK_PTR(profile);
s_profile = profile;
}
WebProfile *WebProfile::defaultProfile()
{
- Q_CHECK_PTR(s_profile);
return s_profile;
}
diff --git a/src/webengine/webprofilemanager.cpp b/src/webengine/webprofilemanager.cpp
index 5cc83f8..9ae2960 100644
--- a/src/webengine/webprofilemanager.cpp
+++ b/src/webengine/webprofilemanager.cpp
@@ -8,6 +8,7 @@
#include "webprofilemanager.h"
#include "webprofile.h"
+#include <QActionGroup>
static WebProfileManager<false> *s_instance = nullptr;
diff --git a/src/webengine/webprofilemanager.h b/src/webengine/webprofilemanager.h
index 91dcaf8..a356506 100644
--- a/src/webengine/webprofilemanager.h
+++ b/src/webengine/webprofilemanager.h
@@ -41,10 +41,11 @@ public:
}
if(!profiles.contains(default_id)) {
- Profile profile;
- profile.settings = WebProfile::load(QString(), search, homepage, newtab);
- profile.ptr = WebProfile::load(default_id, profile.settings, true);
- profiles[default_id] = profile;
+ auto *settings = WebProfile::load(QString(), search, homepage, newtab);
+ profiles[default_id] = Profile{
+ .settings = settings,
+ .ptr = WebProfile::load(default_id, settings, true),
+ };
}
WebProfile::setDefaultProfile(profiles[default_id].ptr);
}
@@ -73,7 +74,7 @@ public:
}
if(profile != nullptr && settings != nullptr) {
- profiles[id] = Profile{ profile, settings, false };
+ profiles[id] = Profile{ settings, profile, false };
}
}
@@ -101,8 +102,8 @@ private:
set_typestate(consumed) void consume() {}
struct Profile {
- WebProfile *ptr = nullptr;
QSettings *settings = nullptr;
+ WebProfile *ptr = nullptr;
bool selfDestruct = false;
};
diff --git a/src/webengine/webview.cpp b/src/webengine/webview.cpp
index 38e564a..bc52102 100644
--- a/src/webengine/webview.cpp
+++ b/src/webengine/webview.cpp
@@ -37,9 +37,7 @@ WebView::WebView(WebProfile *profile, cb_createWindow_t cb, QWidget *parent)
: WebView(parent)
{
cb_createWindow = cb;
- Q_CHECK_PTR(profile);
- m_profile = profile;
- setPage(new WebPage(profile, this));
+ setProfile(profile);
}
WebView::WebView(const Session::WebView &webview_data, cb_createWindow_t cb, QWidget *parent)
@@ -47,11 +45,7 @@ WebView::WebView(const Session::WebView &webview_data, cb_createWindow_t cb, QWi
{
cb_createWindow = cb;
WebProfileManager profileManager;
-
- auto *profile = profileManager.profile(webview_data.profile);
- if(profile != nullptr) {
- setProfile(profile);
- }
+ setProfile(profileManager.profile(webview_data.profile));
if(!webview_data.url.isEmpty())
load(QUrl::fromUserInput(webview_data.url));
@@ -64,9 +58,9 @@ WebView::WebView(const Session::WebView &webview_data, cb_createWindow_t cb, QWi
void WebView::setProfile(WebProfile *profile)
{
- m_profile = profile;
+ m_profile = (profile == nullptr) ? WebProfile::defaultProfile() : profile;
const auto url = this->url();
- setPage(new WebPage(profile, this));
+ setPage(new WebPage(m_profile, this));
this->load(url);
}
diff --git a/src/webengine/webviewcontextmenu.cpp b/src/webengine/webviewcontextmenu.cpp
index ea5e8c6..0de3b9f 100644
--- a/src/webengine/webviewcontextmenu.cpp
+++ b/src/webengine/webviewcontextmenu.cpp
@@ -17,7 +17,7 @@
#include <QStyle>
#include <QToolButton>
#include <QVBoxLayout>
-#include <QWebEngineContextMenuData>
+#include <QWebEngineContextMenuRequest>
#include <QWebEngineHistory>
#include <QWidgetAction>
@@ -94,100 +94,7 @@ WebViewContextMenu::WebViewContextMenu(WebView *view)
this->addAction(navButtons);
this->addSeparator();
- const auto ctxdata = view->page()->contextMenuData();
-
- if(ctxdata.mediaType() == QWebEngineContextMenuData::MediaTypeNone) {
- auto *backMenu = this->addMenu(tr("Back"));
- if(!view->history()->canGoBack()) {
- backMenu->setEnabled(false);
- } else {
- connect(backMenu, &QMenu::aboutToShow, view, [view, backMenu]() {
- backMenu->clear();
- const auto backItems = view->history()->backItems(10);
- for(const QWebEngineHistoryItem &item : backItems) {
- backMenu->addAction(historyAction(view, item));
- }
- });
- }
-
- auto *forwardMenu = this->addMenu(tr("Forward"));
- if(!view->history()->canGoForward()) {
- forwardMenu->setEnabled(false);
- } else {
- connect(forwardMenu, &QMenu::aboutToShow, view, [view, forwardMenu]() {
- forwardMenu->clear();
- const auto forwardItems = view->history()->forwardItems(10);
- for(const QWebEngineHistoryItem &item : forwardItems) {
- forwardMenu->addAction(historyAction(view, item));
- }
- });
- }
-
- connect(this->addAction(tr("Reload")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::Reload);
- });
- connect(this->addAction(tr("Reload and bypass Cache")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::ReloadAndBypassCache);
- });
-
- this->addSeparator();
-
- connect(this->addAction(tr("Select All")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::SelectAll);
- });
- connect(this->addAction(tr("Clear Selection")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::Unselect);
- });
- connect(this->addAction(tr("Copy to clipboard")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::Copy);
- });
-
- } else if(ctxdata.mediaType() == QWebEngineContextMenuData::MediaTypeImage) {
- connect(this->addAction(tr("Copy image to clipboard")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::CopyImageToClipboard);
- });
- connect(this->addAction(tr("Copy image URL to clipboard")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::CopyImageUrlToClipboard);
- });
- if(!ctxdata.mediaUrl().isEmpty()) {
- if(view->url() != ctxdata.mediaUrl()) {
- connect(this->addAction(tr("Open image")), &QAction::triggered, view, [view, ctxdata]() {
- view->load(ctxdata.mediaUrl());
- });
- connect(this->addAction(tr("Open image in new tab")), &QAction::triggered, view, [view, ctxdata]() {
- view->createWindow(QWebEnginePage::WebBrowserTab)->load(ctxdata.mediaUrl());
- });
- }
- connect(this->addAction(tr("Save image")), &QAction::triggered, view, [view, ctxdata]() {
- view->page()->download(ctxdata.mediaUrl());
- });
- }
-
- } else {
- addMenu(view->page()->createStandardContextMenu());
- }
-
- if(!ctxdata.linkUrl().isEmpty()) {
- this->addSeparator();
- connect(this->addAction(tr("Open link in new tab")), &QAction::triggered, view, [view, ctxdata]() {
- view->createWindow(QWebEnginePage::WebBrowserTab)->load(ctxdata.linkUrl());
- });
-
- auto *newTabMenu = this->addMenu(tr("Open link in new tab with profile"));
- profileMenu(newTabMenu, [view, ctxdata](WebProfile *profile) {
- auto *v = view->createWindow(QWebEnginePage::WebBrowserTab);
- v->setProfile(profile);
- v->load(ctxdata.linkUrl());
- });
-
- connect(this->addAction(tr("Open link in new window")), &QAction::triggered, view, [view, ctxdata]() {
- view->createWindow(QWebEnginePage::WebBrowserWindow)->load(ctxdata.linkUrl());
- });
-
- connect(this->addAction(tr("Copy link address")), &QAction::triggered, view, [view]() {
- view->page()->triggerAction(QWebEnginePage::CopyLinkToClipboard);
- });
- }
+ addMenu(view->createStandardContextMenu());
// zoom widget
{
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