-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement treeland_virtual_manager_v1 function
Implementing Virtual Output
- Loading branch information
Showing
14 changed files
with
749 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> | ||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> | ||
) | ||
|
||
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 | ||
) |
243 changes: 243 additions & 0 deletions
243
src/modules/virtual-output/impl/virtual_output_manager_impl.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
// Copyright (C) 2024 Lu YaNing <[email protected]>. | ||
// 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 <wayland-server-core.h> | ||
#include <cassert> | ||
|
||
// extern "C" { | ||
// #define static | ||
// // #include <wlr/types/wlr_compositor.h> | ||
// #include <wlr/types/wlr_output.h> | ||
// // #include <wlr/types/wlr_seat.h> | ||
// // #include <wlr/util/log.h> | ||
// #undef static | ||
// } | ||
|
||
#include <QDebug> | ||
|
||
#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<treeland_virtual_output_v1 *>(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<treeland_virtual_output_manager_v1 *>(wl_resource_get_user_data(resource)); | ||
assert(manager != nullptr); | ||
return manager; | ||
} | ||
|
||
void wlarrayToStringList(const wl_array* wl_array, QStringList& stringList) | ||
{ | ||
char* dataStart = static_cast<char*>(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<char *>(wl_array_add(&arr, virtual_output->name.length() + 1)); | ||
strncpy(dest, virtual_output->name.toLatin1().data(), static_cast<uint>(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<treeland_virtual_output_manager_v1 *>(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; | ||
} |
55 changes: 55 additions & 0 deletions
55
src/modules/virtual-output/impl/virtual_output_manager_impl.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (C) 2024 Lu YaNing <[email protected]>. | ||
// 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 <wayland-server-core.h> | ||
#include <qwsignalconnector.h> | ||
#include <qwdisplay.h> | ||
#include <QObject> | ||
|
||
#include <QList> | ||
#include <QString> | ||
|
||
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<treeland_virtual_output_v1 *> 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<struct wlr_output *> 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(); | ||
}; |
Oops, something went wrong.