.clang-format
.clang-tidy
.gitignore
.vimrc
BrowserTab.cpp
BrowserTab.h
BrowserView.cpp
BrowserView.h
CMakeLists.txt
DatabaseManager.cpp
DatabaseManager.h
DownloadBar.cpp
DownloadBar.h
DownloadWidget.cpp
DownloadWidget.h
MainWindow.cpp
MainWindow.h
Makefile
MasterPasswordDialog.cpp
MasterPasswordDialog.h
PasswordHelper.cpp
PasswordHelper.h
README.md
ThemeConfig.h
VaultManager.cpp
VaultManager.h
browser.desktop
browser.qrc
compile_commands.json
main.cpp
BrowserTab.cpp
raw
1#include "BrowserTab.h"
2#include <QApplication>
3#include <QFile>
4#include <QStyle>
5#include <QWebChannel>
6#include <QWebEnginePage>
7#include <QWebEngineProfile>
8#include <QWebEngineScript>
9#include <QWebEngineScriptCollection>
10#include <QWebEngineSettings>
11#include "PasswordHelper.h"
12#include "ThemeConfig.h"
13
14BrowserTab::BrowserTab(QWidget *parent) : QSplitter(Qt::Vertical, parent) {
15 view = new BrowserView;
16 devtools = new QWebEngineView;
17 passwordHelper = new PasswordHelper(this);
18
19 auto *channel = new QWebChannel(this);
20 channel->registerObject("passwordHelper", passwordHelper);
21 view->page()->setWebChannel(channel);
22
23 view->page()->setDevToolsPage(devtools->page());
24 devtools->hide();
25
26 addWidget(view);
27 addWidget(devtools);
28
29 // Initial layout ratio
30 setStretchFactor(0, 3);
31 setStretchFactor(1, 1);
32 setOpaqueResize(false);
33
34 view->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
35
36 // Visual handle for resizing
37 handle(1)->setAttribute(Qt::WA_Hover);
38 setStyleSheet(QString("QSplitter::handle { background: %1; height: 4px; }").arg(ThemeConfig::SplitterHandleColorLight));
39
40 // Close devtools if requested by the page (e.g. clicking 'x')
41 connect(devtools->page(), &QWebEnginePage::windowCloseRequested, [this]() { setDevToolsVisible(false); });
42
43 setupScripts();
44}
45
46void BrowserTab::setupScripts() {
47 QWebEngineScript qwebchannel;
48 QFile file(":/js/qwebchannel.js");
49 if (file.open(QIODevice::ReadOnly)) {
50 qwebchannel.setSourceCode(file.readAll());
51 qwebchannel.setName("qwebchannel.js");
52 qwebchannel.setWorldId(QWebEngineScript::MainWorld);
53 qwebchannel.setInjectionPoint(QWebEngineScript::DocumentCreation);
54 qwebchannel.setRunsOnSubFrames(true);
55 view->page()->scripts().insert(qwebchannel);
56 } else {
57 qCritical() << "Failed to load bundled qwebchannel.js from resources!";
58 }
59
60 QWebEngineScript passwordScript;
61 QFile scriptFile(":/js/capture.js");
62 if (scriptFile.open(QIODevice::ReadOnly)) {
63 passwordScript.setSourceCode(scriptFile.readAll());
64 passwordScript.setName("passwordScript");
65 passwordScript.setWorldId(QWebEngineScript::MainWorld);
66 passwordScript.setInjectionPoint(QWebEngineScript::DocumentReady);
67 passwordScript.setRunsOnSubFrames(true);
68 view->page()->scripts().insert(passwordScript);
69 } else {
70 qCritical() << "Failed to load capture.js from resources!";
71 }
72}
73
74void BrowserTab::setDevToolsVisible(bool visible) {
75 devtools->setVisible(visible);
76 if (visible) {
77 int h = height();
78 setSizes({static_cast<int>(h * 0.7), static_cast<int>(h * 0.3)});
79 } else {
80 setSizes({height(), 0});
81 }
82}
83
84void BrowserTab::updateTabTheme(bool dark) {
85 view->settings()->setAttribute(QWebEngineSettings::ForceDarkMode, false);
86 devtools->settings()->setAttribute(QWebEngineSettings::ForceDarkMode, false);
87
88 view->page()->setBackgroundColor(dark ? QColor(45, 45, 45) : Qt::white);
89 devtools->page()->setBackgroundColor(dark ? QColor(45, 45, 45) : Qt::white);
90
91 // Keep the view palette default to allow it to inherit from the application
92 view->setPalette(QPalette());
93 devtools->setPalette(QPalette());
94
95 QString handleColor = dark ? ThemeConfig::SplitterHandleColorDark : ThemeConfig::SplitterHandleColorLight;
96 setStyleSheet(QString("QSplitter::handle { background: %1; height: 4px; }").arg(handleColor));
97}