diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 692cd848..cc875c47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ target_link_libraries(treeland shortcut wallpaper-color window-management + virtual-output ) target_compile_definitions(treeland diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 816e5df3..91de6627 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -48,3 +48,4 @@ add_subdirectory("personalization") add_subdirectory("shortcut") add_subdirectory("wallpaper-color") add_subdirectory("window-management") +add_subdirectory("virtual-output") diff --git a/src/modules/virtual-output/CMakeLists.txt b/src/modules/virtual-output/CMakeLists.txt new file mode 100644 index 00000000..b29ca934 --- /dev/null +++ b/src/modules/virtual-output/CMakeLists.txt @@ -0,0 +1,40 @@ +set(MODULE_NAME virtual-output) + +ws_generate_local(server ${CMAKE_CURRENT_SOURCE_DIR}/protocols/treeland-virtual-output-manager-v1.xml server-protocol) + +pkg_search_module(WLROOTS REQUIRED IMPORTED_TARGET wlroots) + +qt_add_library(${MODULE_NAME} STATIC) + +target_sources(${MODULE_NAME} PUBLIC +FILE_SET HEADERS +FILES + virtualoutputmanager.h + impl/virtual_output_manager_impl.h +) + +target_sources(${MODULE_NAME} PRIVATE + virtualoutputmanager.cpp + impl/virtual_output_manager_impl.cpp + server-protocol.c +) + +target_include_directories(${MODULE_NAME} PUBLIC + $ + $ +) + +target_compile_definitions(${MODULE_NAME} + PRIVATE + WLR_USE_UNSTABLE +) + +target_link_libraries(${MODULE_NAME} + PUBLIC + utils + PkgConfig::WLROOTS + Waylib::WaylibServer + Qt${QT_MAJOR_VERSION}::Core + Qt${QT_MAJOR_VERSION}::Gui + Qt${QT_MAJOR_VERSION}::Quick +) diff --git a/src/modules/virtual-output/impl/virtual_output_manager_impl.cpp b/src/modules/virtual-output/impl/virtual_output_manager_impl.cpp new file mode 100644 index 00000000..396a1262 --- /dev/null +++ b/src/modules/virtual-output/impl/virtual_output_manager_impl.cpp @@ -0,0 +1,243 @@ +// Copyright (C) 2024 Lu YaNing . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "virtual_output_manager_impl.h" + +#include +#include + +// extern "C" { +// #define static +// // #include +// #include +// // #include +// // #include +// #undef static +// } + +#include + +#define TREELAND_VIRTUAL_OUTPUT_MANAGER_V1_VERSION 1 + +using QW_NAMESPACE::QWDisplay; + +static treeland_virtual_output_manager_v1 *virtual_output_manager_from_resource(wl_resource *resource); +static void virtual_output_manager_bind(wl_client *client, void *data, uint32_t version, uint32_t id); + +static void virtual_output_manager_handle_create_virtual_output([[maybe_unused]]struct wl_client *client, + struct wl_resource *manager_resource, + uint32_t id, + const char *name, + struct wl_array *outputs); + +static void virtual_output_manager_handle_get_virtual_output_list([[maybe_unused]]struct wl_client *client, struct wl_resource *resource); + +static void virtual_output_manager_handle_get_virtual_output([[maybe_unused]]struct wl_client *client, + struct wl_resource *resource, + const char *name, + uint32_t id); + +static void virtual_output_handle_destroy([[maybe_unused]]struct wl_client *client, + struct wl_resource *resource); + + +static void virtual_output_handle_destroy([[maybe_unused]]struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + + +static const struct virtual_output_v1_interface virtual_output_impl { + .destroy = virtual_output_handle_destroy, +}; + + +static const struct virtual_output_manager_v1_interface virtual_output_manager_impl { + .create_virtual_output = virtual_output_manager_handle_create_virtual_output, + .get_virtual_output_list = virtual_output_manager_handle_get_virtual_output_list, + .get_virtual_output = virtual_output_manager_handle_get_virtual_output, +}; + +static void virtual_output_resource_destroy(struct wl_resource *resource) +{ + wl_list_remove(wl_resource_get_link(resource)); +} + +static void virtual_output_manager_resource_destroy(struct wl_resource *resource) +{ + wl_list_remove(wl_resource_get_link(resource)); +} + +static struct treeland_virtual_output_v1 *treeland_virtual_output_from_resource(wl_resource *resource) +{ + assert(wl_resource_instance_of(resource, + &virtual_output_v1_interface, + &virtual_output_impl)); + auto *manager = static_cast(wl_resource_get_user_data(resource)); + assert(manager != nullptr); + return manager; +} + +static treeland_virtual_output_manager_v1 *virtual_output_manager_from_resource(wl_resource *resource) +{ + assert(wl_resource_instance_of(resource, + &virtual_output_manager_v1_interface, + &virtual_output_manager_impl)); + auto *manager = static_cast(wl_resource_get_user_data(resource)); + assert(manager != nullptr); + return manager; +} + +void wlarrayToStringList(const wl_array* wl_array, QStringList& stringList) +{ + char* dataStart = static_cast(wl_array->data); + char* currentPos = dataStart; + + while (*currentPos != '\0') { + QString str = QString::fromUtf8(currentPos); + stringList << str; + currentPos += str.toUtf8().length() + 1; + } +} + + +static void virtual_output_manager_handle_create_virtual_output([[maybe_unused]]struct wl_client *client, + struct wl_resource *manager_resource, + uint32_t id, + const char *name, + struct wl_array *outputs) +{ + auto *manager = virtual_output_manager_from_resource(manager_resource); + + auto *virtual_output = new treeland_virtual_output_v1; + if (virtual_output == nullptr) { + wl_resource_post_no_memory(manager_resource); + return; + } + + uint32_t version = wl_resource_get_version(manager_resource); + struct wl_resource *resource = + wl_resource_create(client, &virtual_output_v1_interface, version, id); + if (resource == nullptr) { + delete virtual_output; + wl_resource_post_no_memory(manager_resource); + return; + } + + wl_resource_set_implementation(resource, + &virtual_output_impl, + virtual_output, + virtual_output_resource_destroy); + wl_resource_set_user_data(resource, virtual_output); + + virtual_output->manager = manager; + virtual_output->resource = resource; + virtual_output->name = name; + virtual_output->screen_outputs = outputs; + + wlarrayToStringList(outputs,virtual_output->outputList); + + manager->virtual_output.append(virtual_output); + QObject::connect(virtual_output, &treeland_virtual_output_v1::beforeDestroy, manager, [manager, virtual_output]() { + manager->virtual_output.removeOne(virtual_output); + }); + + virtual_output->send_outputs(virtual_output->name, outputs); + Q_EMIT virtual_output->manager->virtualOutputCreated(virtual_output); +} + +static void virtual_output_manager_handle_get_virtual_output_list([[maybe_unused]]struct wl_client *client, struct wl_resource *resource) +{ + auto *manager = virtual_output_manager_from_resource(resource); + + wl_array arr; + wl_array_init(&arr); + for(int i = 0; i < manager->virtual_output.size(); ++i) { + treeland_virtual_output_v1 *virtual_output = manager->virtual_output.at(i); + char *dest = static_cast(wl_array_add(&arr, virtual_output->name.length() + 1)); + strncpy(dest, virtual_output->name.toLatin1().data(), static_cast(virtual_output->name.length())); + } + + virtual_output_manager_v1_send_virtual_output_list(resource,&arr); +} + +static void virtual_output_manager_handle_get_virtual_output([[maybe_unused]]struct wl_client *client, + struct wl_resource *resource, + const char *name, + uint32_t id) +{ + auto *manager = virtual_output_manager_from_resource(resource); + for(int i = 0; i < manager->virtual_output.size(); ++i) { + treeland_virtual_output_v1 *virtual_output = manager->virtual_output.at(i); + if (virtual_output->name == name) { + virtual_output->send_outputs(name, virtual_output->screen_outputs); + } + } +} + +void treeland_virtual_output_v1::send_outputs(QString name, struct wl_array *outputs) +{ + virtual_output_v1_send_outputs(resource, name.toUtf8().data(), outputs); +} + +void treeland_virtual_output_v1::send_error(uint32_t code, const char *message) +{ + virtual_output_v1_send_error(resource, code, message); +} + +treeland_virtual_output_v1::~treeland_virtual_output_v1() +{ + Q_EMIT beforeDestroy(); + if (resource) + wl_resource_set_user_data(resource,nullptr); +} + +treeland_virtual_output_manager_v1::~treeland_virtual_output_manager_v1() +{ + Q_EMIT beforeDestroy(); + if (global) + wl_global_destroy(global); +} + +static void virtual_output_manager_bind(wl_client *client, void *data, uint32_t version, uint32_t id) +{ + auto *manager = static_cast(data); + + struct wl_resource *resource = + wl_resource_create(client, &virtual_output_manager_v1_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, + &virtual_output_manager_impl, + manager, + virtual_output_manager_resource_destroy); + wl_list_insert(&manager->resources, wl_resource_get_link(resource)); +} + +treeland_virtual_output_manager_v1 *treeland_virtual_output_manager_v1::create(QWDisplay *display) +{ + auto *manager = new treeland_virtual_output_manager_v1; + if (!manager) + return nullptr; + + manager->event_loop = wl_display_get_event_loop(display->handle()); + manager->global = wl_global_create(display->handle(), + &virtual_output_manager_v1_interface, + TREELAND_VIRTUAL_OUTPUT_MANAGER_V1_VERSION, + manager, + virtual_output_manager_bind); + if (!manager->global) { + delete manager; + return nullptr; + } + + wl_list_init(&manager->resources); + + connect(display, &QWDisplay::beforeDestroy, manager, [manager] { delete manager; }); + + return manager; +} diff --git a/src/modules/virtual-output/impl/virtual_output_manager_impl.h b/src/modules/virtual-output/impl/virtual_output_manager_impl.h new file mode 100644 index 00000000..21424237 --- /dev/null +++ b/src/modules/virtual-output/impl/virtual_output_manager_impl.h @@ -0,0 +1,55 @@ +// Copyright (C) 2024 Lu YaNing . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include "server-protocol.h" +#include +#include +#include +#include + +#include +#include + +struct treeland_virtual_output_v1; + +struct treeland_virtual_output_manager_v1 : public QObject +{ + Q_OBJECT +public: + ~treeland_virtual_output_manager_v1(); + + wl_global *global{ nullptr }; + wl_list resources; + wl_event_loop *event_loop{ nullptr }; + QList virtual_output; + + static treeland_virtual_output_manager_v1 *create(QW_NAMESPACE::QWDisplay *display); + +Q_SIGNALS: + void virtualOutputCreated(treeland_virtual_output_v1 *virtual_output); + void beforeDestroy(); +}; + +struct treeland_virtual_output_v1 : public QObject +{ + Q_OBJECT +public: + ~treeland_virtual_output_v1(); + treeland_virtual_output_manager_v1 *manager{ nullptr }; + wl_resource *resource{ nullptr }; + QString name; + struct wl_array *screen_outputs; + + QStringList outputList; + // wl_list wl_outputs; + + QList wlr_outputs_list; + + void send_outputs(QString name, struct wl_array *outputs); + void send_error(uint32_t code, const char *message); // tode: send err code and message + +Q_SIGNALS: + void beforeDestroy(); +}; diff --git a/src/modules/virtual-output/protocols/treeland-virtual-output-manager-v1.xml b/src/modules/virtual-output/protocols/treeland-virtual-output-manager-v1.xml new file mode 100644 index 00000000..3220bc73 --- /dev/null +++ b/src/modules/virtual-output/protocols/treeland-virtual-output-manager-v1.xml @@ -0,0 +1,82 @@ + + + . + SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + ]]> + + + This interface is a manager that allows the creation of copied output. + + + + Create virtual output that can be used when setting screen copy mode for use + on multiple screens. Virtual outputs are created to mirror multiple wl_output + outputs. + + The element of the array is the name of the screen. + + The first element of the array outputs is the screen to be copied, and + the subsequent elements are the screens to be mirrored. + + The client calling this interface will not generate an additional wl_output + object on the client. + + + + + + + + Gets a list of virtual output names. + + + + + Sends a list of virtual output names to the client. + + + + + + The client obtains the corresponding virtual_output_v1 object + through the virtual output name. + + + + + + + + A virtual_output_v1 represents a set virtual screen output object. + + + + This event is sent to the client when any screen in the array changes. + + The element of the array is the name of the screen. + + The first element of the array outputs is the screen to be copied, and + the subsequent elements are the screens to be mirrored. + + When the primary screen (the screen being copied) is removed, a successor + is selected from the queue as the primary screen, and the queue information + is updated. + + + + + + + Send invalid replication output signal to the client. + + + + + + + Destroy the output. + + + + diff --git a/src/modules/virtual-output/virtualoutputmanager.cpp b/src/modules/virtual-output/virtualoutputmanager.cpp new file mode 100644 index 00000000..1a585850 --- /dev/null +++ b/src/modules/virtual-output/virtualoutputmanager.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2024 Lu YaNing . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "impl/virtual_output_manager_impl.h" + +#include "virtualoutputmanager.h" + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +extern "C" { +#include +} + +static VirtualOutputV1 *VIRTUAL_OUTPUT = nullptr; + + + +VirtualOutputManagerAttached::VirtualOutputManagerAttached( + WOutputViewport *outputviewport, VirtualOutputV1 *manager) + : QObject(outputviewport) + , m_manager(manager) +{ + + m_viewport = outputviewport; + m_manager->m_viewports_list.append(outputviewport); + + connect(m_manager, + &VirtualOutputV1::requestCreateVirtualOutput, + this, + [this](QString name, QStringList outputList) { + + if(outputList.at(1) == m_viewport->output()->name()) { + m_viewport = m_manager->m_viewports_list.at(0); + + qWarning() << "------------------------------" << name; + Q_EMIT outputViewportChanged(); + } + + }); +} + +VirtualOutputV1::VirtualOutputV1(QObject *parent) +{ + if (VIRTUAL_OUTPUT) { + qFatal("There are multiple instances of VirtualOutputV1"); + } + + VIRTUAL_OUTPUT = this; +} + +void VirtualOutputV1::onVirtualOutputCreated(treeland_virtual_output_v1 *virtual_output) +{ + m_virtualOutput.push_back(virtual_output); + connect(virtual_output, &treeland_virtual_output_v1::beforeDestroy, this, [this, virtual_output] { + std::erase_if(m_virtualOutput, [virtual_output](auto *p) { + return p == virtual_output; + }); + }); + + //virtual_output->outputList.count() >= 2; virtual_output->outputList.at(i) must be in outputviewport->output() + if(virtual_output->name.isEmpty() && !virtual_output->screen_outputs) + return; // todo: send error to client + + Q_EMIT requestCreateVirtualOutput(virtual_output->name, virtual_output->outputList); +} + +VirtualOutputManagerAttached *VirtualOutputV1::Attach(WOutputViewport *outputviewport) +{ + if (outputviewport) { + return new VirtualOutputManagerAttached(outputviewport, + VIRTUAL_OUTPUT); + } + + return nullptr; +} + +void VirtualOutputV1::setVirtualOutput(QString name, QStringList outputList) +{ + if(name.isEmpty()) { + return; + } + + Q_EMIT requestCreateVirtualOutput(name, outputList); +} + +void VirtualOutputV1::create(WServer *server) +{ + m_manager = treeland_virtual_output_manager_v1::create(server->handle()); + connect(m_manager, + &treeland_virtual_output_manager_v1::virtualOutputCreated, + this, + &VirtualOutputV1::onVirtualOutputCreated); +} + +void VirtualOutputV1::destroy(WServer *server) { } + +wl_global *VirtualOutputV1::global() const +{ + return m_manager->global; +} diff --git a/src/modules/virtual-output/virtualoutputmanager.h b/src/modules/virtual-output/virtualoutputmanager.h new file mode 100644 index 00000000..f14022cf --- /dev/null +++ b/src/modules/virtual-output/virtualoutputmanager.h @@ -0,0 +1,74 @@ +// Copyright (C) 2024 Lu YaNing . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include +#include +#include +#include +#include + +#include + +struct treeland_virtual_output_v1; +struct treeland_virtual_output_manager_v1; +QW_USE_NAMESPACE +WAYLIB_SERVER_USE_NAMESPACE + +class VirtualOutputV1; + +class VirtualOutputManagerAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(WOutputViewport *outputViewport READ outputViewport NOTIFY outputViewportChanged FINAL) + QML_ANONYMOUS + +public: + Q_INVOKABLE WOutputViewport *outputViewport() const { + + // qDebug() << "WOutputViewport *outputViewport() ----- " << m_viewport->output()->name(); + + return m_viewport; }; + + // VirtualOutputManagerAttached(WOutput *output, VirtualOutputV1 *manager); + VirtualOutputManagerAttached(WOutputViewport *outputviewport, VirtualOutputV1 *manager); + +Q_SIGNALS: + + void outputViewportChanged(); +private: + WOutput *m_output; + VirtualOutputV1 *m_manager; + WOutputViewport *m_viewport; + WOutputViewport *m_viewport1; +}; + +class VirtualOutputV1 : public QObject, public WServerInterface +{ + Q_OBJECT + +public: + explicit VirtualOutputV1(QObject *parent = nullptr); + + Q_INVOKABLE VirtualOutputManagerAttached *Attach(WOutputViewport *outputviewport); + void setVirtualOutput(QString name, QStringList outputList); + + + QList m_viewports_list; + +Q_SIGNALS: + + void requestCreateVirtualOutput(QString name, QStringList outputList); + +private Q_SLOTS: + void onVirtualOutputCreated(treeland_virtual_output_v1 *virtual_output); + +private: + void create(WServer *server) override; + void destroy(WServer *server) override; + wl_global *global() const override; + + std::vector m_virtualOutput; + treeland_virtual_output_manager_v1 *m_manager{ nullptr }; +}; diff --git a/src/qml/OutputDelegate.qml b/src/qml/OutputDelegate.qml index a2daeb9b..46acc714 100644 --- a/src/qml/OutputDelegate.qml +++ b/src/qml/OutputDelegate.qml @@ -11,6 +11,7 @@ OutputItem { required property WaylandOutput waylandOutput property OutputViewport onscreenViewport: outputViewport property Cursor waylandCursor + property var attachViewport: VirtualOutputV1.Attach(outputViewport).outputViewport output: waylandOutput devicePixelRatio: waylandOutput.scale @@ -47,6 +48,11 @@ OutputItem { devicePixelRatio: parent.devicePixelRatio anchors.centerIn: parent + TextureProxy { + sourceItem: attachViewport + anchors.fill: parent + } + RotationAnimation { id: rotationAnimator @@ -125,6 +131,8 @@ OutputItem { TextureProxy { sourceItem: outputViewport + // sourceItem: virtualOutputV1.outputViewport + // sourceItem: attachViewport anchors.fill: parent } diff --git a/src/treeland.cpp b/src/treeland.cpp index fbc8d1d5..2b5e31f1 100644 --- a/src/treeland.cpp +++ b/src/treeland.cpp @@ -17,6 +17,7 @@ #include "shortcutmanager.h" #include "wallpapercolor.h" #include "windowmanagement.h" +#include "virtualoutputmanager.h" #include #include @@ -283,6 +284,11 @@ void TreeLand::setup() 0, "WindowManagementV1", m_server->attach()); + qmlRegisterSingletonInstance("TreeLand.Protocols", + 1, + 0, + "VirtualOutputV1", + m_server->attach()); m_engine->loadFromModule("TreeLand", "Main"); diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index 428a4c02..4e516bdb 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -5,6 +5,7 @@ #include "../modules/foreign-toplevel/foreigntoplevelmanagerv1.h" #include "../modules/primary-output/outputmanagement.h" +#include "../modules/virtual-output/virtualoutputmanager.h" #include #include @@ -326,6 +327,11 @@ void Helper::initProtocols(WOutputRenderWindow *window) "PrimaryOutputV1"); Q_ASSERT(primaryOutput); + VirtualOutputV1 *virtualOutputV1 = + engine->singletonInstance("TreeLand.Protocols", + "VirtualOutputV1"); + Q_ASSERT(virtualOutputV1); + primaryOutput->newOutput(output); outputManager->newOutput(output); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index abfbcd19..4d55d28d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(test_wallpaper_color) add_subdirectory(test_show_desktop) add_subdirectory(test_window_crusor) add_subdirectory(test_xdgport_wallpaper) +add_subdirectory(test_virtual_output) diff --git a/tests/test_virtual_output/CMakeLists.txt b/tests/test_virtual_output/CMakeLists.txt new file mode 100644 index 00000000..abfc1a24 --- /dev/null +++ b/tests/test_virtual_output/CMakeLists.txt @@ -0,0 +1,19 @@ +find_package(Qt6 REQUIRED COMPONENTS WaylandClient Widgets) + +qt_add_executable(test_virtual_output + main.cpp +) + +qt_generate_wayland_protocol_client_sources(test_virtual_output + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/modules/virtual-output/protocols/treeland-virtual-output-manager-v1.xml +) + +target_link_libraries(test_virtual_output + PRIVATE + Qt${QT_MAJOR_VERSION}::Gui + Qt${QT_MAJOR_VERSION}::Widgets + Qt::WaylandClient + Qt::GuiPrivate + Qt::WaylandClientPrivate +) diff --git a/tests/test_virtual_output/main.cpp b/tests/test_virtual_output/main.cpp new file mode 100644 index 00000000..18059e6c --- /dev/null +++ b/tests/test_virtual_output/main.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2024 Lu YaNing . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qwayland-treeland-virtual-output-manager-v1.h" + +#include +#include + +#include +#include +#include +#include + +class VirtualOutputManager : public QWaylandClientExtensionTemplate, + public QtWayland::virtual_output_manager_v1 +{ + Q_OBJECT +public: + explicit VirtualOutputManager(); + + void treeland_virtual_output_manager_v1_virtual_output_list(wl_array *names) + { + // qInfo() << "-------screens name----- " << state; + } +}; + +VirtualOutputManager::VirtualOutputManager() + : QWaylandClientExtensionTemplate(1) +{ +} + +class VirtualOutput : public QWaylandClientExtensionTemplate, + public QtWayland::virtual_output_v1 +{ + Q_OBJECT +public: + explicit VirtualOutput(struct ::virtual_output_v1 *object); + + void treeland_virtual_output_v1_outputs(const QString &name, wl_array *outputs){ + qInfo() << "-------Screen group name---- " << name; + } + + void treeland_virtual_output_v1_error(uint32_t code, const QString &message){ + + qInfo() << "error code:"<(1) + , QtWayland::virtual_output_v1(object) +{ +} + +int main(int argc, char *argv[]) +{ + qputenv("QT_QPA_PLATFORM", "wayland"); + QApplication app(argc, argv); + VirtualOutputManager manager; + + QObject::connect(&manager, &VirtualOutputManager::activeChanged, &manager, [&manager] { + if (manager.isActive()) { + QWidget *widget = new QWidget; + widget->setAttribute(Qt::WA_TranslucentBackground); + widget->resize(640, 480); + + widget->show(); + + QWindow *window = widget->windowHandle(); + + if (window && window->handle()) { + QtWaylandClient::QWaylandWindow *waylandWindow = + static_cast(window->handle()); + + qInfo() << "--------waylandWindow->waylandScreen()->name()---------" << waylandWindow->waylandScreen()->name(); + + struct wl_output *output = waylandWindow->waylandScreen()->output(); + + QList screens = waylandWindow->display()->screens(); + qInfo() << "--------screens---------" << screens.size(); + + // 实际使用需要判断主屏(被镜像的屏幕),将主屏放在wl_array的第一个,复制屏幕依次填充 + if (!screens.isEmpty()){ + QByteArray screenNmaeArray; + for(auto *screen : screens) { + QString address = screen->name(); + screenNmaeArray.append(address.toUtf8()); + screenNmaeArray.append('\0'); + } + screenNmaeArray.append('\0'); + + VirtualOutput *screen_output = + new VirtualOutput(manager.create_virtual_output("copyscreen1",screenNmaeArray)); //"copyscreen1": 客户端自定义分组名称 + + } + } + } + }); + + return app.exec(); +} + +#include "main.moc"