From f4ca67aa7f70f58d39ef8689ddd5910e215ed6cd Mon Sep 17 00:00:00 2001 From: Kirill Burtsev Date: Thu, 31 Jan 2019 13:08:21 +0100 Subject: Web Notifications API Implements API for end-user notifications. Co-authored by Allan Sandfeld Jensen [ChangeLog][Profile] Support for Web Notifications API for end-user notifications through QWebEngineNotification Task-number: QTBUG-50995 Fixes: QTBUG-51191 Change-Id: Icebaaa05275a713e801f1f8ecdaaec725fa264c8 Reviewed-by: Allan Sandfeld Jensen --- src/3rdparty | 2 +- src/core/api/core_api.pro | 2 + src/core/api/qwebenginenotification.cpp | 275 +++++++++++++++++++++ src/core/api/qwebenginenotification.h | 112 +++++++++ src/core/content_browser_client_qt.cpp | 10 +- src/core/content_browser_client_qt.h | 2 + src/core/core_chromium.pri | 4 + src/core/permission_manager_qt.cpp | 8 +- src/core/platform_notification_service_qt.cpp | 208 ++++++++++++++++ src/core/platform_notification_service_qt.h | 92 +++++++ src/core/profile_adapter.h | 14 +- src/core/profile_adapter_client.h | 4 + src/core/profile_qt.cpp | 1 + src/core/user_notification_controller.cpp | 219 ++++++++++++++++ src/core/user_notification_controller.h | 114 +++++++++ src/core/web_contents_adapter.cpp | 6 + src/core/web_contents_adapter.h | 1 + src/core/web_contents_adapter_client.h | 1 + src/core/web_contents_delegate_qt.cpp | 5 + src/core/web_contents_delegate_qt.h | 1 + src/webengine/api/qquickwebengineprofile.cpp | 23 ++ src/webengine/api/qquickwebengineprofile.h | 3 + src/webengine/api/qquickwebengineprofile_p.h | 2 + src/webengine/api/qquickwebengineview.cpp | 9 + src/webengine/api/qquickwebengineview_p.h | 3 +- src/webengine/api/qquickwebengineview_p_p.h | 1 + src/webengine/doc/src/qtwebengine-features.qdoc | 10 + src/webengine/doc/src/webengineview_lgpl.qdoc | 2 + src/webengine/plugin/plugin.cpp | 3 +- .../api/qwebenginenotificationpresenter.cpp | 101 ++++++++ .../api/qwebenginenotificationpresenter_p.h | 83 +++++++ src/webenginewidgets/api/qwebenginepage.cpp | 10 + src/webenginewidgets/api/qwebenginepage.h | 2 - src/webenginewidgets/api/qwebenginepage_p.h | 1 + src/webenginewidgets/api/qwebengineprofile.cpp | 30 +++ src/webenginewidgets/api/qwebengineprofile.h | 6 + src/webenginewidgets/api/qwebengineprofile_p.h | 6 + .../doc/src/qwebenginepage_lgpl.qdoc | 2 + src/webenginewidgets/webenginewidgets.pro | 2 + 39 files changed, 1370 insertions(+), 10 deletions(-) create mode 100644 src/core/api/qwebenginenotification.cpp create mode 100644 src/core/api/qwebenginenotification.h create mode 100644 src/core/platform_notification_service_qt.cpp create mode 100644 src/core/platform_notification_service_qt.h create mode 100644 src/core/user_notification_controller.cpp create mode 100644 src/core/user_notification_controller.h create mode 100644 src/webenginewidgets/api/qwebenginenotificationpresenter.cpp create mode 100644 src/webenginewidgets/api/qwebenginenotificationpresenter_p.h (limited to 'src') diff --git a/src/3rdparty b/src/3rdparty index 5a76a0a32..8d510183c 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 5a76a0a325a041dab3c93943c99835d3e9297620 +Subproject commit 8d510183ca27142801b56bb50d63cbb2a92d4337 diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index b5bb93847..d6ef81add 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -38,6 +38,7 @@ HEADERS = \ qwebenginecookiestore.h \ qwebenginecookiestore_p.h \ qwebenginehttprequest.h \ + qwebenginenotification.h \ qwebenginequotarequest.h \ qwebengineregisterprotocolhandlerrequest.h \ qwebengineurlrequestinterceptor.h \ @@ -51,6 +52,7 @@ SOURCES = \ qtwebenginecoreglobal.cpp \ qwebenginecookiestore.cpp \ qwebenginehttprequest.cpp \ + qwebenginenotification.cpp \ qwebenginequotarequest.cpp \ qwebengineregisterprotocolhandlerrequest.cpp \ qwebengineurlrequestinfo.cpp \ diff --git a/src/core/api/qwebenginenotification.cpp b/src/core/api/qwebenginenotification.cpp new file mode 100644 index 000000000..0b91cf273 --- /dev/null +++ b/src/core/api/qwebenginenotification.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginenotification.h" + +#include "user_notification_controller.h" + +#include + +QT_BEGIN_NAMESPACE + +using QtWebEngineCore::UserNotificationController; + +/*! + \class QWebEngineNotification + \brief The QWebEngineNotification class encapsulates the data of an HTML5 web notification. + \since 5.13 + + \inmodule QtWebEngineCore + + This class contains the information and API for HTML5 desktop and push notifications. +*/ + +class QWebEngineNotificationPrivate : public UserNotificationController::Client { +public: + QWebEngineNotificationPrivate(QWebEngineNotification *q, const QSharedPointer &controller) + : controller(controller) + , q(q) + { + controller->setClient(this); + } + ~QWebEngineNotificationPrivate() override + { + if (controller->client() == this) + controller->setClient(0); + } + + // UserNotificationController::Client: + virtual void notificationClosed(const UserNotificationController *) Q_DECL_OVERRIDE + { + Q_EMIT q->closed(); + } + + QSharedPointer controller; + QWebEngineNotification *q; +}; + + +/*! + Creates a null QWebEngineNotification. + + \sa isNull() +*/ +QWebEngineNotification::QWebEngineNotification() { } + +/*! \internal +*/ +QWebEngineNotification::QWebEngineNotification(const QSharedPointer &controller) + : d_ptr(new QWebEngineNotificationPrivate(this, controller)) +{ } + +/*! \internal +*/ +QWebEngineNotification::QWebEngineNotification(const QWebEngineNotification &other) + : QObject() + , d_ptr(new QWebEngineNotificationPrivate(this, other.d_ptr->controller)) +{ } + +/*! \internal +*/ +QWebEngineNotification::~QWebEngineNotification() +{ +} + +/*! \internal +*/ +const QWebEngineNotification &QWebEngineNotification::operator=(const QWebEngineNotification &other) +{ + d_ptr.reset(new QWebEngineNotificationPrivate(this, other.d_ptr->controller)); + return *this; +} + +/*! + Returns \c true if the two notifications belong to the same message chain. + That is, if their tag() and origin() are the same. This means one is + a replacement or an update of the \a other. + + \sa tag(), origin() +*/ +bool QWebEngineNotification::matches(const QWebEngineNotification &other) const +{ + if (!d_ptr) + return !other.d_ptr; + if (!other.d_ptr) + return false; + return tag() == other.tag() && origin() == other.origin(); +} + +/*! + \property QWebEngineNotification::title + \brief The title of the notification. + \sa message() +*/ +QString QWebEngineNotification::title() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->title() : QString(); +} + +/*! + \property QWebEngineNotification::message + \brief The body of the notification message. + \sa title() +*/ + +QString QWebEngineNotification::message() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->body() : QString(); +} + +/*! + \property QWebEngineNotification::tag + \brief The tag of the notification message. + + New notifications that have the same tag and origin URL as an existing + one should replace or update the old notification with the same tag. + + \sa matches() +*/ +QString QWebEngineNotification::tag() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->tag() : QString(); +} + +/*! + \property QWebEngineNotification::origin + \brief The URL of the page sending the notification. +*/ + +QUrl QWebEngineNotification::origin() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->origin() : QUrl(); +} + +/*! + \property QWebEngineNotification::icon + \brief The icon to be shown with the notification. + + If no icon is set by the sender, an null QIcon is returned. +*/ +QIcon QWebEngineNotification::icon() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->icon() : QIcon(); +} + +/*! + \property QWebEngineNotification::language + \brief The primary language for the notification's title and body. + + Its value is a valid BCP 47 language tag, or the empty string. + + \sa title(), message() +*/ +QString QWebEngineNotification::language() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->language() : QString(); +} + +/*! + \property QWebEngineNotification::direction + \brief The text direction for the notification's title and body. + \sa title(), message() +*/ +QWebEngineNotification::Direction QWebEngineNotification::direction() const +{ + Q_D(const QWebEngineNotification); + return d ? static_cast(d->controller->direction()) : DirectionAuto; +} + +/*! + Returns \c true if the notification is a default constructed null notification. +*/ +bool QWebEngineNotification::isNull() const +{ + return d_ptr.isNull(); +} + +/*! + Creates and dispatches a JavaScript \e {show event} on notification. + + Should be called by the notification platform when the notification has been shown to user. +*/ +void QWebEngineNotification::show() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationDisplayed(); +} + +/*! + Creates and dispatches a JavaScript \e {click event} on notification. + + Should be called by the notification platform when the notification is activated by the user. +*/ +void QWebEngineNotification::click() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationClicked(); +} + +/*! + Creates and dispatches a JavaScript \e {close event} on notification. + + Should be called by the notification platform when the notification is closed, + either by the underlying platform or by the user. +*/ +void QWebEngineNotification::close() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationClosed(); +} + +/*! + \fn void QWebEngineNotification::closed() + + This signal is emitted when the web page calls close steps for the notification, + and it no longer needs to be shown. +*/ + +QT_END_NAMESPACE + +#include "moc_qwebenginenotification.cpp" diff --git a/src/core/api/qwebenginenotification.h b/src/core/api/qwebenginenotification.h new file mode 100644 index 000000000..b6b7414f9 --- /dev/null +++ b/src/core/api/qwebenginenotification.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINENOTIFICATION_H +#define QWEBENGINENOTIFICATION_H + +#include + +#include +#include +#include +#include +#include + +namespace QtWebEngineCore { +class UserNotificationController; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineNotificationPrivate; + +class QWEBENGINECORE_EXPORT QWebEngineNotification : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL) + Q_PROPERTY(QIcon icon READ icon CONSTANT FINAL) + Q_PROPERTY(QString title READ title CONSTANT FINAL) + Q_PROPERTY(QString message READ message CONSTANT FINAL) + Q_PROPERTY(QString tag READ tag CONSTANT FINAL) + Q_PROPERTY(QString language READ language CONSTANT FINAL) + Q_PROPERTY(Direction direction READ direction CONSTANT FINAL) + +public: + QWebEngineNotification(); + QWebEngineNotification(const QWebEngineNotification &); + virtual ~QWebEngineNotification(); + const QWebEngineNotification &operator=(const QWebEngineNotification &); + + enum Direction { + LeftToRight = Qt::LeftToRight, + RightToLeft = Qt::RightToLeft, + DirectionAuto = Qt::LayoutDirectionAuto + }; + Q_ENUM(Direction) + + bool matches(const QWebEngineNotification &) const; + + QUrl origin() const; + QIcon icon() const; + QString title() const; + QString message() const; + QString tag() const; + QString language() const; + Direction direction() const; + + bool isNull() const; + +public Q_SLOTS: + void show() const; + void click() const; + void close() const; + +Q_SIGNALS: + void closed(); + +private: + QWebEngineNotification(const QSharedPointer &); + Q_DECLARE_PRIVATE(QWebEngineNotification) + QScopedPointer d_ptr; + friend class QQuickWebEngineProfilePrivate; + friend class QWebEngineProfilePrivate; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINENOTIFICATION_H diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 3861d1c95..a9959a82b 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -103,6 +103,7 @@ #include "media_capture_devices_dispatcher.h" #include "net/network_delegate_qt.h" #include "net/url_request_context_getter_qt.h" +#include "platform_notification_service_qt.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "printing/printing_message_filter_qt.h" #endif @@ -454,7 +455,7 @@ void ContentBrowserClientQt::GetAdditionalMappedFilesForChildProcess(const base: void ContentBrowserClientQt::DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) { browser_host->GetPpapiHost()->AddHostFactoryFilter( - base::WrapUnique(new QtWebEngineCore::PepperHostFactoryQt(browser_host))); + std::make_unique(browser_host)); } #endif @@ -463,6 +464,13 @@ content::DevToolsManagerDelegate* ContentBrowserClientQt::GetDevToolsManagerDele return new DevToolsManagerDelegateQt; } +content::PlatformNotificationService *ContentBrowserClientQt::GetPlatformNotificationService() +{ + if (!m_platformNotificationService) + m_platformNotificationService = std::make_unique(); + return m_platformNotificationService.get(); +} + // This is a really complicated way of doing absolutely nothing, but Mojo demands it: class ServiceDriver : public blink::mojom::InsecureInputService diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index fc938f882..403ff3a9d 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -108,6 +108,7 @@ public: std::unique_ptr delegate) override; std::unique_ptr CreateClientCertStore(content::ResourceContext *resource_context) override; content::DevToolsManagerDelegate *GetDevToolsManagerDelegate() override; + content::PlatformNotificationService *GetPlatformNotificationService() override; std::string GetApplicationLocale() override; std::string GetAcceptLangs(content::BrowserContext* context) override; @@ -210,6 +211,7 @@ private: BrowserMainPartsQt* m_browserMainParts; std::unique_ptr m_resourceDispatcherHostDelegate; + std::unique_ptr m_platformNotificationService; scoped_refptr m_shareGroupQtQuick; std::unique_ptr m_frameInterfaces; std::unique_ptr> m_frameInterfacesParameterized; diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index edf6806a3..aa595036d 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -98,6 +98,7 @@ SOURCES = \ ozone/platform_window_qt.cpp \ ozone/surface_factory_qt.cpp \ permission_manager_qt.cpp \ + platform_notification_service_qt.cpp \ process_main.cpp \ profile_adapter.cpp \ profile_adapter_client.cpp \ @@ -123,6 +124,7 @@ SOURCES = \ touch_selection_controller_client_qt.cpp \ touch_selection_menu_controller.cpp \ type_conversion.cpp \ + user_notification_controller.cpp \ user_script.cpp \ visited_links_manager_qt.cpp \ web_contents_adapter.cpp \ @@ -201,6 +203,7 @@ HEADERS = \ ozone/platform_window_qt.h \ ozone/surface_factory_qt.h \ permission_manager_qt.h \ + platform_notification_service_qt.h \ process_main.h \ profile_adapter.h \ profile_adapter_client.h \ @@ -230,6 +233,7 @@ HEADERS = \ touch_selection_controller_client_qt.h \ touch_selection_menu_controller.h \ type_conversion.h \ + user_notification_controller.h \ user_script.h \ visited_links_manager_qt.h \ web_contents_adapter.h \ diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index cf3041e7a..2a7311187 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -61,8 +61,9 @@ ProfileAdapter::PermissionType toQt(content::PermissionType type) return ProfileAdapter::AudioCapturePermission; case content::PermissionType::VIDEO_CAPTURE: return ProfileAdapter::VideoCapturePermission; - case content::PermissionType::FLASH: case content::PermissionType::NOTIFICATIONS: + return ProfileAdapter::NotificationPermission; + case content::PermissionType::FLASH: case content::PermissionType::MIDI_SYSEX: case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER: case content::PermissionType::MIDI: @@ -188,6 +189,9 @@ int PermissionManagerQt::RequestPermission(content::PermissionType permission, m_requests.insert(request_id, request); if (permissionType == ProfileAdapter::GeolocationPermission) contentsDelegate->requestGeolocationPermission(request.origin); + else if (permissionType == ProfileAdapter::NotificationPermission) + contentsDelegate->requestUserNotificationPermission(request.origin); + return request_id; } @@ -236,6 +240,8 @@ int PermissionManagerQt::RequestPermissions(const std::vectorrequestGeolocationPermission(request.origin); + else if (permissionType == ProfileAdapter::NotificationPermission) + contentsDelegate->requestUserNotificationPermission(request.origin); } return request_id; } diff --git a/src/core/platform_notification_service_qt.cpp b/src/core/platform_notification_service_qt.cpp new file mode 100644 index 000000000..dff3aed61 --- /dev/null +++ b/src/core/platform_notification_service_qt.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "platform_notification_service_qt.h" + +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/permission_type.h" +#include "content/public/browser/notification_event_dispatcher.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +#include "profile_adapter.h" +#include "profile_adapter_client.h" +#include "profile_qt.h" +#include "user_notification_controller.h" +#include "resource_context_qt.h" +#include "type_conversion.h" + +#include + +namespace QtWebEngineCore { + +struct NonPersistentNotificationDelegate : UserNotificationController::Delegate { + NonPersistentNotificationDelegate(const std::string &id) : notification_id(id) { } + + virtual void shown() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentShowEvent(notification_id); + } + + virtual void clicked() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentClickEvent(notification_id, base::DoNothing()); + } + + virtual void closed(bool /*by_user*/) override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentCloseEvent(notification_id, base::DoNothing()); + } + + const std::string notification_id; +}; + +struct PersistentNotificationDelegate : UserNotificationController::Delegate { + PersistentNotificationDelegate(content::BrowserContext *context, const std::string &id, const GURL &origin) + : browser_context(context), notification_id(id), origin(origin) { } + + virtual void shown() override { } + + virtual void clicked() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNotificationClickEvent(browser_context, notification_id, origin, base::nullopt, base::nullopt, base::DoNothing()); + } + + virtual void closed(bool by_user) override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNotificationCloseEvent(browser_context, notification_id, origin, by_user, base::DoNothing()); + } + + content::BrowserContext *browser_context; + const std::string notification_id; + const GURL origin; +}; + + +PlatformNotificationServiceQt::PlatformNotificationServiceQt() {} + +PlatformNotificationServiceQt::~PlatformNotificationServiceQt() {} + +void PlatformNotificationServiceQt::DisplayNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id, + const GURL &origin, + const blink::PlatformNotificationData ¬ificationData, + const blink::NotificationResources ¬ificationResources) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast(browser_context); + + auto delegate = new NonPersistentNotificationDelegate(notification_id); + QSharedPointer controller( + new UserNotificationController(notificationData, notificationResources, origin, delegate)); + + profile->profileAdapter()->ephemeralNotifications().insert(QByteArray::fromStdString(notification_id), controller); + + const QList clients = profile->profileAdapter()->clients(); + for (ProfileAdapterClient *client : clients) + client->showNotification(controller); +} + +void PlatformNotificationServiceQt::DisplayPersistentNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id, + const GURL &service_worker_origin, + const GURL &origin, + const blink::PlatformNotificationData ¬ificationData, + const blink::NotificationResources ¬ificationResources) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt * profile = static_cast(browser_context); + + auto delegate = new PersistentNotificationDelegate(profile, notification_id, service_worker_origin); + QSharedPointer controller( + new UserNotificationController(notificationData, notificationResources, service_worker_origin, delegate)); + + profile->profileAdapter()->persistentNotifications().insert(QByteArray::fromStdString(notification_id), controller); + const QList clients = profile->profileAdapter()->clients(); + for (ProfileAdapterClient *client : clients) + client->showNotification(controller); +} + +void PlatformNotificationServiceQt::CloseNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast(browser_context); + + QSharedPointer notificationController = + profile->profileAdapter()->ephemeralNotifications().take(QByteArray::fromStdString(notification_id)).lock(); + if (notificationController) + notificationController->closeNotification(); +} + +void PlatformNotificationServiceQt::ClosePersistentNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast(browser_context); + + QSharedPointer notificationController = + profile->profileAdapter()->persistentNotifications().take(QByteArray::fromStdString(notification_id)); + if (notificationController) + notificationController->closeNotification(); +} + +void PlatformNotificationServiceQt::GetDisplayedNotifications( + content::BrowserContext *browser_context, + const DisplayedNotificationsCallback &callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast(browser_context); + + std::unique_ptr> movableStdStringSet = std::make_unique>(); + auto it = profile->profileAdapter()->persistentNotifications().constBegin(); + const auto end = profile->profileAdapter()->persistentNotifications().constEnd(); + while (it != end) { + if (it.value()->isShown()) + movableStdStringSet->insert(it.key().toStdString()); + ++it; + } + + callback.Run(std::move(movableStdStringSet), true /* supports_synchronization */); +} + +int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId(content::BrowserContext *browser_context) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + auto prefs = static_cast(browser_context)->GetPrefs(); + int64_t nextId = prefs->GetInteger(prefs::kNotificationNextPersistentId) + 1; + prefs->SetInt64(prefs::kNotificationNextPersistentId, nextId); + return nextId; +} + +} // namespace QtWebEngineCore diff --git a/src/core/platform_notification_service_qt.h b/src/core/platform_notification_service_qt.h new file mode 100644 index 000000000..66cee9ed0 --- /dev/null +++ b/src/core/platform_notification_service_qt.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLATFORM_NOTIFICATION_SERVICE_QT_H +#define PLATFORM_NOTIFICATION_SERVICE_QT_H + +#include "content/public/browser/platform_notification_service.h" + +namespace QtWebEngineCore { + +class PlatformNotificationServiceQt : public content::PlatformNotificationService { +public: + PlatformNotificationServiceQt(); + ~PlatformNotificationServiceQt() override; + + // Displays the notification described in |notification_data| to the user. A + // closure through which the notification can be closed will be stored in the + // |cancel_callback| argument. This method must be called on the UI thread. + void DisplayNotification(content::BrowserContext* browser_context, + const std::string& notification_id, + const GURL& origin, + const blink::PlatformNotificationData& notificationData, + const blink::NotificationResources& notificationResources) override; + + // Displays the persistent notification described in |notification_data| to + // the user. This method must be called on the UI thread. + void DisplayPersistentNotification(content::BrowserContext* browser_context, + const std::string& notification_id, + const GURL& service_worker_origin, + const GURL& origin, + const blink::PlatformNotificationData& notification_data, + const blink::NotificationResources& notification_resources) override; + + // Closes the notification identified by |notification_id|. + // This method must be called on the UI thread. + void CloseNotification(content::BrowserContext* browser_context, const std::string& notification_id) override; + + // Closes the persistent notification identified by |persistent_notification_id|. + // This method must be called on the UI thread. + void ClosePersistentNotification(content::BrowserContext* browser_context, const std::string& notification_id) override; + + // Retrieves the ids of all currently displaying notifications and + // posts |callback| with the result. + void GetDisplayedNotifications(content::BrowserContext* browser_context, const DisplayedNotificationsCallback& callback) override; + + // Reads the value of the next persistent notification ID from the profile and + // increments the value, as it is called once per notification write. + virtual int64_t ReadNextPersistentNotificationId(content::BrowserContext* browser_context) override; + + // Records a given notification to UKM. + virtual void RecordNotificationUkmEvent(content::BrowserContext*, const content::NotificationDatabaseData&) override { } +}; + +} // namespace QtWebEngineCore + +#endif // PLATFORM_NOTIFICATION_SERVICE_QT_H diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index 800058bc5..482835010 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -69,8 +69,9 @@ QT_FORWARD_DECLARE_CLASS(QObject) namespace QtWebEngineCore { -class ProfileAdapterClient; +class UserNotificationController; class DownloadManagerDelegateQt; +class ProfileAdapterClient; class ProfileQt; class UserResourceControllerHost; class VisitedLinksManagerQt; @@ -153,8 +154,7 @@ public: enum PermissionType { UnsupportedPermission = 0, GeolocationPermission = 1, -// Reserved: -// NotificationPermission = 2, + NotificationPermission = 2, AudioCapturePermission = 3, VideoCapturePermission = 4, ClipboardRead = 5, @@ -200,6 +200,11 @@ public: void removePageRequestInterceptor(); bool hasPageRequestInterceptor() const { return m_pageRequestInterceptors > 0; } + QHash> &ephemeralNotifications() + { return m_ephemeralNotifications; } + QHash> &persistentNotifications() + { return m_persistentNotifications; } + private: void updateCustomUrlSchemeHandlers(); void resetVisitedLinksManager(); @@ -224,6 +229,9 @@ private: PersistentCookiesPolicy m_persistentCookiesPolicy; VisitedLinksPolicy m_visitedLinksPolicy; QHash> m_customUrlSchemeHandlers; + QHash> m_ephemeralNotifications; + QHash> m_persistentNotifications; + QList m_clients; int m_httpCacheMaxSize; int m_pageRequestInterceptors; diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h index 4711f8bcf..0309200b4 100644 --- a/src/core/profile_adapter_client.h +++ b/src/core/profile_adapter_client.h @@ -52,12 +52,14 @@ #define PROFILE_ADAPTER_CLIENT_H #include "qtwebenginecoreglobal_p.h" +#include #include #include namespace QtWebEngineCore { class WebContentsAdapterClient; +class UserNotificationController; class QWEBENGINECORE_PRIVATE_EXPORT ProfileAdapterClient { @@ -143,6 +145,8 @@ public: virtual void downloadRequested(DownloadItemInfo &info) = 0; virtual void downloadUpdated(const DownloadItemInfo &info) = 0; virtual void useForGlobalCertificateVerificationChanged() {} + virtual void showNotification(QSharedPointer &) { } + static QString downloadInterruptReasonToString(DownloadInterruptReason reason); }; diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp index 0ede1df55..624a52f7b 100644 --- a/src/core/profile_qt.cpp +++ b/src/core/profile_qt.cpp @@ -106,6 +106,7 @@ ProfileQt::ProfileQt(ProfileAdapter *profileAdapter) registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckUseSpellingService, false); #endif // QT_CONFIG(webengine_spellchecker) registry->RegisterBooleanPref(prefs::kShowInternalAccessibilityTree, false); + registry->RegisterIntegerPref(prefs::kNotificationNextPersistentId, 10000); #if BUILDFLAG(ENABLE_EXTENSIONS) registry->RegisterDictionaryPref(extensions::pref_names::kExtensions); diff --git a/src/core/user_notification_controller.cpp b/src/core/user_notification_controller.cpp new file mode 100644 index 000000000..82cb57e51 --- /dev/null +++ b/src/core/user_notification_controller.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "user_notification_controller.h" + +#include "type_conversion.h" + +#include "base/callback.h" +#include "content/public/browser/notification_event_dispatcher.h" +#include "third_party/blink/public/common/notifications/notification_resources.h" +#include "third_party/blink/public/common/notifications/platform_notification_data.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +#include + +namespace QtWebEngineCore { + +static Qt::LayoutDirection toDirection(blink::PlatformNotificationData::Direction direction) +{ + switch (direction) { + case blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT: + return Qt::LeftToRight; + case blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT: + return Qt::RightToLeft; + case blink::PlatformNotificationData::DIRECTION_AUTO: + default: + break; + } + return Qt::LayoutDirectionAuto; +} + +class UserNotificationControllerPrivate { +public: + UserNotificationControllerPrivate(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin) + : m_params(params) + , m_origin(origin) + , m_delegate(nullptr) + , m_resources(resources) + , m_client(nullptr) + , m_iconGenerated(false) + , m_imageGenerated(false) + , m_badgeGenerated(false) + , m_shown(false) + { } + + blink::PlatformNotificationData m_params; + GURL m_origin; + std::unique_ptr m_delegate; + blink::NotificationResources m_resources; + UserNotificationController::Client *m_client; + QIcon m_icon; + QImage m_image; + QImage m_badge; + bool m_iconGenerated; + bool m_imageGenerated; + bool m_badgeGenerated; + bool m_shown; +}; + + +UserNotificationController::UserNotificationController(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin, + Delegate *delegate) + : d(new UserNotificationControllerPrivate(params, resources, origin)) +{ + d->m_delegate.reset(delegate); +} + +UserNotificationController::~UserNotificationController() +{ + delete d; + d = nullptr; +} + +void UserNotificationController::notificationDisplayed() +{ + if (!d->m_shown) { + d->m_shown = true; + if (d->m_delegate) + d->m_delegate->shown(); + } +} + +void UserNotificationController::notificationClosed() +{ + d->m_shown = false; + if (d->m_delegate) + d->m_delegate->closed(true); +} + +void UserNotificationController::notificationClicked() +{ + if (d->m_delegate) + d->m_delegate->clicked(); +} + +void UserNotificationController::closeNotification() +{ + d->m_shown = false; + if (d->m_client) + d->m_client->notificationClosed(this); +} + +void UserNotificationController::setClient(UserNotificationController::Client* client) +{ + d->m_client = client; +} + +UserNotificationController::Client* UserNotificationController::client() +{ + return d->m_client; +} + +QUrl UserNotificationController::origin() const +{ + return toQt(d->m_origin); +} + +QIcon UserNotificationController::icon() const +{ + if (!d->m_iconGenerated) { + d->m_iconGenerated = true; + if (!d->m_resources.notification_icon.isNull()) { + QImage image = toQImage(d->m_resources.notification_icon); + if (!image.isNull()) + d->m_icon = QIcon(QPixmap::fromImage(std::move(image), Qt::NoFormatConversion)); + } + } + return d->m_icon; +} + +QImage UserNotificationController::image() const +{ + if (d->m_imageGenerated) + return d->m_image; + d->m_image = toQImage(d->m_resources.image); + d->m_imageGenerated = true; + return d->m_image; +} + +QImage UserNotificationController::badge() const +{ + if (d->m_badgeGenerated) + return d->m_badge; + d->m_badge = toQImage(d->m_resources.badge); + d->m_badgeGenerated = true; + return d->m_badge; +} + +QString UserNotificationController::title() const +{ + return toQt(d->m_params.title); +} + +QString UserNotificationController::body() const +{ + return toQt(d->m_params.body); +} + +QString UserNotificationController::tag() const +{ + return toQt(d->m_params.tag); +} + +QString UserNotificationController::language() const +{ + return toQt(d->m_params.lang); +} + +Qt::LayoutDirection UserNotificationController::direction() const +{ + return toDirection(d->m_params.direction); +} + +bool UserNotificationController::isShown() const +{ + return d->m_shown; +} + +} // namespace QtWebEngineCore diff --git a/src/core/user_notification_controller.h b/src/core/user_notification_controller.h new file mode 100644 index 000000000..840074843 --- /dev/null +++ b/src/core/user_notification_controller.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESKTOP_NOTIFICATION_CONTROLLER_H +#define DESKTOP_NOTIFICATION_CONTROLLER_H + +#include "qtwebenginecoreglobal.h" + +#include +#include +#include + +class GURL; + +namespace blink { + struct NotificationResources; + struct PlatformNotificationData; +} + +namespace QtWebEngineCore { + +class UserNotificationControllerPrivate; + +// Works as an accessor and owner of chromium objects related to showing desktop notifications. +class QWEBENGINECORE_EXPORT UserNotificationController : public QEnableSharedFromThis { +public: + struct Delegate { + virtual ~Delegate() { } + virtual void shown() = 0; + virtual void clicked() = 0; + virtual void closed(bool byUser) = 0; + }; + + UserNotificationController(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin, + Delegate *delegate); + ~UserNotificationController(); + + // The notification was shown. + void notificationDisplayed(); + + // The notification was closed. + void notificationClosed(); + + // The user clicked on the notification. + void notificationClicked(); + + // Chromium requests to close the notification. + void closeNotification(); + + QUrl origin() const; + QIcon icon() const; + QImage image() const; + QImage badge() const; + QString title() const; + QString body() const; + QString tag() const; + QString language() const; + Qt::LayoutDirection direction() const; + + bool isShown() const; + + class Client { + public: + virtual ~Client() { } + virtual void notificationClosed(const UserNotificationController *) = 0; + }; + void setClient(Client *client); + Client* client(); + +private: + UserNotificationControllerPrivate *d; +}; + +} // namespace QtWebEngineCore + +#endif // DESKTOP_NOTIFICATION_CONTROLLER_H diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 0c884d265..d85d34eb2 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -1271,6 +1271,12 @@ void WebContentsAdapter::runGeolocationRequestCallback(const QUrl &securityOrigi m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::GeolocationPermission, allowed); } +void WebContentsAdapter::runUserNotificationRequestCallback(const QUrl &securityOrigin, bool allowed) +{ + CHECK_INITIALIZED(); + m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::NotificationPermission, allowed); +} + void WebContentsAdapter::grantMouseLockPermission(bool granted) { CHECK_INITIALIZED(); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index b4a01fb17..c6e4f2256 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -183,6 +183,7 @@ public: void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags); void runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed); void grantMouseLockPermission(bool granted); + void runUserNotificationRequestCallback(const QUrl &securityOrigin, bool allowed); void setBackgroundColor(const QColor &color); QAccessibleInterface *browserAccessible(); diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index f4937f0d4..d155ed391 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -459,6 +459,7 @@ public: virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runQuotaRequest(QWebEngineQuotaRequest) = 0; virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0; + virtual void runUserNotificationPermissionRequest(const QUrl &securityOrigin) = 0; virtual WebEngineSettings *webEngineSettings() const = 0; RenderProcessTerminationStatus renderProcessExitStatus(int); virtual void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 963b89a3f..4fcf2944d 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -585,6 +585,11 @@ void WebContentsDelegateQt::requestGeolocationPermission(const QUrl &requestingO m_viewClient->runGeolocationPermissionRequest(requestingOrigin); } +void WebContentsDelegateQt::requestUserNotificationPermission(const QUrl &requestingOrigin) +{ + m_viewClient->runUserNotificationPermissionRequest(requestingOrigin); +} + extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition); void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture) diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 40f585767..77f6cc389 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -148,6 +148,7 @@ public: void allowCertificateError(const QSharedPointer &); void selectClientCert(const QSharedPointer &); void requestGeolocationPermission(const QUrl &requestingOrigin); + void requestUserNotificationPermission(const QUrl &requestingOrigin); void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture); FaviconManager *faviconManager(); diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index 8a6c20f67..cf9dae90a 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -46,6 +46,7 @@ #include "qquickwebenginesettings_p.h" #include "qquickwebengineview_p_p.h" #include "qwebenginecookiestore.h" +#include "qwebenginenotification.h" #include @@ -150,6 +151,13 @@ ASSERT_ENUMS_MATCH(QQuickWebEngineDownloadItem::MimeHtmlSaveFormat, QtWebEngineC The \a download argument holds the state of the finished download instance. */ +/*! + \fn QQuickWebEngineProfile::userNotification(QWebEngineNotification *notification) + + This signal is emitted whenever there is a newly created user notification. + The \a notification argument holds the notification instance to query data and interact with. +*/ + QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(ProfileAdapter *profileAdapter) : m_settings(new QQuickWebEngineSettings()) , m_profileAdapter(profileAdapter) @@ -285,6 +293,14 @@ void QQuickWebEngineProfilePrivate::useForGlobalCertificateVerificationChanged() Q_EMIT q->useForGlobalCertificateVerificationChanged(); } +void QQuickWebEngineProfilePrivate::showNotification(QSharedPointer &controller) +{ + Q_Q(QQuickWebEngineProfile); + auto notification = new QWebEngineNotification(controller); + QQmlEngine::setObjectOwnership(notification, QQmlEngine::JavaScriptOwnership); + Q_EMIT q->userNotification(notification); +} + void QQuickWebEngineProfilePrivate::userScripts_append(QQmlListProperty *p, QQuickWebEngineScript *script) { Q_ASSERT(p && p->data); @@ -364,6 +380,13 @@ void QQuickWebEngineProfilePrivate::userScripts_clear(QQmlListProperty &controller) override; + // QQmlListPropertyHelpers static void userScripts_append(QQmlListProperty *p, QQuickWebEngineScript *script); static int userScripts_count(QQmlListProperty *p); diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 5e6a45924..e7b2d8c9c 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -320,6 +320,12 @@ void QQuickWebEngineViewPrivate::runGeolocationPermissionRequest(const QUrl &url Q_EMIT q->featurePermissionRequested(url, QQuickWebEngineView::Geolocation); } +void QQuickWebEngineViewPrivate::runUserNotificationPermissionRequest(const QUrl &url) +{ + Q_Q(QQuickWebEngineView); + Q_EMIT q->featurePermissionRequested(url, QQuickWebEngineView::Notifications); +} + void QQuickWebEngineViewPrivate::showColorDialog(QSharedPointer controller) { Q_Q(QQuickWebEngineView); @@ -1550,6 +1556,9 @@ void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQu WebContentsAdapterClient::MediaDesktopAudioCapture | WebContentsAdapterClient::MediaDesktopVideoCapture)); break; + case Notifications: + d_ptr->adapter->runUserNotificationRequestCallback(securityOrigin, granted); + break; default: Q_UNREACHABLE(); } diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 3a40abf0a..c851dcb8d 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -209,7 +209,8 @@ public: MediaAudioVideoCapture, Geolocation, DesktopVideoCapture, - DesktopAudioVideoCapture + DesktopAudioVideoCapture, + Notifications, }; Q_ENUM(Feature) diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 4e8657651..543d7b119 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -145,6 +145,7 @@ public: void allowCertificateError(const QSharedPointer &errorController) override; void selectClientCert(const QSharedPointer &selectController) override; void runGeolocationPermissionRequest(QUrl const&) override; + void runUserNotificationPermissionRequest(QUrl const&) override; void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) override; void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) override; void updateScrollPosition(const QPointF &position) override; diff --git a/src/webengine/doc/src/qtwebengine-features.qdoc b/src/webengine/doc/src/qtwebengine-features.qdoc index 1dce17e08..64e9badb1 100644 --- a/src/webengine/doc/src/qtwebengine-features.qdoc +++ b/src/webengine/doc/src/qtwebengine-features.qdoc @@ -50,6 +50,7 @@ \li \l{Touch} \li \l{View Source} \li \l{WebRTC} + \li \l{Notifications} \endlist \section1 Audio and Video Codecs @@ -511,4 +512,13 @@ This feature can be tested by setting up a webcam or microphone and then opening \c https://test.webrtc.org/ in \l{WebEngine Widgets Simple Browser Example}{Simple Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser}. + + \section1 Notifications + + Qt WebEngine supports JavaScript Web Notification API. + The application has to explicitly allow the feature by using + QWebEnginePage::Notifications or \l{WebEngineView::Feature} + {WebEngineView.Notifications}. + + Support for this feature was added in Qt 5.13.0. */ diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc index d96aabc97..a6f2af39e 100644 --- a/src/webengine/doc/src/webengineview_lgpl.qdoc +++ b/src/webengine/doc/src/webengineview_lgpl.qdoc @@ -858,6 +858,8 @@ (Added in Qt 5.10) \value DesktopAudioVideoCapture Both audio and video output capture. (Added in Qt 5.10) + \value WebEnginView.Notifications + Web notifications for the end-user. \sa featurePermissionRequested(), grantFeaturePermission() */ diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index 0e63989ee..82a76760d 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -161,7 +162,7 @@ public: tr("Cannot create a separate instance of WebEngineClientCertificateSelection")); qmlRegisterUncreatableType(uri, 1, 9, "WebEngineClientCertificateOption", tr("Cannot create a separate instance of WebEngineClientCertificateOption")); - + qmlRegisterUncreatableType(uri, 1, 9, "WebEngineNotification", msgUncreatableType("WebEngineNotification")); } private: diff --git a/src/webenginewidgets/api/qwebenginenotificationpresenter.cpp b/src/webenginewidgets/api/qwebenginenotificationpresenter.cpp new file mode 100644 index 000000000..c15a80373 --- /dev/null +++ b/src/webenginewidgets/api/qwebenginenotificationpresenter.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginenotificationpresenter_p.h" + +#include + +QT_BEGIN_NAMESPACE + +DefaultNotificationPresenter::DefaultNotificationPresenter(QObject *parent) : QObject(parent) +{ +#ifndef QT_NO_SYSTEMTRAYICON + m_systemTrayIcon = new QSystemTrayIcon(this); + connect(m_systemTrayIcon, &QSystemTrayIcon::messageClicked, this, &DefaultNotificationPresenter::messageClicked); +#endif +} + +DefaultNotificationPresenter::~DefaultNotificationPresenter() +{ +} + +void DefaultNotificationPresenter::show(const QWebEngineNotification ¬ification) +{ + if (!m_activeNotification.isNull()) + m_activeNotification.close(); + m_activeNotification = notification; +#ifndef QT_NO_SYSTEMTRAYICON + if (m_systemTrayIcon) { + m_systemTrayIcon->show(); + QIcon icon = notification.icon(); + if (!icon.isNull()) + m_systemTrayIcon->showMessage(notification.title(), notification.message(), icon); + else + m_systemTrayIcon->showMessage(notification.title(), notification.message()); + notification.show(); + connect(&m_activeNotification, &QWebEngineNotification::closed, this, &DefaultNotificationPresenter::closeNotification); + } +#endif +} + +void DefaultNotificationPresenter::messageClicked() +{ + if (!m_activeNotification.isNull()) + m_activeNotification.click(); +} + +void DefaultNotificationPresenter::closeNotification() +{ +#ifndef QT_NO_SYSTEMTRAYICON + const QWebEngineNotification *canceled = static_cast(QObject::sender()); + if (m_systemTrayIcon && canceled->matches(m_activeNotification)) + m_systemTrayIcon->hide(); +#endif +} + +void defaultNotificationPresenter(const QWebEngineNotification ¬ification) +{ + static DefaultNotificationPresenter *presenter = nullptr; + if (!presenter) + presenter = new DefaultNotificationPresenter(); + presenter->show(notification); +} + + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginenotificationpresenter_p.h b/src/webenginewidgets/api/qwebenginenotificationpresenter_p.h new file mode 100644 index 000000000..a66dbc1b2 --- /dev/null +++ b/src/webenginewidgets/api/qwebenginenotificationpresenter_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINENOTIFICATIONPRESENTER_P_H +#define QWEBENGINENOTIFICATIONPRESENTER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QSystemTrayIcon; + +class DefaultNotificationPresenter : public QObject { + Q_OBJECT +public: + DefaultNotificationPresenter(QObject *parent = nullptr); + virtual ~DefaultNotificationPresenter(); + + void show(const QWebEngineNotification ¬ification); + +private Q_SLOTS: + void messageClicked(); + void closeNotification(); + +private: + QSystemTrayIcon *m_systemTrayIcon; + QWebEngineNotification m_activeNotification; +}; + +void defaultNotificationPresenter(const QWebEngineNotification ¬ification); + +QT_END_NAMESPACE + +#endif // QWEBENGINENOTIFICATIONPRESENTER_P_H diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 22ef8fffe..790d802f0 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -54,6 +54,7 @@ #include "qwebenginefullscreenrequest.h" #include "qwebenginehistory.h" #include "qwebenginehistory_p.h" +#include "qwebenginenotification.h" #include "qwebengineprofile.h" #include "qwebengineprofile_p.h" #include "qwebenginequotarequest.h" @@ -62,6 +63,7 @@ #include "qwebenginesettings.h" #include "qwebengineview.h" #include "qwebengineview_p.h" +#include "user_notification_controller.h" #include "render_widget_host_view_qt_delegate_widget.h" #include "web_contents_adapter.h" #include "web_engine_settings.h" @@ -538,6 +540,12 @@ void QWebEnginePagePrivate::runRegisterProtocolHandlerRequest(QWebEngineRegister Q_EMIT q->registerProtocolHandlerRequested(request); } +void QWebEnginePagePrivate::runUserNotificationPermissionRequest(const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::Notifications); +} + QObject *QWebEnginePagePrivate::accessibilityParentObject() { return view; @@ -1874,6 +1882,7 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine d->adapter->grantMouseLockPermission(true); break; case Notifications: + d->adapter->runUserNotificationRequestCallback(securityOrigin, true); break; } } else { // if (policy == PermissionDeniedByUser) @@ -1892,6 +1901,7 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine d->adapter->grantMouseLockPermission(false); break; case Notifications: + d->adapter->runUserNotificationRequestCallback(securityOrigin, false); break; } } diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 55450e438..4956877a9 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -185,9 +185,7 @@ public: Q_ENUM(NavigationType) enum Feature { -#ifndef Q_QDOC Notifications = 0, -#endif Geolocation = 1, MediaAudioCapture = 2, MediaVideoCapture, diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index bf2f43f80..d597383e2 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -132,6 +132,7 @@ public: void authenticationRequired(QSharedPointer) override; void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) override; void runGeolocationPermissionRequest(const QUrl &securityOrigin) override; + void runUserNotificationPermissionRequest(const QUrl &securityOrigin) override; void runMouseLockPermissionRequest(const QUrl &securityOrigin) override; void runQuotaRequest(QWebEngineQuotaRequest) override; void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index e9703ffe8..74dc14da0 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -43,6 +43,7 @@ #include "qwebenginecookiestore.h" #include "qwebenginedownloaditem.h" #include "qwebenginedownloaditem_p.h" +#include "qwebenginenotificationpresenter_p.h" #include "qwebenginepage.h" #include "qwebenginepage_p.h" #include "qwebenginesettings.h" @@ -140,6 +141,12 @@ using QtWebEngineCore::ProfileAdapter; Both session and persistent cookies are saved to and restored from disk. */ +void QWebEngineProfilePrivate::showNotification(QSharedPointer ¬ification) +{ + if (m_notificationPresenter) + m_notificationPresenter(QWebEngineNotification(notification)); +} + /*! \fn QWebEngineProfile::downloadRequested(QWebEngineDownloadItem *download) @@ -633,6 +640,27 @@ QWebEngineScriptCollection *QWebEngineProfile::scripts() const return d->m_scriptCollection.data(); } +/*! + Sets the function \a notificationPresenter as responsible for presenting sent notifications. + + \since 5.13 + \sa QWebEngineNotification +*/ +void QWebEngineProfile::setNotificationPresenter(const std::function ¬ificationPresenter) +{ + Q_D(QWebEngineProfile); + d->m_notificationPresenter = notificationPresenter; +} + +/*! + \overload +*/ +void QWebEngineProfile::setNotificationPresenter(std::function &¬ificationPresenter) +{ + Q_D(QWebEngineProfile); + d->m_notificationPresenter = std::move(notificationPresenter); +} + /*! Returns the default profile. @@ -645,6 +673,8 @@ QWebEngineProfile *QWebEngineProfile::defaultProfile() static QWebEngineProfile* profile = new QWebEngineProfile( new QWebEngineProfilePrivate(ProfileAdapter::createDefaultProfileAdapter()), ProfileAdapter::globalQObjectRoot()); + if (!profile->d_ptr->m_notificationPresenter) + profile->setNotificationPresenter(&defaultNotificationPresenter); return profile; } diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h index 79e83c377..5ad999c00 100644 --- a/src/webenginewidgets/api/qwebengineprofile.h +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -46,12 +46,15 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QObject; class QUrl; class QWebEngineCookieStore; class QWebEngineDownloadItem; +class QWebEngineNotification; class QWebEnginePage; class QWebEnginePagePrivate; class QWebEngineProfilePrivate; @@ -137,6 +140,9 @@ public: QString downloadPath() const; void setDownloadPath(const QString &path); + void setNotificationPresenter(const std::function ¬ificationPresenter); + void setNotificationPresenter(std::function &¬ificationPresenter); + static QWebEngineProfile *defaultProfile(); Q_SIGNALS: diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h index 9ff8df849..3dd024ffd 100644 --- a/src/webenginewidgets/api/qwebengineprofile_p.h +++ b/src/webenginewidgets/api/qwebengineprofile_p.h @@ -60,6 +60,8 @@ #include #include +#include + namespace QtWebEngineCore { class ProfileAdapter; } @@ -68,6 +70,7 @@ QT_BEGIN_NAMESPACE class QWebEngineBrowserContext; class QWebEngineProfilePrivate; +class QWebEngineNotification; class QWebEngineSettings; class QWebEngineProfilePrivate : public QtWebEngineCore::ProfileAdapterClient { @@ -84,12 +87,15 @@ public: void downloadRequested(DownloadItemInfo &info) override; void downloadUpdated(const DownloadItemInfo &info) override; + void showNotification(QSharedPointer &) override; + private: QWebEngineProfile *q_ptr; QWebEngineSettings *m_settings; QPointer m_profileAdapter; QScopedPointer m_scriptCollection; QMap > m_ongoingDownloads; + std::function m_notificationPresenter; }; QT_END_NAMESPACE diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index d012c678c..427668a11 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -285,6 +285,8 @@ This enum describes the platform feature access categories that the user may be asked to grant or deny access to: + \value Notifications + Web notifications for the end-user. \value Geolocation Location hardware or service. \value MediaAudioCapture diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 4669c2bce..d4fb40dc7 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -19,6 +19,7 @@ SOURCES = \ api/qwebenginedownloaditem.cpp \ api/qwebenginefullscreenrequest.cpp \ api/qwebenginehistory.cpp \ + api/qwebenginenotificationpresenter.cpp \ api/qwebenginepage.cpp \ api/qwebengineprofile.cpp \ api/qwebenginescript.cpp \ @@ -36,6 +37,7 @@ HEADERS = \ api/qwebenginedownloaditem_p.h \ api/qwebenginefullscreenrequest.h \ api/qwebenginehistory.h \ + api/qwebenginenotificationpresenter_p.h \ api/qwebenginepage.h \ api/qwebenginepage_p.h \ api/qwebengineprofile.h \ -- cgit v1.2.3