Add kde patches

The nixpkgs patch is to clear out a conflict with a patch that's applied
to plasma-workspace by nixpkgs
This commit is contained in:
Toast 2025-07-04 22:31:07 +02:00
parent fd0f27145a
commit 98f9b3a8fc
23 changed files with 7818 additions and 0 deletions

View file

@ -97,6 +97,7 @@
name = "patched-nixpkgs-unstable";
src = nixpkgs-unstable-raw;
patches = [
./nixpkgs-patches/plasma-workspace-patch-trimming.patch
];
};
nixpkgs-patched = nixpkgs-raw.legacyPackages.x86_64-linux.applyPatches {

View file

@ -0,0 +1,65 @@
diff --git a/pkgs/kde/plasma/plasma-workspace/dependency-paths.patch b/pkgs/kde/plasma/plasma-workspace/dependency-paths.patch
index b4d46cd869bb..ca5bfd2c4889 100644
--- a/pkgs/kde/plasma/plasma-workspace/dependency-paths.patch
+++ b/pkgs/kde/plasma/plasma-workspace/dependency-paths.patch
@@ -1,13 +1,14 @@
diff --git a/applets/devicenotifier/plugin/deviceerrormonitor_p.cpp b/applets/devicenotifier/plugin/deviceerrormonitor_p.cpp
-index ba214a555d..421d940738 100644
+index 183f207946..0f64b068ab 100644
--- a/applets/devicenotifier/plugin/deviceerrormonitor_p.cpp
+++ b/applets/devicenotifier/plugin/deviceerrormonitor_p.cpp
-@@ -155,7 +155,7 @@ void DeviceErrorMonitor::queryBlockingApps(const QString &devicePath)
+@@ -168,7 +168,8 @@ void DeviceErrorMonitor::queryBlockingApps(const QString &devicePath)
Q_EMIT blockingAppsReady(blockApps);
p->deleteLater();
});
- p->start(QStringLiteral("lsof"), {QStringLiteral("-t"), devicePath});
+ p->start(QStringLiteral("@lsof@"), {QStringLiteral("-t"), devicePath});
++ // @dbusSend@
// p.start(QStringLiteral("fuser"), {QStringLiteral("-m"), devicePath});
}
@@ -51,7 +52,7 @@ index e4d1ad4311..d45bdfad98 100644
void CFcQuery::procExited()
diff --git a/kcms/krdb/krdb.cpp b/kcms/krdb/krdb.cpp
-index f3c9956921..09c818739d 100644
+index 53f77d0a18..680e81b6e4 100644
--- a/kcms/krdb/krdb.cpp
+++ b/kcms/krdb/krdb.cpp
@@ -425,7 +425,7 @@ void runRdb(unsigned int flags)
@@ -107,7 +108,7 @@ index 7218628ce9..9126475ea4 100644
+ExecStart=@qdbus@ org.kde.kcminit /kcminit org.kde.KCMInit.runPhase1
Slice=session.slice
diff --git a/startkde/startplasma.cpp b/startkde/startplasma.cpp
-index 4d31c6f408..17418b1ff7 100644
+index 02c3f260fb..795244064d 100644
--- a/startkde/startplasma.cpp
+++ b/startkde/startplasma.cpp
@@ -57,7 +57,7 @@ void sigtermHandler(int signalNumber)
@@ -119,7 +120,7 @@ index 4d31c6f408..17418b1ff7 100644
}
QStringList allServices(const QLatin1String &prefix)
-@@ -512,7 +512,7 @@ QProcess *setupKSplash()
+@@ -508,7 +508,7 @@ QProcess *setupKSplash()
if (ksplashCfg.readEntry("Engine", QStringLiteral("KSplashQML")) == QLatin1String("KSplashQML")) {
p = new QProcess;
p->setProcessChannelMode(QProcess::ForwardedChannels);
@@ -128,14 +129,4 @@ index 4d31c6f408..17418b1ff7 100644
}
}
return p;
-diff --git a/startkde/systemd/plasma-ksplash-ready.service.in b/startkde/systemd/plasma-ksplash-ready.service.in
-index 1e903130a9..0861c3d136 100644
---- a/startkde/systemd/plasma-ksplash-ready.service.in
-+++ b/startkde/systemd/plasma-ksplash-ready.service.in
-@@ -6,5 +6,5 @@ PartOf=graphical-session.target
-
- [Service]
- Type=oneshot
--ExecStart=dbus-send --session --reply-timeout=1 --type=method_call --dest=org.kde.KSplash /KSplash org.kde.KSplash.setStage string:ready
-+ExecStart=@dbusSend@ --session --reply-timeout=1 --type=method_call --dest=org.kde.KSplash /KSplash org.kde.KSplash.setStage string:ready
- Slice=session.slice
+

View file

@ -0,0 +1,2 @@
Plasma 6.5.0:
Pr 218 https://invent.kde.org/plasma/bluedevil/-/merge_requests/218

View file

