From 97f209559c00acc1ea6d0736bb318ac0254a3e37 Mon Sep 17 00:00:00 2001 From: Noah Davis Date: Wed, 4 Jun 2025 16:06:06 -0400 Subject: [PATCH 1/2] Say which shortcut can stop recording in recording notification It will say Meta+R by default, but will show the shortcut used to initiate the recording instead if Meta+R isn't assigned to region recording. BUG: 505081 --- src/Platforms/VideoPlatform.cpp | 16 +++++++++++++++ src/Platforms/VideoPlatform.h | 4 ++++ src/Platforms/VideoPlatformWayland.cpp | 6 ++++-- src/SpectacleCore.cpp | 28 +++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/Platforms/VideoPlatform.cpp b/src/Platforms/VideoPlatform.cpp index 592539048..333692326 100644 --- a/src/Platforms/VideoPlatform.cpp +++ b/src/Platforms/VideoPlatform.cpp @@ -69,6 +69,11 @@ VideoPlatform::RecordingState VideoPlatform::recordingState() const return m_recordingState; } +VideoPlatform::RecordingMode VideoPlatform::recordingMode() const +{ + return m_recordingMode; +} + void VideoPlatform::setRecordingState(RecordingState state) { if (state == m_recordingState) { @@ -91,9 +96,20 @@ void VideoPlatform::setRecordingState(RecordingState state) m_elapsedTimer.invalidate(); m_basicTimer.stop(); } + if (state != RecordingState::Recording) { + setRecordingMode(NoRecordingModes); + } m_recordingState = state; Q_EMIT recordingStateChanged(state); Q_EMIT recordedTimeChanged(); } +void VideoPlatform::setRecordingMode(RecordingMode mode) +{ + if (m_recordingMode == mode) { + return; + } + m_recordingMode = mode; +} + #include "moc_VideoPlatform.cpp" diff --git a/src/Platforms/VideoPlatform.h b/src/Platforms/VideoPlatform.h index 4f5fba720..eea81e32a 100644 --- a/src/Platforms/VideoPlatform.h +++ b/src/Platforms/VideoPlatform.h @@ -129,8 +129,11 @@ public: RecordingState recordingState() const; + RecordingMode recordingMode() const; + protected: void setRecordingState(RecordingState state); + void setRecordingMode(RecordingMode mode); void timerEvent(QTimerEvent *event) override; public Q_SLOTS: @@ -157,6 +160,7 @@ private: QBasicTimer m_basicTimer; qint64 m_recordedTime = 0; RecordingState m_recordingState = RecordingState::NotRecording; + RecordingMode m_recordingMode = RecordingMode::NoRecordingModes; }; Q_DECLARE_OPERATORS_FOR_FLAGS(VideoPlatform::RecordingModes) diff --git a/src/Platforms/VideoPlatformWayland.cpp b/src/Platforms/VideoPlatformWayland.cpp index 648f8adbf..984ede0eb 100644 --- a/src/Platforms/VideoPlatformWayland.cpp +++ b/src/Platforms/VideoPlatformWayland.cpp @@ -245,11 +245,12 @@ void VideoPlatformWayland::startRecording(const QUrl &fileUrl, RecordingMode rec m_recorder->setNodeId(0); Q_ASSERT(stream); - connect(stream, &ScreencastingStream::created, this, [this, stream] { + connect(stream, &ScreencastingStream::created, this, [this, stream, recordingMode] { m_recorder->setNodeId(stream->nodeId()); if (!m_recorder->output().isEmpty()) { m_recorder->start(); } + setRecordingMode(recordingMode); setRecordingState(VideoPlatform::RecordingState::Recording); }); connect(stream, &ScreencastingStream::failed, this, [this](const QString &error) { @@ -302,7 +303,7 @@ void VideoPlatformWayland::startRecording(const QUrl &fileUrl, RecordingMode rec m_recorder->start(); } - connect(m_recorder.get(), &PipeWireRecord::stateChanged, this, [this] { + connect(m_recorder.get(), &PipeWireRecord::stateChanged, this, [this, recordingMode] { if (m_recorder->state() == PipeWireRecord::Idle) { m_memoryTimer.stop(); if (recordingState() != RecordingState::NotRecording && recordingState() != RecordingState::Finished) { @@ -311,6 +312,7 @@ void VideoPlatformWayland::startRecording(const QUrl &fileUrl, RecordingMode rec } } else if (m_recorder->state() == PipeWireRecord::Recording) { m_memoryTimer.start(5000, Qt::CoarseTimer, this); + setRecordingMode(recordingMode); setRecordingState(VideoPlatform::RecordingState::Recording); } else if (m_recorder->state() == PipeWireRecord::Rendering) { m_memoryTimer.stop(); diff --git a/src/SpectacleCore.cpp b/src/SpectacleCore.cpp index 8033751c9..aa2e8c6e1 100644 --- a/src/SpectacleCore.cpp +++ b/src/SpectacleCore.cpp @@ -281,7 +281,33 @@ SpectacleCore::SpectacleCore(QObject *parent) SpectacleCore::instance()->finishRecording(); }); const auto messageTitle = i18nc("recording notification title", "Spectacle is Recording"); - const auto messageBody = i18nc("recording notification message", "Click the system tray icon to finish recording"); + auto getSimpleDefaultShortcut = [] { + const auto shortcuts = KGlobalAccel::self()->shortcut(ShortcutActions::self()->recordRegionAction()); + if (shortcuts.contains(QKeySequence{Qt::META | Qt::Key_R})) { + return QKeySequence{Qt::META | Qt::Key_R}; + } + return QKeySequence{}; + }; + auto getShortcut = [](const auto &list) { + auto it = std::find_if(list.cbegin(), list.cend(), [](const QKeySequence &shortcut) { + return !shortcut.isEmpty(); + }); + return it != list.cend() ? *it : QKeySequence{}; + }; + QKeySequence stopShortcut = getSimpleDefaultShortcut(); + if (stopShortcut.isEmpty()) { + auto mode = m_videoPlatform->recordingMode(); + if (mode == VideoPlatform::Screen) { + stopShortcut = getShortcut(KGlobalAccel::self()->shortcut(ShortcutActions::self()->recordScreenAction())); + } else if (mode == VideoPlatform::Window) { + stopShortcut = getShortcut(KGlobalAccel::self()->shortcut(ShortcutActions::self()->recordWindowAction())); + } else if (mode == VideoPlatform::Region) { + stopShortcut = getShortcut(KGlobalAccel::self()->shortcut(ShortcutActions::self()->recordRegionAction())); + } + } + const auto messageBody = stopShortcut.isEmpty() + ? i18nc("recording notification message without shortcut", "To finish the recording, click the pulsing red System Tray icon.") + : xi18nc("recording notification message with shortcut", "To finish the recording, click the pulsing red System Tray icon or press %1.", stopShortcut.toString(QKeySequence::NativeText)); auto notification = new KNotification(u"notification"_s, KNotification::CloseOnTimeout | KNotification::DefaultEvent, this); notification->setTitle(messageTitle); notification->setText(messageBody); -- GitLab From 7fd2fe158408b6285f9855f7fcf34e77d4ecb764 Mon Sep 17 00:00:00 2001 From: Noah Davis Date: Thu, 12 Jun 2025 16:12:48 -0400 Subject: [PATCH 2/2] Rename shortcuts to show that they can start or stop recording BUG: 505081 --- desktop/org.kde.spectacle.desktop.cmake | 6 +++--- src/ShortcutActions.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/desktop/org.kde.spectacle.desktop.cmake b/desktop/org.kde.spectacle.desktop.cmake index 4e36b18e6..800fcb62b 100644 --- a/desktop/org.kde.spectacle.desktop.cmake +++ b/desktop/org.kde.spectacle.desktop.cmake @@ -474,7 +474,7 @@ Exec=${KDE_INSTALL_FULL_BINDIR}/spectacle -u X-KDE-Shortcuts=Meta+Ctrl+Print [Desktop Action RecordRegion] -Name=Record Rectangular Region +Name=Start/Stop Region Recording Name[ar]=يسجل منطقة مستطيلة Name[az]=Düzbucaqlı sahəni yazmaq Name[bg]=Заснемане на правоъгълен регион @@ -522,7 +522,7 @@ Exec=${KDE_INSTALL_FULL_BINDIR}/spectacle -R region X-KDE-Shortcuts=Meta+Shift+R,Meta+R [Desktop Action RecordScreen] -Name=Record Screen +Name=Start/Stop Screen Recording Name[ar]=سجّل الشاشة Name[az]=Ekranı yazmaq Name[bg]=Запис на екрана @@ -570,7 +570,7 @@ Exec=${KDE_INSTALL_FULL_BINDIR}/spectacle -R screen X-KDE-Shortcuts=Meta+Alt+R [Desktop Action RecordWindow] -Name=Record Window +Name=Start/Stop Window Recording Name[ar]=سجل النافذة Name[az]=Pəncərəni yazmaq Name[bg]=Запис на прозорец diff --git a/src/ShortcutActions.cpp b/src/ShortcutActions.cpp index ee73bcfe5..a1464d06d 100644 --- a/src/ShortcutActions.cpp +++ b/src/ShortcutActions.cpp @@ -73,19 +73,19 @@ ShortcutActions::ShortcutActions() mActions.addAction(action->objectName(), action); } { - QAction *action = new QAction(i18nc("@action global shortcut", "Record Screen"), &mActions); + QAction *action = new QAction(i18nc("@action global shortcut", "Start/Stop Screen Recording"), &mActions); action->setObjectName(u"RecordScreen"_s); action->setProperty("isConfigurationAction", true); mActions.addAction(action->objectName(), action); } { - QAction *action = new QAction(i18nc("@action global shortcut", "Record Window"), &mActions); + QAction *action = new QAction(i18nc("@action global shortcut", "Start/Stop Window Recording"), &mActions); action->setObjectName(u"RecordWindow"_s); action->setProperty("isConfigurationAction", true); mActions.addAction(action->objectName(), action); } { - QAction *action = new QAction(i18nc("@action global shortcut", "Record Rectangular Region"), &mActions); + QAction *action = new QAction(i18nc("@action global shortcut", "Start/Stop Region Recording"), &mActions); action->setObjectName(u"RecordRegion"_s); action->setProperty("isConfigurationAction", true); mActions.addAction(action->objectName(), action); -- GitLab