10 #include <QCommandLineParser>
11 #include <QCoreApplication>
13 #include <QFutureWatcher>
14 #include <QMutexLocker>
16 #include <QTextStream>
17 #include <QtConcurrent>
31 auto it = s_clientClassNameMapping.
constFind(wlInterface);
32 if (it != s_clientClassNameMapping.
constEnd()) {
35 qWarning() <<
"Cannot find mapping for " << wlInterface;
43 if (parts.
count() < 2) {
44 return underscoreName;
49 for (; it != parts.
constEnd(); ++it) {
50 camelCase.
append((*it).left(1).toUpper());
51 camelCase.
append((*it).mid(1));
61 : m_name(attributes.value(QStringLiteral(
"name")).
toString())
62 , m_type(parseType(attributes.value(QStringLiteral(
"type"))))
63 , m_allowNull(attributes.hasAttribute(QStringLiteral(
"allow-null")))
64 , m_inteface(attributes.value(QStringLiteral(
"interface")).
toString())
68 Argument::~Argument() =
default;
70 Argument::Type Argument::parseType(
const QStringView type)
76 return Type::Destructor;
82 return Type::FileDescriptor;
100 QString Argument::typeAsQt()
const
103 case Type::Destructor:
105 case Type::FileDescriptor:
106 return QStringLiteral(
"int");
108 return QStringLiteral(
"qreal");
110 return QStringLiteral(
"qint32");
113 return toQtInterfaceName(m_inteface);
115 return QStringLiteral(
"const QString &");
117 return QStringLiteral(
"quint32");
125 QString Argument::typeAsServerWl()
const
128 case Type::Destructor:
130 case Type::FileDescriptor:
131 return QStringLiteral(
"int32_t");
133 return QStringLiteral(
"wl_fixed");
135 return QStringLiteral(
"int32_t");
137 return QStringLiteral(
"wl_resource *");
139 return QStringLiteral(
"const char *");
142 return QStringLiteral(
"uint32_t");
154 Request::Request(
const QString &name)
159 Request::~Request() =
default;
161 bool Request::isFactory()
const
163 for (
const auto &a : m_arguments) {
164 if (a.type() == Argument::Type::NewId) {
175 Event::Event(
const QString &name)
180 Event::~Event() =
default;
182 Interface::Interface() =
default;
185 : m_name(attributes.value(QStringLiteral(
"name")).
toString())
186 , m_version(attributes.value(QStringLiteral(
"version")).toUInt())
189 auto it = s_clientClassNameMapping.
constFind(m_name);
190 if (it != s_clientClassNameMapping.
constEnd()) {
191 m_clientName = it.value();
193 qWarning() <<
"Failed to map " << m_name <<
" to a KWayland name";
197 Interface::~Interface() =
default;
199 Generator::Generator(
QObject *parent)
204 Generator::~Generator() =
default;
208 startAuthorNameProcess();
209 startAuthorEmailProcess();
213 startGenerateHeaderFile();
214 startGenerateCppFile();
215 startGenerateServerHeaderFile();
216 startGenerateServerCppFile();
219 void Generator::startParseXml()
221 if (m_xmlFileName.isEmpty()) {
224 QFile xmlFile(m_xmlFileName);
226 m_xmlReader.setDevice(&xmlFile);
227 while (!m_xmlReader.atEnd()) {
228 if (!m_xmlReader.readNextStartElement()) {
231 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"protocol")) == 0) {
236 auto findFactory = [
this](
const QString interfaceName) -> Interface * {
237 for (
auto it = m_interfaces.begin(); it != m_interfaces.end(); ++it) {
238 if ((*it).name().compare(interfaceName) == 0) {
241 for (
auto r : (*it).requests()) {
242 for (
auto a : r.arguments()) {
243 if (a.type() == Argument::Type::NewId && a.interface().compare(interfaceName) == 0) {
251 for (
auto it = m_interfaces.begin(); it != m_interfaces.end(); ++it) {
252 Interface *factory = findFactory((*it).name());
254 qDebug() << (*it).name() <<
"gets factored by" << factory->kwaylandClientName();
255 (*it).setFactory(factory);
257 qDebug() << (*it).name() <<
"considered as a global";
258 (*it).markAsGlobal();
263 void Generator::parseProtocol()
265 const auto attributes = m_xmlReader.attributes();
268 if (m_baseFileName.isEmpty()) {
272 while (!m_xmlReader.atEnd()) {
273 if (!m_xmlReader.readNextStartElement()) {
274 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"protocol")) == 0) {
279 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"interface")) == 0) {
280 m_interfaces << parseInterface();
285 Interface Generator::parseInterface()
287 Interface interface(m_xmlReader.attributes());
288 while (!m_xmlReader.atEnd()) {
289 if (!m_xmlReader.readNextStartElement()) {
290 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"interface")) == 0) {
295 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"request")) == 0) {
296 interface.addRequest(parseRequest());
298 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"event")) == 0) {
299 interface.addEvent(parseEvent());
305 Request Generator::parseRequest()
307 const auto attributes = m_xmlReader.attributes();
308 Request request(attributes.
value(QStringLiteral(
"name")).
toString());
310 request.markAsDestructor();
312 while (!m_xmlReader.atEnd()) {
313 if (!m_xmlReader.readNextStartElement()) {
314 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"request")) == 0) {
319 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"arg")) == 0) {
320 request.addArgument(Argument(m_xmlReader.attributes()));
326 Event Generator::parseEvent()
328 const auto attributes = m_xmlReader.attributes();
330 while (!m_xmlReader.atEnd()) {
331 if (!m_xmlReader.readNextStartElement()) {
332 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"event")) == 0) {
337 if (m_xmlReader.qualifiedName().compare(
QLatin1String(
"arg")) == 0) {
338 event.addArgument(Argument(m_xmlReader.attributes()));
344 void Generator::startGenerateHeaderFile()
350 QFile file(QStringLiteral(
"%1.h").arg(m_baseFileName));
353 m_project.setLocalData(Project::Client);
354 generateCopyrightHeader();
355 generateStartIncludeGuard();
356 generateHeaderIncludes();
357 generateWaylandForwardDeclarations();
358 generateStartNamespace();
359 generateNamespaceForwardDeclarations();
360 for (
auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
363 generateEndNamespace();
364 generateEndIncludeGuard();
366 m_stream.setLocalData(
nullptr);
371 void Generator::startGenerateCppFile()
377 QFile file(QStringLiteral(
"%1.cpp").arg(m_baseFileName));
380 m_project.setLocalData(Project::Client);
381 generateCopyrightHeader();
382 generateCppIncludes();
383 generateStartNamespace();
384 for (
auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
385 generatePrivateClass(*it);
386 generateClientCpp(*it);
387 generateClientCppRequests(*it);
390 generateEndNamespace();
392 m_stream.setLocalData(
nullptr);
397 void Generator::startGenerateServerHeaderFile()
403 QFile file(QStringLiteral(
"%1_interface.h").arg(m_baseFileName));
406 m_project.setLocalData(Project::Server);
407 generateCopyrightHeader();
408 generateStartIncludeGuard();
409 generateHeaderIncludes();
410 generateStartNamespace();
411 generateNamespaceForwardDeclarations();
412 if (std::any_of(m_interfaces.constBegin(), m_interfaces.constEnd(), [](
const Interface &i) {
413 return i.isUnstableInterface();
416 auto it = std::find_if(m_interfaces.constBegin(), m_interfaces.constEnd(), [](
const Interface &i) {
419 if (it != m_interfaces.constEnd()) {
420 const QString templateString = QStringLiteral(
422 " * Enum describing the interface versions the %1 can support.\n"
426 "enum class %1Version {\n"
432 *m_stream.localData() << templateString.
arg((*it).kwaylandServerName())
434 .
arg((*it).name().mid((*it).name().lastIndexOf(QStringLiteral(
"_v")) + 2));
437 for (
auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
440 generateEndNamespace();
441 generateEndIncludeGuard();
443 m_stream.setLocalData(
nullptr);
448 void Generator::startGenerateServerCppFile()
454 QFile file(QStringLiteral(
"%1_interface.cpp").arg(m_baseFileName));
457 m_project.setLocalData(Project::Server);
458 generateCopyrightHeader();
459 generateCppIncludes();
460 generateStartNamespace();
461 for (
auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
462 generatePrivateClass(*it);
467 generateEndNamespace();
469 m_stream.setLocalData(
nullptr);
474 void Generator::checkEnd()
477 if (m_finishedCounter == 0) {
486 qWarning() <<
"Could not find git executable in PATH.";
491 void Generator::startAuthorNameProcess()
493 const QString exec = findGitExec();
498 proc->
setArguments(
QStringList{QStringLiteral(
"config"), QStringLiteral(
"--get"), QStringLiteral(
"user.name")});
504 m_waitCondition.wakeAll();
509 void Generator::startAuthorEmailProcess()
511 const QString exec = findGitExec();
516 proc->
setArguments(
QStringList{QStringLiteral(
"config"), QStringLiteral(
"--get"), QStringLiteral(
"user.email")});
522 m_waitCondition.wakeAll();
527 void Generator::generateCopyrightHeader()
530 while (m_authorEmail.isEmpty() || m_authorName.isEmpty()) {
531 m_waitCondition.wait(&m_mutex);
534 const QString templateString = QStringLiteral(
535 "/****************************************************************************\n"
536 "Copyright %1 %2 <%3>\n"
538 "This library is free software; you can redistribute it and/or\n"
539 "modify it under the terms of the GNU Lesser General Public\n"
540 "License as published by the Free Software Foundation; either\n"
541 "version 2.1 of the License, or (at your option) version 3, or any\n"
542 "later version accepted by the membership of KDE e.V. (or its\n"
543 "successor approved by the membership of KDE e.V.), which shall\n"
544 "act as a proxy defined in Section 6 of version 3 of the license.\n"
546 "This library is distributed in the hope that it will be useful,\n"
547 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
548 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
549 "Lesser General Public License for more details.\n"
551 "You should have received a copy of the GNU Lesser General Public\n"
552 "License along with this library. If not, see <http://www.gnu.org/licenses/>.\n"
553 "****************************************************************************/\n");
555 *m_stream.localData() << templateString.
arg(date.
year()).
arg(m_authorName).
arg(m_authorEmail);
558 void Generator::generateEndIncludeGuard()
560 *m_stream.localData() << QStringLiteral(
"#endif\n");
563 void Generator::generateStartIncludeGuard()
565 const QString templateString = QStringLiteral(
566 "#ifndef KWAYLAND_%1_%2_H\n"
567 "#define KWAYLAND_%1_%2_H\n\n");
569 *m_stream.localData() << templateString.
arg(projectToName().toUpper()).
arg(m_baseFileName.toUpper());
572 void Generator::generateStartNamespace()
574 const QString templateString = QStringLiteral(
575 "namespace KWayland\n"
579 *m_stream.localData() << templateString.
arg(projectToName());
582 void Generator::generateEndNamespace()
584 *m_stream.localData() << QStringLiteral(
"\n}\n}\n\n");
587 void Generator::generateHeaderIncludes()
589 switch (m_project.localData()) {
590 case Project::Client:
591 *m_stream.localData() << QStringLiteral(
"#include <QObject>\n\n");
593 case Project::Server:
594 *m_stream.localData() << QStringLiteral(
595 "#include \"global.h\"\n"
596 "#include \"resource.h\"\n\n");
601 *m_stream.localData() << QStringLiteral(
"#include <KWayland/%1/kwayland%2_export.h>\n\n").arg(projectToName()).arg(projectToName().toLower());
604 void Generator::generateCppIncludes()
606 switch (m_project.localData()) {
607 case Project::Client:
608 *m_stream.localData() << QStringLiteral(
"#include \"%1.h\"\n").arg(m_baseFileName.toLower());
609 *m_stream.localData() << QStringLiteral(
"#include \"event_queue.h\"\n");
610 *m_stream.localData() << QStringLiteral(
"#include \"wayland_pointer_p.h\"\n\n");
612 case Project::Server:
613 *m_stream.localData() << QStringLiteral(
"#include \"%1_interface.h\"\n").arg(m_baseFileName.toLower());
614 *m_stream.localData() << QStringLiteral(
615 "#include \"display.h\"\n"
616 "#include \"global_p.h\"\n"
617 "#include \"resource_p.h\"\n\n");
624 void Generator::generateClass(
const Interface &interface)
626 switch (m_project.localData()) {
627 case Project::Client:
628 if (interface.isGlobal()) {
629 generateClientGlobalClass(interface);
631 generateClientResourceClass(interface);
634 case Project::Server:
635 if (interface.isGlobal()) {
636 generateServerGlobalClass(interface);
638 generateServerResourceClass(interface);
646 void Generator::generateClientGlobalClass(
const Interface &interface)
648 generateClientGlobalClassDoxy(interface);
649 generateClientClassQObjectDerived(interface);
650 generateClientGlobalClassCtor(interface);
651 generateClientClassDtor(interface);
652 generateClientGlobalClassSetup(interface);
653 generateClientClassReleaseDestroy(interface);
654 generateClientClassStart(interface);
655 generateClientClassRequests(interface);
656 generateClientClassCasts(interface);
657 generateClientClassSignals(interface);
658 generateClientGlobalClassEnd(interface);
661 void Generator::generateClientResourceClass(
const Interface &interface)
663 generateClientClassQObjectDerived(interface);
664 generateClientClassDtor(interface);
665 generateClientResourceClassSetup(interface);
666 generateClientClassReleaseDestroy(interface);
667 generateClientClassRequests(interface);
668 generateClientClassCasts(interface);
669 generateClientResourceClassEnd(interface);
672 void Generator::generateServerGlobalClass(
const Interface &interface)
674 if (interface.isUnstableInterface()) {
675 generateServerGlobalClassUnstable(interface);
678 const QString templateString = QStringLiteral(
679 "class KWAYLANDSERVER_EXPORT %1 : public Global\n"
686 " explicit %1(Display *display, QObject *parent = nullptr);\n"
687 " friend class Display;\n"
691 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName());
694 void Generator::generateServerGlobalClassUnstable(
const Interface &interface)
696 const QString templateString = QStringLiteral(
697 "class KWAYLANDSERVER_EXPORT %1 : public Global\n"
704 " * @returns The interface version used by this %1\n"
706 " %1Version interfaceVersion() const;\n"
710 " explicit %1(Private *d, QObject *parent = nullptr);\n"
713 " Private *d_func() const;\n"
716 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName());
719 void Generator::generateServerResourceClass(
const Interface &interface)
721 if (interface.factory()->isUnstableInterface()) {
722 generateServerResourceClassUnstable(interface);
725 const QString templateString = QStringLiteral(
726 "class KWAYLANDSERVER_EXPORT %1 : public Resource\n"
733 " explicit %1(%2 *parent, wl_resource *parentResource);\n"
734 " friend class %2;\n"
737 " Private *d_func() const;\n"
740 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName()).
arg(interface.factory()->kwaylandServerName());
743 void Generator::generateServerResourceClassUnstable(
const Interface &interface)
745 const QString templateString = QStringLiteral(
746 "class KWAYLANDSERVER_EXPORT %1 : public Resource\n"
754 " * @returns The interface version used by this %1\n"
756 " %2Version interfaceVersion() const;\n"
760 " explicit %1(Private *p, QObject *parent = nullptr);\n"
763 " Private *d_func() const;\n"
766 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName()).
arg(interface.factory()->kwaylandServerName());
769 void Generator::generatePrivateClass(
const Interface &interface)
771 switch (m_project.localData()) {
772 case Project::Client:
773 generateClientPrivateClass(interface);
775 case Project::Server:
776 if (interface.isGlobal()) {
777 generateServerPrivateGlobalClass(interface);
779 generateServerPrivateResourceClass(interface);
787 void Generator::generateServerPrivateGlobalClass(
const Interface &interface)
789 QString templateString = QStringLiteral(
790 "class %1::Private : public Global::Private\n"
793 " Private(%1 *q, Display *d);\n"
796 " void bind(wl_client *client, uint32_t version, uint32_t id) override;\n"
798 " static void unbind(wl_resource *resource);\n"
799 " static Private *cast(wl_resource *r) {\n"
800 " return reinterpret_cast<Private*>(wl_resource_get_user_data(r));\n"
803 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName());
805 generateServerPrivateCallbackDefinitions(interface);
807 templateString = QStringLiteral(
809 " static const struct %2_interface s_interface;\n"
810 " static const quint32 s_version;\n"
813 "const quint32 %1::Private::s_version = %3;\n"
815 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName()).
arg(interface.name()).
arg(interface.version());
816 generateServerPrivateInterfaceClass(interface);
817 generateServerPrivateCallbackImpl(interface);
818 generateServerPrivateGlobalCtorBindClass(interface);
821 void Generator::generateServerPrivateCallbackDefinitions(
const Interface &interface)
823 for (
const auto &r : interface.requests()) {
824 if (r.isDestructor() && !interface.isGlobal()) {
827 *m_stream.localData() << QStringLiteral(
" static void %1Callback(wl_client *client, wl_resource *resource").arg(toCamelCase(r.name()));
828 for (
const auto &a : r.arguments()) {
829 *m_stream.localData() << QStringLiteral(
", %1 %2").arg(a.typeAsServerWl()).arg(a.name());
831 *m_stream.localData() << QStringLiteral(
");\n");
833 *m_stream.localData() << QStringLiteral(
"\n");
836 void Generator::generateServerPrivateCallbackImpl(
const Interface &interface)
838 for (
const auto &r : interface.requests()) {
839 if (r.isDestructor() && !interface.isGlobal()) {
842 *m_stream.localData() << QStringLiteral(
"void %2::Private::%1Callback(wl_client *client, wl_resource *resource")
843 .arg(toCamelCase(r.name()))
844 .arg(interface.kwaylandServerName());
845 for (
const auto &a : r.arguments()) {
846 *m_stream.localData() << QStringLiteral(
", %1 %2").arg(a.typeAsServerWl()).arg(a.name());
848 *m_stream.localData() << QStringLiteral(
851 if (r.isDestructor()) {
852 *m_stream.localData() << QStringLiteral(
853 " Q_UNUSED(client)\n"
854 " wl_resource_destroy(resource);\n");
856 *m_stream.localData() << QStringLiteral(
" // TODO: implement\n");
858 *m_stream.localData() << QStringLiteral(
864 void Generator::generateServerPrivateGlobalCtorBindClass(
const Interface &interface)
866 QString templateString = QStringLiteral(
867 "%1::Private::Private(%1 *q, Display *d)\n"
868 " : Global::Private(d, &%2_interface, s_version)\n"
873 "void %1::Private::bind(wl_client *client, uint32_t version, uint32_t id)\n"
875 " auto c = display->getConnection(client);\n"
876 " wl_resource *resource = c->createResource(&%2_interface, qMin(version, s_version), id);\n"
877 " if (!resource) {\n"
878 " wl_client_post_no_memory(client);\n"
881 " wl_resource_set_implementation(resource, &s_interface, this, unbind);\n"
882 " // TODO: should we track?\n"
885 "void %1::Private::unbind(wl_resource *resource)\n"
887 " Q_UNUSED(resource)\n"
888 " // TODO: implement?\n"
891 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName()).
arg(interface.name());
894 void Generator::generateServerPrivateResourceClass(
const Interface &interface)
896 QString templateString = QStringLiteral(
897 "class %1::Private : public Resource::Private\n"
900 " Private(%1 *q, %2 *c, wl_resource *parentResource);\n"
904 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName()).
arg(interface.factory()->kwaylandServerName());
906 generateServerPrivateCallbackDefinitions(interface);
908 templateString = QStringLiteral(
910 " return reinterpret_cast<%1 *>(q);\n"
913 " static const struct %2_interface s_interface;\n"
916 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName()).
arg(interface.name());
918 generateServerPrivateInterfaceClass(interface);
919 generateServerPrivateCallbackImpl(interface);
920 generateServerPrivateResourceCtorDtorClass(interface);
923 void Generator::generateServerPrivateInterfaceClass(
const Interface &interface)
925 *m_stream.localData() << QStringLiteral(
"#ifndef K_DOXYGEN\n");
926 *m_stream.localData()
927 << QStringLiteral(
"const struct %2_interface %1::Private::s_interface = {\n").arg(interface.kwaylandServerName()).arg(interface.name());
929 for (
auto r : interface.requests()) {
931 *m_stream.localData() << QStringLiteral(
",\n");
935 if (r.isDestructor() && !interface.isGlobal()) {
936 *m_stream.localData() << QStringLiteral(
" resourceDestroyedCallback");
938 *m_stream.localData() << QStringLiteral(
" %1Callback").arg(toCamelCase(r.name()));
941 *m_stream.localData() << QStringLiteral(
"\n};\n#endif\n\n");
944 void Generator::generateServerPrivateResourceCtorDtorClass(
const Interface &interface)
946 QString templateString = QStringLiteral(
947 "%1::Private::Private(%1 *q, %2 *c, wl_resource *parentResource)\n"
948 " : Resource::Private(q, c, parentResource, &%3_interface, &s_interface)\n"
952 "%1::Private::~Private()\n"
955 " wl_resource_destroy(resource);\n"
956 " resource = nullptr;\n"
959 *m_stream.localData() << templateString.
arg(interface.kwaylandServerName()).
arg(interface.factory()->kwaylandServerName()).
arg(interface.name());
962 void Generator::generateClientPrivateClass(
const Interface &interface)
964 if (interface.isGlobal()) {
965 generateClientPrivateGlobalClass(interface);
967 generateClientPrivateResourceClass(interface);
970 const auto events = interface.events();
971 if (!events.isEmpty()) {
972 *m_stream.localData() << QStringLiteral(
"\nprivate:\n");
974 for (
auto event : events) {
975 const QString templateString = QStringLiteral(
" static void %1Callback(void *data, %2 *%2");
976 *m_stream.localData() << templateString.
arg(
event.name()).
arg(interface.name());
977 const auto arguments =
event.arguments();
978 for (
auto argument : arguments) {
979 if (argument.interface().isNull()) {
980 *m_stream.localData() << QStringLiteral(
", %1 %2").
arg(argument.typeAsServerWl()).
arg(argument.name());
982 *m_stream.localData() << QStringLiteral(
", %1 *%2").
arg(argument.interface()).
arg(argument.name());
985 *m_stream.localData() <<
");\n";
987 *m_stream.localData() << QStringLiteral(
"\n static const %1_listener s_listener;\n").
arg(interface.name());
990 *m_stream.localData() << QStringLiteral(
"};\n\n");
993 void Generator::generateClientPrivateResourceClass(
const Interface &interface)
995 const QString templateString = QStringLiteral(
996 "class %1::Private\n"
1001 " void setup(%2 *arg);\n"
1003 " WaylandPointer<%2, %2_destroy> %3;\n"
1008 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName()).
arg(interface.name()).
arg(interface.kwaylandClientName().toLower());
1011 void Generator::generateClientPrivateGlobalClass(
const Interface &interface)
1013 const QString templateString = QStringLiteral(
1014 "class %1::Private\n"
1017 " Private() = default;\n"
1019 " void setup(%2 *arg);\n"
1021 " WaylandPointer<%2, %2_destroy> %3;\n"
1022 " EventQueue *queue = nullptr;\n");
1024 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName()).
arg(interface.name()).
arg(interface.kwaylandClientName().toLower());
1027 void Generator::generateClientCpp(
const Interface &interface)
1030 const auto events = interface.events();
1031 if (!events.isEmpty()) {
1033 *m_stream.localData() << QStringLiteral(
"const %1_listener %2::Private::s_listener = {\n").arg(interface.name()).arg(interface.kwaylandClientName());
1035 for (
auto event : events) {
1037 *m_stream.localData() << QStringLiteral(
",\n");
1039 *m_stream.localData() << QStringLiteral(
" %1Callback").arg(
event.name());
1042 *m_stream.localData() << QStringLiteral(
"\n};\n\n");
1045 for (
auto event : events) {
1046 *m_stream.localData() << QStringLiteral(
"void %1::Private::%2Callback(void *data, %3 *%3")
1047 .arg(interface.kwaylandClientName())
1049 .arg(interface.name());
1051 const auto arguments =
event.arguments();
1052 for (
auto argument : arguments) {
1053 if (argument.interface().isNull()) {
1054 *m_stream.localData() << QStringLiteral(
", %1 %2").arg(argument.typeAsServerWl()).arg(argument.name());
1056 *m_stream.localData() << QStringLiteral(
", %1 *%2").arg(argument.interface()).arg(argument.name());
1060 *m_stream.localData() << QStringLiteral(
1063 " auto p = reinterpret_cast<%1::Private*>(data);\n"
1064 " Q_ASSERT(p->%2 == %3);\n")
1065 .arg(interface.kwaylandClientName())
1066 .arg(interface.kwaylandClientName().toLower())
1067 .arg(interface.name());
1068 for (
auto argument : arguments) {
1069 *m_stream.localData() << QStringLiteral(
" Q_UNUSED(%1)\n").arg(argument.name());
1071 *m_stream.localData() << QStringLiteral(
" // TODO: implement\n}\n\n");
1075 if (interface.isGlobal()) {
1077 const QString templateString = QStringLiteral(
1078 "%1::%1(QObject *parent)\n"
1079 " : QObject(parent)\n"
1080 " , d(new Private)\n"
1083 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName());
1086 const QString templateString = QStringLiteral(
1087 "%1::Private::Private(%1 *q)\n"
1092 "%1::%1(QObject *parent)\n"
1093 " : QObject(parent)\n"
1094 " , d(new Private(this))\n"
1097 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName());
1101 const QString setupTemplate = QStringLiteral(
1103 "void %1::Private::setup(%3 *arg)\n"
1107 " %2.setup(arg);\n");
1108 *m_stream.localData() << setupTemplate.
arg(interface.kwaylandClientName()).
arg(interface.kwaylandClientName().toLower()).
arg(interface.name());
1109 if (!interface.events().isEmpty()) {
1110 *m_stream.localData()
1111 << QStringLiteral(
" %1_add_listener(%2, &s_listener, this);\n").
arg(interface.name()).
arg(interface.kwaylandClientName().toLower());
1113 *m_stream.localData() << QStringLiteral(
"}\n");
1115 const QString templateString = QStringLiteral(
1122 "void %1::setup(%3 *%2)\n"
1127 "void %1::release()\n"
1129 " d->%2.release();\n"
1132 "void %1::destroy()\n"
1134 " d->%2.destroy();\n"
1137 "%1::operator %3*() {\n"
1141 "%1::operator %3*() const {\n"
1145 "bool %1::isValid() const\n"
1147 " return d->%2.isValid();\n"
1150 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName()).
arg(interface.kwaylandClientName().toLower()).
arg(interface.name());
1151 if (interface.isGlobal()) {
1152 const QString templateStringGlobal = QStringLiteral(
1153 "void %1::setEventQueue(EventQueue *queue)\n"
1155 " d->queue = queue;\n"
1158 "EventQueue *%1::eventQueue()\n"
1160 " return d->queue;\n"
1162 *m_stream.localData() << templateStringGlobal.
arg(interface.kwaylandClientName());
1166 void Generator::generateClientGlobalClassDoxy(
const Interface &interface)
1168 const QString templateString = QStringLiteral(
1170 " * @short Wrapper for the %2 interface.\n"
1172 " * This class provides a convenient wrapper for the %2 interface.\n"
1174 " * To use this class one needs to interact with the Registry. There are two\n"
1175 " * possible ways to create the %1 interface:\n"
1177 " * %1 *c = registry->create%1(name, version);\n"
1180 " * This creates the %1 and sets it up directly. As an alternative this\n"
1181 " * can also be done in a more low level way:\n"
1183 " * %1 *c = new %1;\n"
1184 " * c->setup(registry->bind%1(name, version));\n"
1187 " * The %1 can be used as a drop-in replacement for any %2\n"
1188 " * pointer as it provides matching cast operators.\n"
1190 " * @see Registry\n"
1192 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName()).
arg(interface.name());
1195 void Generator::generateClientClassQObjectDerived(
const Interface &interface)
1197 const QString templateString = QStringLiteral(
1198 "class KWAYLANDCLIENT_EXPORT %1 : public QObject\n"
1202 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName());
1205 void Generator::generateClientGlobalClassCtor(
const Interface &interface)
1207 const QString templateString = QStringLiteral(
1209 " * Creates a new %1.\n"
1210 " * Note: after constructing the %1 it is not yet valid and one needs\n"
1211 " * to call setup. In order to get a ready to use %1 prefer using\n"
1212 " * Registry::create%1.\n"
1214 " explicit %1(QObject *parent = nullptr);\n");
1215 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName());
1218 void Generator::generateClientClassDtor(
const Interface &interface)
1220 *m_stream.localData() << QStringLiteral(
" virtual ~%1();\n\n").
arg(interface.kwaylandClientName());
1223 void Generator::generateClientClassReleaseDestroy(
const Interface &interface)
1225 const QString templateString = QStringLiteral(
1227 " * @returns @c true if managing a %2.\n"
1229 " bool isValid() const;\n"
1231 " * Releases the %2 interface.\n"
1232 " * After the interface has been released the %1 instance is no\n"
1233 " * longer valid and can be setup with another %2 interface.\n"
1235 " void release();\n"
1237 " * Destroys the data held by this %1.\n"
1238 " * This method is supposed to be used when the connection to the Wayland\n"
1239 " * server goes away. If the connection is not valid anymore, it's not\n"
1240 " * possible to call release anymore as that calls into the Wayland\n"
1241 " * connection and the call would fail. This method cleans up the data, so\n"
1242 " * that the instance can be deleted or set up to a new %2 interface\n"
1243 " * once there is a new connection available.\n"
1245 " * It is suggested to connect this method to ConnectionThread::connectionDied:\n"
1247 " * connect(connection, &ConnectionThread::connectionDied, %3, &%1::destroy);\n"
1252 " void destroy();\n"
1254 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName()).
arg(interface.name()).
arg(interface.kwaylandClientName().toLower());
1257 void Generator::generateClientGlobalClassSetup(
const Interface &interface)
1259 const QString templateString = QStringLiteral(
1261 " * Setup this %1 to manage the @p %3.\n"
1262 " * When using Registry::create%1 there is no need to call this\n"
1265 " void setup(%2 *%3);\n");
1266 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName()).
arg(interface.name()).
arg(interface.kwaylandClientName().toLower());
1269 void Generator::generateClientResourceClassSetup(
const Interface &interface)
1271 const QString templateString = QStringLiteral(
1273 " * Setup this %1 to manage the @p %3.\n"
1274 " * When using %4::create%1 there is no need to call this\n"
1277 " void setup(%2 *%3);\n");
1278 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName())
1279 .
arg(interface.name())
1280 .
arg(interface.kwaylandClientName().toLower())
1281 .
arg(interface.factory()->kwaylandClientName());
1284 void Generator::generateClientClassStart(
const Interface &interface)
1286 const QString templateString = QStringLiteral(
1288 " * Sets the @p queue to use for creating objects with this %1.\n"
1290 " void setEventQueue(EventQueue *queue);\n"
1292 " * @returns The event queue to use for creating objects with this %1.\n"
1294 " EventQueue *eventQueue();\n\n");
1295 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName());
1298 void Generator::generateClientClassRequests(
const Interface &interface)
1300 const auto requests = interface.requests();
1301 const QString templateString = QStringLiteral(
" void %1(%2);\n\n");
1302 const QString factoryTemplateString = QStringLiteral(
" %1 *%2(%3);\n\n");
1303 for (
const auto &r : requests) {
1304 if (r.isDestructor()) {
1310 for (
const auto &a : r.arguments()) {
1311 if (a.type() == Argument::Type::NewId) {
1312 factored = a.interface();
1316 arguments.
append(QStringLiteral(
", "));
1320 if (a.type() == Argument::Type::Object) {
1321 arguments.
append(QStringLiteral(
"%1 *%2").arg(a.typeAsQt()).arg(toCamelCase(a.name())));
1323 arguments.
append(QStringLiteral(
"%1 %2").arg(a.typeAsQt()).arg(toCamelCase(a.name())));
1327 *m_stream.localData() << templateString.
arg(toCamelCase((r.name()))).
arg(arguments);
1330 arguments.
append(QStringLiteral(
", "));
1332 arguments.
append(QStringLiteral(
"QObject *parent = nullptr"));
1333 *m_stream.localData() << factoryTemplateString.
arg(toQtInterfaceName(factored)).
arg(toCamelCase(r.name())).
arg(arguments);
1338 void Generator::generateClientCppRequests(
const Interface &interface)
1340 const auto requests = interface.requests();
1341 const QString templateString = QStringLiteral(
1344 " Q_ASSERT(isValid());\n"
1345 " %4_%5(d->%6%7);\n"
1347 const QString factoryTemplateString = QStringLiteral(
1350 " Q_ASSERT(isValid());\n"
1351 " auto p = new %2(parent);\n"
1352 " auto w = %5_%6(d->%7%8);\n"
1353 " if (d->queue) {\n"
1354 " d->queue->addProxy(w);\n"
1359 for (
const auto &r : requests) {
1360 if (r.isDestructor()) {
1367 for (
const auto &a : r.arguments()) {
1368 if (a.type() == Argument::Type::NewId) {
1369 factored = a.interface();
1373 arguments.
append(QStringLiteral(
", "));
1377 if (a.type() == Argument::Type::Object) {
1378 arguments.
append(QStringLiteral(
"%1 *%2").arg(a.typeAsQt()).arg(toCamelCase(a.name())));
1379 requestArguments.
append(QStringLiteral(
", *%1").arg(toCamelCase(a.name())));
1381 arguments.
append(QStringLiteral(
"%1 %2").arg(a.typeAsQt()).arg(toCamelCase(a.name())));
1382 QString arg = toCamelCase(a.name());
1383 if (a.type() == Argument::Type::Fixed) {
1384 arg = QStringLiteral(
"wl_fixed_from_double(%1)").
arg(arg);
1386 requestArguments.
append(QStringLiteral(
", %1").arg(arg));
1390 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName())
1391 .
arg(toCamelCase(r.name()))
1393 .
arg(interface.name())
1395 .
arg(interface.kwaylandClientName().toLower())
1396 .
arg(requestArguments);
1399 arguments.
append(QStringLiteral(
", "));
1401 arguments.
append(QStringLiteral(
"QObject *parent"));
1402 *m_stream.localData() << factoryTemplateString.
arg(interface.kwaylandClientName())
1403 .
arg(toQtInterfaceName(factored))
1404 .
arg(toCamelCase(r.name()))
1406 .
arg(interface.name())
1408 .
arg(interface.kwaylandClientName().toLower())
1409 .
arg(requestArguments);
1414 void Generator::generateClientClassCasts(
const Interface &interface)
1416 const QString templateString = QStringLiteral(
1417 " operator %1*();\n"
1418 " operator %1*() const;\n\n");
1419 *m_stream.localData() << templateString.
arg(interface.name());
1422 void Generator::generateClientGlobalClassEnd(
const Interface &interface)
1425 *m_stream.localData() << QStringLiteral(
"private:\n");
1426 generateClientClassDptr(interface);
1427 *m_stream.localData() << QStringLiteral(
"};\n\n");
1430 void Generator::generateClientClassDptr(
const Interface &interface)
1433 *m_stream.localData() << QStringLiteral(
1435 " QScopedPointer<Private> d;\n");
1438 void Generator::generateClientResourceClassEnd(
const Interface &interface)
1440 *m_stream.localData() << QStringLiteral(
1442 " friend class %2;\n"
1443 " explicit %1(QObject *parent = nullptr);\n")
1444 .arg(interface.kwaylandClientName())
1445 .arg(interface.factory()->kwaylandClientName());
1446 generateClientClassDptr(interface);
1447 *m_stream.localData() << QStringLiteral(
"};\n\n");
1450 void Generator::generateWaylandForwardDeclarations()
1452 for (
auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
1453 *m_stream.localData() << QStringLiteral(
"struct %1;\n").arg((*it).name());
1455 *m_stream.localData() <<
"\n";
1458 void Generator::generateNamespaceForwardDeclarations()
1461 for (
auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
1462 const auto events = (*it).events();
1463 const auto requests = (*it).requests();
1464 for (
const auto &e : events) {
1465 const auto args = e.arguments();
1466 for (
const auto &a : args) {
1467 if (a.type() != Argument::Type::Object && a.type() != Argument::Type::NewId) {
1470 referencedObjects << a.interface();
1473 for (
const auto &r : requests) {
1474 const auto args = r.arguments();
1475 for (
const auto &a : args) {
1476 if (a.type() != Argument::Type::Object && a.type() != Argument::Type::NewId) {
1479 referencedObjects << a.interface();
1484 switch (m_project.localData()) {
1485 case Project::Client:
1486 *m_stream.localData() << QStringLiteral(
"class EventQueue;\n");
1487 for (
const auto &o : referencedObjects) {
1488 auto it = s_clientClassNameMapping.
constFind(o);
1489 if (it != s_clientClassNameMapping.
constEnd()) {
1490 *m_stream.localData() << QStringLiteral(
"class %1;\n").arg(it.value());
1492 qWarning() <<
"Cannot forward declare KWayland class for interface " << o;
1495 *m_stream.localData() << QStringLiteral(
"\n");
1497 case Project::Server:
1498 *m_stream.localData() << QStringLiteral(
"class Display;\n\n");
1505 void Generator::generateClientClassSignals(
const Interface &interface)
1507 const QString templateString = QStringLiteral(
1510 " * The corresponding global for this interface on the Registry got removed.\n"
1512 " * This signal gets only emitted if the %1 got created by\n"
1513 " * Registry::create%1\n"
1515 " void removed();\n\n");
1516 *m_stream.localData() << templateString.
arg(interface.kwaylandClientName());
1519 QString Generator::projectToName()
const
1521 switch (m_project.localData()) {
1522 case Project::Client:
1523 return QStringLiteral(
"Client");
1524 case Project::Server:
1525 return QStringLiteral(
"Server");
1531 static void parseMapping()
1533 QFile mappingFile(QStringLiteral(MAPPING_FILE));
1536 while (!stream.atEnd()) {
1537 QString line = stream.readLine();
1542 if (parts.
count() < 2) {
1545 s_clientClassNameMapping.
insert(parts.
first(), parts.
at(1));
1552 int main(
int argc,
char **argv)
1554 using namespace KWayland::Tools;
1562 QStringLiteral(
"The wayland protocol to parse."),
1563 QStringLiteral(
"FileName"));
1565 QStringLiteral(
"The base name of files to be generated. E.g. for \"foo\" the files \"foo.h\" and \"foo.cpp\" are generated."
1566 "If not provided the base name gets derived from the xml protocol name"),
1567 QStringLiteral(
"FileName"));
1576 generator.setXmlFileName(parser.
value(xmlFile));
1577 generator.setBaseFileName(parser.
value(fileName));