Skip to content

Instantly share code, notes, and snippets.

@twaik
Last active July 4, 2023 17:58
Show Gist options
  • Save twaik/563ea91526dccd15e2bf5974d5d3ef10 to your computer and use it in GitHub Desktop.
Save twaik/563ea91526dccd15e2bf5974d5d3ef10 to your computer and use it in GitHub Desktop.
Gradle waylandpp's wayland-scanner++ task
/*
* This code is based on
* https://github.com/NilsBrause/waylandpp/blob/4321ed5c7b4bffa41b8a2a13dc7f3ece1191f4f3/scanner/scanner.cpp
* and should generate code identical to wayland-scanner++
*
* It is created to be used as gradle task in Android Studio builds where we can not use generators
* (crosscompilation does not allow us build code for host).
*/
import org.xml.sax.SAXException
import javax.xml.transform.stream.StreamSource
import javax.xml.validation.SchemaFactory
import javax.xml.XMLConstants
import groovy.xml.XmlSlurper
abstract class WaylandScannerTask extends DefaultTask {
class element_t {
String name
String summary
String description
static final List<String> keywords = [
"alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break",
"case", "catch", "char", "char8_t", "char16_t", "char32_t", "class", "compl", "concept",
"const", "consteval", "constexpr", "constinit", "const_cast", "continue", "co_await",
"co_return", "co_yield", "decltype", "default", "delete", "do", "double", "dynamic_cast",
"else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto",
"if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq",
"nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register",
"reinterpret_cast", "requires", "return", "short", "signed", "sizeof", "static",
"static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local",
"throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using",
"virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
]
static String sanitise(String str) {
return ((keywords.contains(str)) ? "_" : "") + str
}
}
class argument_t extends element_t {
String type
String iface
String enum_iface
String enum_name
Boolean allow_null = false
String print_enum_wire_type() {
switch(type) {
case "int":
return "int32_t"
case "uint":
return "uint32_t"
default:
throw new RuntimeException("Enum type must be int or uint (have " + type + ")")
}
}
String print_type() {
if (!iface.isEmpty())
return iface + "_t"
if (enum_iface?.length() > 0)
return enum_iface + "_" + enum_name
switch (type) {
case "int":
return "int32_t"
case "uint":
return "uint32_t"
case "fixed":
return "double"
case "string":
return "std::string"
case "object":
case "new_id":
return "resource_t"
case "fd":
return "int"
case "array":
return "array_t"
default:
return type
}
}
String print_short() {
switch(type) {
case "int":
return "i"
case "uint":
return "u"
case "fixed":
return "f"
case "string":
return "s"
case "object":
return "o"
case "new_id":
return "n"
case "array":
return "a"
case "fd":
return "h"
default:
return "x"
}
}
String print_argument() {
return print_type() +
((iface?.length() > 0 || enum_iface?.length() > 0 ||
type == "string" || type == "array") ? " const& " : " ") +
sanitise(name)
}
}
class event_t extends element_t {
List<argument_t> args
int since = 0
argument_t ret
int opcode = 0
String print_functional() {
def _args = []
args.each {arg -> _args.add(arg.print_type()) }
return " std::function<void(" + _args.join(", ") + ")> " + sanitise(name) + ";"
}
String print_dispatcher(int opcode) {
def ss = "" << ""
int c = 0
def _args = []
args.each { arg ->
if(arg.enum_name != null && !arg.enum_name.empty && arg.type != "array")
_args.add(arg.print_type() << "(args[" << c++ << "].get<" << arg.print_enum_wire_type() << ">())")
else if(!arg.iface.empty)
_args.add(arg.print_type() << "(args[" << c++ << "].get<resource_t>())")
else
_args.add("args[" << c++ << "].get<" << arg.print_type() << ">()")
}
ss << " case " + opcode + ":\n"
ss << " if(events->" + sanitise(name) + ") events->" + sanitise(name) + "("
ss << _args.join(", ") << ");\n"
ss << " break;"
return ss.toString()
}
String print_signal_header() {
def ss = "" << ""
ss << " /** \\brief " << summary << "\n"
args.each {arg ->
ss << " \\param " << arg.name << " " << arg.summary << "\n"
}
ss << description << "\n"
ss << " */" << "\n"
def _args = []
args.each { a -> _args.add(a.print_type()) }
ss << " std::function<void(" + _args.join(", ") << ")> &on_" << name << "();\n"
return ss.toString()
}
String print_signal_body(String iface_name) {
def ss = "" << ""
def _args = []
args.each { arg-> _args.add(arg.print_type()) }
ss << "std::function<void(" << _args.join(", ") << ")> &" + iface_name +
"_t::on_" + name + "()\n{\n"
ss << " return std::static_pointer_cast<events_t>(get_events())->" + sanitise(name) + ";\n"
ss << "}\n\n"
return ss.toString()
}
String availability_function_name() {
return ((since > 1) ? "can_" + name : "")
}
String since_version_constant_name() {
return name + "_since_version"
}
String print_header() {
def ss = "" << ""
ss << " /** \\brief " << summary << "\n"
if (ret?.summary?.length() > 0)
ss << " \\return " << ret.summary << "\n"
args.each { arg ->
if (arg.type == "new_id") {
if (arg.iface.isEmpty()) {
ss << " \\param interface Interface to bind\n"
ss << " \\param version Interface version\n"
}
} else
ss << " \\param " << sanitise(arg.name) << " " << arg.summary << "\n"
}
ss << description << "\n"
ss << " */\n"
def _args = []
args.each { arg ->
if(arg.type == "new_id") {
if(arg.iface.empty)
_args.add("proxy_t &interface, uint32_t version")
}
else
_args.add(arg.print_argument())
}
_args.add("bool post = true")
ss << " void " << sanitise(name) << "(" << _args.join(", ") << ");\n"
ss << "\n"
ss << " /** \\brief Minimum protocol version required for the \\ref " << sanitise(name) << " function\n"
ss << " */\n"
ss << " static constexpr std::uint32_t " << since_version_constant_name() << " = " << since << ";\n"
if (!availability_function_name().isEmpty()) {
ss << "\n"
ss << " /** \\brief Check whether the \\ref " << name << " function is available with\n"
ss << " the currently bound version of the protocol\n"
ss << " */\n"
ss << " bool " << availability_function_name() << "() const;\n"
}
return ss.toString()
}
String print_body(String iface_name) {
def new_id_arg = false
def _args = []
args.each { arg ->
if(arg.type == "new_id") {
if(arg.iface.empty) {
_args.add("proxy_t &interface, uint32_t version")
new_id_arg = true
}
} else
_args.add(arg.print_argument())
}
_args.add("bool post")
def ss = "" << ""
ss << "void" << " " << iface_name << "_t::" << sanitise(name) << "("
ss << _args.join(", ") << ")\n{\n"
_args = []
args.each { arg ->
if(arg.type == "new_id") {
if(arg.iface.empty)
_args.add("std::string(interface.interface->name), version")
_args.add("nullptr")
}
else if(arg.type == "fd")
_args.add("argument_t::fd(" << sanitise(arg.name) << ")")
else if(arg.type == "object")
_args.add(sanitise(arg.name) << ".proxy_has_object() ? reinterpret_cast<wl_object*>(" << sanitise(arg.name) << ".c_ptr()) : nullptr")
else if(arg.enum_name != null && !arg.enum_name.empty)
_args.add("static_cast<" << arg.print_enum_wire_type() << ">(" << sanitise(arg.name) + ")")
else
_args.add(sanitise(arg.name))
}
ss << " send_event(post, " << opcode << ((args.size > 0) ? ", " << _args.join(", ") : "") << ");\n"
ss << "}\n"
if (!availability_function_name().isEmpty()) {
ss << "\n"
ss << "bool " << iface_name << "_t::" << availability_function_name() << "() const\n"
ss << "{\n"
ss << " return (get_version() >= " << since_version_constant_name() << ");\n"
ss << "}\n"
}
return ss.toString()
}
}
class request_t extends event_t {
}
class enum_entry_t extends element_t {
String value
}
class enumeration_t extends element_t {
List<enum_entry_t> entries
Boolean bitfield = false
int id = 0
int width = 0
String print_forward(String iface_name) {
if (!bitfield)
return "enum class " << iface_name << "_" << name << " : uint32_t;\n"
return "struct " << iface_name << "_" << name << ";\n"
}
String print_header(String iface_name) {
def ss = "" << ""
ss << "/** \\brief " << summary << "\n"
ss << description << "\n"
ss << " */\n"
if(!bitfield) {
ss << "enum class " << iface_name << "_" << name << " : uint32_t\n"
ss << " {\n"
} else {
ss << "struct " << iface_name << "_" << name << " : public wayland::detail::bitfield<" << width << ", " << id << ">\n"
ss << "{\n"
ss << " " << iface_name << "_" << name << "(const wayland::detail::bitfield<" << width << ", " << id << "> &b)\n"
ss << " : wayland::detail::bitfield<" << width << ", " << id << ">(b) {}\n"
ss << " " << iface_name << "_" << name << "(const uint32_t value)\n"
ss << " : wayland::detail::bitfield<" << width << ", " << id << ">(value) {}\n"
}
entries.each { entry ->
if (!entry.summary.isEmpty())
ss << " /** \\brief " << entry.summary << " */\n"
if (!bitfield)
ss << " " << sanitise(entry.name) << " = " << entry.value << ",\n"
else
ss << " static const wayland::detail::bitfield<" << width << ", " << id << "> " << sanitise(entry.name) << ";\n"
}
if (bitfield)
ss << "}\n"
ss.setLength(ss.length() - 2)
if (!bitfield)
ss << "\n"
ss << "};\n"
return ss.toString()
}
String print_body(String iface_name) {
def ss = "" << ""
if (bitfield)
entries.each { entry ->
ss << "const bitfield<" << width << ", " << id << "> " << iface_name << "_"
ss << name << "::" << sanitise(entry.name) << "{" << entry.value << "};\n"
}
return ss.toString()
}
}
class post_error_t extends element_t
{
String print_server_header() {
def ss = "" << ""
ss << " /** \\brief Post error: " << summary << "\n"
if(description?.length() > 0)
ss << " " << description << "\n"
ss << " */\n"
ss << " void post_" << name << "(std::string const& msg);\n"
return ss.toString()
}
String print_server_body(String iface_name) {
def ss = "" << ""
ss << "void " << iface_name << "_t::post_" << name << "(std::string const& msg)\n"
ss << "{\n"
ss << " post_error(static_cast<uint32_t>(" << iface_name << "_error::" << sanitise(name) << "), msg);\n"
ss << "}\n"
return ss.toString()
}
}
class interface_t extends element_t {
int version = 0
String orig_name
int destroy_opcode = 0
List<request_t> requests
List<event_t> events
List<enumeration_t> enums
List<post_error_t> errors
String print_forward() {
def ss = "" << ""
ss << "class " << name << "_t;\n"
enums.each { e -> ss << e.print_forward(name) }
return ss.toString()
}
String print_c_forward() {
def ss = "" << ""
ss << "struct " << orig_name << ";\n"
return ss.toString()
}
String print_server_header() {
def ss = "" << ""
ss << "/** \\brief " << summary << "\n"
ss << description << "\n"
ss << "*/\n"
ss << "class " << name << "_t : public resource_t\n"
ss << "{\n"
ss << "private:\n"
ss << " struct events_t : public resource_t::events_base_t\n"
ss << " {\n"
requests.each { request -> ss << request.print_functional() << "\n" }
ss << " };\n"
ss << "\n"
ss << " static int dispatcher(int opcode, const std::vector<wayland::detail::any>& args, const std::shared_ptr<resource_t::events_base_t>& e);\n"
ss << "\n"
ss << "protected:\n"
ss << " static constexpr const wl_interface *interface = &wayland::server::detail::" << name << "_interface;\n"
ss << " static constexpr const unsigned int max_version = " << version << ";\n"
ss << "\n"
ss << " friend class global_t<" << name << "_t>;\n"
ss << " friend class global_base_t;\n"
ss << "\n"
ss << "public:\n"
ss << " " << name << "_t() = default;\n"
ss << " " << name << "_t(const client_t& client, uint32_t id, int version = " << version << ");\n"
ss << " " << name << "_t(const resource_t &resource);\n"
ss << "\n"
ss << " static const std::string interface_name;\n"
ss << "\n"
ss << " operator " << orig_name << "*() const;\n"
ss << "\n"
requests.each { request -> ss << request.print_signal_header() << "\n" }
events.each { event -> ss << event.print_header() << "\n" }
errors.each { error -> ss << error.print_server_header() << "\n" }
ss << "};\n"
ss << "\n"
ss << "using global_" << name << "_t = global_t<" << name << "_t>;\n"
ss << "\n"
enums.each { e -> ss << e.print_header(name) << "\n" }
return ss.toString()
}
String print_interface_header() {
return " extern const wl_interface " << name << "_interface;\n"
}
String print_server_body() {
def ss = "" << ""
ss << name << "_t::" << name << "_t(const client_t& client, uint32_t id, int version)\n"
ss << " : resource_t(client, &server::detail::" << name << "_interface, id, version)\n"
ss << "{\n"
ss << " set_events(std::shared_ptr<resource_t::events_base_t>(new events_t), dispatcher);\n"
ss << "}\n"
ss << "\n"
ss << name << "_t::" << name << "_t(const resource_t &resource)\n"
ss << " : resource_t(resource)\n"
ss << "{\n"
ss << " set_events(std::shared_ptr<resource_t::events_base_t>(new events_t), dispatcher);\n"
ss << "}\n"
ss << "\n"
ss << "const std::string " << name << "_t::interface_name = \"" << orig_name << "\";\n"
ss << "\n"
ss << name << "_t::operator " << orig_name << "*() const\n"
ss << "{\n"
ss << " return reinterpret_cast<" << orig_name << "*> (c_ptr());\n"
ss << "}\n"
ss << "\n"
requests.each { request -> ss << request.print_signal_body(name) << "\n" }
events.each { event -> ss << event.print_body(name) << "\n" }
errors.each { error -> ss << error.print_server_body(name) << "\n" }
ss << "int " << name << "_t::dispatcher(int opcode, const std::vector<any>& args, const std::shared_ptr<resource_t::events_base_t>& e)\n"
ss << "{\n"
if(!requests.empty) {
ss << " std::shared_ptr<events_t> events = std::static_pointer_cast<events_t>(e);\n"
ss << " switch(opcode)\n"
ss << " {\n"
int opcode = 0
requests.each { request -> ss << request.print_dispatcher(opcode++) << "\n" }
ss << " }\n"
}
ss << " return 0;\n"
ss << "}\n"
enums.each { e -> ss << e.print_body(name) << "\n" }
return ss.toString()
}
String print_interface_body() {
def ss = "" << ""
requests.each { request ->
ss << "const wl_interface* " << name << "_interface_" << request.name << "_request_server" << "[" << request.args.size() << "] = {\n"
request.args.each { arg ->
if (!arg.iface.isEmpty())
ss << " &" << arg.iface << "_interface,\n"
else
ss << " nullptr,\n"
}
ss << "};\n"
ss << "\n"
}
events.each { event ->
ss << "const wl_interface* " << name << "_interface_" << event.name << "_event_server" << "[" << event.args.size() << "] = {\n"
event.args.each { arg ->
if (!arg.iface.isEmpty())
ss << " &" << arg.iface << "_interface,\n"
else
ss << " nullptr,\n"
}
ss << "};\n"
ss << "\n"
}
ss << "const wl_message " << name << "_interface_requests_server" << "[" << requests.size() << "] = {\n"
requests.each { request ->
ss << " {\n"
ss << " \"" << request.name << "\",\n"
ss << " \""
if (request.since > 1)
ss << request.since
request.args.each { arg ->
if (arg.allow_null)
ss << "?"
if (arg.type == "new_id" && arg.iface.empty)
ss << "su"
ss << arg.print_short()
}
ss << "\",\n"
ss << " " << name << "_interface_" << request.name << "_request_server" << ",\n"
ss << " },\n"
}
ss << "};\n"
ss << "\n"
ss << "const wl_message " << name << "_interface_events_server" << "[" << events.size() << "] = {\n"
events.each { event ->
ss << " {\n"
ss << " \"" << event.name << "\",\n"
ss << " \""
if(event.since > 1)
ss << event.since
event.args.each { arg ->
if(arg.allow_null)
ss << "?"
if(arg.type == "new_id" && arg.iface.empty)
ss << "su"
ss << arg.print_short()
}
ss << "\",\n"
ss << " " << name << "_interface_" << event.name << "_event_server" << ",\n"
ss << " },\n"
}
ss << "};\n"
ss << "\n"
ss << "const wl_interface wayland::server::detail::" << name << "_interface =\n"
ss << " {\n"
ss << " \"" << orig_name << "\",\n"
ss << " " << version << ",\n"
ss << " " << requests.size() << ",\n"
ss << " " << name << "_interface_requests_server" << ",\n"
ss << " " << events.size() << ",\n"
ss << " " << name << "_interface_events_server" << ",\n"
ss << " };\n"
ss << "\n"
return ss.toString()
}
}
static String unprefix(String name)
{
def prefix_len = name.indexOf('_')
if(prefix_len != -1) {
def prefix = name.substring(0, prefix_len)
if(prefix == "wl" || prefix == "wp")
return name.substring(prefix_len+1, name.size())
}
return name
}
boolean xmlValidate(File xmlFile, File schemaFile) {
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
try {
schemaFactory.newSchema(schemaFile)
.newValidator()
.validate(new StreamSource(xmlFile))
return true
} catch (SAXException e) {
println(xmlFile.toString() + " is NOT valid reason:" + e)
return false
} catch (IOException ignored) {
return false
}
}
@Input
abstract Property<String> getFrom()
WaylandScannerTask() {
from.convention('')
groovy.xml.slurpersupport.NodeChild.metaClass.children << { name ->
return delegate.depthFirst().findAll { t -> t.name() == name }
}
}
def parseXml(File xmlFile) {
File schemaFile = project.file("wayland.xsd")
xmlValidate(xmlFile, schemaFile)
List<interface_t> ifaces = new ArrayList<interface_t>()
def protocol = new XmlSlurper().parseText(xmlFile.getText())
int enum_id = 0
protocol.children("interface").each { iface ->
interface_t i = new interface_t()
i.requests = new ArrayList<request_t>()
i.events = new ArrayList<event_t>()
i.enums = new ArrayList<enumeration_t>()
i.errors = new ArrayList<post_error_t>()
i.destroy_opcode = -1
i.orig_name = iface.@name
i.name = unprefix([email protected]())
if (iface.@version != null)
i.version = [email protected]() as int
else
i.version = 1
if (iface.description) {
i.summary = iface.description.@summary
i.description = iface.description.text()
}
int opcode = 0 // Opcodes are in order of the XML. (Sadly undocumented)
iface.children("request").each { req ->
request_t r = new request_t()
r.name = req.@name
r.opcode = opcode++
r.args = new ArrayList<argument_t>()
if (req?.@since?.text()?.length() > 0)
r.since = [email protected]() as int
else
r.since = 1
if (req.description) {
r.summary = req.description.@summary
r.description = req.description.text()
}
// destruction takes place through the class destructor
if (req.@name == "destroy")
i.destroy_opcode = r.opcode
req.children("arg").each { arg ->
argument_t a = new argument_t()
a.name = arg.@name
a.type = arg.@type
a.summary = arg.@summary
a.iface = unprefix([email protected]())
String enum_val = arg.@enum
if (!enum_val.isEmpty()) {
if (enum_val.indexOf('.') == -1) {
a.enum_iface = i.name
a.enum_name = enum_val
} else {
a.enum_iface = unprefix(enum_val.substring(0, enum_val.indexOf('.')))
a.enum_name = enum_val.substring(enum_val.indexOf('.') + 1)
}
}
a.allow_null = arg.@"allow-null" == "true"
if (arg.@type == "new_id")
r.ret = a
r.args.add(a)
}
i.requests.add(r)
}
opcode = 0
iface.children("event").each { ev ->
event_t e = new event_t()
e.name = ev.@name
e.opcode = opcode++
e.args = new ArrayList<argument_t>()
if (ev?.@since?.text()?.length() > 0)
e.since = [email protected]() as int
else
e.since = 1
if (ev.description) {
e.summary = ev.description.@summary
e.description = ev.description.text()
}
ev.children("arg").each { arg ->
argument_t a = new argument_t()
a.name = arg.@name
a.type = arg.@type
a.summary = arg.@summary
a.iface = unprefix([email protected]())
String enum_val = [email protected]()
if (enum_val != null && !enum_val.isEmpty()) {
if (enum_val.indexOf('.') == -1) {
a.enum_iface = i.name
a.enum_name = enum_val
} else {
a.enum_iface = unprefix(enum_val.substring(0, enum_val.indexOf('.')))
a.enum_name = enum_val.substring(enum_val.indexOf('.') + 1)
}
}
a.allow_null = arg.@"allow-null" == "true"
if (arg.@type == "new_id")
e.ret = a
e.args.add(a)
}
i.events.add(e)
}
iface.children("enum").each { en ->
enumeration_t e = new enumeration_t()
e.name = en.@name
e.bitfield = (en.@bitfield == "true")
e.id = enum_id++
e.width = 0
e.entries = new ArrayList<enum_entry_t>()
if (en.description) {
e.summary = en.description.@summary
e.description = en.description.text()
}
en.children("entry").each { entry ->
enum_entry_t ent = new enum_entry_t()
ent.name = entry.@name
if (ent.name != null &&
(ent.name == "default" || Character.isDigit(ent.name.charAt(0))))
ent.name = "_" + ent.name
ent.value = entry.@value
ent.summary = entry.@summary
Long val
if (ent.value.startsWith("0x"))
val = Long.parseLong(ent.value.replace("0x", ""), 16)
else
val = Long.parseLong(ent.value)
int tmp = Math.log(val)/Math.log(2) + 1
if (e.width < tmp)
e.width = tmp
e.entries.add(ent)
if (e.name == "error") {
post_error_t error = new post_error_t()
error.name = ent.name
error.summary = ent.summary
error.description = ent.description
i.errors.add(error)
}
}
i.enums.add(e)
}
ifaces.add(i)
}
return ifaces
}
@TaskAction
def execute() {
if (from.get().isEmpty()) {
throw new Exception("from property is empty")
}
File xmlFile = project.file(from.get())
File outFolder = new File(project.buildDir, "/intermediates/generated/wayland")
File wayland_hpp = new File(outFolder, "/wayland.hpp")
File wayland_cpp = new File(outFolder, "/wayland.cpp")
outFolder.mkdirs()
wayland_hpp.text = ''
wayland_cpp.text = ''
def ifaces = parseXml(xmlFile)
// header intro
wayland_hpp << "#pragma once\n"
wayland_hpp << "\n"
wayland_hpp << "#include <array>\n"
wayland_hpp << "#include <functional>\n"
wayland_hpp << "#include <memory>\n"
wayland_hpp << "#include <string>\n"
wayland_hpp << "#include <vector>\n"
wayland_hpp << "\n"
wayland_hpp << "#include <wayland-server.hpp>\n"
wayland_hpp << "\n"
// C forward declarations
ifaces.each {iface ->
if(iface.name != "display")
wayland_hpp << iface.print_c_forward()
}
wayland_hpp << "\n"
wayland_hpp << "namespace wayland\n"
wayland_hpp << "{\n"
wayland_hpp << "namespace server\n"
wayland_hpp << "{\n"
// C++ forward declarations
ifaces.each { iface ->
if(iface.name != "display")
wayland_hpp << iface.print_forward()
}
wayland_hpp << "\n"
// interface headers
wayland_hpp << "namespace detail\n"
wayland_hpp << "{\n"
ifaces.each { iface ->
wayland_hpp << iface.print_interface_header()
}
wayland_hpp << "}\n"
wayland_hpp << "\n"
// class declarations
ifaces.each { iface ->
if(iface.name != "display") {
wayland_hpp << iface.print_server_header() << "\n"
}
}
wayland_hpp << "\n"
wayland_hpp << "}\n"
wayland_hpp << "}\n"
// body intro
wayland_cpp << "#include <" << wayland_hpp.getName() << ">\n"
wayland_cpp << "\n"
wayland_cpp << "using namespace wayland;\n"
wayland_cpp << "using namespace wayland::detail;\n"
wayland_cpp << "using namespace wayland::server;\n"
wayland_cpp << "using namespace wayland::server::detail;\n"
wayland_cpp << "\n"
// interface bodies
ifaces.each { iface -> wayland_cpp << iface.print_interface_body() }
// class member definitions
ifaces.each { iface ->
if(iface.name != "display") {
wayland_cpp << iface.print_server_body() << "\n"
}
}
wayland_cpp << "\n"
}
}
tasks.register('scanner',WaylandScannerTask) {
from = 'wayland.xml'
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit. This document is automatically generated
from wayland.dtd using IntelliJ Idea's XML Actions... -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="protocol">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="copyright"/>
<xs:element minOccurs="0" ref="description"/>
<xs:element maxOccurs="unbounded" ref="interface"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="copyright" type="xs:string"/>
<xs:element name="interface">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="description"/>
<xs:choice maxOccurs="unbounded">
<xs:element ref="request"/>
<xs:element ref="event"/>
<xs:element ref="enum"/>
</xs:choice>
</xs:sequence>
<xs:attribute name="name" use="required"/>
<xs:attribute name="version" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="request">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="description"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="arg"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
<xs:attribute name="type"/>
<xs:attribute name="since"/>
</xs:complexType>
</xs:element>
<xs:element name="event">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="description"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="arg"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
<xs:attribute name="type"/>
<xs:attribute name="since"/>
</xs:complexType>
</xs:element>
<xs:element name="enum">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="description"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="entry"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
<xs:attribute name="since"/>
<xs:attribute name="bitfield"/>
</xs:complexType>
</xs:element>
<xs:element name="entry">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="description"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
<xs:attribute name="value" use="required"/>
<xs:attribute name="summary"/>
<xs:attribute name="since"/>
</xs:complexType>
</xs:element>
<xs:element name="arg">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="description"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
<xs:attribute name="type" use="required"/>
<xs:attribute name="summary"/>
<xs:attribute name="interface"/>
<xs:attribute name="allow-null"/>
<xs:attribute name="enum"/>
</xs:complexType>
</xs:element>
<xs:element name="description">
<xs:complexType mixed="true">
<xs:attribute name="summary" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment