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:
Florian Bruhin 2017-02-06 15:48:58 +01:00
parent 39508d984e
commit 29ffa3d134
3 changed files with 72 additions and 5 deletions

View File

@ -38,6 +38,7 @@ from qutebrowser.browser import browsertab, mouse, shared
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
interceptor, webenginequtescheme,
webenginedownloads)
from qutebrowser.misc import miscwidgets
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
objreg, jinja)
@ -654,9 +655,13 @@ class WebEngineTab(browsertab.AbstractTab):
@pyqtSlot('QWebEngineFullScreenRequest')
def _on_fullscreen_requested(self, request):
# FIXME:qtwebengine do we want a setting to disallow this?
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):
view = self._widget

View File

@ -19,12 +19,12 @@
"""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,
QStyleOption, QStyle, QLayout)
QStyleOption, QStyle, QLayout, QApplication)
from PyQt5.QtGui import QValidator, QPainter
from qutebrowser.utils import utils
from qutebrowser.utils import utils, objreg
from qutebrowser.misc import cmdhistory
@ -264,3 +264,42 @@ class WrapperLayout(QLayout):
def unwrap(self):
self._widget.setParent(None)
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()

View File

@ -100,3 +100,26 @@ class TestWrapperLayout:
def test_wrapped(self, container):
assert container.wrapped.parent() is container
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)