KWaylandServer

qtwaylandscanner.cpp
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 
46 class Scanner
47 {
48 public:
49  explicit Scanner() {}
50  ~Scanner() { delete m_xml; }
51 
52  bool parseArguments(int argc, char **argv);
53  void printUsage();
54  bool process();
55  void printErrors();
56 
57 private:
58  struct WaylandEnumEntry {
60  QByteArray value;
61  QByteArray summary;
62  };
63 
64  struct WaylandEnum {
66 
67  std::vector<WaylandEnumEntry> entries;
68  };
69 
70  struct WaylandArgument {
73  QByteArray interface;
74  QByteArray summary;
75  bool allowNull;
76  };
77 
78  struct WaylandEvent {
79  bool request;
82  std::vector<WaylandArgument> arguments;
83  };
84 
85  struct WaylandInterface {
87  int version;
88 
89  std::vector<WaylandEnum> enums;
90  std::vector<WaylandEvent> events;
91  std::vector<WaylandEvent> requests;
92  };
93 
94  bool isServerSide();
95  bool parseOption(const QByteArray &str);
96 
97  QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name);
98  int intValue(const QXmlStreamReader &xml, const char *name, int defaultValue = 0);
99  bool boolValue(const QXmlStreamReader &xml, const char *name);
100  WaylandEvent readEvent(QXmlStreamReader &xml, bool request);
101  Scanner::WaylandEnum readEnum(QXmlStreamReader &xml);
102  Scanner::WaylandInterface readInterface(QXmlStreamReader &xml);
103  QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface);
104  QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray);
105  const Scanner::WaylandArgument *newIdArgument(const std::vector<WaylandArgument> &arguments);
106 
107  void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource = false);
108  void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true);
109  void printEnums(const std::vector<WaylandEnum> &enums);
110 
111  QByteArray stripInterfaceName(const QByteArray &name);
112  bool ignoreInterface(const QByteArray &name);
113 
114  enum Option {
115  ClientHeader,
116  ServerHeader,
117  ClientCode,
118  ServerCode,
119  } m_option;
120 
121  QByteArray m_protocolName;
122  QByteArray m_protocolFilePath;
123  QByteArray m_scannerName;
124  QByteArray m_headerPath;
125  QByteArray m_prefix;
126  QVector <QByteArray> m_includes;
127  QXmlStreamReader *m_xml = nullptr;
128 };
129 
130 bool Scanner::parseArguments(int argc, char **argv)
131 {
132  QVector<QByteArray> args;
133  args.reserve(argc);
134  for (int i = 0; i < argc; ++i)
135  args << QByteArray(argv[i]);
136 
137  m_scannerName = args[0];
138 
139  if (argc <= 2 || !parseOption(args[1]))
140  return false;
141 
142  m_protocolFilePath = args[2];
143 
144  if (argc > 3 && !args[3].startsWith('-')) {
145  // legacy positional arguments
146  m_headerPath = args[3];
147  if (argc == 5)
148  m_prefix = args[4];
149  } else {
150  // --header-path=<path> (14 characters)
151  // --prefix=<prefix> (9 characters)
152  // --add-include=<include> (14 characters)
153  for (int pos = 3; pos < argc; pos++) {
154  const QByteArray &option = args[pos];
155  if (option.startsWith("--header-path=")) {
156  m_headerPath = option.mid(14);
157  } else if (option.startsWith("--prefix=")) {
158  m_prefix = option.mid(10);
159  } else if (option.startsWith("--add-include=")) {
160  auto include = option.mid(14);
161  if (!include.isEmpty())
162  m_includes << include;
163  } else {
164  return false;
165  }
166  }
167  }
168 
169  return true;
170 }
171 
172 void Scanner::printUsage()
173 {
174  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());
175 }
176 
177 bool Scanner::isServerSide()
178 {
179  return m_option == ServerHeader || m_option == ServerCode;
180 }
181 
182 bool Scanner::parseOption(const QByteArray &str)
183 {
184  if (str == "client-header")
185  m_option = ClientHeader;
186  else if (str == "server-header")
187  m_option = ServerHeader;
188  else if (str == "client-code")
189  m_option = ClientCode;
190  else if (str == "server-code")
191  m_option = ServerCode;
192  else
193  return false;
194 
195  return true;
196 }
197 
198 QByteArray Scanner::byteArrayValue(const QXmlStreamReader &xml, const char *name)
199 {
200  if (xml.attributes().hasAttribute(name))
201  return xml.attributes().value(name).toUtf8();
202  return QByteArray();
203 }
204 
205 int Scanner::intValue(const QXmlStreamReader &xml, const char *name, int defaultValue)
206 {
207  bool ok;
208  int result = byteArrayValue(xml, name).toInt(&ok);
209  return ok ? result : defaultValue;
210 }
211 
212 bool Scanner::boolValue(const QXmlStreamReader &xml, const char *name)
213 {
214  return byteArrayValue(xml, name) == "true";
215 }
216 
217 Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request)
218 {
219  WaylandEvent event = {
220  .request = request,
221  .name = byteArrayValue(xml, "name"),
222  .type = byteArrayValue(xml, "type"),
223  .arguments = {},
224  };
225  while (xml.readNextStartElement()) {
226  if (xml.name() == "arg") {
227  WaylandArgument argument = {
228  .name = byteArrayValue(xml, "name"),
229  .type = byteArrayValue(xml, "type"),
230  .interface = byteArrayValue(xml, "interface"),
231  .summary = byteArrayValue(xml, "summary"),
232  .allowNull = boolValue(xml, "allowNull"),
233  };
234  event.arguments.push_back(std::move(argument));
235  }
236 
237  xml.skipCurrentElement();
238  }
239  return event;
240 }
241 
242 Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml)
243 {
244  WaylandEnum result = {
245  .name = byteArrayValue(xml, "name"),
246  .entries = {},
247  };
248 
249  while (xml.readNextStartElement()) {
250  if (xml.name() == "entry") {
251  WaylandEnumEntry entry = {
252  .name = byteArrayValue(xml, "name"),
253  .value = byteArrayValue(xml, "value"),
254  .summary = byteArrayValue(xml, "summary"),
255  };
256  result.entries.push_back(std::move(entry));
257  }
258 
259  xml.skipCurrentElement();
260  }
261 
262  return result;
263 }
264 
265 Scanner::WaylandInterface Scanner::readInterface(QXmlStreamReader &xml)
266 {
267  WaylandInterface interface = {
268  .name = byteArrayValue(xml, "name"),
269  .version = intValue(xml, "version", 1),
270  .enums = {},
271  .events = {},
272  .requests = {},
273  };
274 
275  while (xml.readNextStartElement()) {
276  if (xml.name() == "event")
277  interface.events.push_back(readEvent(xml, false));
278  else if (xml.name() == "request")
279  interface.requests.push_back(readEvent(xml, true));
280  else if (xml.name() == "enum")
281  interface.enums.push_back(readEnum(xml));
282  else
283  xml.skipCurrentElement();
284  }
285 
286  return interface;
287 }
288 
289 QByteArray Scanner::waylandToCType(const QByteArray &waylandType, const QByteArray &interface)
290 {
291  if (waylandType == "string")
292  return "const char *";
293  else if (waylandType == "int")
294  return "int32_t";
295  else if (waylandType == "uint")
296  return "uint32_t";
297  else if (waylandType == "fixed")
298  return "wl_fixed_t";
299  else if (waylandType == "fd")
300  return "int32_t";
301  else if (waylandType == "array")
302  return "wl_array *";
303  else if (waylandType == "object" || waylandType == "new_id") {
304  if (isServerSide())
305  return "struct ::wl_resource *";
306  if (interface.isEmpty())
307  return "struct ::wl_object *";
308  return "struct ::" + interface + " *";
309  }
310  return waylandType;
311 }
312 
313 QByteArray Scanner::waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray)
314 {
315  if (waylandType == "string")
316  return "const QString &";
317  else if (waylandType == "array")
318  return cStyleArray ? "wl_array *" : "const QByteArray &";
319  else
320  return waylandToCType(waylandType, interface);
321 }
322 
323 const Scanner::WaylandArgument *Scanner::newIdArgument(const std::vector<WaylandArgument> &arguments)
324 {
325  for (const WaylandArgument &a : arguments) {
326  if (a.type == "new_id")
327  return &a;
328  }
329  return nullptr;
330 }
331 
332 void Scanner::printEvent(const WaylandEvent &e, bool omitNames, bool withResource)
333 {
334  printf("%s(", e.name.constData());
335  bool needsComma = false;
336  if (isServerSide()) {
337  if (e.request) {
338  printf("Resource *%s", omitNames ? "" : "resource");
339  needsComma = true;
340  } else if (withResource) {
341  printf("struct ::wl_resource *%s", omitNames ? "" : "resource");
342  needsComma = true;
343  }
344  }
345  for (const WaylandArgument &a : e.arguments) {
346  bool isNewId = a.type == "new_id";
347  if (isNewId && !isServerSide() && (a.interface.isEmpty() != e.request))
348  continue;
349  if (needsComma)
350  printf(", ");
351  needsComma = true;
352  if (isNewId) {
353  if (isServerSide()) {
354  if (e.request) {
355  printf("uint32_t");
356  if (!omitNames)
357  printf(" %s", a.name.constData());
358  continue;
359  }
360  } else {
361  if (e.request) {
362  printf("const struct ::wl_interface *%s, uint32_t%s", omitNames ? "" : "interface", omitNames ? "" : " version");
363  continue;
364  }
365  }
366  }
367 
368  QByteArray qtType = waylandToQtType(a.type, a.interface, e.request == isServerSide());
369  printf("%s%s%s", qtType.constData(), qtType.endsWith("&") || qtType.endsWith("*") ? "" : " ", omitNames ? "" : a.name.constData());
370  }
371  printf(")");
372 }
373 
374 void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent)
375 {
376  const char *indent = deepIndent ? " " : "";
377  printf("handle_%s(\n", e.name.constData());
378  if (isServerSide()) {
379  printf(" %s::wl_client *client,\n", indent);
380  printf(" %sstruct wl_resource *resource", indent);
381  } else {
382  printf(" %svoid *data,\n", indent);
383  printf(" %sstruct ::%s *object", indent, interfaceName);
384  }
385  for (const WaylandArgument &a : e.arguments) {
386  printf(",\n");
387  bool isNewId = a.type == "new_id";
388  if (isServerSide() && isNewId) {
389  printf(" %suint32_t %s", indent, a.name.constData());
390  } else {
391  QByteArray cType = waylandToCType(a.type, a.interface);
392  printf(" %s%s%s%s", indent, cType.constData(), cType.endsWith("*") ? "" : " ", a.name.constData());
393  }
394  }
395  printf(")");
396 }
397 
398 void Scanner::printEnums(const std::vector<WaylandEnum> &enums)
399 {
400  for (const WaylandEnum &e : enums) {
401  printf("\n");
402  printf(" enum %s {\n", e.name.constData());
403  for (const WaylandEnumEntry &entry : e.entries) {
404  printf(" %s_%s = %s,", e.name.constData(), entry.name.constData(), entry.value.constData());
405  if (!entry.summary.isNull())
406  printf(" // %s", entry.summary.constData());
407  printf("\n");
408  }
409  printf(" };\n");
410  }
411 }
412 
413 QByteArray Scanner::stripInterfaceName(const QByteArray &name)
414 {
415  if (!m_prefix.isEmpty() && name.startsWith(m_prefix))
416  return name.mid(m_prefix.size());
417  if (name.startsWith("qt_") || name.startsWith("wl_"))
418  return name.mid(3);
419 
420  return name;
421 }
422 
423 bool Scanner::ignoreInterface(const QByteArray &name)
424 {
425  return name == "wl_display"
426  || (isServerSide() && name == "wl_registry");
427 }
428 
429 bool Scanner::process()
430 {
431  QFile file(m_protocolFilePath);
432  if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
433  fprintf(stderr, "Unable to open file %s\n", m_protocolFilePath.constData());
434  return false;
435  }
436 
437  m_xml = new QXmlStreamReader(&file);
438  if (!m_xml->readNextStartElement())
439  return false;
440 
441  if (m_xml->name() != "protocol") {
442  m_xml->raiseError(QStringLiteral("The file is not a wayland protocol file."));
443  return false;
444  }
445 
446  m_protocolName = byteArrayValue(*m_xml, "name");
447 
448  if (m_protocolName.isEmpty()) {
449  m_xml->raiseError(QStringLiteral("Missing protocol name."));
450  return false;
451  }
452 
453  //We should convert - to _ so that the preprocessor wont generate code which will lead to unexpected behavior
454  //However, the wayland-scanner doesn't do so we will do the same for now
455  //QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper();
456  QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper();
457 
458  std::vector<WaylandInterface> interfaces;
459 
460  while (m_xml->readNextStartElement()) {
461  if (m_xml->name() == "interface")
462  interfaces.push_back(readInterface(*m_xml));
463  else
464  m_xml->skipCurrentElement();
465  }
466 
467  if (m_xml->hasError())
468  return false;
469 
470  printf("// This file was generated by qtwaylandscanner\n");
471  printf("// source file is %s\n\n", qPrintable(m_protocolFilePath));
472 
473  for (auto b : qAsConst(m_includes))
474  printf("#include %s\n", b.constData());
475 
476  if (m_option == ServerHeader) {
477  QByteArray inclusionGuard = QByteArray("QT_WAYLAND_SERVER_") + preProcessorProtocolName.constData();
478  printf("#ifndef %s\n", inclusionGuard.constData());
479  printf("#define %s\n", inclusionGuard.constData());
480  printf("\n");
481  printf("#include \"wayland-server-core.h\"\n");
482  if (m_headerPath.isEmpty())
483  printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
484  else
485  printf("#include <%s/wayland-%s-server-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
486  printf("#include <QByteArray>\n");
487  printf("#include <QMultiMap>\n");
488  printf("#include <QString>\n");
489 
490  printf("\n");
491  printf("#include <unistd.h>\n");
492 
493  printf("\n");
494  printf("#ifndef WAYLAND_VERSION_CHECK\n");
495  printf("#define WAYLAND_VERSION_CHECK(major, minor, micro) \\\n");
496  printf(" ((WAYLAND_VERSION_MAJOR > (major)) || \\\n");
497  printf(" (WAYLAND_VERSION_MAJOR == (major) && WAYLAND_VERSION_MINOR > (minor)) || \\\n");
498  printf(" (WAYLAND_VERSION_MAJOR == (major) && WAYLAND_VERSION_MINOR == (minor) && WAYLAND_VERSION_MICRO >= (micro)))\n");
499  printf("#endif\n");
500 
501  printf("\n");
502  printf("QT_BEGIN_NAMESPACE\n");
503  printf("QT_WARNING_PUSH\n");
504  printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
505  printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n");
506  QByteArray serverExport;
507  if (m_headerPath.size()) {
508  serverExport = QByteArray("Q_WAYLAND_SERVER_") + preProcessorProtocolName + "_EXPORT";
509  printf("\n");
510  printf("#if !defined(%s)\n", serverExport.constData());
511  printf("# if defined(QT_SHARED)\n");
512  printf("# define %s Q_DECL_EXPORT\n", serverExport.constData());
513  printf("# else\n");
514  printf("# define %s\n", serverExport.constData());
515  printf("# endif\n");
516  printf("#endif\n");
517  }
518  printf("\n");
519  printf("namespace QtWaylandServer {\n");
520 
521  bool needsNewLine = false;
522  for (const WaylandInterface &interface : interfaces) {
523 
524  if (ignoreInterface(interface.name))
525  continue;
526 
527  if (needsNewLine)
528  printf("\n");
529  needsNewLine = true;
530 
531  const char *interfaceName = interface.name.constData();
532 
533  QByteArray stripped = stripInterfaceName(interface.name);
534  const char *interfaceNameStripped = stripped.constData();
535 
536  printf(" class %s %s\n {\n", serverExport.constData(), interfaceName);
537  printf(" public:\n");
538  printf(" %s(struct ::wl_client *client, int id, int version);\n", interfaceName);
539  printf(" %s(struct ::wl_display *display, int version);\n", interfaceName);
540  printf(" %s(struct ::wl_resource *resource);\n", interfaceName);
541  printf(" %s();\n", interfaceName);
542  printf("\n");
543  printf(" virtual ~%s();\n", interfaceName);
544  printf("\n");
545  printf(" class Resource\n");
546  printf(" {\n");
547  printf(" public:\n");
548  printf(" Resource() : %s_object(nullptr), handle(nullptr) {}\n", interfaceNameStripped);
549  printf(" virtual ~Resource() {}\n");
550  printf("\n");
551  printf(" %s *%s_object;\n", interfaceName, interfaceNameStripped);
552  printf(" %s *object() { return %s_object; } \n", interfaceName, interfaceNameStripped);
553  printf(" struct ::wl_resource *handle;\n");
554  printf("\n");
555  printf(" struct ::wl_client *client() const { return wl_resource_get_client(handle); }\n");
556  printf(" int version() const { return wl_resource_get_version(handle); }\n");
557  printf("\n");
558  printf(" static Resource *fromResource(struct ::wl_resource *resource);\n");
559  printf(" };\n");
560  printf("\n");
561  printf(" void init(struct ::wl_client *client, int id, int version);\n");
562  printf(" void init(struct ::wl_display *display, int version);\n");
563  printf(" void init(struct ::wl_resource *resource);\n");
564  printf("\n");
565  printf(" Resource *add(struct ::wl_client *client, int version);\n");
566  printf(" Resource *add(struct ::wl_client *client, int id, int version);\n");
567  printf(" Resource *add(struct wl_list *resource_list, struct ::wl_client *client, int id, int version);\n");
568  printf("\n");
569  printf(" Resource *resource() { return m_resource; }\n");
570  printf(" const Resource *resource() const { return m_resource; }\n");
571  printf("\n");
572  printf(" QMultiMap<struct ::wl_client*, Resource*> resourceMap() { return m_resource_map; }\n");
573  printf(" const QMultiMap<struct ::wl_client*, Resource*> resourceMap() const { return m_resource_map; }\n");
574  printf("\n");
575  printf(" bool isGlobalRemoved() const { return m_globalRemovedEvent; }\n");
576  printf(" void globalRemove();\n");
577  printf("\n");
578  printf(" bool isGlobal() const { return m_global != nullptr; }\n");
579  printf(" bool isResource() const { return m_resource != nullptr; }\n");
580  printf("\n");
581  printf(" static const struct ::wl_interface *interface();\n");
582  printf(" static QByteArray interfaceName() { return interface()->name; }\n");
583  printf(" static int interfaceVersion() { return interface()->version; }\n");
584  printf("\n");
585 
586  printEnums(interface.enums);
587 
588  bool hasEvents = !interface.events.empty();
589 
590  if (hasEvents) {
591  printf("\n");
592  for (const WaylandEvent &e : interface.events) {
593  printf(" void send_");
594  printEvent(e);
595  printf(";\n");
596  printf(" void send_");
597  printEvent(e, false, true);
598  printf(";\n");
599  }
600  }
601 
602  printf("\n");
603  printf(" protected:\n");
604  printf(" virtual Resource *%s_allocate();\n", interfaceNameStripped);
605  printf("\n");
606  printf(" virtual void %s_destroy_global();\n", interfaceNameStripped);
607  printf("\n");
608  printf(" virtual void %s_bind_resource(Resource *resource);\n", interfaceNameStripped);
609  printf(" virtual void %s_destroy_resource(Resource *resource);\n", interfaceNameStripped);
610 
611  bool hasRequests = !interface.requests.empty();
612 
613  if (hasRequests) {
614  printf("\n");
615  for (const WaylandEvent &e : interface.requests) {
616  printf(" virtual void %s_", interfaceNameStripped);
617  printEvent(e);
618  printf(";\n");
619  }
620  }
621 
622  printf("\n");
623  printf(" private:\n");
624  printf(" static void bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id);\n");
625  printf(" static void destroy_func(struct ::wl_resource *client_resource);\n");
626  printf(" static void display_destroy_func(struct ::wl_listener *listener, void *data);\n");
627  printf(" static int deferred_destroy_global_func(void *data);\n");
628  printf("\n");
629  printf(" Resource *bind(struct ::wl_client *client, uint32_t id, int version);\n");
630  printf(" Resource *bind(struct ::wl_resource *handle);\n");
631 
632  if (hasRequests) {
633  printf("\n");
634  printf(" static const struct ::%s_interface m_%s_interface;\n", interfaceName, interfaceName);
635 
636  printf("\n");
637  for (const WaylandEvent &e : interface.requests) {
638  printf(" static void ");
639 
640  printEventHandlerSignature(e, interfaceName);
641  printf(";\n");
642  }
643  }
644 
645  printf("\n");
646  printf(" QMultiMap<struct ::wl_client*, Resource*> m_resource_map;\n");
647  printf(" Resource *m_resource;\n");
648  printf(" struct ::wl_global *m_global;\n");
649  printf(" struct ::wl_display *m_display;\n");
650  printf(" struct wl_event_source *m_globalRemovedEvent;\n");
651  printf(" struct DisplayDestroyedListener : ::wl_listener {\n");
652  printf(" %s *parent;\n", interfaceName);
653  printf(" };\n");
654  printf(" DisplayDestroyedListener m_displayDestroyedListener;\n");
655  printf(" };\n");
656  }
657 
658  printf("}\n");
659  printf("\n");
660  printf("QT_WARNING_POP\n");
661  printf("QT_END_NAMESPACE\n");
662  printf("\n");
663  printf("#endif\n");
664  }
665 
666  if (m_option == ServerCode) {
667  if (m_headerPath.isEmpty())
668  printf("#include \"qwayland-server-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
669  else
670  printf("#include <%s/qwayland-server-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
671  printf("\n");
672  printf("QT_BEGIN_NAMESPACE\n");
673  printf("QT_WARNING_PUSH\n");
674  printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
675  printf("\n");
676  printf("namespace QtWaylandServer {\n");
677 
678  bool needsNewLine = false;
679 
680  for (const WaylandInterface &interface : interfaces) {
681 
682  if (ignoreInterface(interface.name))
683  continue;
684 
685  if (needsNewLine)
686  printf("\n");
687 
688  needsNewLine = true;
689 
690  const char *interfaceName = interface.name.constData();
691 
692  QByteArray stripped = stripInterfaceName(interface.name);
693  const char *interfaceNameStripped = stripped.constData();
694 
695  printf("\n");
696  printf(" int %s::deferred_destroy_global_func(void *data) {\n", interfaceName);
697  printf(" auto object = static_cast<%s *>(data);\n", interfaceName);
698  printf(" wl_global_destroy(object->m_global);\n");
699  printf(" object->m_global = nullptr;\n");
700  printf(" wl_event_source_remove(object->m_globalRemovedEvent);\n");
701  printf(" object->m_globalRemovedEvent = nullptr;\n");
702  printf(" wl_list_remove(&object->m_displayDestroyedListener.link);\n");
703  printf(" object->%s_destroy_global();\n", interfaceNameStripped);
704  printf(" return 0;\n");
705  printf(" }\n");
706  printf("\n");
707 
708  printf(" %s::%s(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName);
709  printf(" : m_resource_map()\n");
710  printf(" , m_resource(nullptr)\n");
711  printf(" , m_global(nullptr)\n");
712  printf(" , m_display(nullptr)\n");
713  printf(" , m_globalRemovedEvent(nullptr)\n");
714  printf(" {\n");
715  printf(" init(client, id, version);\n");
716  printf(" }\n");
717  printf("\n");
718 
719  printf(" %s::%s(struct ::wl_display *display, int version)\n", interfaceName, interfaceName);
720  printf(" : m_resource_map()\n");
721  printf(" , m_resource(nullptr)\n");
722  printf(" , m_global(nullptr)\n");
723  printf(" , m_display(nullptr)\n");
724  printf(" , m_globalRemovedEvent(nullptr)\n");
725  printf(" {\n");
726  printf(" init(display, version);\n");
727  printf(" }\n");
728  printf("\n");
729 
730  printf(" %s::%s(struct ::wl_resource *resource)\n", interfaceName, interfaceName);
731  printf(" : m_resource_map()\n");
732  printf(" , m_resource(nullptr)\n");
733  printf(" , m_global(nullptr)\n");
734  printf(" , m_display(nullptr)\n");
735  printf(" , m_globalRemovedEvent(nullptr)\n");
736  printf(" {\n");
737  printf(" init(resource);\n");
738  printf(" }\n");
739  printf("\n");
740 
741  printf(" %s::%s()\n", interfaceName, interfaceName);
742  printf(" : m_resource_map()\n");
743  printf(" , m_resource(nullptr)\n");
744  printf(" , m_global(nullptr)\n");
745  printf(" , m_display(nullptr)\n");
746  printf(" , m_globalRemovedEvent(nullptr)\n");
747  printf(" {\n");
748  printf(" }\n");
749  printf("\n");
750 
751  printf(" %s::~%s()\n", interfaceName, interfaceName);
752  printf(" {\n");
753  printf(" for (auto resource : qAsConst(m_resource_map))\n");
754  printf(" resource->%s_object = nullptr;\n", interfaceNameStripped);
755  printf("\n");
756  printf(" if (m_resource)\n");
757  printf(" m_resource->%s_object = nullptr;\n", interfaceNameStripped);
758  printf("\n");
759  printf(" if (m_global) {\n");
760  printf(" if (m_globalRemovedEvent)\n");
761  printf(" wl_event_source_remove(m_globalRemovedEvent);\n");
762  printf(" wl_global_destroy(m_global);\n");
763  printf(" wl_list_remove(&m_displayDestroyedListener.link);\n");
764  printf(" }\n");
765  printf(" }\n");
766  printf("\n");
767 
768  printf(" void %s::init(struct ::wl_client *client, int id, int version)\n", interfaceName);
769  printf(" {\n");
770  printf(" m_resource = bind(client, id, version);\n");
771  printf(" }\n");
772  printf("\n");
773 
774  printf(" void %s::init(struct ::wl_resource *resource)\n", interfaceName);
775  printf(" {\n");
776  printf(" m_resource = bind(resource);\n");
777  printf(" }\n");
778  printf("\n");
779 
780  printf(" %s::Resource *%s::add(struct ::wl_client *client, int version)\n", interfaceName, interfaceName);
781  printf(" {\n");
782  printf(" Resource *resource = bind(client, 0, version);\n");
783  printf(" m_resource_map.insert(client, resource);\n");
784  printf(" return resource;\n");
785  printf(" }\n");
786  printf("\n");
787 
788  printf(" %s::Resource *%s::add(struct ::wl_client *client, int id, int version)\n", interfaceName, interfaceName);
789  printf(" {\n");
790  printf(" Resource *resource = bind(client, id, version);\n");
791  printf(" m_resource_map.insert(client, resource);\n");
792  printf(" return resource;\n");
793  printf(" }\n");
794  printf("\n");
795 
796  printf(" void %s::init(struct ::wl_display *display, int version)\n", interfaceName);
797  printf(" {\n");
798  printf(" m_display = display;\n");
799  printf(" m_global = wl_global_create(display, &::%s_interface, version, this, bind_func);\n", interfaceName);
800  printf(" m_displayDestroyedListener.notify = %s::display_destroy_func;\n", interfaceName);
801  printf(" m_displayDestroyedListener.parent = this;\n");
802  printf(" wl_display_add_destroy_listener(display, &m_displayDestroyedListener);\n");
803  printf(" }\n");
804  printf("\n");
805 
806  printf(" const struct wl_interface *%s::interface()\n", interfaceName);
807  printf(" {\n");
808  printf(" return &::%s_interface;\n", interfaceName);
809  printf(" }\n");
810  printf("\n");
811 
812  printf(" %s::Resource *%s::%s_allocate()\n", interfaceName, interfaceName, interfaceNameStripped);
813  printf(" {\n");
814  printf(" return new Resource;\n");
815  printf(" }\n");
816  printf("\n");
817 
818  printf(" void %s::%s_destroy_global()\n", interfaceName, interfaceNameStripped);
819  printf(" {\n");
820  printf(" }\n");
821  printf("\n");
822 
823  printf(" void %s::%s_bind_resource(Resource *)\n", interfaceName, interfaceNameStripped);
824  printf(" {\n");
825  printf(" }\n");
826  printf("\n");
827 
828  printf(" void %s::%s_destroy_resource(Resource *)\n", interfaceName, interfaceNameStripped);
829  printf(" {\n");
830  printf(" }\n");
831  printf("\n");
832 
833  printf(" void %s::bind_func(struct ::wl_client *client, void *data, uint32_t version, uint32_t id)\n", interfaceName);
834  printf(" {\n");
835  printf(" %s *that = static_cast<%s *>(data);\n", interfaceName, interfaceName);
836  printf(" that->add(client, id, version);\n");
837  printf(" }\n");
838  printf("\n");
839 
840  printf(" void %s::display_destroy_func(struct ::wl_listener *listener, void *data)\n", interfaceName);
841  printf(" {\n");
842  printf(" Q_UNUSED(data);\n");
843  printf(" %s *that = static_cast<%s::DisplayDestroyedListener *>(listener)->parent;\n", interfaceName, interfaceName);
844  printf(" that->m_global = nullptr;\n");
845  printf(" that->m_globalRemovedEvent = nullptr;\n");
846  printf(" }\n");
847  printf("\n");
848 
849  printf(" void %s::destroy_func(struct ::wl_resource *client_resource)\n", interfaceName);
850  printf(" {\n");
851  printf(" Resource *resource = Resource::fromResource(client_resource);\n");
852  printf(" Q_ASSERT(resource);\n");
853  printf(" %s *that = resource->%s_object;\n", interfaceName, interfaceNameStripped);
854  printf(" if (Q_LIKELY(that)) {\n");
855  printf(" that->m_resource_map.remove(resource->client(), resource);\n");
856  printf(" that->%s_destroy_resource(resource);\n", interfaceNameStripped);
857  printf("\n");
858  printf(" that = resource->%s_object;\n", interfaceNameStripped);
859  printf(" if (that && that->m_resource == resource)\n");
860  printf(" that->m_resource = nullptr;\n");
861  printf(" }\n");
862  printf(" delete resource;\n");
863  printf(" }\n");
864  printf("\n");
865 
866  // Removing a global is racey. Announce removal, and then only perform internal cleanup after a delay
867  // See https://gitlab.freedesktop.org/wayland/wayland/issues/10
868  printf("\n");
869  printf(" void %s::globalRemove()\n", interfaceName);
870  printf(" {\n");
871  printf(" if (!m_global || m_globalRemovedEvent)\n");
872  printf(" return;\n");
873  printf("\n");
874  printf(" wl_global_remove(m_global);\n");
875  printf("\n");
876  printf(" struct wl_event_loop *event_loop = wl_display_get_event_loop(m_display);\n");
877  printf(" m_globalRemovedEvent = wl_event_loop_add_timer(event_loop, deferred_destroy_global_func, this);\n");
878  printf(" wl_event_source_timer_update(m_globalRemovedEvent, 5000);\n");
879  printf(" }\n");
880  printf("\n");
881 
882  bool hasRequests = !interface.requests.empty();
883 
884  QByteArray interfaceMember = hasRequests ? "&m_" + interface.name + "_interface" : QByteArray("nullptr");
885 
886  //We should consider changing bind so that it doesn't special case id == 0
887  //and use function overloading instead. Jan do you have a lot of code dependent on this behavior?
888  printf(" %s::Resource *%s::bind(struct ::wl_client *client, uint32_t id, int version)\n", interfaceName, interfaceName);
889  printf(" {\n");
890  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");
891  printf(" struct ::wl_resource *handle = wl_resource_create(client, &::%s_interface, version, id);\n", interfaceName);
892  printf(" return bind(handle);\n");
893  printf(" }\n");
894  printf("\n");
895 
896  printf(" %s::Resource *%s::bind(struct ::wl_resource *handle)\n", interfaceName, interfaceName);
897  printf(" {\n");
898  printf(" Resource *resource = %s_allocate();\n", interfaceNameStripped);
899  printf(" resource->%s_object = this;\n", interfaceNameStripped);
900  printf("\n");
901  printf(" wl_resource_set_implementation(handle, %s, resource, destroy_func);", interfaceMember.constData());
902  printf("\n");
903  printf(" resource->handle = handle;\n");
904  printf(" %s_bind_resource(resource);\n", interfaceNameStripped);
905  printf(" return resource;\n");
906  printf(" }\n");
907 
908  printf(" %s::Resource *%s::Resource::fromResource(struct ::wl_resource *resource)\n", interfaceName, interfaceName);
909  printf(" {\n");
910  printf(" if (Q_UNLIKELY(!resource))\n");
911  printf(" return nullptr;\n");
912  printf(" if (wl_resource_instance_of(resource, &::%s_interface, %s))\n", interfaceName, interfaceMember.constData());
913  printf(" return static_cast<Resource *>(wl_resource_get_user_data(resource));\n");
914  printf(" return nullptr;\n");
915  printf(" }\n");
916 
917  if (hasRequests) {
918  printf("\n");
919  printf(" const struct ::%s_interface %s::m_%s_interface = {", interfaceName, interfaceName, interfaceName);
920  bool needsComma = false;
921  for (const WaylandEvent &e : interface.requests) {
922  if (needsComma)
923  printf(",");
924  needsComma = true;
925  printf("\n");
926  printf(" %s::handle_%s", interfaceName, e.name.constData());
927  }
928  printf("\n");
929  printf(" };\n");
930 
931  for (const WaylandEvent &e : interface.requests) {
932  printf("\n");
933  printf(" void %s::%s_", interfaceName, interfaceNameStripped);
934  printEvent(e, true);
935  printf("\n");
936  printf(" {\n");
937  printf(" }\n");
938  }
939  printf("\n");
940 
941  for (const WaylandEvent &e : interface.requests) {
942  printf("\n");
943  printf(" void %s::", interfaceName);
944 
945  printEventHandlerSignature(e, interfaceName, false);
946 
947  printf("\n");
948  printf(" {\n");
949  printf(" Q_UNUSED(client);\n");
950  printf(" Resource *r = Resource::fromResource(resource);\n");
951  printf(" if (Q_UNLIKELY(!r->%s_object)) {\n", interfaceNameStripped);
952  for (const WaylandArgument &a : e.arguments) {
953  if (a.type == QByteArrayLiteral("fd"))
954  printf(" close(%s);\n", a.name.constData());
955  }
956  if (e.type == "destructor")
957  printf(" wl_resource_destroy(resource);\n");
958  printf(" return;\n");
959  printf(" }\n");
960  printf(" static_cast<%s *>(r->%s_object)->%s_%s(\n", interfaceName, interfaceNameStripped, interfaceNameStripped, e.name.constData());
961  printf(" r");
962  for (const WaylandArgument &a : e.arguments) {
963  printf(",\n");
964  QByteArray cType = waylandToCType(a.type, a.interface);
965  QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
966  const char *argumentName = a.name.constData();
967  if (cType == qtType)
968  printf(" %s", argumentName);
969  else if (a.type == "string")
970  printf(" QString::fromUtf8(%s)", argumentName);
971  }
972  printf(");\n");
973  printf(" }\n");
974  }
975  }
976 
977  for (const WaylandEvent &e : interface.events) {
978  printf("\n");
979  printf(" void %s::send_", interfaceName);
980  printEvent(e);
981  printf("\n");
982  printf(" {\n");
983  printf(" Q_ASSERT_X(m_resource, \"%s::%s\", \"Uninitialised resource\");\n", interfaceName, e.name.constData());
984  printf(" if (Q_UNLIKELY(!m_resource)) {\n");
985  printf(" qWarning(\"could not call %s::%s as it's not initialised\");\n", interfaceName, e.name.constData());
986  printf(" return;\n");
987  printf(" }\n");
988  printf(" send_%s(\n", e.name.constData());
989  printf(" m_resource->handle");
990  for (const WaylandArgument &a : e.arguments) {
991  printf(",\n");
992  printf(" %s", a.name.constData());
993  }
994  printf(");\n");
995  printf(" }\n");
996  printf("\n");
997 
998  printf(" void %s::send_", interfaceName);
999  printEvent(e, false, true);
1000  printf("\n");
1001  printf(" {\n");
1002 
1003  for (const WaylandArgument &a : e.arguments) {
1004  if (a.type != "array")
1005  continue;
1006  QByteArray array = a.name + "_data";
1007  const char *arrayName = array.constData();
1008  const char *variableName = a.name.constData();
1009  printf(" struct wl_array %s;\n", arrayName);
1010  printf(" %s.size = %s.size();\n", arrayName, variableName);
1011  printf(" %s.data = static_cast<void *>(const_cast<char *>(%s.constData()));\n", arrayName, variableName);
1012  printf(" %s.alloc = 0;\n", arrayName);
1013  printf("\n");
1014  }
1015 
1016  printf(" %s_send_%s(\n", interfaceName, e.name.constData());
1017  printf(" resource");
1018 
1019  for (const WaylandArgument &a : e.arguments) {
1020  printf(",\n");
1021  QByteArray cType = waylandToCType(a.type, a.interface);
1022  QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
1023  if (a.type == "string")
1024  printf(" %s.toUtf8().constData()", a.name.constData());
1025  else if (a.type == "array")
1026  printf(" &%s_data", a.name.constData());
1027  else if (cType == qtType)
1028  printf(" %s", a.name.constData());
1029  }
1030 
1031  printf(");\n");
1032  printf(" }\n");
1033  printf("\n");
1034  }
1035  }
1036  printf("}\n");
1037  printf("\n");
1038  printf("QT_WARNING_POP\n");
1039  printf("QT_END_NAMESPACE\n");
1040  }
1041 
1042  if (m_option == ClientHeader) {
1043  QByteArray inclusionGuard = QByteArray("QT_WAYLAND_") + preProcessorProtocolName.constData();
1044  printf("#ifndef %s\n", inclusionGuard.constData());
1045  printf("#define %s\n", inclusionGuard.constData());
1046  printf("\n");
1047  if (m_headerPath.isEmpty())
1048  printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
1049  else
1050  printf("#include <%s/wayland-%s-client-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
1051  printf("#include <QByteArray>\n");
1052  printf("#include <QString>\n");
1053  printf("\n");
1054  printf("struct wl_registry;\n");
1055  printf("\n");
1056  printf("QT_BEGIN_NAMESPACE\n");
1057  printf("QT_WARNING_PUSH\n");
1058  printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
1059 
1060  QByteArray clientExport;
1061 
1062  if (m_headerPath.size()) {
1063  clientExport = QByteArray("Q_WAYLAND_CLIENT_") + preProcessorProtocolName + "_EXPORT";
1064  printf("\n");
1065  printf("#if !defined(%s)\n", clientExport.constData());
1066  printf("# if defined(QT_SHARED)\n");
1067  printf("# define %s Q_DECL_EXPORT\n", clientExport.constData());
1068  printf("# else\n");
1069  printf("# define %s\n", clientExport.constData());
1070  printf("# endif\n");
1071  printf("#endif\n");
1072  }
1073  printf("\n");
1074  printf("namespace QtWayland {\n");
1075 
1076  bool needsNewLine = false;
1077  for (const WaylandInterface &interface : interfaces) {
1078 
1079  if (ignoreInterface(interface.name))
1080  continue;
1081 
1082  if (needsNewLine)
1083  printf("\n");
1084  needsNewLine = true;
1085 
1086  const char *interfaceName = interface.name.constData();
1087 
1088  QByteArray stripped = stripInterfaceName(interface.name);
1089  const char *interfaceNameStripped = stripped.constData();
1090 
1091  printf(" class %s %s\n {\n", clientExport.constData(), interfaceName);
1092  printf(" public:\n");
1093  printf(" %s(struct ::wl_registry *registry, int id, int version);\n", interfaceName);
1094  printf(" %s(struct ::%s *object);\n", interfaceName, interfaceName);
1095  printf(" %s();\n", interfaceName);
1096  printf("\n");
1097  printf(" virtual ~%s();\n", interfaceName);
1098  printf("\n");
1099  printf(" void init(struct ::wl_registry *registry, int id, int version);\n");
1100  printf(" void init(struct ::%s *object);\n", interfaceName);
1101  printf("\n");
1102  printf(" struct ::%s *object() { return m_%s; }\n", interfaceName, interfaceName);
1103  printf(" const struct ::%s *object() const { return m_%s; }\n", interfaceName, interfaceName);
1104  printf(" static %s *fromObject(struct ::%s *object);\n", interfaceName, interfaceName);
1105  printf("\n");
1106  printf(" bool isInitialized() const;\n");
1107  printf("\n");
1108  printf(" static const struct ::wl_interface *interface();\n");
1109 
1110  printEnums(interface.enums);
1111 
1112  if (!interface.requests.empty()) {
1113  printf("\n");
1114  for (const WaylandEvent &e : interface.requests) {
1115  const WaylandArgument *new_id = newIdArgument(e.arguments);
1116  QByteArray new_id_str = "void ";
1117  if (new_id) {
1118  if (new_id->interface.isEmpty())
1119  new_id_str = "void *";
1120  else
1121  new_id_str = "struct ::" + new_id->interface + " *";
1122  }
1123  printf(" %s", new_id_str.constData());
1124  printEvent(e);
1125  printf(";\n");
1126  }
1127  }
1128 
1129  bool hasEvents = !interface.events.empty();
1130 
1131  if (hasEvents) {
1132  printf("\n");
1133  printf(" protected:\n");
1134  for (const WaylandEvent &e : interface.events) {
1135  printf(" virtual void %s_", interfaceNameStripped);
1136  printEvent(e);
1137  printf(";\n");
1138  }
1139  }
1140 
1141  printf("\n");
1142  printf(" private:\n");
1143  if (hasEvents) {
1144  printf(" void init_listener();\n");
1145  printf(" static const struct %s_listener m_%s_listener;\n", interfaceName, interfaceName);
1146  for (const WaylandEvent &e : interface.events) {
1147  printf(" static void ");
1148 
1149  printEventHandlerSignature(e, interfaceName);
1150  printf(";\n");
1151  }
1152  }
1153  printf(" struct ::%s *m_%s;\n", interfaceName, interfaceName);
1154  printf(" };\n");
1155  }
1156  printf("}\n");
1157  printf("\n");
1158  printf("QT_WARNING_POP\n");
1159  printf("QT_END_NAMESPACE\n");
1160  printf("\n");
1161  printf("#endif\n");
1162  }
1163 
1164  if (m_option == ClientCode) {
1165  if (m_headerPath.isEmpty())
1166  printf("#include \"qwayland-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
1167  else
1168  printf("#include <%s/qwayland-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
1169  printf("\n");
1170  printf("QT_BEGIN_NAMESPACE\n");
1171  printf("QT_WARNING_PUSH\n");
1172  printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
1173  printf("\n");
1174  printf("namespace QtWayland {\n");
1175  printf("\n");
1176 
1177  // wl_registry_bind is part of the protocol, so we can't use that... instead we use core
1178  // libwayland API to do the same thing a wayland-scanner generated wl_registry_bind would.
1179  printf("static inline void *wlRegistryBind(struct ::wl_registry *registry, uint32_t name, const struct ::wl_interface *interface, uint32_t version)\n");
1180  printf("{\n");
1181  printf(" const uint32_t bindOpCode = 0;\n");
1182  printf("#if (WAYLAND_VERSION_MAJOR == 1 && WAYLAND_VERSION_MINOR > 10) || WAYLAND_VERSION_MAJOR > 1\n");
1183  printf(" return (void *) wl_proxy_marshal_constructor_versioned((struct wl_proxy *) registry,\n");
1184  printf(" bindOpCode, interface, version, name, interface->name, version, nullptr);\n");
1185  printf("#else\n");
1186  printf(" return (void *) wl_proxy_marshal_constructor((struct wl_proxy *) registry,\n");
1187  printf(" bindOpCode, interface, name, interface->name, version, nullptr);\n");
1188  printf("#endif\n");
1189  printf("}\n");
1190  printf("\n");
1191 
1192  bool needsNewLine = false;
1193  for (const WaylandInterface &interface : interfaces) {
1194 
1195  if (ignoreInterface(interface.name))
1196  continue;
1197 
1198  if (needsNewLine)
1199  printf("\n");
1200  needsNewLine = true;
1201 
1202  const char *interfaceName = interface.name.constData();
1203 
1204  QByteArray stripped = stripInterfaceName(interface.name);
1205  const char *interfaceNameStripped = stripped.constData();
1206 
1207  bool hasEvents = !interface.events.empty();
1208 
1209  printf(" %s::%s(struct ::wl_registry *registry, int id, int version)\n", interfaceName, interfaceName);
1210  printf(" {\n");
1211  printf(" init(registry, id, version);\n");
1212  printf(" }\n");
1213  printf("\n");
1214 
1215  printf(" %s::%s(struct ::%s *obj)\n", interfaceName, interfaceName, interfaceName);
1216  printf(" : m_%s(obj)\n", interfaceName);
1217  printf(" {\n");
1218  if (hasEvents)
1219  printf(" init_listener();\n");
1220  printf(" }\n");
1221  printf("\n");
1222 
1223  printf(" %s::%s()\n", interfaceName, interfaceName);
1224  printf(" : m_%s(nullptr)\n", interfaceName);
1225  printf(" {\n");
1226  printf(" }\n");
1227  printf("\n");
1228 
1229  printf(" %s::~%s()\n", interfaceName, interfaceName);
1230  printf(" {\n");
1231  printf(" }\n");
1232  printf("\n");
1233 
1234  printf(" void %s::init(struct ::wl_registry *registry, int id, int version)\n", interfaceName);
1235  printf(" {\n");
1236  printf(" m_%s = static_cast<struct ::%s *>(wlRegistryBind(registry, id, &%s_interface, version));\n", interfaceName, interfaceName, interfaceName);
1237  if (hasEvents)
1238  printf(" init_listener();\n");
1239  printf(" }\n");
1240  printf("\n");
1241 
1242  printf(" void %s::init(struct ::%s *obj)\n", interfaceName, interfaceName);
1243  printf(" {\n");
1244  printf(" m_%s = obj;\n", interfaceName);
1245  if (hasEvents)
1246  printf(" init_listener();\n");
1247  printf(" }\n");
1248  printf("\n");
1249 
1250  printf(" %s *%s::fromObject(struct ::%s *object)\n", interfaceName, interfaceName, interfaceName);
1251  printf(" {\n");
1252  if (hasEvents) {
1253  printf(" if (wl_proxy_get_listener((struct ::wl_proxy *)object) != (void *)&m_%s_listener)\n", interfaceName);
1254  printf(" return nullptr;\n");
1255  }
1256  printf(" return static_cast<%s *>(%s_get_user_data(object));\n", interfaceName, interfaceName);
1257  printf(" }\n");
1258  printf("\n");
1259 
1260  printf(" bool %s::isInitialized() const\n", interfaceName);
1261  printf(" {\n");
1262  printf(" return m_%s != nullptr;\n", interfaceName);
1263  printf(" }\n");
1264  printf("\n");
1265 
1266  printf(" const struct wl_interface *%s::interface()\n", interfaceName);
1267  printf(" {\n");
1268  printf(" return &::%s_interface;\n", interfaceName);
1269  printf(" }\n");
1270 
1271  for (const WaylandEvent &e : interface.requests) {
1272  printf("\n");
1273  const WaylandArgument *new_id = newIdArgument(e.arguments);
1274  QByteArray new_id_str = "void ";
1275  if (new_id) {
1276  if (new_id->interface.isEmpty())
1277  new_id_str = "void *";
1278  else
1279  new_id_str = "struct ::" + new_id->interface + " *";
1280  }
1281  printf(" %s%s::", new_id_str.constData(), interfaceName);
1282  printEvent(e);
1283  printf("\n");
1284  printf(" {\n");
1285  for (const WaylandArgument &a : e.arguments) {
1286  if (a.type != "array")
1287  continue;
1288  QByteArray array = a.name + "_data";
1289  const char *arrayName = array.constData();
1290  const char *variableName = a.name.constData();
1291  printf(" struct wl_array %s;\n", arrayName);
1292  printf(" %s.size = %s.size();\n", arrayName, variableName);
1293  printf(" %s.data = static_cast<void *>(const_cast<char *>(%s.constData()));\n", arrayName, variableName);
1294  printf(" %s.alloc = 0;\n", arrayName);
1295  printf("\n");
1296  }
1297  int actualArgumentCount = new_id ? int(e.arguments.size()) - 1 : int(e.arguments.size());
1298  printf(" %s%s_%s(\n", new_id ? "return " : "", interfaceName, e.name.constData());
1299  printf(" m_%s%s", interfaceName, actualArgumentCount > 0 ? "," : "");
1300  bool needsComma = false;
1301  for (const WaylandArgument &a : e.arguments) {
1302  bool isNewId = a.type == "new_id";
1303  if (isNewId && !a.interface.isEmpty())
1304  continue;
1305  if (needsComma)
1306  printf(",");
1307  needsComma = true;
1308  printf("\n");
1309  if (isNewId) {
1310  printf(" interface,\n");
1311  printf(" version");
1312  } else {
1313  QByteArray cType = waylandToCType(a.type, a.interface);
1314  QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
1315  if (a.type == "string")
1316  printf(" %s.toUtf8().constData()", a.name.constData());
1317  else if (a.type == "array")
1318  printf(" &%s_data", a.name.constData());
1319  else if (cType == qtType)
1320  printf(" %s", a.name.constData());
1321  }
1322  }
1323  printf(");\n");
1324  if (e.type == "destructor")
1325  printf(" m_%s = nullptr;\n", interfaceName);
1326  printf(" }\n");
1327  }
1328 
1329  if (hasEvents) {
1330  printf("\n");
1331  for (const WaylandEvent &e : interface.events) {
1332  printf(" void %s::%s_", interfaceName, interfaceNameStripped);
1333  printEvent(e, true);
1334  printf("\n");
1335  printf(" {\n");
1336  printf(" }\n");
1337  printf("\n");
1338  printf(" void %s::", interfaceName);
1339  printEventHandlerSignature(e, interfaceName, false);
1340  printf("\n");
1341  printf(" {\n");
1342  printf(" Q_UNUSED(object);\n");
1343  printf(" static_cast<%s *>(data)->%s_%s(", interfaceName, interfaceNameStripped, e.name.constData());
1344  bool needsComma = false;
1345  for (const WaylandArgument &a : e.arguments) {
1346  if (needsComma)
1347  printf(",");
1348  needsComma = true;
1349  printf("\n");
1350  const char *argumentName = a.name.constData();
1351  if (a.type == "string")
1352  printf(" QString::fromUtf8(%s)", argumentName);
1353  else
1354  printf(" %s", argumentName);
1355  }
1356  printf(");\n");
1357 
1358  printf(" }\n");
1359  printf("\n");
1360  }
1361  printf(" const struct %s_listener %s::m_%s_listener = {\n", interfaceName, interfaceName, interfaceName);
1362  for (const WaylandEvent &e : interface.events) {
1363  printf(" %s::handle_%s,\n", interfaceName, e.name.constData());
1364  }
1365  printf(" };\n");
1366  printf("\n");
1367 
1368  printf(" void %s::init_listener()\n", interfaceName);
1369  printf(" {\n");
1370  printf(" %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName);
1371  printf(" }\n");
1372  }
1373  }
1374  printf("}\n");
1375  printf("\n");
1376  printf("QT_WARNING_POP\n");
1377  printf("QT_END_NAMESPACE\n");
1378  }
1379 
1380  return true;
1381 }
1382 
1383 void Scanner::printErrors()
1384 {
1385  if (m_xml->hasError())
1386  fprintf(stderr, "XML error: %s\nLine %lld, column %lld\n", m_xml->errorString().toLocal8Bit().constData(), m_xml->lineNumber(), m_xml->columnNumber());
1387 }
1388 
1389 int main(int argc, char **argv)
1390 {
1391  QCoreApplication app(argc, argv);
1392  Scanner scanner;
1393 
1394  if (!scanner.parseArguments(argc, argv)) {
1395  scanner.printUsage();
1396  return EXIT_FAILURE;
1397  }
1398 
1399  if (!scanner.process()) {
1400  scanner.printErrors();
1401  return EXIT_FAILURE;
1402  }
1403 
1404  return EXIT_SUCCESS;
1405 }
bool readNextStartElement()
QString name(const QVariant &location)
QByteArray toUpper() const const
bool isEmpty() const const
bool startsWith(const QByteArray &ba) const const
QStringRef value(const QString &namespaceUri, const QString &name) const const
QByteArray toUtf8() const const
void skipCurrentElement()
Type type(const QSqlDatabase &db)
const char * constData() const const
QByteArray & replace(int pos, int len, const char *after)
QByteArray mid(int pos, int len) const const
void push_back(char ch)
void reserve(int size)
bool hasAttribute(const QString &qualifiedName) const const
QXmlStreamAttributes attributes() const const
QStringRef name() const const
KDB_EXPORT KDbVersionInfo version()
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 23 2021 23:08:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.