1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
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 \QC \uicontrol 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::PermissionType, 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 \l {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 \l {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 \c 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;
some \c PermissionTypes are non-persistent, which means they require
a permission prompt be shown to the user every time they're used.
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 AskEveryTime.
\note Check the \l QWebEnginePermission::PermissionType documentation to see which
\c PermissionTypes are persistent.
\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::listAllPermissions():
\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 permission 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::PermissionType. We make sure to filter out non-persistent
permission types, 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::StoreOnDisk 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 only needs 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::StoreInMemory Has the same behavior as above,
except that permissions will be destroyed at application exit, and not committed
to disk.
\li \l QWebEngineProfile::AskEveryTime makes sure permissions are never
remembered, and all act as if they're non-persistent. 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::listAllPermissions():
\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 /^\}/
*/
|