Add a fullscreen notification overlay
From the spec: User agents should ensure, e.g. by means of an overlay, that the end user is aware something is displayed fullscreen. User agents should provide a means of exiting fullscreen that always works and advertise this to the user. This is to prevent a site from spoofing the end user by recreating the user agent or even operating system environment when fullscreen. https://fullscreen.spec.whatwg.org/#security-and-privacy-considerations
This commit is contained in:
parent
39508d984e
commit
29ffa3d134
@ -38,6 +38,7 @@ from qutebrowser.browser import browsertab, mouse, shared
|
|||||||
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
||||||
interceptor, webenginequtescheme,
|
interceptor, webenginequtescheme,
|
||||||
webenginedownloads)
|
webenginedownloads)
|
||||||
|
from qutebrowser.misc import miscwidgets
|
||||||
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
||||||
objreg, jinja)
|
objreg, jinja)
|
||||||
|
|
||||||
@ -654,9 +655,13 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
|
|
||||||
@pyqtSlot('QWebEngineFullScreenRequest')
|
@pyqtSlot('QWebEngineFullScreenRequest')
|
||||||
def _on_fullscreen_requested(self, request):
|
def _on_fullscreen_requested(self, request):
|
||||||
# FIXME:qtwebengine do we want a setting to disallow this?
|
|
||||||
request.accept()
|
request.accept()
|
||||||
self.fullscreen_requested.emit(request.toggleOn())
|
on = request.toggleOn()
|
||||||
|
self.fullscreen_requested.emit(on)
|
||||||
|
if on:
|
||||||
|
notification = miscwidgets.FullscreenNotification(self)
|
||||||
|
notification.show()
|
||||||
|
notification.set_timeout(3000)
|
||||||
|
|
||||||
def _connect_signals(self):
|
def _connect_signals(self):
|
||||||
view = self._widget
|
view = self._widget
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
|
|
||||||
"""Misc. widgets used at different places."""
|
"""Misc. widgets used at different places."""
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QSize
|
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QSize, QTimer
|
||||||
from PyQt5.QtWidgets import (QLineEdit, QWidget, QHBoxLayout, QLabel,
|
from PyQt5.QtWidgets import (QLineEdit, QWidget, QHBoxLayout, QLabel,
|
||||||
QStyleOption, QStyle, QLayout)
|
QStyleOption, QStyle, QLayout, QApplication)
|
||||||
from PyQt5.QtGui import QValidator, QPainter
|
from PyQt5.QtGui import QValidator, QPainter
|
||||||
|
|
||||||
from qutebrowser.utils import utils
|
from qutebrowser.utils import utils, objreg
|
||||||
from qutebrowser.misc import cmdhistory
|
from qutebrowser.misc import cmdhistory
|
||||||
|
|
||||||
|
|
||||||
@ -264,3 +264,42 @@ class WrapperLayout(QLayout):
|
|||||||
def unwrap(self):
|
def unwrap(self):
|
||||||
self._widget.setParent(None)
|
self._widget.setParent(None)
|
||||||
self._widget.deleteLater()
|
self._widget.deleteLater()
|
||||||
|
|
||||||
|
|
||||||
|
class FullscreenNotification(QLabel):
|
||||||
|
|
||||||
|
"""A label telling the user this page is now fullscreen."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setStyleSheet("""
|
||||||
|
background-color: rgba(50, 50, 50, 80%);
|
||||||
|
color: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 30px;
|
||||||
|
""")
|
||||||
|
|
||||||
|
key_config = objreg.get('key-config')
|
||||||
|
all_bindings = key_config.get_reverse_bindings_for('normal')
|
||||||
|
bindings = all_bindings.get('fullscreen --leave')
|
||||||
|
if bindings:
|
||||||
|
key = bindings[0]
|
||||||
|
if utils.is_special_key(key):
|
||||||
|
key = key.strip('<>').capitalize()
|
||||||
|
self.setText("Press {} to exit fullscreen.".format(key))
|
||||||
|
else:
|
||||||
|
self.setText("Page is now fullscreen.")
|
||||||
|
|
||||||
|
self.resize(self.sizeHint())
|
||||||
|
geom = QApplication.desktop().screenGeometry(self)
|
||||||
|
self.move((geom.width() - self.sizeHint().width()) / 2, 30)
|
||||||
|
|
||||||
|
def set_timeout(self, timeout):
|
||||||
|
"""Hide the widget after the given timeout."""
|
||||||
|
QTimer.singleShot(timeout, self._on_timeout)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def _on_timeout(self):
|
||||||
|
"""Hide and delete the widget."""
|
||||||
|
self.hide()
|
||||||
|
self.deleteLater()
|
||||||
|
@ -100,3 +100,26 @@ class TestWrapperLayout:
|
|||||||
def test_wrapped(self, container):
|
def test_wrapped(self, container):
|
||||||
assert container.wrapped.parent() is container
|
assert container.wrapped.parent() is container
|
||||||
assert container.focusProxy() is container.wrapped
|
assert container.focusProxy() is container.wrapped
|
||||||
|
|
||||||
|
|
||||||
|
class TestFullscreenNotification:
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('bindings, text', [
|
||||||
|
({'<escape>': 'fullscreen --leave'},
|
||||||
|
"Press Escape to exit fullscreen."),
|
||||||
|
({'<escape>': 'fullscreen'}, "Page is now fullscreen."),
|
||||||
|
({'a': 'fullscreen --leave'}, "Press a to exit fullscreen."),
|
||||||
|
({}, "Page is now fullscreen."),
|
||||||
|
])
|
||||||
|
def test_text(self, qtbot, key_config_stub, bindings, text):
|
||||||
|
key_config_stub.set_bindings_for('normal', bindings)
|
||||||
|
w = miscwidgets.FullscreenNotification()
|
||||||
|
qtbot.add_widget(w)
|
||||||
|
assert w.text() == text
|
||||||
|
|
||||||
|
def test_timeout(self, qtbot, key_config_stub):
|
||||||
|
key_config_stub.set_bindings_for('normal', {})
|
||||||
|
w = miscwidgets.FullscreenNotification()
|
||||||
|
qtbot.add_widget(w)
|
||||||
|
with qtbot.waitSignal(w.destroyed):
|
||||||
|
w.set_timeout(1)
|
||||||
|
Loading…
Reference in New Issue
Block a user