File indexing completed on 2024-11-10 04:57:24
0001 /**************************************************************************** 0002 ** 0003 ** Copyright (C) 2016 The Qt Company Ltd. 0004 ** Contact: https://www.qt.io/licensing/ 0005 ** 0006 ** This file is part of the tools applications of the Qt Toolkit. 0007 ** 0008 ** $QT_BEGIN_LICENSE:LGPL$ 0009 ** Commercial License Usage 0010 ** Licensees holding valid commercial Qt licenses may use this file in 0011 ** accordance with the commercial license agreement provided with the 0012 ** Software or, alternatively, in accordance with the terms contained in 0013 ** a written agreement between you and The Qt Company. For licensing terms 0014 ** and conditions see https://www.qt.io/terms-conditions. For further 0015 ** information use the contact form at https://www.qt.io/contact-us. 0016 ** 0017 ** GNU Lesser General Public License Usage 0018 ** Alternatively, this file may be used under the terms of the GNU Lesser 0019 ** General Public License version 3 as published by the Free Software 0020 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 0021 ** packaging of this file. Please review the following information to 0022 ** ensure the GNU Lesser General Public License version 3 requirements 0023 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 0024 ** 0025 ** GNU General Public License Usage 0026 ** Alternatively, this file may be used under the terms of the GNU 0027 ** General Public License version 2.0 or (at your option) the GNU General 0028 ** Public license version 3 or any later version approved by the KDE Free 0029 ** Qt Foundation. The licenses are as published by the Free Software 0030 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 0031 ** included in the packaging of this file. Please review the following 0032 ** information to ensure the GNU General Public License requirements will 0033 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 0034 ** https://www.gnu.org/licenses/gpl-3.0.html. 0035 ** 0036 ** $QT_END_LICENSE$ 0037 ** 0038 ****************************************************************************/ 0039 0040 #include <QCoreApplication> 0041 #include <QFile> 0042 #include <QXmlStreamReader> 0043 0044 #include <vector> 0045 #include <utility> 0046 0047 class Scanner 0048 { 0049 public: 0050 explicit Scanner() {} 0051 ~Scanner() { delete m_xml; } 0052 0053 bool parseArguments(int argc, char **argv); 0054 void printUsage(); 0055 bool process(); 0056 void printErrors(); 0057 0058 private: 0059 struct WaylandEnumEntry { 0060 QByteArray name; 0061 QByteArray value; 0062 QByteArray summary; 0063 }; 0064 0065 struct WaylandEnum { 0066 QByteArray name; 0067 0068 std::vector<WaylandEnumEntry> entries; 0069 }; 0070 0071 struct WaylandArgument { 0072 QByteArray name; 0073 QByteArray type; 0074 QByteArray interface; 0075 QByteArray summary; 0076 bool allowNull; 0077 }; 0078 0079 struct WaylandEvent { 0080 bool request; 0081 QByteArray name; 0082 QByteArray type; 0083 std::vector<WaylandArgument> arguments; 0084 }; 0085 0086 struct WaylandInterface { 0087 QByteArray name; 0088 int version; 0089 0090 std::vector<WaylandEnum> enums; 0091 std::vector<WaylandEvent> events; 0092 std::vector<WaylandEvent> requests; 0093 }; 0094 0095 bool isServerSide(); 0096 bool parseOption(const QByteArray &str); 0097 0098 QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name); 0099 int intValue(const QXmlStreamReader &xml, const char *name, int defaultValue = 0); 0100 bool boolValue(const QXmlStreamReader &xml, const char *name); 0101 WaylandEvent readEvent(QXmlStreamReader &xml, bool request); 0102 Scanner::WaylandEnum readEnum(QXmlStreamReader &xml); 0103 Scanner::WaylandInterface readInterface(QXmlStreamReader &xml); 0104 QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface); 0105 QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray); 0106 const Scanner::WaylandArgument *newIdArgument(const std::vector<WaylandArgument> &arguments); 0107 0108 void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource = false); 0109 void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true); 0110 void printEnums(const std::vector<WaylandEnum> &enums); 0111 0112 QByteArray stripInterfaceName(const QByteArray &name); 0113 bool ignoreInterface(const QByteArray &name); 0114 0115 enum Option { 0116 ClientHeader, 0117 ServerHeader, 0118 ClientCode, 0119 ServerCode, 0120 } m_option; 0121 0122 QByteArray m_protocolName; 0123 QByteArray m_protocolFilePath; 0124 QByteArray m_scannerName; 0125 QByteArray m_headerPath; 0126 QByteArray m_prefix; 0127 QList <QByteArray> m_includes; 0128 QXmlStreamReader *m_xml = nullptr; 0129 }; 0130 0131 bool Scanner::parseArguments(int argc, char **argv) 0132 { 0133 QList<QByteArray> args; 0134 args.reserve(argc); 0135 for (int i = 0; i < argc; ++i) 0136 args << QByteArray(argv[i]); 0137 0138 m_scannerName = args[0]; 0139 0140 if (argc <= 2 || !parseOption(args[1])) 0141 return false; 0142 0143 m_protocolFilePath = args[2]; 0144 0145 if (argc > 3 && !args[3].startsWith('-')) { 0146 // legacy positional arguments 0147 m_headerPath = args[3]; 0148 if (argc == 5) 0149 m_prefix = args[4]; 0150 } else { 0151 // --header-path=<path> (14 characters) 0152 // --prefix=<prefix> (9 characters) 0153 // --add-include=<include> (14 characters) 0154 for (int pos = 3; pos < argc; pos++) { 0155 const QByteArray &option = args[pos]; 0156 if (option.startsWith("--header-path=")) { 0157 m_headerPath = option.mid(14); 0158 } else if (option.startsWith("--prefix=")) { 0159 m_prefix = option.mid(10); 0160 } else if (option.startsWith("--add-include=")) { 0161 auto include = option.mid(14); 0162 if (!include.isEmpty()) 0163 m_includes << include; 0164 } else { 0165 return false; 0166 } 0167 } 0168 } 0169 0170 return true; 0171 } 0172 0173 void Scanner::printUsage() 0174 { 0175 fprintf(stderr, "Usage: %s [client-header|server-header|client-code|server-code] specfile [--header-path=<path>] [--prefix=<prefix>] [--add-include=<include>]\n", m_scannerName.constData()); 0176 } 0177 0178 bool Scanner::isServerSide() 0179 { 0180 return m_option == ServerHeader || m_option == ServerCode; 0181 } 0182 0183 bool Scanner::parseOption(const QByteArray &str) 0184 { 0185 if (str == "client-header") 0186 m_option = ClientHeader; 0187 else if (str == "server-header") 0188 m_option = ServerHeader; 0189 else if (str == "client-code") 0190 m_option = ClientCode; 0191 else if (str == "server-code") 0192 m_option = ServerCode; 0193 else 0194 return false; 0195 0196 return true; 0197 } 0198 0199 QByteArray Scanner::byteArrayValue(const QXmlStreamReader &xml, const char *name) 0200 { 0201 if (xml.attributes().hasAttribute(name)) 0202 return xml.attributes().value(name).toUtf8(); 0203 return QByteArray(); 0204 } 0205 0206 int Scanner::intValue(const QXmlStreamReader &xml, const char *name, int defaultValue) 0207 { 0208 bool ok; 0209 int result = byteArrayValue(xml, name).toInt(&ok); 0210 return ok ? result : defaultValue; 0211 } 0212 0213 bool Scanner::boolValue(const QXmlStreamReader &xml, const char *name) 0214 { 0215 return byteArrayValue(xml, name) == "true"; 0216 } 0217 0218 Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request) 0219 { 0220 WaylandEvent event = { 0221 .request = request, 0222 .name = byteArrayValue(xml, "name"), 0223 .type = byteArrayValue(xml, "type"), 0224 .arguments = {}, 0225 }; 0226 while (xml.readNextStartElement()) { 0227 if (xml.name() == QLatin1String("arg")) { 0228 WaylandArgument argument = { 0229 .name = byteArrayValue(xml, "name"), 0230 .type = byteArrayValue(xml, "type"), 0231 .interface = byteArrayValue(xml, "interface"), 0232 .summary = byteArrayValue(xml, "summary"), 0233 .allowNull = boolValue(xml, "allowNull"), 0234 }; 0235 event.arguments.push_back(std::move(argument)); 0236 } 0237 0238 xml.skipCurrentElement(); 0239 } 0240 return event; 0241 } 0242 0243 Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml) 0244 { 0245 WaylandEnum result = { 0246 .name = byteArrayValue(xml, "name"), 0247 .entries = {}, 0248 }; 0249 0250 while (xml.readNextStartElement()) { 0251 if (xml.name() == QLatin1String("entry")) { 0252 WaylandEnumEntry entry = { 0253 .name = byteArrayValue(xml, "name"), 0254 .value = byteArrayValue(xml, "value"), 0255 .summary = byteArrayValue(xml, "summary"), 0256 }; 0257 result.entries.push_back(std::move(entry)); 0258 } 0259 0260 xml.skipCurrentElement(); 0261 } 0262 0263 return result; 0264 } 0265 0266 Scanner::WaylandInterface Scanner::readInterface(QXmlStreamReader &xml) 0267 { 0268 WaylandInterface interface = { 0269 .name = byteArrayValue(xml, "name"), 0270 .version = intValue(xml, "version", 1), 0271 .enums = {}, 0272 .events = {}, 0273 .requests = {}, 0274 }; 0275 0276 while (xml.readNextStartElement()) { 0277 if (xml.name() == QLatin1String("event")) 0278 interface.events.push_back(readEvent(xml, false)); 0279 else if (xml.name() == QLatin1String("request")) 0280 interface.requests.push_back(readEvent(xml, true)); 0281 else if (xml.name() == QLatin1String("enum")) 0282 interface.enums.push_back(readEnum(xml)); 0283 else 0284 xml.skipCurrentElement(); 0285 } 0286 0287 return interface; 0288 } 0289 0290 QByteArray Scanner::waylandToCType(const QByteArray &waylandType, const QByteArray &interface) 0291 { 0292 if (waylandType == "string") 0293 return "const char *"; 0294 else if (waylandType == "int") 0295 return "int32_t"; 0296 else if (waylandType == "uint") 0297 return "uint32_t"; 0298 else if (waylandType == "fixed") 0299 return "wl_fixed_t"; 0300 else if (waylandType == "fd") 0301 return "int32_t"; 0302 else if (waylandType == "array") 0303 return "wl_array *"; 0304 else if (waylandType == "object" || waylandType == "new_id") { 0305 if (isServerSide()) 0306 return "struct ::wl_resource *"; 0307 if (interface.isEmpty()) 0308 return "struct ::wl_object *"; 0309 return "struct ::" + interface + " *"; 0310 } 0311 return waylandType; 0312 } 0313 0314 QByteArray Scanner::waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray) 0315 { 0316 if (waylandType == "string") 0317 return "const QString &"; 0318 else if (waylandType == "array") 0319 return cStyleArray ? "wl_array *" : "const QByteArray &"; 0320 else 0321 return waylandToCType(waylandType, interface); 0322 } 0323 0324 const Scanner::WaylandArgument *Scanner::newIdArgument(const std::vector<WaylandArgument> &arguments) 0325 { 0326 for (const WaylandArgument &a : arguments) { 0327 if (a.type == "new_id") 0328 return &a; 0329 } 0330 return nullptr; 0331 } 0332 0333 void Scanner::printEvent(const WaylandEvent &e, bool omitNames, bool withResource) 0334 { 0335 printf("%s(", e.name.constData()); 0336 bool needsComma = false; 0337 if (isServerSide()) { 0338 if (e.request) { 0339 printf("Resource *%s", omitNames ? "" : "resource"); 0340 needsComma = true; 0341 } else if (withResource) { 0342 printf("struct ::wl_resource *%s", omitNames ? "" : "resource"); 0343 needsComma = true; 0344 } 0345 } 0346 for (const WaylandArgument &a : e.arguments) { 0347 bool isNewId = a.type == "new_id"; 0348 if (isNewId && !isServerSide() && (a.interface.isEmpty() != e.request)) 0349 continue; 0350 if (needsComma) 0351 printf(", "); 0352 needsComma = true; 0353 if (isNewId) { 0354 if (isServerSide()) { 0355 if (e.request) { 0356 printf("uint32_t"); 0357 if (!omitNames) 0358 printf(" %s", a.name.constData()); 0359 continue; 0360 } 0361 } else { 0362 if (e.request) { 0363 printf("const struct ::wl_interface *%s, uint32_t%s", omitNames ? "" : "interface", omitNames ? "" : " version"); 0364 continue; 0365 } 0366 } 0367 } 0368 0369 QByteArray qtType = waylandToQtType(a.type, a.interface, e.request == isServerSide()); 0370 printf("%s%s%s", qtType.constData(), qtType.endsWith("&") || qtType.endsWith("*") ? "" : " ", omitNames ? "" : a.name.constData()); 0371 } 0372 printf(")"); 0373 } 0374 0375 void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent) 0376 { 0377 const char *indent = deepIndent ? " " : ""; 0378 printf("handle_%s(\n", e.name.constData()); 0379 if (isServerSide()) { 0380 printf(" %s::wl_client *client,\n", indent); 0381 printf(" %sstruct wl_resource *resource", indent); 0382 } else { 0383 printf(" %svoid *data,\n", indent); 0384 printf(" %sstruct ::%s *object", indent, interfaceName); 0385 } 0386 for (const WaylandArgument &a : e.arguments) { 0387 printf(",\n"); 0388 bool isNewId = a.type == "new_id"; 0389 if (isServerSide() && isNewId) { 0390 printf(" %suint32_t %s", indent, a.name.constData()); 0391 } else { 0392 QByteArray cType = waylandToCType(a.type, a.interface); 0393 printf(" %s%s%s%s", indent, cType.constData(), cType.endsWith("*") ? "" : " ", a.name.constData()); 0394 } 0395 } 0396 printf(")"); 0397 } 0398 0399 void Scanner::printEnums(const std::vector<WaylandEnum> &enums) 0400 { 0401 for (const WaylandEnum &e : enums) { 0402 printf("\n"); 0403 printf(" enum %s {\n", e.name.constData()); 0404 for (const WaylandEnumEntry &entry : e.entries) { 0405 printf(" %s_%s = %s,", e.name.constData(), entry.name.constData(), entry.value.constData()); 0406 if (!entry.summary.isNull()) 0407 printf(" // %s", entry.summary.constData()); 0408 printf("\n"); 0409 } 0410 printf(" };\n"); 0411 } 0412 } 0413 0414 QByteArray Scanner::stripInterfaceName(const QByteArray &name) 0415 { 0416 if (!m_prefix.isEmpty() && name.startsWith(m_prefix)) 0417 return name.mid(m_prefix.size()); 0418 if (name.startsWith("qt_") || name.startsWith("wl_")) 0419 return name.mid(3); 0420 0421 return name; 0422 } 0423 0424 bool Scanner::ignoreInterface(const QByteArray &name) 0425 { 0426 return name == "wl_display" 0427 || (isServerSide() && name == "wl_registry"); 0428 } 0429 0430 bool Scanner::process() 0431 { 0432 QFile file(m_protocolFilePath); 0433 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 0434 fprintf(stderr, "Unable to open file %s\n", m_protocolFilePath.constData()); 0435 return false; 0436 } 0437 0438 m_xml = new QXmlStreamReader(&file); 0439 if (!m_xml->readNextStartElement()) 0440 return false; 0441 0442 if (m_xml->name() != QLatin1String("protocol")) { 0443 m_xml->raiseError(QStringLiteral("The file is not a wayland protocol file.")); 0444 return false; 0445 } 0446 0447 m_protocolName = byteArrayValue(*m_xml, "name"); 0448 0449 if (m_protocolName.isEmpty()) { 0450 m_xml->raiseError(QStringLiteral("Missing protocol name.")); 0451 return false; 0452 } 0453 0454 //We should convert - to _ so that the preprocessor wont generate code which will lead to unexpected behavior 0455 //However, the wayland-scanner doesn't do so we will do the same for now 0456 //QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper(); 0457 QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper(); 0458 0459 std::vector<WaylandInterface> interfaces; 0460 0461 while (m_xml->readNextStartElement()) { 0462 if (m_xml->name() == QLatin1String("interface")) 0463 interfaces.push_back(readInterface(*m_xml)); 0464 else 0465 m_xml->skipCurrentElement(); 0466 } 0467 0468 if (m_xml->hasError()) 0469 return false; 0470 0471 printf("// This file was generated by qtwaylandscanner\n"); 0472 printf("// source file is %s\n\n", qPrintable(m_protocolFilePath)); 0473 0474 for (auto b : std::as_const(m_includes)) 0475 printf("#include %s\n", b.constData()); 0476 0477 if (m_option == ServerHeader) { 0478 QByteArray inclusionGuard = QByteArray("QT_WAYLAND_SERVER_") + preProcessorProtocolName.constData(); 0479 printf("#ifndef %s\n", inclusionGuard.constData()); 0480 printf("#define %s\n", inclusionGuard.constData()); 0481 printf("\n"); 0482 printf("#include \"wayland-server-core.h\"\n"); 0483 if (m_headerPath.isEmpty()) 0484 printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); 0485 else 0486 printf("#include <%s/wayland-%s-server-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); 0487 printf("#include <QByteArray>\n"); 0488 printf("#include <QMultiMap>\n"); 0489 printf("#include <QString>\n"); 0490 0491 printf("\n"); 0492 printf("#include <unistd.h>\n"); 0493 0494 printf("\n"); 0495 printf("#ifndef WAYLAND_VERSION_CHECK\n"); 0496 printf("#define WAYLAND_VERSION_CHECK(major, minor, micro) \\\n"); 0497 printf(" ((WAYLAND_VERSION_MAJOR > (major)) || \\\n"); 0498 printf(" (WAYLAND_VERSION_MAJOR == (major) && WAYLAND_VERSION_MINOR > (minor)) || \\\n"); 0499 printf(" (WAYLAND_VERSION_MAJOR == (major) && WAYLAND_VERSION_MINOR == (minor) && WAYLAND_VERSION_MICRO >= (micro)))\n"); 0500 printf("#endif\n"); 0501 0502 printf("\n"); 0503 printf("QT_BEGIN_NAMESPACE\n"); 0504 printf("QT_WARNING_PUSH\n"); 0505 printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n"); 0506 printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n"); 0507 QByteArray serverExport; 0508 if (m_headerPath.size()) { 0509 serverExport = QByteArray("Q_WAYLAND_SERVER_") + preProcessorProtocolName + "_EXPORT"; 0510 printf("\n"); 0511 printf("#if !defined(%s)\n", serverExport.constData()); 0512 printf("# if defined(QT_SHARED)\n"); 0513 printf("# define %s Q_DECL_EXPORT\n", serverExport.constData()); 0514 printf("# else\n"); 0515 printf("# define %s\n", serverExport.constData()); 0516 printf("# endif\n"); 0517 printf("#endif\n"); 0518 } 0519 printf("\n"); 0520 printf("namespace QtWaylandServer {\n"); 0521 0522 bool needsNewLine = false; 0523 for (const WaylandInterface &interface : interfaces) { 0524 0525 if (ignoreInterface(interface.name)) 0526 continue; 0527 0528 if (needsNewLine) 0529 printf("\n"); 0530 needsNewLine = true; 0531 0532 const char *interfaceName = interface.name.constData(); 0533 0534 QByteArray stripped = stripInterfaceName(interface.name); 0535 const char *interfaceNameStripped = stripped.constData(); 0536 0537 printf(" class %s %s\n {\n", serverExport.constData(), interfaceName); 0538 printf(" public:\n"); 0539 printf(" %s(struct ::wl_client *client, int id, int version);\n", interfaceName); 0540 printf(" %s(struct ::wl_display *display, int version);\n", interfaceName); 0541 printf(" %s(struct ::wl_resource *resource);\n", interfaceName); 0542 printf(" %s();\n", interfaceName); 0543 printf("\n"); 0544 printf(" virtual ~%s();\n", interfaceName); 0545 printf("\n"); 0546 printf(" class Resource\n"); 0547 printf(" {\n"); 0548 printf(" public:\n"); 0549 printf(" Resource() : %s_object(nullptr), handle(nullptr) {}\n", interfaceNameStripped); 0550 printf(" virtual ~Resource() {}\n"); 0551 printf("\n"); 0552 printf(" %s *%s_object;\n", interfaceName, interfaceNameStripped); 0553 printf(" %s *object() { return %s_object; } \n", interfaceName, interfaceNameStripped); 0554 printf(" struct ::wl_resource *handle;\n"); 0555 printf("\n"); 0556 printf(" struct ::wl_client *client() const { return wl_resource_get_client(handle); }\n"); 0557 printf(" int version() const { return wl_resource_get_version(handle); }\n"); 0558 printf("\n"); 0559 printf(" static Resource *fromResource(struct ::wl_resource *resource);\n"); 0560 printf(" };\n"); 0561 printf("\n"); 0562 printf(" void init(struct ::wl_client *client, int id, int version);\n"); 0563 printf(" void init(struct ::wl_display *display, int version);\n"); 0564 printf(" void init(struct ::wl_resource *resource);\n"); 0565 printf("\n"); 0566 printf(" Resource *add(struct ::wl_client *client, int version);\n"); 0567 printf(" Resource *add(struct ::wl_client *client, int id, int version);\n"); 0568 printf(" Resource *add(struct wl_list *resource_list, struct ::wl_client *client, int id, int version);\n"); 0569 printf("\n"); 0570 printf(" Resource *resource() { return m_resource; }\n"); 0571 printf(" const Resource *resource() const { return m_resource; }\n"); 0572 printf("\n"); 0573 printf(" QMultiMap<struct ::wl_client*, Resource*> resourceMap() { return m_resource_map; }\n"); 0574 printf(" const QMultiMap<struct ::wl_client*, Resource*> resourceMap() const { return m_resource_map; }\n"); 0575 printf("\n"); 0576 printf(" bool isGlobalRemoved() const { return m_globalRemovedEvent; }\n"); 0577 printf(" void globalRemove();\n"); 0578 printf("\n"); 0579 printf(" bool isGlobal() const { return m_global != nullptr; }\n"); 0580 printf(" bool isResource() const { return m_resource != nullptr; }\n"); 0581 printf("\n"); 0582 printf(" static const struct ::wl_interface *interface();\n"); 0583 printf(" static QByteArray interfaceName() { return interface()->name; }\n"); 0584 printf(" static int interfaceVersion() { return interface()->version; }\n"); 0585 printf("\n"); 0586 0587 printEnums(interface.enums); 0588 0589 bool hasEvents = !interface.events.empty(); 0590 0591 if (hasEvents) { 0592 printf("\n"); 0593 for (const WaylandEvent &e : interface.events) { 0594 printf(" void send_"); 0595 printEvent(e); 0596 printf(";\n"); 0597 printf(" void send_"); 0598 printEvent(e, false, true); 0599 printf(";\n"); 0600 } 0601 } 0602 0603 printf("\n"); 0604 printf(" protected:\n"); 0605 printf(" virtual Resource *%s_allocate();\n", interfaceNameStripped); 0606 printf("\n"); 0607 printf(" virtual void %s_destroy_global();\n", interfaceNameStripped); 0608 printf("\n"); 0609 printf(" virtual void %s_bind_resource(Resource *resource);\n", interfaceNameStripped); 0610 printf(" virtual void %s_destroy_resource(Resource *resource);\n", interfaceNameStripped); 0611 0612 bool hasRequests = !interface.requests.empty(); 0613 0614 if (hasRequests) { 0615 printf("\n"); 0616 for (const WaylandEvent &e : interface.requests) { 0617 printf(" virtual void %s_", interfaceNameStripped); 0618 printEvent(e); 0619 printf(";\n"); 0620 } 0621 } 0622 0623 printf("\n"); 0624 printf(" private:\n"); 0625 printf(" static void bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id);\n"); 0626 printf(" static void destroy_func(struct ::wl_resource *client_resource);\n"); 0627 printf(" static void display_destroy_func(struct ::wl_listener *listener, void *data);\n"); 0628 printf(" static int deferred_destroy_global_func(void *data);\n"); 0629 printf("\n"); 0630 printf(" Resource *bind(struct ::wl_client *client, uint32_t id, int version);\n"); 0631 printf(" Resource *bind(struct ::wl_resource *handle);\n"); 0632 0633 if (hasRequests) { 0634 printf("\n"); 0635 printf(" static const struct ::%s_interface m_%s_interface;\n", interfaceName, interfaceName); 0636 0637 printf("\n"); 0638 for (const WaylandEvent &e : interface.requests) { 0639 printf(" static void "); 0640 0641 printEventHandlerSignature(e, interfaceName); 0642 printf(";\n"); 0643 } 0644 } 0645 0646 printf("\n"); 0647 printf(" QMultiMap<struct ::wl_client*, Resource*> m_resource_map;\n"); 0648 printf(" Resource *m_resource;\n"); 0649 printf(" struct ::wl_global *m_global;\n"); 0650 printf(" struct ::wl_display *m_display;\n"); 0651 printf(" struct wl_event_source *m_globalRemovedEvent;\n"); 0652 printf(" struct DisplayDestroyedListener : ::wl_listener {\n"); 0653 printf(" %s *parent;\n", interfaceName); 0654 printf(" };\n"); 0655 printf(" DisplayDestroyedListener m_displayDestroyedListener;\n"); 0656 printf(" };\n"); 0657 } 0658 0659 printf("}\n"); 0660 printf("\n"); 0661 printf("QT_WARNING_POP\n"); 0662 printf("QT_END_NAMESPACE\n"); 0663 printf("\n"); 0664 printf("#endif\n"); 0665 } 0666 0667 if (m_option == ServerCode) { 0668 if (m_headerPath.isEmpty()) 0669 printf("#include \"qwayland-server-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); 0670 else 0671 printf("#include <%s/qwayland-server-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); 0672 printf("\n"); 0673 printf("QT_BEGIN_NAMESPACE\n"); 0674 printf("QT_WARNING_PUSH\n"); 0675 printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n"); 0676 printf("\n"); 0677 printf("namespace QtWaylandServer {\n"); 0678 0679 bool needsNewLine = false; 0680 0681 for (const WaylandInterface &interface : interfaces) { 0682 0683 if (ignoreInterface(interface.name)) 0684 continue; 0685 0686 if (needsNewLine) 0687 printf("\n"); 0688 0689 needsNewLine = true; 0690 0691 const char *interfaceName = interface.name.constData(); 0692 0693 QByteArray stripped = stripInterfaceName(interface.name); 0694 const char *interfaceNameStripped = stripped.constData(); 0695 0696 printf("\n"); 0697 printf(" int %s::deferred_destroy_global_func(void *data) {\n", interfaceName); 0698 printf(" auto object = static_cast<%s *>(data);\n", interfaceName); 0699 printf(" wl_global_destroy(object->m_global);\n"); 0700 printf(" object->m_global = nullptr;\n"); 0701 printf(" wl_event_source_remove(object->m_globalRemovedEvent);\n"); 0702 printf(" object->m_globalRemovedEvent = nullptr;\n"); 0703 printf(" wl_list_remove(&object->m_displayDestroyedListener.link);\n"); 0704 printf(" object->%s_destroy_global();\n", interfaceNameStripped); 0705 printf(" return 0;\n"); 0706 printf(" }\n"); 0707 printf("\n"); 0708 0709 printf(" %s::%s(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName); 0710 printf(" : m_resource_map()\n"); 0711 printf(" , m_resource(nullptr)\n"); 0712 printf(" , m_global(nullptr)\n"); 0713 printf(" , m_display(nullptr)\n"); 0714 printf(" , m_globalRemovedEvent(nullptr)\n"); 0715 printf(" {\n"); 0716 printf(" init(client, id, version);\n"); 0717 printf(" }\n"); 0718 printf("\n"); 0719 0720 printf(" %s::%s(struct ::wl_display *display, int version)\n", interfaceName, interfaceName); 0721 printf(" : m_resource_map()\n"); 0722 printf(" , m_resource(nullptr)\n"); 0723 printf(" , m_global(nullptr)\n"); 0724 printf(" , m_display(nullptr)\n"); 0725 printf(" , m_globalRemovedEvent(nullptr)\n"); 0726 printf(" {\n"); 0727 printf(" init(display, version);\n"); 0728 printf(" }\n"); 0729 printf("\n"); 0730 0731 printf(" %s::%s(struct ::wl_resource *resource)\n", interfaceName, interfaceName); 0732 printf(" : m_resource_map()\n"); 0733 printf(" , m_resource(nullptr)\n"); 0734 printf(" , m_global(nullptr)\n"); 0735 printf(" , m_display(nullptr)\n"); 0736 printf(" , m_globalRemovedEvent(nullptr)\n"); 0737 printf(" {\n"); 0738 printf(" init(resource);\n"); 0739 printf(" }\n"); 0740 printf("\n"); 0741 0742 printf(" %s::%s()\n", interfaceName, interfaceName); 0743 printf(" : m_resource_map()\n"); 0744 printf(" , m_resource(nullptr)\n"); 0745 printf(" , m_global(nullptr)\n"); 0746 printf(" , m_display(nullptr)\n"); 0747 printf(" , m_globalRemovedEvent(nullptr)\n"); 0748 printf(" {\n"); 0749 printf(" }\n"); 0750 printf("\n"); 0751 0752 printf(" %s::~%s()\n", interfaceName, interfaceName); 0753 printf(" {\n"); 0754 printf(" for (auto resource : std::as_const(m_resource_map))\n"); 0755 printf(" resource->%s_object = nullptr;\n", interfaceNameStripped); 0756 printf("\n"); 0757 printf(" if (m_resource)\n"); 0758 printf(" m_resource->%s_object = nullptr;\n", interfaceNameStripped); 0759 printf("\n"); 0760 printf(" if (m_global) {\n"); 0761 printf(" if (m_globalRemovedEvent)\n"); 0762 printf(" wl_event_source_remove(m_globalRemovedEvent);\n"); 0763 printf(" wl_global_destroy(m_global);\n"); 0764 printf(" wl_list_remove(&m_displayDestroyedListener.link);\n"); 0765 printf(" }\n"); 0766 printf(" }\n"); 0767 printf("\n"); 0768 0769 printf(" void %s::init(struct ::wl_client *client, int id, int version)\n", interfaceName); 0770 printf(" {\n"); 0771 printf(" m_resource = bind(client, id, version);\n"); 0772 printf(" }\n"); 0773 printf("\n"); 0774 0775 printf(" void %s::init(struct ::wl_resource *resource)\n", interfaceName); 0776 printf(" {\n"); 0777 printf(" m_resource = bind(resource);\n"); 0778 printf(" }\n"); 0779 printf("\n"); 0780 0781 printf(" %s::Resource *%s::add(struct ::wl_client *client, int version)\n", interfaceName, interfaceName); 0782 printf(" {\n"); 0783 printf(" Resource *resource = bind(client, 0, version);\n"); 0784 printf(" m_resource_map.insert(client, resource);\n"); 0785 printf(" return resource;\n"); 0786 printf(" }\n"); 0787 printf("\n"); 0788 0789 printf(" %s::Resource *%s::add(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName); 0790 printf(" {\n"); 0791 printf(" Resource *resource = bind(client, id, version);\n"); 0792 printf(" m_resource_map.insert(client, resource);\n"); 0793 printf(" return resource;\n"); 0794 printf(" }\n"); 0795 printf("\n"); 0796 0797 printf(" void %s::init(struct ::wl_display *display, int version)\n", interfaceName); 0798 printf(" {\n"); 0799 printf(" m_display = display;\n"); 0800 printf(" m_global = wl_global_create(display, &::%s_interface, version, this, bind_func);\n", interfaceName); 0801 printf(" m_displayDestroyedListener.notify = %s::display_destroy_func;\n", interfaceName); 0802 printf(" m_displayDestroyedListener.parent = this;\n"); 0803 printf(" wl_display_add_destroy_listener(display, &m_displayDestroyedListener);\n"); 0804 printf(" }\n"); 0805 printf("\n"); 0806 0807 printf(" const struct wl_interface *%s::interface()\n", interfaceName); 0808 printf(" {\n"); 0809 printf(" return &::%s_interface;\n", interfaceName); 0810 printf(" }\n"); 0811 printf("\n"); 0812 0813 printf(" %s::Resource *%s::%s_allocate()\n", interfaceName, interfaceName, interfaceNameStripped); 0814 printf(" {\n"); 0815 printf(" return new Resource;\n"); 0816 printf(" }\n"); 0817 printf("\n"); 0818 0819 printf(" void %s::%s_destroy_global()\n", interfaceName, interfaceNameStripped); 0820 printf(" {\n"); 0821 printf(" }\n"); 0822 printf("\n"); 0823 0824 printf(" void %s::%s_bind_resource(Resource *)\n", interfaceName, interfaceNameStripped); 0825 printf(" {\n"); 0826 printf(" }\n"); 0827 printf("\n"); 0828 0829 printf(" void %s::%s_destroy_resource(Resource *)\n", interfaceName, interfaceNameStripped); 0830 printf(" {\n"); 0831 printf(" }\n"); 0832 printf("\n"); 0833 0834 printf(" void %s::bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id)\n", interfaceName); 0835 printf(" {\n"); 0836 printf(" %s *that = static_cast<%s *>(data);\n", interfaceName, interfaceName); 0837 printf(" that->add(client, id, version);\n"); 0838 printf(" }\n"); 0839 printf("\n"); 0840 0841 printf(" void %s::display_destroy_func(struct ::wl_listener *listener, void *data)\n", interfaceName); 0842 printf(" {\n"); 0843 printf(" Q_UNUSED(data);\n"); 0844 printf(" %s *that = static_cast<%s::DisplayDestroyedListener *>(listener)->parent;\n", interfaceName, interfaceName); 0845 printf(" that->m_global = nullptr;\n"); 0846 printf(" that->m_globalRemovedEvent = nullptr;\n"); 0847 printf(" }\n"); 0848 printf("\n"); 0849 0850 printf(" void %s::destroy_func(struct ::wl_resource *client_resource)\n", interfaceName); 0851 printf(" {\n"); 0852 printf(" Resource *resource = Resource::fromResource(client_resource);\n"); 0853 printf(" Q_ASSERT(resource);\n"); 0854 printf(" %s *that = resource->%s_object;\n", interfaceName, interfaceNameStripped); 0855 printf(" if (Q_LIKELY(that)) {\n"); 0856 printf(" that->m_resource_map.remove(resource->client(), resource);\n"); 0857 printf(" that->%s_destroy_resource(resource);\n", interfaceNameStripped); 0858 printf("\n"); 0859 printf(" that = resource->%s_object;\n", interfaceNameStripped); 0860 printf(" if (that && that->m_resource == resource)\n"); 0861 printf(" that->m_resource = nullptr;\n"); 0862 printf(" }\n"); 0863 printf(" delete resource;\n"); 0864 printf(" }\n"); 0865 printf("\n"); 0866 0867 // Removing a global is racey. Announce removal, and then only perform internal cleanup after a delay 0868 // See https://gitlab.freedesktop.org/wayland/wayland/issues/10 0869 printf("\n"); 0870 printf(" void %s::globalRemove()\n", interfaceName); 0871 printf(" {\n"); 0872 printf(" if (!m_global || m_globalRemovedEvent)\n"); 0873 printf(" return;\n"); 0874 printf("\n"); 0875 printf(" wl_global_remove(m_global);\n"); 0876 printf("\n"); 0877 printf(" struct wl_event_loop *event_loop = wl_display_get_event_loop(m_display);\n"); 0878 printf(" m_globalRemovedEvent = wl_event_loop_add_timer(event_loop, deferred_destroy_global_func, this);\n"); 0879 printf(" wl_event_source_timer_update(m_globalRemovedEvent, 5000);\n"); 0880 printf(" }\n"); 0881 printf("\n"); 0882 0883 bool hasRequests = !interface.requests.empty(); 0884 0885 QByteArray interfaceMember = hasRequests ? "&m_" + interface.name + "_interface" : QByteArray("nullptr"); 0886 0887 //We should consider changing bind so that it doesn't special case id == 0 0888 //and use function overloading instead. Jan do you have a lot of code dependent on this behavior? 0889 printf(" %s::Resource *%s::bind(struct ::wl_client *client, uint32_t id, int version)\n", interfaceName, interfaceName); 0890 printf(" {\n"); 0891 printf(" Q_ASSERT_X(!wl_client_get_object(client, id), \"QWaylandObject bind\", QStringLiteral(\"binding to object %%1 more than once\").arg(id).toLocal8Bit().constData());\n"); 0892 printf(" struct ::wl_resource *handle = wl_resource_create(client, &::%s_interface, version, id);\n", interfaceName); 0893 printf(" return bind(handle);\n"); 0894 printf(" }\n"); 0895 printf("\n"); 0896 0897 printf(" %s::Resource *%s::bind(struct ::wl_resource *handle)\n", interfaceName, interfaceName); 0898 printf(" {\n"); 0899 printf(" Resource *resource = %s_allocate();\n", interfaceNameStripped); 0900 printf(" resource->%s_object = this;\n", interfaceNameStripped); 0901 printf("\n"); 0902 printf(" wl_resource_set_implementation(handle, %s, resource, destroy_func);", interfaceMember.constData()); 0903 printf("\n"); 0904 printf(" resource->handle = handle;\n"); 0905 printf(" %s_bind_resource(resource);\n", interfaceNameStripped); 0906 printf(" return resource;\n"); 0907 printf(" }\n"); 0908 0909 printf(" %s::Resource *%s::Resource::fromResource(struct ::wl_resource *resource)\n", interfaceName, interfaceName); 0910 printf(" {\n"); 0911 printf(" if (Q_UNLIKELY(!resource))\n"); 0912 printf(" return nullptr;\n"); 0913 printf(" if (wl_resource_instance_of(resource, &::%s_interface, %s))\n", interfaceName, interfaceMember.constData()); 0914 printf(" return static_cast<Resource *>(wl_resource_get_user_data(resource));\n"); 0915 printf(" return nullptr;\n"); 0916 printf(" }\n"); 0917 0918 if (hasRequests) { 0919 printf("\n"); 0920 printf(" const struct ::%s_interface %s::m_%s_interface = {", interfaceName, interfaceName, interfaceName); 0921 bool needsComma = false; 0922 for (const WaylandEvent &e : interface.requests) { 0923 if (needsComma) 0924 printf(","); 0925 needsComma = true; 0926 printf("\n"); 0927 printf(" %s::handle_%s", interfaceName, e.name.constData()); 0928 } 0929 printf("\n"); 0930 printf(" };\n"); 0931 0932 for (const WaylandEvent &e : interface.requests) { 0933 printf("\n"); 0934 printf(" void %s::%s_", interfaceName, interfaceNameStripped); 0935 printEvent(e, true); 0936 printf("\n"); 0937 printf(" {\n"); 0938 printf(" }\n"); 0939 } 0940 printf("\n"); 0941 0942 for (const WaylandEvent &e : interface.requests) { 0943 printf("\n"); 0944 printf(" void %s::", interfaceName); 0945 0946 printEventHandlerSignature(e, interfaceName, false); 0947 0948 printf("\n"); 0949 printf(" {\n"); 0950 printf(" Q_UNUSED(client);\n"); 0951 printf(" Resource *r = Resource::fromResource(resource);\n"); 0952 printf(" if (Q_UNLIKELY(!r->%s_object)) {\n", interfaceNameStripped); 0953 for (const WaylandArgument &a : e.arguments) { 0954 if (a.type == QByteArrayLiteral("fd")) 0955 printf(" close(%s);\n", a.name.constData()); 0956 } 0957 if (e.type == "destructor") 0958 printf(" wl_resource_destroy(resource);\n"); 0959 printf(" return;\n"); 0960 printf(" }\n"); 0961 printf(" static_cast<%s *>(r->%s_object)->%s_%s(\n", interfaceName, interfaceNameStripped, interfaceNameStripped, e.name.constData()); 0962 printf(" r"); 0963 for (const WaylandArgument &a : e.arguments) { 0964 printf(",\n"); 0965 QByteArray cType = waylandToCType(a.type, a.interface); 0966 QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); 0967 const char *argumentName = a.name.constData(); 0968 if (cType == qtType) 0969 printf(" %s", argumentName); 0970 else if (a.type == "string") 0971 printf(" QString::fromUtf8(%s)", argumentName); 0972 } 0973 printf(");\n"); 0974 printf(" }\n"); 0975 } 0976 } 0977 0978 for (const WaylandEvent &e : interface.events) { 0979 printf("\n"); 0980 printf(" void %s::send_", interfaceName); 0981 printEvent(e); 0982 printf("\n"); 0983 printf(" {\n"); 0984 printf(" Q_ASSERT_X(m_resource, \"%s::%s\", \"Uninitialised resource\");\n", interfaceName, e.name.constData()); 0985 printf(" if (Q_UNLIKELY(!m_resource)) {\n"); 0986 printf(" qWarning(\"could not call %s::%s as it's not initialised\");\n", interfaceName, e.name.constData()); 0987 printf(" return;\n"); 0988 printf(" }\n"); 0989 printf(" send_%s(\n", e.name.constData()); 0990 printf(" m_resource->handle"); 0991 for (const WaylandArgument &a : e.arguments) { 0992 printf(",\n"); 0993 printf(" %s", a.name.constData()); 0994 } 0995 printf(");\n"); 0996 printf(" }\n"); 0997 printf("\n"); 0998 0999 printf(" void %s::send_", interfaceName); 1000 printEvent(e, false, true); 1001 printf("\n"); 1002 printf(" {\n"); 1003 1004 for (const WaylandArgument &a : e.arguments) { 1005 if (a.type != "array") 1006 continue; 1007 QByteArray array = a.name + "_data"; 1008 const char *arrayName = array.constData(); 1009 const char *variableName = a.name.constData(); 1010 printf(" struct wl_array %s;\n", arrayName); 1011 printf(" %s.size = %s.size();\n", arrayName, variableName); 1012 printf(" %s.data = static_cast<void *>(const_cast<char *>(%s.constData()));\n", arrayName, variableName); 1013 printf(" %s.alloc = 0;\n", arrayName); 1014 printf("\n"); 1015 } 1016 1017 printf(" %s_send_%s(\n", interfaceName, e.name.constData()); 1018 printf(" resource"); 1019 1020 for (const WaylandArgument &a : e.arguments) { 1021 printf(",\n"); 1022 QByteArray cType = waylandToCType(a.type, a.interface); 1023 QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); 1024 if (a.type == "string") 1025 printf(" %s.toUtf8().constData()", a.name.constData()); 1026 else if (a.type == "array") 1027 printf(" &%s_data", a.name.constData()); 1028 else if (cType == qtType) 1029 printf(" %s", a.name.constData()); 1030 } 1031 1032 printf(");\n"); 1033 printf(" }\n"); 1034 printf("\n"); 1035 } 1036 } 1037 printf("}\n"); 1038 printf("\n"); 1039 printf("QT_WARNING_POP\n"); 1040 printf("QT_END_NAMESPACE\n"); 1041 } 1042 1043 if (m_option == ClientHeader) { 1044 QByteArray inclusionGuard = QByteArray("QT_WAYLAND_") + preProcessorProtocolName.constData(); 1045 printf("#ifndef %s\n", inclusionGuard.constData()); 1046 printf("#define %s\n", inclusionGuard.constData()); 1047 printf("\n"); 1048 if (m_headerPath.isEmpty()) 1049 printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); 1050 else 1051 printf("#include <%s/wayland-%s-client-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); 1052 printf("#include <QByteArray>\n"); 1053 printf("#include <QString>\n"); 1054 printf("\n"); 1055 printf("struct wl_registry;\n"); 1056 printf("\n"); 1057 printf("QT_BEGIN_NAMESPACE\n"); 1058 printf("QT_WARNING_PUSH\n"); 1059 printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n"); 1060 1061 QByteArray clientExport; 1062 1063 if (m_headerPath.size()) { 1064 clientExport = QByteArray("Q_WAYLAND_CLIENT_") + preProcessorProtocolName + "_EXPORT"; 1065 printf("\n"); 1066 printf("#if !defined(%s)\n", clientExport.constData()); 1067 printf("# if defined(QT_SHARED)\n"); 1068 printf("# define %s Q_DECL_EXPORT\n", clientExport.constData()); 1069 printf("# else\n"); 1070 printf("# define %s\n", clientExport.constData()); 1071 printf("# endif\n"); 1072 printf("#endif\n"); 1073 } 1074 printf("\n"); 1075 printf("namespace QtWayland {\n"); 1076 1077 bool needsNewLine = false; 1078 for (const WaylandInterface &interface : interfaces) { 1079 1080 if (ignoreInterface(interface.name)) 1081 continue; 1082 1083 if (needsNewLine) 1084 printf("\n"); 1085 needsNewLine = true; 1086 1087 const char *interfaceName = interface.name.constData(); 1088 1089 QByteArray stripped = stripInterfaceName(interface.name); 1090 const char *interfaceNameStripped = stripped.constData(); 1091 1092 printf(" class %s %s\n {\n", clientExport.constData(), interfaceName); 1093 printf(" public:\n"); 1094 printf(" %s(struct ::wl_registry *registry, int id, int version);\n", interfaceName); 1095 printf(" %s(struct ::%s *object);\n", interfaceName, interfaceName); 1096 printf(" %s();\n", interfaceName); 1097 printf("\n"); 1098 printf(" virtual ~%s();\n", interfaceName); 1099 printf("\n"); 1100 printf(" void init(struct ::wl_registry *registry, int id, int version);\n"); 1101 printf(" void init(struct ::%s *object);\n", interfaceName); 1102 printf("\n"); 1103 printf(" struct ::%s *object() { return m_%s; }\n", interfaceName, interfaceName); 1104 printf(" const struct ::%s *object() const { return m_%s; }\n", interfaceName, interfaceName); 1105 printf(" static %s *fromObject(struct ::%s *object);\n", interfaceName, interfaceName); 1106 printf("\n"); 1107 printf(" bool isInitialized() const;\n"); 1108 printf("\n"); 1109 printf(" static const struct ::wl_interface *interface();\n"); 1110 1111 printEnums(interface.enums); 1112 1113 if (!interface.requests.empty()) { 1114 printf("\n"); 1115 for (const WaylandEvent &e : interface.requests) { 1116 const WaylandArgument *new_id = newIdArgument(e.arguments); 1117 QByteArray new_id_str = "void "; 1118 if (new_id) { 1119 if (new_id->interface.isEmpty()) 1120 new_id_str = "void *"; 1121 else 1122 new_id_str = "struct ::" + new_id->interface + " *"; 1123 } 1124 printf(" %s", new_id_str.constData()); 1125 printEvent(e); 1126 printf(";\n"); 1127 } 1128 } 1129 1130 bool hasEvents = !interface.events.empty(); 1131 1132 if (hasEvents) { 1133 printf("\n"); 1134 printf(" protected:\n"); 1135 for (const WaylandEvent &e : interface.events) { 1136 printf(" virtual void %s_", interfaceNameStripped); 1137 printEvent(e); 1138 printf(";\n"); 1139 } 1140 } 1141 1142 printf("\n"); 1143 printf(" private:\n"); 1144 if (hasEvents) { 1145 printf(" void init_listener();\n"); 1146 printf(" static const struct %s_listener m_%s_listener;\n", interfaceName, interfaceName); 1147 for (const WaylandEvent &e : interface.events) { 1148 printf(" static void "); 1149 1150 printEventHandlerSignature(e, interfaceName); 1151 printf(";\n"); 1152 } 1153 } 1154 printf(" struct ::%s *m_%s;\n", interfaceName, interfaceName); 1155 printf(" };\n"); 1156 } 1157 printf("}\n"); 1158 printf("\n"); 1159 printf("QT_WARNING_POP\n"); 1160 printf("QT_END_NAMESPACE\n"); 1161 printf("\n"); 1162 printf("#endif\n"); 1163 } 1164 1165 if (m_option == ClientCode) { 1166 if (m_headerPath.isEmpty()) 1167 printf("#include \"qwayland-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData()); 1168 else 1169 printf("#include <%s/qwayland-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData()); 1170 printf("\n"); 1171 printf("QT_BEGIN_NAMESPACE\n"); 1172 printf("QT_WARNING_PUSH\n"); 1173 printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n"); 1174 printf("\n"); 1175 printf("namespace QtWayland {\n"); 1176 printf("\n"); 1177 1178 // wl_registry_bind is part of the protocol, so we can't use that... instead we use core 1179 // libwayland API to do the same thing a wayland-scanner generated wl_registry_bind would. 1180 printf("static inline void *wlRegistryBind(struct ::wl_registry *registry, uint32_t name, const struct ::wl_interface *interface, uint32_t version)\n"); 1181 printf("{\n"); 1182 printf(" const uint32_t bindOpCode = 0;\n"); 1183 printf("#if (WAYLAND_VERSION_MAJOR == 1 && WAYLAND_VERSION_MINOR > 10) || WAYLAND_VERSION_MAJOR > 1\n"); 1184 printf(" return (void *) wl_proxy_marshal_constructor_versioned((struct wl_proxy *) registry,\n"); 1185 printf(" bindOpCode, interface, version, name, interface->name, version, nullptr);\n"); 1186 printf("#else\n"); 1187 printf(" return (void *) wl_proxy_marshal_constructor((struct wl_proxy *) registry,\n"); 1188 printf(" bindOpCode, interface, name, interface->name, version, nullptr);\n"); 1189 printf("#endif\n"); 1190 printf("}\n"); 1191 printf("\n"); 1192 1193 bool needsNewLine = false; 1194 for (const WaylandInterface &interface : interfaces) { 1195 1196 if (ignoreInterface(interface.name)) 1197 continue; 1198 1199 if (needsNewLine) 1200 printf("\n"); 1201 needsNewLine = true; 1202 1203 const char *interfaceName = interface.name.constData(); 1204 1205 QByteArray stripped = stripInterfaceName(interface.name); 1206 const char *interfaceNameStripped = stripped.constData(); 1207 1208 bool hasEvents = !interface.events.empty(); 1209 1210 printf(" %s::%s(struct ::wl_registry *registry, int id, int version)\n", interfaceName, interfaceName); 1211 printf(" {\n"); 1212 printf(" init(registry, id, version);\n"); 1213 printf(" }\n"); 1214 printf("\n"); 1215 1216 printf(" %s::%s(struct ::%s *obj)\n", interfaceName, interfaceName, interfaceName); 1217 printf(" : m_%s(obj)\n", interfaceName); 1218 printf(" {\n"); 1219 if (hasEvents) 1220 printf(" init_listener();\n"); 1221 printf(" }\n"); 1222 printf("\n"); 1223 1224 printf(" %s::%s()\n", interfaceName, interfaceName); 1225 printf(" : m_%s(nullptr)\n", interfaceName); 1226 printf(" {\n"); 1227 printf(" }\n"); 1228 printf("\n"); 1229 1230 printf(" %s::~%s()\n", interfaceName, interfaceName); 1231 printf(" {\n"); 1232 printf(" }\n"); 1233 printf("\n"); 1234 1235 printf(" void %s::init(struct ::wl_registry *registry, int id, int version)\n", interfaceName); 1236 printf(" {\n"); 1237 printf(" m_%s = static_cast<struct ::%s *>(wlRegistryBind(registry, id, &%s_interface, version));\n", interfaceName, interfaceName, interfaceName); 1238 if (hasEvents) 1239 printf(" init_listener();\n"); 1240 printf(" }\n"); 1241 printf("\n"); 1242 1243 printf(" void %s::init(struct ::%s *obj)\n", interfaceName, interfaceName); 1244 printf(" {\n"); 1245 printf(" m_%s = obj;\n", interfaceName); 1246 if (hasEvents) 1247 printf(" init_listener();\n"); 1248 printf(" }\n"); 1249 printf("\n"); 1250 1251 printf(" %s *%s::fromObject(struct ::%s *object)\n", interfaceName, interfaceName, interfaceName); 1252 printf(" {\n"); 1253 if (hasEvents) { 1254 printf(" if (wl_proxy_get_listener((struct ::wl_proxy *)object) != (void *)&m_%s_listener)\n", interfaceName); 1255 printf(" return nullptr;\n"); 1256 } 1257 printf(" return static_cast<%s *>(%s_get_user_data(object));\n", interfaceName, interfaceName); 1258 printf(" }\n"); 1259 printf("\n"); 1260 1261 printf(" bool %s::isInitialized() const\n", interfaceName); 1262 printf(" {\n"); 1263 printf(" return m_%s != nullptr;\n", interfaceName); 1264 printf(" }\n"); 1265 printf("\n"); 1266 1267 printf(" const struct wl_interface *%s::interface()\n", interfaceName); 1268 printf(" {\n"); 1269 printf(" return &::%s_interface;\n", interfaceName); 1270 printf(" }\n"); 1271 1272 for (const WaylandEvent &e : interface.requests) { 1273 printf("\n"); 1274 const WaylandArgument *new_id = newIdArgument(e.arguments); 1275 QByteArray new_id_str = "void "; 1276 if (new_id) { 1277 if (new_id->interface.isEmpty()) 1278 new_id_str = "void *"; 1279 else 1280 new_id_str = "struct ::" + new_id->interface + " *"; 1281 } 1282 printf(" %s%s::", new_id_str.constData(), interfaceName); 1283 printEvent(e); 1284 printf("\n"); 1285 printf(" {\n"); 1286 for (const WaylandArgument &a : e.arguments) { 1287 if (a.type != "array") 1288 continue; 1289 QByteArray array = a.name + "_data"; 1290 const char *arrayName = array.constData(); 1291 const char *variableName = a.name.constData(); 1292 printf(" struct wl_array %s;\n", arrayName); 1293 printf(" %s.size = %s.size();\n", arrayName, variableName); 1294 printf(" %s.data = static_cast<void *>(const_cast<char *>(%s.constData()));\n", arrayName, variableName); 1295 printf(" %s.alloc = 0;\n", arrayName); 1296 printf("\n"); 1297 } 1298 int actualArgumentCount = new_id ? int(e.arguments.size()) - 1 : int(e.arguments.size()); 1299 printf(" %s%s_%s(\n", new_id ? "return " : "", interfaceName, e.name.constData()); 1300 printf(" m_%s%s", interfaceName, actualArgumentCount > 0 ? "," : ""); 1301 bool needsComma = false; 1302 for (const WaylandArgument &a : e.arguments) { 1303 bool isNewId = a.type == "new_id"; 1304 if (isNewId && !a.interface.isEmpty()) 1305 continue; 1306 if (needsComma) 1307 printf(","); 1308 needsComma = true; 1309 printf("\n"); 1310 if (isNewId) { 1311 printf(" interface,\n"); 1312 printf(" version"); 1313 } else { 1314 QByteArray cType = waylandToCType(a.type, a.interface); 1315 QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); 1316 if (a.type == "string") 1317 printf(" %s.toUtf8().constData()", a.name.constData()); 1318 else if (a.type == "array") 1319 printf(" &%s_data", a.name.constData()); 1320 else if (cType == qtType) 1321 printf(" %s", a.name.constData()); 1322 } 1323 } 1324 printf(");\n"); 1325 if (e.type == "destructor") 1326 printf(" m_%s = nullptr;\n", interfaceName); 1327 printf(" }\n"); 1328 } 1329 1330 if (hasEvents) { 1331 printf("\n"); 1332 for (const WaylandEvent &e : interface.events) { 1333 printf(" void %s::%s_", interfaceName, interfaceNameStripped); 1334 printEvent(e, true); 1335 printf("\n"); 1336 printf(" {\n"); 1337 printf(" }\n"); 1338 printf("\n"); 1339 printf(" void %s::", interfaceName); 1340 printEventHandlerSignature(e, interfaceName, false); 1341 printf("\n"); 1342 printf(" {\n"); 1343 printf(" Q_UNUSED(object);\n"); 1344 printf(" static_cast<%s *>(data)->%s_%s(", interfaceName, interfaceNameStripped, e.name.constData()); 1345 bool needsComma = false; 1346 for (const WaylandArgument &a : e.arguments) { 1347 if (needsComma) 1348 printf(","); 1349 needsComma = true; 1350 printf("\n"); 1351 const char *argumentName = a.name.constData(); 1352 if (a.type == "string") 1353 printf(" QString::fromUtf8(%s)", argumentName); 1354 else 1355 printf(" %s", argumentName); 1356 } 1357 printf(");\n"); 1358 1359 printf(" }\n"); 1360 printf("\n"); 1361 } 1362 printf(" const struct %s_listener %s::m_%s_listener = {\n", interfaceName, interfaceName, interfaceName); 1363 for (const WaylandEvent &e : interface.events) { 1364 printf(" %s::handle_%s,\n", interfaceName, e.name.constData()); 1365 } 1366 printf(" };\n"); 1367 printf("\n"); 1368 1369 printf(" void %s::init_listener()\n", interfaceName); 1370 printf(" {\n"); 1371 printf(" %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName); 1372 printf(" }\n"); 1373 } 1374 } 1375 printf("}\n"); 1376 printf("\n"); 1377 printf("QT_WARNING_POP\n"); 1378 printf("QT_END_NAMESPACE\n"); 1379 } 1380 1381 return true; 1382 } 1383 1384 void Scanner::printErrors() 1385 { 1386 if (m_xml->hasError()) 1387 fprintf(stderr, "XML error: %s\nLine %lld, column %lld\n", m_xml->errorString().toLocal8Bit().constData(), m_xml->lineNumber(), m_xml->columnNumber()); 1388 } 1389 1390 int main(int argc, char **argv) 1391 { 1392 QCoreApplication app(argc, argv); 1393 Scanner scanner; 1394 1395 if (!scanner.parseArguments(argc, argv)) { 1396 scanner.printUsage(); 1397 return EXIT_FAILURE; 1398 } 1399 1400 if (!scanner.process()) { 1401 scanner.printErrors(); 1402 return EXIT_FAILURE; 1403 } 1404 1405 return EXIT_SUCCESS; 1406 }