Browse Source

Verify notification desktop scope with a real window manager

master
evgeny 5 days ago
parent
commit
d62fae9e88
  1. 11
      tools/chatgui/CMakeLists.txt
  2. 6
      tools/chatgui/chatgui_doc.md
  3. 80
      tools/chatgui/tests/test_message_notification_x11.cpp

11
tools/chatgui/CMakeLists.txt

@ -313,7 +313,10 @@ enable_testing()
add_executable(test_message_notification tests/test_message_notification.cpp)
target_link_libraries(test_message_notification PRIVATE chatgui_notifications ${QT_TEST_LIB} pthread ${CMAKE_DL_LIBS})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_program(NOTIFICATION_DBUS_RUN_SESSION dbus-run-session REQUIRED)
find_program(NOTIFICATION_DBUS_RUN_SESSION NAMES dbus-run-session)
if(NOT NOTIFICATION_DBUS_RUN_SESSION)
message(FATAL_ERROR "dbus-run-session is required for the isolated notification test")
endif()
target_compile_definitions(test_message_notification PRIVATE UTUN_TEST_ACTIVITY_DBUS)
target_link_libraries(test_message_notification PRIVATE ${QT_DBUS})
add_test(NAME test_message_notification COMMAND ${NOTIFICATION_DBUS_RUN_SESSION} -- $<TARGET_FILE:test_message_notification>)
@ -327,6 +330,12 @@ target_link_libraries(test_message_events PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun
add_test(NAME test_message_events COMMAND test_message_events)
set_tests_properties(test_message_events PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 15)
# Ручной запуск с DISPLAY: проверяет применение desktop hints оконным менеджером, не меняя настройки рабочих столов.
if(TARGET X11::X11)
add_executable(test_message_notification_x11 tests/test_message_notification_x11.cpp)
target_link_libraries(test_message_notification_x11 PRIVATE chatgui_notifications ${QT_TEST_LIB} X11::X11 pthread ${CMAKE_DL_LIBS})
endif()
add_executable(test_file_drop tests/test_file_drop.cpp src/inputbar.cpp src/audiorecorder.cpp src/audio_device.cpp src/sound_manager.cpp
src/voicemessageencoder.cpp src/emojipanel.cpp src/emojitabbar.cpp src/emoji.cpp src/animtimer.cpp src/lottieicon.cpp
src/voice_audio_io.cpp transport/miniaudio_impl.c transport/audio_diagnostics.cpp)

6
tools/chatgui/chatgui_doc.md

@ -89,8 +89,14 @@ Wayland/XWayland в GNOME использует асинхронный `org.gnome
X11 idle time в Wayland-сессии не используется: он не гарантирует активность в других приложениях.
Если системный механизм недоступен, учитываются только события внутри ChatGUI; закрытие крестиком остаётся доступным.
При отсутствии координат трея выбирается угол доступной области экрана; нативный Wayland управляет позицией и порядком окон.
В X11/XWayland уведомление запрашивает показ на всех виртуальных рабочих столах через `_NET_WM_DESKTOP=0xffffffff`.
Подсказка выставляется перед первым показом и повторяется через EWMH при обновлении уже видимого окна.
Уведомление не является дочерним окном главного чата: сворачивание или рабочий стол главного окна не определяют его видимость.
На нативном Wayland поверхность пересоздаётся при новом сообщении, чтобы не сохранять прежний рабочий стол;
выбор текущего стола и возможность показа поверх других окон остаются политикой композитора.
Показ/скрытие и причины ограничений логируются в `general`; запуск отсчёта и первая активность — на уровне `debug`.
Проверка: `ctest --test-dir build -R 'test_message_(notification|events)' --output-on-failure`.
При доступном X11/XWayland: `./build/test_message_notification_x11` проверяет all-desktop hint после показа, обновления и скрытия.
**ChatView** (`src/chatview.h`) — QListView с фоновым изображением и drag-to-select. При движении >5px от точки нажатия стартует выделение сообщений. Ctrl+C копирует: для одного — выделенный текст, для нескольких — `[time] author: text`. Сигнал `hoveredIndexChanged` используется для активации анимаций эмодзи в MessageList.

80
tools/chatgui/tests/test_message_notification_x11.cpp

@ -0,0 +1,80 @@
/* Ручная проверка EWMH на настоящем X11/XWayland: настройки рабочих столов пользователя не меняются. */
#include "../src/message_notification.h"
#include "../../../lib/debug_config.h"
#include <QtTest>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
class NotificationDesktopTest : public QObject {
Q_OBJECT
Display* m_display = nullptr;
qint64 desktop(Window window, const char* property = "_NET_WM_DESKTOP") {
Atom type = None;
int format = 0;
unsigned long count = 0, remaining = 0;
unsigned char* data = nullptr;
const Atom atom = XInternAtom(m_display, property, False);
const int status = XGetWindowProperty(m_display, window, atom, 0, 1, False,
XA_CARDINAL, &type, &format, &count, &remaining, &data);
qint64 value = -1;
if (status == Success && type == XA_CARDINAL && format == 32 && count == 1 && data)
value = *reinterpret_cast<const unsigned long*>(data) & 0xffffffffUL;
if (data) XFree(data);
return value;
}
private slots:
void initTestCase() {
debug_config_init();
debug_set_level(DEBUG_LEVEL_DEBUG);
m_display = XOpenDisplay(nullptr);
QVERIFY(m_display);
}
void cleanupTestCase() { if (m_display) XCloseDisplay(m_display); }
void allDesktopsOnFirstShowUpdateAndReshow() {
MessageNotification notification;
notification.showMessage("42", "Alice", "Desktop test", {});
const Window window = Window(notification.winId());
QTRY_COMPARE_WITH_TIMEOUT(desktop(window), qint64(0xffffffffUL), 2000);
QVERIFY(!notification.parentWidget());
QVERIFY(notification.windowFlags() & Qt::WindowDoesNotAcceptFocus);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "notification desktop test: first show window=0x%lx desktop=all", window);
// Переносим только собственное тестовое окно на текущий стол, затем проверяем повторный запрос all.
const qint64 current = desktop(DefaultRootWindow(m_display), "_NET_CURRENT_DESKTOP");
QVERIFY(current >= 0);
XEvent event{};
event.xclient.type = ClientMessage;
event.xclient.window = window;
event.xclient.message_type = XInternAtom(m_display, "_NET_WM_DESKTOP", False);
event.xclient.format = 32;
event.xclient.data.l[0] = long(current);
event.xclient.data.l[1] = 1;
QVERIFY(XSendEvent(m_display, DefaultRootWindow(m_display), False,
SubstructureRedirectMask | SubstructureNotifyMask, &event));
XFlush(m_display);
QTRY_COMPARE_WITH_TIMEOUT(desktop(window), current, 2000);
notification.showMessage("dm:7", "Bob", "Desktop test", {});
QTRY_COMPARE_WITH_TIMEOUT(desktop(window), qint64(0xffffffffUL), 2000);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "notification desktop test: updated visible window desktop=all");
notification.dismiss("test-reshow");
QTest::qWait(50);
notification.showMessage("43", "Charlie", "Desktop test", {});
QTRY_COMPARE_WITH_TIMEOUT(desktop(Window(notification.winId())), qint64(0xffffffffUL), 2000);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "notification desktop test: withdrawn window shown again desktop=all");
notification.dismiss("test-complete");
}
};
int main(int argc, char** argv) {
if (qEnvironmentVariableIsEmpty("DISPLAY")) return 77;
qputenv("QT_QPA_PLATFORM", "xcb");
QApplication application(argc, argv);
NotificationDesktopTest test;
return QTest::qExec(&test, argc, argv);
}
#include "test_message_notification_x11.moc"
Loading…
Cancel
Save