mirror of
https://github.com/zealdocs/zeal.git
synced 2026-08-29 08:34:50 +08:00
@@ -0,0 +1,13 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M12 3a9 9 0 1 0 9 9" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 243 B |
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Welcome</title>
|
||||
<title>New tab</title>
|
||||
<link rel="stylesheet" type="text/css" href="assets/css/oat.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="assets/css/welcome.css">
|
||||
</head>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<file alias="dots-vertical.svg">../../assets/tabler/dots-vertical.svg</file>
|
||||
<file alias="info-circle.svg">../../assets/tabler/info-circle.svg</file>
|
||||
<file alias="library.svg">../../assets/tabler/library.svg</file>
|
||||
<file alias="loader-2.svg">../../assets/tabler/loader-2.svg</file>
|
||||
<file alias="logout.svg">../../assets/tabler/logout.svg</file>
|
||||
<file alias="minus.svg">../../assets/tabler/minus.svg</file>
|
||||
<file alias="plus.svg">../../assets/tabler/plus.svg</file>
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QKeyEvent>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMetaEnum>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWebChannel>
|
||||
#include <QWebEngineHistory>
|
||||
@@ -19,6 +23,13 @@
|
||||
|
||||
namespace Zeal::Browser {
|
||||
|
||||
namespace {
|
||||
Q_LOGGING_CATEGORY(log, "zeal.browser.webcontrol")
|
||||
|
||||
// Bound recovery attempts so a deterministically crashing page does not thrash forever.
|
||||
constexpr int MaxRenderProcessReloadAttempts = 3;
|
||||
} // namespace
|
||||
|
||||
WebControl::WebControl(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
@@ -40,6 +51,57 @@ WebControl::WebControl(QWidget *parent)
|
||||
connect(m_webView, &QWebEngineView::urlChanged, this, &WebControl::urlChanged);
|
||||
connect(m_webView, &WebView::zoomLevelChanged, this, &WebControl::zoomLevelChanged);
|
||||
|
||||
// On a failed load that set no title, relabel the tab to signal the failure.
|
||||
connect(m_webView, &QWebEngineView::loadFinished, this, [this](bool ok) {
|
||||
if (ok) {
|
||||
m_renderProcessReloadAttempts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
qCWarning(log, "Failed to load '%s'.", qPrintable(m_webView->url().toString()));
|
||||
if (m_webView->title().isEmpty()) {
|
||||
emit titleChanged(tr("Couldn't load page"));
|
||||
}
|
||||
});
|
||||
|
||||
// A crashed render process leaves a blank page and never updates the title. Reload a
|
||||
// bounded number of times to recover, then relabel the tab if it keeps dying.
|
||||
connect(m_webView,
|
||||
&QWebEngineView::renderProcessTerminated,
|
||||
this,
|
||||
[this](QWebEnginePage::RenderProcessTerminationStatus status, int exitCode) {
|
||||
if (status == QWebEnginePage::NormalTerminationStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *statusName = QMetaEnum::fromType<QWebEnginePage::RenderProcessTerminationStatus>().valueToKey(
|
||||
status);
|
||||
qCWarning(log,
|
||||
"Render process for '%s' terminated (%s, exit code %d).",
|
||||
qPrintable(m_webView->url().toString()),
|
||||
statusName,
|
||||
exitCode);
|
||||
|
||||
if (m_renderProcessReloadAttempts < MaxRenderProcessReloadAttempts) {
|
||||
++m_renderProcessReloadAttempts;
|
||||
// Reloading directly from the termination handler is not supported; defer it.
|
||||
// Skip if the user has navigated away in the meantime.
|
||||
const QUrl crashedUrl = m_webView->url();
|
||||
QTimer::singleShot(0, m_webView, [this, crashedUrl]() {
|
||||
if (m_webView->url() == crashedUrl) {
|
||||
m_webView->reload();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
qCWarning(log,
|
||||
"Giving up reloading '%s' after %d attempts.",
|
||||
qPrintable(m_webView->url().toString()),
|
||||
MaxRenderProcessReloadAttempts);
|
||||
emit titleChanged(tr("Couldn't load page"));
|
||||
});
|
||||
|
||||
layout->addWidget(m_webView);
|
||||
|
||||
setLayout(layout);
|
||||
@@ -97,6 +159,7 @@ void WebControl::setWebBridgeObject(const QString &name, QObject *object)
|
||||
|
||||
void WebControl::load(const QUrl &url)
|
||||
{
|
||||
m_renderProcessReloadAttempts = 0;
|
||||
m_webView->load(url);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ private:
|
||||
|
||||
WebView *m_webView = nullptr;
|
||||
SearchToolBar *m_searchToolBar = nullptr;
|
||||
int m_renderProcessReloadAttempts = 0;
|
||||
};
|
||||
|
||||
} // namespace Zeal::Browser
|
||||
|
||||
@@ -230,7 +230,9 @@ void MainWindow::addTab(BrowserTab *tab, int index, bool activate)
|
||||
}
|
||||
|
||||
m_webViewStack->insertWidget(index, tab);
|
||||
m_tabBar->insertTab(index, tr("Loading…"));
|
||||
// Seed with "New tab" to match browsers and avoid a stranded label.
|
||||
// The placeholder icon reserves the slot so the label does not jump when the favicon loads.
|
||||
m_tabBar->insertTab(index, IconHelper::fromResource(QStringLiteral(":/icons/tabler/loader-2.svg")), tr("New tab"));
|
||||
m_tabBar->setTabData(index, QVariant::fromValue(tab));
|
||||
|
||||
if (activate) {
|
||||
|
||||
@@ -125,12 +125,17 @@ bool useThemeIcons()
|
||||
#endif
|
||||
}
|
||||
|
||||
QIcon fromResource(const QString &svgResource)
|
||||
{
|
||||
return QIcon(new TintedSvgIconEngine(svgResource));
|
||||
}
|
||||
|
||||
QIcon fromTheme(const QString &themeName, const QString &fallbackSvgResource)
|
||||
{
|
||||
if (useThemeIcons()) {
|
||||
return QIcon::fromTheme(themeName, QIcon(new TintedSvgIconEngine(fallbackSvgResource)));
|
||||
return QIcon::fromTheme(themeName, fromResource(fallbackSvgResource));
|
||||
}
|
||||
return QIcon(new TintedSvgIconEngine(fallbackSvgResource));
|
||||
return fromResource(fallbackSvgResource);
|
||||
}
|
||||
|
||||
} // namespace Zeal::WidgetUi::IconHelper
|
||||
|
||||
@@ -19,6 +19,11 @@ bool useThemeIcons();
|
||||
// color schemes. Use freedesktop icon naming for themeName (e.g. "go-previous").
|
||||
QIcon fromTheme(const QString &themeName, const QString &fallbackSvgResource);
|
||||
|
||||
// Returns a monochrome Tabler SVG loaded from svgResource and tinted to the active
|
||||
// palette, without any desktop icon theme lookup. Use this for glyphs that have no
|
||||
// suitable freedesktop equivalent (e.g. the tab loading placeholder).
|
||||
QIcon fromResource(const QString &svgResource);
|
||||
|
||||
} // namespace Zeal::WidgetUi::IconHelper
|
||||
|
||||
#endif // ZEAL_WIDGETUI_ICONHELPER_H
|
||||
|
||||
Reference in New Issue
Block a user