diff options
author | Samuel Rødal <samuel.rodal@digia.com> | 2013-04-09 16:52:59 +0200 |
---|---|---|
committer | Jørgen Lind <jorgen.lind@digia.com> | 2013-04-17 09:30:31 +0200 |
commit | 05d054ad7207764293525661876ebc689940a15c (patch) | |
tree | 192bd81afc1acb656155ccbfcfc8ac92feafdacc | |
parent | e5601d283c4d9a5c43352b6f1acd0e1968a31b83 (diff) |
Introduced qtwaylandscanner.
Generates C++ headers with Qt types based on the Wayland XML protocol files,
to reduce a lot of code duplication in all the places that interface between
Qt and the wayland protocol headers.
Change-Id: I34a4417d3d3d0238de2f2f74986855d097b50ec9
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
-rw-r--r-- | src/qtwaylandscanner/qtwaylandscanner.cpp | 1033 | ||||
-rw-r--r-- | src/qtwaylandscanner/qtwaylandscanner.pro | 8 | ||||
-rw-r--r-- | src/src.pro | 2 |
3 files changed, 1043 insertions, 0 deletions
diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp new file mode 100644 index 000000000..86fc4937c --- /dev/null +++ b/src/qtwaylandscanner/qtwaylandscanner.cpp @@ -0,0 +1,1033 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QCoreApplication> +#include <QFile> +#include <QXmlStreamReader> + +enum Option { + ClientHeader, + ServerHeader, + ClientCode, + ServerCode +} option; + +bool isServerSide() +{ + return option == ServerHeader || option == ServerCode; +} + +QByteArray protocolName; + +bool parseOption(const char *str, Option *option) +{ + if (str == QLatin1String("client-header")) + *option = ClientHeader; + else if (str == QLatin1String("server-header")) + *option = ServerHeader; + else if (str == QLatin1String("client-code")) + *option = ClientCode; + else if (str == QLatin1String("server-code")) + *option = ServerCode; + else + return false; + + return true; +} + +struct WaylandEnumEntry { + QByteArray name; + int value; + QByteArray summary; +}; + +struct WaylandEnum { + QByteArray name; + + QList<WaylandEnumEntry> entries; +}; + +struct WaylandArgument { + QByteArray name; + QByteArray type; + QByteArray interface; + QByteArray summary; + bool allowNull; +}; + +struct WaylandEvent { + bool request; + QByteArray name; + QList<WaylandArgument> arguments; +}; + +struct WaylandInterface { + QByteArray name; + int version; + + QList<WaylandEnum> enums; + QList<WaylandEvent> events; + QList<WaylandEvent> requests; +}; + +QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name) +{ + if (xml.attributes().hasAttribute(name)) + return xml.attributes().value(name).toUtf8(); + return QByteArray(); +} + +int intValue(const QXmlStreamReader &xml, const char *name, int defaultValue = 0) +{ + bool ok; + int result = byteArrayValue(xml, name).toInt(&ok); + return ok ? result : defaultValue; +} + +bool boolValue(const QXmlStreamReader &xml, const char *name) +{ + return byteArrayValue(xml, name) == "true"; +} + +WaylandEvent readEvent(QXmlStreamReader &xml, bool request) +{ + WaylandEvent event; + event.request = request; + event.name = byteArrayValue(xml, "name"); + while (xml.readNextStartElement()) { + if (xml.name() == "arg") { + WaylandArgument argument; + argument.name = byteArrayValue(xml, "name"); + argument.type = byteArrayValue(xml, "type"); + argument.interface = byteArrayValue(xml, "interface"); + argument.summary = byteArrayValue(xml, "summary"); + argument.allowNull = boolValue(xml, "allowNull"); + event.arguments << argument; + } + + xml.skipCurrentElement(); + } + return event; +} + +WaylandEnum readEnum(QXmlStreamReader &xml) +{ + WaylandEnum result; + result.name = byteArrayValue(xml, "name"); + + while (xml.readNextStartElement()) { + if (xml.name() == "entry") { + WaylandEnumEntry entry; + entry.name = byteArrayValue(xml, "name"); + entry.value = intValue(xml, "value"); + entry.summary = byteArrayValue(xml, "summary"); + result.entries << entry; + } + + xml.skipCurrentElement(); + } + + return result; +} + +WaylandInterface readInterface(QXmlStreamReader &xml) +{ + WaylandInterface interface; + interface.name = byteArrayValue(xml, "name"); + interface.version = intValue(xml, "name", 1); + + while (xml.readNextStartElement()) { + if (xml.name() == "event") + interface.events << readEvent(xml, false); + else if (xml.name() == "request") + interface.requests << readEvent(xml, true); + else if (xml.name() == "enum") + interface.enums << readEnum(xml); + else + xml.skipCurrentElement(); + } + + return interface; +} + +QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface) +{ + if (waylandType == "string") + return "const char *"; + else if (waylandType == "int") + return "int32_t"; + else if (waylandType == "uint") + return "uint32_t"; + else if (waylandType == "fixed") + return "wl_fixed_t"; + else if (waylandType == "fd") + return "int32_t"; + else if (waylandType == "array") + return "wl_array *"; + else if (waylandType == "object" || waylandType == "new_id") + return isServerSide() ? "struct ::wl_resource *" : interface.isEmpty() ? "struct ::wl_object *" : "struct ::" + interface + " *"; + return waylandType; +} + +QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray) +{ + if (waylandType == "string") + return "const QString &"; + else if (waylandType == "array") + return cStyleArray ? "wl_array *" : "const QByteArray &"; + else + return waylandToCType(waylandType, interface); +} + +const WaylandArgument *newIdArgument(const QList<WaylandArgument> &arguments) +{ + for (int i = 0; i < arguments.size(); ++i) { + if (arguments.at(i).type == "new_id") + return &arguments.at(i); + } + return 0; +} + +void printEvent(const WaylandEvent &e, const char *interfaceName, bool omitNames = false, bool withResource = false) +{ + printf("%s(", e.name.constData()); + bool needsComma = false; + if (isServerSide()) { + if (e.request) { + printf("Resource *%s", omitNames ? "" : "resource"); + needsComma = true; + } else if (withResource) { + printf("struct ::wl_resource *%s", omitNames ? "" : "resource"); + needsComma = true; + } + } + for (int i = 0; i < e.arguments.size(); ++i) { + const WaylandArgument &a = e.arguments.at(i); + bool isNewId = a.type == "new_id"; + if (isNewId && !isServerSide() && (a.interface.isEmpty() != e.request)) + continue; + if (needsComma) + printf(", "); + needsComma = true; + if (isNewId) { + if (isServerSide()) { + if (e.request) { + printf("uint32_t"); + if (!omitNames) + printf(" %s", a.name.constData()); + continue; + } + } else { + if (e.request) { + printf("const struct ::wl_interface *%s, uint32_t%s", omitNames ? "" : "interface", omitNames ? "" : " version"); + continue; + } + + printf("struct ::%s *%s, ", interfaceName, omitNames ? "" : "object"); + } + } + + QByteArray qtType = waylandToQtType(a.type, a.interface, e.request == isServerSide()); + printf("%s%s%s", qtType.constData(), qtType.endsWith("&") || qtType.endsWith("*") ? "" : " ", omitNames ? "" : a.name.constData()); + } + printf(")"); +} + +void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true) +{ + const char *indent = deepIndent ? " " : ""; + printf("handle_%s(\n", e.name.constData()); + if (isServerSide()) { + printf(" %s::wl_client *client,\n", indent); + printf(" %sstruct wl_resource *resource", indent); + } else { + printf(" %svoid *data,\n", indent); + printf(" %sstruct ::%s *object", indent, interfaceName); + } + for (int i = 0; i < e.arguments.size(); ++i) { + printf(",\n"); + const WaylandArgument &a = e.arguments.at(i); + bool isNewId = a.type == "new_id"; + if (isServerSide() && isNewId) { + printf(" %suint32_t %s", indent, a.name.constData()); + } else { + QByteArray cType = waylandToCType(a.type, a.interface); + printf(" %s%s%s%s", indent, cType.constData(), cType.endsWith("*") ? "" : " ", a.name.constData()); + } + } + printf(")"); +} + +void printEnums(const QList<WaylandEnum> &enums) +{ + for (int i = 0; i < enums.size(); ++i) { + printf("\n"); + const WaylandEnum &e = enums.at(i); + printf(" enum %s {\n", e.name.constData()); + for (int i = 0; i < e.entries.size(); ++i) { + const WaylandEnumEntry &entry = e.entries.at(i); + printf(" %s_%s = %d", e.name.constData(), entry.name.constData(), entry.value); + if (i < e.entries.size() - 1) + printf(","); + if (!entry.summary.isNull()) + printf(" // %s", entry.summary.constData()); + printf("\n"); + } + printf(" };\n"); + } +} + +QByteArray stripInterfaceName(const QByteArray &name) +{ + if (name.startsWith("qt_") || name.startsWith("wl_")) + return name.mid(3); + + return name; +} + +bool ignoreInterface(const QByteArray &name) +{ + return name == "wl_display" + || (isServerSide() && name == "wl_registry"); +} + +void process(QXmlStreamReader &xml) +{ + if (!xml.readNextStartElement()) + return; + + if (xml.name() != "protocol") { + xml.raiseError(QStringLiteral("The file is not a wayland protocol file.")); + return; + } + + protocolName = byteArrayValue(xml, "name"); + + if (protocolName.isEmpty()) { + xml.raiseError(QStringLiteral("Missing protocol name.")); + return; + } + + QList<WaylandInterface> interfaces; + + while (xml.readNextStartElement()) { + if (xml.name() == "interface") + interfaces << readInterface(xml); + else + xml.skipCurrentElement(); + } + + if (xml.hasError()) + return; + + if (option == ServerHeader) { + QByteArray inclusionGuard = "QT_WAYLAND_SERVER_" + protocolName.toUpper(); + printf("#ifndef %s\n", inclusionGuard.constData()); + printf("#define %s\n", inclusionGuard.constData()); + printf("\n"); + printf("#include \"wayland-server.h\"\n"); + printf("#include \"wayland-server-protocol.h\"\n"); + printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + printf("#include <QByteArray>\n"); + printf("#include <QString>\n"); + printf("\n"); + printf("QT_BEGIN_NAMESPACE\n"); + printf("\n"); + printf("namespace QtWaylandServer {\n"); + + for (int j = 0; j < interfaces.size(); ++j) { + const WaylandInterface &interface = interfaces.at(j); + + if (ignoreInterface(interface.name)) + continue; + + const char *interfaceName = interface.name.constData(); + + QByteArray stripped = stripInterfaceName(interface.name); + const char *interfaceNameStripped = stripped.constData(); + + printf(" class %s\n {\n", interfaceName); + printf(" public:\n"); + printf(" %s(struct ::wl_client *client, int id);\n", interfaceName); + printf(" %s(struct ::wl_display *display);\n", interfaceName); + printf(" %s();\n", interfaceName); + printf("\n"); + printf(" virtual ~%s();\n", interfaceName); + printf("\n"); + printf(" class Resource\n"); + printf(" {\n"); + printf(" public:\n"); + printf(" Resource() : %s(0), handle(0) {}\n", interfaceNameStripped); + printf(" virtual ~Resource() {}\n"); + printf("\n"); + printf(" %s *%s;\n", interfaceName, interfaceNameStripped); + printf(" struct ::wl_resource *handle;\n"); + printf("\n"); + printf(" struct ::wl_client *client() const { return handle->client; }\n"); + printf("\n"); + printf(" static Resource *fromResource(struct ::wl_resource *resource) { return static_cast<Resource *>(resource->data); }\n"); + printf(" };\n"); + printf("\n"); + printf(" void init(struct ::wl_client *client, int id);\n"); + printf(" void init(struct ::wl_display *display);\n"); + printf("\n"); + printf(" Resource *add(struct ::wl_client *client, int id);\n"); + printf(" Resource *add(struct wl_list *resource_list, struct ::wl_client *client, int id);\n"); + printf("\n"); + printf(" Resource *resource() { return m_resource; }\n"); + printf(" const Resource *resource() const { return m_resource; }\n"); + printf("\n"); + printf(" struct ::wl_list *resourceList() { return &m_resource_list; }\n"); + printf(" const struct ::wl_list *resourceList() const { return &m_resource_list; }\n"); + printf("\n"); + printf(" bool isGlobal() const { return m_global != 0; }\n"); + printf(" bool isResource() const { return m_resource != 0; }\n"); + + printEnums(interface.enums); + + bool hasEvents = !interface.events.isEmpty(); + + if (hasEvents) { + printf("\n"); + foreach (const WaylandEvent &e, interface.events) { + printf(" void send_"); + printEvent(e, interfaceName); + printf(";\n"); + printf(" void send_"); + printEvent(e, interfaceName, false, true); + printf(";\n"); + } + } + + printf("\n"); + printf(" protected:\n"); + printf(" virtual Resource *%s_allocate();\n", interfaceNameStripped); + printf("\n"); + printf(" virtual void %s_bind_resource(Resource *resource);\n", interfaceNameStripped); + printf(" virtual void %s_destroy_resource(Resource *resource);\n", interfaceNameStripped); + + bool hasRequests = !interface.requests.isEmpty(); + + if (hasRequests) { + printf("\n"); + foreach (const WaylandEvent &e, interface.requests) { + printf(" virtual void %s_", interfaceNameStripped); + printEvent(e, interfaceName); + printf(";\n"); + } + } + + printf("\n"); + printf(" private:\n"); + printf(" static void bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id);\n"); + printf(" static void destroy_func(struct ::wl_resource *client_resource);\n"); + printf("\n"); + printf(" Resource *bind(struct ::wl_client *client, uint32_t id);\n"); + + if (hasRequests) { + printf("\n"); + printf(" static const struct ::%s_interface m_%s_interface;\n", interfaceName, interfaceName); + + printf("\n"); + for (int i = 0; i < interface.requests.size(); ++i) { + const WaylandEvent &e = interface.requests.at(i); + printf(" static void "); + + printEventHandlerSignature(e, interfaceName); + printf(";\n"); + } + } + + printf("\n"); + printf(" Resource *m_resource;\n"); + printf(" struct ::wl_list m_resource_list;\n"); + printf(" struct ::wl_global *m_global;\n"); + printf(" };\n"); + + if (j < interfaces.size() - 1) + printf("\n"); + } + + printf("}\n"); + printf("\n"); + printf("QT_END_NAMESPACE\n"); + printf("\n"); + printf("#endif\n"); + } + + if (option == ServerCode) { + printf("#include \"qwayland-server-%s.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + printf("\n"); + printf("QT_BEGIN_NAMESPACE\n"); + printf("\n"); + printf("namespace QtWaylandServer {\n"); + + bool needsNewLine = false; + for (int j = 0; j < interfaces.size(); ++j) { + const WaylandInterface &interface = interfaces.at(j); + + if (ignoreInterface(interface.name)) + continue; + + if (needsNewLine) + printf("\n"); + + needsNewLine = true; + + const char *interfaceName = interface.name.constData(); + + QByteArray stripped = stripInterfaceName(interface.name); + const char *interfaceNameStripped = stripped.constData(); + + printf(" %s::%s(struct ::wl_client *client, int id)\n", interfaceName, interfaceName); + printf(" : m_resource(0)\n"); + printf(" , m_global(0)\n"); + printf(" {\n"); + printf(" wl_list_init(&m_resource_list);\n"); + printf(" init(client, id);\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::%s(struct ::wl_display *display)\n", interfaceName, interfaceName); + printf(" : m_resource(0)\n"); + printf(" , m_global(0)\n"); + printf(" {\n"); + printf(" wl_list_init(&m_resource_list);\n"); + printf(" init(display);\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::%s()\n", interfaceName, interfaceName); + printf(" : m_resource(0)\n"); + printf(" , m_global(0)\n"); + printf(" {\n"); + printf(" wl_list_init(&m_resource_list);\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::~%s()\n", interfaceName, interfaceName); + printf(" {\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::init(struct ::wl_client *client, int id)\n", interfaceName); + printf(" {\n"); + printf(" m_resource = bind(client, id);\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::Resource *%s::add(struct ::wl_client *client, int id)\n", interfaceName, interfaceName); + printf(" {\n"); + printf(" return add(&m_resource_list, client, id);\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::Resource *%s::add(struct wl_list *resource_list, struct ::wl_client *client, int id)\n", interfaceName, interfaceName); + printf(" {\n"); + printf(" Resource *resource = bind(client, id);\n"); + printf(" wl_list_insert(resource_list, &resource->handle->link);\n"); + printf(" return resource;\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::init(struct ::wl_display *display)\n", interfaceName); + printf(" {\n"); + printf(" m_global = wl_display_add_global(display, &::%s_interface, this, bind_func);\n", interfaceName); + printf(" }\n"); + printf("\n"); + + printf(" %s::Resource *%s::%s_allocate()\n", interfaceName, interfaceName, interfaceNameStripped); + printf(" {\n"); + printf(" return new Resource;\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::%s_bind_resource(Resource *)\n", interfaceName, interfaceNameStripped); + printf(" {\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::%s_destroy_resource(Resource *)\n", interfaceName, interfaceNameStripped); + printf(" {\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id)\n", interfaceName); + printf(" {\n"); + printf(" Q_UNUSED(version);\n"); + printf(" %s *that = static_cast<%s *>(data);\n", interfaceName, interfaceName); + printf(" Resource *resource = that->bind(client, id);\n"); + printf(" resource->handle->destroy = destroy_func;\n"); + printf(" that->%s_bind_resource(resource);\n", interfaceNameStripped); + printf(" }\n"); + printf("\n"); + + printf(" void %s::destroy_func(struct ::wl_resource *client_resource)\n", interfaceName); + printf(" {\n"); + printf(" Resource *resource = Resource::fromResource(client_resource);\n"); + printf(" %s *that = resource->%s;\n", interfaceName, interfaceNameStripped); + printf(" that->%s_destroy_resource(resource);\n", interfaceNameStripped); + printf(" if (client_resource->link.next)\n"); + printf(" wl_list_remove(&client_resource->link);\n"); + printf(" delete resource;\n"); + printf(" free(client_resource);\n"); + printf(" }\n"); + printf("\n"); + + bool hasRequests = !interface.requests.isEmpty(); + + printf(" %s::Resource *%s::bind(struct ::wl_client *client, uint32_t id)\n", interfaceName, interfaceName); + printf(" {\n"); + printf(" Resource *resource = %s_allocate();\n", interfaceNameStripped); + printf(" resource->%s = this;\n", interfaceNameStripped); + if (hasRequests) + printf(" resource->handle = wl_client_add_object(client, &::%s_interface, &m_%s_interface, id, resource);\n", interfaceName, interfaceName); + else + printf(" resource->handle = wl_client_add_object(client, &::%s_interface, 0, id, resource);\n", interfaceName); + printf(" wl_list_init(&resource->handle->link);\n"); + printf(" return resource;\n"); + printf(" }\n"); + + if (hasRequests) { + printf("\n"); + printf(" const struct ::%s_interface %s::m_%s_interface = {", interfaceName, interfaceName, interfaceName); + for (int i = 0; i < interface.requests.size(); ++i) { + if (i > 0) + printf(","); + printf("\n"); + const WaylandEvent &e = interface.requests.at(i); + printf(" %s::handle_%s", interfaceName, e.name.constData()); + } + printf("\n"); + printf(" };\n"); + + foreach (const WaylandEvent &e, interface.requests) { + printf("\n"); + printf(" void %s::%s_", interfaceName, interfaceNameStripped); + printEvent(e, interfaceName, true); + printf("\n"); + printf(" {\n"); + printf(" }\n"); + } + printf("\n"); + + for (int i = 0; i < interface.requests.size(); ++i) { + printf("\n"); + printf(" void %s::", interfaceName); + + const WaylandEvent &e = interface.requests.at(i); + printEventHandlerSignature(e, interfaceName, false); + + printf("\n"); + printf(" {\n"); + printf(" Q_UNUSED(client);\n"); + printf(" Resource *r = Resource::fromResource(resource);\n"); + printf(" static_cast<%s *>(r->%s)->%s_%s(\n", interfaceName, interfaceNameStripped, interfaceNameStripped, e.name.constData()); + printf(" r"); + for (int i = 0; i < e.arguments.size(); ++i) { + printf(",\n"); + const WaylandArgument &a = e.arguments.at(i); + QByteArray cType = waylandToCType(a.type, a.interface); + QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); + const char *argumentName = a.name.constData(); + if (cType == qtType) + printf(" %s", argumentName); + else if (a.type == "string") + printf(" QString::fromUtf8(%s)", argumentName); + } + printf(");\n"); + printf(" }\n"); + } + } + + for (int i = 0; i < interface.events.size(); ++i) { + printf("\n"); + const WaylandEvent &e = interface.events.at(i); + printf(" void %s::send_", interfaceName); + printEvent(e, interfaceName); + printf("\n"); + printf(" {\n"); + printf(" send_%s(\n", e.name.constData()); + printf(" m_resource->handle"); + for (int i = 0; i < e.arguments.size(); ++i) { + const WaylandArgument &a = e.arguments.at(i); + printf(",\n"); + printf(" %s", a.name.constData()); + } + printf(");\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::send_", interfaceName); + printEvent(e, interfaceName, false, true); + printf("\n"); + printf(" {\n"); + + for (int i = 0; i < e.arguments.size(); ++i) { + const WaylandArgument &a = e.arguments.at(i); + if (a.type != "array") + continue; + QByteArray array = a.name + "_data"; + const char *arrayName = array.constData(); + const char *variableName = a.name.constData(); + printf(" struct wl_array %s;\n", arrayName); + printf(" %s.size = %s.size();\n", arrayName, variableName); + printf(" %s.data = static_cast<void *>(const_cast<char *>(%s.constData()));\n", arrayName, variableName); + printf(" %s.alloc = 0;\n", arrayName); + printf("\n"); + } + + printf(" %s_send_%s(\n", interfaceName, e.name.constData()); + printf(" resource"); + + for (int i = 0; i < e.arguments.size(); ++i) { + const WaylandArgument &a = e.arguments.at(i); + printf(",\n"); + QByteArray cType = waylandToCType(a.type, a.interface); + QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); + if (a.type == "string") + printf(" %s.toUtf8().constData()", a.name.constData()); + else if (a.type == "array") + printf(" &%s_data", a.name.constData()); + else if (cType == qtType) + printf(" %s", a.name.constData()); + } + + printf(");\n"); + printf(" }\n"); + printf("\n"); + } + } + printf("}\n"); + printf("\n"); + printf("QT_END_NAMESPACE\n"); + } + + if (option == ClientHeader) { + QByteArray inclusionGuard = "QT_WAYLAND_" + protocolName.toUpper(); + printf("#ifndef %s\n", inclusionGuard.constData()); + printf("#define %s\n", inclusionGuard.constData()); + printf("\n"); + printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + printf("#include <QByteArray>\n"); + printf("#include <QString>\n"); + printf("\n"); + printf("QT_BEGIN_NAMESPACE\n"); + printf("\n"); + printf("namespace QtWayland {\n"); + for (int j = 0; j < interfaces.size(); ++j) { + const WaylandInterface &interface = interfaces.at(j); + + if (ignoreInterface(interface.name)) + continue; + + const char *interfaceName = interface.name.constData(); + + QByteArray stripped = stripInterfaceName(interface.name); + const char *interfaceNameStripped = stripped.constData(); + + printf(" class %s\n {\n", interfaceName); + printf(" public:\n"); + printf(" %s(struct ::wl_registry *registry, int id);\n", interfaceName); + printf(" %s(struct ::%s *object);\n", interfaceName, interfaceName); + printf(" %s();\n", interfaceName); + printf("\n"); + printf(" virtual ~%s();\n", interfaceName); + printf("\n"); + printf(" void init(struct ::wl_registry *registry, int id);\n"); + printf(" void init(struct ::%s *object);\n", interfaceName); + printf("\n"); + printf(" struct ::%s *object() { return m_%s; }\n", interfaceName, interfaceName); + printf(" const struct ::%s *object() const { return m_%s; }\n", interfaceName, interfaceName); + printf("\n"); + printf(" bool isInitialized() const;\n"); + + printEnums(interface.enums); + + if (!interface.requests.isEmpty()) { + printf("\n"); + foreach (const WaylandEvent &e, interface.requests) { + const WaylandArgument *new_id = newIdArgument(e.arguments); + printf(" %s", new_id ? (new_id->interface.isEmpty() ? "void *" : "struct ::" + new_id->interface + " *").constData() : "void "); + printEvent(e, interfaceName); + printf(";\n"); + } + } + + bool hasEvents = !interface.events.isEmpty(); + + if (hasEvents) { + printf("\n"); + printf(" protected:\n"); + foreach (const WaylandEvent &e, interface.events) { + printf(" virtual void %s_", interfaceNameStripped); + printEvent(e, interfaceName); + printf(";\n"); + } + } + + printf("\n"); + printf(" private:\n"); + if (hasEvents) { + printf(" void init_listener();\n"); + printf(" static const struct %s_listener m_%s_listener;\n", interfaceName, interfaceName); + for (int i = 0; i < interface.events.size(); ++i) { + const WaylandEvent &e = interface.events.at(i); + printf(" static void "); + + printEventHandlerSignature(e, interfaceName); + printf(";\n"); + } + } + printf(" struct ::%s *m_%s;\n", interfaceName, interfaceName); + printf(" };\n"); + + if (j < interfaces.size() - 1) + printf("\n"); + } + printf("}\n"); + printf("\n"); + printf("QT_END_NAMESPACE\n"); + printf("\n"); + printf("#endif\n"); + } + + if (option == ClientCode) { + printf("#include \"qwayland-%s.h\"\n", QByteArray(protocolName).replace('_', '-').constData()); + printf("\n"); + printf("QT_BEGIN_NAMESPACE\n"); + printf("\n"); + printf("namespace QtWayland {\n"); + for (int j = 0; j < interfaces.size(); ++j) { + const WaylandInterface &interface = interfaces.at(j); + + if (ignoreInterface(interface.name)) + continue; + + const char *interfaceName = interface.name.constData(); + + QByteArray stripped = stripInterfaceName(interface.name); + const char *interfaceNameStripped = stripped.constData(); + + bool hasEvents = !interface.events.isEmpty(); + + printf(" %s::%s(struct ::wl_registry *registry, int id)\n", interfaceName, interfaceName); + printf(" {\n"); + printf(" init(registry, id);\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::%s(struct ::%s *obj)\n", interfaceName, interfaceName, interfaceName); + printf(" : m_%s(obj)\n", interfaceName); + printf(" {\n"); + if (hasEvents) + printf(" init_listener();\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::%s()\n", interfaceName, interfaceName); + printf(" : m_%s(0)\n", interfaceName); + printf(" {\n"); + printf(" }\n"); + printf("\n"); + + printf(" %s::~%s()\n", interfaceName, interfaceName); + printf(" {\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::init(struct ::wl_registry *registry, int id)\n", interfaceName); + printf(" {\n"); + printf(" m_%s = static_cast<struct ::%s *>(wl_registry_bind(registry, id, &%s_interface, %d));\n", interfaceName, interfaceName, interfaceName, interface.version); + if (hasEvents) + printf(" init_listener();\n"); + printf(" }\n"); + printf("\n"); + + printf(" void %s::init(struct ::%s *obj)\n", interfaceName, interfaceName); + printf(" {\n"); + printf(" m_%s = obj;\n", interfaceName); + if (hasEvents) + printf(" init_listener();\n"); + printf(" }\n"); + printf("\n"); + + printf(" bool %s::isInitialized() const\n", interfaceName); + printf(" {\n"); + printf(" return m_%s != 0;\n", interfaceName); + printf(" }\n"); + + for (int i = 0; i < interface.requests.size(); ++i) { + printf("\n"); + const WaylandEvent &e = interface.requests.at(i); + const WaylandArgument *new_id = newIdArgument(e.arguments); + printf(" %s%s::", new_id ? (new_id->interface.isEmpty() ? "void *" : "struct ::" + new_id->interface + " *").constData() : "void ", interfaceName); + printEvent(e, interfaceName); + printf("\n"); + printf(" {\n"); + for (int i = 0; i < e.arguments.size(); ++i) { + const WaylandArgument &a = e.arguments.at(i); + if (a.type != "array") + continue; + QByteArray array = a.name + "_data"; + const char *arrayName = array.constData(); + const char *variableName = a.name.constData(); + printf(" struct wl_array %s;\n", arrayName); + printf(" %s.size = %s.size();\n", arrayName, variableName); + printf(" %s.data = static_cast<void *>(const_cast<char *>(%s.constData()));\n", arrayName, variableName); + printf(" %s.alloc = 0;\n", arrayName); + printf("\n"); + } + int actualArgumentCount = new_id ? e.arguments.size() - 1 : e.arguments.size(); + printf(" %s%s_%s(\n", new_id ? "return " : "", interfaceName, e.name.constData()); + printf(" m_%s%s", interfaceName, actualArgumentCount > 0 ? "," : ""); + bool needsComma = false; + for (int i = 0; i < e.arguments.size(); ++i) { + const WaylandArgument &a = e.arguments.at(i); + bool isNewId = a.type == "new_id"; + if (isNewId && !a.interface.isEmpty()) + continue; + if (needsComma) + printf(","); + needsComma = true; + printf("\n"); + if (isNewId) { + printf(" interface,\n"); + printf(" version"); + } else { + QByteArray cType = waylandToCType(a.type, a.interface); + QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); + if (a.type == "string") + printf(" %s.toUtf8().constData()", a.name.constData()); + else if (a.type == "array") + printf(" &%s_data", a.name.constData()); + else if (cType == qtType) + printf(" %s", a.name.constData()); + } + } + printf(");\n"); + printf(" }\n"); + } + + if (hasEvents) { + printf("\n"); + for (int i = 0; i < interface.events.size(); ++i) { + const WaylandEvent &e = interface.events.at(i); + printf(" void %s::%s_", interfaceName, interfaceNameStripped); + printEvent(e, interfaceName, true); + printf("\n"); + printf(" {\n"); + printf(" }\n"); + printf("\n"); + printf(" void %s::", interfaceName); + printEventHandlerSignature(e, interfaceName, false); + printf("\n"); + printf(" {\n"); + if (!newIdArgument(e.arguments)) + printf(" Q_UNUSED(object);\n"); + printf(" static_cast<%s *>(data)->%s_%s(", interfaceName, interfaceNameStripped, e.name.constData()); + for (int i = 0; i < e.arguments.size(); ++i) { + printf("\n"); + const WaylandArgument &a = e.arguments.at(i); + QByteArray cType = waylandToCType(a.type, a.interface); + QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); + const char *argumentName = a.name.constData(); + if (a.type == "new_id") + printf(" object,\n"); + if (a.type == "string") + printf(" QString::fromUtf8(%s)", argumentName); + else + printf(" %s", argumentName); + + if (i < e.arguments.size() - 1) + printf(","); + } + printf(");\n"); + + printf(" }\n"); + printf("\n"); + } + printf(" const struct %s_listener %s::m_%s_listener = {\n", interfaceName, interfaceName, interfaceName); + for (int i = 0; i < interface.events.size(); ++i) { + const WaylandEvent &e = interface.events.at(i); + printf(" %s::handle_%s%s\n", interfaceName, e.name.constData(), i < interface.events.size() - 1 ? "," : ""); + } + printf(" };\n"); + printf("\n"); + + printf(" void %s::init_listener()\n", interfaceName); + printf(" {\n"); + printf(" %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName); + printf(" }\n"); + } + + if (j < interfaces.size() - 1) + printf("\n"); + } + printf("}\n"); + printf("\n"); + printf("QT_END_NAMESPACE\n"); + } +} + +int main(int argc, char **argv) +{ + if (argc <= 2 || !parseOption(argv[1], &option)) { + fprintf(stderr, "Usage: %s [client-header|server-header|client-code|server-code] specfile\n", argv[0]); + return 1; + } + + QCoreApplication app(argc, argv); + + QFile file(argv[2]); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + fprintf(stderr, "Unable to open file %s\n", argv[2]); + return 1; + } + + QXmlStreamReader xml(&file); + process(xml); + + if (xml.hasError()) { + fprintf(stderr, "XML error: %s\nLine %lld, column %lld\n", xml.errorString().toLocal8Bit().constData(), xml.lineNumber(), xml.columnNumber()); + return 1; + } +} diff --git a/src/qtwaylandscanner/qtwaylandscanner.pro b/src/qtwaylandscanner/qtwaylandscanner.pro new file mode 100644 index 000000000..34d25b922 --- /dev/null +++ b/src/qtwaylandscanner/qtwaylandscanner.pro @@ -0,0 +1,8 @@ +option(host_build) + +HEADERS += qtwaylandscanner.h + +SOURCES += qtwaylandscanner.cpp + +load(qt_tool) + diff --git a/src/src.pro b/src/src.pro index a12622d57..ac4e62aa4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,6 +1,8 @@ TEMPLATE=subdirs CONFIG+=ordered +SUBDIRS += qtwaylandscanner + #Don't build QtCompositor API unless explicitly enabled contains(CONFIG, wayland-compositor) { SUBDIRS += compositor |