diff --git a/.gitignore b/.gitignore index 5e732742b3c41881f5d6be79a8cf1267d15b08ab..8685fc80a2720ab96af336d2632c81a7fe729590 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -multi-screen +qt-multi-screen-compositor/multi-screen.pro.user +compositor.pro.user diff --git a/compositor-message/compositor-message.cpp b/compositor-message/compositor-message.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a2c1414e578fc3df1e698c8eddfbb0dfd640987 --- /dev/null +++ b/compositor-message/compositor-message.cpp @@ -0,0 +1,155 @@ +#include <QThread> + +#include "compositor-message.h" + +const QString CompositorMessage::socketName = "serversocket"; + +CompositorMessage::CompositorMessage(QObject *parent) + : QObject{parent}, socket(new QLocalSocket(this)) + +{ + socketReadData.setDevice(socket); + socketReadData.setVersion(QDataStream::Qt_5_10); + connect(socket, &QLocalSocket::readyRead, this, &CompositorMessage::readData); + connect(socket, &QLocalSocket::errorOccurred, this, &CompositorMessage::socketError); +} + +bool CompositorMessage::connectSocket(void) +{ + socket->abort(); + socket->connectToServer(socketName); + if ( socket->waitForConnected()) + { + qDebug() << "Connected to Server"; + return true; + }else + { + qDebug() << "Timeout waiting for the server connection"; + return false; + } +} + +int CompositorMessage::sendMessage(QString msg, qint32 windowid, qint32 screenid){ + QByteArray data; + QDataStream out(&data, QIODevice::WriteOnly); + + if( ! socket->isValid()){ + qWarning() << "Can't send something. Socket not valid"; + return -1; + } + + out << quint32(0xDEADBEEF) << msg << windowid << screenid; + socket->write(data); + socket->flush(); + return 0; +} + +void CompositorMessage::sendSomething(void){ + QByteArray data; + QDataStream out(&data, QIODevice::WriteOnly); + + if( ! socket->isValid()){ + qWarning() << "Can't send something. Socket not valid"; + return; + } + + out << QString("This is to be skipped"); + out << quint32(0xDEADBEEF); + out << QString("This is my message"); + socket->write(data); + socket->flush(); + qDebug() << "Data length" << data.length(); + data.clear(); + qDebug() << "Data length" << data.length(); + QThread::sleep(1); // seconds + + { + QByteArray data2; + QDataStream out2(&data2, QIODevice::WriteOnly); + out2 << quint32(42); + out2 << quint32(2); + qDebug() << "Data length" << data2.length(); + socket->write(data2); + socket->flush(); + + } + + + { + QByteArray data2; + QDataStream out2(&data2, QIODevice::WriteOnly); + out2 << quint16(42); + out2 << quint32(0xDEADBEEF); + qDebug() << "Data length" << data2.length(); + socket->write(data2); + socket->flush(); + } +} + +bool CompositorMessage::searchHeader(QDataStream *stream){ + // The message needs to begin with a magic + int headerstate = 0; + char header[4] = { (char)0xDE, (char)0xAD, (char)0xBE, (char)0xEF }; + while(headerstate < 4){ // four bytes of header need to match + char byte; + if(stream->readRawData(&byte, 1) == -1){ + qDebug() << "End of data, bytes magic byte not found"; + return false; + } + if(byte == header[headerstate]) + headerstate++; + else + headerstate=0; + }; + return true; +} + +void CompositorMessage::readData(void){ + QString message; + quint32 status; + + qDebug() << "Server send data: " << socket->bytesAvailable(); + + while(socket->bytesAvailable() > 0){ + // Use transaction to make sure to receive a complete message + socketReadData.startTransaction(); + + if(!searchHeader(&socketReadData)) + return; + + socketReadData >> message >> status; + if(!socketReadData.commitTransaction()){ + qDebug() << "Message incomplete, continue waiting"; + return; + } + + // TODO use received data, emit signal + qDebug() << message << status; + if( message == "Status") + emit statusReceived(status); + + if(socket->bytesAvailable() > 0){ + qDebug() << "Still bytes available: " << socket->bytesAvailable(); + } + } +} + +void CompositorMessage::socketError(QLocalSocket::LocalSocketError error){ + switch (error) { + case QLocalSocket::ServerNotFoundError: + qWarning() << "The host was not found. Please make sure " + "that the server is running and that the " + "server name is correct."; + break; + case QLocalSocket::ConnectionRefusedError: + qWarning() << "The connection was refused by the peer. " + "Make sure the server is running, " + "and check that the server name " + "is correct."; + break; + case QLocalSocket::PeerClosedError: + break; + default: + qWarning() << "The following error occurred: " << socket->errorString(); + } +} diff --git a/compositor-message/compositor-message.h b/compositor-message/compositor-message.h new file mode 100644 index 0000000000000000000000000000000000000000..c70a3621a6c91a671e0d67c8f26986a26ecbf9d4 --- /dev/null +++ b/compositor-message/compositor-message.h @@ -0,0 +1,31 @@ +#ifndef COMPOSITOR_MESSAGE_H +#define COMPOSITOR_MESSAGE_H + +#include <QDataStream> +#include <QObject> +#include <QLocalSocket> + +class CompositorMessage : public QObject +{ + Q_OBJECT +public: + explicit CompositorMessage(QObject *parent = nullptr); + bool connectSocket(); + void sendSomething(); +public slots: + int sendMessage(QString msg, qint32 windowid, qint32 screenid); +signals: + void statusReceived(int); + +private slots: + void readData(); + void socketError(QLocalSocket::LocalSocketError error); + +private: + static const QString socketName; + QLocalSocket *socket; + QDataStream socketReadData; + bool searchHeader(QDataStream *stream); +}; + +#endif // COMPOSITOR-MSG-CLIENT_H diff --git a/compositor-message/compositor-message.pro b/compositor-message/compositor-message.pro new file mode 100644 index 0000000000000000000000000000000000000000..e768c0d05c4042476f83dfc7f2718986ae0cedaf --- /dev/null +++ b/compositor-message/compositor-message.pro @@ -0,0 +1,21 @@ +QT -= gui +QT += network + +CONFIG += c++17 console +CONFIG -= app_bundle + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + compositor-message.cpp \ + main.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /usr/bin +!isEmpty(target.path): INSTALLS += target + +HEADERS += \ + compositor-message.h diff --git a/compositor-message/main.cpp b/compositor-message/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b13f75ee2aed8106dafbd605b1bb573c78b813d --- /dev/null +++ b/compositor-message/main.cpp @@ -0,0 +1,51 @@ +#include <QCommandLineParser> +#include <QCoreApplication> + +#include "compositor-message.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + CompositorMessage client; + ; + QCommandLineParser parser; + + parser.setApplicationDescription("Client to send messages to qt-multi-screen-compositor from command line."); + parser.addHelpOption(); + parser.addPositionalArgument("command", "Command string to send to the compositor."); + parser.addPositionalArgument("windowid", "Id used when started the window to modify."); + parser.addPositionalArgument("screenid", "Id to identify one of multiple connected screens."); + parser.process(a); + + const QStringList args = parser.positionalArguments(); + if(args.length() < 2){ + parser.showHelp(); + exit(-1); + } + + QString command; + bool ok; + qint32 windowid; + qint32 screenid = 0; + + command = QString(args[0]); + windowid = qint32(args[1].toInt(&ok)); + if(ok){ + if(args.length() > 2){ + screenid = qint32(args[2].toInt(&ok)); + } + } + if(! ok){ + QTextStream(stdout) << "windowid or screenid could not be parsed as integer."; + parser.showHelp(); + exit(-1); + } + + if(!client.connectSocket()) + return -1; + + QObject::connect(&client, SIGNAL(statusReceived(int)), &a, SLOT(quit() )); + client.sendMessage(command, windowid, screenid); + + return a.exec(); +} diff --git a/compositor.pro b/compositor.pro new file mode 100644 index 0000000000000000000000000000000000000000..5b58e7aa41e12dac3c0150697a91ef1111e37eb8 --- /dev/null +++ b/compositor.pro @@ -0,0 +1,7 @@ + + +TEMPLATE = subdirs + +SUBDIRS += \ + compositor-message/compositor-message.pro \ + multiscreen-compositor/multiscreen-compositor.pro diff --git a/compositorcommands.cpp b/compositorcommands.cpp deleted file mode 100644 index 416788c726b8615ab0fd8793d6972d816fedb682..0000000000000000000000000000000000000000 --- a/compositorcommands.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "compositorcommands.h" -#include <QDebug> - -CompositorCommands::CompositorCommands(QObject *parent) - : QObject{parent} -{ -} - -void CompositorCommands::messageReceived(QString message, quint32 value0, quint32 value1){ - qDebug() << "New message" << message; - - if(message == "moveWindowToScreen"){ - emit moveWindowToScreen(value0, value1); - }else - if(message == "hideWindow"){ - emit hideWindow(value0); - }else - if(message == "showWindow"){ - emit showWindow(value0); - }else{ - qWarning() << "Unknown message received: " << message; - } -} diff --git a/multi-screen.pro b/multi-screen.pro deleted file mode 100644 index 64211ed022264e808b45b2f00a35338bf843c546..0000000000000000000000000000000000000000 --- a/multi-screen.pro +++ /dev/null @@ -1,29 +0,0 @@ -QT += gui qml - -SOURCES += \ - compositorcommands.cpp \ - main.cpp \ - config.cpp \ - server.cpp \ - serverconnection.cpp - -HEADERS += \ - compositorcommands.h \ - config.h \ - server.h \ - serverconnection.h - -OTHER_FILES = \ - qml/main.qml \ - -RESOURCES += multi-screen.qrc - -target.path = $$[QT_INSTALL_EXAMPLES]/wayland/multi-screen -sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS multi-screen.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/wayland/multi-screen -INSTALLS += target sources - -DISTFILES += \ - qml/Screen.qml \ - qml/Chrome.qml \ - qml/IviChrome.qml diff --git a/multiscreen-compositor/compositor-messages.cpp b/multiscreen-compositor/compositor-messages.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3bf734b122f838529666d27dba447dffdee202f --- /dev/null +++ b/multiscreen-compositor/compositor-messages.cpp @@ -0,0 +1,23 @@ +#include "compositor-messages.h" +#include <QDebug> + +CompositorMessages::CompositorMessages(QObject *parent) + : QObject{parent} +{ +} + +void CompositorMessages::messageReceived(QString message, quint32 windowId, quint32 screenId){ + qDebug() << "New message" << message; + + if(message == "moveWindowToScreen"){ + emit moveWindowToScreen(windowId, screenId); + }else + if(message == "hideWindow"){ + emit hideWindow(windowId); + }else + if(message == "showWindow"){ + emit showWindow(windowId); + }else{ + qWarning() << "Unknown message received: " << message; + } +} diff --git a/compositorcommands.h b/multiscreen-compositor/compositor-messages.h similarity index 77% rename from compositorcommands.h rename to multiscreen-compositor/compositor-messages.h index bc8533cc841cbb06c708cbaa72aa41c315108f39..f09a39aac62ca2ed136007b9bb4b2794b139c922 100644 --- a/compositorcommands.h +++ b/multiscreen-compositor/compositor-messages.h @@ -3,11 +3,11 @@ #include <QObject> -class CompositorCommands : public QObject +class CompositorMessages : public QObject { Q_OBJECT public: - explicit CompositorCommands(QObject *parent = nullptr); + explicit CompositorMessages(QObject *parent = nullptr); public slots: void messageReceived(QString, quint32 value0, quint32 value2); diff --git a/config.cpp b/multiscreen-compositor/config.cpp similarity index 100% rename from config.cpp rename to multiscreen-compositor/config.cpp diff --git a/config.h b/multiscreen-compositor/config.h similarity index 100% rename from config.h rename to multiscreen-compositor/config.h diff --git a/main.cpp b/multiscreen-compositor/main.cpp similarity index 96% rename from main.cpp rename to multiscreen-compositor/main.cpp index e8d3515c089a1ffe3a62de107c2477e786498890..72c5d221f4698221613c7bfce97f56d580d767cf 100644 --- a/main.cpp +++ b/multiscreen-compositor/main.cpp @@ -50,13 +50,8 @@ #include <QtCore/QUrl> #include <QtCore/QDebug> - #include <QtGui/QGuiApplication> - #include <QtQml/QQmlApplicationEngine> - -#include <server.h> - #include <QDebug> #include <QCommandLineParser> #include <QCommandLineOption> @@ -64,8 +59,10 @@ #include <QRegularExpressionMatch> #include <QFile> #include <QQmlContext> + #include "config.h" -#include "compositorcommands.h" +#include <message-server.h> +#include "compositor-messages.h" static QRegularExpression findRotation("[0-3]"); @@ -128,17 +125,17 @@ int main(int argc, char *argv[]) else config.setRotation(readRotation("/sys/class/graphics/fbcon/rotate")); - Server server; + MessageServer server; if ( ! server.listen()) { - qDebug() << "Failed to setup the server"; + qWarning() << "Failed to setup the message server"; return -1; } - CompositorCommands commands; + + CompositorMessages commands; QObject::connect(&server, SIGNAL(newMessage(QString,quint32,quint32)), &commands, SLOT(messageReceived(QString,quint32,quint32))); - QQmlApplicationEngine appEngine; appEngine.rootContext()->setContextProperty("config", &config); appEngine.rootContext()->setContextProperty("commands", &commands); diff --git a/server.cpp b/multiscreen-compositor/message-server.cpp similarity index 54% rename from server.cpp rename to multiscreen-compositor/message-server.cpp index 6250cd640b4d10861b70a57a0e258ee8d9f82ea1..edf593559505acd8fa409c4b41d33ae1d1d6894d 100644 --- a/server.cpp +++ b/multiscreen-compositor/message-server.cpp @@ -3,17 +3,17 @@ #include <QList> #include <QAbstractSocket> -#include "server.h" +#include "message-server.h" #include <QDebug> -const QString Server::socketName = "serversocket"; +const QString MessageServer::socketName = "serversocket"; -Server::Server(QObject *parent) +MessageServer::MessageServer(QObject *parent) : QObject{parent} { } -bool Server::listen() { +bool MessageServer::listen() { server = new QLocalServer(this); while(true) @@ -31,36 +31,36 @@ bool Server::listen() { } qDebug() << "Setup socket at" << server->fullServerName(); - connect(server, &QLocalServer::newConnection, this, &Server::handleConnection); + connect(server, &QLocalServer::newConnection, this, &MessageServer::handleConnection); return true; } -bool Server::deleteSocket(void){ +bool MessageServer::deleteSocket(void){ return QFile::remove(QString("/tmp/") + socketName ); } -void Server::destroy(){ +void MessageServer::destroy(){ delete server; } -void Server::handleConnection() +void MessageServer::handleConnection() { qDebug() << "Got new connection"; - ServerConnection *c = new ServerConnection(server->nextPendingConnection(), this); - connect(c, &ServerConnection::disconnected, this, &Server::connectionGone); - connect(c, &ServerConnection::newMessage, this, &Server::messageReceived); + MessageServerConnection *c = new MessageServerConnection(server->nextPendingConnection(), this); + connect(c, &MessageServerConnection::disconnected, this, &MessageServer::connectionGone); + connect(c, &MessageServerConnection::newMessage, this, &MessageServer::messageReceived); connections.append(c); } -void Server::connectionGone(ServerConnection* c){ +void MessageServer::connectionGone(MessageServerConnection* c){ qDebug() << "Connection disconnected"; connections.removeAll(c); delete c; } -void Server::messageReceived(QString m, quint32 value0, quint32 value1) +void MessageServer::messageReceived(QString m, quint32 value0, quint32 value1) { qDebug() << "Got message" << m << value0 << value1; emit newMessage(m , value0, value1); diff --git a/server.h b/multiscreen-compositor/message-server.h similarity index 55% rename from server.h rename to multiscreen-compositor/message-server.h index 46575d12d5f5b1a37bf6f40d5f54cf088b6b4751..f85d0db271b9ff0b4ce121ef33c7ea36bf10fa5a 100644 --- a/server.h +++ b/multiscreen-compositor/message-server.h @@ -1,15 +1,14 @@ -#ifndef SERVER_H -#define SERVER_H - -#include "serverconnection.h" +#ifndef MESSAGEGSERVER_H +#define MESSAGEGSERVER_H #include <QLocalServer> +#include "message-serverconnection.h" -class Server : public QObject +class MessageServer : public QObject { Q_OBJECT public: - explicit Server(QObject *parent = nullptr); + explicit MessageServer(QObject *parent = nullptr); bool listen(); @@ -21,15 +20,15 @@ signals: private slots: void handleConnection(void); - void connectionGone(ServerConnection *c); + void connectionGone(MessageServerConnection *c); void messageReceived(QString, quint32, quint32); private: static const QString socketName; QLocalServer *server; - QList<ServerConnection*> connections; + QList<MessageServerConnection*> connections; bool deleteSocket(); }; -#endif // SERVER_H +#endif // MSG-SERVER_H diff --git a/serverconnection.cpp b/multiscreen-compositor/message-serverconnection.cpp similarity index 79% rename from serverconnection.cpp rename to multiscreen-compositor/message-serverconnection.cpp index 9ecfb959fa3140e7293d5990c869617c33f37966..2b6284dab4819cecd8fd50d2eca0ac125c0c2dca 100644 --- a/serverconnection.cpp +++ b/multiscreen-compositor/message-serverconnection.cpp @@ -1,21 +1,21 @@ -#include "serverconnection.h" +#include "message-serverconnection.h" -ServerConnection::ServerConnection(QLocalSocket *socket, QObject *parent) +MessageServerConnection::MessageServerConnection(QLocalSocket *socket, QObject *parent) : QObject{parent} { this->socket = socket; - connect(socket, &QLocalSocket::disconnected, this, &ServerConnection::disconnect); + connect(socket, &QLocalSocket::disconnected, this, &MessageServerConnection::disconnect); - connect(socket, &QLocalSocket::readyRead, this, &ServerConnection::readData); - connect(socket, &QLocalSocket::errorOccurred, this, &ServerConnection::socketError); + connect(socket, &QLocalSocket::readyRead, this, &MessageServerConnection::readData); + connect(socket, &QLocalSocket::errorOccurred, this, &MessageServerConnection::socketError); socketReadData.setDevice(socket); socketReadData.setVersion(QDataStream::Qt_5_10); } -bool ServerConnection::searchHeader(QDataStream *stream){ +bool MessageServerConnection::searchHeader(QDataStream *stream){ // The message needs to begin with a magic int headerstate = 0; char header[4] = { (char)0xDE, (char)0xAD, (char)0xBE, (char)0xEF }; @@ -33,7 +33,7 @@ bool ServerConnection::searchHeader(QDataStream *stream){ return true; } -void ServerConnection::readData(void){ +void MessageServerConnection::readData(void){ QString message; quint32 value0; quint32 value1; @@ -64,7 +64,7 @@ void ServerConnection::readData(void){ } } -void ServerConnection::sendStatus(int status) +void MessageServerConnection::sendStatus(int status) { QByteArray data; QDataStream out(&data, QIODevice::WriteOnly); @@ -81,14 +81,14 @@ void ServerConnection::sendStatus(int status) socket->flush(); } -void ServerConnection::disconnect(void){ +void MessageServerConnection::disconnect(void){ qDebug() << "Socket disconnected"; socket->deleteLater(); emit disconnected(this); } -void ServerConnection::socketError(QLocalSocket::LocalSocketError error){ +void MessageServerConnection::socketError(QLocalSocket::LocalSocketError error){ switch (error) { case QLocalSocket::ServerNotFoundError: qWarning() << "The host was not found. Please make sure " diff --git a/serverconnection.h b/multiscreen-compositor/message-serverconnection.h similarity index 64% rename from serverconnection.h rename to multiscreen-compositor/message-serverconnection.h index 8628bdff9e1709fa223445af3fbe1a830ef042af..f628965154b41e59e732ece4eec934c7c856202d 100644 --- a/serverconnection.h +++ b/multiscreen-compositor/message-serverconnection.h @@ -1,18 +1,18 @@ -#ifndef SERVERCONNECTION_H -#define SERVERCONNECTION_H +#ifndef MESSAGESERVERCONNECTION_H +#define MESSAGESERVERCONNECTION_H #include <QDataStream> #include <QLocalSocket> #include <QObject> -class ServerConnection : public QObject +class MessageServerConnection : public QObject { Q_OBJECT public: - explicit ServerConnection( QLocalSocket *socket, QObject *parent = nullptr); + explicit MessageServerConnection( QLocalSocket *socket, QObject *parent = nullptr); signals: - void disconnected(ServerConnection*); + void disconnected(MessageServerConnection*); void newMessage(QString, quint32 value0, quint32 value2); private slots: diff --git a/multiscreen-compositor/multiscreen-compositor.pro b/multiscreen-compositor/multiscreen-compositor.pro new file mode 100644 index 0000000000000000000000000000000000000000..bf35ffda2e383f6d382f76d7b6d65f1e39c773df --- /dev/null +++ b/multiscreen-compositor/multiscreen-compositor.pro @@ -0,0 +1,29 @@ +QT += gui qml + +SOURCES += \ + compositor-messages.cpp \ + main.cpp \ + config.cpp \ + message-server.cpp \ + message-serverconnection.cpp + +HEADERS += \ + compositor-messages.h \ + config.h \ \ + message-server.h \ + message-serverconnection.h + +OTHER_FILES = \ + qml/main.qml \ + +RESOURCES += multiscreen-compositor.qrc + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /usr/bin +!isEmpty(target.path): INSTALLS += target + +DISTFILES += \ + qml/Screen.qml \ + qml/Chrome.qml \ + qml/IviChrome.qml diff --git a/multi-screen.qrc b/multiscreen-compositor/multiscreen-compositor.qrc similarity index 100% rename from multi-screen.qrc rename to multiscreen-compositor/multiscreen-compositor.qrc diff --git a/qml/Chrome.qml b/multiscreen-compositor/qml/Chrome.qml similarity index 100% rename from qml/Chrome.qml rename to multiscreen-compositor/qml/Chrome.qml diff --git a/qml/IviChrome.qml b/multiscreen-compositor/qml/IviChrome.qml similarity index 100% rename from qml/IviChrome.qml rename to multiscreen-compositor/qml/IviChrome.qml diff --git a/qml/Screen.qml b/multiscreen-compositor/qml/Screen.qml similarity index 100% rename from qml/Screen.qml rename to multiscreen-compositor/qml/Screen.qml diff --git a/qml/main.qml b/multiscreen-compositor/qml/main.qml similarity index 98% rename from qml/main.qml rename to multiscreen-compositor/qml/main.qml index ac06ea6d7fa7966e27a1d8b8a0e8d8daf2b62a31..e7be840ace06ace89d11b57b456e98149b10b41c 100644 --- a/qml/main.qml +++ b/multiscreen-compositor/qml/main.qml @@ -194,7 +194,7 @@ WaylandCompositor { } // ============================================= - // Handle the signals emmitted by the extarnal + // Handle the signals emmitted by the external // compositor commands class // ============================================= Connections { @@ -222,12 +222,12 @@ WaylandCompositor { surface.visible = show } - function onHideWindow( windowid){ + function onHideWindow(windowid){ console.log("Received a hideWindow Signal", windowid) windowVisibility(windowid, false) } - function onShowWindow( windowid){ + function onShowWindow(windowid){ console.log("Received a showWindow Signal", windowid) windowVisibility(windowid, true) }