@ -0,0 +1,53 @@
From ddbf7452c6f2fe8849de723175710dbf39242422 Mon Sep 17 00:00:00 2001
From: Nate Graham <nate@kde.org>
Date: Fri, 13 Jun 2025 11:55:47 -0600
Subject: [PATCH] applet: use standard section headers
We have them; might as well use them. This lets us get rid of a bunch of
complex and fragile code that's responsible for the existing separator.
---
.../contents/ui/FullRepresentation.qml | 27 +++----------------
1 file changed, 3 insertions(+), 24 deletions(-)
diff --git a/src/applet/package/contents/ui/FullRepresentation.qml b/src/applet/package/contents/ui/FullRepresentation.qml
index df989267d..27295de21 100644
--- a/src/applet/package/contents/ui/FullRepresentation.qml
+++ b/src/applet/package/contents/ui/FullRepresentation.qml
@@ -111,31 +111,10 @@ PlasmaExtras.Representation {
bottomMargin: Kirigami.Units.largeSpacing
section.property: "Section"
- // We want to hide the section delegate for the "Connected"
- // group because it's unnecessary; all we want to do here is
- // separate the connected devices from the available ones
- section.delegate: Loader {
+ section.delegate: PlasmaExtras.ListSectionHeader {
required property string section
-
- active: section !== "Connected" && BluezQt.Manager.connectedDevices.length > 0
-
- width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
- // Need to manually set the height or else the loader takes up
- // space after the first time it unloads a previously-loaded item
- height: active ? Kirigami.Units.gridUnit : 0
-
- // give us 2 frames to try and figure out a layout, this reduces jumpyness quite a bit but doesn't
- // entirely eliminate it https://bugs.kde.org/show_bug.cgi?id=438610
- Behavior on height { PropertyAnimation { duration: 32 } }
-
- sourceComponent: Item {
- KSvg.SvgItem {
- width: parent.width - Kirigami.Units.gridUnit * 2
- anchors.centerIn: parent
- imagePath: "widgets/line"
- elementId: "horizontal-line"
- }
- }
+ width: listView.width - listView.leftMargin - listView.rightMargin
+ text: section
}
highlight: PlasmaExtras.Highlight {}
highlightMoveDuration: Kirigami.Units.shortDuration
--
GitLab

View file

@ -0,0 +1,2 @@
Plasma 6.5.0:
Pr 545 https://invent.kde.org/plasma/breeze/-/merge_requests/545

View file

@ -0,0 +1,333 @@
From 38567c2f2d2d0f8524e42224dff53a929cbf086a Mon Sep 17 00:00:00 2001
From: Kai Uwe Broulik <kde@privat.broulik.de>
Date: Sat, 24 May 2025 09:33:44 +0200
Subject: [PATCH 1/3] kstyle/animations: Use QObject as base type rather than
QWidget
This prepares for the animation engine being used with Qt Quick Controls.
In most cases the type is cast to the relevant widget type for checking
anyway, so might as well use the cast object further down but not require
a QWidget at the beginning.
---
kstyle/animations/breezeanimations.cpp | 48 +++++++++++++-------------
kstyle/animations/breezeanimations.h | 4 +--
2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/kstyle/animations/breezeanimations.cpp b/kstyle/animations/breezeanimations.cpp
index 12e5107c5..ceab53802 100644
--- a/kstyle/animations/breezeanimations.cpp
+++ b/kstyle/animations/breezeanimations.cpp
@@ -82,7 +82,7 @@ void Animations::setupEngines()
}
//____________________________________________________________
-void Animations::registerWidget(QWidget *widget) const
+void Animations::registerWidget(QObject *widget) const
{
if (!widget) {
return;
@@ -101,37 +101,37 @@ void Animations::registerWidget(QWidget *widget) const
// for optimization, one should put with most used widgets here first
// buttons
- if (qobject_cast<QToolButton *>(widget)) {
- _toolButtonEngine->registerWidget(widget, AnimationHover | AnimationFocus);
- _widgetStateEngine->registerWidget(widget, AnimationHover | AnimationFocus);
+ if (auto toolButton = qobject_cast<QToolButton *>(widget)) {
+ _toolButtonEngine->registerWidget(toolButton, AnimationHover | AnimationFocus);
+ _widgetStateEngine->registerWidget(toolButton, AnimationHover | AnimationFocus);
} else if (qobject_cast<QCheckBox *>(widget) || qobject_cast<QRadioButton *>(widget)) {
_widgetStateEngine->registerWidget(widget, AnimationHover | AnimationFocus | AnimationPressed);
- } else if (qobject_cast<QAbstractButton *>(widget)) {
+ } else if (auto button = qobject_cast<QAbstractButton *>(widget)) {
// register to toolbox engine if needed
- if (qobject_cast<QToolBox *>(widget->parent())) {
- _toolBoxEngine->registerWidget(widget);
+ if (auto toolBox = qobject_cast<QToolBox *>(widget->parent())) {
+ _toolBoxEngine->registerWidget(toolBox);
}
- _widgetStateEngine->registerWidget(widget, AnimationHover | AnimationFocus);
+ _widgetStateEngine->registerWidget(button, AnimationHover | AnimationFocus);
}
// groupboxes
else if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget)) {
if (groupBox->isCheckable()) {
- _widgetStateEngine->registerWidget(widget, AnimationHover | AnimationFocus);
+ _widgetStateEngine->registerWidget(groupBox, AnimationHover | AnimationFocus);
}
}
// sliders
- else if (qobject_cast<QScrollBar *>(widget)) {
- _scrollBarEngine->registerWidget(widget, AnimationHover | AnimationFocus);
- } else if (qobject_cast<QSlider *>(widget)) {
- _widgetStateEngine->registerWidget(widget, AnimationHover | AnimationFocus);
- } else if (qobject_cast<QDial *>(widget)) {
- _dialEngine->registerWidget(widget, AnimationHover | AnimationFocus);
+ else if (auto scrollBar = qobject_cast<QScrollBar *>(widget)) {
+ _scrollBarEngine->registerWidget(scrollBar, AnimationHover | AnimationFocus);
+ } else if (auto slider = qobject_cast<QSlider *>(widget)) {
+ _widgetStateEngine->registerWidget(slider, AnimationHover | AnimationFocus);
+ } else if (auto dial = qobject_cast<QDial *>(widget)) {
+ _dialEngine->registerWidget(dial, AnimationHover | AnimationFocus);
}
// progress bar
@@ -162,24 +162,24 @@ void Animations::registerWidget(QWidget *widget) const
// header views
// need to come before abstract item view, otherwise is skipped
- else if (qobject_cast<QHeaderView *>(widget)) {
- _headerViewEngine->registerWidget(widget);
+ else if (auto headerView = qobject_cast<QHeaderView *>(widget)) {
+ _headerViewEngine->registerWidget(headerView);
}
// lists
- else if (qobject_cast<QAbstractItemView *>(widget)) {
- _inputWidgetEngine->registerWidget(widget, AnimationHover | AnimationFocus);
+ else if (auto itemView = qobject_cast<QAbstractItemView *>(widget)) {
+ _inputWidgetEngine->registerWidget(itemView, AnimationHover | AnimationFocus);
}
// tabbar
- else if (qobject_cast<QTabBar *>(widget)) {
- _tabBarEngine->registerWidget(widget);
+ else if (auto tabBar = qobject_cast<QTabBar *>(widget)) {
+ _tabBarEngine->registerWidget(tabBar);
}
// scrollarea
else if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget)) {
- if (scrollArea->frameShadow() == QFrame::Sunken && (widget->focusPolicy() & Qt::StrongFocus)) {
- _inputWidgetEngine->registerWidget(widget, AnimationHover | AnimationFocus);
+ if (scrollArea->frameShadow() == QFrame::Sunken && (scrollArea->focusPolicy() & Qt::StrongFocus)) {
+ _inputWidgetEngine->registerWidget(scrollArea, AnimationHover | AnimationFocus);
}
}
@@ -190,7 +190,7 @@ void Animations::registerWidget(QWidget *widget) const
}
//____________________________________________________________
-void Animations::unregisterWidget(QWidget *widget) const
+void Animations::unregisterWidget(QObject *widget) const
{
if (!widget) {
return;
diff --git a/kstyle/animations/breezeanimations.h b/kstyle/animations/breezeanimations.h
index 6551900a5..3215e8fb9 100644
--- a/kstyle/animations/breezeanimations.h
+++ b/kstyle/animations/breezeanimations.h
@@ -31,10 +31,10 @@ public:
explicit Animations();
//* register animations corresponding to given widget, depending on its type.
- void registerWidget(QWidget *widget) const;
+ void registerWidget(QObject *widget) const;
/** unregister all animations associated to a widget */
- void unregisterWidget(QWidget *widget) const;
+ void unregisterWidget(QObject *widget) const;
//* enability engine
[[nodiscard]] WidgetStateEngine &widgetEnabilityEngine() const
--
GitLab
From 75201d1e63d82f7282c8bedcc7cc3d2417b1e123 Mon Sep 17 00:00:00 2001
From: Kai Uwe Broulik <kde@privat.broulik.de>
Date: Sat, 24 May 2025 09:40:01 +0200
Subject: [PATCH 2/3] kstyle: Use styleObject for widgetStateEngine in
CheckBox/RadioButton
Prepares it for doing the animation also with Qt Quick Controls
without an actual QWidget.
---
kstyle/breezestyle.cpp | 44 ++++++++++++++++++++++++++++--------------
1 file changed, 29 insertions(+), 15 deletions(-)
diff --git a/kstyle/breezestyle.cpp b/kstyle/breezestyle.cpp
index 09cee6003..19149c382 100644
--- a/kstyle/breezestyle.cpp
+++ b/kstyle/breezestyle.cpp
@@ -4738,6 +4738,8 @@ bool Style::drawPanelItemViewItemPrimitive(const QStyleOption *option, QPainter
//___________________________________________________________________________________
bool Style::drawIndicatorCheckBoxPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
+ const QObject *styleObject = widget ? widget : option->styleObject;
+
// copy rect and palette
const auto &rect(option->rect);
const auto &palette(option->palette);
@@ -4757,15 +4759,15 @@ bool Style::drawIndicatorCheckBoxPrimitive(const QStyleOption *option, QPainter
}
// animation state
- _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver);
- _animations->widgetStateEngine().updateState(widget, AnimationPressed, checkBoxState != CheckOff);
+ _animations->widgetStateEngine().updateState(styleObject, AnimationHover, mouseOver);
+ _animations->widgetStateEngine().updateState(styleObject, AnimationPressed, checkBoxState != CheckOff);
auto target = checkBoxState;
- if (_animations->widgetStateEngine().isAnimated(widget, AnimationPressed)) {
+ if (_animations->widgetStateEngine().isAnimated(styleObject, AnimationPressed)) {
checkBoxState = CheckAnimated;
}
- const qreal animation(_animations->widgetStateEngine().opacity(widget, AnimationPressed));
+ const qreal animation(_animations->widgetStateEngine().opacity(styleObject, AnimationPressed));
- const qreal opacity(_animations->widgetStateEngine().opacity(widget, AnimationHover));
+ const qreal opacity(_animations->widgetStateEngine().opacity(styleObject, AnimationHover));
// render
_helper->renderCheckBoxBackground(painter, rect, palette, checkBoxState, hasHighlightNeutral(widget, option, mouseOver), sunken, animation);
@@ -4777,6 +4779,8 @@ bool Style::drawIndicatorCheckBoxPrimitive(const QStyleOption *option, QPainter
//___________________________________________________________________________________
bool Style::drawIndicatorRadioButtonPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
+ const QObject *styleObject = widget ? widget : option->styleObject;
+
// copy rect and palette
const auto &rect(option->rect);
const auto &palette(option->palette);
@@ -4791,19 +4795,27 @@ bool Style::drawIndicatorRadioButtonPrimitive(const QStyleOption *option, QPaint
RadioButtonState radioButtonState((state & State_On) ? RadioOn : RadioOff);
// animation state
- _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver);
- _animations->widgetStateEngine().updateState(widget, AnimationPressed, radioButtonState != RadioOff);
- if (_animations->widgetStateEngine().isAnimated(widget, AnimationPressed)) {
+ _animations->widgetStateEngine().updateState(styleObject, AnimationHover, mouseOver);
+ _animations->widgetStateEngine().updateState(styleObject, AnimationPressed, radioButtonState != RadioOff);
+ if (_animations->widgetStateEngine().isAnimated(styleObject, AnimationPressed)) {
radioButtonState = RadioAnimated;
}
- const qreal animation(_animations->widgetStateEngine().opacity(widget, AnimationPressed));
+ const qreal animation(_animations->widgetStateEngine().opacity(styleObject, AnimationPressed));
// colors
- const qreal opacity(_animations->widgetStateEngine().opacity(widget, AnimationHover));
+ const qreal opacity(_animations->widgetStateEngine().opacity(styleObject, AnimationHover));
// render
- _helper->renderRadioButtonBackground(painter, rect, palette, radioButtonState, hasHighlightNeutral(widget, option, mouseOver), sunken, animation);
- _helper->renderRadioButton(painter, rect, palette, mouseOver, radioButtonState, hasHighlightNeutral(widget, option, mouseOver), sunken, animation, opacity);
+ _helper->renderRadioButtonBackground(painter, rect, palette, radioButtonState, hasHighlightNeutral(styleObject, option, mouseOver), sunken, animation);
+ _helper->renderRadioButton(painter,
+ rect,
+ palette,
+ mouseOver,
+ radioButtonState,
+ hasHighlightNeutral(styleObject, option, mouseOver),
+ sunken,
+ animation,
+ opacity);
return true;
}
@@ -5450,6 +5462,8 @@ bool Style::drawCheckBoxLabelControl(const QStyleOption *option, QPainter *paint
return true;
}
+ const QObject *styleObject = widget ? widget : option->styleObject;
+
// copy palette and rect
const auto &palette(option->palette);
const auto &rect(option->rect);
@@ -5501,10 +5515,10 @@ bool Style::drawCheckBoxLabelControl(const QStyleOption *option, QPainter *paint
const bool hasFocus(enabled && (state & State_HasFocus));
// update animation state
- _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus);
+ _animations->widgetStateEngine().updateState(styleObject, AnimationFocus, hasFocus);
- const bool isFocusAnimated(_animations->widgetStateEngine().isAnimated(widget, AnimationFocus));
- const qreal opacity(_animations->widgetStateEngine().opacity(widget, AnimationFocus));
+ const bool isFocusAnimated(_animations->widgetStateEngine().isAnimated(styleObject, AnimationFocus));
+ const qreal opacity(_animations->widgetStateEngine().opacity(styleObject, AnimationFocus));
// focus color
QColor focusColor;
if (isFocusAnimated) {
--
GitLab
From a572df8f099969919544dbc2478de6aa2082a705 Mon Sep 17 00:00:00 2001
From: Kai Uwe Broulik <kde@privat.broulik.de>
Date: Sat, 24 May 2025 09:54:44 +0200
Subject: [PATCH 3/3] kstyle: Register Qt Quick Controls with animations
Since it's all software-rendered and indirect, only the
CheckBox and RadioButton controls are actually wired up
since the rest of the animations is quite subtle.
---
kstyle/animations/breezeanimations.cpp | 9 +++++++++
kstyle/breezestyle.cpp | 4 ++++
2 files changed, 13 insertions(+)
diff --git a/kstyle/animations/breezeanimations.cpp b/kstyle/animations/breezeanimations.cpp
index ceab53802..5285f5daf 100644
--- a/kstyle/animations/breezeanimations.cpp
+++ b/kstyle/animations/breezeanimations.cpp
@@ -100,6 +100,15 @@ void Animations::registerWidget(QObject *widget) const
// install animation timers
// for optimization, one should put with most used widgets here first
+ // KQuickStyleItem.
+ const QString elementType = widget->property("elementType").toString();
+ if (!elementType.isEmpty()) {
+ if (elementType == QLatin1String("checkbox") || elementType == QLatin1String("radiobutton")) {
+ _widgetStateEngine->registerWidget(widget, AnimationHover | AnimationFocus | AnimationPressed);
+ }
+ return;
+ }
+
// buttons
if (auto toolButton = qobject_cast<QToolButton *>(widget)) {
_toolButtonEngine->registerWidget(toolButton, AnimationHover | AnimationFocus);
diff --git a/kstyle/breezestyle.cpp b/kstyle/breezestyle.cpp
index 19149c382..e549803f1 100644
--- a/kstyle/breezestyle.cpp
+++ b/kstyle/breezestyle.cpp
@@ -4739,6 +4739,7 @@ bool Style::drawPanelItemViewItemPrimitive(const QStyleOption *option, QPainter
bool Style::drawIndicatorCheckBoxPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
const QObject *styleObject = widget ? widget : option->styleObject;
+ isQtQuickControl(option, widget); // registers it with widgetStateEngine.
// copy rect and palette
const auto &rect(option->rect);
@@ -4780,6 +4781,7 @@ bool Style::drawIndicatorCheckBoxPrimitive(const QStyleOption *option, QPainter
bool Style::drawIndicatorRadioButtonPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
const QObject *styleObject = widget ? widget : option->styleObject;
+ isQtQuickControl(option, widget); // registers it with widgetStateEngine.
// copy rect and palette
const auto &rect(option->rect);
@@ -5463,6 +5465,7 @@ bool Style::drawCheckBoxLabelControl(const QStyleOption *option, QPainter *paint
}
const QObject *styleObject = widget ? widget : option->styleObject;
+ isQtQuickControl(option, widget); // registers it with widgetStateEngine.
// copy palette and rect
const auto &palette(option->palette);
@@ -8460,6 +8463,7 @@ bool Style::isQtQuickControl(const QStyleOption *option, const QWidget *widget)
if (!widget && option) {
if (const auto item = qobject_cast<QQuickItem *>(option->styleObject)) {
_windowManager->registerQuickItem(item);
+ _animations->registerWidget(item);
return true;
}
}
--
GitLab

View file

@ -0,0 +1,3 @@
Gear 25.08.0:
Pr 946 https://invent.kde.org/system/dolphin/-/merge_requests/946

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
Plasma 6.5.0:
Pr 3612 https://invent.kde.org/plasma/kwin/-/merge_requests/3612
Pr 7823 https://invent.kde.org/plasma/kwin/-/merge_requests/7823
Plasma 6.4.2:
Pr 7822 https://invent.kde.org/plasma/kwin/-/merge_requests/7822
Pr 7829 https://invent.kde.org/plasma/kwin/-/merge_requests/7829

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
From 3ac297b99540eae81568edca1e550ca7d1d6c01f Mon Sep 17 00:00:00 2001
From: Ismael Asensio <isma.af@gmail.com>
Date: Tue, 24 Jun 2025 17:08:00 +0200
Subject: [PATCH] plugins/fadingpopups: Blacklist spectacle popup menus from
fading effect
Spectacle can trigger a screenshot from a popup menu. This menu needs
to get hidden immediately with no effects, to avoid appearing on the
screenshot.
BUG: 505803
FIXED-IN: 6.4.2
(cherry picked from commit 99f6418e3c2e044eb1f4e8bedcdccac55f1a01d4)
Co-authored-by: Ismael Asensio <isma.af@gmail.com>
---
src/plugins/fadingpopups/package/contents/code/main.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/plugins/fadingpopups/package/contents/code/main.js b/src/plugins/fadingpopups/package/contents/code/main.js
index f0764b42ac6..7c00640ae8f 100644
--- a/src/plugins/fadingpopups/package/contents/code/main.js
+++ b/src/plugins/fadingpopups/package/contents/code/main.js
@@ -17,7 +17,10 @@ var blacklist = [
// The lockscreen isn't a popup window
"kscreenlocker_greet kscreenlocker_greet",
// KDE Plasma splash screen has to be animated only by the login effect.
- "ksplashqml ksplashqml"
+ "ksplashqml ksplashqml",
+ // Spectacle can trigger a screenshot from a popup menu
+ "spectacle org.kde.spectacle",
+ "spectacle spectacle",
];
function isPopupWindow(window) {
--
GitLab

View file

@ -0,0 +1,26 @@
From a1868942fbc2ad5de4c053dd17335dff34d81779 Mon Sep 17 00:00:00 2001
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Date: Wed, 25 Jun 2025 14:10:18 +0300
Subject: [PATCH] plugins/login: Reduce animation duration
This makes the startup feel a bit faster.
---
src/plugins/login/package/contents/code/main.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/plugins/login/package/contents/code/main.js b/src/plugins/login/package/contents/code/main.js
index 7f849a6e2e6..e3ad0b76c07 100644
--- a/src/plugins/login/package/contents/code/main.js
+++ b/src/plugins/login/package/contents/code/main.js
@@ -11,7 +11,7 @@
"use strict";
var loginEffect = {
- duration: animationTime(1000),
+ duration: animationTime(500),
isFadeToBlack: false,
loadConfig: function () {
loginEffect.isFadeToBlack = effect.readConfig("FadeToBlack", false);
--
GitLab

View file

@ -0,0 +1,85 @@
From 4ddb4a23d5f453cf890c9f1b1aa5429150991db3 Mon Sep 17 00:00:00 2001
From: David Redondo <kde@david-redondo.de>
Date: Thu, 26 Jun 2025 17:00:07 +0200
Subject: [PATCH] scene: Skip visibility check for the Item itself in
framePainted
Fixes offscreen rendering and window thumbnails for hidden windows
not udpating.
Co-authored-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
---
src/scene/item.cpp | 9 +++++----
src/scene/item.h | 2 +-
src/scene/rootitem.cpp | 9 ---------
src/scene/rootitem.h | 2 --
4 files changed, 6 insertions(+), 16 deletions(-)
diff --git a/src/scene/item.cpp b/src/scene/item.cpp
index 2637a131dbd..eb2b6b46977 100644
--- a/src/scene/item.cpp
+++ b/src/scene/item.cpp
@@ -648,12 +648,13 @@ void Item::removeEffect()
void Item::framePainted(Output *output, OutputFrame *frame, std::chrono::milliseconds timestamp)
{
- if (!isVisible() || workspace()->outputAt(mapToScene(boundingRect()).center()) != output) {
- return;
- }
+ // The visibility of the item itself is not checked here to be able to paint hidden items for
+ // things like screncasts or thumbnails
handleFramePainted(output, frame, timestamp);
for (const auto child : std::as_const(m_childItems)) {
- child->framePainted(output, frame, timestamp);
+ if (child->explicitVisible() && workspace()->outputAt(child->mapToScene(child->boundingRect()).center()) == output) {
+ child->framePainted(output, frame, timestamp);
+ }
}
}
diff --git a/src/scene/item.h b/src/scene/item.h
index acb29994328..d42b32abf7b 100644
--- a/src/scene/item.h
+++ b/src/scene/item.h
@@ -144,7 +144,7 @@ public:
void addEffect();
void removeEffect();
- virtual void framePainted(Output *output, OutputFrame *frame, std::chrono::milliseconds timestamp);
+ void framePainted(Output *output, OutputFrame *frame, std::chrono::milliseconds timestamp);
bool isAncestorOf(const Item *item) const;
diff --git a/src/scene/rootitem.cpp b/src/scene/rootitem.cpp
index fe0cecc76e3..466a25ce828 100644
--- a/src/scene/rootitem.cpp
+++ b/src/scene/rootitem.cpp
@@ -14,13 +14,4 @@ RootItem::RootItem(Scene *scene)
setScene(scene);
}
-void RootItem::framePainted(Output *output, OutputFrame *frame, std::chrono::milliseconds timestamp)
-{
- handleFramePainted(output, frame, timestamp);
- const auto children = childItems();
- for (const auto child : children) {
- child->framePainted(output, frame, timestamp);
- }
-}
-
} // namespace KWin
diff --git a/src/scene/rootitem.h b/src/scene/rootitem.h
index 45fa1359c84..43b3cdb90e9 100644
--- a/src/scene/rootitem.h
+++ b/src/scene/rootitem.h
@@ -20,8 +20,6 @@ class KWIN_EXPORT RootItem : public Item
public:
explicit RootItem(Scene *scene);
-
- void framePainted(Output *output, OutputFrame *frame, std::chrono::milliseconds timestamp) override;
};
} // namespace KWin
--
GitLab

View file

@ -0,0 +1,4 @@
Plasma 6.5.0:
Pr 439 https://invent.kde.org/plasma/plasma-nm/-/merge_requests/439
Pr 442 https://invent.kde.org/plasma/plasma-nm/-/merge_requests/442

View file

@ -0,0 +1,140 @@
From ac32824009397188131aab4fcc3394fcc4551c5c Mon Sep 17 00:00:00 2001
From: Nate Graham <nate@kde.org>
Date: Tue, 10 Jun 2025 15:43:13 -0600
Subject: [PATCH 1/2] applet: handle some more states
1. Looking for Wi-Fi networks but haven't found any yet
2. NetworkManager isn't running
FEATURE: 485982
BUG: 462454
FIXED-IN: 6.5.0
---
applet/contents/ui/ConnectionListPage.qml | 15 ++++++++++++---
applet/contents/ui/Toolbar.qml | 3 ++-
applet/metadata.json | 1 -
libs/networkstatus.h | 3 +--
4 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/applet/contents/ui/ConnectionListPage.qml b/applet/contents/ui/ConnectionListPage.qml
index b9a949d87..056f52de3 100644
--- a/applet/contents/ui/ConnectionListPage.qml
+++ b/applet/contents/ui/ConnectionListPage.qml
@@ -101,9 +101,12 @@ ColumnLayout {
if (toolbar.displayplaneModeMessage) {
return "network-flightmode-on"
}
- if (toolbar.displayWifiMessage) {
+ if (toolbar.displayWifiOffMessage) {
return "network-wireless-off"
}
+ if (toolbar.displayWifiConnectingMessage) {
+ return "view-refresh-symbolic"
+ }
if (toolbar.displayWwanMessage) {
return "network-mobile-off"
}
@@ -113,19 +116,25 @@ ColumnLayout {
if (toolbar.displayplaneModeMessage) {
return i18n("Airplane mode is enabled")
}
- if (toolbar.displayWifiMessage) {
+ if (toolbar.displayWifiOffMessage) {
if (toolbar.displayWwanMessage) {
return i18n("Wireless and mobile networks are deactivated")
}
return i18n("Wireless is deactivated")
}
+ if (toolbar.displayWifiConnectingMessage) {
+ return i18n("Looking for wireless networks")
+ }
if (toolbar.displayWwanMessage) {
return i18n("Mobile network is deactivated")
}
if (toolbar.searchTextField.text.length > 0) {
return i18n("No matches")
}
- return i18n("No available connections")
+ if (connectionListPage.nmStatus.connectivity === NMQt.NetworkManager.Full) {
+ return i18n("No available connections")
+ }
+ return nmStatus.checkUnknownReason()
}
}
}
diff --git a/applet/contents/ui/Toolbar.qml b/applet/contents/ui/Toolbar.qml
index 87b3f1654..0d382109b 100644
--- a/applet/contents/ui/Toolbar.qml
+++ b/applet/contents/ui/Toolbar.qml
@@ -16,7 +16,8 @@ import org.kde.kcmutils as KCMUtils
RowLayout {
id: toolbar
- readonly property var displayWifiMessage: !wifiSwitchButton.checked && wifiSwitchButton.visible
+ readonly property var displayWifiOffMessage: !wifiSwitchButton.checked && wifiSwitchButton.visible
+ readonly property var displayWifiConnectingMessage: wifiSwitchButton.checked && wifiSwitchButton.visible
readonly property var displayWwanMessage: !wwanSwitchButton.checked && wwanSwitchButton.visible
readonly property var displayplaneModeMessage: planeModeSwitchButton.checked && planeModeSwitchButton.visible
diff --git a/applet/metadata.json b/applet/metadata.json
index 0ca36a2b7..2f12891b5 100644
--- a/applet/metadata.json
+++ b/applet/metadata.json
@@ -210,6 +210,5 @@
"X-KDE-Keywords[zh_CN]": "network,internet,ethernet,wireless,wifi,wlan,vpn,wangluo,hulianwang,yitaiwang,juyuwang,wuxianwangluo,xunizhuanyongwangluo,网络,互联网,以太网,局域网,无线网络,虚拟专用网络",
"X-KDE-Keywords[zh_TW]": "網路,網絡,網際網路,乙太網路,以太網路,無線",
"X-Plasma-API-Minimum-Version": "6.0",
- "X-Plasma-DBusActivationService": "org.freedesktop.NetworkManager",
"X-Plasma-NotificationAreaCategory": "Hardware"
}
diff --git a/libs/networkstatus.h b/libs/networkstatus.h
index aa88bf7c5..a885f04dd 100644
--- a/libs/networkstatus.h
+++ b/libs/networkstatus.h
@@ -59,6 +59,7 @@ public:
QString activeConnections() const;
QString networkStatus() const;
NetworkManager::Connectivity connectivity() const;
+ Q_INVOKABLE QString checkUnknownReason() const;
private Q_SLOTS:
void activeConnectionsChanged();
@@ -75,8 +76,6 @@ private:
QString m_activeConnections;
QString m_networkStatus;
NetworkManager::Connectivity m_connectivity = NetworkManager::UnknownConnectivity;
-
- QString checkUnknownReason() const;
};
#endif // PLAMA_NM_NETWORK_STATUS_H
--
GitLab
From a45534cd9c19f267075fe4261087045f1f3a9318 Mon Sep 17 00:00:00 2001
From: Nate Graham <nate@kde.org>
Date: Wed, 11 Jun 2025 10:14:40 -0600
Subject: [PATCH 2/2] Rephrase "NetworkManager not running" message to be more
user-friendly
---
libs/networkstatus.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libs/networkstatus.cpp b/libs/networkstatus.cpp
index c89ca9fca..b778eedda 100644
--- a/libs/networkstatus.cpp
+++ b/libs/networkstatus.cpp
@@ -253,7 +253,7 @@ QString NetworkStatus::checkUnknownReason() const
{
// Check if NetworkManager is running.
if (!QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral(NM_DBUS_INTERFACE))) {
- return i18n("NetworkManager not running");
+ return i18nc("@info:status", "NetworkManager service is not running");
}
// Check for compatible NetworkManager version.
--
GitLab

View file

@ -0,0 +1,168 @@
From 63a9d544dc4f5160f28e5f3203a2c0a5e639e5ac Mon Sep 17 00:00:00 2001
From: Nate Graham <nate@kde.org>
Date: Fri, 13 Jun 2025 12:24:22 -0600
Subject: [PATCH] applet: use standard section headers
We have them, so we might as well use them. This lets us get rid of a
bunch of complex and fragile code that's responsible for the existing
separator.
---
applet/contents/ui/ConnectionItem.qml | 14 -----
applet/contents/ui/ConnectionListPage.qml | 10 ++--
applet/contents/ui/ListItem.qml | 64 -----------------------
libs/models/networkmodelitem.cpp | 8 ++-
4 files changed, 12 insertions(+), 84 deletions(-)
delete mode 100644 applet/contents/ui/ListItem.qml
diff --git a/applet/contents/ui/ConnectionItem.qml b/applet/contents/ui/ConnectionItem.qml
index ed154e633..5bb5c530c 100644
--- a/applet/contents/ui/ConnectionItem.qml
+++ b/applet/contents/ui/ConnectionItem.qml
@@ -321,20 +321,6 @@ PlasmaExtras.ExpandableListItem {
}
}
- onDeactivatedChanged: {
- /* Separator is part of section, which is visible only when available connections exist. Need to determine
- if there is a connection in use, to show Separator. Otherwise need to hide it from the top of the list.
- Connections in use are always on top, only need to check the first one. */
- if (appletProxyModel.data(appletProxyModel.index(0, 0), PlasmaNM.NetworkModel.SectionRole) !== "Available connections") {
- if (connectionView.showSeparator != true) {
- connectionView.showSeparator = true
- }
- return
- }
- connectionView.showSeparator = false
- return
- }
-
onItemCollapsed: {
connectionItem.customExpandedViewContent = detailsComponent;
setDelayModelUpdates(false);
diff --git a/applet/contents/ui/ConnectionListPage.qml b/applet/contents/ui/ConnectionListPage.qml
index b62da252c..d8ebd2c54 100644
--- a/applet/contents/ui/ConnectionListPage.qml
+++ b/applet/contents/ui/ConnectionListPage.qml
@@ -8,7 +8,7 @@ import QtQuick 2.15
import QtQuick.Layouts 1.2
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.kirigami 2.20 as Kirigami
-import org.kde.plasma.extras 2.0 as PlasmaExtras
+import org.kde.plasma.extras as PlasmaExtras
import org.kde.plasma.networkmanagement as PlasmaNM
import org.kde.networkmanager as NMQt
@@ -55,7 +55,6 @@ ColumnLayout {
id: connectionView
property int currentVisibleButtonIndex: -1
- property bool showSeparator: false
Keys.onDownPressed: event => {
connectionView.incrementCurrentIndex();
@@ -80,9 +79,10 @@ ColumnLayout {
model: appletProxyModel
currentIndex: -1
boundsBehavior: Flickable.StopAtBounds
- section.property: showSeparator ? "Section" : ""
- section.delegate: ListItem {
- separator: true
+ section.property: "Section"
+ section.delegate: PlasmaExtras.ListSectionHeader {
+ width: connectionView.width - connectionView.leftMargin - connectionView.rightMargin
+ text: section
}
highlight: PlasmaExtras.Highlight { }
highlightMoveDuration: Kirigami.Units.shortDuration
diff --git a/applet/contents/ui/ListItem.qml b/applet/contents/ui/ListItem.qml
deleted file mode 100644
index bfe1390d1..000000000
--- a/applet/contents/ui/ListItem.qml
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- SPDX-FileCopyrightText: 2010 Marco Martin <notmart@gmail.com>
- SPDX-FileCopyrightText: 2016 Jan Grulich <jgrulich@redhat.com>
- SPDX-FileCopyrightText: 2020 George Vogiatzis <gvgeo@protonmail.com>
-
- SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
-*/
-
-import QtQuick 2.1
-import org.kde.kirigami 2.20 as Kirigami
-import org.kde.ksvg 1.0 as KSvg
-
-/**
- * Ignores the theme's listItem margins, and uses custom highlight(pressed) area.
- * Could break some themes but the majority look fine.
- * Also includes a separator to be used in sections.
- */
-MouseArea {
- id: listItem
-
- property bool checked: false
- property bool separator: false
- property rect highlightRect: Qt.rect(0, 0, width, height)
-
- width: parent.width
-
- // Sections have spacing above but not below. Will use 2 of them below.
- height: separator ? separatorLine.height + Kirigami.Units.smallSpacing * 3 : parent.height
- hoverEnabled: true
-
- KSvg.SvgItem {
- id: separatorLine
- anchors {
- horizontalCenter: parent.horizontalCenter
- top: parent.top
- topMargin: Kirigami.Units.smallSpacing
- }
- imagePath: "widgets/line"
- elementId: "horizontal-line"
- width: parent.width - Kirigami.Units.gridUnit * 2
- visible: listItem.separator
- }
-
- KSvg.FrameSvgItem {
- id: background
- imagePath: "widgets/listitem"
- prefix: "normal"
- anchors.fill: parent
- visible: listItem.separator ? false : true
- }
-
- KSvg.FrameSvgItem {
- id: pressed
- imagePath: "widgets/listitem"
- prefix: "pressed"
- opacity: listItem.checked ? 1 : 0
- Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } }
-
- x: listItem.highlightRect.x
- y: listItem.highlightRect.y
- height: listItem.highlightRect.height
- width: listItem.highlightRect.width
- }
-}
diff --git a/libs/models/networkmodelitem.cpp b/libs/models/networkmodelitem.cpp
index b92ec0df2..4d7cbd77d 100644
--- a/libs/models/networkmodelitem.cpp
+++ b/libs/models/networkmodelitem.cpp
@@ -344,7 +344,13 @@ QString NetworkModelItem::originalName() const
QString NetworkModelItem::sectionType() const
{
if (m_connectionState == NetworkManager::ActiveConnection::Deactivated) {
- return QStringLiteral("Available connections");
+ return i18nc("@title:column header for list of available network connections", "Available");
+ // clang-format off
+ } else if (m_connectionState == NetworkManager::ActiveConnection::Activating
+ || m_connectionState == NetworkManager::ActiveConnection::Activated
+ || m_connectionState == NetworkManager::ActiveConnection::Deactivating) {
+ // clang-format on
+ return i18nc("@title:column header for list of connected network connections", "Connected");
} else {
return {};
}
--
GitLab

View file

@ -0,0 +1,6 @@
Plasma 6.5.0:
Pr 5589 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5589
Pr 5626 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5626
Pr 5627 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5627
Pr 5628 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5628

View file

@ -0,0 +1,37 @@
From 2278398309c68ce401a8e35b193fca3782391a4a Mon Sep 17 00:00:00 2001
From: Nate Graham <nate@kde.org>
Date: Thu, 12 Jun 2025 09:15:15 -0600
Subject: [PATCH] applets/devicenotifier: use standard section header
No need for a custom header here when we have a standard one.
CCBUG: 442724
---
.../package/contents/ui/FullRepresentation.qml | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/applets/devicenotifier/package/contents/ui/FullRepresentation.qml b/applets/devicenotifier/package/contents/ui/FullRepresentation.qml
index 967223e0a1a..a0c28df45fe 100644
--- a/applets/devicenotifier/package/contents/ui/FullRepresentation.qml
+++ b/applets/devicenotifier/package/contents/ui/FullRepresentation.qml
@@ -132,15 +132,9 @@ PlasmaExtras.Representation {
section {
property: "deviceType"
- delegate: Item {
- height: Math.floor(childrenRect.height)
+ delegate: PlasmaExtras.ListSectionHeader {
width: notifierDialog.width - (scrollView.PlasmaComponents3.ScrollBar.vertical.visible ? Kirigami.Units.largeSpacing * 2 : 0)
- Kirigami.Heading {
- level: 3
- opacity: 0.6
- text: section
- textFormat: Text.PlainText
- }
+ text: section
}
}
--
GitLab

View file

@ -0,0 +1,102 @@
From 9fabf42c39a25308739dd3483881cc889243bf58 Mon Sep 17 00:00:00 2001
From: Kristen McWilliam <kristen@kde.org>
Date: Tue, 24 Jun 2025 17:44:33 -0400
Subject: [PATCH] applets/notifications: Add actions to missed notifications
notification
When a notification is displayed informing the user that notifications were missed while in Do Not
Disturb, now clicking the button or the notification itself will open the notifications applet to
show the missed notifications.
BUG: 502423
---
.../package/contents/ui/main.qml | 10 ++++++
libnotificationmanager/notifications.cpp | 34 ++++++++++++++-----
libnotificationmanager/notifications.h | 7 ++++
3 files changed, 42 insertions(+), 9 deletions(-)
diff --git a/applets/notifications/package/contents/ui/main.qml b/applets/notifications/package/contents/ui/main.qml
index c96afa0558d..ab66a52f45e 100644
--- a/applets/notifications/package/contents/ui/main.qml
+++ b/applets/notifications/package/contents/ui/main.qml
@@ -268,4 +268,14 @@ PlasmoidItem {
Component.onDestruction: {
Globals.forget(root);
}
+
+ Connections {
+ target: Globals.popupNotificationsModel
+
+ // The user requested to show the notifications popup, probably by
+ // clicking the "Missed Notifications in Do Not Disturb" notification.
+ function onShowNotificationsRequested(): void {
+ root.expanded = true;
+ }
+ }
}
diff --git a/libnotificationmanager/notifications.cpp b/libnotificationmanager/notifications.cpp
index 2cba1360b10..7b5cd9d68c4 100644
--- a/libnotificationmanager/notifications.cpp
+++ b/libnotificationmanager/notifications.cpp
@@ -903,15 +903,31 @@ void Notifications::showInhibitionSummary(Urgency urgency, const QStringList &bl
return;
}
- KNotification::event(u"inhibitionSummary"_s,
- i18ncp("@title", "Unread Notification", "Unread Notifications", inhibited),
- i18ncp("@info",
- "%1 notification was received while Do Not Disturb was active.",
- "%1 notifications were received while Do Not Disturb was active.",
- inhibited),
- u"preferences-desktop-notification-bell"_s,
- KNotification::CloseOnTimeout,
- u"libnotificationmanager"_s);
+ KNotification *notification = new KNotification(u"inhibitionSummary"_s);
+ notification->setTitle(i18ncp("@title", "Unread Notification", "Unread Notifications", inhibited));
+ notification->setText(i18ncp("@info",
+ "%1 notification was received while Do Not Disturb was active.",
+ "%1 notifications were received while Do Not Disturb was active.",
+ inhibited));
+ notification->setIconName(u"preferences-desktop-notification-bell"_s);
+ notification->setFlags(KNotification::CloseOnTimeout);
+ notification->setComponentName(u"libnotificationmanager"_s);
+
+ const QString showNotificationsText = i18nc( //
+ "@action:button Show the notifications popup; translate this in as short a form as possible",
+ "Show Notifications");
+
+ const KNotificationAction *defaultShowNotificationsAction = notification->addDefaultAction(showNotificationsText);
+ connect(defaultShowNotificationsAction, &KNotificationAction::activated, this, [this]() {
+ Q_EMIT showNotificationsRequested();
+ });
+
+ const KNotificationAction *showNotificationsAction = notification->addAction(showNotificationsText);
+ connect(showNotificationsAction, &KNotificationAction::activated, this, [this]() {
+ Q_EMIT showNotificationsRequested();
+ });
+
+ notification->sendEvent();
}
QVariant Notifications::data(const QModelIndex &index, int role) const
diff --git a/libnotificationmanager/notifications.h b/libnotificationmanager/notifications.h
index e927c472c8f..8544b6271ae 100644
--- a/libnotificationmanager/notifications.h
+++ b/libnotificationmanager/notifications.h
@@ -597,6 +597,13 @@ Q_SIGNALS:
void jobsPercentageChanged();
void windowChanged(QWindow *window);
+ /**
+ * Emitted when the user has requested to show the notifications popup.
+ *
+ * This is typically connected to a button in the "Missed Notifications in Do Not Disturb" notification.
+ */
+ void showNotificationsRequested();
+
protected:
void classBegin() override;
void componentComplete() override;
--
GitLab

View file

@ -0,0 +1,157 @@
From 1641ea3897d565d672e29a7524ce4171ddbcfd32 Mon Sep 17 00:00:00 2001
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Date: Wed, 25 Jun 2025 14:00:05 +0300
Subject: [PATCH 1/2] shell: Set desktop ksplash stage when all desktop views
are ready
If there are two outputs and the wallpaper for the first one is ready
but for the second one is not, the ksplash will be notified about the
desktop stage.
This changes fixes checkAllDesktopsUiReady() so it sets the desktop
stage only if all desktop views are ready.
---
shell/shellcorona.cpp | 28 +++++++++++++++-------------
shell/shellcorona.h | 2 +-
2 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp
index 37d93d05353..65c8ccc272e 100644
--- a/shell/shellcorona.cpp
+++ b/shell/shellcorona.cpp
@@ -1338,6 +1338,8 @@ void ShellCorona::removeDesktop(DesktopView *desktopView)
desktopView->destroy();
desktopView->containment()->reactToScreenChange();
+
+ checkAllDesktopsUiReady();
}
PanelView *ShellCorona::panelView(Plasma::Containment *containment) const
@@ -1529,22 +1531,22 @@ void ShellCorona::addOutput(QScreen *screen)
#endif
}
-void ShellCorona::checkAllDesktopsUiReady(bool ready)
+void ShellCorona::checkAllDesktopsUiReady()
{
- if (!ready)
+ const bool ready = std::ranges::all_of(std::as_const(m_desktopViewForScreen), [](const DesktopView *view) {
+ return view->containment()->isUiReady();
+ });
+ if (!ready) {
return;
- for (auto v : std::as_const(m_desktopViewForScreen)) {
- if (!v->containment()->isUiReady())
- return;
-
- qCDebug(PLASMASHELL) << "Plasma Shell startup completed";
- QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"),
- QStringLiteral("/KSplash"),
- QStringLiteral("org.kde.KSplash"),
- QStringLiteral("setStage"));
- ksplashProgressMessage.setArguments(QList<QVariant>() << QStringLiteral("desktop"));
- QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage);
}
+
+ qCDebug(PLASMASHELL) << "Plasma Shell startup completed";
+ QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"),
+ QStringLiteral("/KSplash"),
+ QStringLiteral("org.kde.KSplash"),
+ QStringLiteral("setStage"));
+ ksplashProgressMessage.setArguments(QList<QVariant>() << QStringLiteral("desktop"));
+ QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage);
}
Plasma::Containment *ShellCorona::createContainmentForActivity(const QString &activity, int screenNum)
diff --git a/shell/shellcorona.h b/shell/shellcorona.h
index 0f544ca266f..7b6c6a559a1 100644
--- a/shell/shellcorona.h
+++ b/shell/shellcorona.h
@@ -275,7 +275,7 @@ private:
DesktopView *desktopForScreen(QScreen *screen) const;
void setupWaylandIntegration();
void executeSetupPlasmoidScript(Plasma::Containment *containment, Plasma::Applet *applet);
- void checkAllDesktopsUiReady(bool ready);
+ void checkAllDesktopsUiReady();
void activateLauncherMenu(const QString &screenName);
void handleColorRequestedFromDBus(const QDBusMessage &msg);
--
GitLab
From 00bd19ecaccbb10d5cfcc6006b06a9714c615741 Mon Sep 17 00:00:00 2001
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Date: Wed, 25 Jun 2025 14:03:28 +0300
Subject: [PATCH 2/2] shell: Create panel views after desktop views are ready
With the current code, the splash screen will be hidden as soon as the
wallpapers are loaded.
However, the splash screnn is actually notified about the desktop stage
about 1-1.5 second later after the wallpaper plugin resets the loading
property.
The reason for that is that the panel is loaded between
`wallpaper.loading = false` in the wallpaper and ShellCorona::checkAllDesktopsUiReady().
This change re-arranges the startup sequence so the panels are loaded
after the desktop views become ready. It reduces plasma startup time a bit.
In long term, we should look for making panel loading as async as
possible so the main thread doesn't get blocked for too long.
---
shell/shellcorona.cpp | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp
index 65c8ccc272e..6a59683dba7 100644
--- a/shell/shellcorona.cpp
+++ b/shell/shellcorona.cpp
@@ -868,10 +868,6 @@ void ShellCorona::load()
connect(m_screenPool, &ScreenPool::screenOrderChanged, this, &ShellCorona::handleScreenOrderChanged, Qt::UniqueConnection);
connect(m_screenPool, &ScreenPool::screenRemoved, this, &ShellCorona::handleScreenRemoved, Qt::UniqueConnection);
- if (!m_waitingPanels.isEmpty()) {
- m_waitingPanelsTimer.start();
- }
-
if (config()->isImmutable() || !KAuthorized::authorize(QStringLiteral("plasma/plasmashell/unlockedDesktop"))) {
setImmutability(Plasma::Types::SystemImmutable);
} else {
@@ -1517,11 +1513,6 @@ void ShellCorona::addOutput(QScreen *screen)
// in the list. We still don't want to have an invisible view added.
containment->reactToScreenChange();
- // were there any panels for this screen before it popped up?
- if (!m_waitingPanels.isEmpty()) {
- m_waitingPanelsTimer.start();
- }
-
if (!m_screenReorderInProgress) {
Q_EMIT availableScreenRectChanged(m_screenPool->idForScreen(screen));
}
@@ -1547,6 +1538,10 @@ void ShellCorona::checkAllDesktopsUiReady()
QStringLiteral("setStage"));
ksplashProgressMessage.setArguments(QList<QVariant>() << QStringLiteral("desktop"));
QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage);
+
+ if (!m_waitingPanels.isEmpty()) {
+ m_waitingPanelsTimer.start();
+ }
}
Plasma::Containment *ShellCorona::createContainmentForActivity(const QString &activity, int screenNum)
@@ -1604,7 +1599,7 @@ void ShellCorona::createWaitingPanels()
QScreen *screen = m_screenPool->screenForId(requestedScreen);
DesktopView *desktopView = desktopForScreen(screen);
- if (!screen || !desktopView) {
+ if (!screen || !desktopView || !desktopView->containment()->isUiReady()) {
stillWaitingPanels << cont;
continue;
}
--
GitLab

View file

@ -0,0 +1,277 @@
From 9171f24afe6be37e1ac384b8ef03ff89b552be7a Mon Sep 17 00:00:00 2001
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Date: Wed, 25 Jun 2025 17:25:37 +0300
Subject: [PATCH 1/2] startkde: Remove Before=plasma-ksplash-ready.service
This line makes ksplash wait for unrelated services such as powerdevil
and baloo.
This change reduces plasma startup time on my machine to 2-3 seconds.
---
startkde/systemd/plasma-workspace.target | 1 -
1 file changed, 1 deletion(-)
diff --git a/startkde/systemd/plasma-workspace.target b/startkde/systemd/plasma-workspace.target
index a62db5e252a..a9113f49112 100644
--- a/startkde/systemd/plasma-workspace.target
+++ b/startkde/systemd/plasma-workspace.target
@@ -17,7 +17,6 @@ Wants=xdg-desktop-autostart.target
BindsTo=graphical-session.target
Before=graphical-session.target
Before=xdg-desktop-autostart.target
-Before=plasma-ksplash-ready.service
Before=plasma-restoresession.service
RefuseManualStart=yes
StopWhenUnneeded=true
--
GitLab
From 8202ba92b610c691b8bc6bab8ad5a1c3b9ac73da Mon Sep 17 00:00:00 2001
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Date: Wed, 25 Jun 2025 17:29:19 +0300
Subject: [PATCH 2/2] startkde: Drop ready stage
In order to hide the splash screen, it is sufficient just to see the
wallpaper. If more desktop environment components are loaded soon
afterwards, it is okay.
With systemd boot, the way the ready stage is integrated is also kind
of a hack.
---
appiumtests/CMakeLists.txt | 1 -
appiumtests/ksplash/CMakeLists.txt | 14 ----
appiumtests/ksplash/ksplashtest.py | 79 -------------------
ksplash/ksplashqml/splashapp.cpp | 5 +-
startkde/plasma-session/startup.cpp | 11 ---
startkde/plasma-session/startup.h | 1 -
startkde/systemd/CMakeLists.txt | 3 -
.../systemd/plasma-ksplash-ready.service.in | 10 ---
startkde/systemd/plasma-workspace.target | 1 -
9 files changed, 2 insertions(+), 123 deletions(-)
delete mode 100644 appiumtests/ksplash/CMakeLists.txt
delete mode 100755 appiumtests/ksplash/ksplashtest.py
delete mode 100644 startkde/systemd/plasma-ksplash-ready.service.in
diff --git a/appiumtests/CMakeLists.txt b/appiumtests/CMakeLists.txt
index 68d0b6895ba..22234aeb031 100644
--- a/appiumtests/CMakeLists.txt
+++ b/appiumtests/CMakeLists.txt
@@ -20,5 +20,4 @@ add_subdirectory(applets)
add_subdirectory(components_tests)
add_subdirectory(kcms)
add_subdirectory(krunner)
-add_subdirectory(ksplash)
add_subdirectory(wallpapers)
diff --git a/appiumtests/ksplash/CMakeLists.txt b/appiumtests/ksplash/CMakeLists.txt
deleted file mode 100644
index 3bea5174f5a..00000000000
--- a/appiumtests/ksplash/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-FileCopyrightText: 2024 Fushan Wen <qydwhotmail@gmail.com>
-# SPDX-License-Identifier: BSD-3-Clause
-
-add_test(
- NAME ksplashtest_wayland
- COMMAND sh -c "mkdir -p /tmp/appium/ksplashtest_wayland;dbus-launch selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/ksplashtest.py --failfast"
-)
-set_tests_properties(ksplashtest_wayland PROPERTIES TIMEOUT 60 ENVIRONMENT "XDG_RUNTIME_DIR=/tmp/appium/ksplashtest_wayland;FLASK_PORT=5701")
-
-add_test(
- NAME ksplashtest_x11
- COMMAND sh -c "mkdir -p /tmp/appium/ksplashtest_x11;dbus-launch selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/ksplashtest.py --failfast"
-)
-set_tests_properties(ksplashtest_x11 PROPERTIES TIMEOUT 60 ENVIRONMENT "XDG_RUNTIME_DIR=/tmp/appium/ksplashtest_x11;FLASK_PORT=5702;TEST_WITH_KWIN_WAYLAND=0")
diff --git a/appiumtests/ksplash/ksplashtest.py b/appiumtests/ksplash/ksplashtest.py
deleted file mode 100755
index b7ca43c0519..00000000000
--- a/appiumtests/ksplash/ksplashtest.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python3
-
-# SPDX-FileCopyrightText: 2024 Fushan Wen <qydwhotmail@gmail.com>
-# SPDX-License-Identifier: MIT
-
-# pylint: disable=too-many-arguments
-
-import os
-import subprocess
-import sys
-import time
-import unittest
-
-from appium import webdriver
-from appium.options.common.base import AppiumOptions
-from appium.webdriver.common.appiumby import AppiumBy
-from gi.repository import Gio, GLib
-
-
-class KSplashTest(unittest.TestCase):
-
- driver: webdriver.Remote
-
- @classmethod
- def setUpClass(cls) -> None:
- options = AppiumOptions()
- options.set_capability("app", "ksplashqml --window")
- options.set_capability("environ", {
- "LC_ALL": "en_US.UTF-8",
- "QT_FATAL_WARNINGS": "1",
- "QT_LOGGING_RULES": "qt.accessibility.atspi.warning=false;kf.plasma.core.warning=false;kf.windowsystem.warning=false;kf.kirigami.platform.warning=false;org.kde.plasma.ksplashqml.debug=true",
- })
- options.set_capability("timeouts", {'implicit': 10000})
- cls.driver = webdriver.Remote(command_executor=f'http://127.0.0.1:{os.getenv("FLASK_PORT", "4723")}', options=options)
-
- def tearDown(self) -> None:
- """
- Take screenshot when the current test fails
- """
- if not self._outcome.result.wasSuccessful():
- self.driver.get_screenshot_as_file(f"failed_test_shot_ksplash_#{self.id()}.png")
-
- def test_1_bug494840_setStage(self) -> None:
- """
- Checks if the setStage method is ever called after starting plasma-ksplash-ready.service.
- """
- if os.getenv("TEST_WITH_KWIN_WAYLAND", "1") == "0":
- stages = ("wm", "kcminit", "ksmserver", "startPlasma", "desktop")
- else:
- stages = ("kcminit", "ksmserver", "startPlasma", "desktop")
-
- session_bus = Gio.bus_get_sync(Gio.BusType.SESSION)
- for stage in stages:
- message: Gio.DBusMessage = Gio.DBusMessage.new_method_call("org.kde.KSplash", "/KSplash", "org.kde.KSplash", "setStage")
- message.set_body(GLib.Variant("(s)", [stage]))
- session_bus.send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE, 3000)
-
- self.driver.find_element(AppiumBy.NAME, "Plasma made by KDE")
-
- with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir, "startkde", "systemd", "plasma-ksplash-ready.service.in"), encoding="utf-8") as handler:
- for line in handler:
- if line.startswith("ExecStart="):
- command = line.removeprefix("ExecStart=").strip().split(" ")
- subprocess.check_call(command, stdout=sys.stderr, stderr=sys.stderr)
- break
-
- success = False
- for _ in range(10):
- try:
- subprocess.check_call(["pidof", "ksplashqml"])
- except subprocess.CalledProcessError:
- success = True
- break
- time.sleep(1)
- self.assertTrue(success)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/ksplash/ksplashqml/splashapp.cpp b/ksplash/ksplashqml/splashapp.cpp
index b60a58724be..2262503b1c3 100644
--- a/ksplash/ksplashqml/splashapp.cpp
+++ b/ksplash/ksplashqml/splashapp.cpp
@@ -26,13 +26,12 @@
#define TEST_STEP_INTERVAL 2000
/**
- * There are 7 stages in ksplash
+ * There are 6 stages in ksplash
* - initial (from this class)
* - startPlasma (from startplasma)
* - kcminit
* - ksmserver
* - wm (for X11 from KWin, for Wayland from this class)
- * - ready (from plasma-session startup)
* - desktop (from shellcorona)
*/
@@ -114,7 +113,7 @@ void SplashApp::setStage(const QString &stage)
void SplashApp::setStage(int stage)
{
m_stage = stage;
- if (m_stage == 7) {
+ if (m_stage == 6) {
QGuiApplication::exit(EXIT_SUCCESS);
}
for (SplashWindow *w : std::as_const(m_windows)) {
diff --git a/startkde/plasma-session/startup.cpp b/startkde/plasma-session/startup.cpp
index a731c7b2791..0567e00881f 100644
--- a/startkde/plasma-session/startup.cpp
+++ b/startkde/plasma-session/startup.cpp
@@ -206,20 +206,9 @@ Startup::Startup(QObject *parent)
// app will be closed when all KJobs finish thanks to the QEventLoopLocker in each KJob
}
-void Startup::upAndRunning(const QString &msg)
-{
- QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"),
- QStringLiteral("/KSplash"),
- QStringLiteral("org.kde.KSplash"),
- QStringLiteral("setStage"));
- ksplashProgressMessage.setArguments(QList<QVariant>() << msg);
- QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage);
-}
-
void Startup::finishStartup()
{
qCDebug(PLASMA_SESSION) << "Finished";
- upAndRunning(QStringLiteral("ready"));
playStartupSound();
new SessionTrack(m_processes);
diff --git a/startkde/plasma-session/startup.h b/startkde/plasma-session/startup.h
index 6ef4fee9bdd..876a1439fce 100644
--- a/startkde/plasma-session/startup.h
+++ b/startkde/plasma-session/startup.h
@@ -20,7 +20,6 @@ class Startup : public QObject
Q_OBJECT
public:
Startup(QObject *parent);
- void upAndRunning(const QString &msg);
void finishStartup();
static Startup *self()
diff --git a/startkde/systemd/CMakeLists.txt b/startkde/systemd/CMakeLists.txt
index 2f5d30e8456..c3455ebae81 100644
--- a/startkde/systemd/CMakeLists.txt
+++ b/startkde/systemd/CMakeLists.txt
@@ -1,6 +1,3 @@
-ecm_install_configured_files(INPUT plasma-ksplash-ready.service.in @ONLY
- DESTINATION ${KDE_INSTALL_SYSTEMDUSERUNITDIR})
-
install(FILES plasma-core.target DESTINATION ${KDE_INSTALL_SYSTEMDUSERUNITDIR})
install(FILES plasma-workspace.target DESTINATION ${KDE_INSTALL_SYSTEMDUSERUNITDIR})
install(FILES plasma-workspace-wayland.target DESTINATION ${KDE_INSTALL_SYSTEMDUSERUNITDIR})
diff --git a/startkde/systemd/plasma-ksplash-ready.service.in b/startkde/systemd/plasma-ksplash-ready.service.in
deleted file mode 100644
index 1e903130a96..00000000000
--- a/startkde/systemd/plasma-ksplash-ready.service.in
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=KSplash "ready" Stage
-Wants=plasma-core.target
-After=plasma-core.target
-PartOf=graphical-session.target
-
-[Service]
-Type=oneshot
-ExecStart=dbus-send --session --reply-timeout=1 --type=method_call --dest=org.kde.KSplash /KSplash org.kde.KSplash.setStage string:ready
-Slice=session.slice
diff --git a/startkde/systemd/plasma-workspace.target b/startkde/systemd/plasma-workspace.target
index a9113f49112..4cc8d9330c3 100644
--- a/startkde/systemd/plasma-workspace.target
+++ b/startkde/systemd/plasma-workspace.target
@@ -6,7 +6,6 @@ Wants=plasma-restoresession.service
Wants=plasma-xembedsniproxy.service
Wants=plasma-gmenudbusmenuproxy.service
Wants=plasma-powerdevil.service
-Wants=plasma-ksplash-ready.service
Wants=plasma-polkit-agent.service
Wants=kde-baloo.service
Wants=plasma-foreground-booster.service
--
GitLab

View file

@ -0,0 +1,3 @@
Plasma 6.5.0:
Pr 460 https://invent.kde.org/plasma/spectacle/-/merge_requests/460

View file

@ -0,0 +1,228 @@
From 97f209559c00acc1ea6d0736bb318ac0254a3e37 Mon Sep 17 00:00:00 2001
From: Noah Davis <noahadvs@gmail.com>
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 <shortcut>%1</shortcut>.", 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 <noahadvs@gmail.com>
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