feat: Migrate Wayland POC to Qt6 and QScreenCapture

This commit is contained in:
Tobias J. Endres 2025-08-14 19:43:28 +02:00
parent ab4bb5a7ec
commit 7dbc11afe1
2 changed files with 31 additions and 98 deletions

View File

@ -9,12 +9,12 @@ set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core Gui WaylandClient REQUIRED) find_package(Qt6 COMPONENTS Core Gui WaylandClient Multimedia Widgets MultimediaWidgets REQUIRED)
# Add the Wayland POC executable # Add the Wayland POC executable
add_executable(wayland_poc "wayland_poc.cpp") add_executable(wayland_poc "wayland_poc.cpp")
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner++) find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
set(WAYLAND_PROTOCOLS_DIR "${CMAKE_CURRENT_BINARY_DIR}/wayland_protocols") set(WAYLAND_PROTOCOLS_DIR "${CMAKE_CURRENT_BINARY_DIR}/wayland_protocols")
file(MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR}) file(MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR})
@ -38,11 +38,20 @@ add_custom_target(generate_wayland_protocols ALL
${WAYLAND_PROTOCOLS_DIR}/zkde-screencast-unstable-v1-client-protocol.h ${WAYLAND_PROTOCOLS_DIR}/zkde-screencast-unstable-v1-client-protocol.h
) )
target_include_directories(wayland_poc PRIVATE ${WAYLAND_PROTOCOLS_DIR}) find_package(PkgConfig REQUIRED)
pkg_check_modules(PIPEWIRE REQUIRED libpipewire-0.3)
target_include_directories(wayland_poc PRIVATE ${WAYLAND_PROTOCOLS_DIR} ${PIPEWIRE_INCLUDE_DIRS})
add_dependencies(wayland_poc generate_wayland_protocols) add_dependencies(wayland_poc generate_wayland_protocols)
target_link_libraries(wayland_poc target_link_libraries(wayland_poc
Qt5::Core Qt6::Core
Qt5::Gui Qt6::Gui
Qt5::WaylandClient Qt6::WaylandClient
Qt6::Multimedia
Qt6::Widgets
Qt6::MultimediaWidgets
${PIPEWIRE_LIBRARIES}
) )

View File

@ -1,99 +1,23 @@
#include <QCoreApplication> #include <QApplication>
#include <QDebug>
#include <QScreen> #include <QScreen>
#include <QGuiApplication> #include <QMediaCaptureSession>
#include <QtWaylandClient/QWaylandClientExtensionTemplate> #include <QScreenCapture>
#include <QNativeInterface> #include <QVideoWidget>
#include "qwayland-zkde-screencast-unstable-v1.h"
class ScreencastManager : public QObject, public QtWayland::zkde_screencast_unstable_v1
{
Q_OBJECT
public:
ScreencastManager(QObject *parent = nullptr)
: QObject(parent)
, QtWayland::zkde_screencast_unstable_v1(5) // Version 5 is required for stream_output
{
if (!isInitialized()) {
qCritical() << "Failed to initialize zkde_screencast_unstable_v1. Make sure KWin is running and supports this protocol.";
QCoreApplication::quit();
return;
}
qDebug() << "zkde_screencast_unstable_v1 initialized.";
// Request a screencast of the primary screen
QScreen *screen = QGuiApplication::primaryScreen();
if (!screen) {
qCritical() << "No primary screen found.";
QCoreApplication::quit();
return;
}
if (auto *waylandScreen = qobject_cast<QNativeInterface::QWaylandScreen *>(screen->nativeInterface())) {
wl_output *output = waylandScreen->output();
if (!output) {
qCritical() << "Failed to get native Wayland output from QWaylandScreen.";
QCoreApplication::quit();
return;
}
// Create a stream for the output
// The 'mode' parameter (last argument) can be Hidden = 1, Embedded = 2, Metadata = 4
// We'll use Metadata for now.
stream_output(output, 4); // 4 for Metadata cursor mode
} else {
qCritical() << "Failed to get Wayland screen interface from QScreen.";
QCoreApplication::quit();
return;
}
}
protected:
// Implement the generated Wayland protocol callbacks
void zkde_screencast_unstable_v1_stream_created(zkde_screencast_stream_unstable_v1 *stream) override
{
qDebug() << "Screencast stream created!";
// Connect to the stream's signals to get the PipeWire node ID
connect(static_cast<QtWayland::zkde_screencast_stream_unstable_v1 *>(stream), &QtWayland::zkde_screencast_stream_unstable_v1::created, this, &ScreencastManager::onStreamCreated);
connect(static_cast<QtWayland::zkde_screencast_stream_unstable_v1 *>(stream), &QtWayland::zkde_screencast_stream_unstable_v1::closed, this, &ScreencastManager::onStreamClosed);
connect(static_cast<QtWayland::zkde_screencast_stream_unstable_v1 *>(stream), &QtWayland::zkde_screencast_stream_unstable_v1::failed, this, &ScreencastManager::onStreamFailed);
}
void zkde_screencast_unstable_v1_stream_destroyed(zkde_screencast_stream_unstable_v1 *stream) override
{
qDebug() << "Screencast stream destroyed.";
}
private slots:
void onStreamCreated(quint32 node_id)
{
qDebug() << "PipeWire node ID:" << node_id;
// Here you would typically use the node_id to connect to PipeWire and start processing frames.
QCoreApplication::quit(); // For POC, quit after getting the node ID
}
void onStreamClosed()
{
qDebug() << "Screencast stream closed.";
QCoreApplication::quit();
}
void onStreamFailed(const QString &error)
{
qCritical() << "Screencast stream failed:" << error;
QCoreApplication::quit();
}
};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication app(argc, argv); QApplication app(argc, argv);
qDebug() << "Starting Wayland POC..."; QVideoWidget videoWidget;
videoWidget.show();
ScreencastManager manager; QMediaCaptureSession captureSession;
QScreenCapture *screenCapture = new QScreenCapture(&app);
captureSession.setScreenCapture(screenCapture);
captureSession.setVideoOutput(&videoWidget);
screenCapture->start();
return app.exec(); return app.exec();
} }
#include "wayland_poc.moc"