KWin
Loading...
Searching...
No Matches
qtwaylandscanner.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QCoreApplication>
41#include <QFile>
42#include <QXmlStreamReader>
43
44#include <vector>
45#include <utility>
46
48{
49public:
50 explicit Scanner() {}
51 ~Scanner() { delete m_xml; }
52
53 bool parseArguments(int argc, char **argv);
54 void printUsage();
55 bool process();
56 void printErrors();
57
58private:
59 struct WaylandEnumEntry {
60 QByteArray name;
61 QByteArray value;
62 QByteArray summary;
63 };
64
65 struct WaylandEnum {
66 QByteArray name;
67
68 std::vector<WaylandEnumEntry> entries;
69 };
70
71 struct WaylandArgument {
72 QByteArray name;
73 QByteArray type;
74 QByteArray interface;
75 QByteArray summary;
76 bool allowNull;
77 };
78
79 struct WaylandEvent {
80 bool request;
81 QByteArray name;
82 QByteArray type;
83 std::vector<WaylandArgument> arguments;
84 };
85
86 struct WaylandInterface {
87 QByteArray name;
88 int version;
89
90 std::vector<WaylandEnum> enums;
91 std::vector<WaylandEvent> events;
92 std::vector<WaylandEvent> requests;
93 };
94
95 bool isServerSide();
96 bool parseOption(const QByteArray &str);
97
98 QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name);
99 int intValue(const QXmlStreamReader &xml, const char *name, int defaultValue = 0);
100 bool boolValue(const QXmlStreamReader &xml, const char *name);
101 WaylandEvent readEvent(QXmlStreamReader &xml, bool request);
102 Scanner::WaylandEnum readEnum(QXmlStreamReader &xml);
103 Scanner::WaylandInterface readInterface(QXmlStreamReader &xml);
104 QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface);
105 QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray);
106 const Scanner::WaylandArgument *newIdArgument(const std::vector<WaylandArgument> &arguments);
107
108 void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource = false);
109 void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true);
110 void printEnums(const std::vector<WaylandEnum> &enums);
111
112 QByteArray stripInterfaceName(const QByteArray &name);
113 bool ignoreInterface(const QByteArray &name);
114
115 enum Option {
116 ClientHeader,
117 ServerHeader,
118 ClientCode,
119 ServerCode,
120 } m_option;
121
122 QByteArray m_protocolName;
123 QByteArray m_protocolFilePath;
124 QByteArray m_scannerName;
125 QByteArray m_headerPath;
126 QByteArray m_prefix;
127 QList <QByteArray> m_includes;
128 QXmlStreamReader *m_xml = nullptr;
129};
130
131bool Scanner::parseArguments(int argc, char **argv)
132{
133 QList<QByteArray> args;
134 args.reserve(argc);
135 for (int i = 0; i < argc; ++i)
136 args << QByteArray(argv[i]);
137
138 m_scannerName = args[0];
139
140 if (argc <= 2 || !parseOption(args[1]))
141 return false;
142
143 m_protocolFilePath = args[2];
144
145 if (argc > 3 && !args[3].startsWith('-')) {
146 // legacy positional arguments
147 m_headerPath = args[3];
148 if (argc == 5)
149 m_prefix = args[4];
150 } else {
151 // --header-path=<path> (14 characters)
152 // --prefix=<prefix> (9 characters)
153 // --add-include=<include> (14 characters)
154 for (int pos = 3; pos < argc; pos++) {
155 const QByteArray &option = args[pos];
156 if (option.startsWith("--header-path=")) {
157 m_headerPath = option.mid(14);
158 } else if (option.startsWith("--prefix=")) {
159 m_prefix = option.mid(10);
160 } else if (option.startsWith("--add-include=")) {
161 auto include = option.mid(14);
162 if (!include.isEmpty())
163 m_includes << include;
164 } else {
165 return false;
166 }
167 }
168 }
169
170 return true;
171}
172
174{
175 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());
176}
177
178bool Scanner::isServerSide()
179{
180 return m_option == ServerHeader || m_option == ServerCode;
181}
182
183bool Scanner::parseOption(const QByteArray &str)
184{
185 if (str == "client-header")
186 m_option = ClientHeader;
187 else if (str == "server-header")
188 m_option = ServerHeader;
189 else if (str == "client-code")
190 m_option = ClientCode;
191 else if (str == "server-code")
192 m_option = ServerCode;
193 else
194 return false;
195
196 return true;
197}
198
199QByteArray Scanner::byteArrayValue(const QXmlStreamReader &xml, const char *name)
200{
201 if (xml.attributes().hasAttribute(name))
202 return xml.attributes().value(name).toUtf8();
203 return QByteArray();
204}
205
206int Scanner::intValue(const QXmlStreamReader &xml, const char *name, int defaultValue)
207{
208 bool ok;
209 int result = byteArrayValue(xml, name).toInt(&ok);
210 return ok ? result : defaultValue;
211}
212
213bool Scanner::boolValue(const QXmlStreamReader &xml, const char *name)
214{
215 return byteArrayValue(xml, name) == "true";
216}
217
218Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request)
219{
220 WaylandEvent event = {
221 .request = request,
222 .name = byteArrayValue(xml, "name"),
223 .type = byteArrayValue(xml, "type"),
224 .arguments = {},
225 };
226 while (xml.readNextStartElement()) {
227 if (xml.name() == QLatin1String("arg")) {
228 WaylandArgument argument = {
229 .name = byteArrayValue(xml, "name"),
230 .type = byteArrayValue(xml, "type"),
231 .interface = byteArrayValue(xml, "interface"),
232 .summary = byteArrayValue(xml, "summary"),
233 .allowNull = boolValue(xml, "allowNull"),
234 };
235 event.arguments.push_back(std::move(argument));
236 }
237
238 xml.skipCurrentElement();
239 }
240 return event;
241}
242
243Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml)
244{
245 WaylandEnum result = {
246 .name = byteArrayValue(xml, "name"),
247 .entries = {},
248 };
249
250 while (xml.readNextStartElement()) {
251 if (xml.name() == QLatin1String("entry")) {
252 WaylandEnumEntry entry = {
253 .name = byteArrayValue(xml, "name"),
254 .value = byteArrayValue(xml, "value"),
255 .summary = byteArrayValue(xml, "summary"),
256 };
257 result.entries.push_back(std::move(entry));
258 }
259
260 xml.skipCurrentElement();
261 }
262
263 return result;
264}
265
266Scanner::WaylandInterface Scanner::readInterface(QXmlStreamReader &xml)
267{
268 WaylandInterface interface = {
269 .name = byteArrayValue(xml, "name"),
270 .version = intValue(xml, "version", 1),
271 .enums = {},
272 .events = {},
273 .requests = {},
274 };
275
276 while (xml.readNextStartElement()) {
277 if (xml.name() == QLatin1String("event"))
278 interface.events.push_back(readEvent(xml, false));
279 else if (xml.name() == QLatin1String("request"))
280 interface.requests.push_back(readEvent(xml, true));
281 else if (xml.name() == QLatin1String("enum"))
282 interface.enums.push_back(readEnum(xml));
283 else
284 xml.skipCurrentElement();
285 }
286
287 return interface;
288}
289
290QByteArray Scanner::waylandToCType(const QByteArray &waylandType, const QByteArray &interface)
291{
292 if (waylandType == "string")
293 return "const char *";
294 else if (waylandType == "int")
295 return "int32_t";
296 else if (waylandType == "uint")
297 return "uint32_t";
298 else if (waylandType == "fixed")
299 return "wl_fixed_t";
300 else if (waylandType == "fd")
301 return "int32_t";
302 else if (waylandType == "array")
303 return "wl_array *";
304 else if (waylandType == "object" || waylandType == "new_id") {
305 if (isServerSide())
306 return "struct ::wl_resource *";
307 if (interface.isEmpty())
308 return "struct ::wl_object *";
309 return "struct ::" + interface + " *";
310 }
311 return waylandType;
312}
313
314QByteArray Scanner::waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray)
315{
316 if (waylandType == "string")
317 return "const QString &";
318 else if (waylandType == "array")
319 return cStyleArray ? "wl_array *" : "const QByteArray &";
320 else
321 return waylandToCType(waylandType, interface);
322}
323
324const Scanner::WaylandArgument *Scanner::newIdArgument(const std::vector<WaylandArgument> &arguments)
325{
326 for (const WaylandArgument &a : arguments) {
327 if (a.type == "new_id")
328 return &a;
329 }
330 return nullptr;
331}
332
333void Scanner::printEvent(const WaylandEvent &e, bool omitNames, bool withResource)
334{
335 printf("%s(", e.name.constData());
336 bool needsComma = false;
337 if (isServerSide()) {
338 if (e.request) {
339 printf("Resource *%s", omitNames ? "" : "resource");
340 needsComma = true;
341 } else if (withResource) {
342 printf("struct ::wl_resource *%s", omitNames ? "" : "resource");
343 needsComma = true;
344 }
345 }
346 for (const WaylandArgument &a : e.arguments) {
347 bool isNewId = a.type == "new_id";
348 if (isNewId && !isServerSide() && (a.interface.isEmpty() != e.request))
349 continue;
350 if (needsComma)
351 printf(", ");
352 needsComma = true;
353 if (isNewId) {
354 if (isServerSide()) {
355 if (e.request) {
356 printf("uint32_t");
357 if (!omitNames)
358 printf(" %s", a.name.constData());
359 continue;
360 }
361 } else {
362 if (e.request) {
363 printf("const struct ::wl_interface *%s, uint32_t%s", omitNames ? "" : "interface", omitNames ? "" : " version");
364 continue;
365 }
366 }
367 }
368
369 QByteArray qtType = waylandToQtType(a.type, a.interface, e.request == isServerSide());
370 printf("%s%s%s", qtType.constData(), qtType.endsWith("&") || qtType.endsWith("*") ? "" : " ", omitNames ? "" : a.name.constData());
371 }
372 printf(")");
373}
374
375void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent)
376{
377 const char *indent = deepIndent ? " " : "";
378 printf("handle_%s(\n", e.name.constData());
379 if (isServerSide()) {
380 printf(" %s::wl_client *client,\n", indent);
381 printf(" %sstruct wl_resource *resource", indent);
382 } else {
383 printf(" %svoid *data,\n", indent);
384 printf(" %sstruct ::%s *object", indent, interfaceName);
385 }
386 for (const WaylandArgument &a : e.arguments) {
387 printf(",\n");
388 bool isNewId = a.type == "new_id";
389 if (isServerSide() && isNewId) {
390 printf(" %suint32_t %s", indent, a.name.constData());
391 } else {
392 QByteArray cType = waylandToCType(a.type, a.interface);
393 printf(" %s%s%s%s", indent, cType.constData(), cType.endsWith("*") ? "" : " ", a.name.constData());
394 }
395 }
396 printf(")");
397}
398
399void Scanner::printEnums(const std::vector<WaylandEnum> &enums)
400{
401 for (const WaylandEnum &e : enums) {
402 printf("\n");
403 printf(" enum %s {\n", e.name.constData());
404 for (const WaylandEnumEntry &entry : e.entries) {
405 printf(" %s_%s = %s,", e.name.constData(), entry.name.constData(), entry.value.constData());
406 if (!entry.summary.isNull())
407 printf(" // %s", entry.summary.constData());
408 printf("\n");
409 }
410 printf(" };\n");
411 }
412}
413
414QByteArray Scanner::stripInterfaceName(const QByteArray &name)
415{
416 if (!m_prefix.isEmpty() && name.startsWith(m_prefix))
417 return name.mid(m_prefix.size());
418 if (name.startsWith("qt_") || name.startsWith("wl_"))
419 return name.mid(3);
420
421 return name;
422}
423
424bool Scanner::ignoreInterface(const QByteArray &name)
425{
426 return name == "wl_display"
427 || (isServerSide() && name == "wl_registry");
428}
429
431{
432 QFile file(m_protocolFilePath);
433 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
434 fprintf(stderr, "Unable to open file %s\n", m_protocolFilePath.constData());
435 return false;
436 }
437
438 m_xml = new QXmlStreamReader(&file);
439 if (!m_xml->readNextStartElement())
440 return false;
441
442 if (m_xml->name() != QLatin1String("protocol")) {
443 m_xml->raiseError(QStringLiteral("The file is not a wayland protocol file."));
444 return false;
445 }
446
447 m_protocolName = byteArrayValue(*m_xml, "name");
448
449 if (m_protocolName.isEmpty()) {
450 m_xml->raiseError(QStringLiteral("Missing protocol name."));
451 return false;
452 }
453
454 //We should convert - to _ so that the preprocessor wont generate code which will lead to unexpected behavior
455 //However, the wayland-scanner doesn't do so we will do the same for now
456 //QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper();
457 QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper();
458
459 std::vector<WaylandInterface> interfaces;
460
461 while (m_xml->readNextStartElement()) {
462 if (m_xml->name() == QLatin1String("interface"))
463 interfaces.push_back(readInterface(*m_xml));
464 else
465 m_xml->skipCurrentElement();
466 }
467
468 if (m_xml->hasError())
469 return false;
470
471 printf("// This file was generated by qtwaylandscanner\n");
472 printf("// source file is %s\n\n", qPrintable(m_protocolFilePath));
473
474 for (auto b : std::as_const(m_includes))
475 printf("#include %s\n", b.constData());
476
477 if (m_option == ServerHeader) {
478 QByteArray inclusionGuard = QByteArray("QT_WAYLAND_SERVER_") + preProcessorProtocolName.constData();
479 printf("#ifndef %s\n", inclusionGuard.constData());
480 printf("#define %s\n", inclusionGuard.constData());
481 printf("\n");
482 printf("#include \"wayland-server-core.h\"\n");
483 if (m_headerPath.isEmpty())
484 printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
485 else
486 printf("#include <%s/wayland-%s-server-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
487 printf("#include <QByteArray>\n");
488 printf("#include <QMultiMap>\n");
489 printf("#include <QString>\n");
490
491 printf("\n");
492 printf("#include <unistd.h>\n");
493
494 printf("\n");
495 printf("#ifndef WAYLAND_VERSION_CHECK\n");
496 printf("#define WAYLAND_VERSION_CHECK(major, minor, micro) \\\n");
497 printf(" ((WAYLAND_VERSION_MAJOR > (major)) || \\\n");
498 printf(" (WAYLAND_VERSION_MAJOR == (major) && WAYLAND_VERSION_MINOR > (minor)) || \\\n");
499 printf(" (WAYLAND_VERSION_MAJOR == (major) && WAYLAND_VERSION_MINOR == (minor) && WAYLAND_VERSION_MICRO >= (micro)))\n");
500 printf("#endif\n");
501
502 printf("\n");
503 printf("QT_BEGIN_NAMESPACE\n");
504 printf("QT_WARNING_PUSH\n");
505 printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
506 printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n");
507 QByteArray serverExport;
508 if (m_headerPath.size()) {
509 serverExport = QByteArray("Q_WAYLAND_SERVER_") + preProcessorProtocolName + "_EXPORT";
510 printf("\n");
511 printf("#if !defined(%s)\n", serverExport.constData());
512 printf("# if defined(QT_SHARED)\n");
513 printf("# define %s Q_DECL_EXPORT\n", serverExport.constData());
514 printf("# else\n");
515 printf("# define %s\n", serverExport.constData());
516 printf("# endif\n");
517 printf("#endif\n");
518 }
519 printf("\n");
520 printf("namespace QtWaylandServer {\n");
521
522 bool needsNewLine = false;
523 for (const WaylandInterface &interface : interfaces) {
524
525 if (ignoreInterface(interface.name))
526 continue;
527
528 if (needsNewLine)
529 printf("\n");
530 needsNewLine = true;
531
532 const char *interfaceName = interface.name.constData();
533
534 QByteArray stripped = stripInterfaceName(interface.name);
535 const char *interfaceNameStripped = stripped.constData();
536
537 printf(" class %s %s\n {\n", serverExport.constData(), interfaceName);
538 printf(" public:\n");
539 printf(" %s(struct ::wl_client *client, int id, int version);\n", interfaceName);
540 printf(" %s(struct ::wl_display *display, int version);\n", interfaceName);
541 printf(" %s(struct ::wl_resource *resource);\n", interfaceName);
542 printf(" %s();\n", interfaceName);
543 printf("\n");
544 printf(" virtual ~%s();\n", interfaceName);
545 printf("\n");
546 printf(" class Resource\n");
547 printf(" {\n");
548 printf(" public:\n");
549 printf(" Resource() : %s_object(nullptr), handle(nullptr) {}\n", interfaceNameStripped);
550 printf(" virtual ~Resource() {}\n");
551 printf("\n");
552 printf(" %s *%s_object;\n", interfaceName, interfaceNameStripped);
553 printf(" %s *object() { return %s_object; } \n", interfaceName, interfaceNameStripped);
554 printf(" struct ::wl_resource *handle;\n");
555 printf("\n");
556 printf(" struct ::wl_client *client() const { return wl_resource_get_client(handle); }\n");
557 printf(" int version() const { return wl_resource_get_version(handle); }\n");
558 printf("\n");
559 printf(" static Resource *fromResource(struct ::wl_resource *resource);\n");
560 printf(" };\n");
561 printf("\n");
562 printf(" void init(struct ::wl_client *client, int id, int version);\n");
563 printf(" void init(struct ::wl_display *display, int version);\n");
564 printf(" void init(struct ::wl_resource *resource);\n");
565 printf("\n");
566 printf(" Resource *add(struct ::wl_client *client, int version);\n");
567 printf(" Resource *add(struct ::wl_client *client, int id, int version);\n");
568 printf(" Resource *add(struct wl_list *resource_list, struct ::wl_client *client, int id, int version);\n");
569 printf("\n");
570 printf(" Resource *resource() { return m_resource; }\n");
571 printf(" const Resource *resource() const { return m_resource; }\n");
572 printf("\n");
573 printf(" QMultiMap<struct ::wl_client*, Resource*> resourceMap() { return m_resource_map; }\n");
574 printf(" const QMultiMap<struct ::wl_client*, Resource*> resourceMap() const { return m_resource_map; }\n");
575 printf("\n");
576 printf(" bool isGlobalRemoved() const { return m_globalRemovedEvent; }\n");
577 printf(" void globalRemove();\n");
578 printf("\n");
579 printf(" bool isGlobal() const { return m_global != nullptr; }\n");
580 printf(" bool isResource() const { return m_resource != nullptr; }\n");
581 printf("\n");
582 printf(" static const struct ::wl_interface *interface();\n");
583 printf(" static QByteArray interfaceName() { return interface()->name; }\n");
584 printf(" static int interfaceVersion() { return interface()->version; }\n");
585 printf("\n");
586
587 printEnums(interface.enums);
588
589 bool hasEvents = !interface.events.empty();
590
591 if (hasEvents) {
592 printf("\n");
593 for (const WaylandEvent &e : interface.events) {
594 printf(" void send_");
595 printEvent(e);
596 printf(";\n");
597 printf(" void send_");
598 printEvent(e, false, true);
599 printf(";\n");
600 }
601 }
602
603 printf("\n");
604 printf(" protected:\n");
605 printf(" virtual Resource *%s_allocate();\n", interfaceNameStripped);
606 printf("\n");
607 printf(" virtual void %s_destroy_global();\n", interfaceNameStripped);
608 printf("\n");
609 printf(" virtual void %s_bind_resource(Resource *resource);\n", interfaceNameStripped);
610 printf(" virtual void %s_destroy_resource(Resource *resource);\n", interfaceNameStripped);
611
612 bool hasRequests = !interface.requests.empty();
613
614 if (hasRequests) {
615 printf("\n");
616 for (const WaylandEvent &e : interface.requests) {
617 printf(" virtual void %s_", interfaceNameStripped);
618 printEvent(e);
619 printf(";\n");
620 }
621 }
622
623 printf("\n");
624 printf(" private:\n");
625 printf(" static void bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id);\n");
626 printf(" static void destroy_func(struct ::wl_resource *client_resource);\n");
627 printf(" static void display_destroy_func(struct ::wl_listener *listener, void *data);\n");
628 printf(" static int deferred_destroy_global_func(void *data);\n");
629 printf("\n");
630 printf(" Resource *bind(struct ::wl_client *client, uint32_t id, int version);\n");
631 printf(" Resource *bind(struct ::wl_resource *handle);\n");
632
633 if (hasRequests) {
634 printf("\n");
635 printf(" static const struct ::%s_interface m_%s_interface;\n", interfaceName, interfaceName);
636
637 printf("\n");
638 for (const WaylandEvent &e : interface.requests) {
639 printf(" static void ");
640
641 printEventHandlerSignature(e, interfaceName);
642 printf(";\n");
643 }
644 }
645
646 printf("\n");
647 printf(" QMultiMap<struct ::wl_client*, Resource*> m_resource_map;\n");
648 printf(" Resource *m_resource;\n");
649 printf(" struct ::wl_global *m_global;\n");
650 printf(" struct ::wl_display *m_display;\n");
651 printf(" struct wl_event_source *m_globalRemovedEvent;\n");
652 printf(" struct DisplayDestroyedListener : ::wl_listener {\n");
653 printf(" %s *parent;\n", interfaceName);
654 printf(" };\n");
655 printf(" DisplayDestroyedListener m_displayDestroyedListener;\n");
656 printf(" };\n");
657 }
658
659 printf("}\n");
660 printf("\n");
661 printf("QT_WARNING_POP\n");
662 printf("QT_END_NAMESPACE\n");
663 printf("\n");
664 printf("#endif\n");
665 }
666
667 if (m_option == ServerCode) {
668 if (m_headerPath.isEmpty())
669 printf("#include \"qwayland-server-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
670 else
671 printf("#include <%s/qwayland-server-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
672 printf("\n");
673 printf("QT_BEGIN_NAMESPACE\n");
674 printf("QT_WARNING_PUSH\n");
675 printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
676 printf("\n");
677 printf("namespace QtWaylandServer {\n");
678
679 bool needsNewLine = false;
680
681 for (const WaylandInterface &interface : interfaces) {
682
683 if (ignoreInterface(interface.name))
684 continue;
685
686 if (needsNewLine)
687 printf("\n");
688
689 needsNewLine = true;
690
691 const char *interfaceName = interface.name.constData();
692
693 QByteArray stripped = stripInterfaceName(interface.name);
694 const char *interfaceNameStripped = stripped.constData();
695
696 printf("\n");
697 printf(" int %s::deferred_destroy_global_func(void *data) {\n", interfaceName);
698 printf(" auto object = static_cast<%s *>(data);\n", interfaceName);
699 printf(" wl_global_destroy(object->m_global);\n");
700 printf(" object->m_global = nullptr;\n");
701 printf(" wl_event_source_remove(object->m_globalRemovedEvent);\n");
702 printf(" object->m_globalRemovedEvent = nullptr;\n");
703 printf(" wl_list_remove(&object->m_displayDestroyedListener.link);\n");
704 printf(" object->%s_destroy_global();\n", interfaceNameStripped);
705 printf(" return 0;\n");
706 printf(" }\n");
707 printf("\n");
708
709 printf(" %s::%s(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName);
710 printf(" : m_resource_map()\n");
711 printf(" , m_resource(nullptr)\n");
712 printf(" , m_global(nullptr)\n");
713 printf(" , m_display(nullptr)\n");
714 printf(" , m_globalRemovedEvent(nullptr)\n");
715 printf(" {\n");
716 printf(" init(client, id, version);\n");
717 printf(" }\n");
718 printf("\n");
719
720 printf(" %s::%s(struct ::wl_display *display, int version)\n", interfaceName, interfaceName);
721 printf(" : m_resource_map()\n");
722 printf(" , m_resource(nullptr)\n");
723 printf(" , m_global(nullptr)\n");
724 printf(" , m_display(nullptr)\n");
725 printf(" , m_globalRemovedEvent(nullptr)\n");
726 printf(" {\n");
727 printf(" init(display, version);\n");
728 printf(" }\n");
729 printf("\n");
730
731 printf(" %s::%s(struct ::wl_resource *resource)\n", interfaceName, interfaceName);
732 printf(" : m_resource_map()\n");
733 printf(" , m_resource(nullptr)\n");
734 printf(" , m_global(nullptr)\n");
735 printf(" , m_display(nullptr)\n");
736 printf(" , m_globalRemovedEvent(nullptr)\n");
737 printf(" {\n");
738 printf(" init(resource);\n");
739 printf(" }\n");
740 printf("\n");
741
742 printf(" %s::%s()\n", interfaceName, interfaceName);
743 printf(" : m_resource_map()\n");
744 printf(" , m_resource(nullptr)\n");
745 printf(" , m_global(nullptr)\n");
746 printf(" , m_display(nullptr)\n");
747 printf(" , m_globalRemovedEvent(nullptr)\n");
748 printf(" {\n");
749 printf(" }\n");
750 printf("\n");
751
752 printf(" %s::~%s()\n", interfaceName, interfaceName);
753 printf(" {\n");
754 printf(" for (auto resource : std::as_const(m_resource_map))\n");
755 printf(" resource->%s_object = nullptr;\n", interfaceNameStripped);
756 printf("\n");
757 printf(" if (m_resource)\n");
758 printf(" m_resource->%s_object = nullptr;\n", interfaceNameStripped);
759 printf("\n");
760 printf(" if (m_global) {\n");
761 printf(" if (m_globalRemovedEvent)\n");
762 printf(" wl_event_source_remove(m_globalRemovedEvent);\n");
763 printf(" wl_global_destroy(m_global);\n");
764 printf(" wl_list_remove(&m_displayDestroyedListener.link);\n");
765 printf(" }\n");
766 printf(" }\n");
767 printf("\n");
768
769 printf(" void %s::init(struct ::wl_client *client, int id, int version)\n", interfaceName);
770 printf(" {\n");
771 printf(" m_resource = bind(client, id, version);\n");
772 printf(" }\n");
773 printf("\n");
774
775 printf(" void %s::init(struct ::wl_resource *resource)\n", interfaceName);
776 printf(" {\n");
777 printf(" m_resource = bind(resource);\n");
778 printf(" }\n");
779 printf("\n");
780
781 printf(" %s::Resource *%s::add(struct ::wl_client *client, int version)\n", interfaceName, interfaceName);
782 printf(" {\n");
783 printf(" Resource *resource = bind(client, 0, version);\n");
784 printf(" m_resource_map.insert(client, resource);\n");
785 printf(" return resource;\n");
786 printf(" }\n");
787 printf("\n");
788
789 printf(" %s::Resource *%s::add(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName);
790 printf(" {\n");
791 printf(" Resource *resource = bind(client, id, version);\n");
792 printf(" m_resource_map.insert(client, resource);\n");
793 printf(" return resource;\n");
794 printf(" }\n");
795 printf("\n");
796
797 printf(" void %s::init(struct ::wl_display *display, int version)\n", interfaceName);
798 printf(" {\n");
799 printf(" m_display = display;\n");
800 printf(" m_global = wl_global_create(display, &::%s_interface, version, this, bind_func);\n", interfaceName);
801 printf(" m_displayDestroyedListener.notify = %s::display_destroy_func;\n", interfaceName);
802 printf(" m_displayDestroyedListener.parent = this;\n");
803 printf(" wl_display_add_destroy_listener(display, &m_displayDestroyedListener);\n");
804 printf(" }\n");
805 printf("\n");
806
807 printf(" const struct wl_interface *%s::interface()\n", interfaceName);
808 printf(" {\n");
809 printf(" return &::%s_interface;\n", interfaceName);
810 printf(" }\n");
811 printf("\n");
812
813 printf(" %s::Resource *%s::%s_allocate()\n", interfaceName, interfaceName, interfaceNameStripped);
814 printf(" {\n");
815 printf(" return new Resource;\n");
816 printf(" }\n");
817 printf("\n");
818
819 printf(" void %s::%s_destroy_global()\n", interfaceName, interfaceNameStripped);
820 printf(" {\n");
821 printf(" }\n");
822 printf("\n");
823
824 printf(" void %s::%s_bind_resource(Resource *)\n", interfaceName, interfaceNameStripped);
825 printf(" {\n");
826 printf(" }\n");
827 printf("\n");
828
829 printf(" void %s::%s_destroy_resource(Resource *)\n", interfaceName, interfaceNameStripped);
830 printf(" {\n");
831 printf(" }\n");
832 printf("\n");
833
834 printf(" void %s::bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id)\n", interfaceName);
835 printf(" {\n");
836 printf(" %s *that = static_cast<%s *>(data);\n", interfaceName, interfaceName);
837 printf(" that->add(client, id, version);\n");
838 printf(" }\n");
839 printf("\n");
840
841 printf(" void %s::display_destroy_func(struct ::wl_listener *listener, void *data)\n", interfaceName);
842 printf(" {\n");
843 printf(" Q_UNUSED(data);\n");
844 printf(" %s *that = static_cast<%s::DisplayDestroyedListener *>(listener)->parent;\n", interfaceName, interfaceName);
845 printf(" that->m_global = nullptr;\n");
846 printf(" that->m_globalRemovedEvent = nullptr;\n");
847 printf(" }\n");
848 printf("\n");
849
850 printf(" void %s::destroy_func(struct ::wl_resource *client_resource)\n", interfaceName);
851 printf(" {\n");
852 printf(" Resource *resource = Resource::fromResource(client_resource);\n");
853 printf(" Q_ASSERT(resource);\n");
854 printf(" %s *that = resource->%s_object;\n", interfaceName, interfaceNameStripped);
855 printf(" if (Q_LIKELY(that)) {\n");
856 printf(" that->m_resource_map.remove(resource->client(), resource);\n");
857 printf(" that->%s_destroy_resource(resource);\n", interfaceNameStripped);
858 printf("\n");
859 printf(" that = resource->%s_object;\n", interfaceNameStripped);
860 printf(" if (that && that->m_resource == resource)\n");
861 printf(" that->m_resource = nullptr;\n");
862 printf(" }\n");
863 printf(" delete resource;\n");
864 printf(" }\n");
865 printf("\n");
866
867 // Removing a global is racey. Announce removal, and then only perform internal cleanup after a delay
868 // See https://gitlab.freedesktop.org/wayland/wayland/issues/10
869 printf("\n");
870 printf(" void %s::globalRemove()\n", interfaceName);
871 printf(" {\n");
872 printf(" if (!m_global || m_globalRemovedEvent)\n");
873 printf(" return;\n");
874 printf("\n");
875 printf(" wl_global_remove(m_global);\n");
876 printf("\n");
877 printf(" struct wl_event_loop *event_loop = wl_display_get_event_loop(m_display);\n");
878 printf(" m_globalRemovedEvent = wl_event_loop_add_timer(event_loop, deferred_destroy_global_func, this);\n");
879 printf(" wl_event_source_timer_update(m_globalRemovedEvent, 5000);\n");
880 printf(" }\n");
881 printf("\n");
882
883 bool hasRequests = !interface.requests.empty();
884
885 QByteArray interfaceMember = hasRequests ? "&m_" + interface.name + "_interface" : QByteArray("nullptr");
886
887 //We should consider changing bind so that it doesn't special case id == 0
888 //and use function overloading instead. Jan do you have a lot of code dependent on this behavior?
889 printf(" %s::Resource *%s::bind(struct ::wl_client *client, uint32_t id, int version)\n", interfaceName, interfaceName);
890 printf(" {\n");
891 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");
892 printf(" struct ::wl_resource *handle = wl_resource_create(client, &::%s_interface, version, id);\n", interfaceName);
893 printf(" return bind(handle);\n");
894 printf(" }\n");
895 printf("\n");
896
897 printf(" %s::Resource *%s::bind(struct ::wl_resource *handle)\n", interfaceName, interfaceName);
898 printf(" {\n");
899 printf(" Resource *resource = %s_allocate();\n", interfaceNameStripped);
900 printf(" resource->%s_object = this;\n", interfaceNameStripped);
901 printf("\n");
902 printf(" wl_resource_set_implementation(handle, %s, resource, destroy_func);", interfaceMember.constData());
903 printf("\n");
904 printf(" resource->handle = handle;\n");
905 printf(" %s_bind_resource(resource);\n", interfaceNameStripped);
906 printf(" return resource;\n");
907 printf(" }\n");
908
909 printf(" %s::Resource *%s::Resource::fromResource(struct ::wl_resource *resource)\n", interfaceName, interfaceName);
910 printf(" {\n");
911 printf(" if (Q_UNLIKELY(!resource))\n");
912 printf(" return nullptr;\n");
913 printf(" if (wl_resource_instance_of(resource, &::%s_interface, %s))\n", interfaceName, interfaceMember.constData());
914 printf(" return static_cast<Resource *>(wl_resource_get_user_data(resource));\n");
915 printf(" return nullptr;\n");
916 printf(" }\n");
917
918 if (hasRequests) {
919 printf("\n");
920 printf(" const struct ::%s_interface %s::m_%s_interface = {", interfaceName, interfaceName, interfaceName);
921 bool needsComma = false;
922 for (const WaylandEvent &e : interface.requests) {
923 if (needsComma)
924 printf(",");
925 needsComma = true;
926 printf("\n");
927 printf(" %s::handle_%s", interfaceName, e.name.constData());
928 }
929 printf("\n");
930 printf(" };\n");
931
932 for (const WaylandEvent &e : interface.requests) {
933 printf("\n");
934 printf(" void %s::%s_", interfaceName, interfaceNameStripped);
935 printEvent(e, true);
936 printf("\n");
937 printf(" {\n");
938 printf(" }\n");
939 }
940 printf("\n");
941
942 for (const WaylandEvent &e : interface.requests) {
943 printf("\n");
944 printf(" void %s::", interfaceName);
945
946 printEventHandlerSignature(e, interfaceName, false);
947
948 printf("\n");
949 printf(" {\n");
950 printf(" Q_UNUSED(client);\n");
951 printf(" Resource *r = Resource::fromResource(resource);\n");
952 printf(" if (Q_UNLIKELY(!r->%s_object)) {\n", interfaceNameStripped);
953 for (const WaylandArgument &a : e.arguments) {
954 if (a.type == QByteArrayLiteral("fd"))
955 printf(" close(%s);\n", a.name.constData());
956 }
957 if (e.type == "destructor")
958 printf(" wl_resource_destroy(resource);\n");
959 printf(" return;\n");
960 printf(" }\n");
961 printf(" static_cast<%s *>(r->%s_object)->%s_%s(\n", interfaceName, interfaceNameStripped, interfaceNameStripped, e.name.constData());
962 printf(" r");
963 for (const WaylandArgument &a : e.arguments) {
964 printf(",\n");
965 QByteArray cType = waylandToCType(a.type, a.interface);
966 QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
967 const char *argumentName = a.name.constData();
968 if (cType == qtType)
969 printf(" %s", argumentName);
970 else if (a.type == "string")
971 printf(" QString::fromUtf8(%s)", argumentName);
972 }
973 printf(");\n");
974 printf(" }\n");
975 }
976 }
977
978 for (const WaylandEvent &e : interface.events) {
979 printf("\n");
980 printf(" void %s::send_", interfaceName);
981 printEvent(e);
982 printf("\n");
983 printf(" {\n");
984 printf(" Q_ASSERT_X(m_resource, \"%s::%s\", \"Uninitialised resource\");\n", interfaceName, e.name.constData());
985 printf(" if (Q_UNLIKELY(!m_resource)) {\n");
986 printf(" qWarning(\"could not call %s::%s as it's not initialised\");\n", interfaceName, e.name.constData());
987 printf(" return;\n");
988 printf(" }\n");
989 printf(" send_%s(\n", e.name.constData());
990 printf(" m_resource->handle");
991 for (const WaylandArgument &a : e.arguments) {
992 printf(",\n");
993 printf(" %s", a.name.constData());
994 }
995 printf(");\n");
996 printf(" }\n");
997 printf("\n");
998
999 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
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
1390int 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}
bool parseArguments(int argc, char **argv)
constexpr int version