summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/webenginequick/quicknanobrowser/BrowserWindow.qml49
-rw-r--r--examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc30
-rw-r--r--examples/webenginewidgets/CMakeLists.txt1
-rw-r--r--examples/webenginewidgets/maps/doc/src/maps.qdoc11
-rw-r--r--examples/webenginewidgets/maps/mainwindow.cpp21
-rw-r--r--examples/webenginewidgets/notifications/doc/src/notifications.qdoc4
-rw-r--r--examples/webenginewidgets/notifications/main.cpp9
-rw-r--r--examples/webenginewidgets/permissionbrowser/CMakeLists.txt84
-rw-r--r--examples/webenginewidgets/permissionbrowser/Info.cmake.macos.plist36
-rw-r--r--examples/webenginewidgets/permissionbrowser/doc/images/permissionbrowser-example.pngbin0 -> 50311 bytes
-rw-r--r--examples/webenginewidgets/permissionbrowser/doc/src/permissionbrowser.qdoc221
-rw-r--r--examples/webenginewidgets/permissionbrowser/main.cpp18
-rw-r--r--examples/webenginewidgets/permissionbrowser/mainwindow.cpp270
-rw-r--r--examples/webenginewidgets/permissionbrowser/mainwindow.h74
-rw-r--r--examples/webenginewidgets/permissionbrowser/mainwindow.ui356
-rw-r--r--examples/webenginewidgets/permissionbrowser/permissionbrowser.exe.manifest17
-rw-r--r--examples/webenginewidgets/permissionbrowser/permissionbrowser.qrc7
-rw-r--r--examples/webenginewidgets/permissionbrowser/permissiondialog.ui117
-rw-r--r--examples/webenginewidgets/permissionbrowser/permissionwidget.ui119
-rw-r--r--examples/webenginewidgets/permissionbrowser/resources/3rdparty/COPYING1
-rw-r--r--examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-next.pngbin0 -> 1219 bytes
-rw-r--r--examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-previous.pngbin0 -> 1200 bytes
-rw-r--r--examples/webenginewidgets/permissionbrowser/resources/3rdparty/qt_attribution.json24
-rw-r--r--examples/webenginewidgets/permissionbrowser/resources/3rdparty/view-refresh.pngbin0 -> 1364 bytes
-rw-r--r--examples/webenginewidgets/permissionbrowser/resources/AppLogoColor.pngbin0 -> 6113 bytes
-rw-r--r--examples/webenginewidgets/permissionbrowser/resources/landing.html88
-rw-r--r--examples/webenginewidgets/push-notifications/main.cpp9
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc27
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.cpp5
-rw-r--r--examples/webenginewidgets/simplebrowser/webpage.cpp7
-rw-r--r--examples/webenginewidgets/simplebrowser/webview.cpp39
-rw-r--r--examples/webenginewidgets/simplebrowser/webview.h4
32 files changed, 1554 insertions, 94 deletions
diff --git a/examples/webenginequick/quicknanobrowser/BrowserWindow.qml b/examples/webenginequick/quicknanobrowser/BrowserWindow.qml
index 3b911262b..2c5b3d86e 100644
--- a/examples/webenginequick/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webenginequick/quicknanobrowser/BrowserWindow.qml
@@ -563,6 +563,11 @@ ApplicationWindow {
settings.imageAnimationPolicy: appSettings.imageAnimationPolicy
onCertificateError: function(error) {
+ if (!error.isMainFrame) {
+ error.rejectCertificate();
+ return;
+ }
+
error.defer();
sslDialog.enqueue(error);
}
@@ -643,10 +648,9 @@ ApplicationWindow {
findBar.reset();
}
- onFeaturePermissionRequested: function(securityOrigin, feature) {
- featurePermissionDialog.securityOrigin = securityOrigin;
- featurePermissionDialog.feature = feature;
- featurePermissionDialog.visible = true;
+ onPermissionRequested: function(permission) {
+ permissionDialog.permission = permission;
+ permissionDialog.visible = true;
}
onWebAuthUxRequested: function(request) {
webAuthDialog.init(request);
@@ -731,7 +735,7 @@ ApplicationWindow {
}
}
Dialog {
- id: featurePermissionDialog
+ id: permissionDialog
anchors.centerIn: parent
width: Math.min(browserWindow.width, browserWindow.height) / 3 * 2
contentWidth: mainTextForPermissionDialog.width
@@ -739,59 +743,58 @@ ApplicationWindow {
standardButtons: Dialog.No | Dialog.Yes
title: "Permission Request"
- property var feature;
- property url securityOrigin;
+ property var permission;
contentItem: Item {
Label {
id: mainTextForPermissionDialog
- text: featurePermissionDialog.questionForFeature()
+ text: permissionDialog.questionForFeature()
}
}
- onAccepted: currentWebView && currentWebView.grantFeaturePermission(securityOrigin, feature, true)
- onRejected: currentWebView && currentWebView.grantFeaturePermission(securityOrigin, feature, false)
+ onAccepted: permission.grant()
+ onRejected: permission.deny()
onVisibleChanged: {
if (visible)
width = contentWidth + 20;
}
function questionForFeature() {
- var question = "Allow " + securityOrigin + " to "
+ var question = "Allow " + permission.origin + " to "
- switch (feature) {
- case WebEngineView.Geolocation:
+ switch (permission.feature) {
+ case WebEnginePermission.Geolocation:
question += "access your location information?";
break;
- case WebEngineView.MediaAudioCapture:
+ case WebEnginePermission.MediaAudioCapture:
question += "access your microphone?";
break;
- case WebEngineView.MediaVideoCapture:
+ case WebEnginePermission.MediaVideoCapture:
question += "access your webcam?";
break;
- case WebEngineView.MediaVideoCapture:
+ case WebEnginePermission.MediaAudioVideoCapture:
question += "access your microphone and webcam?";
break;
- case WebEngineView.MouseLock:
+ case WebEnginePermission.MouseLock:
question += "lock your mouse cursor?";
break;
- case WebEngineView.DesktopVideoCapture:
+ case WebEnginePermission.DesktopVideoCapture:
question += "capture video of your desktop?";
break;
- case WebEngineView.DesktopAudioVideoCapture:
+ case WebEnginePermission.DesktopAudioVideoCapture:
question += "capture audio and video of your desktop?";
break;
- case WebEngineView.Notifications:
+ case WebEnginePermission.Notifications:
question += "show notification on your desktop?";
break;
- case WebEngineView.ClipboardReadWrite:
+ case WebEnginePermission.ClipboardReadWrite:
question += "read from and write to your clipboard?";
break;
- case WebEngineView.LocalFontsAccess:
+ case WebEnginePermission.LocalFontsAccess:
question += "access the fonts stored on your machine?";
break;
default:
- question += "access unknown or unsupported feature [" + feature + "] ?";
+ question += "access unknown or unsupported feature [" + permission.feature + "] ?";
break;
}
diff --git a/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc b/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc
index 1dc209c2e..cff4d3354 100644
--- a/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc
+++ b/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc
@@ -75,13 +75,16 @@
\section1 Handling Certificate Errors
- If the certificate of the site being loaded triggers a certificate error, we call the
- \l{WebEngineCertificateError::}{defer()} QML method to pause the URL request and wait for user
- input:
+ In case of a certificate error, we check whether it came from the main frame, or from a
+ resource inside the page. Resource errors automatically trigger a certificate rejection,
+ since a user won't have enough context to make a decision.
+ For all other cases, we call the \l{WebEngineCertificateError::}{defer()} QML method to pause
+ the URL request and wait for user input:
\quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml
\skipto onCertificateError
\printuntil }
+ \printuntil }
We use the Dialog type to prompt users to continue or cancel the loading of the web page.
If users select \uicontrol Yes, we call the
@@ -93,25 +96,22 @@
\skipto Dialog {
\printuntil /^\ {4}\}/
- \section1 Handling Feature Permission Requests
+ \section1 Handling Permission Requests
- We use the \c onFeaturePermissionRequested() signal handler to handle requests for
- accessing a certain feature or device. The \c securityOrigin parameter identifies the
- requester web site, and the \c feature parameter is the requested feature. We use these
- to construct the message of the dialog:
+ We use the \c onPermissionRequested() signal handler to handle requests for
+ accessing a certain feature or device. The \c permission parameter is an object of the
+ WebEnginePermission type, which can be used to handle the incoming request. We temporarily store
+ this object, since we need to use it to construct the message of the dialog:
\quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml
- \skipto onFeaturePermissionRequested
+ \skipto onPermissionRequested
\printuntil }
- We show a dialog where the user is asked to grant or deny access. The custom
+ We display a dialog where the user is asked to grant or deny access. The custom
\c questionForFeature() JavaScript function generates a human-readable question about
the request.
- If users select \uicontrol Yes, we call the \l{WebEngineView::}{grantFeaturePermission()}
- method with a third \c true parameter to grant the \c securityOrigin web site the permission
- to access the \c feature.
- If users select \uicontrol No, we call the same method but with the \c false parameter to
- deny access:
+ If user selects \uicontrol Yes, we call the \l{webEnginePermission::grant}{grant()}
+ method, and if they select \uicontrol No we call \l{webEnginePermission::deny}{deny()}.
\skipto id: sslDialog
\skipto Dialog {
diff --git a/examples/webenginewidgets/CMakeLists.txt b/examples/webenginewidgets/CMakeLists.txt
index 3ce666d72..ebe34d668 100644
--- a/examples/webenginewidgets/CMakeLists.txt
+++ b/examples/webenginewidgets/CMakeLists.txt
@@ -3,6 +3,7 @@
qt_internal_add_example(contentmanipulation)
qt_internal_add_example(cookiebrowser)
+qt_internal_add_example(permissionbrowser)
qt_internal_add_example(notifications)
qt_internal_add_example(simplebrowser)
qt_internal_add_example(push-notifications)
diff --git a/examples/webenginewidgets/maps/doc/src/maps.qdoc b/examples/webenginewidgets/maps/doc/src/maps.qdoc
index 0175f8b65..f9bd19bfc 100644
--- a/examples/webenginewidgets/maps/doc/src/maps.qdoc
+++ b/examples/webenginewidgets/maps/doc/src/maps.qdoc
@@ -48,10 +48,10 @@
\printuntil setCentralWidget
We then proceed to connect a lambda function to the \l
- QWebEnginePage::featurePermissionRequested signal:
+ QWebEnginePage::permissionRequested signal:
\skipto m_view->page()
- \printuntil QWebEnginePage::Feature
+ \printuntil QWebEnginePermission permission
This signal is emitted whenever a web page requests to make use of a certain
feature or device, including not only location services but also audio
@@ -62,15 +62,14 @@
Now comes the part where we actually ask the user for permission:
- \printuntil securityOrigin
\printuntil });
Note that the question includes the host component of the web site's URI (\c
- securityOrigin) to inform the user as to exactly which web site will be
+ permission.origin()) to inform the user as to exactly which web site will be
receiving their location data.
- We use the \l QWebEnginePage::setFeaturePermission method to communicate the
- user's answer back to the web page.
+ We use the \l QWebEnginePermission::grant() and \l QWebEnginePermission::deny()
+ methods to communicate the user's answer back to the web page.
Finally we ask the \l QWebEnginePage to load the web page that might want to
use location services:
diff --git a/examples/webenginewidgets/maps/mainwindow.cpp b/examples/webenginewidgets/maps/mainwindow.cpp
index 0d2b49911..ca98ca263 100644
--- a/examples/webenginewidgets/maps/mainwindow.cpp
+++ b/examples/webenginewidgets/maps/mainwindow.cpp
@@ -13,25 +13,22 @@ MainWindow::MainWindow(QWidget *parent)
QWebEnginePage *page = m_view->page();
- connect(page, &QWebEnginePage::featurePermissionRequested,
- [this, page](const QUrl &securityOrigin, QWebEnginePage::Feature feature) {
- if (feature != QWebEnginePage::Geolocation)
+ connect(page, &QWebEnginePage::permissionRequested,
+ [this, page](QWebEnginePermission permission) {
+ if (permission.feature() != QWebEnginePermission::Geolocation)
return;
QMessageBox msgBox(this);
- msgBox.setText(tr("%1 wants to know your location").arg(securityOrigin.host()));
+ msgBox.setText(tr("%1 wants to know your location").arg(permission.origin().host()));
msgBox.setInformativeText(tr("Do you want to send your current location to this website?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
- if (msgBox.exec() == QMessageBox::Yes) {
- page->setFeaturePermission(
- securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
- } else {
- page->setFeaturePermission(
- securityOrigin, feature, QWebEnginePage::PermissionDeniedByUser);
- }
+ if (msgBox.exec() == QMessageBox::Yes)
+ permission.grant();
+ else
+ permission.deny();
});
- page->load(QUrl(QStringLiteral("https://maps.google.com")));
+ page->load(QUrl(QStringLiteral("https://bing.com/maps")));
}
diff --git a/examples/webenginewidgets/notifications/doc/src/notifications.qdoc b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc
index f4fe1818f..bd0def910 100644
--- a/examples/webenginewidgets/notifications/doc/src/notifications.qdoc
+++ b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc
@@ -45,11 +45,11 @@
\section2 Requesting Feature Permissions
- We then use the \l QWebEnginePage::featurePermissionRequested() call to
+ We then use the \l QWebEnginePage::permissionRequested() call to
request the user's permission to show notifications on their device.
\quotefromfile webenginewidgets/notifications/main.cpp
- \skipto featurePermissionRequested
+ \skipto permissionRequested
\printuntil });
\section2 Handling New Notifications
diff --git a/examples/webenginewidgets/notifications/main.cpp b/examples/webenginewidgets/notifications/main.cpp
index c754aff3f..df9ebff73 100644
--- a/examples/webenginewidgets/notifications/main.cpp
+++ b/examples/webenginewidgets/notifications/main.cpp
@@ -33,11 +33,11 @@ int main(int argc, char *argv[])
// set custom page to open all page's links for https scheme in system browser
view.setPage(new WebEnginePage(&view));
- QObject::connect(view.page(), &QWebEnginePage::featurePermissionRequested,
- [&] (const QUrl &origin, QWebEnginePage::Feature feature) {
- if (feature != QWebEnginePage::Notifications)
+ QObject::connect(view.page(), &QWebEnginePage::permissionRequested,
+ [&] (QWebEnginePermission permission) {
+ if (permission.feature() != QWebEnginePermission::Notifications)
return;
- view.page()->setFeaturePermission(origin, feature, QWebEnginePage::PermissionGrantedByUser);
+ permission.grant();
});
auto profile = view.page()->profile();
@@ -50,4 +50,3 @@ int main(int argc, char *argv[])
view.setUrl(QStringLiteral("qrc:/index.html"));
return app.exec();
}
-
diff --git a/examples/webenginewidgets/permissionbrowser/CMakeLists.txt b/examples/webenginewidgets/permissionbrowser/CMakeLists.txt
new file mode 100644
index 000000000..0a92691ba
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/CMakeLists.txt
@@ -0,0 +1,84 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.5)
+project(permissionbrowser LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/webenginewidgets/permissionbrowser")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui WebEngineWidgets)
+
+qt_add_executable(permissionbrowser
+ permissiondialog.ui
+ permissionwidget.ui
+ main.cpp
+ mainwindow.cpp mainwindow.h mainwindow.ui
+)
+
+if(WIN32)
+ set_property(
+ TARGET permissionbrowser
+ APPEND PROPERTY
+ SOURCES permissionbrowser.exe.manifest)
+endif()
+
+set_target_properties(permissionbrowser PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+ MACOSX_BUNDLE_GUI_IDENTIFIER "io.qt.examples.webenginewidgets.permissionbrowser"
+)
+
+target_link_libraries(permissionbrowser PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::WebEngineWidgets
+)
+
+# Resources:
+set(permissionbrowser_resource_files
+ "resources/3rdparty/view-refresh.png"
+ "resources/3rdparty/go-next.png"
+ "resources/3rdparty/go-previous.png"
+ "resources/AppLogoColor.png"
+ "resources/landing.html"
+)
+
+qt_add_resources(permissionbrowser "permissionbrowser"
+ PREFIX
+ "/"
+ BASE
+ "resources"
+ FILES
+ ${permissionbrowser_resource_files}
+)
+
+if (APPLE)
+ set_target_properties(permissionbrowser PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.cmake.macos.plist"
+ )
+
+ if (NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ # Need to sign application for location permissions to work
+ if(QT_FEATURE_debug_and_release)
+ set(exe_path "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/")
+ else()
+ unset(exe_path)
+ endif()
+ add_custom_command(TARGET permissionbrowser
+ POST_BUILD COMMAND codesign --force -s - ${exe_path}permissionbrowser.app
+ )
+ endif()
+endif()
+
+install(TARGETS permissionbrowser
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/webenginewidgets/permissionbrowser/Info.cmake.macos.plist b/examples/webenginewidgets/permissionbrowser/Info.cmake.macos.plist
new file mode 100644
index 000000000..48ddaadc6
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/Info.cmake.macos.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+ <key>NSLocationUsageDescription</key>
+ <string>Permission Browser would like to give web sites access to your location for demo purposes.</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Permission Browser would like to give web sites access to your computer's microphone for demo purposes.</string>
+ <key>NSCameraUsageDescription</key>
+ <string>Permission Browser would like to give web sites access to your computer's camera for demo purposes.</string>
+</dict>
+</plist>
diff --git a/examples/webenginewidgets/permissionbrowser/doc/images/permissionbrowser-example.png b/examples/webenginewidgets/permissionbrowser/doc/images/permissionbrowser-example.png
new file mode 100644
index 000000000..56ea60025
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/doc/images/permissionbrowser-example.png
Binary files differ
diff --git a/examples/webenginewidgets/permissionbrowser/doc/src/permissionbrowser.qdoc b/examples/webenginewidgets/permissionbrowser/doc/src/permissionbrowser.qdoc
new file mode 100644
index 000000000..a266ec62a
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/doc/src/permissionbrowser.qdoc
@@ -0,0 +1,221 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example webenginewidgets/permissionbrowser
+ \examplecategory {Web Technologies}
+ \title WebEngine Widgets Permission Browser Example
+ \ingroup webengine-widgetexamples
+ \brief Demonstrates how to handle website permission requests, and manage
+ existing permissions.
+
+ \image permissionbrowser-example.png
+
+ Permission Browser demonstrates how to use the \l{QWebEnginePermission} class
+ to manage website permissions. The example includes code for handling incoming
+ permission requests, as well as modifying already existing permissions. Also
+ demonstrated are the effects of the different permission persistence policies
+ defined within the \l{QWebEngineProfile} class.
+
+ \include examples-run.qdocinc
+
+ \section1 Class Definitions
+
+ \section2 MainWindow
+
+ The \c MainWindow class inherits \l QMainWindow. Inside, we declare a convenience
+ pointer to the \l QVBoxLayout which will lay out the widgets used to manipulate
+ individual permissions, as well as another convenience pointer to the widget
+ displaying the currently pending permission request. We also declare a
+ \l QWebEngineView, which will be used to display the actual webpage contents.
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.h
+ \skipto class MainWindow :
+ \printuntil /^\}/
+
+ The rest of the layout for the application is defined inside mainwindow.ui,
+ and was created using Qt Creator's Design mode. \c MainWindow is a child class
+ of Ui_MainWindow, which is a C++ class generated at compile time from the
+ definitions found inside mainwindow.ui.
+
+ \section2 PermissionWidget and PermissionDialog
+
+ The \c PermissionWidget class defines a widget corresponding to a single
+ \l QWebEnginePermission instance. For convenience, the \l QWebEnginePermission
+ object is stored within. The widget itself has controls for granting, denying,
+ or deleting the permission; all of this is defined inside \c PermissionWidget.ui.
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.h
+ \skipto class PermissionWidget :
+ \printuntil /^\}/
+
+ When clicking the "New" button in the main window's UI, a pop-up window will
+ appear, allowing the user to pre-grant permission to a known origin. That
+ pop-up is defined by the \c PermissionDialog class:
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.h
+ \skipto class PermissionDialog :
+ \printuntil /^\}/
+
+ \section1 Handling incoming permission requests
+
+ Whenever a website uses an API that might compromise the user's privacy, the
+ browser is expected to show them a prompt asking to either grant or deny permission.
+ The PermissionBrowser example has a dedicated section at the bottom right, which
+ gets populated with a \c PermissionWidget whenever that happens.
+
+ The \c PermissionWidget displays the permission's origin, the requested
+ \l QWebEnginePermission::Feature, as well as the current status of that permission.
+ It also has buttons for granting and denying the permission. Since the permission status
+ is (by default) remembered, the delete button allows the user to remove the permission
+ from the underlying storage.
+
+ To achieve all this, we first connect QWebEnginePage's \c permissionRequested signal
+ to \c MainWindow's \c handlePermissionRequested slot:
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto connect(m_webview->page(),
+ \printline connect(m_webview->page(),
+
+ The signal handler is relatively simple: it attempts to create a \c PermissionWidget
+ instance for the provided QWebEnginePermission object, and if it succeeds it
+ plugs that widget into the QFrame designated for pending permissions. We also
+ subscribe to \c PermissionWidget's \c permissionModified signal so that we can later move
+ the \c PermissionWidget from the bottom right to the list of existing widgets above.
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto void MainWindow::handlePermissionRequested
+ \printuntil /^\}/
+
+ We only create a new \c PermissionWidget if we don't already have an existing one:
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto PermissionWidget *MainWindow::create PermissionWidget
+ \printuntil /^\}/
+
+ \target PermissionWidgetConstructor
+ \section1 Modifying a permission and displaying it to the user
+
+ The QWebEnginePermission interface provides the \l {QWebEnginePermission::grant}{grant}()
+ and {QWebEnginePermission::deny}{deny}() functions, which are all that's needed to
+ change the status of a permission. If the application needs to forget about a permission,
+ we use the {QWebEnginePermission::reset}{reset}() function.
+
+ Inside the \c PermissionWidget constructor, we hook those function up to the buttons'
+ \c clicked signal, so that we can execute the relevant functionality on the
+ QWebEnginePermission object.
+
+ Whenever a button is pressed, we emit the \c permissionModified signal, which
+ \c MainWindow uses to know when it needs to move the widget from the bottom-right
+ to the list of existing permissions. We also make sure to call \c updateState(), which
+ handles visual updates to the widget. When the delete button is pressed, we also make
+ sure mark the widget for deletion, since we only want to display existing permissions to
+ the user.
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto PermissionWidget::PermissionWidget
+ \printuntil /^\}/
+
+ The \c updateState() function displays the data supplied by QWebEnginePermission
+ to the user. It also makes sure that, when a permission is in the
+ \l QWebEnginePermission::Invalid state, the buttons for granting or denying it
+ are disabled.
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto void PermissionWidget::updateState()
+ \printuntil /^\}/
+
+ When a pending permission is granted or denied, we want to move the associated
+ widget to the list above, which contains all currently existing permissions.
+ We do this in the MainWindow::handlePermissionModified slot.
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto void MainWindow::handlePermissionModified
+ \printuntil /^\}/
+
+ Notably, we only do this in cases where we know the permission is remembered.
+ This is not true for transient \c Features,
+ which require a permission prompt be shown to the user every time they're needed.
+ We also exclude permissions with a \l QWebEnginePermission::Ask state, which
+ indicates that the permission was \l {QWebEnginePermission::reset}{reset}(),
+ and we don't add anything to the list of existing permissions when
+ \l QWebEngineProfile::persistentPermissionsPolicy is set to
+ \c NoPersistentPermissions.
+
+ \note Check the \l QWebEnginePermission::Feature documentation to see which
+ \c Features are transient.
+
+ \section1 Displaying and modifying existing permissions
+
+ By default, permissions are stored to disk and retrieved again on application
+ startup. To get a list of all existing website permissions, we call
+ \l QWebEngineProfile::listPermissions():
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto void MainWindow::loadStoredPermissions()
+ \printuntil /^\}/
+
+ For every permission in the list, we simply construct a new \c PermissionWidget, and
+ add it to the list on the right-hand side of the screen. Existing permissions
+ are modified \l {PermissionWidgetConstructor}{using the exact same API as pending ones}.
+
+ \section1 Pre-granting permissions
+
+ Certain permissions may be granted in advance, provided the origin and Feature type
+ are known. Clicking on the "New" button in the top right will create a pop-up
+ dialog that allows you to do just that. The dialog is implemented by the
+ \c PermissionDialog class:
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto PermissionDialog::PermissionDialog
+ \printuntil /^\}/
+
+ We populate the \l QComboBox using the QMetaEnum type associated with
+ \l QWebEnginePermission::Feature. We make sure to filter out transient
+ features, since pre-granting these is not supported.
+
+ We display the dialog and add show the resulting \c PermissionWidget
+ in the UI inside the \c MainWindow::handleNewClicked slot. The new
+ permission is handled the same way we would if a website requested it:
+ by calling \c handlePermissionRequested().
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto void MainWindow::handleNewClicked()
+ \printuntil /^\}/
+
+ \section1 Changing the permission persistence policy
+
+ By default, permissions are stored to disk for every named QWebEngineProfile,
+ and in memory for every unnamed/off-the-record one. Normally, this setting
+ won't be changed at runtime, but this example explores the effects
+ of each option.
+
+ \list
+ \li \l QWebEngineProfile::PersistentPermissionsOnDisk is the default, and it ensures
+ that any permissions that have been granted in the current application run will be
+ loaded back up at next startup. A permission onlycneeds to be granted once, and
+ subsequent uses of the API that triggered the request will automatically be granted,
+ until the application calls QWebEnginePermission::reset().
+ li \l QWebEngineProfile::PersistentPermissionsInMemory Has the same behavior as above,
+ except that permissions will be destroyed at application exit, and not committed
+ to disk.
+ li \l QWebEngineProfile::NoPersistentPermissions makes sure permissions are never
+ remembered, and all act as if they're transient. Thus, every time a web API needs
+ a permission, a new prompt will be shown to the user. This option is intended for
+ backwards compatibility and applications which implement their own permission storage.
+ \endlist
+
+ To ensure the user will be shown previously existing permissions, we need to call
+ \l QWebEngineProfile::listPermissions():
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto void MainWindow::loadStoredPermissions()
+ \printuntil /^\}/
+
+ This is done one time at startup, as well as whenever the user changes the policy
+ from the \l QComboBox from the top right.
+
+ \quotefromfile webenginewidgets/permissionbrowser/mainwindow.cpp
+ \skipto void MainWindow::handlePolicyComboBoxIndexChanged
+ \printuntil /^\}/
+*/
diff --git a/examples/webenginewidgets/permissionbrowser/main.cpp b/examples/webenginewidgets/permissionbrowser/main.cpp
new file mode 100644
index 000000000..c1e2c2566
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/main.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+#include <QApplication>
+#include <QLoggingCategory>
+#include <QUrl>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setOrganizationName("QtExamples");
+ QApplication app(argc, argv);
+ app.setWindowIcon(QIcon(QString(u":AppLogoColor.png")));
+ MainWindow window(QUrl("qrc:/landing.html"));
+ window.resize(1024, 768);
+ window.show();
+ return app.exec();
+}
diff --git a/examples/webenginewidgets/permissionbrowser/mainwindow.cpp b/examples/webenginewidgets/permissionbrowser/mainwindow.cpp
new file mode 100644
index 000000000..2fe3c3b17
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/mainwindow.cpp
@@ -0,0 +1,270 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+#include <QWebEngineProfile>
+#include <QWebEnginePermission>
+#include <QWebEngineSettings>
+#include <QMetaEnum>
+#include <QUrl>
+
+PermissionDialog::PermissionDialog(const QWebEngineProfile *profile, QWidget *parent)
+ : QDialog(parent)
+ , m_profile(profile)
+ , m_permission(nullptr)
+{
+ setupUi(this);
+
+ auto metaEnum = QMetaEnum::fromType<QWebEnginePermission::Feature>();
+ Q_ASSERT(metaEnum.value(QWebEnginePermission::Unsupported) == 0);
+ for (int i = 1; i < metaEnum.keyCount(); ++i) {
+ QWebEnginePermission::Feature feature = QWebEnginePermission::Feature(metaEnum.value(i));
+ if (!QWebEnginePermission::isTransient(feature))
+ m_featureComboBox->addItem(metaEnum.valueToKey(feature), QVariant(feature));
+ }
+}
+
+PermissionDialog::~PermissionDialog()
+{
+ delete m_permission;
+}
+
+QWebEnginePermission PermissionDialog::permission()
+{
+ return m_profile->getPermission(QUrl(m_originLineEdit->text()),
+ QWebEnginePermission::Feature(m_featureComboBox->itemData(m_featureComboBox->currentIndex()).toInt()));
+}
+
+PermissionWidget::PermissionWidget(const QWebEnginePermission &permission, QWidget *parent)
+ : QWidget(parent)
+ , m_permission(permission)
+{
+ setupUi(this);
+ connect(m_deleteButton, &QPushButton::clicked, [this]() {
+ m_permission.reset();
+ emit permissionModified(this);
+ deleteLater();
+ });
+
+ connect(m_grantButton, &QPushButton::clicked, [this]() {
+ m_permission.grant();
+ updateState();
+ emit permissionModified(this);
+ });
+
+ connect(m_denyButton, &QPushButton::clicked, [this]() {
+ m_permission.deny();
+ updateState();
+ emit permissionModified(this);
+ });
+
+ updateState();
+}
+
+void PermissionWidget::updateState()
+{
+ switch (m_permission.state()) {
+ case QWebEnginePermission::Invalid:
+ m_stateLabel->setText("<font color='gray'>Invalid</font>");
+ m_grantButton->setEnabled(false);
+ m_denyButton->setEnabled(false);
+ break;
+ case QWebEnginePermission::Ask:
+ m_stateLabel->setText("<font color='yellow'>Waiting for response</font>");
+ break;
+ case QWebEnginePermission::Granted:
+ m_stateLabel->setText("<font color='green'>Granted</font>");
+ break;
+ case QWebEnginePermission::Denied:
+ m_stateLabel->setText("<font color='red'>Denied</font>");
+ break;
+ }
+
+ m_typeLabel->setText(QMetaEnum::fromType<QWebEnginePermission::Feature>().valueToKey(m_permission.feature()));
+ m_originLabel->setText(m_permission.origin().toDisplayString());
+}
+
+MainWindow::MainWindow(const QUrl &url)
+ : QMainWindow()
+ , m_layout(new QVBoxLayout)
+ , m_profile(new QWebEngineProfile("permissionbrowser"))
+ , m_webview(new QWebEngineView(m_profile, this))
+ , m_pendingWidget(nullptr)
+{
+ setupUi(this);
+ m_urlLineEdit->setText(url.toString());
+
+ m_layout->addItem(new QSpacerItem(0,0, QSizePolicy::Minimum, QSizePolicy::Expanding));
+ m_layout->setContentsMargins(0, 0, 0, 0);
+ m_layout->setSpacing(0);
+
+ QWidget *w = new QWidget();
+ w->setLayout(m_layout);
+
+ m_storedScrollArea->setWidget(w);
+ m_storedScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ (new QVBoxLayout(m_pendingFrame))->setContentsMargins(0, 0, 0, 0);
+
+ loadStoredPermissions();
+
+ connect(m_deleteAllButton, &QPushButton::clicked, this, &MainWindow::handleDeleteAllClicked);
+ connect(m_newButton, &QPushButton::clicked, this, &MainWindow::handleNewClicked);
+ connect(m_refreshButton, &QPushButton::clicked, this, &MainWindow::handleRefreshClicked);
+ connect(m_backButton, &QPushButton::clicked, this, &MainWindow::handleBackClicked);
+ connect(m_forwardButton, &QPushButton::clicked, this, &MainWindow::handleForwardClicked);
+ connect(m_policyComboBox, &QComboBox::currentIndexChanged, this, &MainWindow::handlePolicyComboBoxIndexChanged);
+ connect(m_webview, &QWebEngineView::urlChanged, this, &MainWindow::handleUrlChanged);
+ connect(m_webview->page(), &QWebEnginePage::permissionRequested, this, &MainWindow::handlePermissionRequested);
+
+ m_profile->settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
+ m_profile->settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, true);
+
+ m_frame->layout()->addWidget(m_webview);
+ static_cast<QVBoxLayout *>(m_frame->layout())->setStretchFactor(m_webview, 1);
+ m_webview->load(url);
+}
+
+MainWindow::~MainWindow()
+{
+ delete m_webview;
+ delete m_profile;
+}
+
+void MainWindow::handlePermissionRequested(QWebEnginePermission permission)
+{
+ PermissionWidget *widget = createPermissionWidget(permission);
+ if (widget) {
+ m_pendingFrame->layout()->addWidget(widget);
+ connect(widget, &PermissionWidget::permissionModified, this, &MainWindow::handlePermissionModified);
+
+ if (m_pendingWidget)
+ m_pendingWidget->deleteLater();
+
+ m_pendingWidget = widget;
+ }
+}
+
+void MainWindow::handlePermissionModified(PermissionWidget *widget)
+{
+ if (!m_pendingWidget || m_pendingWidget != widget)
+ return;
+
+ m_pendingFrame->layout()->removeWidget(widget);
+ m_pendingWidget = nullptr;
+
+ if (QWebEnginePermission::isTransient(widget->m_permission.feature())
+ || widget->m_permission.state() == QWebEnginePermission::Ask
+ || m_profile->persistentPermissionsPolicy() == QWebEngineProfile::NoPersistentPermissions) {
+
+ widget->deleteLater();
+ return;
+ }
+
+ m_layout->insertWidget(0, widget);
+}
+
+void MainWindow::handleUrlChanged(const QUrl &url)
+{
+ m_urlLineEdit->setText(url.toString());
+}
+
+void MainWindow::handleDeleteAllClicked()
+{
+ for (int i = m_layout->count() - 1; i >= 0; i--) {
+ PermissionWidget *widget = qobject_cast<PermissionWidget *>(m_layout->itemAt(i)->widget());
+ if (!widget)
+ continue;
+
+ widget->m_permission.reset();
+ widget->deleteLater();
+ }
+}
+
+void MainWindow::handleNewClicked()
+{
+ PermissionDialog dialog(m_profile);
+ if (dialog.exec() == QDialog::Accepted) {
+ handlePermissionRequested(dialog.permission());
+ }
+}
+
+void MainWindow::handleRefreshClicked()
+{
+ m_webview->load(QUrl::fromUserInput(m_urlLineEdit->text()));
+}
+
+void MainWindow::handleBackClicked()
+{
+ m_webview->triggerPageAction(QWebEnginePage::Back);
+}
+
+void MainWindow::handleForwardClicked()
+{
+ m_webview->triggerPageAction(QWebEnginePage::Forward);
+}
+
+void MainWindow::handlePolicyComboBoxIndexChanged(int index)
+{
+ QWebEngineProfile::PersistentPermissionsPolicy policy;
+ switch (index) {
+ case 0:
+ policy = QWebEngineProfile::PersistentPermissionsOnDisk;
+ break;
+ case 1:
+ policy = QWebEngineProfile::PersistentPermissionsInMemory;
+ break;
+ case 2:
+ policy = QWebEngineProfile::NoPersistentPermissions;
+ break;
+ }
+
+ if (policy == m_profile->persistentPermissionsPolicy())
+ return;
+
+ for (int i = m_layout->count() - 1; i >= 0; i--) {
+ PermissionWidget *widget = qobject_cast<PermissionWidget *>(m_layout->itemAt(i)->widget());
+ if (!widget)
+ continue;
+
+ widget->deleteLater();
+ }
+
+ m_profile->setPersistentPermissionsPolicy(policy);
+ loadStoredPermissions();
+}
+
+bool MainWindow::containsPermission(const QWebEnginePermission &permission)
+{
+ for (const auto *w: std::as_const(m_storedScrollArea->widget()->children())) {
+ const PermissionWidget *widget = qobject_cast<const PermissionWidget *>(w);
+ if (!widget)
+ continue;
+ const QWebEnginePermission &widgetPermission = widget->m_permission;
+ if (widgetPermission == permission)
+ return true;
+ }
+
+ if (m_pendingWidget && m_pendingWidget->m_permission == permission)
+ return true;
+
+ return false;
+}
+
+PermissionWidget *MainWindow::createPermissionWidget(const QWebEnginePermission &permission)
+{
+ if (containsPermission(permission))
+ return nullptr;
+
+ return new PermissionWidget(permission, this);
+}
+
+void MainWindow::loadStoredPermissions()
+{
+ QList<QWebEnginePermission> permissionsList = m_profile->listPermissions();
+ for (QWebEnginePermission &permission : permissionsList) {
+ PermissionWidget *widget = createPermissionWidget(permission);
+ if (widget)
+ m_layout->insertWidget(0, widget);
+ }
+}
diff --git a/examples/webenginewidgets/permissionbrowser/mainwindow.h b/examples/webenginewidgets/permissionbrowser/mainwindow.h
new file mode 100644
index 000000000..8f7a09450
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/mainwindow.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "ui_mainwindow.h"
+#include "ui_permissiondialog.h"
+#include "ui_permissionwidget.h"
+#include <QDialog>
+#include <QMainWindow>
+#include <QWebEngineView>
+#include <QWebEnginePermission>
+
+QT_BEGIN_NAMESPACE
+class QWebEngineView;
+class QWebEngineProfile;
+class QLineEdit;
+QT_END_NAMESPACE
+
+class PermissionDialog : public QDialog, public Ui_PermissionDialog
+{
+ Q_OBJECT
+public:
+ PermissionDialog(const QWebEngineProfile *profile, QWidget *parent = nullptr);
+ ~PermissionDialog();
+ QWebEnginePermission permission();
+
+private:
+ const QWebEngineProfile *m_profile;
+ QWebEnginePermission *m_permission;
+};
+
+class PermissionWidget : public QWidget, public Ui_PermissionWidget
+{
+ Q_OBJECT
+public:
+ PermissionWidget(const QWebEnginePermission &permission, QWidget *parent = nullptr);
+
+ QWebEnginePermission m_permission;
+
+signals:
+ void permissionModified(PermissionWidget *widget);
+
+private:
+ void updateState();
+};
+
+class MainWindow : public QMainWindow, public Ui_MainWindow
+{
+ Q_OBJECT
+public:
+ explicit MainWindow(const QUrl &url);
+ ~MainWindow();
+
+private slots:
+ void handlePermissionRequested(QWebEnginePermission permission);
+ void handleUrlChanged(const QUrl &url);
+
+ void handlePermissionModified(PermissionWidget *widget);
+ void handleDeleteAllClicked();
+ void handleNewClicked();
+ void handleRefreshClicked();
+ void handleBackClicked();
+ void handleForwardClicked();
+ void handlePolicyComboBoxIndexChanged(int index);
+
+private:
+ bool containsPermission(const QWebEnginePermission &permission);
+ PermissionWidget *createPermissionWidget(const QWebEnginePermission &permission);
+ void loadStoredPermissions();
+
+ QVBoxLayout *m_layout;
+ QWebEngineProfile *m_profile;
+ QWebEngineView *m_webview;
+ PermissionWidget *m_pendingWidget;
+};
diff --git a/examples/webenginewidgets/permissionbrowser/mainwindow.ui b/examples/webenginewidgets/permissionbrowser/mainwindow.ui
new file mode 100644
index 000000000..4496b8c07
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/mainwindow.ui
@@ -0,0 +1,356 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1600</width>
+ <height>900</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Permission Browser</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QFrame" name="m_frame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="m_backButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="permissionbrowser.qrc">
+ <normaloff>:3rdparty/go-previous.png</normaloff>:3rdparty/go-previous.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_forwardButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="permissionbrowser.qrc">
+ <normaloff>:3rdparty/go-next.png</normaloff>:3rdparty/go-next.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_refreshButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="permissionbrowser.qrc">
+ <normaloff>:3rdparty/view-refresh.png</normaloff>:3rdparty/view-refresh.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="m_urlLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame_2">
+ <property name="maximumSize">
+ <size>
+ <width>336</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0,0,1,0,0,0">
+ <item>
+ <widget class="QWidget" name="widget_2" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Permissions:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>87</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_newButton">
+ <property name="text">
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_deleteAllButton">
+ <property name="text">
+ <string>Delete All</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_3" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Persistence policy:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QComboBox" name="m_policyComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>Persist on disk</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Persist in memory</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Do not persist</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Stored permissions</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="m_storedScrollArea">
+ <property name="minimumSize">
+ <size>
+ <width>320</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>320</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="lineWidth">
+ <number>2</number>
+ </property>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Pending permission</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="m_pendingFrame">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>104</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <property name="lineWidth">
+ <number>2</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources>
+ <include location="permissionbrowser.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>m_urlLineEdit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>m_refreshButton</receiver>
+ <slot>click()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>509</x>
+ <y>28</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>1024</x>
+ <y>27</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webenginewidgets/permissionbrowser/permissionbrowser.exe.manifest b/examples/webenginewidgets/permissionbrowser/permissionbrowser.exe.manifest
new file mode 100644
index 000000000..acc401776
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/permissionbrowser.exe.manifest
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!--The ID below indicates application support for Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ <!--The ID below indicates application support for Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!--The ID below indicates application support for Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!--The ID below indicates application support for Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!--The ID below indicates application support for Windows 10/11 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ </application>
+</compatibility>
+</assembly>
diff --git a/examples/webenginewidgets/permissionbrowser/permissionbrowser.qrc b/examples/webenginewidgets/permissionbrowser/permissionbrowser.qrc
new file mode 100644
index 000000000..80a7d20f2
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/permissionbrowser.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="view-refresh.png">resources/3rdparty/view-refresh.png</file>
+ <file alias="go-next.png">resources/3rdparty/go-next.png</file>
+ <file alias="go-previous.png">resources/3rdparty/go-previous.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/webenginewidgets/permissionbrowser/permissiondialog.ui b/examples/webenginewidgets/permissionbrowser/permissiondialog.ui
new file mode 100644
index 000000000..a98432131
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/permissiondialog.ui
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PermissionDialog</class>
+ <widget class="QDialog" name="PermissionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>110</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Permission</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Origin</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="m_originLineEdit">
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Feature</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_addButton">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_cancelButton">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="m_featureComboBox"/>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>m_originLineEdit</tabstop>
+ <tabstop>m_addButton</tabstop>
+ <tabstop>m_cancelButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>m_cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>PermissionDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>349</x>
+ <y>89</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>334</x>
+ <y>67</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_addButton</sender>
+ <signal>clicked()</signal>
+ <receiver>PermissionDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>264</x>
+ <y>88</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>218</x>
+ <y>68</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webenginewidgets/permissionbrowser/permissionwidget.ui b/examples/webenginewidgets/permissionbrowser/permissionwidget.ui
new file mode 100644
index 000000000..0a09da5d3
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/permissionwidget.ui
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PermissionWidget</class>
+ <widget class="QWidget" name="PermissionWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>104</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>310</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="formAlignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="verticalSpacing">
+ <number>10</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Origin:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="m_originLabel">
+ <property name="text">
+ <string>Empty</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="m_typeLabel">
+ <property name="text">
+ <string>Empty</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>State:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="m_stateLabel">
+ <property name="text">
+ <string>Empty</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="m_grantButton">
+ <property name="text">
+ <string>Grant</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_denyButton">
+ <property name="text">
+ <string>Deny</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="m_deleteButton">
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/webenginewidgets/permissionbrowser/resources/3rdparty/COPYING b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/COPYING
new file mode 100644
index 000000000..220881da6
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/COPYING
@@ -0,0 +1 @@
+The icons in this repository are herefore released into the Public Domain.
diff --git a/examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-next.png b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-next.png
new file mode 100644
index 000000000..a68e2db77
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-next.png
Binary files differ
diff --git a/examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-previous.png b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-previous.png
new file mode 100644
index 000000000..c37bc0414
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/go-previous.png
Binary files differ
diff --git a/examples/webenginewidgets/permissionbrowser/resources/3rdparty/qt_attribution.json b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/qt_attribution.json
new file mode 100644
index 000000000..e11663d5e
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/qt_attribution.json
@@ -0,0 +1,24 @@
+{
+ "Id": "permissionbrowser-tango",
+ "Name": "Tango Icon Library",
+ "QDocModule": "qtwebengine",
+ "QtUsage": "Used in WebEngine Permission Browser example.",
+
+ "QtParts": [ "examples" ],
+ "Description": "Selected icons from the Tango Icon Library",
+ "Homepage": "http://tango.freedesktop.org/Tango_Icon_Library",
+ "Version": "0.8.90",
+ "DownloadLocation": "http://tango.freedesktop.org/releases/tango-icon-theme-0.8.90.tar.gz",
+ "LicenseId": "urn:dje:license:public-domain",
+ "License": "Public Domain",
+ "LicenseFile": "COPYING",
+ "Copyright": ["Ulisse Perusin <uli.peru@gmail.com>",
+ "Steven Garrity <sgarrity@silverorange.com>",
+ "Lapo Calamandrei <calamandrei@gmail.com>",
+ "Ryan Collier <rcollier@novell.com>",
+ "Rodney Dawes <dobey@novell.com>",
+ "Andreas Nilsson <nisses.mail@home.se>",
+ "Tuomas Kuosmanen <tigert@tigert.com>",
+ "Garrett LeSage <garrett@novell.com>",
+ "Jakub Steiner <jimmac@novell.com>"]
+}
diff --git a/examples/webenginewidgets/permissionbrowser/resources/3rdparty/view-refresh.png b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/view-refresh.png
new file mode 100644
index 000000000..cab4d02c7
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/resources/3rdparty/view-refresh.png
Binary files differ
diff --git a/examples/webenginewidgets/permissionbrowser/resources/AppLogoColor.png b/examples/webenginewidgets/permissionbrowser/resources/AppLogoColor.png
new file mode 100644
index 000000000..2a4971782
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/resources/AppLogoColor.png
Binary files differ
diff --git a/examples/webenginewidgets/permissionbrowser/resources/landing.html b/examples/webenginewidgets/permissionbrowser/resources/landing.html
new file mode 100644
index 000000000..5d921671f
--- /dev/null
+++ b/examples/webenginewidgets/permissionbrowser/resources/landing.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Permissions example page</title>
+ <script>
+ function copyText() {
+ navigator.clipboard.writeText(document.getElementById("copyTextInput").value);
+ }
+
+ function pasteText() {
+ navigator.clipboard.readText()
+ .then((text) => (
+ document.getElementById("pasteTextInput").value = text
+ ))
+ .catch((err) => (
+ document.getElementById("pasteTextInput").value = "<permission denied>"
+ ));
+ }
+
+ function showNotification() {
+ new Notification("Example notification", {
+ body: "Notification contents",
+ tag: "notifTag",
+ lang: "",
+ dir: "auto",
+ icon: "./3rdparty/go-next.png"
+ });
+ }
+
+ function tryShowNotification() {
+ if (Notification.permission !== "granted") {
+ Notification.requestPermission()
+ .then((permission) => {
+ if (permission === "granted") { showNotification() }
+
+ })
+ .catch((err) => (
+ document.getElementById("pasteTextInput").value = err
+ ));
+ } else {
+ showNotification();
+ }
+ }
+
+ function listFonts() {
+ var fontSelect = document.getElementById("fontSelect");
+ var i, length = fontSelect.options.length - 1;
+ for (i = length; i >= 0; i--) {
+ fontSelect.remove(i);
+ }
+
+ window.queryLocalFonts()
+ .then((fontsList) => {
+ for (const font of fontsList) {
+ fontSelect.add(new Option(text = font.fullName));
+ }
+ })
+ .catch()
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Permission Browser Example</h1>
+ <div>
+ <h2>Clipboard</h2>
+ <div>
+ <button onclick="copyText()">Copy text</button>
+ <input id="copyTextInput" value="Example text"></input>
+ </div>
+ <div>
+ <button onclick="pasteText()">Paste text</button>
+ <input id="pasteTextInput" placeholder="Text will be pasted here"></input>
+ </div>
+ </div>
+ <div>
+ <h2>Notifications</h2>
+ <div>
+ <button onclick="tryShowNotification()">Show notification</button>
+ </div>
+ </div>
+ <div>
+ <h2>Local fonts</h2>
+ <button onclick="listFonts()">List fonts</button>
+ <select id="fontSelect"></select>
+ </div>
+ </body>
+</html>
diff --git a/examples/webenginewidgets/push-notifications/main.cpp b/examples/webenginewidgets/push-notifications/main.cpp
index 18a862182..950ebfc9f 100644
--- a/examples/webenginewidgets/push-notifications/main.cpp
+++ b/examples/webenginewidgets/push-notifications/main.cpp
@@ -20,13 +20,12 @@ int main(int argc, char *argv[])
QWebEngineView view(profile.data());
auto popup = new NotificationPopup(&view);
- QObject::connect(view.page(), &QWebEnginePage::featurePermissionRequested,
- [&](const QUrl &origin, QWebEnginePage::Feature feature) {
- if (feature != QWebEnginePage::Notifications)
+ QObject::connect(view.page(), &QWebEnginePage::permissionRequested,
+ [&](QWebEnginePermission permission) {
+ if (permission.feature() != QWebEnginePage::Notifications)
return;
- view.page()->setFeaturePermission(origin, feature,
- QWebEnginePage::PermissionGrantedByUser);
+ permission.grant();
});
profile->setPushServiceEnabled(true);
diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
index dd7a8b998..a312da3ad 100644
--- a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
+++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
@@ -103,6 +103,25 @@
\skipto TabWidget::setupView
\printuntil /^\}/
+ \section1 Closing Tabs
+
+ When the user closes a tab, we first trigger the \l {QWebEnginePage::}{RequestClose} web action
+ on the corresponding \c WebView:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.cpp
+ \skipto QTabBar::tabCloseRequested
+ \printuntil }
+
+ This allows any JavaScript \c beforeunload event listeners to fire, which may
+ prompt the user with a dialog to confirm that they want to close the page.
+ In this case, the user can reject the close request and leave the tab open,
+ otherwise the \l {QWebEnginePage::}{windowCloseRequested} signal is emitted and we close the
+ tab:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.cpp
+ \skipto QWebEnginePage::windowCloseRequested
+ \printuntil }
+
\section1 Implementing WebView Functionality
The \c WebView is derived from QWebEngineView to support the following
@@ -204,13 +223,17 @@
The \c handleProxyAuthenticationRequired signal handler implements the very same
steps for the authentication of HTTP proxies.
- In case of SSL errors, we just need to return a boolean value indicating
- whether the certificate should be ignored.
+ In case of SSL errors, we check whether they come from the main frame, or
+ from a resource inside the page. Resource errors automatically trigger a
+ certificate rejection, since a user won't have enough context to make a
+ decision. For all other cases, we trigger a dialog where the user can
+ allow or reject the certificate.
\quotefromfile webenginewidgets/simplebrowser/webpage.cpp
\skipto WebPage::handleCertificateError(
\printuntil }
\printuntil }
+ \printuntil }
\section1 Opening a Web Page
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
index f9037a8e1..acdf49510 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
@@ -21,7 +21,10 @@ TabWidget::TabWidget(QWebEngineProfile *profile, QWidget *parent)
tabBar->setMovable(true);
tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
connect(tabBar, &QTabBar::customContextMenuRequested, this, &TabWidget::handleContextMenuRequested);
- connect(tabBar, &QTabBar::tabCloseRequested, this, &TabWidget::closeTab);
+ connect(tabBar, &QTabBar::tabCloseRequested, [this](int index) {
+ if (WebView *view = webView(index))
+ view->page()->triggerAction(QWebEnginePage::WebAction::RequestClose);
+ });
connect(tabBar, &QTabBar::tabBarDoubleClicked, [this](int index) {
if (index == -1)
createTab();
diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp
index 807cdf0ff..6fc9aeaf9 100644
--- a/examples/webenginewidgets/simplebrowser/webpage.cpp
+++ b/examples/webenginewidgets/simplebrowser/webpage.cpp
@@ -19,6 +19,13 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
void WebPage::handleCertificateError(QWebEngineCertificateError error)
{
+ // Automatically block certificate errors from page resources without prompting the user.
+ // This mirrors the behavior found in other major browsers.
+ if (!error.isMainFrame()) {
+ error.rejectCertificate();
+ return;
+ }
+
error.defer();
QTimer::singleShot(0, this,
[this, error]() mutable { emit createCertificateErrorDialog(error); });
diff --git a/examples/webenginewidgets/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp
index 08e044f70..3dcfc0c47 100644
--- a/examples/webenginewidgets/simplebrowser/webview.cpp
+++ b/examples/webenginewidgets/simplebrowser/webview.cpp
@@ -71,26 +71,26 @@ WebView::~WebView()
m_imageAnimationGroup = nullptr;
}
-inline QString questionForFeature(QWebEnginePage::Feature feature)
+inline QString questionForFeature(QWebEnginePermission::Feature feature)
{
switch (feature) {
- case QWebEnginePage::Geolocation:
+ case QWebEnginePermission::Geolocation:
return QObject::tr("Allow %1 to access your location information?");
- case QWebEnginePage::MediaAudioCapture:
+ case QWebEnginePermission::MediaAudioCapture:
return QObject::tr("Allow %1 to access your microphone?");
- case QWebEnginePage::MediaVideoCapture:
+ case QWebEnginePermission::MediaVideoCapture:
return QObject::tr("Allow %1 to access your webcam?");
- case QWebEnginePage::MediaAudioVideoCapture:
+ case QWebEnginePermission::MediaAudioVideoCapture:
return QObject::tr("Allow %1 to access your microphone and webcam?");
- case QWebEnginePage::MouseLock:
+ case QWebEnginePermission::MouseLock:
return QObject::tr("Allow %1 to lock your mouse cursor?");
- case QWebEnginePage::DesktopVideoCapture:
+ case QWebEnginePermission::DesktopVideoCapture:
return QObject::tr("Allow %1 to capture video of your desktop?");
- case QWebEnginePage::DesktopAudioVideoCapture:
+ case QWebEnginePermission::DesktopAudioVideoCapture:
return QObject::tr("Allow %1 to capture audio and video of your desktop?");
- case QWebEnginePage::Notifications:
+ case QWebEnginePermission::Notifications:
return QObject::tr("Allow %1 to show notification on your desktop?");
- case QWebEnginePage::ClipboardReadWrite:
+ case QWebEnginePermission::ClipboardReadWrite:
return QObject::tr("Allow %1 to read from and write to the clipboard?");
}
return QString();
@@ -103,8 +103,8 @@ void WebView::setPage(WebPage *page)
&WebView::handleCertificateError);
disconnect(oldPage, &QWebEnginePage::authenticationRequired, this,
&WebView::handleAuthenticationRequired);
- disconnect(oldPage, &QWebEnginePage::featurePermissionRequested, this,
- &WebView::handleFeaturePermissionRequested);
+ disconnect(oldPage, &QWebEnginePage::permissionRequested, this,
+ &WebView::handlePermissionRequested);
disconnect(oldPage, &QWebEnginePage::proxyAuthenticationRequired, this,
&WebView::handleProxyAuthenticationRequired);
disconnect(oldPage, &QWebEnginePage::registerProtocolHandlerRequested, this,
@@ -124,8 +124,8 @@ void WebView::setPage(WebPage *page)
connect(page, &WebPage::createCertificateErrorDialog, this, &WebView::handleCertificateError);
connect(page, &QWebEnginePage::authenticationRequired, this,
&WebView::handleAuthenticationRequired);
- connect(page, &QWebEnginePage::featurePermissionRequested, this,
- &WebView::handleFeaturePermissionRequested);
+ connect(page, &QWebEnginePage::permissionRequested, this,
+ &WebView::handlePermissionRequested);
connect(page, &QWebEnginePage::proxyAuthenticationRequired, this,
&WebView::handleProxyAuthenticationRequired);
connect(page, &QWebEnginePage::registerProtocolHandlerRequested, this,
@@ -309,17 +309,14 @@ void WebView::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticato
}
}
-void WebView::handleFeaturePermissionRequested(const QUrl &securityOrigin,
- QWebEnginePage::Feature feature)
+void WebView::handlePermissionRequested(QWebEnginePermission permission)
{
QString title = tr("Permission Request");
- QString question = questionForFeature(feature).arg(securityOrigin.host());
+ QString question = questionForFeature(permission.feature()).arg(permission.origin().host());
if (!question.isEmpty() && QMessageBox::question(window(), title, question) == QMessageBox::Yes)
- page()->setFeaturePermission(securityOrigin, feature,
- QWebEnginePage::PermissionGrantedByUser);
+ permission.grant();
else
- page()->setFeaturePermission(securityOrigin, feature,
- QWebEnginePage::PermissionDeniedByUser);
+ permission.deny();
}
void WebView::handleProxyAuthenticationRequired(const QUrl &, QAuthenticator *auth,
diff --git a/examples/webenginewidgets/simplebrowser/webview.h b/examples/webenginewidgets/simplebrowser/webview.h
index c7e7f394c..d652fbdc9 100644
--- a/examples/webenginewidgets/simplebrowser/webview.h
+++ b/examples/webenginewidgets/simplebrowser/webview.h
@@ -14,6 +14,7 @@
#include <QWebEngineRegisterProtocolHandlerRequest>
#include <QWebEngineWebAuthUxRequest>
#include <QWebEngineSettings>
+#include <QWebEnginePermission>
#include <QActionGroup>
class WebPage;
@@ -43,8 +44,7 @@ signals:
private slots:
void handleCertificateError(QWebEngineCertificateError error);
void handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth);
- void handleFeaturePermissionRequested(const QUrl &securityOrigin,
- QWebEnginePage::Feature feature);
+ void handlePermissionRequested(QWebEnginePermission permission);
void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth,
const QString &proxyHost);
void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request);