diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc
index d8d58d9a2..75ea4a0a6 100644
--- a/doc/help/settings.asciidoc
+++ b/doc/help/settings.asciidoc
@@ -2536,6 +2536,7 @@ Valid values:
* +qt+: Use Qt's native notification presenter. Switching from or to this value requires a restart of qutebrowser.
* +libnotify+: Use a libnotify-compatible presenter if DBus is available, show an error (and fall back to Qt's presenter) otherwise.
* +systray+: Use a notification presenter based on a systray icon. This is a reimplementation of the `qt` setting value, but with the possibility to switch to it at runtime.
+ * +messages+: Show notifications as qutebrowser messages. Most features (images, clicking/closing notifications) aren't available.
Default: +pass:[auto]+
diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py
index d46a3013f..17f2b3f9b 100644
--- a/qutebrowser/browser/webengine/notification.py
+++ b/qutebrowser/browser/webengine/notification.py
@@ -27,10 +27,11 @@ https://specifications.freedesktop.org/notification-spec/notification-spec-lates
import html
import dataclasses
+import itertools
from typing import Any, Dict, Optional, TYPE_CHECKING
from PyQt5.QtCore import (Qt, QObject, QVariant, QMetaType, QByteArray, pyqtSlot,
- pyqtSignal)
+ pyqtSignal, QTimer)
from PyQt5.QtGui import QImage, QIcon, QPixmap
from PyQt5.QtDBus import (QDBusConnection, QDBusInterface, QDBus,
QDBusArgument, QDBusMessage, QDBusError)
@@ -129,6 +130,8 @@ class NotificationBridgePresenter(QObject):
self._adapter = SystrayNotificationAdapter()
elif setting == "systray":
self._adapter = SystrayNotificationAdapter()
+ elif setting == "messages":
+ self._adapter = MessagesNotificationAdapter()
else:
raise utils.Unreachable(setting)
@@ -181,9 +184,8 @@ class NotificationBridgePresenter(QObject):
f"new id {notification_id}.")
log.webview.debug(f"Sent out notification {notification_id}")
- self._active_notifications[notification_id] = qt_notification
-
qt_notification.show()
+ self._active_notifications[notification_id] = qt_notification
def _find_replaces_id(
self,
@@ -290,6 +292,43 @@ class SystrayNotificationAdapter(AbstractNotificationAdapter):
self.on_clicked.emit(self.NOTIFICATION_ID)
+class MessagesNotificationAdapter(AbstractNotificationAdapter):
+
+ """Shows notifications using qutebrowser messages.
+
+ This is mostly used as a fallback if no other method is available. Most notification
+ features are not supported.
+ """
+
+ def __init__(self, parent: QObject = None) -> None:
+ super().__init__(parent)
+ self._id_gen = itertools.count(1)
+
+ def present(
+ self,
+ qt_notification: "QWebEngineNotification",
+ *,
+ replaces_id: Optional[int],
+ ) -> int:
+ url = html.escape(qt_notification.origin().toDisplayString())
+ title = html.escape(qt_notification.title())
+ body = html.escape(qt_notification.message())
+ hint = "" if qt_notification.icon().isNull() else " (image not shown)"
+
+ new_id = replaces_id if replaces_id is not None else next(self._id_gen)
+ markup = (
+ f"Notification from {url}:{hint}
"
+ f"{title}
"
+ f"{body}"
+ )
+ message.info(markup, replace=f'notifications-{new_id}')
+
+ # Faking closing, timing might not be 100% accurate
+ QTimer.singleShot(config.val.messages.timeout, lambda: self.close_id.emit(new_id))
+
+ return new_id
+
+
@dataclasses.dataclass
class _ServerQuirks:
diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml
index 0ef9f2fad..b828732ce 100644
--- a/qutebrowser/config/configdata.yml
+++ b/qutebrowser/config/configdata.yml
@@ -926,6 +926,8 @@ content.notifications.presenter:
- systray: Use a notification presenter based on a systray icon. This is a
reimplementation of the `qt` setting value, but with the possibility to switch
to it at runtime.
+ - messages: Show notifications as qutebrowser messages. Most features (images,
+ clicking/closing notifications) aren't available.
backend:
QtWebEngine: Qt 5.14
QtWebKit: false