summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsh <relativistic.policeman@gmail.com>2020-06-03 22:21:22 -0700
committerAsh <relativistic.policeman@gmail.com>2020-06-03 23:43:26 -0700
commit77d4d3f4d4255ddfdd4f05ae4abda51ef306b32c (patch)
treed15e13adf4bdec9a63da9aad0ff39f5d8c501a89
parent755fafc9ce56a02104f672722d6d1db7b243ff37 (diff)
downloadqutebrowser-77d4d3f4d4255ddfdd4f05ae4abda51ef306b32c.tar.gz
qutebrowser-77d4d3f4d4255ddfdd4f05ae4abda51ef306b32c.zip
Add support for onclose callbacks on notifications.
-rw-r--r--pytest.ini1
-rw-r--r--qutebrowser/browser/webengine/notification.py32
-rw-r--r--tests/end2end/conftest.py12
-rw-r--r--tests/end2end/features/notifications.feature14
-rw-r--r--tests/end2end/features/test_notifications_bdd.py4
-rw-r--r--tests/end2end/fixtures/notificationserver.py10
6 files changed, 65 insertions, 8 deletions
diff --git a/pytest.ini b/pytest.ini
index e85f2b298..a01c456f7 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -23,6 +23,7 @@ markers =
qtwebkit_skip: Tests not applicable with QtWebKit
qtwebengine_flaky: Tests which are flaky (and currently skipped) with QtWebEngine
qtwebengine_mac_xfail: Tests which fail on macOS with QtWebEngine
+ qtwebengine_py_5_15: Tests which require PyQtWebEngine 5.15.
js_prompt: Tests needing to display a javascript prompt
this: Used to mark tests during development
no_invalid_lines: Don't fail on unparseable lines in end2end tests
diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py
index e2bc3700d..95a084c7e 100644
--- a/qutebrowser/browser/webengine/notification.py
+++ b/qutebrowser/browser/webengine/notification.py
@@ -24,8 +24,9 @@ import typing
from qutebrowser.utils import log
from PyQt5.QtGui import QImage
-from PyQt5.QtCore import QVariant, QMetaType, QByteArray, PYQT_VERSION
-from PyQt5.QtDBus import QDBusConnection, QDBusInterface, QDBus, QDBusArgument
+from PyQt5.QtCore import QObject, QVariant, QMetaType, QByteArray, pyqtSlot, PYQT_VERSION
+from PyQt5.QtDBus import QDBusConnection, QDBusInterface, QDBus, QDBusArgument, QDBusMessage
+from PyQt5.QtWebEngine import PYQT_WEBENGINE_VERSION
from PyQt5.QtWebEngineCore import QWebEngineNotification
from PyQt5.QtWebEngineWidgets import QWebEngineProfile
@@ -34,7 +35,7 @@ class DBusException(Exception):
"""Raised when something goes wrong with talking to DBus."""
-class DBusNotificationPresenter:
+class DBusNotificationPresenter(QObject):
"""Manages notifications that are sent over DBus."""
SERVICE = "org.freedesktop.Notifications"
@@ -43,17 +44,29 @@ class DBusNotificationPresenter:
INTERFACE = "org.freedesktop.Notifications"
def __init__(self, test_service: bool = False):
+ super().__init__()
+ self._active_notifications = {} # type: typing.Dict[int, QWebEngineNotification]
bus = QDBusConnection.sessionBus()
if not bus.isConnected():
raise DBusException("Failed to connect to DBus session bus")
+ service = self.TEST_SERVICE if test_service else self.SERVICE
+
self.interface = QDBusInterface(
- self.TEST_SERVICE if test_service else self.SERVICE,
+ service,
self.PATH,
self.INTERFACE,
bus,
)
+ bus.connect(
+ service,
+ self.PATH,
+ self.INTERFACE,
+ "NotificationClosed",
+ self._handle_close
+ )
+
if not self.interface:
raise DBusException("Could not construct a DBus interface")
@@ -114,6 +127,7 @@ class DBusNotificationPresenter:
)
notification_id = reply.arguments()[0]
+ self._active_notifications[notification_id] = qt_notification
log.webview.debug("Sent out notification {}".format(notification_id))
def _convert_image(self, qimage: QImage) -> QDBusArgument:
@@ -141,3 +155,13 @@ class DBusNotificationPresenter:
image_data.add(QByteArray(bits))
image_data.endStructure()
return image_data
+
+ @pyqtSlot(QDBusMessage)
+ def _handle_close(self, message: QDBusMessage) -> None:
+ notification_id = message.arguments()[0]
+ if notification_id in self._active_notifications:
+ try:
+ self._active_notifications[notification_id].close()
+ except RuntimeError:
+ # WORKAROUND for https://www.riverbankcomputing.com/pipermail/pyqt/2020-May/042918.html
+ pass
diff --git a/tests/end2end/conftest.py b/tests/end2end/conftest.py
index 7190c7ef4..84e612952 100644
--- a/tests/end2end/conftest.py
+++ b/tests/end2end/conftest.py
@@ -112,6 +112,7 @@ def _get_backend_tag(tag):
'qtwebengine_todo': pytest.mark.qtwebengine_todo,
'qtwebengine_skip': pytest.mark.qtwebengine_skip,
'qtwebengine_notifications': pytest.mark.qtwebengine_notifications,
+ 'qtwebengine_py_5_15': pytest.mark.qtwebengine_py_5_15,
'qtwebkit_skip': pytest.mark.qtwebkit_skip,
}
if not any(tag.startswith(t + ':') for t in pytest_marks):
@@ -136,6 +137,13 @@ if not getattr(sys, 'frozen', False):
return None
+def _pyqt_webengine_at_least_5_15() -> bool:
+ try:
+ from PyQt5.QtWebEngine import PYQT_WEBENGINE_VERSION
+ return PYQT_WEBENGINE_VERSION >= 0x050F00
+ except ImportError:
+ return False
+
def pytest_collection_modifyitems(config, items):
"""Apply @qtwebengine_* markers; skip unittests with QUTE_BDD_WEBENGINE."""
markers = [
@@ -153,6 +161,10 @@ def pytest_collection_modifyitems(config, items):
config.webengine),
('qtwebengine_mac_xfail', 'Fails on macOS with QtWebEngine',
pytest.mark.xfail, config.webengine and utils.is_mac),
+ # WORKAROUND for https://www.riverbankcomputing.com/pipermail/pyqt/2020-May/042918.html
+ ('qtwebengine_py_5_15', 'Skipped with PyQtWebEngine < 5.15',
+ pytest.mark.skipif,
+ config.webengine and not _pyqt_webengine_at_least_5_15())
]
for item in items:
diff --git a/tests/end2end/features/notifications.feature b/tests/end2end/features/notifications.feature
index fcbb8fa25..4e950c133 100644
--- a/tests/end2end/features/notifications.feature
+++ b/tests/end2end/features/notifications.feature
@@ -4,7 +4,8 @@ Feature: Notifications
HTML5 notification API interaction
Background:
- Given I open data/prompt/notifications.html
+ Given I have a fresh instance
+ And I open data/prompt/notifications.html
And I set content.notifications to true
And I run :click-element id button
@@ -14,3 +15,14 @@ Feature: Notifications
Then the javascript message "notification shown" should be logged
And a notification with id 1 is presented
+ @qtwebengine_notifications @qtwebengine_py_5_15
+ Scenario: User closes presented notification
+ When I run :click-element id show-button
+ And I close the notification with id 1
+ Then the javascript message "notification closed" should be logged
+
+ @qtwebengine_notifications @qtwebengine_py_5_15
+ Scenario: User closes some other application's notification
+ When I run :click-element id show-button
+ And I close the notification with id 1234
+ Then the javascript message "notification closed" should not be logged
diff --git a/tests/end2end/features/test_notifications_bdd.py b/tests/end2end/features/test_notifications_bdd.py
index c06cb394f..1c16b4c01 100644
--- a/tests/end2end/features/test_notifications_bdd.py
+++ b/tests/end2end/features/test_notifications_bdd.py
@@ -27,3 +27,7 @@ from qutebrowser.utils import qtutils
@bdd.then(bdd.parsers.cfparse('a notification with id {id_:d} is presented'))
def notification_presented(notification_server, id_):
assert id_ in notification_server.messages
+
+@bdd.when(bdd.parsers.cfparse('I close the notification with id {id_:d}'))
+def close_notification(notification_server, id_):
+ notification_server.close(id_)
diff --git a/tests/end2end/fixtures/notificationserver.py b/tests/end2end/fixtures/notificationserver.py
index d08a34eb3..5abb8c498 100644
--- a/tests/end2end/fixtures/notificationserver.py
+++ b/tests/end2end/fixtures/notificationserver.py
@@ -23,6 +23,7 @@ class TestNotificationServer(QObject):
super().__init__()
self._service = service
self._bus = QDBusConnection.sessionBus()
+ assert self._bus.isConnected()
self._message_id = 0
# A dict mapping notification IDs to currently-displayed notifications.
self.messages = {} # type: typing.Dict[int, QDBusMessage]
@@ -35,6 +36,7 @@ class TestNotificationServer(QObject):
QDBusConnection.ExportAllSlots)
def unregister(self) -> None:
+ self._bus.unregisterObject(DBusNotificationPresenter.PATH)
assert self._bus.unregisterService(self._service)
@pyqtSlot(QDBusMessage, result="uint")
@@ -58,9 +60,11 @@ class TestNotificationServer(QObject):
@pytest.fixture
def notification_server(qapp):
server = TestNotificationServer(DBusNotificationPresenter.TEST_SERVICE)
- server.register()
- yield server
- server.unregister()
+ try:
+ server.register()
+ yield server
+ finally:
+ server.unregister()
def _as_uint32(x: int) -> QVariant: