1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-24 12:46:35 +01:00

Add support for Navigator.registerProtocolHandler()

It is now possible to eg. register webmail to handle mailto:
links.
If a site asks to register protocol handler, it will be available
in site info widget (right click on web icon in location bar).

Requires QtWebEngine >= 5.11

BUG: 403183
FIXED-IN: 3.1.0
This commit is contained in:
David Rosca 2019-01-28 17:52:11 +01:00
parent 38b2631de9
commit db9d506cf5
No known key found for this signature in database
GPG Key ID: EBC3FC294452C6D8
12 changed files with 282 additions and 30 deletions

View File

@ -151,6 +151,7 @@ set(SRCS ${SRCS}
other/statusbar.cpp other/statusbar.cpp
other/updater.cpp other/updater.cpp
other/useragentmanager.cpp other/useragentmanager.cpp
other/protocolhandlermanager.cpp
plugins/pluginproxy.cpp plugins/pluginproxy.cpp
plugins/plugins.cpp plugins/plugins.cpp
plugins/speeddial.cpp plugins/speeddial.cpp

View File

@ -46,6 +46,7 @@
#include "scripts.h" #include "scripts.h"
#include "sessionmanager.h" #include "sessionmanager.h"
#include "closedwindowsmanager.h" #include "closedwindowsmanager.h"
#include "protocolhandlermanager.h"
#include "../config.h" #include "../config.h"
#include <QWebEngineSettings> #include <QWebEngineSettings>
@ -100,6 +101,7 @@ MainApplication::MainApplication(int &argc, char** argv)
, m_userAgentManager(nullptr) , m_userAgentManager(nullptr)
, m_searchEnginesManager(nullptr) , m_searchEnginesManager(nullptr)
, m_closedWindowsManager(nullptr) , m_closedWindowsManager(nullptr)
, m_protocolHandlerManager(nullptr)
, m_html5PermissionsManager(nullptr) , m_html5PermissionsManager(nullptr)
, m_desktopNotifications(nullptr) , m_desktopNotifications(nullptr)
, m_webProfile(nullptr) , m_webProfile(nullptr)
@ -317,6 +319,7 @@ MainApplication::MainApplication(int &argc, char** argv)
m_plugins = new PluginProxy(this); m_plugins = new PluginProxy(this);
m_autoFill = new AutoFill(this); m_autoFill = new AutoFill(this);
mApp->protocolHandlerManager();
if (!noAddons) if (!noAddons)
m_plugins->loadPlugins(); m_plugins->loadPlugins();
@ -597,6 +600,14 @@ ClosedWindowsManager* MainApplication::closedWindowsManager()
return m_closedWindowsManager; return m_closedWindowsManager;
} }
ProtocolHandlerManager *MainApplication::protocolHandlerManager()
{
if (!m_protocolHandlerManager) {
m_protocolHandlerManager = new ProtocolHandlerManager(this);
}
return m_protocolHandlerManager;
}
HTML5PermissionsManager* MainApplication::html5PermissionsManager() HTML5PermissionsManager* MainApplication::html5PermissionsManager()
{ {
if (!m_html5PermissionsManager) { if (!m_html5PermissionsManager) {

View File

@ -52,6 +52,7 @@ class DesktopNotificationsFactory;
class ProxyStyle; class ProxyStyle;
class SessionManager; class SessionManager;
class ClosedWindowsManager; class ClosedWindowsManager;
class ProtocolHandlerManager;
class FALKON_EXPORT MainApplication : public QtSingleApplication class FALKON_EXPORT MainApplication : public QtSingleApplication
{ {
@ -108,6 +109,7 @@ public:
UserAgentManager* userAgentManager(); UserAgentManager* userAgentManager();
SearchEnginesManager* searchEnginesManager(); SearchEnginesManager* searchEnginesManager();
ClosedWindowsManager* closedWindowsManager(); ClosedWindowsManager* closedWindowsManager();
ProtocolHandlerManager *protocolHandlerManager();
HTML5PermissionsManager* html5PermissionsManager(); HTML5PermissionsManager* html5PermissionsManager();
DesktopNotificationsFactory* desktopNotifications(); DesktopNotificationsFactory* desktopNotifications();
QWebEngineProfile* webProfile() const; QWebEngineProfile* webProfile() const;
@ -182,6 +184,7 @@ private:
UserAgentManager* m_userAgentManager; UserAgentManager* m_userAgentManager;
SearchEnginesManager* m_searchEnginesManager; SearchEnginesManager* m_searchEnginesManager;
ClosedWindowsManager* m_closedWindowsManager; ClosedWindowsManager* m_closedWindowsManager;
ProtocolHandlerManager *m_protocolHandlerManager;
HTML5PermissionsManager* m_html5PermissionsManager; HTML5PermissionsManager* m_html5PermissionsManager;
DesktopNotificationsFactory* m_desktopNotifications; DesktopNotificationsFactory* m_desktopNotifications;
QWebEngineProfile* m_webProfile; QWebEngineProfile* m_webProfile;

View File

@ -46,6 +46,16 @@ void Settings::syncSettings()
s_settings->sync(); s_settings->sync();
} }
QStringList Settings::childKeys() const
{
return s_settings->childKeys();
}
QStringList Settings::childGroups() const
{
return s_settings->childGroups();
}
bool Settings::contains(const QString &key) const bool Settings::contains(const QString &key) const
{ {
return s_settings->contains(key); return s_settings->contains(key);

View File

@ -38,6 +38,9 @@ public:
static QSettings* globalSettings(); static QSettings* globalSettings();
static QzSettings* staticSettings(); static QzSettings* staticSettings();
QStringList childKeys() const;
QStringList childGroups() const;
bool contains(const QString &key) const; bool contains(const QString &key) const;
void remove(const QString &key); void remove(const QString &key);

View File

@ -0,0 +1,92 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2019 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "protocolhandlermanager.h"
#include "settings.h"
#include <QWebEnginePage>
#include <QtWebEngineWidgetsVersion>
#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0)
#include <QWebEngineRegisterProtocolHandlerRequest>
#endif
ProtocolHandlerManager::ProtocolHandlerManager(QObject *parent)
: QObject(parent)
{
init();
}
QHash<QString, QUrl> ProtocolHandlerManager::protocolHandlers() const
{
return m_protocolHandlers;
}
void ProtocolHandlerManager::addProtocolHandler(const QString &scheme, const QUrl &url)
{
if (scheme.isEmpty() || url.isEmpty()) {
return;
}
m_protocolHandlers[scheme] = url;
registerHandler(scheme, url);
save();
}
void ProtocolHandlerManager::removeProtocolHandler(const QString &scheme)
{
m_protocolHandlers.remove(scheme);
save();
}
void ProtocolHandlerManager::init()
{
Settings settings;
settings.beginGroup(QSL("ProtocolHandlers"));
const QStringList keys = settings.childKeys();
for (const QString &scheme : keys) {
const QUrl url = settings.value(scheme).toUrl();
m_protocolHandlers[scheme] = url;
registerHandler(scheme, url);
}
settings.endGroup();
}
void ProtocolHandlerManager::save()
{
Settings settings;
settings.remove(QSL("ProtocolHandlers"));
settings.beginGroup(QSL("ProtocolHandlers"));
for (auto it = m_protocolHandlers.cbegin(); it != m_protocolHandlers.cend(); ++it) {
settings.setValue(it.key(), it.value());
}
settings.endGroup();
}
void ProtocolHandlerManager::registerHandler(const QString &scheme, const QUrl &url)
{
QString urlString = url.toString();
urlString.replace(QL1S("%25s"), QL1S("%s"));
QWebEnginePage *page = new QWebEnginePage(this);
connect(page, &QWebEnginePage::loadFinished, page, &QObject::deleteLater);
#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0)
connect(page, &QWebEnginePage::registerProtocolHandlerRequested, this, [](QWebEngineRegisterProtocolHandlerRequest request) {
request.accept();
});
#endif
page->setHtml(QSL("<script>navigator.registerProtocolHandler('%1', '%2', '')</script>").arg(scheme, urlString), url);
}

View File

@ -0,0 +1,44 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2019 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#pragma once
#include <QUrl>
#include <QHash>
#include <QObject>
#include "qzcommon.h"
class FALKON_EXPORT ProtocolHandlerManager : public QObject
{
Q_OBJECT
public:
explicit ProtocolHandlerManager(QObject *parent = nullptr);
QHash<QString, QUrl> protocolHandlers() const;
void addProtocolHandler(const QString &scheme, const QUrl &url);
void removeProtocolHandler(const QString &scheme);
private:
void init();
void save();
void registerHandler(const QString &scheme, const QUrl &url);
QHash<QString, QUrl> m_protocolHandlers;
};

View File

@ -23,6 +23,7 @@
#include "webpage.h" #include "webpage.h"
#include "tabbedwebview.h" #include "tabbedwebview.h"
#include "sqldatabase.h" #include "sqldatabase.h"
#include "protocolhandlermanager.h"
#include <QToolTip> #include <QToolTip>
@ -83,10 +84,38 @@ SiteInfoWidget::SiteInfoWidget(BrowserWindow* window, QWidget* parent)
} }
} }
updateProtocolHandler();
connect(ui->pushButton, &QAbstractButton::clicked, m_window->action(QSL("Tools/SiteInfo")), &QAction::trigger); connect(ui->pushButton, &QAbstractButton::clicked, m_window->action(QSL("Tools/SiteInfo")), &QAction::trigger);
connect(ui->protocolHandlerButton, &QPushButton::clicked, this, &SiteInfoWidget::protocolHandlerButtonClicked);
} }
SiteInfoWidget::~SiteInfoWidget() SiteInfoWidget::~SiteInfoWidget()
{ {
delete ui; delete ui;
} }
void SiteInfoWidget::updateProtocolHandler()
{
WebPage *page = m_window->weView()->page();
const QString scheme = page->registerProtocolHandlerRequestScheme();
const QUrl registeredUrl = mApp->protocolHandlerManager()->protocolHandlers().value(scheme);
if (!scheme.isEmpty() && registeredUrl != page->registerProtocolHandlerRequestUrl()) {
ui->protocolHandlerLabel->setText(tr("Register as <b>%1</b> links handler").arg(page->registerProtocolHandlerRequestScheme()));
ui->protocolHandlerButton->setText(tr("Register"));
} else {
ui->protocolHandlerLabel->hide();
ui->protocolHandlerButton->hide();
ui->protocolHandlerLine->hide();
}
}
void SiteInfoWidget::protocolHandlerButtonClicked()
{
WebPage *page = m_window->weView()->page();
mApp->protocolHandlerManager()->addProtocolHandler(page->registerProtocolHandlerRequestScheme(), page->registerProtocolHandlerRequestUrl());
close();
}

