summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@digia.com>2013-04-09 16:52:59 +0200
committerJørgen Lind <jorgen.lind@digia.com>2013-04-17 09:30:31 +0200
commit05d054ad7207764293525661876ebc689940a15c (patch)
tree192bd81afc1acb656155ccbfcfc8ac92feafdacc
parente5601d283c4d9a5c43352b6f1acd0e1968a31b83 (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.cpp1033
-rw-r--r--src/qtwaylandscanner/qtwaylandscanner.pro8
-rw-r--r--src/src.pro2
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