File indexing completed on 2024-03-24 17:02:24
0001 /* 0002 SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "PlasmaRecordMe.h" 0008 #include <QCoreApplication> 0009 #include <QDir> 0010 #include <QGuiApplication> 0011 #include <QLoggingCategory> 0012 #include <QProcess> 0013 #include <QQmlApplicationEngine> 0014 #include <QQmlContext> 0015 #include <QQuickItem> 0016 #include <QQuickView> 0017 #include <QRegularExpression> 0018 #include <QScreen> 0019 #include <QThread> 0020 #include <QTimer> 0021 0022 #include <KWayland/Client/event_queue.h> 0023 #include <KWayland/Client/connection_thread.h> 0024 #include <KWayland/Client/output.h> 0025 #include <KWayland/Client/xdgoutput.h> 0026 #include <KWayland/Client/registry.h> 0027 #include <KWayland/Client/plasmawindowmanagement.h> 0028 0029 using namespace KWayland::Client; 0030 0031 PlasmaRecordMe::PlasmaRecordMe(Screencasting::CursorMode cursorMode, const QString &source, QObject *parent) 0032 : QObject(parent) 0033 , m_cursorMode(cursorMode) 0034 , m_durationTimer(new QTimer(this)) 0035 , m_sourceName(source) 0036 , m_engine(new QQmlApplicationEngine(this)) 0037 { 0038 m_engine->setInitialProperties({ 0039 { QStringLiteral("app"), QVariant::fromValue<QObject *>(this) }, 0040 }); 0041 m_engine->load(QUrl(QStringLiteral("qrc:/main.qml"))); 0042 0043 auto connection = ConnectionThread::fromApplication(this); 0044 if (!connection) { 0045 qWarning() << "Failed getting Wayland connection from QPA"; 0046 QCoreApplication::exit(1); 0047 return; 0048 } 0049 0050 m_durationTimer->setSingleShot(true); 0051 auto registry = new Registry(qApp); 0052 connect(registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, this, [this, registry] (quint32 name, quint32 version) { 0053 m_management = registry->createPlasmaWindowManagement(name, version, this); 0054 auto addWindow = [this] (KWayland::Client::PlasmaWindow *window) { 0055 const QRegularExpression rx(m_sourceName); 0056 const auto match = rx.match(window->appId()); 0057 if (match.hasMatch()) { 0058 auto f = [this, window] { 0059 start(m_screencasting->createWindowStream(window, m_cursorMode)); 0060 }; 0061 qDebug() << "window" << window << window->uuid() << m_sourceName << m_screencasting; 0062 if (m_screencasting) 0063 f(); 0064 else 0065 m_delayed << f; 0066 } 0067 }; 0068 for (auto w : m_management->windows()) 0069 addWindow(w); 0070 connect(m_management, &KWayland::Client::PlasmaWindowManagement::windowCreated, this, addWindow); 0071 }); 0072 0073 connect(registry, &KWayland::Client::Registry::outputAnnounced, this, [this, registry] (quint32 name, quint32 version) { 0074 auto output = new KWayland::Client::Output(this); 0075 output->setup(registry->bindOutput(name, version)); 0076 0077 connect(output, &Output::changed, this, [this, output] { 0078 const QRegularExpression rx(m_sourceName); 0079 const auto match = rx.match(output->model()); 0080 if (match.hasMatch()) { 0081 auto f = [this, output] { 0082 start(m_screencasting->createOutputStream(output, m_cursorMode)); 0083 }; 0084 connect(this, &PlasmaRecordMe::cursorModeChanged, output, f); 0085 if (m_screencasting) 0086 f(); 0087 else 0088 m_delayed << f; 0089 } 0090 }); 0091 }); 0092 0093 if (m_sourceName.isEmpty() || m_sourceName == QLatin1String("region")) { 0094 connect(this, &PlasmaRecordMe::workspaceChanged, this, [this] { 0095 delete m_workspaceStream; 0096 m_workspaceStream = m_screencasting->createRegionStream(m_workspace, 1, m_cursorMode); 0097 start(m_workspaceStream); 0098 }); 0099 } 0100 0101 registry->create(connection); 0102 registry->setup(); 0103 0104 m_screencasting = new Screencasting(this); 0105 0106 bool ok = false; 0107 auto node = m_sourceName.toInt(&ok); 0108 if (ok) { 0109 const auto roots = m_engine->rootObjects(); 0110 for (auto root : roots) { 0111 auto mo = root->metaObject(); 0112 mo->invokeMethod(root, 0113 "addStream", 0114 Q_ARG(QVariant, QVariant::fromValue<int>(node)), 0115 Q_ARG(QVariant, QStringLiteral("raw node %1").arg(node)), 0116 Q_ARG(QVariant, 0)); 0117 } 0118 } 0119 0120 for (auto screen : qGuiApp->screens()) { 0121 m_workspace |= screen->geometry(); 0122 } 0123 Q_EMIT workspaceChanged(); 0124 } 0125 0126 PlasmaRecordMe::~PlasmaRecordMe() 0127 { 0128 } 0129 0130 void PlasmaRecordMe::start(ScreencastingStream *stream) 0131 { 0132 qDebug() << "start" << stream; 0133 connect(stream, &ScreencastingStream::failed, this, [this] (const QString &error) { 0134 qWarning() << "stream failed" << error;const auto roots = m_engine->rootObjects(); 0135 for (auto root : roots) { 0136 auto mo = root->metaObject(); 0137 mo->invokeMethod(root, "showPassiveNotification", Qt::QueuedConnection, Q_ARG(QVariant, QVariant(error)) 0138 , Q_ARG(QVariant, {}) 0139 , Q_ARG(QVariant, {}) 0140 , Q_ARG(QVariant, {}) 0141 ); 0142 } 0143 }); 0144 connect(stream, &ScreencastingStream::closed, this, [this, stream] { 0145 auto nodeId = stream->property("nodeid").toInt(); 0146 qDebug() << "bye bye" << stream << nodeId; 0147 0148 const auto roots = m_engine->rootObjects(); 0149 for (auto root : roots) { 0150 auto mo = root->metaObject(); 0151 mo->invokeMethod(root, "removeStream", Qt::QueuedConnection, Q_ARG(QVariant, QVariant::fromValue<quint32>(nodeId))); 0152 } 0153 }); 0154 connect(stream, &ScreencastingStream::created, this, [this, stream] (quint32 nodeId) 0155 { 0156 stream->setProperty("nodeid", nodeId); 0157 qDebug() << "starting..." << nodeId; 0158 const auto roots = m_engine->rootObjects(); 0159 for (auto root : roots) { 0160 auto mo = root->metaObject(); 0161 mo->invokeMethod(root, 0162 "addStream", 0163 Q_ARG(QVariant, QVariant::fromValue<quint32>(nodeId)), 0164 Q_ARG(QVariant, stream->objectName()), 0165 Q_ARG(QVariant, 0)); 0166 } 0167 } 0168 ); 0169 connect(this, &PlasmaRecordMe::cursorModeChanged, stream, &ScreencastingStream::closed); 0170 } 0171 0172 void PlasmaRecordMe::setDuration(int duration) 0173 { 0174 m_durationTimer->setInterval(duration); 0175 } 0176 0177 void PlasmaRecordMe::createVirtualMonitor() 0178 { 0179 m_screencasting->createVirtualMonitorStream(QStringLiteral("recordme"), {1920, 1080}, 1, m_cursorMode); 0180 }