[tools] Generator can parse xml protocol description to generate code

* parses the protocol
* can derive file name to generate from protocol name
* detects which interface is a global and which one is referenced
* generates client code for global and for resource
* comes with a mapping.txt file to translate wl -> KWayland
This commit is contained in:
Martin Gräßlin 2015-09-04 13:58:14 +02:00
parent 51018e8e38
commit 7a52d15eca
4 changed files with 630 additions and 71 deletions

View file

@ -5,6 +5,7 @@ find_package(Qt5Concurrent ${QT_MIN_VERSION} CONFIG QUIET)
if (Qt5Concurrent_FOUND)
set(scannerSRCS generator.cpp)
add_definitions(-DMAPPING_FILE="${CMAKE_CURRENT_SOURCE_DIR}/mapping.txt")
add_executable(kwaylandScanner ${scannerSRCS})
target_link_libraries(kwaylandScanner Qt5::Core Qt5::Concurrent)
ecm_mark_as_test(kwaylandScanner)

View file

@ -29,12 +29,99 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include <QProcess>
#include <QtConcurrent>
#include <QTextStream>
#include <QXmlStreamReader>
#include <QDebug>
namespace KWayland
{
namespace Tools
{
static QMap<QString, QString> s_clientClassNameMapping;
Argument::Argument()
{
}
Argument::Argument(const QXmlStreamAttributes &attributes)
: m_name(attributes.value(QStringLiteral("name")).toString())
, m_type(parseType(attributes.value(QStringLiteral("type"))))
, m_allowNull(attributes.hasAttribute(QStringLiteral("allow-null")))
, m_inteface(attributes.value(QStringLiteral("interface")).toString())
{
}
Argument::~Argument() = default;
Argument::Type Argument::parseType(const QStringRef &type)
{
if (type.compare(QLatin1String("new_id")) == 0) {
return Type::NewId;
}
if (type.compare(QLatin1String("destructor")) == 0) {
return Type::Destructor;
}
if (type.compare(QLatin1String("object")) == 0) {
return Type::Object;
}
if (type.compare(QLatin1String("fd")) == 0) {
return Type::FileDescriptor;
}
if (type.compare(QLatin1String("fixed")) == 0) {
return Type::Fixed;
}
if (type.compare(QLatin1String("uint")) == 0) {
return Type::Uint;
}
if (type.compare(QLatin1String("int")) == 0) {
return Type::Int;
}
if (type.compare(QLatin1String("string")) == 0) {
return Type::String;
}
return Type::Unknown;
}
Request::Request()
{
}
Request::Request(const QString &name)
: m_name(name)
{
}
Request::~Request() = default;
Event::Event()
{
}
Event::Event(const QString &name)
: m_name(name)
{
}
Event::~Event() = default;
Interface::Interface() = default;
Interface::Interface(const QXmlStreamAttributes &attributes)
: m_name(attributes.value(QStringLiteral("name")).toString())
, m_version(attributes.value(QStringLiteral("version")).toUInt())
{
auto it = s_clientClassNameMapping.constFind(m_name);
if (it != s_clientClassNameMapping.constEnd()) {
m_clientName = it.value();
} else {
qWarning() << "Failed to map " << m_name << " to a KWayland name";
}
}
Interface::~Interface() = default;
Generator::Generator(QObject *parent)
: QObject(parent)
{
@ -47,10 +134,134 @@ void Generator::start()
startAuthorNameProcess();
startAuthorEmailProcess();
startParseXml();
startGenerateHeaderFile();
startGenerateCppFile();
}
void Generator::startParseXml()
{
if (m_xmlFileName.isEmpty()) {
return;
}
QFile xmlFile(m_xmlFileName);
xmlFile.open(QIODevice::ReadOnly);
m_xmlReader.setDevice(&xmlFile);
while (!m_xmlReader.atEnd()) {
if (!m_xmlReader.readNextStartElement()) {
continue;
}
if (m_xmlReader.qualifiedName().compare(QLatin1String("protocol")) == 0) {
parseProtocol();
}
}
auto findFactory = [this] (const QString interfaceName) -> Interface* {
for (auto it = m_interfaces.begin(); it != m_interfaces.end(); ++it) {
if ((*it).name().compare(interfaceName) == 0) {
continue;
}
for (auto r: (*it).requests()) {
for (auto a: r.arguments()) {
if (a.type() == Argument::Type::NewId && a.interface().compare(interfaceName) == 0) {
return &(*it);
}
}
}
}
return nullptr;
};
for (auto it = m_interfaces.begin(); it != m_interfaces.end(); ++it) {
Interface *factory = findFactory((*it).name());
if (factory) {
qDebug() << (*it).name() << "gets factored by" << factory->kwaylandClientName();
(*it).setFactory(factory);
} else {
qDebug() << (*it).name() << "considered as a global";
(*it).markAsGlobal();
}
}
}
void Generator::parseProtocol()
{
const auto attributes = m_xmlReader.attributes();
const QString protocolName = attributes.value(QStringLiteral("name")).toString();
if (m_baseFileName.isEmpty()) {
m_baseFileName = protocolName.toLower();
}
while (!m_xmlReader.atEnd()) {
if (!m_xmlReader.readNextStartElement()) {
if (m_xmlReader.qualifiedName().compare(QLatin1String("protocol")) == 0) {
return;
}
continue;
}
if (m_xmlReader.qualifiedName().compare(QLatin1String("interface")) == 0) {
m_interfaces << parseInterface();
}
}
}
Interface Generator::parseInterface()
{
Interface interface(m_xmlReader.attributes());
while (!m_xmlReader.atEnd()) {
if (!m_xmlReader.readNextStartElement()) {
if (m_xmlReader.qualifiedName().compare(QLatin1String("interface")) == 0) {
break;
}
continue;
}
if (m_xmlReader.qualifiedName().compare(QLatin1String("request")) == 0) {
interface.addRequest(parseRequest());
}
if (m_xmlReader.qualifiedName().compare(QLatin1String("event")) == 0) {
interface.addEvent(parseEvent());
}
}
return interface;
}
Request Generator::parseRequest()
{
const auto attributes = m_xmlReader.attributes();
Request request(attributes.value(QStringLiteral("name")).toString());
while (!m_xmlReader.atEnd()) {
if (!m_xmlReader.readNextStartElement()) {
if (m_xmlReader.qualifiedName().compare(QLatin1String("request")) == 0) {
break;
}
continue;
}
if (m_xmlReader.qualifiedName().compare(QLatin1String("arg")) == 0) {
request.addArgument(Argument(m_xmlReader.attributes()));
}
}
return request;
}
Event Generator::parseEvent()
{
const auto attributes = m_xmlReader.attributes();
Event event(attributes.value(QStringLiteral("name")).toString());
while (!m_xmlReader.atEnd()) {
if (!m_xmlReader.readNextStartElement()) {
if (m_xmlReader.qualifiedName().compare(QLatin1String("event")) == 0) {
break;
}
continue;
}
if (m_xmlReader.qualifiedName().compare(QLatin1String("arg")) == 0) {
event.addArgument(Argument(m_xmlReader.attributes()));
}
}
return event;
}
void Generator::startGenerateHeaderFile()
{
QFutureWatcher<void> *watcher = new QFutureWatcher<void>(this);
@ -66,7 +277,9 @@ void Generator::startGenerateHeaderFile()
generateWaylandForwardDeclarations();
generateStartNamespace();
generateNamespaceForwardDeclarations();
generateClass();
for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
generateClass(*it);
}
generateEndNamespace();
generateEndIncludeGuard();
@ -87,8 +300,10 @@ void Generator::startGenerateCppFile()
generateCopyrightHeader();
generateCppIncludes();
generateStartNamespace();
generatePrivateClass();
generateClientCpp();
for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
generatePrivateClass(*it);
generateClientCpp(*it);
}
generateEndNamespace();
@ -188,7 +403,7 @@ void Generator::generateStartIncludeGuard()
"#ifndef KWAYLAND_%1_%2_H\n"
"#define KWAYLAND_%1_%2_H\n\n");
*m_stream.localData() << templateString.arg(projectToName().toUpper()).arg(m_className.toUpper());
*m_stream.localData() << templateString.arg(projectToName().toUpper()).arg(m_baseFileName.toUpper());
}
void Generator::generateStartNamespace()
@ -223,7 +438,7 @@ void Generator::generateHeaderIncludes()
void Generator::generateCppIncludes()
{
*m_stream.localData() << QStringLiteral("#include \"%1.h\"\n").arg(m_className.toLower());
*m_stream.localData() << QStringLiteral("#include \"%1.h\"\n").arg(m_baseFileName.toLower());
switch (m_project) {
case Project::Client:
*m_stream.localData() << QStringLiteral("#include \"event_queue.h\"\n\n");
@ -236,14 +451,15 @@ void Generator::generateCppIncludes()
}
}
void Generator::generateClass()
void Generator::generateClass(const Interface &interface)
{
switch (m_project) {
case Project::Client:
generateClientClassStart();
generateClientClassCasts();
generateClientClassSignals();
generateClientClassEnd();
if (interface.isGlobal()) {
generateClientGlobalClass(interface);
} else {
generateClientResourceClass(interface);
}
break;
case Project::Server:
// TODO: implement
@ -253,11 +469,35 @@ void Generator::generateClass()
}
}
void Generator::generatePrivateClass()
void Generator::generateClientGlobalClass(const Interface &interface)
{
generateClientGlobalClassDoxy(interface);
generateClientClassQObjectDerived(interface);
generateClientGlobalClassCtor(interface);
generateClientClassDtor(interface);
generateClientGlobalClassSetup(interface);
generateClientClassReleaseDestroy(interface);
generateClientClassStart(interface);
generateClientClassCasts(interface);
generateClientClassSignals(interface);
generateClientGlobalClassEnd(interface);
}
void Generator::generateClientResourceClass(const Interface &interface)
{
generateClientClassQObjectDerived(interface);
generateClientClassDtor(interface);
generateClientResourceClassSetup(interface);
generateClientClassReleaseDestroy(interface);
generateClientClassCasts(interface);
generateClientResourceClassEnd(interface);
}
void Generator::generatePrivateClass(const Interface &interface)
{
switch (m_project) {
case Project::Client:
generateClientPrivateClass();
generateClientPrivateClass(interface);
break;
case Project::Server:
// TODO: implement
@ -267,7 +507,7 @@ void Generator::generatePrivateClass()
}
}
void Generator::generateClientPrivateClass()
void Generator::generateClientPrivateClass(const Interface &interface)
{
const QString templateString = QStringLiteral(
"class %1::Private\n"
@ -275,14 +515,16 @@ void Generator::generateClientPrivateClass()
"public:\n"
" Private() = default;\n"
"\n"
" WaylandPointer<%2, %2_destroy> %3;\n"
" EventQueue *queue = nullptr;\n"
"};\n\n");
" WaylandPointer<%2, %2_destroy> %3;\n");
*m_stream.localData() << templateString.arg(m_className).arg(m_waylandGlobal).arg(m_className.toLower());
*m_stream.localData() << templateString.arg(interface.kwaylandClientName()).arg(interface.name()).arg(interface.kwaylandClientName().toLower());
if (interface.isGlobal()) {
*m_stream.localData() << " EventQueue *queue = nullptr;\n";
}
*m_stream.localData() << "};\n\n";
}
void Generator::generateClientCpp()
void Generator::generateClientCpp(const Interface &interface)
{
const QString templateString = QStringLiteral(
"%1::%1(QObject *parent)\n"
@ -336,10 +578,12 @@ void Generator::generateClientCpp()
" return d->%2.isValid();\n"
"}\n\n");
*m_stream.localData() << templateString.arg(m_className).arg(m_className.toLower()).arg(m_waylandGlobal);
*m_stream.localData() << templateString.arg(interface.kwaylandClientName())
.arg(interface.kwaylandClientName().toLower())
.arg(interface.name());
}
void Generator::generateClientClassStart()
void Generator::generateClientGlobalClassDoxy(const Interface &interface)
{
const QString templateString = QStringLiteral(
"/**\n"
@ -364,31 +608,46 @@ void Generator::generateClientClassStart()
" * pointer as it provides matching cast operators.\n"
" *\n"
" * @see Registry\n"
" **/\n"
"class KWAYLAND%3_EXPORT %1 : public QObject\n"
" **/\n");
*m_stream.localData() << templateString.arg(interface.kwaylandClientName()).arg(interface.name());
}
void Generator::generateClientClassQObjectDerived(const Interface &interface)
{
const QString templateString = QStringLiteral(
"class KWAYLANDCLIENT_EXPORT %1 : public QObject\n"
"{\n"
" Q_OBJECT\n"
"public:\n"
"public:\n");
*m_stream.localData() << templateString.arg(interface.kwaylandClientName());
}
void Generator::generateClientGlobalClassCtor(const Interface &interface)
{
const QString templateString = QStringLiteral(
" /**\n"
" * Creates a new %1.\n"
" * Note: after constructing the %1 it is not yet valid and one needs\n"
" * to call setup. In order to get a ready to use %1 prefer using\n"
" * Registry::create%1.\n"
" **/\n"
" explicit %1(QObject *parent = nullptr);\n"
" virtual ~%1();\n"
"\n"
" explicit %1(QObject *parent = nullptr);\n");
*m_stream.localData() << templateString.arg(interface.kwaylandClientName());
}
void Generator::generateClientClassDtor(const Interface &interface)
{
*m_stream.localData() << QStringLiteral(" virtual ~%1();\n\n").arg(interface.kwaylandClientName());
}
void Generator::generateClientClassReleaseDestroy(const Interface &interface)
{
const QString templateString = QStringLiteral(
" /**\n"
" * @returns @c true if managing a %2.\n"
" **/\n"
" bool isValid() const;\n"
" /**\n"
" * Setup this %1 to manage the @p %4.\n"
" * When using Registry::create%1 there is no need to call this\n"
" * method.\n"
" **/\n"
" void setup(%2 *%4);\n"
" /**\n"
" * Releases the %2 interface.\n"
" * After the interface has been released the %1 instance is no\n"
" * longer valid and can be setup with another %2 interface.\n"
@ -405,13 +664,47 @@ void Generator::generateClientClassStart()
" *\n"
" * It is suggested to connect this method to ConnectionThread::connectionDied:\n"
" * @code\n"
" * connect(connection, &ConnectionThread::connectionDied, %4, &%1::destroy);\n"
" * connect(connection, &ConnectionThread::connectionDied, %3, &%1::destroy);\n"
" * @endcode\n"
" *\n"
" * @see release\n"
" **/\n"
" void destroy();\n"
"\n"
"\n");
*m_stream.localData() << templateString.arg(interface.kwaylandClientName()).arg(interface.name()).arg(interface.kwaylandClientName().toLower());
}
void Generator::generateClientGlobalClassSetup(const Interface &interface)
{
const QString templateString = QStringLiteral(
" /**\n"
" * Setup this %1 to manage the @p %3.\n"
" * When using Registry::create%1 there is no need to call this\n"
" * method.\n"
" **/\n"
" void setup(%2 *%3);\n");
*m_stream.localData() << templateString.arg(interface.kwaylandClientName()).arg(interface.name()).arg(interface.kwaylandClientName().toLower());
}
void Generator::generateClientResourceClassSetup(const Interface &interface)
{
const QString templateString = QStringLiteral(
" /**\n"
" * Setup this %1 to manage the @p %3.\n"
" * When using %4::create%1 there is no need to call this\n"
" * method.\n"
" **/\n"
" void setup(%2 *%3);\n");
*m_stream.localData() << templateString.arg(interface.kwaylandClientName())
.arg(interface.name())
.arg(interface.kwaylandClientName().toLower())
.arg(interface.factory()->kwaylandClientName());
}
void Generator::generateClientClassStart(const Interface &interface)
{
const QString templateString = QStringLiteral(
" /**\n"
" * Sets the @p queue to use for creating objects with this %1.\n"
" **/\n"
@ -420,36 +713,90 @@ void Generator::generateClientClassStart()
" * @returns The event queue to use for creating objects with this %1.\n"
" **/\n"
" EventQueue *eventQueue();\n\n");
*m_stream.localData() << templateString.arg(m_className).arg(m_waylandGlobal).arg(projectToName().toUpper()).arg(m_className.toLower());
*m_stream.localData() << templateString.arg(interface.kwaylandClientName());
}
void Generator::generateClientClassCasts()
void Generator::generateClientClassCasts(const Interface &interface)
{
const QString templateString = QStringLiteral(
" operator %1*();\n"
" operator %1*() const;\n\n");
*m_stream.localData() << templateString.arg(m_waylandGlobal);
*m_stream.localData() << templateString.arg(interface.name());
}
void Generator::generateClientClassEnd()
void Generator::generateClientGlobalClassEnd(const Interface &interface)
{
Q_UNUSED(interface)
*m_stream.localData() << QStringLiteral("private:\n");
generateClientClassDptr(interface);
*m_stream.localData() << QStringLiteral("};\n\n");
}
void Generator::generateClientClassDptr(const Interface &interface)
{
Q_UNUSED(interface)
*m_stream.localData() << QStringLiteral(
" class Private;\n"
" QScopedPointer<Private> d;\n");
}
void Generator::generateClientResourceClassEnd(const Interface &interface)
{
*m_stream.localData() << QStringLiteral(
"private:\n"
" class Private;\n"
" QScopedPointer<Private> d;\n"
"};\n\n");
" friend class %2;\n"
" explicit %1(QObject *parent = nullptr);\n"
).arg(interface.kwaylandClientName()).arg(interface.factory()->kwaylandClientName());
generateClientClassDptr(interface);
*m_stream.localData() << QStringLiteral("};\n\n");
}
void Generator::generateWaylandForwardDeclarations()
{
*m_stream.localData() << QStringLiteral("struct %1;\n\n").arg(m_waylandGlobal);
for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
*m_stream.localData() << QStringLiteral("struct %1;\n").arg((*it).name());
}
*m_stream.localData() << "\n";
}
void Generator::generateNamespaceForwardDeclarations()
{
QSet<QString> referencedObjects;
for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
const auto events = (*it).events();
const auto requests = (*it).requests();
for (const auto &e: events) {
const auto args = e.arguments();
for (const auto &a: args) {
if (a.type() != Argument::Type::Object && a.type() != Argument::Type::NewId) {
continue;
}
referencedObjects << a.interface();
}
}
for (const auto &r: requests) {
const auto args = r.arguments();
for (const auto &a: args) {
if (a.type() != Argument::Type::Object && a.type() != Argument::Type::NewId) {
continue;
}
referencedObjects << a.interface();
}
}
}
switch (m_project) {
case Project::Client:
*m_stream.localData() << QStringLiteral("class EventQueue;\n\n");
*m_stream.localData() << QStringLiteral("class EventQueue;\n");
for (const auto &o : referencedObjects) {
auto it = s_clientClassNameMapping.constFind(o);
if (it != s_clientClassNameMapping.constEnd()) {
*m_stream.localData() << QStringLiteral("class %1;\n").arg(it.value());
} else {
qWarning() << "Cannot forward declare KWayland class for interface " << it.key();
}
}
*m_stream.localData() << QStringLiteral("\n");
break;
case Project::Server:
// TODO: implement
@ -459,7 +806,7 @@ void Generator::generateNamespaceForwardDeclarations()
}
}
void Generator::generateClientClassSignals()
void Generator::generateClientClassSignals(const Interface &interface)
{
const QString templateString = QStringLiteral(
"Q_SIGNALS:\n"
@ -470,7 +817,7 @@ void Generator::generateClientClassSignals()
" * Registry::create%1\n"
" **/\n"
" void removed();\n\n");
*m_stream.localData() << templateString.arg(m_className);
*m_stream.localData() << templateString.arg(interface.kwaylandClientName());
}
QString Generator::projectToName() const
@ -485,36 +832,53 @@ QString Generator::projectToName() const
}
}
static void parseMapping()
{
QFile mappingFile(QStringLiteral(MAPPING_FILE));
mappingFile.open(QIODevice::ReadOnly);
QTextStream stream(&mappingFile);
while (!stream.atEnd()) {
QString line = stream.readLine();
if (line.startsWith(QLatin1String("#")) || line.isEmpty()) {
continue;
}
const QStringList parts = line.split(QStringLiteral(";"));
if (parts.count() < 2) {
continue;
}
s_clientClassNameMapping.insert(parts.first(), parts.at(1));
}
}
}
}
int main(int argc, char **argv)
{
using namespace KWayland::Tools;
parseMapping();
QCoreApplication app(argc, argv);
QCommandLineParser parser;
QCommandLineOption className(QStringList{QStringLiteral("c"), QStringLiteral("class")},
QStringLiteral("The class name to generate. On Server \"Interface\" is added."),
QStringLiteral("ClassName"));
QCommandLineOption xmlFile(QStringList{QStringLiteral("x"), QStringLiteral("xml")},
QStringLiteral("The wayland protocol to parse."),
QStringLiteral("FileName"));
QCommandLineOption fileName(QStringList{QStringLiteral("f"), QStringLiteral("file")},
QStringLiteral("The base name of files to be generated. E.g. for \"foo\" the files \"foo.h\" and \"foo.cpp\" are generated"),
QStringLiteral("The base name of files to be generated. E.g. for \"foo\" the files \"foo.h\" and \"foo.cpp\" are generated."
"If not provided the base name gets derived from the xml protocol name"),
QStringLiteral("FileName"));
QCommandLineOption globalName(QStringList{QStringLiteral("g"), QStringLiteral("global")},
QStringLiteral("The name for the Wayland global for which the wrapper is generated. E.g. \"wl_foo\"."),
QStringLiteral("wl_global"));
parser.addHelpOption();
parser.addOption(className);
parser.addOption(xmlFile);
parser.addOption(fileName);
parser.addOption(globalName);
parser.process(app);
Generator generator(&app);
generator.setClassName(parser.value(className));
generator.setXmlFileName(parser.value(xmlFile));
generator.setBaseFileName(parser.value(fileName));
generator.setWaylandGlobal(parser.value(globalName));
generator.setProject(Generator::Project::Client);
generator.start();

View file

@ -21,9 +21,11 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#define KWAYLAND_TOOLS_GENERATOR_H
#include <QObject>
#include <QMap>
#include <QMutex>
#include <QThreadStorage>
#include <QWaitCondition>
#include <QXmlStreamReader>
class QTextStream;
@ -32,6 +34,150 @@ namespace KWayland
namespace Tools
{
class Argument
{
public:
explicit Argument();
explicit Argument(const QXmlStreamAttributes &attributes);
~Argument();
enum class Type {
Unknown,
NewId,
Destructor,
Object,
FileDescriptor,
Fixed,
Uint,
Int,
String
};
QString name() const {
return m_name;
}
Type type() const {
return m_type;
}
bool isNullAllowed() const {
return m_allowNull;
}
QString interface() const {
return m_inteface;
}
private:
Type parseType(const QStringRef &type);
QString m_name;
Type m_type = Type::Unknown;
bool m_allowNull = false;
QString m_inteface;
};
class Request
{
public:
explicit Request();
explicit Request(const QString &name);
~Request();
void addArgument(const Argument &arg) {
m_arguments << arg;
}
QString name() const {
return m_name;
}
QVector<Argument> arguments() const {
return m_arguments;
}
private:
QString m_name;
QVector<Argument> m_arguments;
};
class Event
{
public:
explicit Event();
explicit Event(const QString &name);
~Event();
void addArgument(const Argument &arg) {
m_arguments << arg;
}
QString name() const {
return m_name;
}
QVector<Argument> arguments() const {
return m_arguments;
}
private:
QString m_name;
QVector<Argument> m_arguments;
};
class Interface
{
public:
explicit Interface();
explicit Interface(const QXmlStreamAttributes &attributes);
virtual ~Interface();
void addRequest(const Request &request) {
m_requests << request;
}
void addEvent(const Event &event) {
m_events << event;
}
QString name() const {
return m_name;
}
quint32 version() const {
return m_version;
}
QString kwaylandClientName() const {
return m_clientName;
}
QVector<Request> requests() const {
return m_requests;
}
QVector<Event> events() const {
return m_events;
}
void markAsGlobal() {
m_global = true;
}
bool isGlobal() const {
return m_global;
}
void setFactory(Interface *factory) {
m_factory = factory;
}
Interface *factory() const {
return m_factory;
}
private:
QString m_name;
QString m_clientName;
quint32 m_version;
QVector<Request> m_requests;
QVector<Event> m_events;
bool m_global = false;
Interface *m_factory;
};
class Generator : public QObject
{
Q_OBJECT
@ -39,15 +185,12 @@ public:
explicit Generator(QObject *parent = nullptr);
virtual ~Generator();
void setClassName(const QString &name) {
m_className = name;
void setXmlFileName(const QString &name) {
m_xmlFileName = name;
}
void setBaseFileName(const QString &name) {
m_baseFileName = name;
}
void setWaylandGlobal(const QString &name) {
m_waylandGlobal = name;
}
enum class Project {
Client,
Server
@ -65,16 +208,28 @@ private:
void generateEndNamespace();
void generateHeaderIncludes();
void generateCppIncludes();
void generatePrivateClass();
void generateClientPrivateClass();
void generateClientCpp();
void generateClass();
void generateClientClassStart();
void generateClientClassCasts();
void generateClientClassSignals();
void generateClientClassEnd();
void generatePrivateClass(const Interface &interface);
void generateClientPrivateClass(const Interface &interface);
void generateClientCpp(const Interface &interface);
void generateClass(const Interface &interface);
void generateClientGlobalClass(const Interface &interface);
void generateClientResourceClass(const Interface &interface);
void generateClientClassQObjectDerived(const Interface &interface);
void generateClientGlobalClassDoxy(const Interface &interface);
void generateClientGlobalClassCtor(const Interface &interface);
void generateClientGlobalClassSetup(const Interface &interface);
void generateClientResourceClassSetup(const Interface &interface);
void generateClientClassDtor(const Interface &interface);
void generateClientClassReleaseDestroy(const Interface &interface);
void generateClientClassStart(const Interface &interface);
void generateClientClassCasts(const Interface &interface);
void generateClientClassSignals(const Interface &interface);
void generateClientClassDptr(const Interface &interface);
void generateClientGlobalClassEnd(const Interface &interface);
void generateClientResourceClassEnd(const Interface &interface);
void generateWaylandForwardDeclarations();
void generateNamespaceForwardDeclarations();
void startParseXml();
void startAuthorNameProcess();
void startAuthorEmailProcess();
void startGenerateHeaderFile();
@ -82,11 +237,15 @@ private:
void checkEnd();
void parseProtocol();
Interface parseInterface();
Request parseRequest();
Event parseEvent();
QString projectToName() const;
QThreadStorage<QTextStream*> m_stream;
QString m_className;
QString m_waylandGlobal;
QString m_xmlFileName;
Project m_project;
QString m_authorName;
QString m_authorEmail;
@ -94,6 +253,8 @@ private:
QMutex m_mutex;
QWaitCondition m_waitCondition;
QXmlStreamReader m_xmlReader;
QVector<Interface> m_interfaces;
int m_finishedCounter = 0;
};

View file

@ -0,0 +1,33 @@
#wl_name;KWayland::ClientName
wl_buffer;Buffer
wl_compositor;Compositor
wl_data_device;DataDevice
wl_data_device_manager;DataDeviceManager
wl_data_offer;DataOffer
wl_data_source;DataSource
wl_event_queue;EventQueue
wl_keyboard;Keyboard
wl_output;Output
wl_pointer;Pointer
wl_region;Region
wl_registry;Registry
wl_seat;Seat
wl_shell;Shell
wl_shell_surface;ShellSurface
wl_shm;ShmPool
wl_subcompositor;SubCompositor
wl_subsurface;SubSurface
wl_surface;Surface
wl_touch;Touch
_wl_fullscreen_shell;FullscreenShell
org_kde_kwin_blur;Blur
org_kde_kwin_blur_manager;BlurManager
org_kde_kwin_fake_input;FakeInput
org_kde_kwin_idle;Idle
org_kde_kwin_idle_timeout;IdleTimeout
org_kde_kwin_shadow;Shadow
org_kde_kwin_shadow_manager;ShadowManager
org_kde_plasma_shell;PlasmaShell
org_kde_plasma_surface;PlasmaShellSurface
org_kde_plasma_window_management;PlasmaWindowManagement
org_kde_plasma_window;PlasmaWindow