diff --git a/tools/chatgui/CMakeLists.txt b/tools/chatgui/CMakeLists.txt index 098154c1..451bd52f 100644 --- a/tools/chatgui/CMakeLists.txt +++ b/tools/chatgui/CMakeLists.txt @@ -196,6 +196,14 @@ if(QT_PACKAGE STREQUAL "Qt6" AND FFMPEG_FOUND) endif() endif() file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/chatgui_capture_enabled.txt" "${GUI_CAPTURE_ENABLED}\n") +if(GUI_CAPTURE_ENABLED AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + find_package(Qt6 COMPONENTS DBus REQUIRED) + pkg_check_modules(STREAM_PIPEWIRE REQUIRED IMPORTED_TARGET libpipewire-0.3>=0.3.44) + add_library(chatgui_portal_capture STATIC src/stream_portal_capture.cpp) + target_link_libraries(chatgui_portal_capture PUBLIC Qt6::Multimedia Qt6::DBus PRIVATE utun PkgConfig::STREAM_PIPEWIRE) + target_compile_definitions(chatgui_stream_publish PUBLIC UTUN_STREAM_PORTAL) + target_link_libraries(chatgui_stream_publish PRIVATE chatgui_portal_capture) +endif() if(GUI_CAPTURE_ENABLED AND UNIX AND NOT APPLE AND QT_FEATURE_xcb) find_package(X11 REQUIRED COMPONENTS Xfixes) target_sources(chatgui_stream_publish PRIVATE src/stream_screen_cursor.cpp) diff --git a/tools/chatgui/src/stream_publish_engine.cpp b/tools/chatgui/src/stream_publish_engine.cpp index 183f6804..ebf8950d 100644 --- a/tools/chatgui/src/stream_publish_engine.cpp +++ b/tools/chatgui/src/stream_publish_engine.cpp @@ -34,6 +34,9 @@ extern "C" { #ifdef UTUN_STREAM_X11_CURSOR #include "stream_screen_cursor.h" #endif +#ifdef UTUN_STREAM_PORTAL +#include "stream_portal_capture.h" +#endif namespace { int64_t monotonicUs() { return std::chrono::duration_cast( @@ -77,6 +80,9 @@ struct StreamPublishEngine::Impl { std::unique_ptr sink; std::unique_ptr camera; std::unique_ptr screen; +#ifdef UTUN_STREAM_PORTAL + std::unique_ptr portal; +#endif std::unique_ptr screenGrabTimer; #ifdef UTUN_STREAM_X11_CURSOR std::unique_ptr cursor; @@ -148,6 +154,9 @@ QVariant StreamPublishEngine::previewFrame() const { } QList StreamPublishEngine::codecs() const { std::lock_guard guard(m->lock); return m->codecs; } bool StreamPublishEngine::cursorSupported(const StreamVideoSource& source) { +#ifdef UTUN_STREAM_PORTAL + if (source.kind == StreamVideoSource::Screen && source.id == "portal") return true; +#endif #ifdef UTUN_STREAM_X11_CURSOR return source.kind == StreamVideoSource::Screen && source.screen && source.id != "portal" && QGuiApplication::platformName() == "xcb"; #else @@ -267,6 +276,14 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) { if (screen == config.source.screen && screenId(screen) == config.source.id) { selected = screen; break; } if (!selected) { DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop screen disappeared"); return false; } } +#ifdef UTUN_STREAM_PORTAL + if (config.source.id == "portal") { + m->portal = std::make_unique(); + connect(m->portal.get(), &StreamPortalCapture::frameReady, m->sink.get(), &QVideoSink::setVideoFrame); + connect(m->portal.get(), &StreamPortalCapture::errorOccurred, this, failed, Qt::QueuedConnection); + m->portal->start(config.showCursor); + } else +#endif // Qt X11 screen capture ищет root по имени и путает мониторы; QScreen захватывает именно выбранный экран. if (selected && QGuiApplication::platformName() == "xcb") { #ifdef UTUN_STREAM_X11_CURSOR @@ -340,6 +357,9 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) { void StreamPublishEngine::closeSource() { #ifdef HAVE_STREAM_CAPTURE m->screenGrabTimer.reset(); +#ifdef UTUN_STREAM_PORTAL + m->portal.reset(); +#endif #ifdef UTUN_STREAM_X11_CURSOR m->cursor.reset(); #endif @@ -388,6 +408,10 @@ bool StreamPublishEngine::start(uint64_t group, const StreamPublishConfig& confi bool StreamPublishEngine::reconfigure(const StreamPublishConfig& config) { if (!m->running) return false; StreamPublishConfig previous = this->config(); + if (previous.source.id == "portal" && config.source.sameSource(previous.source) && config.showCursor != previous.showCursor) { + DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "Wayland capture cursor mode cannot change during a portal session"); + emit errorOccurred(text("Change cursor visibility before starting screen sharing")); return false; + } if (config.audio != previous.audio || config.microphone != previous.microphone) { DEBUG_WARN(DEBUG_CATEGORY_STREAM, "desktop microphone selection changed during live publication"); emit errorOccurred(text("Change the microphone before starting the stream")); return false; diff --git a/tools/chatgui/src/stream_publish_window.cpp b/tools/chatgui/src/stream_publish_window.cpp index f85633cc..9693fb5b 100644 --- a/tools/chatgui/src/stream_publish_window.cpp +++ b/tools/chatgui/src/stream_publish_window.cpp @@ -302,5 +302,7 @@ void StreamPublishWindow::synchronize() { m_cursor->setChecked(config.showCursor); } m_cursor->setVisible(StreamPublishEngine::cursorSupported(selection().source)); - m_cursor->setEnabled(!active || m_engine->running()); + bool portal = selection().source.id == "portal"; + m_cursor->setEnabled(!active || (m_engine->running() && !portal)); + m_cursor->setToolTip(portal ? text("Change cursor visibility before starting screen sharing") : QString()); }