Compare commits

...

12 Commits

Author SHA1 Message Date
alan (NyxTrail) 9606635565
Update d/copyright year 2025-03-16 11:30:07 +00:00
alan (NyxTrail) 092820f30d
New upstream version 0.4.4
- Also updated standards version to 4.7.2
2025-03-02 10:23:23 +00:00
alan (NyxTrail) 95d26cd408 Update upstream source from tag 'upstream/0.4.4'
Update to upstream version '0.4.4'
with Debian dir f4a9f057d8
2025-03-02 10:20:27 +00:00
alan (NyxTrail) f6dbe63aff New upstream version 0.4.4 2025-03-02 10:20:27 +00:00
alan (NyxTrail) fc399d482a
Make package Multi-Arch: foreign
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1085254
2024-10-26 06:04:27 +00:00
alan (NyxTrail) bd888c80ac
New upstream version 0.4.2 2024-09-22 09:12:01 +00:00
alan (NyxTrail) da27435de4 New upstream version 0.4.2 2024-09-22 09:07:19 +00:00
alan (NyxTrail) 59a128c953 Update upstream source from tag 'upstream/0.4.2'
Update to upstream version '0.4.2'
with Debian dir addd66515d
2024-09-22 09:07:19 +00:00
alan (NyxTrail) 75628269f9
Update to new standards version 4.7.0 2024-06-19 10:54:49 +00:00
alan (NyxTrail) c0855a23fb
Remove generated man page 2024-06-19 10:53:50 +00:00
alan (NyxTrail) 92695e1c1e
Fix watch file 2024-06-17 11:58:40 +00:00
alan (NyxTrail) d87d65b9d5
Initial d/* files 2024-06-14 14:46:12 +00:00
14 changed files with 453 additions and 157 deletions

View File

@ -1,11 +1,12 @@
cmake_minimum_required(VERSION 3.19)
set(VERSION 0.3.10)
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
string(STRIP ${VER_RAW} VERSION)
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)
@ -15,18 +16,17 @@ 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,25 +41,22 @@ 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,12 +1,20 @@
# 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.
@ -26,7 +34,3 @@ cmake --build build -j `nproc`
```sh
sudo cmake --install build
```
## TODO
- [ ] Support for generating client headers

1
VERSION Normal file
View File

@ -0,0 +1 @@
0.4.4

24
debian/changelog vendored Normal file
View File

@ -0,0 +1,24 @@
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 Normal file
View File

@ -0,0 +1,24 @@
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 Normal file
View File

@ -0,0 +1,42 @@
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 Executable file
View File

@ -0,0 +1,17 @@
#!/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

1
debian/source/format vendored Normal file
View File

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

4
debian/upstream/metadata vendored Normal file
View File

@ -0,0 +1,4 @@
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 Normal file
View File

@ -0,0 +1,4 @@
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": 1713537308,
"narHash": "sha256-XtTSSIB2DA6tOv+l0FhvfDMiyCmhoRbNB+0SeInZkbk=",
"lastModified": 1734119587,
"narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5c24cf2f0a12ad855f444c30b2421d044120c66f",
"rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5",
"type": "github"
},
"original": {

View File

@ -18,18 +18,26 @@
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.gcc13Stdenv;
version = "0.1.0" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
stdenv = final.gcc14Stdenv;
version = version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
};
};
};
@ -37,6 +45,7 @@
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,6 +15,9 @@ stdenv.mkDerivation {
nativeBuildInputs = [
cmake
pkg-config
];
buildInputs = [
pugixml
];

View File

@ -9,32 +9,31 @@
#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 SRequest {
std::vector<SRequestArgument> args;
std::string name;
std::string since;
};
struct SEvent {
struct SWaylandFunction {
std::vector<SRequestArgument> args;
std::string name;
std::string since;
std::string newIdType = ""; // client only
bool destructor = false;
};
struct SInterface {
std::vector<SRequest> requests;
std::vector<SEvent> events;
std::string name;
int version = 1;
std::vector<SWaylandFunction> requests;
std::vector<SWaylandFunction> events;
std::string name;
int version = 1;
};
struct SEnum {
@ -48,6 +47,10 @@ 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_";
@ -108,19 +111,24 @@ 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("C_" + arg.interface + "*");
return camelize((clientCode ? "CC_" : "C_") + arg.interface + "*");
}
return "wl_resource*";
return std::string{resourceName()} + "*";
}
return "uint32_t";
@ -129,10 +137,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("C_" + arg.interface + "*");
return camelize((clientCode ? "CC_" : "C_") + arg.interface + "*");
}
}
return "wl_resource*";
return std::string{resourceName()} + "*";
}
if (arg.wlType == "int" || arg.wlType == "fd")
return "int32_t";
@ -187,12 +195,17 @@ void parseXML(pugi::xml_document& doc) {
}
for (auto& rq : iface.children("request")) {
SRequest srq;
srq.name = rq.attribute("name").as_string();
srq.since = rq.attribute("since").as_string();
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"};
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();
@ -206,9 +219,10 @@ void parseXML(pugi::xml_document& doc) {
}
for (auto& ev : iface.children("event")) {
SEvent sev;
sev.name = ev.attribute("name").as_string();
sev.since = ev.attribute("since").as_string();
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"};
for (auto& arg : ev.children("arg")) {
SRequestArgument sargm;
@ -231,19 +245,20 @@ void parseXML(pugi::xml_document& doc) {
void parseHeader() {
// add some boilerplate
HEADER += R"#(#pragma once
HEADER +=
std::format(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) {
@ -258,13 +273,13 @@ struct wl_resource;
// fw declare all classes
for (auto& iface : XMLDATA.ifaces) {
const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name);
const auto IFACE_CLASS_NAME_CAMEL = camelize((clientCode ? "CC_" : "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("C_" + arg.interface));
HEADER += std::format("\nclass {};", camelize((clientCode ? "CC_" : "C_") + arg.interface));
}
}
}
@ -272,7 +287,7 @@ struct wl_resource;
for (auto& rq : iface.events) {
for (auto& arg : rq.args) {
if (!arg.interface.empty()) {
HEADER += std::format("\nclass {};", camelize("C_" + arg.interface));
HEADER += std::format("\nclass {};", camelize((clientCode ? "CC_" : "C_") + arg.interface));
}
}
}
@ -291,15 +306,32 @@ struct wl_resource;
for (auto& iface : XMLDATA.ifaces) {
const auto IFACE_NAME_CAMEL = camelize(iface.name);
const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + 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);
}
// 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;
@ -314,7 +346,7 @@ class {} {{
void* data() {{
return pData;
}}
// get the raw wl_resource ptr
wl_resource* resource() {{
return pResource;
@ -339,17 +371,46 @@ 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;
}}
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
// 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);
}}
)#";
}
// add all setters for requests
HEADER += "\n // --------------- Requests --------------- //\n\n";
for (auto& rq : iface.requests) {
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
std::string args = ", ";
for (auto& arg : rq.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, false) + ", ";
}
@ -363,9 +424,11 @@ class {} {{
HEADER += "\n // --------------- Events --------------- //\n\n";
for (auto& ev : iface.events) {
for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
std::string args = "";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, true) + ", ";
}
@ -374,22 +437,26 @@ class {} {{
args.pop_back();
}
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name), args);
HEADER += std::format(" {} {}({});\n", ev.newIdType.empty() ? "void" : "wl_proxy*", camelize("send_" + ev.name), args);
}
// dangerous ones
for (auto& ev : iface.events) {
std::string args = "";
for (auto& arg : ev.args) {
args += WPTypeToCType(arg, true, true) + ", ";
}
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();
}
if (!args.empty()) {
args.pop_back();
args.pop_back();
}
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name + "_raw"), args);
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name + "_raw"), args);
}
}
// end events
@ -400,10 +467,12 @@ class {} {{
// start requests storage
HEADER += " struct {\n";
for (auto& rq : iface.requests) {
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
std::string args = ", ";
for (auto& arg : rq.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, false) + ", ";
}
@ -419,17 +488,26 @@ class {} {{
HEADER += " } requests;\n";
// constant resource stuff
HEADER += std::format(R"#(
if (!clientCode) {
HEADER += std::format(R"#(
void onDestroyCalled();
F<void({}*)> onDestroy;
wl_resource* pResource = nullptr;
wl_listener resourceDestroyListener;
{}DestroyWrapper resourceDestroyListener;
void* pData = nullptr;)#",
IFACE_CLASS_NAME_CAMEL);
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
} else {
HEADER += R"#(
wl_proxy* pResource = nullptr;
bool destroyed = false;
void* pData = nullptr;)#";
}
HEADER += "\n};\n\n";
}
@ -510,14 +588,16 @@ 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("C_" + iface.name);
const auto IFACE_CLASS_NAME_CAMEL = camelize((clientCode ? "CC_" : "C_") + iface.name);
// create handlers
for (auto& rq : iface.requests) {
for (auto& rq : (clientCode ? iface.events : 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 + ", ";
}
@ -534,24 +614,38 @@ static const wl_interface* dummyTypes[] = { nullptr };
argsN.pop_back();
}
SOURCE += std::format(R"#(
if (!clientCode) {
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);
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);
}
}
// destroy handler
SOURCE += std::format(R"#(
if (!clientCode) {
SOURCE += std::format(R"#(
static void _{}__DestroyListener(wl_listener* l, void* d) {{
{}* pResource = wl_container_of(l, pResource, resourceDestroyListener);
{}DestroyWrapper *wrap = wl_container_of(l, wrap, listener);
{}* pResource = wrap->parent;
pResource->onDestroyCalled();
}}
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
}
// create vtable
@ -562,7 +656,7 @@ static const void* {}[] = {{
)#",
IFACE_VTABLE_NAME);
for (auto& rq : iface.requests) {
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
const auto REQUEST_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name);
SOURCE += std::format(" (void*){},\n", REQUEST_NAME);
}
@ -572,11 +666,13 @@ static const void* {}[] = {{
// create events
int evid = 0;
for (auto& ev : iface.events) {
for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
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 + ", ";
}
@ -587,60 +683,85 @@ static const void* {}[] = {{
std::string argsN = ", ";
for (auto& arg : ev.args) {
if (!WPTypeToCType(arg, true).starts_with("C"))
if (arg.newType)
argsN += "nullptr, ";
else if (!WPTypeToCType(arg, true).starts_with("C"))
argsN += arg.name + ", ";
else
argsN += arg.name + "->pResource, ";
argsN += (arg.name + " ? " + arg.name + "->pResource : nullptr, ");
}
argsN.pop_back();
argsN.pop_back();
SOURCE += std::format(R"#(
if (!clientCode) {
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);
} 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;"));
}
evid++;
}
// dangerous
evid = 0;
for (auto& ev : iface.events) {
const auto EVENT_NAME = camelize("send_" + ev.name + "_raw");
if (!clientCode) {
evid = 0;
for (auto& ev : iface.events) {
const auto EVENT_NAME = camelize("send_" + ev.name + "_raw");
std::string argsC = "";
for (auto& arg : ev.args) {
argsC += WPTypeToCType(arg, true, true) + " " + arg.name + ", ";
}
std::string argsC = "";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
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) {
argsN += arg.name + ", ";
}
std::string argsN = ", ";
for (auto& arg : ev.args) {
if (arg.newType)
continue;
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
@ -687,49 +808,52 @@ void {}::{}({}) {{
const auto MESSAGE_NAME_EVENTS = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_events");
// message
if (iface.requests.size() > 0) {
SOURCE += std::format(R"#(
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");
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 += std::format(" {{ \"{}\", \"{}\", {}}},\n", rq.name, argsToShort(rq.args, rq.since), rq.args.empty() ? "dummyTypes + 0" : TYPE_TABLE_NAME + " + 0");
}
SOURCE += "};\n";
}
SOURCE += "};\n";
}
if (iface.events.size() > 0) {
SOURCE += std::format(R"#(
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");
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 += std::format(" {{ \"{}\", \"{}\", {}}},\n", ev.name, argsToShort(ev.args, ev.since), ev.args.empty() ? "dummyTypes + 0" : TYPE_TABLE_NAME + " + 0");
}
SOURCE += "};\n";
}
SOURCE += "};\n";
}
// iface
SOURCE += std::format(R"#(
// 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
SOURCE += std::format(R"#(
if (!clientCode) {
SOURCE += std::format(R"#(
{}::{}(wl_client* client, uint32_t version, uint32_t id) {{
pResource = wl_resource_create(client, &{}, version, id);
@ -737,16 +861,17 @@ const wl_interface {} = {{
return;
wl_resource_set_user_data(pResource, this);
wl_list_init(&resourceDestroyListener.link);
resourceDestroyListener.notify = _{}__DestroyListener;
wl_resource_add_destroy_listener(pResource, &resourceDestroyListener);
wl_list_init(&resourceDestroyListener.listener.link);
resourceDestroyListener.listener.notify = _{}__DestroyListener;
resourceDestroyListener.parent = this;
wl_resource_add_destroy_listener(pResource, &resourceDestroyListener.listener);
wl_resource_set_implementation(pResource, {}, this, nullptr);
}}
{}::~{}() {{
wl_list_remove(&resourceDestroyListener.link);
wl_list_init(&resourceDestroyListener.link);
wl_list_remove(&resourceDestroyListener.listener.link);
wl_list_init(&resourceDestroyListener.listener.link);
// if we still own the wayland resource,
// it means we need to destroy it.
@ -758,8 +883,8 @@ const wl_interface {} = {{
void {}::onDestroyCalled() {{
wl_resource_set_user_data(pResource, nullptr);
wl_list_remove(&resourceDestroyListener.link);
wl_list_init(&resourceDestroyListener.link);
wl_list_remove(&resourceDestroyListener.listener.link);
wl_list_init(&resourceDestroyListener.listener.link);
// set the resource to nullptr,
// as it will be freed. If the consumer does not destroy this resource
@ -770,10 +895,41 @@ 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);
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 = "";
for (auto& rq : iface.requests) {
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)) {
std::string args = ", ";
for (auto& arg : rq.args) {
args += WPTypeToCType(arg, false) + ", ";
@ -808,6 +964,16 @@ 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;