Browse Source

Keep notification independent of main window minimization

master
evgeny 1 week ago
parent
commit
bc42df12f5
  1. 9
      tools/chatgui/src/message_notification.cpp
  2. 6
      tools/chatgui/src/message_notification.h
  3. 21
      tools/chatgui/tests/test_message_notification.cpp

9
tools/chatgui/src/message_notification.cpp

@ -13,8 +13,8 @@
#include <QHideEvent> #include <QHideEvent>
#include <QCloseEvent> #include <QCloseEvent>
MessageNotification::MessageNotification(QWidget* parent) MessageNotification::MessageNotification()
: QWidget(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus) : QWidget(nullptr, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus)
, m_activity(new UserActivityMonitor(this)) , m_activity(new UserActivityMonitor(this))
{ {
setObjectName("messageNotification"); setObjectName("messageNotification");
@ -67,9 +67,10 @@ MessageNotification::~MessageNotification() {
qPrintable(m_target), int(isVisible()), int(m_hideTimer.isActive())); qPrintable(m_target), int(isVisible()), int(m_hideTimer.isActive()));
} }
void MessageNotification::showMessage(const QString& target, const QString& sender, const QString& channel, const QRect& trayGeometry) { void MessageNotification::showMessage(const QString& target, const QString& sender, const QString& channel,
const QRect& trayGeometry, QScreen* preferredScreen) {
QScreen* screen = trayGeometry.isEmpty() ? nullptr : QGuiApplication::screenAt(trayGeometry.center()); QScreen* screen = trayGeometry.isEmpty() ? nullptr : QGuiApplication::screenAt(trayGeometry.center());
if (!screen && parentWidget()) screen = parentWidget()->screen(); if (!screen) screen = preferredScreen;
if (!screen) screen = QGuiApplication::primaryScreen(); if (!screen) screen = QGuiApplication::primaryScreen();
if (!screen || screen->availableGeometry().isEmpty()) { if (!screen || screen->availableGeometry().isEmpty()) {
GUI_ERROR("notification: no available screen target=%s", qPrintable(target)); GUI_ERROR("notification: no available screen target=%s", qPrintable(target));

6
tools/chatgui/src/message_notification.h

@ -6,14 +6,16 @@
#include <QTimer> #include <QTimer>
class QLabel; class QLabel;
class QScreen;
class UserActivityMonitor; class UserActivityMonitor;
class MessageNotification : public QWidget { class MessageNotification : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit MessageNotification(QWidget* parent = nullptr); MessageNotification();
~MessageNotification() override; ~MessageNotification() override;
void showMessage(const QString& target, const QString& sender, const QString& channel, const QRect& trayGeometry); void showMessage(const QString& target, const QString& sender, const QString& channel,
const QRect& trayGeometry, QScreen* preferredScreen = nullptr);
void dismiss(const char* reason); void dismiss(const char* reason);
signals: signals:

21
tools/chatgui/tests/test_message_notification.cpp

@ -43,8 +43,9 @@ public slots:
requests, (unsigned long long)idle, delayMs, int(calledFromDBus())); requests, (unsigned long long)idle, delayMs, int(calledFromDBus()));
if (delayMs) { if (delayMs) {
const QDBusMessage reply = message().createReply(QVariant::fromValue(idle)); const QDBusMessage reply = message().createReply(QVariant::fromValue(idle));
const QDBusConnection bus = connection();
setDelayedReply(true); setDelayedReply(true);
QTimer::singleShot(delayMs, this, [reply] { QDBusConnection::sessionBus().send(reply); }); QTimer::singleShot(delayMs, this, [reply, bus] { bus.send(reply); });
} }
return idle; return idle;
} }
@ -60,6 +61,13 @@ private slots:
qunsetenv("XDG_SESSION_TYPE"); qunsetenv("XDG_SESSION_TYPE");
} }
void cleanup() {
qunsetenv("XDG_SESSION_TYPE");
#ifdef UTUN_TEST_ACTIVITY_DBUS
QDBusConnection::disconnectFromBus("notification-test-service");
#endif
}
void firstSystemActivityAndCancellation() { void firstSystemActivityAndCancellation() {
FakeSystemActivity activity; FakeSystemActivity activity;
QSignalSpy spy(&activity, &UserActivityMonitor::activity); QSignalSpy spy(&activity, &UserActivityMonitor::activity);
@ -98,11 +106,15 @@ private slots:
QWidget hiddenParent; QWidget hiddenParent;
QLineEdit otherWindow; QLineEdit otherWindow;
otherWindow.show(); otherWindow.show();
QApplication::setActiveWindow(&otherWindow); otherWindow.activateWindow();
MessageNotification notification(&hiddenParent); QTRY_COMPARE(QApplication::activeWindow(), &otherWindow);
MessageNotification notification;
notification.showMessage("42", "Alice", "Test channel", {}); notification.showMessage("42", "Alice", "Test channel", {});
QVERIFY(notification.isVisible()); QVERIFY(notification.isVisible());
QVERIFY(!notification.parentWidget()); // ОС не должна скрывать уведомление вместе с главным окном.
QCOMPARE(QApplication::activeWindow(), &otherWindow); QCOMPARE(QApplication::activeWindow(), &otherWindow);
hiddenParent.showMinimized();
QVERIFY(notification.isVisible());
QTest::qWait(10200); QTest::qWait(10200);
QVERIFY(notification.isVisible()); // Без активности автоматического таймера нет. QVERIFY(notification.isVisible()); // Без активности автоматического таймера нет.
QElapsedTimer elapsed; QElapsedTimer elapsed;
@ -144,7 +156,8 @@ private slots:
#ifdef UTUN_TEST_ACTIVITY_DBUS #ifdef UTUN_TEST_ACTIVITY_DBUS
void gnomeIdleAndStaleReplies() { void gnomeIdleAndStaleReplies() {
auto bus = QDBusConnection::sessionBus(); // Разные соединения исключают прямой вызов внутри Qt, чтобы задержка действительно прошла через D-Bus.
auto bus = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "notification-test-service");
QVERIFY(bus.registerService("org.gnome.Mutter.IdleMonitor")); QVERIFY(bus.registerService("org.gnome.Mutter.IdleMonitor"));
FakeGnomeIdle idle; FakeGnomeIdle idle;
QVERIFY(bus.registerObject("/org/gnome/Mutter/IdleMonitor/Core", &idle, QDBusConnection::ExportAllSlots)); QVERIFY(bus.registerObject("/org/gnome/Mutter/IdleMonitor/Core", &idle, QDBusConnection::ExportAllSlots));

Loading…
Cancel
Save