View File

@ -38,6 +38,9 @@ public:
~SiteInfoWidget(); ~SiteInfoWidget();
private: private:
void updateProtocolHandler();
void protocolHandlerButtonClicked();
Ui::SiteInfoWidget* ui; Ui::SiteInfoWidget* ui;
BrowserWindow* m_window; BrowserWindow* m_window;
}; };

View File

@ -38,7 +38,7 @@
<property name="rightMargin"> <property name="rightMargin">
<number>15</number> <number>15</number>
</property> </property>
<item row="5" column="0" colspan="3"> <item row="8" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing"> <property name="spacing">
<number>6</number> <number>6</number>
@ -75,23 +75,15 @@
</layout> </layout>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="secureIcon"> <widget class="QLabel" name="secureIcon"/>
<property name="text">
<string/>
</property>
</widget>
</item> </item>
<item row="2" column="1" colspan="2"> <item row="3" column="2">
<widget class="QLabel" name="secureLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QLabel" name="historyLabel"> <widget class="QLabel" name="historyLabel">
<property name="text"> <property name="sizePolicy">
<string/> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
</widget> </widget>
</item> </item>
@ -102,20 +94,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="historyIcon">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3"> <item row="1" column="0" colspan="3">
<widget class="Line" name="line_2"> <widget class="Line" name="line_2">
<property name="orientation"> <property name="orientation">
@ -123,6 +101,50 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QLabel" name="historyIcon"/>
</item>
<item row="7" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="secureLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="Line" name="protocolHandlerLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="protocolHandlerLabel"/>
</item>
<item>
<widget class="QPushButton" name="protocolHandlerButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -59,6 +59,10 @@
#include <QUrlQuery> #include <QUrlQuery>
#include <QtWebEngineWidgetsVersion> #include <QtWebEngineWidgetsVersion>
#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0)
#include <QWebEngineRegisterProtocolHandlerRequest>
#endif
QString WebPage::s_lastUploadLocation = QDir::homePath(); QString WebPage::s_lastUploadLocation = QDir::homePath();
QUrl WebPage::s_lastUnsupportedUrl; QUrl WebPage::s_lastUnsupportedUrl;
QTime WebPage::s_lastUnsupportedUrlTime; QTime WebPage::s_lastUnsupportedUrlTime;
@ -111,6 +115,13 @@ WebPage::WebPage(QObject* parent)
} }
}); });
#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0)
connect(this, &QWebEnginePage::registerProtocolHandlerRequested, this, [this](QWebEngineRegisterProtocolHandlerRequest request) {
delete m_registerProtocolHandlerRequest;
m_registerProtocolHandlerRequest = new QWebEngineRegisterProtocolHandlerRequest(request);
});
#endif
#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 12, 0) #if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 12, 0)
connect(this, &QWebEnginePage::printRequested, this, &WebPage::printRequested); connect(this, &QWebEnginePage::printRequested, this, &WebPage::printRequested);
connect(this, &QWebEnginePage::selectClientCertificate, this, [this](QWebEngineClientCertificateSelection selection) { connect(this, &QWebEnginePage::selectClientCertificate, this, [this](QWebEngineClientCertificateSelection selection) {
@ -122,6 +133,8 @@ WebPage::WebPage(QObject* parent)
WebPage::~WebPage() WebPage::~WebPage()
{ {
delete m_registerProtocolHandlerRequest;
if (m_runningLoop) { if (m_runningLoop) {
m_runningLoop->exit(1); m_runningLoop->exit(1);
m_runningLoop = 0; m_runningLoop = 0;
@ -491,6 +504,22 @@ QStringList WebPage::autoFillUsernames() const
return m_autoFillUsernames; return m_autoFillUsernames;
} }
QUrl WebPage::registerProtocolHandlerRequestUrl() const
{
if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) {
return m_registerProtocolHandlerRequest->origin();
}
return QUrl();
}
QString WebPage::registerProtocolHandlerRequestScheme() const
{
if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) {
return m_registerProtocolHandlerRequest->scheme();
}
return QString();
}
bool WebPage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result) bool WebPage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result)
{ {
if (!kEnableJsNonBlockDialogs) { if (!kEnableJsNonBlockDialogs) {

View File

@ -27,6 +27,7 @@
class QEventLoop; class QEventLoop;
class QWebEngineDownloadItem; class QWebEngineDownloadItem;
class QWebEngineRegisterProtocolHandlerRequest;
class WebView; class WebView;
class WebHitTestResult; class WebHitTestResult;
@ -63,6 +64,9 @@ public:
QStringList autoFillUsernames() const; QStringList autoFillUsernames() const;
QUrl registerProtocolHandlerRequestUrl() const;
QString registerProtocolHandlerRequestScheme() const;
bool isRunningLoop(); bool isRunningLoop();
bool isLoading() const; bool isLoading() const;
@ -106,6 +110,7 @@ private:
QEventLoop* m_runningLoop; QEventLoop* m_runningLoop;
QStringList m_autoFillUsernames; QStringList m_autoFillUsernames;
QWebEngineRegisterProtocolHandlerRequest *m_registerProtocolHandlerRequest = nullptr;
int m_loadProgress; int m_loadProgress;
bool m_blockAlerts; bool m_blockAlerts;