mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
quicksettings/record: Make it more efficient on initial load
Try to reduce the amount of preloaded objects that aren't needed until the quick setting is toggled. Also port the the kpipewire interaction parts to C++.
This commit is contained in:
parent
92a1cfc740
commit
e4919690b4
5 changed files with 205 additions and 57 deletions
|
|
@ -81,6 +81,7 @@ find_package(PlasmaQuick CONFIG REQUIRED)
|
|||
find_package(PlasmaActivities CONFIG REQUIRED)
|
||||
find_package(KF6Screen CONFIG REQUIRED)
|
||||
find_package(KWayland CONFIG REQUIRED)
|
||||
find_package(KPipeWire ${PROJECT_DEP_VERSION} REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ target_link_libraries(recordplugin PRIVATE
|
|||
KF6::ConfigGui
|
||||
KF6::I18n
|
||||
KF6::Notifications
|
||||
K::KPipeWire
|
||||
K::KPipeWireRecord
|
||||
)
|
||||
|
||||
ecm_finalize_qml_module(recordplugin)
|
||||
|
|
|
|||
|
|
@ -1,65 +1,49 @@
|
|||
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||
// SPDX-FileCopyrightText: 2022-2025 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Window
|
||||
|
||||
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
||||
import org.kde.pipewire.record 0.1 as PWRec
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
import org.kde.taskmanager as TaskManager
|
||||
import org.kde.plasma.quicksetting.record
|
||||
import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
|
||||
|
||||
QS.QuickSetting {
|
||||
id: root
|
||||
text: switch (record.state) {
|
||||
case PWRec.PipeWireRecord.Idle:
|
||||
return i18n("Record Screen")
|
||||
case PWRec.PipeWireRecord.Recording:
|
||||
return i18n("Recording…")
|
||||
case PWRec.PipeWireRecord.Rendering:
|
||||
i18n("Writing…")
|
||||
}
|
||||
status: switch(record.state) {
|
||||
case PWRec.PipeWireRecord.Idle:
|
||||
return i18n("Tap to start recording")
|
||||
case PWRec.PipeWireRecord.Recording:
|
||||
return i18n("Screen is being captured…")
|
||||
case PWRec.PipeWireRecord.Rendering:
|
||||
i18n("Please wait…")
|
||||
}
|
||||
|
||||
text: RecordUtil.quickSettingText
|
||||
status: RecordUtil.quickSettingStatus
|
||||
icon: "camera-video-symbolic"
|
||||
enabled: false
|
||||
available: record.encoder != PWRec.PipeWireRecord.NoEncoder
|
||||
enabled: RecordUtil.isRecording
|
||||
available: true
|
||||
|
||||
function toggle() {
|
||||
if (!record.active) {
|
||||
// See this https://invent.kde.org/plasma/kpipewire/-/blob/eb21912e7e0ce5a70c6f906c6e5a20f56cc6783e/src/pipewirerecord.cpp#L82
|
||||
switch (record.encoder) {
|
||||
case PWRec.PipeWireRecord.H264Main:
|
||||
case PWRec.PipeWireRecord.H264Baseline:
|
||||
record.output = RecordUtil.videoLocation("screen-recording.mp4");
|
||||
break;
|
||||
case PWRec.PipeWireRecord.VP8:
|
||||
case PWRec.PipeWireRecord.VP9:
|
||||
record.output = RecordUtil.videoLocation("screen-recording.webm");
|
||||
break;
|
||||
}
|
||||
if (RecordUtil.isRecording) {
|
||||
RecordUtil.stopRecording();
|
||||
waylandItem.outputName = '';
|
||||
} else {
|
||||
RecordUtil.showNotification(i18n("New Screen Recording"), i18n("New Screen Recording saved in %1", record.output), record.output);
|
||||
// Start recording only when waylandItem's nodeId updates
|
||||
waylandItem.startRecordingRequest = true;
|
||||
waylandItem.outputName = Screen.name;
|
||||
}
|
||||
|
||||
enabled = !enabled
|
||||
MobileShellState.ShellDBusClient.closeActionDrawer();
|
||||
}
|
||||
|
||||
PWRec.PipeWireRecord {
|
||||
id: record
|
||||
nodeId: waylandItem.nodeId
|
||||
active: root.enabled
|
||||
}
|
||||
TaskManager.ScreencastingRequest {
|
||||
id: waylandItem
|
||||
outputName: root.enabled ? Screen.name : ""
|
||||
property bool startRecordingRequest: false
|
||||
|
||||
onNodeIdChanged: {
|
||||
if (startRecordingRequest) {
|
||||
let status = RecordUtil.startRecording(waylandItem.nodeId);
|
||||
if (status) {
|
||||
MobileShellState.ShellDBusClient.closeActionDrawer();
|
||||
} else {
|
||||
waylandItem.outputName = '';
|
||||
}
|
||||
|
||||
startRecordingRequest = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 by Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
// SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
// SPDX-FileCopyrightText: 2022-2025 by Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "recordutil.h"
|
||||
|
||||
|
|
@ -11,6 +9,7 @@
|
|||
#include <QStandardPaths>
|
||||
|
||||
#include <KFileUtils>
|
||||
#include <KLocalizedString>
|
||||
#include <KNotification>
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
|
@ -18,6 +17,80 @@ using namespace Qt::StringLiterals;
|
|||
RecordUtil::RecordUtil(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
updateQuickSettingText();
|
||||
updateQuickSettingStatus();
|
||||
}
|
||||
|
||||
bool RecordUtil::startRecording(int nodeId)
|
||||
{
|
||||
if (!m_pipeWireRecord) {
|
||||
createPipeWireRecord();
|
||||
}
|
||||
|
||||
if (m_pipeWireRecord->isActive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (m_pipeWireRecord->encoder()) {
|
||||
case PipeWireRecord::H264Main:
|
||||
case PipeWireRecord::H264Baseline:
|
||||
m_pipeWireRecord->setOutput(videoLocation("screen-recording.mp4"));
|
||||
break;
|
||||
case PipeWireRecord::VP8:
|
||||
case PipeWireRecord::VP9:
|
||||
m_pipeWireRecord->setOutput(videoLocation("screen-recording.webm"));
|
||||
break;
|
||||
case PipeWireRecord::WebP:
|
||||
m_pipeWireRecord->setOutput(videoLocation("screen-recording.webp"));
|
||||
break;
|
||||
case PipeWireRecord::Gif:
|
||||
m_pipeWireRecord->setOutput(videoLocation("screen-recording.gif"));
|
||||
break;
|
||||
case PipeWireRecord::NoEncoder:
|
||||
default:
|
||||
m_quickSettingStatus = i18n("No encoders available for recording");
|
||||
Q_EMIT quickSettingStatusChanged();
|
||||
qWarning() << "No video encoders available for screen recording!";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pipeWireRecord->setNodeId(nodeId);
|
||||
m_pipeWireRecord->start();
|
||||
|
||||
qDebug() << "Started recording screen with nodeId" << nodeId << "to file" << m_pipeWireRecord->output() << videoLocation("screen-recording.webm");
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordUtil::stopRecording()
|
||||
{
|
||||
if (!m_pipeWireRecord) {
|
||||
return;
|
||||
}
|
||||
if (!m_pipeWireRecord->isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_pipeWireRecord->stop();
|
||||
showNotification(i18n("New Screen Recording"), i18n("New Screen Recording saved in %1", m_pipeWireRecord->output()), m_pipeWireRecord->output());
|
||||
}
|
||||
|
||||
QString RecordUtil::quickSettingText() const
|
||||
{
|
||||
return m_quickSettingText;
|
||||
}
|
||||
|
||||
QString RecordUtil::quickSettingStatus() const
|
||||
{
|
||||
return m_quickSettingStatus;
|
||||
}
|
||||
|
||||
bool RecordUtil::isRecording() const
|
||||
{
|
||||
if (!m_pipeWireRecord) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_pipeWireRecord->isActive();
|
||||
}
|
||||
|
||||
QString RecordUtil::videoLocation(const QString &name)
|
||||
|
|
@ -42,3 +115,63 @@ void RecordUtil::showNotification(const QString &title, const QString &text, con
|
|||
notif->setText(text);
|
||||
notif->sendEvent();
|
||||
}
|
||||
|
||||
void RecordUtil::updateQuickSettingText()
|
||||
{
|
||||
QString defaultText = i18nc("@action:button", "Record Screen");
|
||||
if (!m_pipeWireRecord) {
|
||||
m_quickSettingText = defaultText;
|
||||
Q_EMIT quickSettingTextChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_pipeWireRecord->state()) {
|
||||
case PipeWireRecord::Recording:
|
||||
m_quickSettingText = i18nc("@info:status", "Recording…");
|
||||
break;
|
||||
case PipeWireRecord::Rendering:
|
||||
m_quickSettingText = i18nc("@info:status", "Writing…");
|
||||
break;
|
||||
case PipeWireRecord::Idle:
|
||||
default:
|
||||
m_quickSettingText = defaultText;
|
||||
break;
|
||||
}
|
||||
|
||||
Q_EMIT quickSettingTextChanged();
|
||||
}
|
||||
|
||||
void RecordUtil::updateQuickSettingStatus()
|
||||
{
|
||||
QString defaultText = i18n("Tap to start recording");
|
||||
|
||||
if (!m_pipeWireRecord) {
|
||||
m_quickSettingStatus = defaultText;
|
||||
Q_EMIT quickSettingStatusChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_pipeWireRecord->state()) {
|
||||
case PipeWireRecord::Recording:
|
||||
m_quickSettingStatus = i18n("Screen is being captured…");
|
||||
break;
|
||||
case PipeWireRecord::Rendering:
|
||||
m_quickSettingStatus = i18n("Please wait…");
|
||||
break;
|
||||
case PipeWireRecord::Idle:
|
||||
default:
|
||||
m_quickSettingStatus = defaultText;
|
||||
break;
|
||||
}
|
||||
|
||||
Q_EMIT quickSettingStatusChanged();
|
||||
}
|
||||
|
||||
void RecordUtil::createPipeWireRecord()
|
||||
{
|
||||
m_pipeWireRecord = new PipeWireRecord{this};
|
||||
|
||||
connect(m_pipeWireRecord, &PipeWireRecord::stateChanged, this, &RecordUtil::updateQuickSettingText);
|
||||
connect(m_pipeWireRecord, &PipeWireRecord::stateChanged, this, &RecordUtil::updateQuickSettingStatus);
|
||||
connect(m_pipeWireRecord, &PipeWireRecord::activeChanged, this, &RecordUtil::isRecordingChanged);
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 by Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
// SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
// SPDX-FileCopyrightText: 2022-2025 by Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
@ -10,15 +8,28 @@
|
|||
#include <QVariantMap>
|
||||
#include <qqmlregistration.h>
|
||||
|
||||
#include <PipeWireRecord>
|
||||
|
||||
class RecordUtil : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
Q_PROPERTY(QString quickSettingText READ quickSettingText NOTIFY quickSettingTextChanged)
|
||||
Q_PROPERTY(QString quickSettingStatus READ quickSettingStatus NOTIFY quickSettingStatusChanged)
|
||||
Q_PROPERTY(bool isRecording READ isRecording NOTIFY isRecordingChanged)
|
||||
|
||||
public:
|
||||
RecordUtil(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE bool startRecording(int nodeId);
|
||||
Q_INVOKABLE void stopRecording();
|
||||
|
||||
QString quickSettingText() const;
|
||||
QString quickSettingStatus() const;
|
||||
bool isRecording() const;
|
||||
|
||||
/**
|
||||
* Allows us to get a filename in the standard videos directory (~/Videos by default)
|
||||
* with a name that starts with @p name
|
||||
|
|
@ -28,7 +39,24 @@ public:
|
|||
* @see QStandardPaths::writableLocation()
|
||||
* @see KFileUtil::suggestName()
|
||||
*/
|
||||
Q_INVOKABLE QString videoLocation(const QString &name);
|
||||
QString videoLocation(const QString &name);
|
||||
|
||||
Q_INVOKABLE void showNotification(const QString &title, const QString &text, const QString &filePath);
|
||||
void showNotification(const QString &title, const QString &text, const QString &filePath);
|
||||
|
||||
Q_SIGNALS:
|
||||
void quickSettingTextChanged();
|
||||
void quickSettingStatusChanged();
|
||||
void isRecordingChanged();
|
||||
|
||||
private:
|
||||
void updateQuickSettingText();
|
||||
void updateQuickSettingStatus();
|
||||
|
||||
void createPipeWireRecord();
|
||||
|
||||
QString m_quickSettingText;
|
||||
QString m_quickSettingStatus;
|
||||
|
||||
// Only created when needed
|
||||
PipeWireRecord *m_pipeWireRecord{nullptr};
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue