Desktop/kde: add patches
This commit is contained in:
parent
b6119bd2cc
commit
09d0847ea4
14 changed files with 2981 additions and 0 deletions
|
|
@ -5,3 +5,12 @@ Pr 5626 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5626
|
|||
Pr 5627 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5627
|
||||
Commit 8202ba92 https://invent.kde.org/plasma/plasma-workspace/-/commit/8202ba92b610c691b8bc6bab8ad5a1c3b9ac73da
|
||||
Part of https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5628, the other part got cherry picked on 6.4.2
|
||||
Pr 5657 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5657
|
||||
Pr 5734 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5734
|
||||
Depends on Pr 5609 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5609
|
||||
Pr 5746 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5746
|
||||
Pr 5782 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5782
|
||||
Pr 5678 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5678
|
||||
Depends on Pr 5673 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5673
|
||||
Pr 5788 https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5788
|
||||
Allows compiling on gcc 14 after applying pr 5678
|
||||
|
|
|
|||
456
roles/kde/patches/plasma-workspace/pr5609.patch
Normal file
456
roles/kde/patches/plasma-workspace/pr5609.patch
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
From 439b251bcb3ea24f52c052e7244fb7ced04503aa Mon Sep 17 00:00:00 2001
|
||||
From: Bohdan Onofriichuk <bogdan.onofriuchuk@gmail.com>
|
||||
Date: Thu, 19 Jun 2025 14:51:30 +0000
|
||||
Subject: [PATCH] applets/devicenotifier: port to plasma_add_applet
|
||||
|
||||
---
|
||||
applets/devicenotifier/CMakeLists.txt | 58 ++++++++++++++++---
|
||||
.../{plugin => }/actioninterface.cpp | 0
|
||||
.../{plugin => }/actioninterface.h | 0
|
||||
.../{plugin => }/actions/defaultaction.cpp | 0
|
||||
.../{plugin => }/actions/defaultaction.h | 0
|
||||
.../{plugin => }/actions/mountaction.cpp | 0
|
||||
.../{plugin => }/actions/mountaction.h | 0
|
||||
.../actions/mountandopenaction.cpp | 0
|
||||
.../{plugin => }/actions/mountandopenaction.h | 0
|
||||
.../actions/openwithfilemanageraction.cpp | 0
|
||||
.../actions/openwithfilemanageraction.h | 0
|
||||
.../{plugin => }/actions/unmountaction.cpp | 0
|
||||
.../{plugin => }/actions/unmountaction.h | 0
|
||||
.../{plugin => }/actionscontrol.cpp | 0
|
||||
.../{plugin => }/actionscontrol.h | 0
|
||||
.../{plugin => }/devicecontrol.cpp | 0
|
||||
.../{plugin => }/devicecontrol.h | 0
|
||||
.../{plugin => }/deviceerrormonitor_p.cpp | 0
|
||||
.../{plugin => }/deviceerrormonitor_p.h | 0
|
||||
.../{plugin => }/devicefiltercontrol.cpp | 0
|
||||
.../{plugin => }/devicefiltercontrol.h | 0
|
||||
.../{plugin => }/devicenotifications.notifyrc | 0
|
||||
.../{plugin => }/deviceserviceaction.cpp | 0
|
||||
.../{plugin => }/deviceserviceaction.h | 0
|
||||
.../{plugin => }/devicestatemonitor_p.cpp | 0
|
||||
.../{plugin => }/devicestatemonitor_p.h | 0
|
||||
.../{package/contents/config => }/main.xml | 0
|
||||
.../{package => }/metadata.json | 1 -
|
||||
applets/devicenotifier/plugin/CMakeLists.txt | 51 ----------------
|
||||
.../{plugin => }/predicatesmonitor_p.cpp | 0
|
||||
.../{plugin => }/predicatesmonitor_p.h | 0
|
||||
.../contents/ui => qml}/DeviceItem.qml | 22 ++++---
|
||||
.../ui => qml}/FullRepresentation.qml | 0
|
||||
.../{package/contents/ui => qml}/main.qml | 9 ++-
|
||||
.../{plugin => }/spacemonitor_p.cpp | 0
|
||||
.../{plugin => }/spacemonitor_p.h | 0
|
||||
36 files changed, 65 insertions(+), 76 deletions(-)
|
||||
rename applets/devicenotifier/{plugin => }/actioninterface.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actioninterface.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/defaultaction.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/defaultaction.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/mountaction.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/mountaction.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/mountandopenaction.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/mountandopenaction.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/openwithfilemanageraction.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/openwithfilemanageraction.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/unmountaction.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actions/unmountaction.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actionscontrol.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/actionscontrol.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/devicecontrol.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/devicecontrol.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/deviceerrormonitor_p.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/deviceerrormonitor_p.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/devicefiltercontrol.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/devicefiltercontrol.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/devicenotifications.notifyrc (100%)
|
||||
rename applets/devicenotifier/{plugin => }/deviceserviceaction.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/deviceserviceaction.h (100%)
|
||||
rename applets/devicenotifier/{plugin => }/devicestatemonitor_p.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/devicestatemonitor_p.h (100%)
|
||||
rename applets/devicenotifier/{package/contents/config => }/main.xml (100%)
|
||||
rename applets/devicenotifier/{package => }/metadata.json (99%)
|
||||
delete mode 100644 applets/devicenotifier/plugin/CMakeLists.txt
|
||||
rename applets/devicenotifier/{plugin => }/predicatesmonitor_p.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/predicatesmonitor_p.h (100%)
|
||||
rename applets/devicenotifier/{package/contents/ui => qml}/DeviceItem.qml (81%)
|
||||
rename applets/devicenotifier/{package/contents/ui => qml}/FullRepresentation.qml (100%)
|
||||
rename applets/devicenotifier/{package/contents/ui => qml}/main.qml (96%)
|
||||
rename applets/devicenotifier/{plugin => }/spacemonitor_p.cpp (100%)
|
||||
rename applets/devicenotifier/{plugin => }/spacemonitor_p.h (100%)
|
||||
|
||||
diff --git a/applets/devicenotifier/CMakeLists.txt b/applets/devicenotifier/CMakeLists.txt
|
||||
index bde4a38dd30..f336db13a69 100644
|
||||
--- a/applets/devicenotifier/CMakeLists.txt
|
||||
+++ b/applets/devicenotifier/CMakeLists.txt
|
||||
@@ -1,11 +1,55 @@
|
||||
-add_subdirectory(plugin)
|
||||
+# SPDX-FileCopyrightText: 2024 Fushan Wen <qydwhotmail@gmail.com>
|
||||
+# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
-ecm_qt_install_logging_categories(
|
||||
- EXPORT APPLETS::DEVICENOTIFIER
|
||||
- FILE applets/devicenotifier.categories
|
||||
- DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
|
||||
+add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.plasma.devicenotifier\")
|
||||
+
|
||||
+plasma_add_applet(org.kde.plasma.devicenotifier
|
||||
+ QML_SOURCES
|
||||
+ qml/DeviceItem.qml
|
||||
+ qml/FullRepresentation.qml
|
||||
+ qml/main.qml
|
||||
+ CPP_SOURCES
|
||||
+ actionscontrol.cpp
|
||||
+ devicecontrol.cpp
|
||||
+ spacemonitor_p.cpp
|
||||
+ devicestatemonitor_p.cpp
|
||||
+ deviceserviceaction.cpp
|
||||
+ predicatesmonitor_p.cpp
|
||||
+ deviceerrormonitor_p.cpp
|
||||
+ actioninterface.cpp
|
||||
+ devicefiltercontrol.cpp
|
||||
+ actions/defaultaction.cpp
|
||||
+ actions/mountandopenaction.cpp
|
||||
+ actions/mountaction.cpp
|
||||
+ actions/unmountaction.cpp
|
||||
+ actions/openwithfilemanageraction.cpp
|
||||
+ RESOURCES
|
||||
+ main.xml
|
||||
+ GENERATE_APPLET_CLASS
|
||||
+)
|
||||
+
|
||||
+target_link_libraries(org.kde.plasma.devicenotifier
|
||||
+ PRIVATE
|
||||
+ Qt::Qml
|
||||
+ Plasma::Plasma
|
||||
+ KF6::Solid
|
||||
+ KF6::I18n
|
||||
+ KF6::CoreAddons
|
||||
+ KF6::Service
|
||||
+ KF6::KIOCore
|
||||
+ KF6::KIOGui # KIO::CommandLauncherJob
|
||||
+ KF6::JobWidgets # KNotificationJobUiDelegate
|
||||
+ KSysGuard::ProcessCore
|
||||
+ KF6::Notifications
|
||||
)
|
||||
|
||||
-plasma_install_package(package org.kde.plasma.devicenotifier)
|
||||
+ecm_qt_declare_logging_category(org.kde.plasma.devicenotifier
|
||||
+ HEADER "devicenotifier_debug.h"
|
||||
+ IDENTIFIER "APPLETS::DEVICENOTIFIER"
|
||||
+ CATEGORY_NAME org.kde.applets.devicenotifier
|
||||
+ DEFAULT_SEVERITY Warning
|
||||
+ DESCRIPTION "Device Notifier applet" EXPORT "APPLETS::DEVICENOTIFIER"
|
||||
+)
|
||||
|
||||
-install(FILES openWithFileManager.desktop DESTINATION ${KDE_INSTALL_DATADIR}/solid/actions )
|
||||
+install(FILES devicenotifications.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
||||
+install(FILES openWithFileManager.desktop DESTINATION ${KDE_INSTALL_DATADIR}/solid/actions)
|
||||
diff --git a/applets/devicenotifier/plugin/actioninterface.cpp b/applets/devicenotifier/actioninterface.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actioninterface.cpp
|
||||
rename to applets/devicenotifier/actioninterface.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/actioninterface.h b/applets/devicenotifier/actioninterface.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actioninterface.h
|
||||
rename to applets/devicenotifier/actioninterface.h
|
||||
diff --git a/applets/devicenotifier/plugin/actions/defaultaction.cpp b/applets/devicenotifier/actions/defaultaction.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/defaultaction.cpp
|
||||
rename to applets/devicenotifier/actions/defaultaction.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/actions/defaultaction.h b/applets/devicenotifier/actions/defaultaction.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/defaultaction.h
|
||||
rename to applets/devicenotifier/actions/defaultaction.h
|
||||
diff --git a/applets/devicenotifier/plugin/actions/mountaction.cpp b/applets/devicenotifier/actions/mountaction.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/mountaction.cpp
|
||||
rename to applets/devicenotifier/actions/mountaction.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/actions/mountaction.h b/applets/devicenotifier/actions/mountaction.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/mountaction.h
|
||||
rename to applets/devicenotifier/actions/mountaction.h
|
||||
diff --git a/applets/devicenotifier/plugin/actions/mountandopenaction.cpp b/applets/devicenotifier/actions/mountandopenaction.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/mountandopenaction.cpp
|
||||
rename to applets/devicenotifier/actions/mountandopenaction.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/actions/mountandopenaction.h b/applets/devicenotifier/actions/mountandopenaction.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/mountandopenaction.h
|
||||
rename to applets/devicenotifier/actions/mountandopenaction.h
|
||||
diff --git a/applets/devicenotifier/plugin/actions/openwithfilemanageraction.cpp b/applets/devicenotifier/actions/openwithfilemanageraction.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/openwithfilemanageraction.cpp
|
||||
rename to applets/devicenotifier/actions/openwithfilemanageraction.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/actions/openwithfilemanageraction.h b/applets/devicenotifier/actions/openwithfilemanageraction.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/openwithfilemanageraction.h
|
||||
rename to applets/devicenotifier/actions/openwithfilemanageraction.h
|
||||
diff --git a/applets/devicenotifier/plugin/actions/unmountaction.cpp b/applets/devicenotifier/actions/unmountaction.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/unmountaction.cpp
|
||||
rename to applets/devicenotifier/actions/unmountaction.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/actions/unmountaction.h b/applets/devicenotifier/actions/unmountaction.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actions/unmountaction.h
|
||||
rename to applets/devicenotifier/actions/unmountaction.h
|
||||
diff --git a/applets/devicenotifier/plugin/actionscontrol.cpp b/applets/devicenotifier/actionscontrol.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actionscontrol.cpp
|
||||
rename to applets/devicenotifier/actionscontrol.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/actionscontrol.h b/applets/devicenotifier/actionscontrol.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/actionscontrol.h
|
||||
rename to applets/devicenotifier/actionscontrol.h
|
||||
diff --git a/applets/devicenotifier/plugin/devicecontrol.cpp b/applets/devicenotifier/devicecontrol.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/devicecontrol.cpp
|
||||
rename to applets/devicenotifier/devicecontrol.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/devicecontrol.h b/applets/devicenotifier/devicecontrol.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/devicecontrol.h
|
||||
rename to applets/devicenotifier/devicecontrol.h
|
||||
diff --git a/applets/devicenotifier/plugin/deviceerrormonitor_p.cpp b/applets/devicenotifier/deviceerrormonitor_p.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/deviceerrormonitor_p.cpp
|
||||
rename to applets/devicenotifier/deviceerrormonitor_p.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/deviceerrormonitor_p.h b/applets/devicenotifier/deviceerrormonitor_p.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/deviceerrormonitor_p.h
|
||||
rename to applets/devicenotifier/deviceerrormonitor_p.h
|
||||
diff --git a/applets/devicenotifier/plugin/devicefiltercontrol.cpp b/applets/devicenotifier/devicefiltercontrol.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/devicefiltercontrol.cpp
|
||||
rename to applets/devicenotifier/devicefiltercontrol.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/devicefiltercontrol.h b/applets/devicenotifier/devicefiltercontrol.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/devicefiltercontrol.h
|
||||
rename to applets/devicenotifier/devicefiltercontrol.h
|
||||
diff --git a/applets/devicenotifier/plugin/devicenotifications.notifyrc b/applets/devicenotifier/devicenotifications.notifyrc
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/devicenotifications.notifyrc
|
||||
rename to applets/devicenotifier/devicenotifications.notifyrc
|
||||
diff --git a/applets/devicenotifier/plugin/deviceserviceaction.cpp b/applets/devicenotifier/deviceserviceaction.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/deviceserviceaction.cpp
|
||||
rename to applets/devicenotifier/deviceserviceaction.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/deviceserviceaction.h b/applets/devicenotifier/deviceserviceaction.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/deviceserviceaction.h
|
||||
rename to applets/devicenotifier/deviceserviceaction.h
|
||||
diff --git a/applets/devicenotifier/plugin/devicestatemonitor_p.cpp b/applets/devicenotifier/devicestatemonitor_p.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/devicestatemonitor_p.cpp
|
||||
rename to applets/devicenotifier/devicestatemonitor_p.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/devicestatemonitor_p.h b/applets/devicenotifier/devicestatemonitor_p.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/devicestatemonitor_p.h
|
||||
rename to applets/devicenotifier/devicestatemonitor_p.h
|
||||
diff --git a/applets/devicenotifier/package/contents/config/main.xml b/applets/devicenotifier/main.xml
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/package/contents/config/main.xml
|
||||
rename to applets/devicenotifier/main.xml
|
||||
diff --git a/applets/devicenotifier/package/metadata.json b/applets/devicenotifier/metadata.json
|
||||
similarity index 99%
|
||||
rename from applets/devicenotifier/package/metadata.json
|
||||
rename to applets/devicenotifier/metadata.json
|
||||
index 0a330dfc189..77d7feac1cb 100644
|
||||
--- a/applets/devicenotifier/package/metadata.json
|
||||
+++ b/applets/devicenotifier/metadata.json
|
||||
@@ -115,7 +115,6 @@
|
||||
"desktop"
|
||||
],
|
||||
"Icon": "device-notifier",
|
||||
- "Id": "org.kde.plasma.devicenotifier",
|
||||
"License": "GPL-2.0+",
|
||||
"Name": "Disks & Devices",
|
||||
"Name[ar]": "الأجهزة والأقراص",
|
||||
diff --git a/applets/devicenotifier/plugin/CMakeLists.txt b/applets/devicenotifier/plugin/CMakeLists.txt
|
||||
deleted file mode 100644
|
||||
index 34a3456d690..00000000000
|
||||
--- a/applets/devicenotifier/plugin/CMakeLists.txt
|
||||
+++ /dev/null
|
||||
@@ -1,51 +0,0 @@
|
||||
-# SPDX-FileCopyrightText: 2024 Fushan Wen <qydwhotmail@gmail.com>
|
||||
-# SPDX-License-Identifier: BSD-3-Clause
|
||||
-
|
||||
-add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.plasma.devicenotifier\")
|
||||
-
|
||||
-ecm_add_qml_module(devicenotifierplugin URI org.kde.plasma.private.devicenotifier GENERATE_PLUGIN_SOURCE)
|
||||
-
|
||||
-target_sources(devicenotifierplugin
|
||||
- PRIVATE
|
||||
- actionscontrol.cpp actionscontrol.h
|
||||
- devicecontrol.cpp devicecontrol.h
|
||||
- spacemonitor_p.cpp spacemonitor_p.h
|
||||
- devicestatemonitor_p.cpp devicestatemonitor_p.h
|
||||
- deviceserviceaction.cpp deviceserviceaction.h
|
||||
- predicatesmonitor_p.cpp predicatesmonitor_p.h
|
||||
- deviceerrormonitor_p.cpp deviceerrormonitor_p.h
|
||||
- actioninterface.cpp actioninterface.h
|
||||
- devicefiltercontrol.cpp devicefiltercontrol.h
|
||||
- actions/defaultaction.cpp actions/defaultaction.h
|
||||
- actions/mountandopenaction.cpp actions/mountandopenaction.h
|
||||
- actions/mountaction.cpp actions/mountaction.h
|
||||
- actions/unmountaction.cpp actions/unmountaction.h
|
||||
- actions/openwithfilemanageraction.cpp actions/openwithfilemanageraction.h
|
||||
-)
|
||||
-
|
||||
-target_link_libraries(devicenotifierplugin
|
||||
- PRIVATE
|
||||
- Qt::Qml
|
||||
- Plasma::Plasma
|
||||
- KF6::Solid
|
||||
- KF6::I18n
|
||||
- KF6::CoreAddons
|
||||
- KF6::Service
|
||||
- KF6::KIOCore
|
||||
- KF6::KIOGui # KIO::CommandLauncherJob
|
||||
- KF6::JobWidgets # KNotificationJobUiDelegate
|
||||
- KSysGuard::ProcessCore
|
||||
- KF6::Notifications
|
||||
-)
|
||||
-
|
||||
-ecm_qt_declare_logging_category(devicenotifierplugin
|
||||
- HEADER "devicenotifier_debug.h"
|
||||
- IDENTIFIER "APPLETS::DEVICENOTIFIER"
|
||||
- CATEGORY_NAME org.kde.applets.devicenotifier
|
||||
- DEFAULT_SEVERITY Warning
|
||||
- DESCRIPTION "Device Notifier applet" EXPORT "APPLETS::DEVICENOTIFIER"
|
||||
-)
|
||||
-
|
||||
-ecm_finalize_qml_module(devicenotifierplugin)
|
||||
-
|
||||
-install(FILES devicenotifications.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
||||
diff --git a/applets/devicenotifier/plugin/predicatesmonitor_p.cpp b/applets/devicenotifier/predicatesmonitor_p.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/predicatesmonitor_p.cpp
|
||||
rename to applets/devicenotifier/predicatesmonitor_p.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/predicatesmonitor_p.h b/applets/devicenotifier/predicatesmonitor_p.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/predicatesmonitor_p.h
|
||||
rename to applets/devicenotifier/predicatesmonitor_p.h
|
||||
diff --git a/applets/devicenotifier/package/contents/ui/DeviceItem.qml b/applets/devicenotifier/qml/DeviceItem.qml
|
||||
similarity index 81%
|
||||
rename from applets/devicenotifier/package/contents/ui/DeviceItem.qml
|
||||
rename to applets/devicenotifier/qml/DeviceItem.qml
|
||||
index c19c9535b04..861996af45c 100644
|
||||
--- a/applets/devicenotifier/package/contents/ui/DeviceItem.qml
|
||||
+++ b/applets/devicenotifier/qml/DeviceItem.qml
|
||||
@@ -19,8 +19,6 @@ import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.kquickcontrolsaddons
|
||||
|
||||
-import org.kde.plasma.private.devicenotifier as DN
|
||||
-
|
||||
PlasmaExtras.ExpandableListItem {
|
||||
id: deviceItem
|
||||
|
||||
@@ -41,18 +39,18 @@ PlasmaExtras.ExpandableListItem {
|
||||
|
||||
property bool hasMessage: deviceItem.deviceErrorMessage !== ""
|
||||
|
||||
- property bool isFree: deviceItem.deviceOperationResult !== DN.DevicesStateMonitor.Working && deviceItem.deviceOperationResult !== DN.DevicesStateMonitor.Checking && deviceItem.deviceOperationResult !== DN.DevicesStateMonitor.Repairing && deviceItem.deviceOperationResult !== DN.DevicesStateMonitor.NotPresent && !(deviceItem.deviceMounted === false && deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Successful)
|
||||
+ property bool isFree: deviceItem.deviceOperationResult !== DevicesStateMonitor.Working && deviceItem.deviceOperationResult !== DevicesStateMonitor.Checking && deviceItem.deviceOperationResult !== DevicesStateMonitor.Repairing && deviceItem.deviceOperationResult !== DevicesStateMonitor.NotPresent && !(deviceItem.deviceMounted === false && deviceItem.deviceOperationResult === DevicesStateMonitor.Successful)
|
||||
|
||||
onDeviceOperationResultChanged: {
|
||||
if (!popupIconTimer.running) {
|
||||
- if (deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Working) {
|
||||
+ if (deviceItem.deviceOperationResult === DevicesStateMonitor.Working) {
|
||||
if(deviceMounted){
|
||||
unmountTimer.restart();
|
||||
}
|
||||
- } else if (deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Successful) {
|
||||
+ } else if (deviceItem.deviceOperationResult === DevicesStateMonitor.Successful) {
|
||||
devicenotifier.popupIcon = "dialog-ok"
|
||||
popupIconTimer.restart()
|
||||
- } else if (deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Unsuccessful) {
|
||||
+ } else if (deviceItem.deviceOperationResult === DevicesStateMonitor.Unsuccessful) {
|
||||
devicenotifier.popupIcon = "dialog-error"
|
||||
popupIconTimer.restart()
|
||||
}
|
||||
@@ -80,7 +78,7 @@ PlasmaExtras.ExpandableListItem {
|
||||
} else {
|
||||
return "emblem-error"
|
||||
}
|
||||
- } else if (deviceItem.deviceOperationResult !== DN.DevicesStateMonitor.Working && deviceItem.deviceEmblems[0]) {
|
||||
+ } else if (deviceItem.deviceOperationResult !== DevicesStateMonitor.Working && deviceItem.deviceEmblems[0]) {
|
||||
return deviceItem.deviceEmblems[0]
|
||||
} else {
|
||||
return ""
|
||||
@@ -93,16 +91,16 @@ PlasmaExtras.ExpandableListItem {
|
||||
if (deviceItem.hasMessage) {
|
||||
return deviceItem.deviceErrorMessage
|
||||
}
|
||||
- if (deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Checking) {
|
||||
+ if (deviceItem.deviceOperationResult === DevicesStateMonitor.Checking) {
|
||||
return i18nc("Accessing is a less technical word for Mounting; translation should be short and mean \'Currently mounting this device\'", "Checking…")
|
||||
- } else if (deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Repairing) {
|
||||
+ } else if (deviceItem.deviceOperationResult === DevicesStateMonitor.Repairing) {
|
||||
return i18nc("Accessing is a less technical word for Mounting; translation should be short and mean \'Currently mounting this device\'", "Repairing…")
|
||||
- } else if (deviceItem.deviceOperationResult !== DN.DevicesStateMonitor.Working) {
|
||||
+ } else if (deviceItem.deviceOperationResult !== DevicesStateMonitor.Working) {
|
||||
if (deviceItem.deviceFreeSpace > 0 && deviceItem.deviceSize > 0) {
|
||||
return i18nc("@info:status Free disk space", "%1 free of %2", deviceItem.deviceFreeSpaceText, deviceItem.deviceSizeText)
|
||||
}
|
||||
return ""
|
||||
- } else if (!deviceItem.deviceMounted && deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Working) {
|
||||
+ } else if (!deviceItem.deviceMounted && deviceItem.deviceOperationResult === DevicesStateMonitor.Working) {
|
||||
return i18nc("Accessing is a less technical word for Mounting; translation should be short and mean \'Currently mounting this device\'", "Accessing…")
|
||||
} else if (unmountTimer.running) {
|
||||
// Unmounting; shown if unmount takes less than 1 second
|
||||
@@ -139,7 +137,7 @@ PlasmaExtras.ExpandableListItem {
|
||||
}
|
||||
}
|
||||
|
||||
- isBusy: deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Working || deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Checking || deviceItem.deviceOperationResult === DN.DevicesStateMonitor.Repairing
|
||||
+ isBusy: deviceItem.deviceOperationResult === DevicesStateMonitor.Working || deviceItem.deviceOperationResult === DevicesStateMonitor.Checking || deviceItem.deviceOperationResult === DevicesStateMonitor.Repairing
|
||||
|
||||
customExpandedViewContent: deviceActions !== undefined && deviceActions.rowCount() !== 0 && isFree ? actionComponent : null
|
||||
|
||||
diff --git a/applets/devicenotifier/package/contents/ui/FullRepresentation.qml b/applets/devicenotifier/qml/FullRepresentation.qml
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/package/contents/ui/FullRepresentation.qml
|
||||
rename to applets/devicenotifier/qml/FullRepresentation.qml
|
||||
diff --git a/applets/devicenotifier/package/contents/ui/main.qml b/applets/devicenotifier/qml/main.qml
|
||||
similarity index 96%
|
||||
rename from applets/devicenotifier/package/contents/ui/main.qml
|
||||
rename to applets/devicenotifier/qml/main.qml
|
||||
index 4061480becc..7fcd76a6d16 100644
|
||||
--- a/applets/devicenotifier/package/contents/ui/main.qml
|
||||
+++ b/applets/devicenotifier/qml/main.qml
|
||||
@@ -15,21 +15,20 @@ import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.kcmutils // For KCMLauncher
|
||||
import org.kde.config // KAuthorized
|
||||
-import org.kde.plasma.private.devicenotifier as DN
|
||||
|
||||
PlasmoidItem {
|
||||
id: devicenotifier
|
||||
|
||||
- DN.DeviceFilterControl {
|
||||
+ DeviceFilterControl {
|
||||
id: filterModel
|
||||
|
||||
filterType: {
|
||||
if (Plasmoid.configuration.allDevices) {
|
||||
- return DN.DeviceFilterControl.All
|
||||
+ return DeviceFilterControl.All
|
||||
} else if (Plasmoid.configuration.removableDevices) {
|
||||
- return DN.DeviceFilterControl.Removable
|
||||
+ return DeviceFilterControl.Removable
|
||||
} else {
|
||||
- return DN.DeviceFilterControl.Unremovable
|
||||
+ return DeviceFilterControl.Unremovable
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/applets/devicenotifier/plugin/spacemonitor_p.cpp b/applets/devicenotifier/spacemonitor_p.cpp
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/spacemonitor_p.cpp
|
||||
rename to applets/devicenotifier/spacemonitor_p.cpp
|
||||
diff --git a/applets/devicenotifier/plugin/spacemonitor_p.h b/applets/devicenotifier/spacemonitor_p.h
|
||||
similarity index 100%
|
||||
rename from applets/devicenotifier/plugin/spacemonitor_p.h
|
||||
rename to applets/devicenotifier/spacemonitor_p.h
|
||||
--
|
||||
GitLab
|
||||
|
||||
177
roles/kde/patches/plasma-workspace/pr5657.patch
Normal file
177
roles/kde/patches/plasma-workspace/pr5657.patch
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
From aa1e466e5f7684a8b624c34d466dda9d10a331d2 Mon Sep 17 00:00:00 2001
|
||||
From: Nate Graham <nate@kde.org>
|
||||
Date: Sun, 6 Jul 2025 23:20:47 -0400
|
||||
Subject: [PATCH 1/2] Improve UX of USB plug/unplug notifications when popup is
|
||||
shown
|
||||
|
||||
1. When plugged or unplugged, revoke the opposite notification if it's
|
||||
visible.
|
||||
2. Set the urgency to low so it won't clutter up the notification
|
||||
history.
|
||||
---
|
||||
devicenotifications/devicenotifications.cpp | 55 ++++++++++++++++-----
|
||||
devicenotifications/devicenotifications.h | 5 ++
|
||||
2 files changed, 48 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/devicenotifications/devicenotifications.cpp b/devicenotifications/devicenotifications.cpp
|
||||
index cc462f58f5..f326691c11 100644
|
||||
--- a/devicenotifications/devicenotifications.cpp
|
||||
+++ b/devicenotifications/devicenotifications.cpp
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
+#include <knotification.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(KdedDeviceNotifications, "devicenotifications.json")
|
||||
@@ -375,13 +376,28 @@ void KdedDeviceNotifications::onDeviceAdded(const UdevDevice &device)
|
||||
return;
|
||||
}
|
||||
|
||||
- const QString text = !displayName.isEmpty() ? i18n("%1 has been plugged in.", displayName.toHtmlEscaped()) : i18n("A USB device has been plugged in.");
|
||||
+ // If the user unplugged something and then immediately plugged it in again,
|
||||
+ // there's no need to keep the unplug notification around.
|
||||
+ if (m_usbDeviceRemovedNotification) {
|
||||
+ m_usbDeviceRemovedNotification->close();
|
||||
+ }
|
||||
+
|
||||
+ // Only show one of these at a time. We already suppressed creating a bunch
|
||||
+ // in quick succession for the dock/hub use case, so any that are created
|
||||
+ // over that time limit anyway are not necessary to stack up.
|
||||
+ if (m_usbDeviceAddedNotification) {
|
||||
+ m_usbDeviceAddedNotification->close();
|
||||
+ }
|
||||
+
|
||||
+ const QString text = !displayName.isEmpty() ? i18n("%1 has been connected.", displayName.toHtmlEscaped()) : i18n("A USB device has been connected.");
|
||||
+
|
||||
+ m_usbDeviceAddedNotification = new KNotification(QStringLiteral("deviceAdded"));
|
||||
+ m_usbDeviceAddedNotification->setFlags(KNotification::DefaultEvent);
|
||||
+ m_usbDeviceAddedNotification->setIconName(QStringLiteral("drive-removable-media-usb"));
|
||||
+ m_usbDeviceAddedNotification->setTitle(i18nc("@title:notifications", "USB Device Detected"));
|
||||
+ m_usbDeviceAddedNotification->setText(text);
|
||||
+ m_usbDeviceAddedNotification->sendEvent();
|
||||
|
||||
- KNotification::event(QStringLiteral("deviceAdded"),
|
||||
- i18nc("@title:notifications", "USB Device Detected"),
|
||||
- text,
|
||||
- QStringLiteral("drive-removable-media-usb"),
|
||||
- KNotification::DefaultEvent);
|
||||
m_deviceAddedTimer.start();
|
||||
}
|
||||
|
||||
@@ -401,13 +417,28 @@ void KdedDeviceNotifications::onDeviceRemoved(const UdevDevice &device)
|
||||
return;
|
||||
}
|
||||
|
||||
- const QString text = !displayName.isEmpty() ? i18n("%1 has been unplugged.", displayName.toHtmlEscaped()) : i18n("A USB device has been unplugged.");
|
||||
+ // If the user plugged something in and then immediately unplugged it again,
|
||||
+ // there's no need to keep the plug notification around.
|
||||
+ if (m_usbDeviceAddedNotification) {
|
||||
+ m_usbDeviceAddedNotification->close();
|
||||
+ }
|
||||
+
|
||||
+ // Only show one of these at a time. We already suppressed removing a bunch
|
||||
+ // in quick succession for the dock/hub use case, so any that are removed
|
||||
+ // over that time limit anyway are not necessary to stack up.
|
||||
+ if (m_usbDeviceRemovedNotification) {
|
||||
+ m_usbDeviceRemovedNotification->close();
|
||||
+ }
|
||||
+
|
||||
+ const QString text = !displayName.isEmpty() ? i18n("%1 has been disconnected.", displayName.toHtmlEscaped()) : i18n("A USB device has been disconnected.");
|
||||
+
|
||||
+ m_usbDeviceRemovedNotification = new KNotification(QStringLiteral("deviceRemoved"));
|
||||
+ m_usbDeviceRemovedNotification->setFlags(KNotification::DefaultEvent);
|
||||
+ m_usbDeviceRemovedNotification->setIconName(QStringLiteral("drive-removable-media-usb"));
|
||||
+ m_usbDeviceRemovedNotification->setTitle(i18nc("@title:notifications", "USB Device Went Away"));
|
||||
+ m_usbDeviceRemovedNotification->setText(text);
|
||||
+ m_usbDeviceRemovedNotification->sendEvent();
|
||||
|
||||
- KNotification::event(QStringLiteral("deviceRemoved"),
|
||||
- i18nc("@title:notifications", "USB Device Removed"),
|
||||
- text,
|
||||
- QStringLiteral("drive-removable-media-usb"),
|
||||
- KNotification::DefaultEvent);
|
||||
m_deviceRemovedTimer.start();
|
||||
}
|
||||
|
||||
diff --git a/devicenotifications/devicenotifications.h b/devicenotifications/devicenotifications.h
|
||||
index 11334008b0..ab7e6b3ff9 100644
|
||||
--- a/devicenotifications/devicenotifications.h
|
||||
+++ b/devicenotifications/devicenotifications.h
|
||||
@@ -8,11 +8,13 @@
|
||||
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
+#include <QPointer>
|
||||
#include <QSocketNotifier>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
|
||||
#include <KDEDModule>
|
||||
+#include <KNotification>
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
@@ -98,4 +100,7 @@ private:
|
||||
|
||||
QTimer m_deviceAddedTimer;
|
||||
QTimer m_deviceRemovedTimer;
|
||||
+
|
||||
+ QPointer<KNotification> m_usbDeviceAddedNotification;
|
||||
+ QPointer<KNotification> m_usbDeviceRemovedNotification;
|
||||
};
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From 05f72383fd0b29105f3b5494759500d26b38ffc2 Mon Sep 17 00:00:00 2001
|
||||
From: Nate Graham <nate@kde.org>
|
||||
Date: Fri, 11 Jul 2025 11:25:23 -0600
|
||||
Subject: [PATCH 2/2] Delete closed notifications too
|
||||
|
||||
Closing is async; make sure we actually delete them when we want them
|
||||
gone.
|
||||
---
|
||||
devicenotifications/devicenotifications.cpp | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/devicenotifications/devicenotifications.cpp b/devicenotifications/devicenotifications.cpp
|
||||
index f326691c11..987d65d805 100644
|
||||
--- a/devicenotifications/devicenotifications.cpp
|
||||
+++ b/devicenotifications/devicenotifications.cpp
|
||||
@@ -380,6 +380,7 @@ void KdedDeviceNotifications::onDeviceAdded(const UdevDevice &device)
|
||||
// there's no need to keep the unplug notification around.
|
||||
if (m_usbDeviceRemovedNotification) {
|
||||
m_usbDeviceRemovedNotification->close();
|
||||
+ m_usbDeviceRemovedNotification = nullptr;
|
||||
}
|
||||
|
||||
// Only show one of these at a time. We already suppressed creating a bunch
|
||||
@@ -387,6 +388,7 @@ void KdedDeviceNotifications::onDeviceAdded(const UdevDevice &device)
|
||||
// over that time limit anyway are not necessary to stack up.
|
||||
if (m_usbDeviceAddedNotification) {
|
||||
m_usbDeviceAddedNotification->close();
|
||||
+ m_usbDeviceAddedNotification = nullptr;
|
||||
}
|
||||
|
||||
const QString text = !displayName.isEmpty() ? i18n("%1 has been connected.", displayName.toHtmlEscaped()) : i18n("A USB device has been connected.");
|
||||
@@ -421,6 +423,7 @@ void KdedDeviceNotifications::onDeviceRemoved(const UdevDevice &device)
|
||||
// there's no need to keep the plug notification around.
|
||||
if (m_usbDeviceAddedNotification) {
|
||||
m_usbDeviceAddedNotification->close();
|
||||
+ m_usbDeviceAddedNotification = nullptr;
|
||||
}
|
||||
|
||||
// Only show one of these at a time. We already suppressed removing a bunch
|
||||
@@ -428,6 +431,7 @@ void KdedDeviceNotifications::onDeviceRemoved(const UdevDevice &device)
|
||||
// over that time limit anyway are not necessary to stack up.
|
||||
if (m_usbDeviceRemovedNotification) {
|
||||
m_usbDeviceRemovedNotification->close();
|
||||
+ m_usbDeviceRemovedNotification = nullptr;
|
||||
}
|
||||
|
||||
const QString text = !displayName.isEmpty() ? i18n("%1 has been disconnected.", displayName.toHtmlEscaped()) : i18n("A USB device has been disconnected.");
|
||||
--
|
||||
2.51.0
|
||||
|
||||
392
roles/kde/patches/plasma-workspace/pr5673.patch
Normal file
392
roles/kde/patches/plasma-workspace/pr5673.patch
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
From 97c77a8e3259d77cb615dadd1c92185545513ebb Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Sun, 13 Jul 2025 16:06:08 +0200
|
||||
Subject: [PATCH 1/7] servicerunner: en_US spelling please
|
||||
|
||||
---
|
||||
runners/services/servicerunner.cpp | 14 +++++++-------
|
||||
runners/services/servicerunner.h | 4 ++--
|
||||
2 files changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index 454cf4e99f..357558a77d 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -296,7 +296,7 @@ private:
|
||||
relevance += .09;
|
||||
}
|
||||
|
||||
- if (const auto foundIt = m_runner->m_favourites.constFind(service->desktopEntryName()); foundIt != m_runner->m_favourites.cend()) {
|
||||
+ if (const auto foundIt = m_runner->m_favorites.constFind(service->desktopEntryName()); foundIt != m_runner->m_favorites.cend()) {
|
||||
if (foundIt->isGlobal || foundIt->linkedActivities.contains(m_currentActivity)) {
|
||||
qCDebug(RUNNER_SERVICES) << "entry is a favorite" << id << match.subtext() << relevance;
|
||||
relevance *= 1.25; // Give favorites a relative boost,
|
||||
@@ -423,7 +423,7 @@ ServiceRunner::ServiceRunner(QObject *parent, const KPluginMetaData &metaData)
|
||||
});
|
||||
|
||||
connect(&m_kactivitiesWatcher, &ResultWatcher::resultUnlinked, [this](QString resource) {
|
||||
- m_favourites.remove(resource.remove(".desktop"_L1));
|
||||
+ m_favorites.remove(resource.remove(".desktop"_L1));
|
||||
// In case it was only unlinked from one activity
|
||||
processActivitiesResults(ResultSet(m_kactivitiesQuery | Terms::Url::contains(resource)));
|
||||
});
|
||||
@@ -466,11 +466,11 @@ void ServiceRunner::processActivitiesResults(const ResultSet &results)
|
||||
const static QLatin1String applicationScheme("applications");
|
||||
for (const ResultSet::Result &result : results) {
|
||||
if (result.url().scheme() == applicationScheme) {
|
||||
- m_favourites.insert(result.url().path().remove(QLatin1String(".desktop")),
|
||||
- ActivityFavourite{
|
||||
- result.linkedActivities(),
|
||||
- result.linkedActivities().contains(globalActivity),
|
||||
- });
|
||||
+ m_favorites.insert(result.url().path().remove(QLatin1String(".desktop")),
|
||||
+ ActivityFavorite{
|
||||
+ result.linkedActivities(),
|
||||
+ result.linkedActivities().contains(globalActivity),
|
||||
+ });
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/runners/services/servicerunner.h b/runners/services/servicerunner.h
|
||||
index e0507ea459..571d22d90c 100644
|
||||
--- a/runners/services/servicerunner.h
|
||||
+++ b/runners/services/servicerunner.h
|
||||
@@ -33,11 +33,11 @@ public:
|
||||
void run(const KRunner::RunnerContext &context, const KRunner::QueryMatch &match) override;
|
||||
void init() override;
|
||||
|
||||
- struct ActivityFavourite {
|
||||
+ struct ActivityFavorite {
|
||||
QStringList linkedActivities;
|
||||
bool isGlobal;
|
||||
};
|
||||
- QMap<QString, ActivityFavourite> m_favourites;
|
||||
+ QMap<QString, ActivityFavorite> m_favorites;
|
||||
|
||||
protected:
|
||||
void setupMatch(const KService::Ptr &service, KRunner::QueryMatch &action);
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From 537d0cf67d600cb40636f9aaef7db6957f002eb2 Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Sun, 13 Jul 2025 16:06:50 +0200
|
||||
Subject: [PATCH 2/7] servicerunner: use designated initializers
|
||||
|
||||
makes code easier to read
|
||||
---
|
||||
runners/services/servicerunner.cpp | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index 357558a77d..2cade45b26 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -468,8 +468,8 @@ void ServiceRunner::processActivitiesResults(const ResultSet &results)
|
||||
if (result.url().scheme() == applicationScheme) {
|
||||
m_favorites.insert(result.url().path().remove(QLatin1String(".desktop")),
|
||||
ActivityFavorite{
|
||||
- result.linkedActivities(),
|
||||
- result.linkedActivities().contains(globalActivity),
|
||||
+ .linkedActivities = result.linkedActivities(),
|
||||
+ .isGlobal = result.linkedActivities().contains(globalActivity),
|
||||
});
|
||||
}
|
||||
}
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From 2c5eb156410c022a50a5b6e08a6abc454dd49b83 Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Sun, 13 Jul 2025 16:09:37 +0200
|
||||
Subject: [PATCH 3/7] servicerunner: use ranges algorithms
|
||||
|
||||
makes for nicer to read code
|
||||
---
|
||||
runners/services/servicerunner.cpp | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index 2cade45b26..87b38a2da3 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -46,15 +46,15 @@ int weightedLength(const QString &query)
|
||||
|
||||
inline bool contains(const QString &result, const QList<QStringView> &queryList)
|
||||
{
|
||||
- return std::all_of(queryList.cbegin(), queryList.cend(), [&result](QStringView query) {
|
||||
+ return std::ranges::all_of(queryList, [&result](QStringView query) {
|
||||
return result.contains(query, Qt::CaseInsensitive);
|
||||
});
|
||||
}
|
||||
|
||||
inline bool contains(const QStringList &results, const QList<QStringView> &queryList)
|
||||
{
|
||||
- return std::all_of(queryList.cbegin(), queryList.cend(), [&results](QStringView query) {
|
||||
- return std::any_of(results.cbegin(), results.cend(), [&query](QStringView result) {
|
||||
+ return std::ranges::all_of(queryList, [&results](QStringView query) {
|
||||
+ return std::ranges::any_of(results, [&query](QStringView result) {
|
||||
return result.contains(query, Qt::CaseInsensitive);
|
||||
});
|
||||
});
|
||||
@@ -327,7 +327,7 @@ private:
|
||||
setupMatch(service, match);
|
||||
|
||||
qreal relevance = 0.4;
|
||||
- if (std::any_of(categories.begin(), categories.end(), [this](const QString &category) {
|
||||
+ if (std::ranges::any_of(categories, [this](const QString &category) {
|
||||
return category.compare(query, Qt::CaseInsensitive) == 0;
|
||||
})) {
|
||||
relevance = 0.6;
|
||||
@@ -499,7 +499,7 @@ void ServiceRunner::run(const KRunner::RunnerContext & /*context*/, const KRunne
|
||||
job = new KIO::ApplicationLauncherJob(service);
|
||||
} else {
|
||||
const auto actions = service->actions();
|
||||
- auto it = std::find_if(actions.begin(), actions.end(), [&actionName](const KServiceAction &action) {
|
||||
+ auto it = std::ranges::find_if(actions, [&actionName](const KServiceAction &action) {
|
||||
return action.name() == actionName;
|
||||
});
|
||||
Q_ASSERT(it != actions.end());
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From 0599abb0af9d1da43d8067dd59b8afad7c7be9c6 Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Sun, 13 Jul 2025 16:11:05 +0200
|
||||
Subject: [PATCH 4/7] servicerunner: put helper functions into anon namespace
|
||||
|
||||
they are translation unit local after all
|
||||
---
|
||||
runners/services/servicerunner.cpp | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index 87b38a2da3..baef7ae50f 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "debug.h"
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
+namespace
|
||||
+{
|
||||
|
||||
int weightedLength(const QString &query)
|
||||
{
|
||||
@@ -60,6 +62,8 @@ inline bool contains(const QStringList &results, const QList<QStringView> &query
|
||||
});
|
||||
}
|
||||
|
||||
+} // namespace
|
||||
+
|
||||
/**
|
||||
* @brief Finds all KServices for a given runner query
|
||||
*/
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From 2f81c3ab0520729ed4f97d666b5c74258eed149b Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Sun, 13 Jul 2025 16:12:37 +0200
|
||||
Subject: [PATCH 5/7] servicerunner: typos--
|
||||
|
||||
---
|
||||
runners/services/autotests/servicerunnertest.cpp | 4 ++--
|
||||
runners/services/servicerunner.cpp | 10 +++++-----
|
||||
runners/services/servicerunner.h | 2 +-
|
||||
3 files changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/runners/services/autotests/servicerunnertest.cpp b/runners/services/autotests/servicerunnertest.cpp
|
||||
index ecb8a4816c..fcfd3275ac 100644
|
||||
--- a/runners/services/autotests/servicerunnertest.cpp
|
||||
+++ b/runners/services/autotests/servicerunnertest.cpp
|
||||
@@ -27,7 +27,7 @@ private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
- void testExcutableExactMatch();
|
||||
+ void testExecutableExactMatch();
|
||||
void testKonsoleVsYakuakeComment();
|
||||
void testSystemSettings();
|
||||
void testSystemSettings2();
|
||||
@@ -76,7 +76,7 @@ void ServiceRunnerTest::cleanupTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
-void ServiceRunnerTest::testExcutableExactMatch()
|
||||
+void ServiceRunnerTest::testExecutableExactMatch()
|
||||
{
|
||||
const auto matches = launchQuery(QStringLiteral("Virtual Machine Manager ServiceRunnerTest")); // virt-manager.desktop
|
||||
QVERIFY(std::any_of(matches.cbegin(), matches.cend(), [](const KRunner::QueryMatch &match) {
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index baef7ae50f..ced1b526ce 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -125,7 +125,7 @@ private:
|
||||
GenericName,
|
||||
Comment,
|
||||
};
|
||||
- qreal increaseMatchRelavance(const QString &serviceProperty, const QList<QStringView> &strList, Category category)
|
||||
+ qreal increaseMatchRelevance(const QString &serviceProperty, const QList<QStringView> &strList, Category category)
|
||||
{
|
||||
// Increment the relevance based on all the words (other than the first) of the query list
|
||||
qreal relevanceIncrement = 0;
|
||||
@@ -273,20 +273,20 @@ private:
|
||||
categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Highest;
|
||||
} else if (const int idx = name.indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
relevance = 0.8;
|
||||
- relevance += increaseMatchRelavance(name, queryList, Category::Name);
|
||||
+ relevance += increaseMatchRelevance(name, queryList, Category::Name);
|
||||
if (idx == 0) {
|
||||
relevance += 0.1;
|
||||
categoryRelevance = KRunner::QueryMatch::CategoryRelevance::High;
|
||||
}
|
||||
} else if (const int idx = service->genericName().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
relevance = 0.65;
|
||||
- relevance += increaseMatchRelavance(service->genericName(), queryList, Category::GenericName);
|
||||
+ relevance += increaseMatchRelevance(service->genericName(), queryList, Category::GenericName);
|
||||
if (idx == 0) {
|
||||
relevance += 0.05;
|
||||
}
|
||||
} else if (const int idx = service->comment().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
relevance = 0.5;
|
||||
- relevance += increaseMatchRelavance(service->comment(), queryList, Category::Comment);
|
||||
+ relevance += increaseMatchRelevance(service->comment(), queryList, Category::Comment);
|
||||
if (idx == 0) {
|
||||
relevance += 0.05;
|
||||
}
|
||||
@@ -481,7 +481,7 @@ void ServiceRunner::processActivitiesResults(const ResultSet &results)
|
||||
|
||||
void ServiceRunner::match(KRunner::RunnerContext &context)
|
||||
{
|
||||
- ServiceFinder finder(this, m_services, m_activitiesConsuer.currentActivity());
|
||||
+ ServiceFinder finder(this, m_services, m_activitiesConsumer.currentActivity());
|
||||
finder.match(context);
|
||||
}
|
||||
|
||||
diff --git a/runners/services/servicerunner.h b/runners/services/servicerunner.h
|
||||
index 571d22d90c..96a110789b 100644
|
||||
--- a/runners/services/servicerunner.h
|
||||
+++ b/runners/services/servicerunner.h
|
||||
@@ -46,7 +46,7 @@ private:
|
||||
void processActivitiesResults(const ResultSet &results);
|
||||
const Query m_kactivitiesQuery;
|
||||
const ResultWatcher m_kactivitiesWatcher;
|
||||
- const KActivities::Consumer m_activitiesConsuer;
|
||||
+ const KActivities::Consumer m_activitiesConsumer;
|
||||
QList<KService::Ptr> m_services;
|
||||
bool m_matching = false;
|
||||
};
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From d25a269e9dbf6209ae51f94c298cb1ef640b045c Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Sun, 13 Jul 2025 16:14:53 +0200
|
||||
Subject: [PATCH 6/7] servicerunner: don't narrow qsizetype to int
|
||||
|
||||
use auto instead since we don't actually care about their size anyway
|
||||
since we only perform trivial >=0 checks
|
||||
---
|
||||
runners/services/servicerunner.cpp | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index ced1b526ce..551717947f 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -206,7 +206,7 @@ private:
|
||||
static const auto specialArgs = {QStringLiteral("-qwindowtitle"), QStringLiteral("-qwindowicon"), QStringLiteral("--started-from-file")};
|
||||
|
||||
for (const auto &specialArg : specialArgs) {
|
||||
- int index = resultingArgs.indexOf(specialArg);
|
||||
+ auto index = resultingArgs.indexOf(specialArg);
|
||||
if (index > -1) {
|
||||
if (resultingArgs.count() > index) {
|
||||
resultingArgs.removeAt(index);
|
||||
@@ -271,20 +271,20 @@ private:
|
||||
} else if (name.compare(query, Qt::CaseInsensitive) == 0) {
|
||||
relevance = 1;
|
||||
categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Highest;
|
||||
- } else if (const int idx = name.indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
+ } else if (const auto idx = name.indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
relevance = 0.8;
|
||||
relevance += increaseMatchRelevance(name, queryList, Category::Name);
|
||||
if (idx == 0) {
|
||||
relevance += 0.1;
|
||||
categoryRelevance = KRunner::QueryMatch::CategoryRelevance::High;
|
||||
}
|
||||
- } else if (const int idx = service->genericName().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
+ } else if (const auto idx = service->genericName().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
relevance = 0.65;
|
||||
relevance += increaseMatchRelevance(service->genericName(), queryList, Category::GenericName);
|
||||
if (idx == 0) {
|
||||
relevance += 0.05;
|
||||
}
|
||||
- } else if (const int idx = service->comment().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
+ } else if (const auto idx = service->comment().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
relevance = 0.5;
|
||||
relevance += increaseMatchRelevance(service->comment(), queryList, Category::Comment);
|
||||
if (idx == 0) {
|
||||
@@ -364,7 +364,7 @@ private:
|
||||
}
|
||||
seen(action);
|
||||
|
||||
- const int matchIndex = action.text().indexOf(query, 0, Qt::CaseInsensitive);
|
||||
+ const auto matchIndex = action.text().indexOf(query, 0, Qt::CaseInsensitive);
|
||||
if (matchIndex < 0) {
|
||||
continue;
|
||||
}
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From 1a14af41b78a192d10fb5dcef93bba430872eab4 Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Sun, 13 Jul 2025 16:15:55 +0200
|
||||
Subject: [PATCH 7/7] servicerunner: remove inline noise
|
||||
|
||||
functions defined inside a definition are always inline
|
||||
---
|
||||
runners/services/servicerunner.cpp | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index 551717947f..eb9f02e74b 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -92,22 +92,22 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
- inline void seen(const KService::Ptr &service)
|
||||
+ void seen(const KService::Ptr &service)
|
||||
{
|
||||
m_seen.insert(service->exec());
|
||||
}
|
||||
|
||||
- inline void seen(const KServiceAction &action)
|
||||
+ void seen(const KServiceAction &action)
|
||||
{
|
||||
m_seen.insert(action.exec());
|
||||
}
|
||||
|
||||
- inline bool hasSeen(const KService::Ptr &service)
|
||||
+ bool hasSeen(const KService::Ptr &service)
|
||||
{
|
||||
return m_seen.contains(service->exec());
|
||||
}
|
||||
|
||||
- inline bool hasSeen(const KServiceAction &action)
|
||||
+ bool hasSeen(const KServiceAction &action)
|
||||
{
|
||||
return m_seen.contains(action.exec());
|
||||
}
|
||||
--
|
||||
2.51.0
|
||||
|
||||
913
roles/kde/patches/plasma-workspace/pr5678.9.patch
Normal file
913
roles/kde/patches/plasma-workspace/pr5678.9.patch
Normal file
|
|
@ -0,0 +1,913 @@
|
|||
From 312c215e717654e55fa48ec968f412201d2a5544 Mon Sep 17 00:00:00 2001
|
||||
From: Harald Sitter <sitter@kde.org>
|
||||
Date: Mon, 14 Jul 2025 17:28:14 +0200
|
||||
Subject: [PATCH] servicerunner: fuzzy match
|
||||
|
||||
use a bitap implementation instead of doing awkward contains dances.
|
||||
this should lead to somewhat more reliable results, which are now more
|
||||
comprehensively asserted in the unit test
|
||||
|
||||
at the heart of this is a new fuzzyScore function that assigns a score
|
||||
to a service vis a vis a query. this score is adjusted depending on
|
||||
which field it is regarding (name > genericname > keywords).
|
||||
this should hopefully ensure that a match against name outweighs most
|
||||
other matches. all scores are eventually assembled into a final score
|
||||
that gets used as match relevance
|
||||
---
|
||||
runners/services/autotests/CMakeLists.txt | 3 +
|
||||
runners/services/autotests/bitaptest.cpp | 70 +++++
|
||||
.../autotests/fixtures/audacity.desktop | 2 +-
|
||||
.../fixtures/org.kde.discover.desktop | 17 ++
|
||||
.../autotests/fixtures/org.kde.kpat.desktop | 2 +-
|
||||
.../services/autotests/servicerunnertest.cpp | 94 ++++--
|
||||
runners/services/bitap.h | 178 +++++++++++
|
||||
runners/services/levenshtein.h | 58 ++++
|
||||
runners/services/servicerunner.cpp | 286 +++++++++++-------
|
||||
9 files changed, 576 insertions(+), 134 deletions(-)
|
||||
create mode 100644 runners/services/autotests/bitaptest.cpp
|
||||
create mode 100755 runners/services/autotests/fixtures/org.kde.discover.desktop
|
||||
create mode 100644 runners/services/bitap.h
|
||||
create mode 100644 runners/services/levenshtein.h
|
||||
|
||||
diff --git a/runners/services/autotests/CMakeLists.txt b/runners/services/autotests/CMakeLists.txt
|
||||
index 04849a2928..ff7ec66634 100644
|
||||
--- a/runners/services/autotests/CMakeLists.txt
|
||||
+++ b/runners/services/autotests/CMakeLists.txt
|
||||
@@ -6,3 +6,6 @@ remove_definitions(-DQT_NO_CAST_FROM_ASCII)
|
||||
ecm_add_test(servicerunnertest.cpp TEST_NAME servicerunnertest
|
||||
LINK_LIBRARIES Qt::Test KF6::Service KF6::Runner)
|
||||
krunner_configure_test(servicerunnertest krunner_services)
|
||||
+
|
||||
+ecm_add_test(bitaptest.cpp TEST_NAME bitaptest
|
||||
+ LINK_LIBRARIES Qt::Test)
|
||||
diff --git a/runners/services/autotests/bitaptest.cpp b/runners/services/autotests/bitaptest.cpp
|
||||
new file mode 100644
|
||||
index 0000000000..1a1cb856ec
|
||||
--- /dev/null
|
||||
+++ b/runners/services/autotests/bitaptest.cpp
|
||||
@@ -0,0 +1,70 @@
|
||||
+// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
+// SPDX-FileCopyrightText: 2025 Harald Sitter <sitter@kde.org>
|
||||
+
|
||||
+#include <QDebug>
|
||||
+#include <QDir>
|
||||
+#include <QFile>
|
||||
+#include <QObject>
|
||||
+#include <QStandardPaths>
|
||||
+#include <QTest>
|
||||
+#include <QThread>
|
||||
+
|
||||
+#include "../bitap.h"
|
||||
+
|
||||
+class BitapTest : public QObject
|
||||
+{
|
||||
+ Q_OBJECT
|
||||
+private Q_SLOTS:
|
||||
+ void initTestCase()
|
||||
+ {
|
||||
+ }
|
||||
+ void cleanupTestCase()
|
||||
+ {
|
||||
+ }
|
||||
+
|
||||
+ void testBitap()
|
||||
+ {
|
||||
+ using namespace Bitap;
|
||||
+ // The macro has trouble with designated initializers, so we wrap them in ().
|
||||
+ QCOMPARE(bitap(u"hello world", u"hello", 1), (Match{.end = 4, .distance = 0}));
|
||||
+ QCOMPARE(bitap(u"wireshark", u"di", 1), (Match{.end = 1, .distance = 1}));
|
||||
+ QCOMPARE(bitap(u"discover", u"disk", 1), (Match{.end = 2, .distance = 1}));
|
||||
+ QCOMPARE(bitap(u"discover", u"disc", 1), (Match{.end = 3, .distance = 0}));
|
||||
+ QCOMPARE(bitap(u"discover", u"scov", 1), (Match{.end = 5, .distance = 0}));
|
||||
+ QCOMPARE(bitap(u"discover", u"diki", 1), std::nullopt);
|
||||
+ QCOMPARE(bitap(u"discover", u"obo", 1), std::nullopt);
|
||||
+ // With a hamming distance of 1 this may match because it is a single transposition.
|
||||
+ QCOMPARE(bitap(u"discover", u"dicsover", 1), (Match{.end = 7, .distance = 1}));
|
||||
+ // … but with three characters out of place things should not match.
|
||||
+ QCOMPARE(bitap(u"discover", u"dicosver", 1), std::nullopt);
|
||||
+ // pattern too long
|
||||
+ QCOMPARE(bitap(u"discover", u" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 1), std::nullopt);
|
||||
+ // This is not a transposition as per Damerau–Levenshtein distance because the characters are not adjacent.
|
||||
+ QCOMPARE(bitap(u"steam", u"skeap", 1), std::nullopt);
|
||||
+ // Deletion required
|
||||
+ QCOMPARE(bitap(u"discover", u"discover", 1), (Match{.end = 7, .distance = 0}));
|
||||
+ QCOMPARE(bitap(u"discover", u"discovery", 1), (Match{.end = 7, .distance = 1}));
|
||||
+ // Insertion required
|
||||
+ QCOMPARE(bitap(u"discover", u"dicover", 1), (Match{.end = 7, .distance = 1}));
|
||||
+ }
|
||||
+
|
||||
+ void testScore()
|
||||
+ {
|
||||
+ using namespace Bitap;
|
||||
+ // aperfectten has 10 big beautiful indexes. The maximum end is therefore 10.
|
||||
+ QCOMPARE(score(u"aperfectten", Match{.end = 10, .distance = 0}, 1), 1.0);
|
||||
+ QCOMPARE(score(u"aperfectten", Match{.end = 4, .distance = 0}, 1), 0.4);
|
||||
+ QCOMPARE(score(u"aperfectten", Match{.end = 4, .distance = 1}, 1), 0.35);
|
||||
+ QCOMPARE(score(u"aperfectten", Match{.end = 0, .distance = 0}, 0), 0);
|
||||
+ QCOMPARE(score(u"aperfectten", Match{.end = 0, .distance = 0}, 1), 0);
|
||||
+ QCOMPARE(score(u"aperfectten", Match{.end = 1, .distance = 1}, 1), 0.05);
|
||||
+
|
||||
+ QCOMPARE(score(u"abc", Match{.end = 2, .distance = 1}, 1), 0.95);
|
||||
+ // Ask for distance 0 but it has a distance so this is a super bad match.
|
||||
+ QCOMPARE(score(u"abc", Match{.end = 2, .distance = 1}, 0), 0);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+QTEST_MAIN(BitapTest)
|
||||
+
|
||||
+#include "bitaptest.moc"
|
||||
diff --git a/runners/services/autotests/fixtures/audacity.desktop b/runners/services/autotests/fixtures/audacity.desktop
|
||||
index 7613d9f32f..05e1b9d929 100644
|
||||
--- a/runners/services/autotests/fixtures/audacity.desktop
|
||||
+++ b/runners/services/autotests/fixtures/audacity.desktop
|
||||
@@ -1,5 +1,5 @@
|
||||
[Desktop Entry]
|
||||
-Name=Audacity
|
||||
+Name=Audacity ServiceRunnerTest
|
||||
GenericName=Sound Editor
|
||||
Comment=Record and edit audio files
|
||||
Keywords=audio;sound;alsa;jack;editor;
|
||||
diff --git a/runners/services/autotests/fixtures/org.kde.discover.desktop b/runners/services/autotests/fixtures/org.kde.discover.desktop
|
||||
new file mode 100755
|
||||
index 0000000000..978b2b4152
|
||||
--- /dev/null
|
||||
+++ b/runners/services/autotests/fixtures/org.kde.discover.desktop
|
||||
@@ -0,0 +1,17 @@
|
||||
+# SPDX-FileCopyrightText: None
|
||||
+# SPDX-License-Identifier: CC0-1.0
|
||||
+[Desktop Entry]
|
||||
+Name=Discover ServiceRunnerTest
|
||||
+Comment=Install and remove apps and add-ons
|
||||
+MimeType=application/vnd.flatpak;application/vnd.flatpak.repo;application/vnd.flatpak.ref;
|
||||
+Exec=plasma-discover %F
|
||||
+Icon=plasmadiscover
|
||||
+Type=Application
|
||||
+X-DocPath=plasma-discover/index.html
|
||||
+InitialPreference=5
|
||||
+NoDisplay=false
|
||||
+Actions=Updates;
|
||||
+SingleMainWindow=true
|
||||
+GenericName=Software Center
|
||||
+Categories=Qt;KDE;System;
|
||||
+Keywords=program;software;store;repository;package;add;install;uninstall;remove;update;apps;applications;games;flatpak;snap;addons;add-ons;firmware;
|
||||
diff --git a/runners/services/autotests/fixtures/org.kde.kpat.desktop b/runners/services/autotests/fixtures/org.kde.kpat.desktop
|
||||
index 71d7fd2a89..3a91d89afe 100644
|
||||
--- a/runners/services/autotests/fixtures/org.kde.kpat.desktop
|
||||
+++ b/runners/services/autotests/fixtures/org.kde.kpat.desktop
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-FileCopyrightText: 2022 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
[Desktop Entry]
|
||||
-Name=KPatience
|
||||
+Name=KPatience ServiceRunnerTest
|
||||
Exec=true -qwindowtitle %c %u
|
||||
Type=Application
|
||||
Icon=kpat
|
||||
diff --git a/runners/services/autotests/servicerunnertest.cpp b/runners/services/autotests/servicerunnertest.cpp
|
||||
index fcfd3275ac..b911667a3b 100644
|
||||
--- a/runners/services/autotests/servicerunnertest.cpp
|
||||
+++ b/runners/services/autotests/servicerunnertest.cpp
|
||||
@@ -36,6 +36,10 @@ private Q_SLOTS:
|
||||
void testINotifyUsage();
|
||||
void testSpecialArgs();
|
||||
void testEnv();
|
||||
+ void testDisassociation();
|
||||
+ void testMultipleKeywords();
|
||||
+ void testMultipleNameWords();
|
||||
+ void testDiscover();
|
||||
};
|
||||
|
||||
void ServiceRunnerTest::initTestCase()
|
||||
@@ -86,8 +90,8 @@ void ServiceRunnerTest::testExecutableExactMatch()
|
||||
|
||||
void ServiceRunnerTest::testKonsoleVsYakuakeComment()
|
||||
{
|
||||
- // Yakuake has konsole mentioned in comment, should be rated lower.
|
||||
- const auto matches = launchQuery(QStringLiteral("kons"));
|
||||
+ // Yakuake has konsole mentioned in comment, should not be listed (if it was it should be lower)
|
||||
+ auto matches = launchQueryAndSort(QStringLiteral("kons"));
|
||||
|
||||
bool konsoleFound = false;
|
||||
bool yakuakeFound = false;
|
||||
@@ -97,17 +101,10 @@ void ServiceRunnerTest::testKonsoleVsYakuakeComment()
|
||||
continue;
|
||||
}
|
||||
|
||||
- if (match.text() == QLatin1String("Konsole ServiceRunnerTest")) {
|
||||
- QCOMPARE(match.relevance(), 0.99);
|
||||
- konsoleFound = true;
|
||||
- } else if (match.text() == QLatin1String("Yakuake ServiceRunnerTest")) {
|
||||
- // Rates lower because it doesn't have it in the name.
|
||||
- QCOMPARE(match.relevance(), 0.59);
|
||||
- yakuakeFound = true;
|
||||
- }
|
||||
- }
|
||||
- QVERIFY(konsoleFound);
|
||||
- QVERIFY(yakuakeFound);
|
||||
+ QCOMPARE(texts,
|
||||
+ QStringList({
|
||||
+ u"Konsole ServiceRunnerTest"_s,
|
||||
+ }));
|
||||
}
|
||||
|
||||
void ServiceRunnerTest::testSystemSettings()
|
||||
@@ -150,8 +147,9 @@ void ServiceRunnerTest::testSystemSettings2()
|
||||
foreignSystemSettingsFound = true;
|
||||
}
|
||||
}
|
||||
- QVERIFY(systemSettingsFound);
|
||||
- QVERIFY(!foreignSystemSettingsFound);
|
||||
+
|
||||
+ // The matched texts will contain much more because of the generic search term. Make sure our settings win.
|
||||
+ QCOMPARE(texts.at(0), u"System Settings ServiceRunnerTest"_s);
|
||||
}
|
||||
|
||||
void ServiceRunnerTest::testCategories()
|
||||
@@ -172,10 +170,6 @@ void ServiceRunnerTest::testCategories()
|
||||
QVERIFY(std::none_of(matches.cbegin(), matches.cend(), [](const KRunner::QueryMatch &match) {
|
||||
return match.text() == QLatin1String("Konsole ServiceRunnerTest");
|
||||
}));
|
||||
-
|
||||
- // Query too short to match any category
|
||||
- matches = launchQuery(QStringLiteral("Dumm"));
|
||||
- QVERIFY(matches.isEmpty());
|
||||
}
|
||||
|
||||
void ServiceRunnerTest::testJumpListActions()
|
||||
@@ -234,6 +228,68 @@ void ServiceRunnerTest::testEnv()
|
||||
}));
|
||||
}
|
||||
|
||||
+void ServiceRunnerTest::testDisassociation()
|
||||
+{
|
||||
+ // This test makes sure that we do not associate a service with a query that is not relevant.
|
||||
+ auto matches = launchQueryAndSort(u"new laptop com"_s); // particularly notorious because it has two three letter words; 'com' is an incomplete word
|
||||
+
|
||||
+ QStringList texts;
|
||||
+ for (const auto &match : matches) {
|
||||
+ texts.push_back(match.text());
|
||||
+ }
|
||||
+
|
||||
+ QCOMPARE(texts, QStringList());
|
||||
+}
|
||||
+
|
||||
+void ServiceRunnerTest::testMultipleKeywords()
|
||||
+{
|
||||
+ auto matches = launchQueryAndSort(u"text editor programming"_s);
|
||||
+
|
||||
+ QStringList texts;
|
||||
+ for (const auto &match : matches) {
|
||||
+ texts.push_back(match.text());
|
||||
+ }
|
||||
+
|
||||
+ QCOMPARE(texts,
|
||||
+ QStringList({
|
||||
+ u"Kate ServiceRunnerTest"_s,
|
||||
+ }));
|
||||
+}
|
||||
+
|
||||
+void ServiceRunnerTest::testMultipleNameWords()
|
||||
+{
|
||||
+ auto matches = launchQueryAndSort(u"system settings"_s);
|
||||
+
|
||||
+ QStringList texts;
|
||||
+ for (const auto &match : matches) {
|
||||
+ if (!match.text().contains("ServiceRunnerTest"_L1)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ texts.push_back(match.text());
|
||||
+ }
|
||||
+
|
||||
+ QCOMPARE(texts,
|
||||
+ QStringList({
|
||||
+ u"System Settings ServiceRunnerTest"_s,
|
||||
+ }));
|
||||
+}
|
||||
+
|
||||
+void ServiceRunnerTest::testDiscover()
|
||||
+{
|
||||
+ auto matches = launchQueryAndSort(u"disco"_s);
|
||||
+
|
||||
+ QStringList texts;
|
||||
+ for (const auto &match : matches) {
|
||||
+ texts.push_back(match.text());
|
||||
+ }
|
||||
+
|
||||
+ qDebug() << texts;
|
||||
+ QCOMPARE(texts,
|
||||
+ QStringList({
|
||||
+ u"Discover ServiceRunnerTest"_s,
|
||||
+ }));
|
||||
+}
|
||||
+
|
||||
QTEST_MAIN(ServiceRunnerTest)
|
||||
|
||||
#include "servicerunnertest.moc"
|
||||
diff --git a/runners/services/bitap.h b/runners/services/bitap.h
|
||||
new file mode 100644
|
||||
index 0000000000..a6aedb7eaf
|
||||
--- /dev/null
|
||||
+++ b/runners/services/bitap.h
|
||||
@@ -0,0 +1,178 @@
|
||||
+// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
+// SPDX-FileCopyrightText: 2025 Harald Sitter <sitter@kde.org>
|
||||
+
|
||||
+#pragma once
|
||||
+
|
||||
+#include <bitset>
|
||||
+#include <optional>
|
||||
+
|
||||
+#include <QDebug>
|
||||
+#include <QLoggingCategory>
|
||||
+#include <QString>
|
||||
+
|
||||
+namespace Bitap
|
||||
+{
|
||||
+
|
||||
+Q_DECLARE_LOGGING_CATEGORY(BITAP)
|
||||
+Q_LOGGING_CATEGORY(BITAP, "org.kde.plasma.runner.services.bitap", QtWarningMsg)
|
||||
+
|
||||
+struct Match {
|
||||
+ qsizetype end;
|
||||
+ qsizetype distance;
|
||||
+
|
||||
+ bool operator==(const Match &other) const = default;
|
||||
+};
|
||||
+
|
||||
+inline QDebug operator<<(QDebug dbg, const Bitap::Match &match)
|
||||
+{
|
||||
+ dbg.nospace() << "Bitap::Match(" << match.end << ", " << match.distance << ")";
|
||||
+ return dbg;
|
||||
+}
|
||||
+
|
||||
+// Bitap is a bit of a complicated algorithm thanks to bitwise operations. I've opted to replace them with bitsets for readability.
|
||||
+// It creates a patternMask based on all characters in the pattern. Basically each character gets assigned a representative bit.
|
||||
+// e.g. in the pattern 'abc' the character 'a' would be 110, 'b' 101, 'c' 011.
|
||||
+// This is a bit expensive up front but allows it to carry out everything else using bitwise operations.
|
||||
+// For each match we set a matching bit in the bits vector.
|
||||
+// Matching happens within a hamming distance, meaning up to `hammingDistance` characters can be out of place.
|
||||
+inline std::optional<Match> bitap(const QStringView &name, const QStringView &pattern, int hammingDistance)
|
||||
+{
|
||||
+ qCDebug(BITAP) << "Bitap called with name:" << name << "and pattern:" << pattern << "with hamming distance:" << hammingDistance;
|
||||
+ const auto patternEndIndex = pattern.size() - 1;
|
||||
+ if (name == pattern) {
|
||||
+ return Match{.end = patternEndIndex, .distance = 0}; // Perfect match
|
||||
+ }
|
||||
+
|
||||
+ if (pattern.isEmpty() || name.isEmpty()) {
|
||||
+ return std::nullopt;
|
||||
+ }
|
||||
+
|
||||
+ // Being a bitset we could have any number of bits, but practically we probably don't need more than 64, most bitaps I've seen even use 32.
|
||||
+ constexpr auto maxMaskBits = 64;
|
||||
+ using Mask = std::bitset<maxMaskBits>;
|
||||
+ using PatternMask = std::array<Mask, std::numeric_limits<char16_t>::max()>;
|
||||
+
|
||||
+ // The way bitap works is that each bit of the Mask represents a character position. Because of this we cannot match
|
||||
+ // more characters than we have bits for.
|
||||
+ // -1 because one bit is used for the result (I think)
|
||||
+ if (pattern.size() >= qsizetype(Mask().size()) - 1) {
|
||||
+ qCWarning(BITAP) << "Pattern is too long for bitap algorithm, max length is" << Mask().size() - 1;
|
||||
+ return std::nullopt;
|
||||
+ }
|
||||
+
|
||||
+ const PatternMask patternMask = [&pattern, &name] {
|
||||
+ PatternMask patternMask;
|
||||
+ // The following is an optimized version of patternMask.fill(Mask().set()); to set all **necessary** bits to 1.
|
||||
+ for (const auto &qchar : pattern) {
|
||||
+ patternMask.at(qchar.unicode()).set();
|
||||
+ }
|
||||
+ for (const auto &qchar : name) {
|
||||
+ patternMask.at(qchar.unicode()).set();
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < pattern.size(); ++i) {
|
||||
+ const auto char_ = pattern.at(i).unicode();
|
||||
+ patternMask.at(char_).reset(i); // unset the relevant index bits
|
||||
+ }
|
||||
+
|
||||
+ if (BITAP().isDebugEnabled()) {
|
||||
+ for (const auto &i : pattern) {
|
||||
+ const auto char_ = i.unicode();
|
||||
+ qCDebug(BITAP) << "Pattern mask for" << char_ << "is" << patternMask.at(char_).to_string();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return patternMask;
|
||||
+ }();
|
||||
+
|
||||
+ Match match{
|
||||
+ .end = -1, // -1 means no match found for convenience
|
||||
+ .distance = name.size(),
|
||||
+ };
|
||||
+
|
||||
+ std::vector<Mask> bits((hammingDistance + 1), Mask().set().reset(0));
|
||||
+ std::vector<Mask> transpositions(bits.cbegin(), bits.cend());
|
||||
+ for (int i = 0; i < name.size(); ++i) {
|
||||
+ const auto &char_ = name.at(i);
|
||||
+ auto previousBit = bits[0];
|
||||
+ const auto mask = patternMask.at(char_.unicode());
|
||||
+ bits[0] |= mask;
|
||||
+ bits[0] <<= 1;
|
||||
+
|
||||
+ for (int j = 1; j <= hammingDistance; ++j) {
|
||||
+ auto bit = bits[j];
|
||||
+ auto current = (bit | mask) << 1;
|
||||
+ // https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
|
||||
+ auto substitute = previousBit << 1;
|
||||
+ auto delete_ = bits[j - 1] << 1;
|
||||
+ auto insert = previousBit;
|
||||
+ auto transpose = (transpositions[j - 1] | (mask << 1)) << 1;
|
||||
+ bits[j] = current & substitute & transpose & delete_ & insert;
|
||||
+ transpositions[j - 1] = (previousBit << 1) | mask;
|
||||
+ previousBit = bit;
|
||||
+ }
|
||||
+
|
||||
+ if (BITAP().isDebugEnabled()) {
|
||||
+ qCDebug(BITAP) << "After processing character" << char_ << "at index" << i;
|
||||
+ for (const auto &bit : bits) {
|
||||
+ qCDebug(BITAP) << "bit" << bit.to_string();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (int k = 0; k <= hammingDistance; ++k) {
|
||||
+ // If the bit at the end of the mask is 0, it means we have a match.
|
||||
+ if (0 == (bits[k] & Mask().set(pattern.size()))) {
|
||||
+ if (k < match.distance && match.end < i) {
|
||||
+ qCDebug(BITAP) << "Match found at index" << i << "with hamming distance" << k << "better than previous match with distance"
|
||||
+ << match.distance << "at index" << match.end;
|
||||
+ match = {
|
||||
+ .end = i,
|
||||
+ .distance = k,
|
||||
+ };
|
||||
+ }
|
||||
+ // We do not return early because we want to find the best match, not just any.
|
||||
+ // e.g. with a maximum distance of 1 `disc` could match `disc` either at index two with distance one, or at index three with distance zero.
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Because we use a complete Damerau–Levenshtein distance the return value is a bit complicated. The trick is that the distance incurs a negative penalty
|
||||
+ // in relation to the max distance. While an end that is closer to the real end is generally favorably. Combining the two into a single value
|
||||
+ // would complicate the meaning of the return value to mean "approximate end with random penalty". This is garbage to reason about so instead we return
|
||||
+ // both values and then assign them meaning in the score function.
|
||||
+ if (match.end != -1) {
|
||||
+ return match;
|
||||
+ }
|
||||
+
|
||||
+ qCDebug(BITAP) << "No match found for pattern" << pattern << "in name" << name;
|
||||
+ return std::nullopt;
|
||||
+}
|
||||
+
|
||||
+inline qreal score(const QStringView &name, const auto &match, auto hammingDistance)
|
||||
+{
|
||||
+ // Normalize the score to a value between 0.0 and 1.0
|
||||
+ // No distance means the score is directly correlated to the end index. The more characters matched the higher the score.
|
||||
+ // Any distance will lower the score by a sub 0.1 margin.
|
||||
+
|
||||
+ if (name.size() == 0) {
|
||||
+ return 0.0; // No name, no score.
|
||||
+ }
|
||||
+
|
||||
+ const auto maxEnd = name.size() - 1;
|
||||
+ const auto penalty = [&] {
|
||||
+ if (hammingDistance <= 0) {
|
||||
+ return 1.0; // No penalty for no distance
|
||||
+ }
|
||||
+ constexpr auto tenth = 10.0;
|
||||
+ constexpr auto half = 2.0;
|
||||
+ return qreal(match.distance) / qreal(hammingDistance) / tenth / half;
|
||||
+ }();
|
||||
+ auto score = qreal(match.end) / qreal(maxEnd);
|
||||
+ // Prevent underflows when the penalty is larger than the score.
|
||||
+ score = std::max(0.0, score - penalty);
|
||||
+
|
||||
+ Q_ASSERT(score >= 0.0 && score <= 1.0);
|
||||
+ return score;
|
||||
+}
|
||||
+
|
||||
+} // namespace Bitap
|
||||
diff --git a/runners/services/levenshtein.h b/runners/services/levenshtein.h
|
||||
new file mode 100644
|
||||
index 0000000000..0efb960be3
|
||||
--- /dev/null
|
||||
+++ b/runners/services/levenshtein.h
|
||||
@@ -0,0 +1,58 @@
|
||||
+// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
+// SPDX-FileCopyrightText: 2025 Harald Sitter <sitter@kde.org>
|
||||
+
|
||||
+#pragma
|
||||
+
|
||||
+#include <QLoggingCategory>
|
||||
+#include <QString>
|
||||
+
|
||||
+namespace Levenshtein
|
||||
+{
|
||||
+
|
||||
+inline int distance(const QStringView &name, const QStringView &query)
|
||||
+{
|
||||
+ if (name == query) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ std::vector<int> distance0(query.size() + 1, 0);
|
||||
+ std::vector<int> distance1(query.size() + 1, 0);
|
||||
+
|
||||
+ for (int i = 0; i <= query.size(); ++i) {
|
||||
+ distance0[i] = i;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < name.size(); ++i) {
|
||||
+ distance1[0] = i + 1;
|
||||
+ for (int j = 0; j < query.size(); ++j) {
|
||||
+ const auto deletionCost = distance0[j + 1] + 1;
|
||||
+ const auto insertionCost = distance1[j] + 1;
|
||||
+ const auto substitutionCost = [&] {
|
||||
+ if (name[i] == query[j]) {
|
||||
+ return distance0[j];
|
||||
+ }
|
||||
+ return distance0[j] + 1;
|
||||
+ }();
|
||||
+ distance1[j + 1] = std::min({deletionCost, insertionCost, substitutionCost});
|
||||
+ }
|
||||
+ std::swap(distance0, distance1);
|
||||
+ }
|
||||
+ return distance0[query.size()];
|
||||
+}
|
||||
+
|
||||
+inline qreal score(const QStringView &name, int distance)
|
||||
+{
|
||||
+ // Normalize the distance to a value between 0.0 and 1.0
|
||||
+ // The maximum distance is the length of the pattern.
|
||||
+ // If the distance is 0, it means a perfect match, so we return 1.0.
|
||||
+ // If the distance is equal to the length of the pattern, we return 0.0.
|
||||
+ if (distance == 0) {
|
||||
+ return 1.0;
|
||||
+ }
|
||||
+ if (distance >= name.size()) {
|
||||
+ return 0.0;
|
||||
+ }
|
||||
+ return 1.0 - (qreal(distance) / qreal(name.size()));
|
||||
+}
|
||||
+
|
||||
+} // namespace Levenshtein
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index eb9f02e74b..3d5de8feb2 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006 Aaron Seigo <aseigo@kde.org>
|
||||
SPDX-FileCopyrightText: 2014 Vishesh Handa <vhanda@kde.org>
|
||||
- SPDX-FileCopyrightText: 2016-2020 Harald Sitter <sitter@kde.org>
|
||||
+ SPDX-FileCopyrightText: 2016-2025 Harald Sitter <sitter@kde.org>
|
||||
SPDX-FileCopyrightText: 2022-2023 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include <KApplicationTrader>
|
||||
+#include <KFuzzyMatcher>
|
||||
#include <KLocalizedString>
|
||||
#include <KNotificationJobUiDelegate>
|
||||
#include <KServiceAction>
|
||||
@@ -35,22 +36,130 @@
|
||||
#include <KIO/ApplicationLauncherJob>
|
||||
#include <KIO/DesktopExecParser>
|
||||
|
||||
+#include "bitap.h"
|
||||
#include "debug.h"
|
||||
+#include "levenshtein.h"
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
namespace
|
||||
{
|
||||
|
||||
-int weightedLength(const QString &query)
|
||||
+struct Score {
|
||||
+ qreal value = 0.0; // The final score, it is the sum of all scores.
|
||||
+ KRunner::QueryMatch::CategoryRelevance categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Lowest; // The category relevance of the match.
|
||||
+};
|
||||
+
|
||||
+struct ScoreCard {
|
||||
+ Bitap::Match bitap;
|
||||
+ qreal bitapScore;
|
||||
+ int levenshtein;
|
||||
+ qreal levenshteinScore;
|
||||
+};
|
||||
+
|
||||
+QDebug operator<<(QDebug dbg, const ScoreCard &card)
|
||||
{
|
||||
- return KStringHandler::logicalLength(query);
|
||||
+ dbg.nospace() << "Scorecard(" << "bitap: " << card.bitap << ", bitapScore: " << card.bitapScore << ", levenshtein: " << card.levenshtein
|
||||
+ << ", levenshteinScore: " << card.levenshteinScore << ")";
|
||||
+ return dbg;
|
||||
}
|
||||
|
||||
-inline bool contains(const QString &result, const QList<QStringView> &queryList)
|
||||
+using ScoreCards = std::vector<ScoreCard>;
|
||||
+
|
||||
+struct WeightedScoreCard {
|
||||
+ ScoreCards cards;
|
||||
+ qreal weight;
|
||||
+};
|
||||
+
|
||||
+QDebug operator<<(QDebug dbg, const WeightedScoreCard &card)
|
||||
{
|
||||
- return std::ranges::all_of(queryList, [&result](QStringView query) {
|
||||
- return result.contains(query, Qt::CaseInsensitive);
|
||||
- });
|
||||
+
|
||||
+ dbg.nospace() << "WeightedCard[";
|
||||
+ for (const auto &scoreCard : card.cards) {
|
||||
+ dbg.nospace() << scoreCard;
|
||||
+ if (&scoreCard != &card.cards.back()) {
|
||||
+ dbg.nospace() << ", ";
|
||||
+ }
|
||||
+ }
|
||||
+ dbg.nospace() << "]";
|
||||
+ return dbg;
|
||||
+}
|
||||
+
|
||||
+auto makeScores(const auto ¬NormalizedString, const auto &queryList) {
|
||||
+ if (notNormalizedString.isEmpty()) {
|
||||
+ return ScoreCards{}; // No string, no score.
|
||||
+ }
|
||||
+
|
||||
+ const auto string = notNormalizedString.toLower();
|
||||
+
|
||||
+ ScoreCards cards;
|
||||
+ for (const auto &queryItem : queryList) {
|
||||
+ constexpr auto maxDistance = 1;
|
||||
+ const auto bitap = Bitap::bitap(string, queryItem, maxDistance);
|
||||
+ if (!bitap) {
|
||||
+ // One of the query items didn't match. This means the entire query is not a match
|
||||
+ return ScoreCards{};
|
||||
+ }
|
||||
+
|
||||
+ const auto bitapScore = Bitap::score(string, bitap.value(), maxDistance);
|
||||
+
|
||||
+ // Mind that we give different levels of bonus. This is important to imply ordering within competing matches of the same "type".
|
||||
+ // If we perfectly match that gives a bonus for not requiring any changes.
|
||||
+ const auto noSubstitionBonus = Bitap::score(string, bitap.value(), 0) == 1.0 ? 4.0 : 1.0;
|
||||
+ // If we match the entire length of the string that gets a bonus (disregarding distance, that was considered above).
|
||||
+ const auto completeMatchBonus = bitap->end >= (queryItem.size() - 1) ? 3.0 : 1.0;
|
||||
+ // If the string starts with the query item that gets a bonus.
|
||||
+ const auto startsWithBonus = (string.startsWith(queryItem, Qt::CaseInsensitive)) ? 2.0 : 1.0;
|
||||
+
|
||||
+ // Also consider the distance between the input and the query item.
|
||||
+ // If one is "yolotrollingservice" and the other is "yolo" then we must consider them worse matches than say "yolotroll".
|
||||
+ const auto levenshtein = Levenshtein::distance(string, queryItem);
|
||||
+
|
||||
+ cards.emplace_back(ScoreCard{
|
||||
+ .bitap = *bitap,
|
||||
+ .bitapScore = bitapScore + completeMatchBonus + noSubstitionBonus + startsWithBonus,
|
||||
+ .levenshtein = levenshtein,
|
||||
+ .levenshteinScore = Levenshtein::score(string, levenshtein),
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ return cards;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+auto makeScoreFromList(const auto &queryList, const QStringList &strings) {
|
||||
+ // This turns the loop inside out. For every query item we must find a match in our keywords or we discard
|
||||
+ ScoreCards cards;
|
||||
+ // e.g. text,editor,programming
|
||||
+ for (const auto &queryItem : queryList) {
|
||||
+ // e.g. text;txt;editor;programming;programmer;development;developer;code;
|
||||
+ auto found = false;
|
||||
+ ScoreCards queryCards;
|
||||
+ for (const auto &string : strings) {
|
||||
+ auto stringCards = makeScores(string, QList{queryItem});
|
||||
+ if (stringCards.empty()) {
|
||||
+ continue; // The combination didn't match.
|
||||
+ }
|
||||
+ for (auto &scoreCard : stringCards) {
|
||||
+ if (scoreCard.levenshteinScore < 0.8) {
|
||||
+ continue; // Not a good match, skip it. We are very strict with keywords
|
||||
+ }
|
||||
+ found = true;
|
||||
+ queryCards.append_range(stringCards);
|
||||
+ }
|
||||
+ // We do not break because other string might also match, improving the score.
|
||||
+ }
|
||||
+ if (!found) {
|
||||
+ // No item in strings matched the query item. This means the entire query is not a match.
|
||||
+ return ScoreCards{};
|
||||
+ }
|
||||
+ cards.append_range(queryCards);
|
||||
+ }
|
||||
+ return cards;
|
||||
+};
|
||||
+
|
||||
+int weightedLength(const QString &query)
|
||||
+{
|
||||
+ return KStringHandler::logicalLength(query);
|
||||
}
|
||||
|
||||
inline bool contains(const QStringList &results, const QList<QStringView> &queryList)
|
||||
@@ -79,7 +188,7 @@ public:
|
||||
|
||||
void match(KRunner::RunnerContext &context)
|
||||
{
|
||||
- query = context.query();
|
||||
+ query = context.query().toLower();
|
||||
// Splitting the query term to match using subsequences
|
||||
queryList = QStringView(query).split(QLatin1Char(' '));
|
||||
weightedTermLength = weightedLength(query);
|
||||
@@ -120,36 +229,6 @@ private:
|
||||
return ret;
|
||||
}
|
||||
|
||||
- enum class Category {
|
||||
- Name,
|
||||
- GenericName,
|
||||
- Comment,
|
||||
- };
|
||||
- qreal increaseMatchRelevance(const QString &serviceProperty, const QList<QStringView> &strList, Category category)
|
||||
- {
|
||||
- // Increment the relevance based on all the words (other than the first) of the query list
|
||||
- qreal relevanceIncrement = 0;
|
||||
-
|
||||
- for (int i = 1; i < strList.size(); ++i) {
|
||||
- const auto &str = strList.at(i);
|
||||
- if (category == Category::Name) {
|
||||
- if (serviceProperty.contains(str, Qt::CaseInsensitive)) {
|
||||
- relevanceIncrement += 0.01;
|
||||
- }
|
||||
- } else if (category == Category::GenericName) {
|
||||
- if (serviceProperty.contains(str, Qt::CaseInsensitive)) {
|
||||
- relevanceIncrement += 0.01;
|
||||
- }
|
||||
- } else if (category == Category::Comment) {
|
||||
- if (serviceProperty.contains(str, Qt::CaseInsensitive)) {
|
||||
- relevanceIncrement += 0.01;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return relevanceIncrement;
|
||||
- }
|
||||
-
|
||||
void setupMatch(const KService::Ptr &service, KRunner::QueryMatch &match)
|
||||
{
|
||||
const QString name = service->name();
|
||||
@@ -219,96 +298,77 @@ private:
|
||||
return resultingArgs.join(QLatin1Char(' '));
|
||||
}
|
||||
|
||||
- void matchNameKeywordAndGenericName()
|
||||
+ [[nodiscard]] std::optional<Score> fuzzyScore(KService::Ptr service)
|
||||
{
|
||||
- const auto nameKeywordAndGenericNameFilter = [this](const KService::Ptr &service) {
|
||||
- // Name
|
||||
- if (contains(service->name(), queryList)) {
|
||||
- return true;
|
||||
- }
|
||||
- // If the term length is < 3, no real point searching the untranslated Name, Keywords and GenericName
|
||||
- if (weightedTermLength < 3) {
|
||||
- return false;
|
||||
- }
|
||||
- if (contains(service->untranslatedName(), queryList)) {
|
||||
- return true;
|
||||
- }
|
||||
+ if (queryList.isEmpty()) {
|
||||
+ return std::nullopt; // No query, no score.
|
||||
+ }
|
||||
+
|
||||
+ const auto name = service->name();
|
||||
+ if (name.compare(query, Qt::CaseInsensitive) == 0) {
|
||||
+ // Absolute match. Can't get any better than this.
|
||||
+ return Score{.value = std::numeric_limits<decltype(Score::value)>::max(), .categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Highest};
|
||||
+ }
|
||||
|
||||
- // Keywords
|
||||
- if (contains(service->keywords(), queryList)) {
|
||||
- return true;
|
||||
+ std::array<WeightedScoreCard, 4> weightedCards = {
|
||||
+ WeightedScoreCard{.cards = makeScores(name, queryList), .weight = 1.0},
|
||||
+ WeightedScoreCard{.cards = makeScores(service->untranslatedName(), queryList), .weight = 0.8},
|
||||
+ WeightedScoreCard{.cards = makeScores(service->genericName(), queryList), .weight = 0.6},
|
||||
+ WeightedScoreCard{.cards = makeScoreFromList(queryList, service->keywords()), .weight = 0.1},
|
||||
+ };
|
||||
+
|
||||
+ if (RUNNER_SERVICES().isDebugEnabled()) {
|
||||
+ qCDebug(RUNNER_SERVICES) << "+++++++ Weighted Cards for" << name;
|
||||
+ for (const auto &weightedCard : weightedCards) {
|
||||
+ qCDebug(RUNNER_SERVICES) << weightedCard;
|
||||
}
|
||||
- // GenericName
|
||||
- if (contains(service->genericName(), queryList) || contains(service->untranslatedGenericName(), queryList)) {
|
||||
- return true;
|
||||
+ qCDebug(RUNNER_SERVICES) << "-------";
|
||||
+ }
|
||||
+
|
||||
+ int scores = 1; // starts at 1 to avoid division by zero
|
||||
+ qreal finalScore = 0.0;
|
||||
+ for (const auto &weightedCard : weightedCards) {
|
||||
+ if (weightedCard.cards.empty()) {
|
||||
+ continue; // No scores, no match.
|
||||
}
|
||||
- // Comment
|
||||
- if (contains(service->comment(), queryList)) {
|
||||
- return true;
|
||||
+
|
||||
+ qreal weightedScore = 0.0;
|
||||
+ for (const auto &scoreCard : weightedCard.cards) {
|
||||
+ weightedScore += (scoreCard.bitapScore + scoreCard.levenshteinScore) * weightedCard.weight;
|
||||
+ scores++;
|
||||
}
|
||||
|
||||
- return false;
|
||||
- };
|
||||
+ finalScore += weightedScore;
|
||||
+ }
|
||||
+ finalScore = finalScore / scores; // Average the score for this card
|
||||
|
||||
- for (const KService::Ptr &service : m_services) {
|
||||
- if (!nameKeywordAndGenericNameFilter(service) || disqualify(service)) {
|
||||
- continue;
|
||||
- }
|
||||
+ qCDebug(RUNNER_SERVICES) << "Final score for" << name << "is" << finalScore;
|
||||
+ if (finalScore > 0.0) {
|
||||
+ return Score{.value = finalScore, .categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Moderate};
|
||||
+ }
|
||||
|
||||
- const QString id = service->storageId();
|
||||
- const QString name = service->name();
|
||||
+ return std::nullopt;
|
||||
+ }
|
||||
|
||||
- KRunner::QueryMatch::CategoryRelevance categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Moderate;
|
||||
- qreal relevance(0.6);
|
||||
+ void matchNameKeywordAndGenericName()
|
||||
+ {
|
||||
+ static auto isTest = QStandardPaths::isTestModeEnabled();
|
||||
|
||||
- // If the term was < 3 chars and NOT at the beginning of the App's name, then chances are the user doesn't want that app
|
||||
- if (weightedTermLength < 3) {
|
||||
- if (name.startsWith(query, Qt::CaseInsensitive)) {
|
||||
- relevance = 0.9;
|
||||
- } else {
|
||||
- continue;
|
||||
- }
|
||||
- } else if (name.compare(query, Qt::CaseInsensitive) == 0) {
|
||||
- relevance = 1;
|
||||
- categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Highest;
|
||||
- } else if (const auto idx = name.indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
- relevance = 0.8;
|
||||
- relevance += increaseMatchRelevance(name, queryList, Category::Name);
|
||||
- if (idx == 0) {
|
||||
- relevance += 0.1;
|
||||
- categoryRelevance = KRunner::QueryMatch::CategoryRelevance::High;
|
||||
- }
|
||||
- } else if (const auto idx = service->genericName().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
- relevance = 0.65;
|
||||
- relevance += increaseMatchRelevance(service->genericName(), queryList, Category::GenericName);
|
||||
- if (idx == 0) {
|
||||
- relevance += 0.05;
|
||||
- }
|
||||
- } else if (const auto idx = service->comment().indexOf(queryList[0], 0, Qt::CaseInsensitive); idx != -1) {
|
||||
- relevance = 0.5;
|
||||
- relevance += increaseMatchRelevance(service->comment(), queryList, Category::Comment);
|
||||
- if (idx == 0) {
|
||||
- relevance += 0.05;
|
||||
- }
|
||||
+ for (const KService::Ptr &service : m_services) {
|
||||
+ if (isTest && !service->name().contains("ServiceRunnerTest"_L1)) {
|
||||
+ continue; // Skip services that are not part of the test.
|
||||
}
|
||||
|
||||
KRunner::QueryMatch match(m_runner);
|
||||
- match.setCategoryRelevance(categoryRelevance);
|
||||
- setupMatch(service, match);
|
||||
- if (service->categories().contains(QLatin1String("KDE"))) {
|
||||
- qCDebug(RUNNER_SERVICES) << "found a kde thing" << id << match.subtext() << relevance;
|
||||
- relevance += .09;
|
||||
- }
|
||||
-
|
||||
- if (const auto foundIt = m_runner->m_favorites.constFind(service->desktopEntryName()); foundIt != m_runner->m_favorites.cend()) {
|
||||
- if (foundIt->isGlobal || foundIt->linkedActivities.contains(m_currentActivity)) {
|
||||
- qCDebug(RUNNER_SERVICES) << "entry is a favorite" << id << match.subtext() << relevance;
|
||||
- relevance *= 1.25; // Give favorites a relative boost,
|
||||
- }
|
||||
+ auto score = fuzzyScore(service);
|
||||
+ if (!score || disqualify(service)) {
|
||||
+ continue;
|
||||
}
|
||||
|
||||
- qCDebug(RUNNER_SERVICES) << name << "is this relevant:" << relevance;
|
||||
- match.setRelevance(relevance);
|
||||
+ setupMatch(service, match);
|
||||
+ match.setCategoryRelevance(score->categoryRelevance);
|
||||
+ match.setRelevance(score->value);
|
||||
+ qCDebug(RUNNER_SERVICES) << match.text() << "is this relevant:" << match.relevance() << "category relevance" << match.categoryRelevance();
|
||||
|
||||
matches << match;
|
||||
}
|
||||
--
|
||||
2.51.0
|
||||
|
||||
133
roles/kde/patches/plasma-workspace/pr5734.patch
Normal file
133
roles/kde/patches/plasma-workspace/pr5734.patch
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
From 0168ee68b484995ed9398d31004dd80678ac7e37 Mon Sep 17 00:00:00 2001
|
||||
From: Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
Date: Tue, 5 Aug 2025 12:57:00 +0200
|
||||
Subject: [PATCH] Close USB device added notification when devicenotifier pops
|
||||
up
|
||||
|
||||
The device notification is supposed to be super quick feedback that
|
||||
"something" got detected. Once it has been identified as storage
|
||||
device (disks spun up and what not), devicenotifier will show up
|
||||
and then you have two popups.
|
||||
---
|
||||
applets/devicenotifier/CMakeLists.txt | 1 +
|
||||
applets/devicenotifier/devicefiltercontrol.cpp | 14 ++++++++++++++
|
||||
applets/devicenotifier/devicefiltercontrol.h | 1 +
|
||||
applets/devicenotifier/qml/main.qml | 1 +
|
||||
devicenotifications/devicenotifications.cpp | 8 ++++++++
|
||||
devicenotifications/devicenotifications.h | 3 +++
|
||||
6 files changed, 28 insertions(+)
|
||||
|
||||
diff --git a/applets/devicenotifier/CMakeLists.txt b/applets/devicenotifier/CMakeLists.txt
|
||||
index d87964dc46d..fa415837e68 100644
|
||||
--- a/applets/devicenotifier/CMakeLists.txt
|
||||
+++ b/applets/devicenotifier/CMakeLists.txt
|
||||
@@ -31,6 +31,7 @@ plasma_add_applet(org.kde.plasma.devicenotifier
|
||||
|
||||
target_link_libraries(org.kde.plasma.devicenotifier
|
||||
PRIVATE
|
||||
+ Qt::DBus
|
||||
Qt::Qml
|
||||
Plasma::Plasma
|
||||
KF6::Solid
|
||||
diff --git a/applets/devicenotifier/devicefiltercontrol.cpp b/applets/devicenotifier/devicefiltercontrol.cpp
|
||||
index dfdb51a4304..f585eb2f063 100644
|
||||
--- a/applets/devicenotifier/devicefiltercontrol.cpp
|
||||
+++ b/applets/devicenotifier/devicefiltercontrol.cpp
|
||||
@@ -11,9 +11,14 @@
|
||||
#include "devicecontrol.h"
|
||||
#include "devicestatemonitor_p.h"
|
||||
|
||||
+#include <QDBusConnection>
|
||||
+#include <QDBusMessage>
|
||||
+
|
||||
#include <Solid/Device>
|
||||
#include <Solid/OpticalDrive>
|
||||
|
||||
+using namespace Qt::Literals::StringLiterals;
|
||||
+
|
||||
DeviceFilterControl::DeviceFilterControl(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_filterType(Removable)
|
||||
@@ -54,6 +59,15 @@ void DeviceFilterControl::unmountAllRemovables()
|
||||
qCDebug(APPLETS::DEVICENOTIFIER) << "Device Filter Control: unmount all removables function finished";
|
||||
}
|
||||
|
||||
+void DeviceFilterControl::dismissUsbDeviceAddedNotification()
|
||||
+{
|
||||
+ QDBusMessage msg = QDBusMessage::createMethodCall(u"org.kde.kded6"_s,
|
||||
+ u"/modules/devicenotifications"_s,
|
||||
+ u"org.kde.plasma.devicenotifications"_s,
|
||||
+ u"dismissUsbDeviceAdded"_s);
|
||||
+ QDBusConnection::sessionBus().call(msg, QDBus::NoBlock);
|
||||
+}
|
||||
+
|
||||
QBindable<QString> DeviceFilterControl::bindableLastUdi()
|
||||
{
|
||||
return &m_lastUdi;
|
||||
diff --git a/applets/devicenotifier/devicefiltercontrol.h b/applets/devicenotifier/devicefiltercontrol.h
|
||||
index e4c0a321657..fa6266fb197 100644
|
||||
--- a/applets/devicenotifier/devicefiltercontrol.h
|
||||
+++ b/applets/devicenotifier/devicefiltercontrol.h
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
Q_ENUM(DevicesType)
|
||||
|
||||
Q_INVOKABLE void unmountAllRemovables();
|
||||
+ Q_INVOKABLE void dismissUsbDeviceAddedNotification();
|
||||
|
||||
explicit DeviceFilterControl(QObject *parent = nullptr);
|
||||
~DeviceFilterControl() override;
|
||||
diff --git a/applets/devicenotifier/qml/main.qml b/applets/devicenotifier/qml/main.qml
|
||||
index 7fcd76a6d16..c7fe6e6197d 100644
|
||||
--- a/applets/devicenotifier/qml/main.qml
|
||||
+++ b/applets/devicenotifier/qml/main.qml
|
||||
@@ -35,6 +35,7 @@ PlasmoidItem {
|
||||
onLastUdiChanged: {
|
||||
if (lastDeviceAdded) {
|
||||
if (Plasmoid.configuration.popupOnNewDevice) {
|
||||
+ filterModel.dismissUsbDeviceAddedNotification();
|
||||
devicenotifier.expanded = true;
|
||||
fullRepresentationItem.spontaneousOpen = true;
|
||||
}
|
||||
diff --git a/devicenotifications/devicenotifications.cpp b/devicenotifications/devicenotifications.cpp
|
||||
index 71ae0ff340e..196e28ca948 100644
|
||||
--- a/devicenotifications/devicenotifications.cpp
|
||||
+++ b/devicenotifications/devicenotifications.cpp
|
||||
@@ -323,6 +323,14 @@ void KdedDeviceNotifications::setupWaylandOutputListener()
|
||||
wl_callback_add_listener(syncCallback, &syncCallbackListener, this);
|
||||
}
|
||||
|
||||
+void KdedDeviceNotifications::dismissUsbDeviceAdded()
|
||||
+{
|
||||
+ if (m_usbDeviceAddedNotification) {
|
||||
+ m_usbDeviceAddedNotification->close();
|
||||
+ m_usbDeviceAddedNotification = nullptr;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void KdedDeviceNotifications::notifyOutputAdded()
|
||||
{
|
||||
if (m_deviceAddedTimer.isActive()) {
|
||||
diff --git a/devicenotifications/devicenotifications.h b/devicenotifications/devicenotifications.h
|
||||
index ab7e6b3ff9b..75005193287 100644
|
||||
--- a/devicenotifications/devicenotifications.h
|
||||
+++ b/devicenotifications/devicenotifications.h
|
||||
@@ -77,6 +77,7 @@ private:
|
||||
class KdedDeviceNotifications : public KDEDModule
|
||||
{
|
||||
Q_OBJECT
|
||||
+ Q_CLASSINFO("D-Bus Interface", "org.kde.plasma.devicenotifications")
|
||||
|
||||
public:
|
||||
KdedDeviceNotifications(QObject *parent, const QVariantList &args);
|
||||
@@ -84,6 +85,8 @@ public:
|
||||
|
||||
void setupWaylandOutputListener();
|
||||
|
||||
+ Q_SCRIPTABLE void dismissUsbDeviceAdded();
|
||||
+
|
||||
private:
|
||||
void notifyOutputAdded();
|
||||
void notifyOutputRemoved();
|
||||
--
|
||||
GitLab
|
||||
|
||||
33
roles/kde/patches/plasma-workspace/pr5746.patch
Normal file
33
roles/kde/patches/plasma-workspace/pr5746.patch
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
From f6ec2847358178a5b6ff0497e52d1e2be43d2a48 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Luan=20Vitor=20Simi=C3=A3o=20oliveira?=
|
||||
<luanv.oliveira@outlook.com>
|
||||
Date: Fri, 8 Aug 2025 14:41:49 -0300
|
||||
Subject: [PATCH] kcms/style: add special case for Adwaita gtk theme
|
||||
|
||||
Allows the user to set the GTK theme to the default "Adwaita"
|
||||
needs to be special cased because the theme is implemented in code.
|
||||
---
|
||||
kcms/style/gtkthemesmodel.cpp | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/kcms/style/gtkthemesmodel.cpp b/kcms/style/gtkthemesmodel.cpp
|
||||
index 002e87dbd0d..6dcdf4f1a1d 100644
|
||||
--- a/kcms/style/gtkthemesmodel.cpp
|
||||
+++ b/kcms/style/gtkthemesmodel.cpp
|
||||
@@ -35,7 +35,12 @@ void GtkThemesModel::load()
|
||||
if (possibleThemeDirectory.dirName() == u"Breeze-Dark") {
|
||||
continue;
|
||||
}
|
||||
-
|
||||
+ if (possibleThemeDirectory.dirName() == u"Default") {
|
||||
+ // Adwaita is a special case, since it is implemented inside GTK itself
|
||||
+ // also setting gtk-theme-name to "Default" breaks dark theme
|
||||
+ gtk3ThemesNames.insert(QStringLiteral("Adwaita"), possibleThemeDirectory.path());
|
||||
+ continue;
|
||||
+ }
|
||||
gtk3ThemesNames.insert(possibleThemeDirectory.dirName(), possibleThemeDirectory.path());
|
||||
}
|
||||
}
|
||||
--
|
||||
GitLab
|
||||
|
||||
32
roles/kde/patches/plasma-workspace/pr5782.patch
Normal file
32
roles/kde/patches/plasma-workspace/pr5782.patch
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
From 4ab3894d75e1f9c6c7738a893a9b707ff0575953 Mon Sep 17 00:00:00 2001
|
||||
From: Nate Graham <nate@kde.org>
|
||||
Date: Thu, 21 Aug 2025 19:37:33 -0600
|
||||
Subject: [PATCH] notifications: make "you missed some notifications"
|
||||
notification transient
|
||||
|
||||
Its purpose is to direct you to the notifications history. If you're
|
||||
seeing it *in* the notification history, its purpose has been bypassed
|
||||
because you're already where it wanted to take you.
|
||||
|
||||
Don't show it in the notification history.
|
||||
---
|
||||
libnotificationmanager/notifications.cpp | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/libnotificationmanager/notifications.cpp b/libnotificationmanager/notifications.cpp
|
||||
index f68c342e7e9..128665f4de9 100644
|
||||
--- a/libnotificationmanager/notifications.cpp
|
||||
+++ b/libnotificationmanager/notifications.cpp
|
||||
@@ -917,6 +917,9 @@ void Notifications::showInhibitionSummary(Urgency urgency, const QStringList &bl
|
||||
notification->setIconName(u"preferences-desktop-notification-bell"_s);
|
||||
notification->setFlags(KNotification::CloseOnTimeout);
|
||||
notification->setComponentName(u"libnotificationmanager"_s);
|
||||
+ // Don't put it in the history because this doesn't make sense; if you're seeing it
|
||||
+ // in the history, you're seeing the notifications it was telling you about!
|
||||
+ notification->setHint(u"transient"_s, true);
|
||||
|
||||
const QString showNotificationsText = i18nc("@action:button Show the notifications popup", "Show Notifications");
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
42
roles/kde/patches/plasma-workspace/pr5788.patch
Normal file
42
roles/kde/patches/plasma-workspace/pr5788.patch
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
From f0d2dd20803f2eee364d26656715b89e7c74366c Mon Sep 17 00:00:00 2001
|
||||
From: David Redondo <kde@david-redondo.de>
|
||||
Date: Wed, 27 Aug 2025 09:40:43 +0200
|
||||
Subject: [PATCH] servicerunner: use vector::insert on compilers that don't
|
||||
support append_range yet
|
||||
|
||||
g++ only gained support for it with g++ 15 which was released this month.
|
||||
---
|
||||
runners/services/servicerunner.cpp | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp
|
||||
index 2ccc9a0af37..9e9d4e70a72 100644
|
||||
--- a/runners/services/servicerunner.cpp
|
||||
+++ b/runners/services/servicerunner.cpp
|
||||
@@ -142,7 +142,11 @@ auto makeScoreFromList(const auto &queryList, const QStringList &strings) {
|
||||
continue; // Not a good match, skip it. We are very strict with keywords
|
||||
}
|
||||
found = true;
|
||||
+#ifdef __cpp_lib_containers_ranges
|
||||
queryCards.append_range(stringCards);
|
||||
+#else
|
||||
+ queryCards.insert(queryCards.end(), stringCards.cbegin(), stringCards.cend());
|
||||
+#endif
|
||||
}
|
||||
// We do not break because other string might also match, improving the score.
|
||||
}
|
||||
@@ -150,7 +154,11 @@ auto makeScoreFromList(const auto &queryList, const QStringList &strings) {
|
||||
// No item in strings matched the query item. This means the entire query is not a match.
|
||||
return ScoreCards{};
|
||||
}
|
||||
+#ifdef __cpp_lib_containers_ranges
|
||||
cards.append_range(queryCards);
|
||||
+#else
|
||||
+ cards.insert(cards.end(), queryCards.cbegin(), queryCards.cend());
|
||||
+#endif
|
||||
}
|
||||
return cards;
|
||||
};
|
||||
--
|
||||
GitLab
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue