Compare commits

..

No commits in common. "master" and "upstream/0.3.10" have entirely different histories.

14 changed files with 167 additions and 463 deletions

View File

@ -1,12 +1,11 @@
cmake_minimum_required(VERSION 3.19)
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
string(STRIP ${VER_RAW} VERSION)
set(VERSION 0.3.10)
project(
hyprwayland-scanner
DESCRIPTION "A hyprland version of wayland-scanner in and for C++"
VERSION ${VERSION})
project(hyprwayland-scanner
DESCRIPTION "A hyprland version of wayland-scanner in and for C++"
VERSION ${VERSION}
)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
@ -16,17 +15,18 @@ set(PREFIX ${CMAKE_INSTALL_PREFIX})
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring hyprwayland-scanner in Debug with CMake")
add_compile_definitions(HYPRLAND_DEBUG)
message(STATUS "Configuring hyprwayland-scanner in Debug with CMake")
add_compile_definitions(HYPRLAND_DEBUG)
else()
add_compile_options(-O3)
message(STATUS "Configuring hyprwayland-scanner in Release with CMake")
add_compile_options(-O3)
message(STATUS "Configuring hyprwayland-scanner in Release with CMake")
endif()
# configure
set(CMAKE_CXX_STANDARD 23)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value
-Wno-missing-field-initializers -Wno-narrowing)
-Wno-missing-field-initializers -Wno-narrowing)
add_compile_definitions(SCANNER_VERSION="${VERSION}")
@ -41,22 +41,25 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET pugixml)
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
add_executable(hyprwayland-scanner ${SRCFILES})
target_link_libraries(hyprwayland-scanner PRIVATE rt Threads::Threads
PkgConfig::deps)
target_link_libraries(hyprwayland-scanner PRIVATE rt Threads::Threads PkgConfig::deps)
configure_package_config_file(
hyprwayland-scanner-config.cmake.in hyprwayland-scanner-config.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/hyprwayland-scanner"
PATH_VARS CMAKE_INSTALL_BINDIR)
hyprwayland-scanner-config.cmake.in
hyprwayland-scanner-config.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/hyprwayland-scanner"
PATH_VARS CMAKE_INSTALL_BINDIR
)
write_basic_package_version_file(
"hyprwayland-scanner-config-version.cmake"
VERSION "${VERSION}"
COMPATIBILITY AnyNewerVersion)
"hyprwayland-scanner-config-version.cmake"
VERSION "${VERSION}"
COMPATIBILITY AnyNewerVersion
)
# Installation
install(TARGETS hyprwayland-scanner)
install(FILES ${CMAKE_BINARY_DIR}/hyprwayland-scanner.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install(FILES ${CMAKE_BINARY_DIR}/hyprwayland-scanner-config.cmake
${CMAKE_BINARY_DIR}/hyprwayland-scanner-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hyprwayland-scanner)
install(FILES ${CMAKE_BINARY_DIR}/hyprwayland-scanner.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install(FILES
${CMAKE_BINARY_DIR}/hyprwayland-scanner-config.cmake
${CMAKE_BINARY_DIR}/hyprwayland-scanner-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hyprwayland-scanner
)

View File

@ -1,20 +1,12 @@
# hyprwayland-scanner
A Hyprland implementation of wayland-scanner, in and for C++.
hw-s automatically generates properly RAII-ready, modern C++ bindings for Wayland protocols, for
either servers or clients.
## Usage
```sh
hyprwayland-scanner '/path/to/proto' '/path/to/output/directory'
```
### Options
- `--client` -> generate client code
- `--wayland-enums` -> use wayland enum naming (snake instead of camel)
## Dependencies
Requires a compiler with C++23 support.
@ -34,3 +26,7 @@ cmake --build build -j `nproc`
```sh
sudo cmake --install build
```
## TODO
- [ ] Support for generating client headers

View File

@ -1 +0,0 @@
0.4.4

24
debian/changelog vendored
View File

@ -1,24 +0,0 @@
hyprwayland-scanner (0.4.4-1) unstable; urgency=medium
* New upstream version 0.4.4
-- Alan M Varghese (NyxTrail) <alan@digistorm.in> Sun, 02 Mar 2025 10:20:41 +0000
hyprwayland-scanner (0.4.2-2) unstable; urgency=medium
* #1085254 : Mark 'Multi-Arch: foreign', and move pkgconf
and cmake files to /usr/share
-- Alan M Varghese (NyxTrail) <alan@digistorm.in> Sat, 19 Oct 2024 13:39:08 +0000
hyprwayland-scanner (0.4.2-1) unstable; urgency=medium
* New upstream version 0.4.2
-- Alan M Varghese (NyxTrail) <alan@digistorm.in> Sun, 22 Sep 2024 09:08:26 +0000
hyprwayland-scanner (0.3.10-1) unstable; urgency=medium
* Initial release. (Closes: #1073195)
-- Alan M Varghese (NyxTrail) <alan@digistorm.in> Fri, 14 Jun 2024 10:21:06 +0000

24
debian/control vendored
View File

@ -1,24 +0,0 @@
Source: hyprwayland-scanner
Section: libdevel
Priority: optional
Maintainer: Alan M Varghese (NyxTrail) <alan@digistorm.in>
Rules-Requires-Root: no
Build-Depends:
debhelper-compat (= 13),
cmake,
libpugixml-dev,
pkgconf
Standards-Version: 4.7.2
Homepage: https://github.com/hyprwm/hyprwayland-scanner
Vcs-Browser: https://salsa.debian.org/NyxTrail/hyprwayland-scanner
Vcs-Git: https://salsa.debian.org/NyxTrail/hyprwayland-scanner.git
Package: hyprwayland-scanner
Architecture: any
Multi-Arch: foreign
Depends:
${shlibs:Depends},
${misc:Depends},
Description: Implementation of wayland-scanner for Hyprland
hyprwayland-scanner is a Hyprland implementation of wayland-scanner,
in and for C++.

42
debian/copyright vendored
View File

@ -1,42 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: https://github.com/hyprwm/hyprwayland-scanner
Upstream-Name: hyprwayland-scanner
Upstream-Contact: vaxerski <vaxry@vaxry.net>
Files:
*
Copyright:
2024 Hypr Development
License: BSD-3-Clause
Files:
debian/*
Copyright:
2024-2025 Alan M Varghese (NyxTrail) <alan@digistorm.in>
License: BSD-3-Clause
License: BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

17
debian/rules vendored
View File

@ -1,17 +0,0 @@
#!/usr/bin/make -f
# export DH_VERBOSE = 1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
%:
dh $@
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_INSTALL_LIBDIR=/usr/share

View File

@ -1 +0,0 @@
3.0 (quilt)

View File

@ -1,4 +0,0 @@
Bug-Database: https://github.com/hyprwm/hyprwayland-scanner/issues
Bug-Submit: https://github.com/hyprwm/hyprwayland-scanner/issues/new
Repository-Browse: https://github.com/hyprwm/hyprwayland-scanner
Repository: https://github.com/hyprwm/hyprwayland-scanner.git

4
debian/watch vendored
View File

@ -1,4 +0,0 @@
version=4
opts="searchmode=html" \
https://github.com/hyprwm/hyprwayland-scanner/tags \
https://github.com/hyprwm/hyprwayland-scanner/archive/refs/tags/v(\d+)\.(\d+)\.(\d+)?\.tar\.gz

View File

@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1734119587,
"narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=",
"lastModified": 1713537308,
"narHash": "sha256-XtTSSIB2DA6tOv+l0FhvfDMiyCmhoRbNB+0SeInZkbk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5",
"rev": "5c24cf2f0a12ad855f444c30b2421d044120c66f",
"type": "github"
},
"original": {

View File

@ -18,26 +18,18 @@
localSystem.system = system;
overlays = with self.overlays; [hyprwayland-scanner];
});
pkgsCrossFor = eachSystem (system: crossSystem:
import nixpkgs {
localSystem = system;
crossSystem = crossSystem;
overlays = with self.overlays; [hyprwayland-scanner];
});
mkDate = longDate: (lib.concatStringsSep "-" [
(builtins.substring 0 4 longDate)
(builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate)
]);
version = lib.removeSuffix "\n" (builtins.readFile ./VERSION);
in {
overlays = {
default = self.overlays.hyprwayland-scanner;
hyprwayland-scanner = final: prev: {
hyprwayland-scanner = final.callPackage ./nix/default.nix {
stdenv = final.gcc14Stdenv;
version = version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
stdenv = final.gcc13Stdenv;
version = "0.1.0" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
};
};
};
@ -45,7 +37,6 @@
packages = eachSystem (system: {
default = self.packages.${system}.hyprwayland-scanner;
inherit (pkgsFor.${system}) hyprwayland-scanner;
hyprwayland-scanner-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprwayland-scanner;
});
formatter = eachSystem (system: pkgsFor.${system}.alejandra);

View File

@ -15,9 +15,6 @@ stdenv.mkDerivation {
nativeBuildInputs = [
cmake
pkg-config
];
buildInputs = [
pugixml
];

View File

@ -9,31 +9,32 @@
#include <filesystem>
bool waylandEnums = false;
bool clientCode = false;
bool noInterfaces = false;
struct SRequestArgument {
std::string wlType;
std::string interface;
std::string enumName;
std::string name;
bool newType = false;
bool allowNull = false;
};
struct SWaylandFunction {
struct SRequest {
std::vector<SRequestArgument> args;
std::string name;
std::string since;
};
struct SEvent {
std::vector<SRequestArgument> args;
std::string name;
std::string since;
std::string newIdType = ""; // client only
bool destructor = false;
};
struct SInterface {
std::vector<SWaylandFunction> requests;
std::vector<SWaylandFunction> events;
std::string name;
int version = 1;
std::vector<SRequest> requests;
std::vector<SEvent> events;
std::string name;
int version = 1;
};
struct SEnum {
@ -47,10 +48,6 @@ struct {
std::vector<SEnum> enums;
} XMLDATA;
const char* resourceName() {
return clientCode ? "wl_proxy" : "wl_resource";
}
std::string sanitize(const std::string& in) {
if (in == "namespace")
return "namespace_";
@ -111,24 +108,19 @@ std::string WPTypeToCType(const SRequestArgument& arg, bool event /* events pass
return "uint32_t";
// enum
if (!arg.enumName.empty()) {
if (!arg.enumName.empty())
for (auto& e : XMLDATA.enums) {
if (e.nameOriginal == arg.enumName)
return e.name;
}
return "uint32_t";
}
if (!event && clientCode && arg.wlType == "new_id")
return "wl_proxy*";
// iface
if (!arg.interface.empty() && event) {
for (auto& i : XMLDATA.ifaces) {
if (i.name == arg.interface)
return camelize((clientCode ? "CC_" : "C_") + arg.interface + "*");
return camelize("C_" + arg.interface + "*");
}
return std::string{resourceName()} + "*";
return "wl_resource*";
}
return "uint32_t";
@ -137,10 +129,10 @@ std::string WPTypeToCType(const SRequestArgument& arg, bool event /* events pass
if (!arg.interface.empty() && event && !ignoreTypes) {
for (auto& i : XMLDATA.ifaces) {
if (i.name == arg.interface)
return camelize((clientCode ? "CC_" : "C_") + arg.interface + "*");
return camelize("C_" + arg.interface + "*");
}
}
return std::string{resourceName()} + "*";
return "wl_resource*";
}
if (arg.wlType == "int" || arg.wlType == "fd")
return "int32_t";
@ -195,17 +187,12 @@ void parseXML(pugi::xml_document& doc) {
}
for (auto& rq : iface.children("request")) {
SWaylandFunction srq;
srq.name = rq.attribute("name").as_string();
srq.since = rq.attribute("since").as_string();
srq.destructor = rq.attribute("type").as_string() == std::string{"destructor"};
SRequest srq;
srq.name = rq.attribute("name").as_string();
srq.since = rq.attribute("since").as_string();
for (auto& arg : rq.children("arg")) {
SRequestArgument sargm;
if (arg.attribute("type").as_string() == std::string{"new_id"} && clientCode)
srq.newIdType = arg.attribute("interface").as_string();
sargm.newType = arg.attribute("type").as_string() == std::string{"new_id"} && clientCode;
sargm.name = sanitize(arg.attribute("name").as_string());
sargm.wlType = arg.attribute("type").as_string();
sargm.interface = arg.attribute("interface").as_string();
@ -219,10 +206,9 @@ void parseXML(pugi::xml_document& doc) {
}
for (auto& ev : iface.children("event")) {
SWaylandFunction sev;
sev.name = ev.attribute("name").as_string();
sev.since = ev.attribute("since").as_string();
sev.destructor = ev.attribute("type").as_string() == std::string{"destructor"};
SEvent sev;
sev.name = ev.attribute("name").as_string();
sev.since = ev.attribute("since").as_string();
for (auto& arg : ev.children("arg")) {
SRequestArgument sargm;
@ -245,20 +231,19 @@ void parseXML(pugi::xml_document& doc) {
void parseHeader() {
// add some boilerplate
HEADER +=
std::format(R"#(#pragma once
HEADER += R"#(#pragma once
#include <functional>
#include <cstdint>
#include <string>
{}
#include <wayland-server.h>
#define F std::function
{}
struct wl_client;
struct wl_resource;
)#",
(clientCode ? "#include <wayland-client.h>" : "#include <wayland-server.h>"), (clientCode ? "struct wl_proxy;" : "struct wl_client;\nstruct wl_resource;"));
)#";
// parse all enums
if (!waylandEnums) {
@ -273,13 +258,13 @@ void parseHeader() {
// fw declare all classes
for (auto& iface : XMLDATA.ifaces) {
const auto IFACE_CLASS_NAME_CAMEL = camelize((clientCode ? "CC_" : "C_") + iface.name);
const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name);
HEADER += std::format("\nclass {};", IFACE_CLASS_NAME_CAMEL);
for (auto& rq : iface.requests) {
for (auto& arg : rq.args) {
if (!arg.interface.empty()) {
HEADER += std::format("\nclass {};", camelize((clientCode ? "CC_" : "C_") + arg.interface));
HEADER += std::format("\nclass {};", camelize("C_" + arg.interface));
}
}
}
@ -287,7 +272,7 @@ void parseHeader() {
for (auto& rq : iface.events) {
for (auto& arg : rq.args) {
if (!arg.interface.empty()) {
HEADER += std::format("\nclass {};", camelize((clientCode ? "CC_" : "C_") + arg.interface));
HEADER += std::format("\nclass {};", camelize("C_" + arg.interface));
}
}
}
@ -306,32 +291,15 @@ void parseHeader() {
for (auto& iface : XMLDATA.ifaces) {
const auto IFACE_NAME_CAMEL = camelize(iface.name);
const auto IFACE_CLASS_NAME_CAMEL = camelize((clientCode ? "CC_" : "C_") + iface.name);
if (!clientCode) {
HEADER += std::format(R"#(
struct {}DestroyWrapper {{
wl_listener listener;
{}* parent = nullptr;
}};
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
}
const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name);
// begin the class
HEADER +=
std::format(R"#(
HEADER += std::format(R"#(
class {} {{
public:
{}({});
{}(wl_client* client, uint32_t version, uint32_t id);
~{}();
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, (clientCode ? "wl_proxy*" : "wl_client* client, uint32_t version, uint32_t id"), IFACE_CLASS_NAME_CAMEL);
if (!clientCode) {
HEADER += std::format(R"#(
// set a listener for when this resource is _being_ destroyed
void setOnDestroy(F<void({}*)> handler) {{
onDestroy = handler;
@ -346,7 +314,7 @@ class {} {{
void* data() {{
return pData;
}}
// get the raw wl_resource ptr
wl_resource* resource() {{
return pResource;
@ -371,46 +339,17 @@ class {} {{
int version() {{
return wl_resource_get_version(pResource);
}}
)#",
IFACE_CLASS_NAME_CAMEL);
} else {
HEADER += R"#(
// set the data for this resource
void setData(void* data) {{
pData = data;
}}
// get the data for this resource
void* data() {{
return pData;
}}
// get the raw wl_resource (wl_proxy) ptr
wl_proxy* resource() {{
return pResource;
}}
// get the raw wl_proxy ptr
wl_proxy* proxy() {{
return pResource;
}}
// get the resource version
int version() {{
return wl_proxy_get_version(pResource);
}}
)#";
}
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
// add all setters for requests
HEADER += "\n // --------------- Requests --------------- //\n\n";
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
for (auto& rq : iface.requests) {
std::string args = ", ";
for (auto& arg : rq.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, false) + ", ";
}
@ -424,11 +363,9 @@ class {} {{
HEADER += "\n // --------------- Events --------------- //\n\n";
for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
for (auto& ev : iface.events) {
std::string args = "";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, true) + ", ";
}
@ -437,26 +374,22 @@ class {} {{
args.pop_back();
}
HEADER += std::format(" {} {}({});\n", ev.newIdType.empty() ? "void" : "wl_proxy*", camelize("send_" + ev.name), args);
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name), args);
}
// dangerous ones
if (!clientCode) {
for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
std::string args = "";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, true, true) + ", ";
}
if (!args.empty()) {
args.pop_back();
args.pop_back();
}
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name + "_raw"), args);
for (auto& ev : iface.events) {
std::string args = "";
for (auto& arg : ev.args) {
args += WPTypeToCType(arg, true, true) + ", ";
}
if (!args.empty()) {
args.pop_back();
args.pop_back();
}
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name + "_raw"), args);
}
// end events
@ -467,12 +400,10 @@ class {} {{
// start requests storage
HEADER += " struct {\n";
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
for (auto& rq : iface.requests) {
std::string args = ", ";
for (auto& arg : rq.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, false) + ", ";
}
@ -488,26 +419,17 @@ class {} {{
HEADER += " } requests;\n";
// constant resource stuff
if (!clientCode) {
HEADER += std::format(R"#(
HEADER += std::format(R"#(
void onDestroyCalled();
F<void({}*)> onDestroy;
wl_resource* pResource = nullptr;
{}DestroyWrapper resourceDestroyListener;
wl_listener resourceDestroyListener;
void* pData = nullptr;)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
} else {
HEADER += R"#(
wl_proxy* pResource = nullptr;
bool destroyed = false;
void* pData = nullptr;)#";
}
IFACE_CLASS_NAME_CAMEL);
HEADER += "\n};\n\n";
}
@ -588,16 +510,14 @@ static const wl_interface* dummyTypes[] = { nullptr };
const auto IFACE_WL_NAME = iface.name + "_interface";
const auto IFACE_NAME = iface.name;
const auto IFACE_NAME_CAMEL = camelize(iface.name);
const auto IFACE_CLASS_NAME_CAMEL = camelize((clientCode ? "CC_" : "C_") + iface.name);
const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name);
// create handlers
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
for (auto& rq : iface.requests) {
const auto REQUEST_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name);
std::string argsC = ", ";
for (auto& arg : rq.args) {
if (arg.newType)
continue;
argsC += WPTypeToCType(arg, false) + " " + arg.name + ", ";
}
@ -614,38 +534,24 @@ static const wl_interface* dummyTypes[] = { nullptr };
argsN.pop_back();
}
if (!clientCode) {
SOURCE += std::format(R"#(
SOURCE += std::format(R"#(
static void {}(wl_client* client, wl_resource* resource{}) {{
const auto PO = ({}*)wl_resource_get_user_data(resource);
if (PO && PO->requests.{})
PO->requests.{}(PO{});
}}
)#",
REQUEST_NAME, argsC, IFACE_CLASS_NAME_CAMEL, camelize(rq.name), camelize(rq.name), argsN);
} else {
SOURCE += std::format(R"#(
static void {}(void* data, void* resource{}) {{
const auto PO = ({}*)data;
if (PO && PO->requests.{})
PO->requests.{}(PO{});
}}
)#",
REQUEST_NAME, argsC, IFACE_CLASS_NAME_CAMEL, camelize(rq.name), camelize(rq.name), argsN);
}
REQUEST_NAME, argsC, IFACE_CLASS_NAME_CAMEL, camelize(rq.name), camelize(rq.name), argsN);
}
// destroy handler
if (!clientCode) {
SOURCE += std::format(R"#(
SOURCE += std::format(R"#(
static void _{}__DestroyListener(wl_listener* l, void* d) {{
{}DestroyWrapper *wrap = wl_container_of(l, wrap, listener);
{}* pResource = wrap->parent;
{}* pResource = wl_container_of(l, pResource, resourceDestroyListener);
pResource->onDestroyCalled();
}}
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
}
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
// create vtable
@ -656,7 +562,7 @@ static const void* {}[] = {{
)#",
IFACE_VTABLE_NAME);
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
for (auto& rq : iface.requests) {
const auto REQUEST_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name);
SOURCE += std::format(" (void*){},\n", REQUEST_NAME);
}
@ -666,13 +572,11 @@ static const void* {}[] = {{
// create events
int evid = 0;
for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
for (auto& ev : iface.events) {
const auto EVENT_NAME = camelize("send_" + ev.name);
std::string argsC = "";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
argsC += WPTypeToCType(arg, true) + " " + arg.name + ", ";
}
@ -683,85 +587,60 @@ static const void* {}[] = {{
std::string argsN = ", ";
for (auto& arg : ev.args) {
if (arg.newType)
argsN += "nullptr, ";
else if (!WPTypeToCType(arg, true).starts_with("C"))
if (!WPTypeToCType(arg, true).starts_with("C"))
argsN += arg.name + ", ";
else
argsN += (arg.name + " ? " + arg.name + "->pResource : nullptr, ");
argsN += arg.name + "->pResource, ";
}
argsN.pop_back();
argsN.pop_back();
if (!clientCode) {
SOURCE += std::format(R"#(
SOURCE += std::format(R"#(
void {}::{}({}) {{
if (!pResource)
return;
wl_resource_post_event(pResource, {}{});
}}
)#",
IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, evid, argsN);
} else {
std::string retType = ev.newIdType.empty() ? "void" : "wl_proxy";
std::string ptrRetType = ev.newIdType.empty() ? "void" : "wl_proxy*";
std::string flags = ev.destructor ? "1" : "0";
SOURCE += std::format(R"#(
{} {}::{}({}) {{
if (!pResource)
return{};{}
auto proxy = wl_proxy_marshal_flags((wl_proxy*)pResource, {}, {}, wl_proxy_get_version((wl_proxy*)pResource), {}{});{}
}}
)#",
ptrRetType, IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, (ev.newIdType.empty() ? "" : " nullptr"),
(ev.destructor ? "\n destroyed = true;" : ""), evid, (ev.newIdType.empty() ? "nullptr" : "&" + ev.newIdType + "_interface"), flags, argsN,
(ev.newIdType.empty() ? "\n proxy;" : "\n\n return proxy;"));
}
IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, evid, argsN);
evid++;
}
// dangerous
if (!clientCode) {
evid = 0;
for (auto& ev : iface.events) {
const auto EVENT_NAME = camelize("send_" + ev.name + "_raw");
evid = 0;
for (auto& ev : iface.events) {
const auto EVENT_NAME = camelize("send_" + ev.name + "_raw");
std::string argsC = "";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
argsC += WPTypeToCType(arg, true, true) + " " + arg.name + ", ";
}
std::string argsC = "";
for (auto& arg : ev.args) {
argsC += WPTypeToCType(arg, true, true) + " " + arg.name + ", ";
}
if (!argsC.empty()) {
argsC.pop_back();
argsC.pop_back();
}
if (!argsC.empty()) {
argsC.pop_back();
argsC.pop_back();
}
std::string argsN = ", ";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
argsN += arg.name + ", ";
}
std::string argsN = ", ";
for (auto& arg : ev.args) {
argsN += arg.name + ", ";
}
argsN.pop_back();
argsN.pop_back();
argsN.pop_back();
argsN.pop_back();
SOURCE += std::format(R"#(
SOURCE += std::format(R"#(
void {}::{}({}) {{
if (!pResource)
return;
wl_resource_post_event(pResource, {}{});
}}
)#",
IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, evid, argsN);
IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, evid, argsN);
evid++;
}
evid++;
}
// wayland interfaces and stuff
@ -808,52 +687,49 @@ void {}::{}({}) {{
const auto MESSAGE_NAME_EVENTS = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_events");
// message
if (!noInterfaces) {
if (iface.requests.size() > 0) {
SOURCE += std::format(R"#(
static const wl_message {}[] = {{
)#",
MESSAGE_NAME_REQUESTS);
for (auto& rq : iface.requests) {
// create type table
const auto TYPE_TABLE_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name + "_types");
SOURCE += std::format(" {{ \"{}\", \"{}\", {}}},\n", rq.name, argsToShort(rq.args, rq.since), rq.args.empty() ? "dummyTypes + 0" : TYPE_TABLE_NAME + " + 0");
}
SOURCE += "};\n";
}
if (iface.events.size() > 0) {
SOURCE += std::format(R"#(
static const wl_message {}[] = {{
)#",
MESSAGE_NAME_EVENTS);
for (auto& ev : iface.events) {
// create type table
const auto TYPE_TABLE_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + ev.name + "_types");
SOURCE += std::format(" {{ \"{}\", \"{}\", {}}},\n", ev.name, argsToShort(ev.args, ev.since), ev.args.empty() ? "dummyTypes + 0" : TYPE_TABLE_NAME + " + 0");
}
SOURCE += "};\n";
}
// iface
if (iface.requests.size() > 0) {
SOURCE += std::format(R"#(
static const wl_message {}[] = {{
)#",
MESSAGE_NAME_REQUESTS);
for (auto& rq : iface.requests) {
// create type table
const auto TYPE_TABLE_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name + "_types");
SOURCE += std::format(" {{ \"{}\", \"{}\", {}}},\n", rq.name, argsToShort(rq.args, rq.since), rq.args.empty() ? "dummyTypes + 0" : TYPE_TABLE_NAME + " + 0");
}
SOURCE += "};\n";
}
if (iface.events.size() > 0) {
SOURCE += std::format(R"#(
static const wl_message {}[] = {{
)#",
MESSAGE_NAME_EVENTS);
for (auto& ev : iface.events) {
// create type table
const auto TYPE_TABLE_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + ev.name + "_types");
SOURCE += std::format(" {{ \"{}\", \"{}\", {}}},\n", ev.name, argsToShort(ev.args, ev.since), ev.args.empty() ? "dummyTypes + 0" : TYPE_TABLE_NAME + " + 0");
}
SOURCE += "};\n";
}
// iface
SOURCE += std::format(R"#(
const wl_interface {} = {{
"{}", {},
{}, {},
{}, {},
}};
)#",
IFACE_WL_NAME, iface.name, iface.version, iface.requests.size(), (iface.requests.size() > 0 ? MESSAGE_NAME_REQUESTS : "nullptr"),
iface.events.size(), (iface.events.size() > 0 ? MESSAGE_NAME_EVENTS : "nullptr"));
}
IFACE_WL_NAME, iface.name, iface.version, iface.requests.size(), (iface.requests.size() > 0 ? MESSAGE_NAME_REQUESTS : "nullptr"), iface.events.size(),
(iface.events.size() > 0 ? MESSAGE_NAME_EVENTS : "nullptr"));
// protocol body
if (!clientCode) {
SOURCE += std::format(R"#(
SOURCE += std::format(R"#(
{}::{}(wl_client* client, uint32_t version, uint32_t id) {{
pResource = wl_resource_create(client, &{}, version, id);
@ -861,17 +737,16 @@ const wl_interface {} = {{
return;
wl_resource_set_user_data(pResource, this);
wl_list_init(&resourceDestroyListener.listener.link);
resourceDestroyListener.listener.notify = _{}__DestroyListener;
resourceDestroyListener.parent = this;
wl_resource_add_destroy_listener(pResource, &resourceDestroyListener.listener);
wl_list_init(&resourceDestroyListener.link);
resourceDestroyListener.notify = _{}__DestroyListener;
wl_resource_add_destroy_listener(pResource, &resourceDestroyListener);
wl_resource_set_implementation(pResource, {}, this, nullptr);
}}
{}::~{}() {{
wl_list_remove(&resourceDestroyListener.listener.link);
wl_list_init(&resourceDestroyListener.listener.link);
wl_list_remove(&resourceDestroyListener.link);
wl_list_init(&resourceDestroyListener.link);
// if we still own the wayland resource,
// it means we need to destroy it.
@ -883,8 +758,8 @@ const wl_interface {} = {{
void {}::onDestroyCalled() {{
wl_resource_set_user_data(pResource, nullptr);
wl_list_remove(&resourceDestroyListener.listener.link);
wl_list_init(&resourceDestroyListener.listener.link);
wl_list_remove(&resourceDestroyListener.link);
wl_list_init(&resourceDestroyListener.link);
// set the resource to nullptr,
// as it will be freed. If the consumer does not destroy this resource
@ -895,41 +770,10 @@ void {}::onDestroyCalled() {{
onDestroy(this);
}}
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_NAME + "_interface", IFACE_CLASS_NAME_CAMEL, IFACE_VTABLE_NAME, IFACE_CLASS_NAME_CAMEL,
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
} else {
std::string DTOR_FUNC = "";
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_NAME + "_interface", IFACE_CLASS_NAME_CAMEL, IFACE_VTABLE_NAME, IFACE_CLASS_NAME_CAMEL,
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
for (auto& rq : iface.requests) {
if (!rq.destructor)
continue;
DTOR_FUNC = camelize("send_" + rq.name) + "()";
break;
}
if (DTOR_FUNC.empty())
DTOR_FUNC = "wl_proxy_destroy(pResource)";
SOURCE += std::format(R"#(
{}::{}(wl_proxy* resource) {{
pResource = resource;
if (!pResource)
return;
wl_proxy_add_listener(pResource, (void (**)(void))&{}, this);
}}
{}::~{}() {{
if (!destroyed)
{};
}}
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_VTABLE_NAME, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, DTOR_FUNC);
}
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
for (auto& rq : iface.requests) {
std::string args = ", ";
for (auto& arg : rq.args) {
args += WPTypeToCType(arg, false) + ", ";
@ -964,16 +808,6 @@ int main(int argc, char** argv, char** envp) {
return 0;
}
if (curarg == "-c" || curarg == "--client") {
clientCode = true;
continue;
}
if (curarg == "--no-interfaces") {
noInterfaces = true;
continue;
}
if (curarg == "--wayland-enums") {
waylandEnums = true;
continue;